mirror of
https://github.com/LeavesMC/Leaves.git
synced 2025-12-28 19:39:22 +00:00
1.21.5 (#470)
--------- Co-authored-by: violetc <58360096+s-yh-china@users.noreply.github.com> Co-authored-by: Fortern <blueten.ki@gmail.com> Co-authored-by: MC_XiaoHei <xor7xiaohei@gmail.com> Co-authored-by: Helvetica Volubi <88063803+Suisuroru@users.noreply.github.com> Co-authored-by: MC_XiaoHei <xiaohei.xor7@outlook.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
package co.aikar.timings;
|
||||
|
||||
// It is only used to make certain plugin "confirm" that this is a Paper server
|
||||
// since we removed all timings related codes and classes
|
||||
public class Timings {
|
||||
}
|
||||
@@ -4,7 +4,9 @@ import com.destroystokyo.paper.util.SneakyThrow;
|
||||
import io.papermc.paper.configuration.GlobalConfiguration;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.permissions.Permission;
|
||||
@@ -28,6 +30,7 @@ import org.leavesmc.leaves.protocol.CarpetServerProtocol.CarpetRules;
|
||||
import org.leavesmc.leaves.protocol.bladeren.BladerenProtocol.LeavesFeature;
|
||||
import org.leavesmc.leaves.protocol.bladeren.BladerenProtocol.LeavesFeatureSet;
|
||||
import org.leavesmc.leaves.region.RegionFileFormat;
|
||||
import org.leavesmc.leaves.util.ElytraAeronauticsHelper;
|
||||
import org.leavesmc.leaves.util.ForcePeacefulModeSwitchType;
|
||||
import org.leavesmc.leaves.util.MathUtils;
|
||||
|
||||
@@ -39,6 +42,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class LeavesConfig {
|
||||
|
||||
@@ -216,14 +220,19 @@ public final class LeavesConfig {
|
||||
@GlobalConfig("cce-update-suppression")
|
||||
public boolean cceUpdateSuppression = false;
|
||||
|
||||
@GlobalConfig("sound-update-suppression")
|
||||
public boolean soundUpdateSuppression = false;
|
||||
|
||||
@RemovedConfig(name = "redstone-wire-dont-connect-if-on-trapdoor", category = "modify", transform = true)
|
||||
@RemovedConfig(name = "redstone-wire-dont-connect-if-on-trapdoor", category = {"modify", "minecraft-old"}, transform = true)
|
||||
@GlobalConfig("redstone-wire-dont-connect-if-on-trapdoor")
|
||||
public boolean redstoneDontCantOnTrapDoor = false;
|
||||
@RemovedConfig(name = "redstone-wire-dont-connect-if-on-trapdoor", category = {"modify", "minecraft-old", "block-updater"}, transform = true)
|
||||
@GlobalConfig("redstone-ignore-upwards-update")
|
||||
public boolean redstoneIgnoreUpwardsUpdate = false;
|
||||
|
||||
@RemovedConfig(name = "old-block-entity-behaviour", category = {"modify", "minecraft-old"}, transform = true)
|
||||
@GlobalConfig("old-block-entity-behaviour")
|
||||
public boolean oldBlockEntityBehaviour = false;
|
||||
@RemovedConfig(name = "old-block-entity-behaviour", category = {"modify", "minecraft-old", "block-updater"}, transform = true)
|
||||
@GlobalConfig("old-block-remove-behaviour")
|
||||
public boolean oldBlockRemoveBehaviour = false;
|
||||
}
|
||||
|
||||
@RemovedConfig(name = "shears-in-dispenser-can-zero-amount", category = {}, transform = true)
|
||||
@@ -235,7 +244,7 @@ public final class LeavesConfig {
|
||||
public boolean armorStandCantKillByMobProjectile = false;
|
||||
|
||||
@GlobalConfig(value = "villager-infinite-discounts", validator = VillagerInfiniteDiscountsValidator.class)
|
||||
public boolean villagerInfiniteDiscounts = false;
|
||||
private boolean villagerInfiniteDiscounts = false;
|
||||
|
||||
private static class VillagerInfiniteDiscountsValidator extends BooleanConfigValidator {
|
||||
@Override
|
||||
@@ -277,12 +286,18 @@ public final class LeavesConfig {
|
||||
@GlobalConfig("disable-LivingEntity-ai-step-alive-check")
|
||||
public boolean disableLivingEntityAiStepAliveCheck = false;
|
||||
|
||||
@GlobalConfig("fix-fortress-mob-spawn")
|
||||
public boolean fixFortressMobSpawn = false;
|
||||
@GlobalConfig("spawn-invulnerable-time")
|
||||
public boolean spawnInvulnerableTime = false;
|
||||
|
||||
@GlobalConfig("old-hopper-suck-in-behavior")
|
||||
public boolean oldHopperSuckInBehavior = false;
|
||||
|
||||
@GlobalConfig("old-nether-portal-collision") // Should remove in 1.21.6
|
||||
public boolean oldNetherPortalCollision = false;
|
||||
|
||||
@GlobalConfig("old-zombie-piglin-drop")
|
||||
public boolean oldZombiePiglinDrop = false;
|
||||
|
||||
public RaidConfig raid = new RaidConfig();
|
||||
|
||||
@GlobalConfigCategory("revert-raid-changes")
|
||||
@@ -300,11 +315,27 @@ public final class LeavesConfig {
|
||||
public boolean skipHeightCheck = false;
|
||||
}
|
||||
|
||||
@GlobalConfig("old-zombie-reinforcement")
|
||||
public boolean oldZombieReinforcement = false;
|
||||
|
||||
@GlobalConfig("allow-anvil-destroy-item-entities")
|
||||
public boolean allowAnvilDestroyItemEntities = false;
|
||||
|
||||
@GlobalConfig("string-tripwire-hook-duplicate")
|
||||
public boolean stringTripwireHookDuplicate = false;
|
||||
public TripwireConfig tripwire = new TripwireConfig();
|
||||
|
||||
@GlobalConfigCategory("tripwire-and-hook-behavior")
|
||||
public static class TripwireConfig {
|
||||
@RemovedConfig(name = "string-tripwire-hook-duplicate", category = {"modify", "minecraft-old"}, transform = true)
|
||||
@GlobalConfig("string-tripwire-hook-duplicate")
|
||||
public boolean stringTripwireHookDuplicate = false;
|
||||
|
||||
@GlobalConfig("tripwire-behavior")
|
||||
public TripwireBehavior tripwireBehavior = TripwireBehavior.VANILLA_21;
|
||||
|
||||
public enum TripwireBehavior {
|
||||
VANILLA_20, VANILLA_21, MIXED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ElytraAeronauticsConfig elytraAeronautics = new ElytraAeronauticsConfig();
|
||||
@@ -312,7 +343,7 @@ public final class LeavesConfig {
|
||||
@GlobalConfigCategory("elytra-aeronautics")
|
||||
public static class ElytraAeronauticsConfig {
|
||||
@GlobalConfig("no-chunk-load")
|
||||
public boolean noChunk = false;
|
||||
public boolean enableNoChunkLoad = false;
|
||||
|
||||
@GlobalConfig(value = "no-chunk-height")
|
||||
public double noChunkHeight = 500.0D;
|
||||
@@ -321,13 +352,13 @@ public final class LeavesConfig {
|
||||
public double noChunkSpeed = -1.0D;
|
||||
|
||||
@GlobalConfig("message")
|
||||
public boolean noChunkMes = true;
|
||||
public boolean doSendMessages = true;
|
||||
|
||||
@GlobalConfig(value = "message-start")
|
||||
public String noChunkStartMes = "Flight enter cruise mode";
|
||||
public String startMessage = "Flight enter cruise mode";
|
||||
|
||||
@GlobalConfig(value = "message-end")
|
||||
public String noChunkEndMes = "Flight exit cruise mode";
|
||||
public String endMessage = "Flight exit cruise mode";
|
||||
}
|
||||
|
||||
@RemovedConfig(name = "redstone-shears-wrench", category = {}, transform = true)
|
||||
@@ -451,9 +482,6 @@ public final class LeavesConfig {
|
||||
@GlobalConfig("shave-snow-layers")
|
||||
public boolean shaveSnowLayers = true;
|
||||
|
||||
@GlobalConfig("ignore-lc")
|
||||
public boolean ignoreLC = false;
|
||||
|
||||
@GlobalConfig("disable-packet-limit")
|
||||
public boolean disablePacketLimit = false;
|
||||
|
||||
@@ -580,11 +608,33 @@ public final class LeavesConfig {
|
||||
@GlobalConfig("disable-vault-blacklist")
|
||||
public boolean disableVaultBlacklist = false;
|
||||
|
||||
@GlobalConfig(value = "exp-orb-absorb-mode", validator = ExpOrbModeValidator.class)
|
||||
private ExpOrbAbsorbMode expOrbAbsorbMode = ExpOrbAbsorbMode.VANILLA;
|
||||
|
||||
public Predicate<ServerPlayer> fastAbsorbPredicate = player -> false;
|
||||
|
||||
public enum ExpOrbAbsorbMode {
|
||||
VANILLA, FAST, FAST_CREATIVE
|
||||
}
|
||||
|
||||
private static class ExpOrbModeValidator extends EnumConfigValidator<ExpOrbAbsorbMode> {
|
||||
@Override
|
||||
public void verify(ExpOrbAbsorbMode old, ExpOrbAbsorbMode value) throws IllegalArgumentException {
|
||||
LeavesConfig.modify.fastAbsorbPredicate = switch (value) {
|
||||
case FAST -> player -> true;
|
||||
case VANILLA -> player -> false;
|
||||
case FAST_CREATIVE -> Player::hasInfiniteMaterials;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@RemovedConfig(name = "tick-command", category = "modify")
|
||||
@RemovedConfig(name = "player-can-edit-sign", category = "modify")
|
||||
@RemovedConfig(name = "mending-compatibility-infinity", category = {"modify", "minecraft-old"})
|
||||
@RemovedConfig(name = "protection-stacking", category = {"modify", "minecraft-old"})
|
||||
@RemovedConfig(name = "disable-moved-wrongly-threshold", category = {"modify"})
|
||||
@RemovedConfig(name = "disable-moved-wrongly-threshold", category = "modify")
|
||||
@RemovedConfig(name = "ignore-lc", category = "modify")
|
||||
@RemovedConfig(name = "fix-fortress-mob-spawn", category = {"modify", "minecraft-old"})
|
||||
private final boolean removed = false;
|
||||
}
|
||||
|
||||
@@ -947,7 +997,7 @@ public final class LeavesConfig {
|
||||
public boolean loginProtect = false;
|
||||
|
||||
@GlobalConfig(value = "urls", lock = true, validator = ExtraYggdrasilUrlsValidator.class)
|
||||
public List<String> serviceList = List.of("https://url.with.authlib-injector-yggdrasil");
|
||||
private List<String> serviceList = List.of("https://url.with.authlib-injector-yggdrasil");
|
||||
|
||||
public static class ExtraYggdrasilUrlsValidator extends ListConfigValidator.STRING {
|
||||
@Override
|
||||
@@ -1022,9 +1072,6 @@ public final class LeavesConfig {
|
||||
@GlobalConfig(value = "version", lock = true)
|
||||
public org.leavesmc.leaves.region.linear.LinearVersion version = org.leavesmc.leaves.region.linear.LinearVersion.V2;
|
||||
|
||||
@GlobalConfig(value = "auto-convert-anvil-to-linear", lock = true)
|
||||
public boolean autoConvertAnvilToLinear = false;
|
||||
|
||||
@GlobalConfig(value = "flush-max-threads", lock = true)
|
||||
public int flushThreads = 6;
|
||||
|
||||
@@ -1056,7 +1103,8 @@ public final class LeavesConfig {
|
||||
|
||||
@RemovedConfig(name = "flush-frequency", category = {"region", "linear"})
|
||||
@RemovedConfig(name = "crash-on-broken-symlink", category = {"region", "linear"})
|
||||
private final boolean linearCrashOnBrokenSymlink = true;
|
||||
@RemovedConfig(name = "auto-convert-anvil-to-linear", category = {"region", "linear"})
|
||||
private final boolean removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1070,6 +1118,16 @@ public final class LeavesConfig {
|
||||
@GlobalConfig("vanilla-display-name")
|
||||
public boolean vanillaDisplayName = false;
|
||||
|
||||
@GlobalConfig(value = "collision-behavior")
|
||||
public CollisionBehavior collisionBehavior = CollisionBehavior.BLOCK_SHAPE_VANILLA;
|
||||
|
||||
public enum CollisionBehavior {
|
||||
VANILLA, BLOCK_SHAPE_VANILLA, PAPER
|
||||
}
|
||||
|
||||
@GlobalConfig("vanilla-portal-handle")
|
||||
public boolean vanillaPortalHandle = false;
|
||||
|
||||
@RemovedConfig(name = "spigot-EndPlatform-destroy", category = "fix")
|
||||
private final boolean spigotEndPlatformDestroy = false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.leavesmc.leaves.bot;
|
||||
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
@@ -23,13 +25,24 @@ import org.leavesmc.leaves.bot.subcommands.BotRemoveCommand;
|
||||
import org.leavesmc.leaves.bot.subcommands.BotSaveCommand;
|
||||
import org.leavesmc.leaves.command.LeavesCommandUtil;
|
||||
import org.leavesmc.leaves.command.LeavesSubcommand;
|
||||
import org.leavesmc.leaves.command.LeavesSuggestionCommand;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
|
||||
public class BotCommand extends Command {
|
||||
//TODO rewrite
|
||||
public class BotCommand extends Command implements LeavesSuggestionCommand {
|
||||
|
||||
public BotCommand(String name) {
|
||||
super(name);
|
||||
@@ -74,6 +87,17 @@ public class BotCommand extends Command {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable CompletableFuture<Suggestions> tabSuggestion(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, @NotNull SuggestionsBuilder builder) throws IllegalArgumentException {
|
||||
if (args.length > 1) {
|
||||
final @Nullable Pair<String, LeavesSubcommand> subCommand = resolveCommand(args[0]);
|
||||
if (subCommand != null) {
|
||||
return subCommand.second().tabSuggestion(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length), location, builder);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final @NotNull CommandSender sender, final @NotNull String commandLabel, final String @NotNull [] args) {
|
||||
if (!testPermission(sender) || !LeavesConfig.modify.fakeplayer.enable) return true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.leavesmc.leaves.bot;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.core.UUIDUtil;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtAccounter;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
@@ -64,7 +65,7 @@ public class BotDataStorage implements IPlayerDataStorage {
|
||||
if (flag && player instanceof ServerBot bot) {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.putString("name", bot.createState.name());
|
||||
nbt.putUUID("uuid", bot.getUUID());
|
||||
nbt.store("uuid", UUIDUtil.CODEC, bot.getUUID());
|
||||
nbt.putBoolean("resume", bot.resume);
|
||||
this.savedBotList.put(bot.createState.realName(), nbt);
|
||||
this.saveBotList();
|
||||
|
||||
@@ -1,157 +1,114 @@
|
||||
package org.leavesmc.leaves.bot;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.core.component.DataComponentPatch;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.ContainerHelper;
|
||||
import net.minecraft.world.SimpleContainer;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
||||
// Power by gugle-carpet-addition(https://github.com/Gu-ZT/gugle-carpet-addition)
|
||||
public class BotInventoryContainer extends SimpleContainer {
|
||||
public class BotInventoryContainer extends Inventory {
|
||||
|
||||
public final NonNullList<ItemStack> items;
|
||||
public final NonNullList<ItemStack> armor;
|
||||
public final NonNullList<ItemStack> offhand;
|
||||
private final List<NonNullList<ItemStack>> compartments;
|
||||
private final NonNullList<ItemStack> buttons = NonNullList.withSize(13, ItemStack.EMPTY);
|
||||
private final ServerBot player;
|
||||
private static final ItemStack button;
|
||||
|
||||
public BotInventoryContainer(ServerBot player) {
|
||||
this.player = player;
|
||||
this.items = this.player.getInventory().items;
|
||||
this.armor = this.player.getInventory().armor;
|
||||
this.offhand = this.player.getInventory().offhand;
|
||||
this.compartments = ImmutableList.of(this.items, this.armor, this.offhand, this.buttons);
|
||||
createButton();
|
||||
static {
|
||||
CompoundTag customData = new CompoundTag();
|
||||
customData.putBoolean("Leaves.Gui.Placeholder", true);
|
||||
|
||||
DataComponentPatch patch = DataComponentPatch.builder()
|
||||
.set(DataComponents.CUSTOM_NAME, Component.empty())
|
||||
.set(DataComponents.CUSTOM_DATA, CustomData.of(customData))
|
||||
.build();
|
||||
|
||||
button = new ItemStack(Items.STRUCTURE_VOID);
|
||||
button.applyComponents(patch);
|
||||
}
|
||||
|
||||
private final Inventory original;
|
||||
|
||||
public BotInventoryContainer(Inventory original) {
|
||||
super(original.player, original.equipment);
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContainerSize() {
|
||||
return this.items.size() + this.armor.size() + this.offhand.size() + this.buttons.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (ItemStack itemStack : this.items) {
|
||||
if (itemStack.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
for (ItemStack itemStack : this.armor) {
|
||||
if (itemStack.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
for (ItemStack itemStack : this.offhand) {
|
||||
if (itemStack.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return 54;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public ItemStack getItem(int slot) {
|
||||
Pair<NonNullList<ItemStack>, Integer> pair = getItemSlot(slot);
|
||||
if (pair != null) {
|
||||
return pair.getFirst().get(pair.getSecond());
|
||||
} else {
|
||||
return ItemStack.EMPTY;
|
||||
int realSlot = convertSlot(slot);
|
||||
if (realSlot == -999) {
|
||||
// buttons are the same
|
||||
return button;
|
||||
}
|
||||
return original.getItem(realSlot);
|
||||
}
|
||||
|
||||
public Pair<NonNullList<ItemStack>, Integer> getItemSlot(int slot) {
|
||||
switch (slot) {
|
||||
case 0 -> {
|
||||
return new Pair<>(buttons, 0);
|
||||
}
|
||||
case 1, 2, 3, 4 -> {
|
||||
return new Pair<>(armor, 4 - slot);
|
||||
}
|
||||
case 5, 6 -> {
|
||||
return new Pair<>(buttons, slot - 4);
|
||||
}
|
||||
case 7 -> {
|
||||
return new Pair<>(offhand, 0);
|
||||
}
|
||||
case 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 -> {
|
||||
return new Pair<>(buttons, slot - 5);
|
||||
}
|
||||
public int convertSlot(int slot) {
|
||||
return switch (slot) {
|
||||
// Mainhand is always store at slot 0
|
||||
case 6 -> 0;
|
||||
|
||||
// Offhand
|
||||
case 7 -> 40;
|
||||
|
||||
// Equipment slot start at 36
|
||||
case 1, 2, 3, 4 -> 40 - slot;
|
||||
|
||||
// Inventory storage
|
||||
case 18, 19, 20, 21, 22, 23, 24, 25, 26,
|
||||
27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44 -> {
|
||||
return new Pair<>(items, slot - 9);
|
||||
}
|
||||
case 45, 46, 47, 48, 49, 50, 51, 52, 53 -> {
|
||||
return new Pair<>(items, slot - 45);
|
||||
}
|
||||
default -> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44 -> slot - 9;
|
||||
|
||||
// Hotbar, 45 -> Mainhand (0)
|
||||
case 45, 46, 47, 48, 49, 50, 51, 52, 53 -> slot - 45;
|
||||
|
||||
// Buttons
|
||||
default -> -999;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public ItemStack removeItem(int slot, int amount) {
|
||||
Pair<NonNullList<ItemStack>, Integer> pair = getItemSlot(slot);
|
||||
NonNullList<ItemStack> list = null;
|
||||
ItemStack itemStack = ItemStack.EMPTY;
|
||||
if (pair != null) {
|
||||
list = pair.getFirst();
|
||||
slot = pair.getSecond();
|
||||
int realSlot = convertSlot(slot);
|
||||
if (realSlot == -999) {
|
||||
// Don't remove buttons
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
if (list != null && !list.get(slot).isEmpty()) {
|
||||
itemStack = ContainerHelper.removeItem(list, slot, amount);
|
||||
player.detectEquipmentUpdatesPublic();
|
||||
}
|
||||
return itemStack;
|
||||
ItemStack removed = original.removeItem(realSlot, amount);
|
||||
player.detectEquipmentUpdates();
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public ItemStack removeItemNoUpdate(int slot) {
|
||||
Pair<NonNullList<ItemStack>, Integer> pair = getItemSlot(slot);
|
||||
NonNullList<ItemStack> list = null;
|
||||
if (pair != null) {
|
||||
list = pair.getFirst();
|
||||
slot = pair.getSecond();
|
||||
int realSlot = convertSlot(slot);
|
||||
if (realSlot == -999) {
|
||||
// Don't remove buttons
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
if (list != null && !list.get(slot).isEmpty()) {
|
||||
ItemStack itemStack = list.get(slot);
|
||||
list.set(slot, ItemStack.EMPTY);
|
||||
return itemStack;
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
return original.removeItemNoUpdate(realSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int slot, @Nonnull ItemStack stack) {
|
||||
Pair<NonNullList<ItemStack>, Integer> pair = getItemSlot(slot);
|
||||
NonNullList<ItemStack> list = null;
|
||||
if (pair != null) {
|
||||
list = pair.getFirst();
|
||||
slot = pair.getSecond();
|
||||
}
|
||||
if (list != null) {
|
||||
list.set(slot, stack);
|
||||
player.detectEquipmentUpdatesPublic();
|
||||
int realSlot = convertSlot(slot);
|
||||
if (realSlot == -999) {
|
||||
// Don't modify buttons
|
||||
return;
|
||||
}
|
||||
original.setItem(realSlot, stack);
|
||||
player.detectEquipmentUpdates();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,27 +122,4 @@ public class BotInventoryContainer extends SimpleContainer {
|
||||
}
|
||||
return !(player.distanceToSqr(this.player) > 64.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearContent() {
|
||||
for (List<ItemStack> list : this.compartments) {
|
||||
list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void createButton() {
|
||||
CompoundTag customData = new CompoundTag();
|
||||
customData.putBoolean("Leaves.Gui.Placeholder", true);
|
||||
|
||||
DataComponentPatch patch = DataComponentPatch.builder()
|
||||
.set(DataComponents.CUSTOM_NAME, Component.empty())
|
||||
.set(DataComponents.CUSTOM_DATA, CustomData.of(customData))
|
||||
.build();
|
||||
|
||||
for (int i = 0; i < 13; i++) {
|
||||
ItemStack button = new ItemStack(Items.STRUCTURE_VOID);
|
||||
button.applyComponents(patch);
|
||||
buttons.set(i, button);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.LeavesConfig;
|
||||
import org.leavesmc.leaves.bot.agent.Configs;
|
||||
import org.leavesmc.leaves.event.bot.BotCreateEvent;
|
||||
import org.leavesmc.leaves.event.bot.BotJoinEvent;
|
||||
import org.leavesmc.leaves.event.bot.BotLoadEvent;
|
||||
@@ -60,7 +59,7 @@ public class BotList {
|
||||
|
||||
public ServerBot createNewBot(BotCreateState state) {
|
||||
BotCreateEvent event = new BotCreateEvent(state.name(), state.skinName(), state.location(), state.createReason(), state.creator());
|
||||
event.setCancelled(!isCreateLegal(state.name()));
|
||||
event.setCancelled(!BotUtil.isCreateLegal(state.name()));
|
||||
this.server.server.getPluginManager().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
@@ -100,10 +99,11 @@ public class BotList {
|
||||
if (optional.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
CompoundTag nbt = optional.get();
|
||||
|
||||
ResourceKey<Level> resourcekey = null;
|
||||
if (optional.get().contains("WorldUUIDMost") && optional.get().contains("WorldUUIDLeast")) {
|
||||
org.bukkit.World bWorld = Bukkit.getServer().getWorld(new UUID(optional.get().getLong("WorldUUIDMost"), optional.get().getLong("WorldUUIDLeast")));
|
||||
if (nbt.contains("WorldUUIDMost") && nbt.contains("WorldUUIDLeast")) {
|
||||
org.bukkit.World bWorld = Bukkit.getServer().getWorld(new UUID(nbt.getLong("WorldUUIDMost").orElseThrow(), nbt.getLong("WorldUUIDLeast").orElseThrow()));
|
||||
if (bWorld != null) {
|
||||
resourcekey = ((CraftWorld) bWorld).getHandle().dimension();
|
||||
}
|
||||
@@ -113,11 +113,11 @@ public class BotList {
|
||||
}
|
||||
|
||||
ServerLevel world = this.server.getLevel(resourcekey);
|
||||
return this.placeNewBot(bot, world, bot.getLocation(), optional.get());
|
||||
return this.placeNewBot(bot, world, bot.getLocation(), nbt);
|
||||
}
|
||||
|
||||
public ServerBot placeNewBot(ServerBot bot, ServerLevel world, Location location, @Nullable CompoundTag nbt) {
|
||||
Optional<CompoundTag> optional = Optional.ofNullable(nbt);
|
||||
public ServerBot placeNewBot(@NotNull ServerBot bot, ServerLevel world, Location location, @Nullable CompoundTag save) {
|
||||
Optional<CompoundTag> optional = Optional.ofNullable(save);
|
||||
|
||||
bot.isRealPlayer = true;
|
||||
bot.loginTime = System.currentTimeMillis();
|
||||
@@ -142,8 +142,10 @@ public class BotList {
|
||||
|
||||
bot.supressTrackerForLogin = true;
|
||||
world.addNewPlayer(bot);
|
||||
bot.loadAndSpawnEnderpearls(optional);
|
||||
bot.loadAndSpawnParentVehicle(optional);
|
||||
optional.ifPresent(nbt -> {
|
||||
bot.loadAndSpawnEnderPearls(nbt);
|
||||
bot.loadAndSpawnParentVehicle(nbt);
|
||||
});
|
||||
|
||||
BotJoinEvent event1 = new BotJoinEvent(bot.getBukkitEntity(), PaperAdventure.asAdventure(Component.translatable("multiplayer.player.joined", bot.getDisplayName())).style(Style.style(NamedTextColor.YELLOW)));
|
||||
this.server.server.getPluginManager().callEvent(event1);
|
||||
@@ -178,17 +180,13 @@ public class BotList {
|
||||
bot.removeTaskId = -1;
|
||||
}
|
||||
|
||||
if (this.server.isSameThread()) {
|
||||
bot.doTick();
|
||||
}
|
||||
|
||||
if (event.shouldSave()) {
|
||||
playerIO.save(bot);
|
||||
} else {
|
||||
bot.dropAll();
|
||||
bot.dropAll(true);
|
||||
}
|
||||
|
||||
if (bot.isPassenger()) {
|
||||
if (bot.isPassenger() && event.shouldSave()) {
|
||||
Entity entity = bot.getRootVehicle();
|
||||
if (entity.hasExactlyOnePlayerPassenger()) {
|
||||
bot.stopRiding();
|
||||
@@ -217,7 +215,7 @@ public class BotList {
|
||||
|
||||
bot.removeTab();
|
||||
for (ServerPlayer player : bot.serverLevel().players()) {
|
||||
if (!(player instanceof ServerBot) && !bot.needSendFakeData(player)) {
|
||||
if (!(player instanceof ServerBot)) {
|
||||
player.connection.send(new ClientboundRemoveEntitiesPacket(bot.getId()));
|
||||
}
|
||||
}
|
||||
@@ -239,9 +237,9 @@ public class BotList {
|
||||
public void loadResume() {
|
||||
if (LeavesConfig.modify.fakeplayer.enable && LeavesConfig.modify.fakeplayer.canResident) {
|
||||
CompoundTag savedBotList = this.getSavedBotList().copy();
|
||||
for (String realName : savedBotList.getAllKeys()) {
|
||||
CompoundTag nbt = savedBotList.getCompound(realName);
|
||||
if (nbt.getBoolean("resume")) {
|
||||
for (String realName : savedBotList.keySet()) {
|
||||
CompoundTag nbt = savedBotList.getCompound(realName).orElseThrow();
|
||||
if (nbt.getBoolean("resume").orElse(false)) {
|
||||
this.loadNewBot(realName);
|
||||
}
|
||||
}
|
||||
@@ -249,7 +247,7 @@ public class BotList {
|
||||
}
|
||||
|
||||
public void networkTick() {
|
||||
this.bots.stream().filter(bot -> bot.getConfigValue(Configs.TICK_TYPE) == ServerBot.TickType.NETWORK).forEach(ServerBot::doTick); // TODO perf?
|
||||
this.bots.forEach(ServerBot::networkTick);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -266,22 +264,6 @@ public class BotList {
|
||||
return this.dataStorage.getSavedBotList();
|
||||
}
|
||||
|
||||
public boolean isCreateLegal(@NotNull String name) {
|
||||
if (!name.matches("^[a-zA-Z0-9_]{4,16}$")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Bukkit.getPlayerExact(name) != null || this.getBotByName(name) != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LeavesConfig.modify.fakeplayer.unableNames.contains(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.bots.size() < LeavesConfig.modify.fakeplayer.limit;
|
||||
}
|
||||
|
||||
public static class CustomGameProfile extends GameProfile {
|
||||
|
||||
public CustomGameProfile(UUID uuid, String name, String[] skin) {
|
||||
|
||||
@@ -4,7 +4,9 @@ import com.google.common.base.Charsets;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.leavesmc.leaves.LeavesConfig;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -70,4 +72,24 @@ public class BotUtil {
|
||||
public static UUID getBotUUID(@NotNull String realName) {
|
||||
return UUID.nameUUIDFromBytes(("Fakeplayer:" + realName).getBytes(Charsets.UTF_8));
|
||||
}
|
||||
|
||||
public static String getFullName(String inputName) {
|
||||
return LeavesConfig.modify.fakeplayer.prefix + inputName + LeavesConfig.modify.fakeplayer.suffix;
|
||||
}
|
||||
|
||||
public static boolean isCreateLegal(@NotNull String name) {
|
||||
if (!name.matches("^[a-zA-Z0-9_]{4,16}$")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Bukkit.getPlayerExact(name) != null || BotList.INSTANCE.getBotByName(name) != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LeavesConfig.modify.fakeplayer.unableNames.contains(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return BotList.INSTANCE.bots.size() < LeavesConfig.modify.fakeplayer.limit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.core.particles.BlockParticleOption;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@@ -14,6 +15,7 @@ import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ClientInformation;
|
||||
@@ -35,6 +37,7 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.ChestMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import net.minecraft.world.level.portal.TeleportTransition;
|
||||
@@ -99,7 +102,7 @@ public class ServerBot extends ServerPlayer {
|
||||
this.configs = configBuilder.build();
|
||||
|
||||
this.stats = new BotStatsCounter(server);
|
||||
this.container = new BotInventoryContainer(this);
|
||||
this.container = new BotInventoryContainer(this.getInventory());
|
||||
this.tracingRange = world.spigotConfig.playerTrackingRange * world.spigotConfig.playerTrackingRange;
|
||||
|
||||
this.notSleepTicks = 0;
|
||||
@@ -130,7 +133,7 @@ public class ServerBot extends ServerPlayer {
|
||||
// copy ServerPlayer end
|
||||
|
||||
if (this.getConfigValue(Configs.SPAWN_PHANTOM)) {
|
||||
notSleepTicks++;
|
||||
this.notSleepTicks++;
|
||||
}
|
||||
|
||||
if (LeavesConfig.modify.fakeplayer.regenAmount > 0.0 && server.getTickCount() % 20 == 0) {
|
||||
@@ -155,7 +158,12 @@ public class ServerBot extends ServerPlayer {
|
||||
|
||||
@Override
|
||||
public void doTick() {
|
||||
this.absMoveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
|
||||
if (!this.isAlive()) {
|
||||
this.die(this.damageSources().generic());
|
||||
return;
|
||||
}
|
||||
|
||||
this.absSnapTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
|
||||
|
||||
if (this.isPassenger()) {
|
||||
this.setOnGround(false);
|
||||
@@ -172,7 +180,7 @@ public class ServerBot extends ServerPlayer {
|
||||
this.notSleepTicks = 0;
|
||||
}
|
||||
|
||||
if (!this.level().isClientSide && this.level().isDay()) {
|
||||
if (!this.level().isClientSide && this.level().isBrightOutside()) {
|
||||
this.stopSleepInBed(false, true);
|
||||
}
|
||||
} else if (this.sleepCounter > 0) {
|
||||
@@ -212,27 +220,56 @@ public class ServerBot extends ServerPlayer {
|
||||
this.updatePlayerPose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ServerBot teleport(@NotNull TeleportTransition teleportTarget) {
|
||||
if (this.isSleeping() || this.isRemoved()) {
|
||||
return null;
|
||||
}
|
||||
if (teleportTarget.newLevel().dimension() != this.serverLevel().dimension()) {
|
||||
return null;
|
||||
} else {
|
||||
if (!teleportTarget.asPassenger()) {
|
||||
this.stopRiding();
|
||||
}
|
||||
|
||||
this.connection.internalTeleport(PositionMoveRotation.of(teleportTarget), teleportTarget.relatives());
|
||||
this.connection.resetPosition();
|
||||
teleportTarget.postTeleportTransition().onTransition(this);
|
||||
return this;
|
||||
public void networkTick() {
|
||||
if (this.getConfigValue(Configs.TICK_TYPE) == TickType.NETWORK) {
|
||||
this.doTick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePortal() {
|
||||
public @Nullable ServerBot teleport(@NotNull TeleportTransition teleportTransition) {
|
||||
if (this.isSleeping() || this.isRemoved()) {
|
||||
return null;
|
||||
}
|
||||
if (!teleportTransition.asPassenger()) {
|
||||
this.removeVehicle();
|
||||
}
|
||||
|
||||
ServerLevel fromLevel = this.serverLevel();
|
||||
ServerLevel toLevel = teleportTransition.newLevel();
|
||||
|
||||
if (toLevel.dimension() == fromLevel.dimension()) {
|
||||
this.teleportSetPosition(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives());
|
||||
teleportTransition.postTeleportTransition().onTransition(this);
|
||||
return this;
|
||||
} else {
|
||||
this.isChangingDimension = true;
|
||||
fromLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
|
||||
this.unsetRemoved();
|
||||
this.setServerLevel(toLevel);
|
||||
this.teleportSetPosition(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives());
|
||||
toLevel.addDuringTeleport(this);
|
||||
this.stopUsingItem();
|
||||
teleportTransition.postTeleportTransition().onTransition(this);
|
||||
this.isChangingDimension = false;
|
||||
|
||||
if (org.leavesmc.leaves.LeavesConfig.modify.netherPortalFix) {
|
||||
final ResourceKey<Level> fromDim = fromLevel.dimension();
|
||||
final ResourceKey<Level> toDim = level().dimension();
|
||||
if (!((fromDim != Level.OVERWORLD || toDim != Level.NETHER) && (fromDim != Level.NETHER || toDim != Level.OVERWORLD))) {
|
||||
BlockPos fromPortal = org.leavesmc.leaves.util.ReturnPortalManager.findPortalAt(this, fromDim, lastPos);
|
||||
BlockPos toPos = this.blockPosition();
|
||||
if (fromPortal != null) {
|
||||
org.leavesmc.leaves.util.ReturnPortalManager.storeReturnPortal(this, toDim, toPos, fromPortal);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.isBlocking()) {
|
||||
this.stopUsingItem();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -245,12 +282,12 @@ public class ServerBot extends ServerPlayer {
|
||||
ItemStack item = this.getItemInHand(hand);
|
||||
|
||||
if (!item.isEmpty()) {
|
||||
BotUtil.replenishment(item, getInventory().items);
|
||||
BotUtil.replenishment(item, getInventory().getNonEquipmentItems());
|
||||
if (BotUtil.isDamage(item, 10)) {
|
||||
BotUtil.replaceTool(hand == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND, this);
|
||||
}
|
||||
}
|
||||
this.detectEquipmentUpdatesPublic();
|
||||
this.detectEquipmentUpdates();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -271,6 +308,9 @@ public class ServerBot extends ServerPlayer {
|
||||
@Override
|
||||
public void checkFallDamage(double y, boolean onGround, @NotNull BlockState state, @NotNull BlockPos pos) {
|
||||
ServerLevel serverLevel = this.serverLevel();
|
||||
if (!this.isInWater() && y < 0.0) {
|
||||
this.fallDistance -= (float) y;
|
||||
}
|
||||
if (onGround && this.fallDistance > 0.0F) {
|
||||
this.onChangedBlock(serverLevel, pos);
|
||||
double attributeValue = this.getAttributeValue(Attributes.SAFE_FALL_DISTANCE);
|
||||
@@ -354,21 +394,21 @@ public class ServerBot extends ServerPlayer {
|
||||
@Override
|
||||
public void readAdditionalSaveData(@NotNull CompoundTag nbt) {
|
||||
super.readAdditionalSaveData(nbt);
|
||||
this.setShiftKeyDown(nbt.getBoolean("isShiftKeyDown"));
|
||||
this.setShiftKeyDown(nbt.getBoolean("isShiftKeyDown").orElse(false));
|
||||
|
||||
CompoundTag createNbt = nbt.getCompound("createStatus");
|
||||
BotCreateState.Builder createBuilder = BotCreateState.builder(createNbt.getString("realName"), null).name(createNbt.getString("name"));
|
||||
CompoundTag createNbt = nbt.getCompound("createStatus").orElseThrow();
|
||||
BotCreateState.Builder createBuilder = BotCreateState.builder(createNbt.getString("realName").orElseThrow(), null).name(createNbt.getString("name").orElseThrow());
|
||||
|
||||
String[] skin = null;
|
||||
if (createNbt.contains("skin")) {
|
||||
ListTag skinTag = createNbt.getList("skin", 8);
|
||||
ListTag skinTag = createNbt.getList("skin").orElseThrow();
|
||||
skin = new String[skinTag.size()];
|
||||
for (int i = 0; i < skinTag.size(); i++) {
|
||||
skin[i] = skinTag.getString(i);
|
||||
skin[i] = skinTag.getString(i).orElseThrow();
|
||||
}
|
||||
}
|
||||
|
||||
createBuilder.skinName(createNbt.getString("skinName")).skin(skin);
|
||||
createBuilder.skinName(createNbt.getString("skinName").orElseThrow()).skin(skin);
|
||||
createBuilder.createReason(BotCreateEvent.CreateReason.INTERNAL).creator(null);
|
||||
|
||||
this.createState = createBuilder.build();
|
||||
@@ -376,10 +416,10 @@ public class ServerBot extends ServerPlayer {
|
||||
|
||||
|
||||
if (nbt.contains("actions")) {
|
||||
ListTag actionNbt = nbt.getList("actions", 10);
|
||||
ListTag actionNbt = nbt.getList("actions").orElseThrow();
|
||||
for (int i = 0; i < actionNbt.size(); i++) {
|
||||
CompoundTag actionTag = actionNbt.getCompound(i);
|
||||
AbstractBotAction<?> action = Actions.getForName(actionTag.getString("actionName"));
|
||||
CompoundTag actionTag = actionNbt.getCompound(i).orElseThrow();
|
||||
AbstractBotAction<?> action = Actions.getForName(actionTag.getString("actionName").orElseThrow());
|
||||
if (action != null) {
|
||||
AbstractBotAction<?> newAction = action.create();
|
||||
newAction.load(actionTag);
|
||||
@@ -389,10 +429,10 @@ public class ServerBot extends ServerPlayer {
|
||||
}
|
||||
|
||||
if (nbt.contains("configs")) {
|
||||
ListTag configNbt = nbt.getList("configs", 10);
|
||||
ListTag configNbt = nbt.getList("configs").orElseThrow();
|
||||
for (int i = 0; i < configNbt.size(); i++) {
|
||||
CompoundTag configTag = configNbt.getCompound(i);
|
||||
Configs<?> configKey = Configs.getConfig(configTag.getString("configName"));
|
||||
CompoundTag configTag = configNbt.getCompound(i).orElseThrow();
|
||||
Configs<?> configKey = Configs.getConfig(configTag.getString("configName").orElseThrow());
|
||||
if (configKey != null) {
|
||||
this.configs.get(configKey).load(configTag);
|
||||
}
|
||||
@@ -400,6 +440,11 @@ public class ServerBot extends ServerPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClientAuthoritative() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void sendPlayerInfo(ServerPlayer player) {
|
||||
player.connection.send(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME), List.of(this)));
|
||||
}
|
||||
@@ -510,9 +555,23 @@ public class ServerBot extends ServerPlayer {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void dropAll() {
|
||||
this.getInventory().dropAll();
|
||||
this.detectEquipmentUpdatesPublic();
|
||||
public void dropAll(boolean death) {
|
||||
NonNullList<ItemStack> items = this.getInventory().getNonEquipmentItems();
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
ItemStack itemStack = items.get(i);
|
||||
if (!itemStack.isEmpty()) {
|
||||
this.drop(itemStack, death, false);
|
||||
items.set(i, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
for (EquipmentSlot slot : EquipmentSlot.values()) {
|
||||
ItemStack itemStack;
|
||||
if (!(itemStack = this.equipment.get(slot)).isEmpty()) {
|
||||
this.drop(itemStack, death, false);
|
||||
this.equipment.set(slot, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
this.detectEquipmentUpdates();
|
||||
}
|
||||
|
||||
private void runAction() {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package org.leavesmc.leaves.bot.agent;
|
||||
|
||||
import net.minecraft.core.UUIDUtil;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.bot.ServerBot;
|
||||
@@ -12,21 +15,24 @@ import org.leavesmc.leaves.event.bot.BotActionStopEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
//TODO onStop for fully terminate action (use, etc.)
|
||||
public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
|
||||
|
||||
private final String name;
|
||||
private final CommandArgument argument;
|
||||
private final Supplier<E> creator;
|
||||
|
||||
private boolean cancel;
|
||||
private int tickDelay;
|
||||
private int number;
|
||||
private UUID uuid;
|
||||
|
||||
private int needWaitTick;
|
||||
private int canDoNumber;
|
||||
private int initialTickDelay;
|
||||
private int initialTickInterval;
|
||||
private int initialNumber;
|
||||
|
||||
private int tickToNext;
|
||||
private int numberRemaining;
|
||||
private boolean cancel;
|
||||
|
||||
public AbstractBotAction(String name, CommandArgument argument, Supplier<E> creator) {
|
||||
this.name = name;
|
||||
@@ -35,16 +41,98 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
|
||||
this.creator = creator;
|
||||
|
||||
this.cancel = false;
|
||||
this.tickDelay = 20;
|
||||
this.number = -1;
|
||||
this.initialTickInterval = 20;
|
||||
this.initialNumber = -1;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
this.needWaitTick = 0;
|
||||
this.canDoNumber = this.getNumber();
|
||||
this.tickToNext = initialTickDelay;
|
||||
this.numberRemaining = this.getInitialNumber();
|
||||
this.setCancelled(false);
|
||||
}
|
||||
|
||||
public void tryTick(ServerBot bot) {
|
||||
if (this.numberRemaining == 0) {
|
||||
this.stop(bot, BotActionStopEvent.Reason.DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.tickToNext <= 0) {
|
||||
BotActionExecuteEvent event = new BotActionExecuteEvent(bot.getBukkitEntity(), name, uuid);
|
||||
|
||||
event.callEvent();
|
||||
if (event.getResult() == BotActionExecuteEvent.Result.SOFT_CANCEL) {
|
||||
this.tickToNext = this.getInitialTickInterval() - 1;
|
||||
return;
|
||||
} else if (event.getResult() == BotActionExecuteEvent.Result.HARD_CANCEL) {
|
||||
if (this.numberRemaining > 0) {
|
||||
this.numberRemaining--;
|
||||
}
|
||||
this.tickToNext = this.getInitialTickInterval() - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.doTick(bot)) {
|
||||
if (this.numberRemaining > 0) {
|
||||
this.numberRemaining--;
|
||||
}
|
||||
this.tickToNext = this.getInitialTickInterval() - 1;
|
||||
}
|
||||
} else {
|
||||
this.tickToNext--;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CompoundTag save(@NotNull CompoundTag nbt) {
|
||||
if (!this.cancel) {
|
||||
nbt.putString("actionName", this.name);
|
||||
nbt.store("actionUUID", UUIDUtil.CODEC, this.uuid);
|
||||
|
||||
nbt.putInt("initialTickDelay", this.initialTickDelay);
|
||||
nbt.putInt("initialTickInterval", this.initialTickInterval);
|
||||
nbt.putInt("initialNumber", this.initialNumber);
|
||||
|
||||
nbt.putInt("tickToNext", this.tickToNext);
|
||||
nbt.putInt("numberRemaining", this.numberRemaining);
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
this.uuid = nbt.read("actionUUID", UUIDUtil.CODEC).orElse(UUID.randomUUID());
|
||||
|
||||
this.initialTickDelay = nbt.getInt("initialTickDelay").orElse(0);
|
||||
this.initialTickInterval = nbt.getInt("initialTickInterval").orElse(0);
|
||||
this.initialNumber = nbt.getInt("initialNumber").orElse(0);
|
||||
|
||||
this.tickToNext = nbt.getInt("tickToNext").orElse(0);
|
||||
this.numberRemaining = nbt.getInt("numberRemaining").orElse(0);
|
||||
}
|
||||
|
||||
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
|
||||
new BotActionStopEvent(bot.getBukkitEntity(), this.name, this.uuid, reason, null).callEvent();
|
||||
this.setCancelled(true);
|
||||
}
|
||||
|
||||
public abstract void loadCommand(@Nullable ServerPlayer player, @NotNull CommandArgumentResult result);
|
||||
|
||||
public abstract boolean doTick(@NotNull ServerBot bot);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public E setSuggestion(int n, BiFunction<CommandSender, String, Pair<List<String>, String>> suggestion) {
|
||||
this.argument.setSuggestion(n, suggestion);
|
||||
return (E) this;
|
||||
}
|
||||
|
||||
public E setSuggestion(int n, Pair<List<String>, String> suggestion) {
|
||||
return this.setSuggestion(n, (sender, arg) -> suggestion);
|
||||
}
|
||||
|
||||
public E setSuggestion(int n, List<String> tabComplete) {
|
||||
return this.setSuggestion(n, Pair.of(tabComplete, null));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
@@ -53,28 +141,42 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public int getTickDelay() {
|
||||
return this.tickDelay;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public E setTickDelay(int tickDelay) {
|
||||
this.tickDelay = Math.max(0, tickDelay);
|
||||
public E setInitialTickDelay(int initialTickDelay) {
|
||||
this.initialTickDelay = initialTickDelay;
|
||||
return (E) this;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return this.number;
|
||||
public int getInitialTickDelay() {
|
||||
return this.initialTickDelay;
|
||||
}
|
||||
|
||||
public int getInitialTickInterval() {
|
||||
return this.initialTickInterval;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public E setNumber(int number) {
|
||||
this.number = Math.max(-1, number);
|
||||
public E setInitialTickInterval(int initialTickInterval) {
|
||||
this.initialTickInterval = Math.max(1, initialTickInterval);
|
||||
return (E) this;
|
||||
}
|
||||
|
||||
public int getCanDoNumber() {
|
||||
return this.canDoNumber;
|
||||
public int getInitialNumber() {
|
||||
return this.initialNumber;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public E setInitialNumber(int initialNumber) {
|
||||
this.initialNumber = Math.max(-1, initialNumber);
|
||||
return (E) this;
|
||||
}
|
||||
|
||||
public int getTickToNext() {
|
||||
return this.tickToNext;
|
||||
}
|
||||
|
||||
public int getNumberRemaining() {
|
||||
return this.numberRemaining;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
@@ -85,79 +187,12 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
|
||||
this.cancel = cancel;
|
||||
}
|
||||
|
||||
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
|
||||
new BotActionStopEvent(bot.getBukkitEntity(), this.name, this.uuid, reason, null).callEvent();
|
||||
this.setCancelled(true);
|
||||
}
|
||||
|
||||
public CommandArgument getArgument() {
|
||||
return this.argument;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public E setTabComplete(int index, List<String> list) {
|
||||
this.argument.setTabComplete(index, list);
|
||||
return (E) this;
|
||||
}
|
||||
|
||||
public void tryTick(ServerBot bot) {
|
||||
if (this.canDoNumber == 0) {
|
||||
this.stop(bot, BotActionStopEvent.Reason.DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.needWaitTick <= 0) {
|
||||
BotActionExecuteEvent event = new BotActionExecuteEvent(bot.getBukkitEntity(), name, uuid);
|
||||
|
||||
event.callEvent();
|
||||
if (event.getResult() == BotActionExecuteEvent.Result.SOFT_CANCEL) {
|
||||
this.needWaitTick = this.getTickDelay();
|
||||
return;
|
||||
} else if (event.getResult() == BotActionExecuteEvent.Result.HARD_CANCEL) {
|
||||
if (this.canDoNumber > 0) {
|
||||
this.canDoNumber--;
|
||||
}
|
||||
this.needWaitTick = this.getTickDelay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.doTick(bot)) {
|
||||
if (this.canDoNumber > 0) {
|
||||
this.canDoNumber--;
|
||||
}
|
||||
this.needWaitTick = this.getTickDelay();
|
||||
}
|
||||
} else {
|
||||
this.needWaitTick--;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public E create() {
|
||||
return this.creator.get();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CompoundTag save(@NotNull CompoundTag nbt) {
|
||||
if (!this.cancel) {
|
||||
nbt.putString("actionName", this.name);
|
||||
nbt.putUUID("actionUUID", this.uuid);
|
||||
|
||||
nbt.putInt("canDoNumber", this.canDoNumber);
|
||||
nbt.putInt("needWaitTick", this.needWaitTick);
|
||||
nbt.putInt("tickDelay", this.tickDelay);
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
this.tickDelay = nbt.getInt("tickDelay");
|
||||
this.needWaitTick = nbt.getInt("needWaitTick");
|
||||
this.canDoNumber = nbt.getInt("canDoNumber");
|
||||
this.uuid = nbt.getUUID("actionUUID");
|
||||
}
|
||||
|
||||
public abstract void loadCommand(@Nullable ServerPlayer player, @NotNull CommandArgumentResult result);
|
||||
|
||||
public abstract boolean doTick(@NotNull ServerBot bot);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public class Actions {
|
||||
register(new UseItemOnOffhandAction());
|
||||
register(new UseItemToOffhandAction());
|
||||
register(new RotationAction());
|
||||
register(new ShootAction());
|
||||
}
|
||||
|
||||
public static boolean register(@NotNull AbstractBotAction<?> action) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.leavesmc.leaves.bot.agent.actions;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.bot.agent.AbstractBotAction;
|
||||
@@ -8,18 +9,25 @@ import org.leavesmc.leaves.command.CommandArgument;
|
||||
import org.leavesmc.leaves.command.CommandArgumentResult;
|
||||
import org.leavesmc.leaves.command.CommandArgumentType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class AbstractTimerAction<E extends AbstractTimerAction<E>> extends AbstractBotAction<E> {
|
||||
|
||||
public AbstractTimerAction(String name, Supplier<E> creator) {
|
||||
super(name, CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), creator);
|
||||
this.setTabComplete(0, List.of("[TickDelay]")).setTabComplete(1, List.of("[DoNumber]"));
|
||||
this(name, CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), creator);
|
||||
}
|
||||
|
||||
public AbstractTimerAction(String name, CommandArgument argument, Supplier<E> creator) {
|
||||
super(name, argument, creator);
|
||||
this.setSuggestion(0, Pair.of(Collections.singletonList("0"), "[TickDelay]"));
|
||||
this.setSuggestion(1, Pair.of(Collections.singletonList("20"), "[TickInterval]"));
|
||||
this.setSuggestion(2, Pair.of(List.of("1", "-1"), "[DoNumber]"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCommand(@Nullable ServerPlayer player, @NotNull CommandArgumentResult result) {
|
||||
this.setTickDelay(result.readInt(20)).setNumber(result.readInt(-1));
|
||||
this.setInitialTickDelay(result.readInt(0)).setInitialTickInterval(result.readInt(20)).setInitialNumber(result.readInt(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class CraftBotAction extends LeavesBotAction {
|
||||
private final AbstractBotAction<?> handle;
|
||||
|
||||
public CraftBotAction(@NotNull AbstractBotAction<?> action) {
|
||||
super(BotActionType.valueOf(action.getName()), action.getTickDelay(), action.getCanDoNumber());
|
||||
super(BotActionType.valueOf(action.getName()), action.getInitialTickInterval(), action.getNumberRemaining());
|
||||
this.handle = action;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class CraftBotAction extends LeavesBotAction {
|
||||
}
|
||||
|
||||
AbstractBotAction<?> newAction = null;
|
||||
String[] args = new String[]{String.valueOf(action.getExecuteInterval()), String.valueOf(action.getRemainingExecuteTime())};
|
||||
String[] args = new String[]{String.valueOf(action.getInitialTickDelay()), String.valueOf(action.getInitialTickInterval()), String.valueOf(action.getInitialNumber())};
|
||||
try {
|
||||
if (act instanceof CraftCustomBotAction customBotAction) {
|
||||
newAction = customBotAction.createCraft(action.getActionPlayer(), args);
|
||||
|
||||
@@ -15,7 +15,7 @@ public class CraftCustomBotAction extends AbstractBotAction<CraftCustomBotAction
|
||||
private final CustomBotAction realAction;
|
||||
|
||||
public CraftCustomBotAction(String name, @NotNull CustomBotAction realAction) {
|
||||
super(name, CommandArgument.of().setAllTabComplete(realAction.getTabComplete()), null);
|
||||
super(name, CommandArgument.EMPTY, null);
|
||||
this.realAction = realAction;
|
||||
}
|
||||
|
||||
@@ -33,13 +33,18 @@ public class CraftCustomBotAction extends AbstractBotAction<CraftCustomBotAction
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumber() {
|
||||
return realAction.getNumber();
|
||||
public int getInitialNumber() {
|
||||
return realAction.getInitialNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTickDelay() {
|
||||
return realAction.getTickDelay();
|
||||
public int getInitialTickDelay() {
|
||||
return realAction.getInitialTickDelay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInitialTickInterval() {
|
||||
return realAction.getInitialTickInterval();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package org.leavesmc.leaves.bot.agent.actions;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.bot.ServerBot;
|
||||
import org.leavesmc.leaves.command.CommandArgumentResult;
|
||||
|
||||
public class DropAction extends AbstractTimerAction<DropAction> {
|
||||
|
||||
@@ -12,14 +9,9 @@ public class DropAction extends AbstractTimerAction<DropAction> {
|
||||
super("drop", DropAction::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCommand(@Nullable ServerPlayer player, @NotNull CommandArgumentResult result) {
|
||||
this.setTickDelay(result.readInt(100)).setNumber(result.readInt(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doTick(@NotNull ServerBot bot) {
|
||||
bot.dropAll();
|
||||
bot.dropAll(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,15 @@ public class FishAction extends AbstractTimerAction<FishAction> {
|
||||
super("fish", FishAction::new);
|
||||
}
|
||||
|
||||
private int delay = 0;
|
||||
private int nowDelay = 0;
|
||||
private static final int CATCH_ENTITY_DELAY = 20;
|
||||
|
||||
private int initialFishInterval = 0;
|
||||
private int tickToNextFish = 0;
|
||||
|
||||
@Override
|
||||
public FishAction setTickDelay(int tickDelay) {
|
||||
super.setTickDelay(0);
|
||||
this.delay = tickDelay;
|
||||
public FishAction setInitialTickInterval(int initialTickInterval) {
|
||||
super.setInitialTickInterval(1);
|
||||
this.initialFishInterval = initialTickInterval;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -28,22 +30,22 @@ public class FishAction extends AbstractTimerAction<FishAction> {
|
||||
@NotNull
|
||||
public CompoundTag save(@NotNull CompoundTag nbt) {
|
||||
super.save(nbt);
|
||||
nbt.putInt("fishDelay", this.delay);
|
||||
nbt.putInt("fishNowDelay", this.nowDelay);
|
||||
nbt.putInt("initialFishInterval", this.initialFishInterval);
|
||||
nbt.putInt("tickToNextFish", this.tickToNextFish);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
this.delay = nbt.getInt("fishDelay");
|
||||
this.nowDelay = nbt.getInt("fishNowDelay");
|
||||
this.initialFishInterval = nbt.getInt("initialFishInterval").orElseThrow();
|
||||
this.tickToNextFish = nbt.getInt("tickToNextFish").orElseThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doTick(@NotNull ServerBot bot) {
|
||||
if (this.nowDelay > 0) {
|
||||
this.nowDelay--;
|
||||
if (this.tickToNextFish > 0) {
|
||||
this.tickToNextFish--;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -56,12 +58,12 @@ public class FishAction extends AbstractTimerAction<FishAction> {
|
||||
if (fishingHook != null) {
|
||||
if (fishingHook.currentState == FishingHook.FishHookState.HOOKED_IN_ENTITY) {
|
||||
mainHand.use(bot.level(), bot, InteractionHand.MAIN_HAND);
|
||||
this.nowDelay = 20;
|
||||
this.tickToNextFish = CATCH_ENTITY_DELAY;
|
||||
return false;
|
||||
}
|
||||
if (fishingHook.nibble > 0) {
|
||||
mainHand.use(bot.level(), bot, InteractionHand.MAIN_HAND);
|
||||
this.nowDelay = this.delay;
|
||||
this.tickToNextFish = this.initialFishInterval - 1;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.leavesmc.leaves.bot.agent.actions;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -11,15 +12,18 @@ import org.leavesmc.leaves.command.CommandArgument;
|
||||
import org.leavesmc.leaves.command.CommandArgumentResult;
|
||||
import org.leavesmc.leaves.command.CommandArgumentType;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.List;
|
||||
|
||||
public class LookAction extends AbstractBotAction<LookAction> {
|
||||
|
||||
private static final DecimalFormat DF = new DecimalFormat("0.0");
|
||||
|
||||
public LookAction() {
|
||||
super("look", CommandArgument.of(CommandArgumentType.DOUBLE, CommandArgumentType.DOUBLE, CommandArgumentType.DOUBLE), LookAction::new);
|
||||
this.setTabComplete(0, List.of("<X>"));
|
||||
this.setTabComplete(1, List.of("<Y>"));
|
||||
this.setTabComplete(2, List.of("<Z>"));
|
||||
this.setSuggestion(0, (sender, arg) -> sender instanceof ServerPlayer player ? Pair.of(List.of(DF.format(player.getX())), "<X>") : Pair.of(List.of("0"), "<X>"));
|
||||
this.setSuggestion(1, (sender, arg) -> sender instanceof ServerPlayer player ? Pair.of(List.of(DF.format(player.getY())), "<Y>") : Pair.of(List.of("0"), "<Y>"));
|
||||
this.setSuggestion(2, (sender, arg) -> sender instanceof ServerPlayer player ? Pair.of(List.of(DF.format(player.getZ())), "<Z>") : Pair.of(List.of("0"), "<Z>"));
|
||||
}
|
||||
|
||||
private Vector pos;
|
||||
@@ -28,7 +32,7 @@ public class LookAction extends AbstractBotAction<LookAction> {
|
||||
public void loadCommand(@Nullable ServerPlayer player, @NotNull CommandArgumentResult result) throws IllegalArgumentException {
|
||||
Vector pos = result.readVector();
|
||||
if (pos != null) {
|
||||
this.setPos(pos).setTickDelay(0).setNumber(1);
|
||||
this.setPos(pos).setInitialTickDelay(0).setInitialTickInterval(1).setInitialNumber(1);
|
||||
} else {
|
||||
throw new IllegalArgumentException("pos?");
|
||||
}
|
||||
@@ -47,7 +51,13 @@ public class LookAction extends AbstractBotAction<LookAction> {
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
this.setPos(new Vector(nbt.getDouble("x"), nbt.getDouble("y"), nbt.getDouble("z")));
|
||||
this.setPos(
|
||||
new Vector(
|
||||
nbt.getDouble("x").orElse(0.0),
|
||||
nbt.getDouble("y").orElse(0.0),
|
||||
nbt.getDouble("z").orElse(0.0)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public LookAction setPos(Vector pos) {
|
||||
|
||||
@@ -19,7 +19,7 @@ public class RotateAction extends AbstractBotAction<RotateAction> {
|
||||
|
||||
@Override
|
||||
public void loadCommand(@Nullable ServerPlayer player, @NotNull CommandArgumentResult result) {
|
||||
this.setPlayer(player).setTickDelay(0).setNumber(1);
|
||||
this.setPlayer(player).setInitialTickDelay(0).setInitialTickInterval(1).setInitialNumber(1);
|
||||
}
|
||||
|
||||
public RotateAction setPlayer(ServerPlayer player) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.leavesmc.leaves.bot.agent.actions;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.bot.ServerBot;
|
||||
@@ -10,14 +11,17 @@ import org.leavesmc.leaves.command.CommandArgument;
|
||||
import org.leavesmc.leaves.command.CommandArgumentResult;
|
||||
import org.leavesmc.leaves.command.CommandArgumentType;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.List;
|
||||
|
||||
public class RotationAction extends AbstractBotAction<RotationAction> {
|
||||
|
||||
private static final DecimalFormat DF = new DecimalFormat("0.00");
|
||||
|
||||
public RotationAction() {
|
||||
super("rotation", CommandArgument.of(CommandArgumentType.FLOAT, CommandArgumentType.FLOAT), RotationAction::new);
|
||||
this.setTabComplete(0, List.of("<yaw>"));
|
||||
this.setTabComplete(1, List.of("<pitch>"));
|
||||
this.setSuggestion(0, (sender, arg) -> sender instanceof ServerPlayer player ? Pair.of(List.of(DF.format(player.getYRot())), "[yaw]") : Pair.of(List.of("0"), "<yaw>"));
|
||||
this.setSuggestion(0, (sender, arg) -> sender instanceof ServerPlayer player ? Pair.of(List.of(DF.format(player.getXRot())), "[pitch]") : Pair.of(List.of("0"), "<pitch>"));
|
||||
}
|
||||
|
||||
private float yaw;
|
||||
@@ -29,7 +33,7 @@ public class RotationAction extends AbstractBotAction<RotationAction> {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setYaw(result.readFloat(player.getYRot())).setPitch(result.readFloat(player.getXRot())).setTickDelay(0).setNumber(1);
|
||||
this.setYaw(result.readFloat(player.getYRot())).setPitch(result.readFloat(player.getXRot())).setInitialTickDelay(0).setInitialTickInterval(1).setInitialNumber(1);
|
||||
}
|
||||
|
||||
public RotationAction setYaw(float yaw) {
|
||||
@@ -54,7 +58,7 @@ public class RotationAction extends AbstractBotAction<RotationAction> {
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
this.setYaw(nbt.getFloat("yaw")).setPitch(nbt.getFloat("pitch"));
|
||||
this.setYaw(nbt.getFloat("yaw").orElseThrow()).setPitch(nbt.getFloat("pitch").orElseThrow());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package org.leavesmc.leaves.bot.agent.actions;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.bot.ServerBot;
|
||||
import org.leavesmc.leaves.command.CommandArgument;
|
||||
import org.leavesmc.leaves.command.CommandArgumentResult;
|
||||
import org.leavesmc.leaves.command.CommandArgumentType;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class ShootAction extends AbstractTimerAction<ShootAction> {
|
||||
|
||||
private int drawingTick;
|
||||
private int tickToRelease = -1;
|
||||
|
||||
public ShootAction() {
|
||||
super("shoot", CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), ShootAction::new);
|
||||
this.setSuggestion(3, Pair.of(Collections.singletonList("20"), "[DrawingTick]"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
tickToRelease = drawingTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doTick(@NotNull ServerBot bot) {
|
||||
if (!bot.getItemInHand(InteractionHand.MAIN_HAND).is(Items.BOW)) {
|
||||
return false;
|
||||
}
|
||||
tickToRelease--;
|
||||
if (tickToRelease >= 0) {
|
||||
bot.gameMode.useItem(bot, bot.level(), bot.getItemInHand(InteractionHand.MAIN_HAND), InteractionHand.MAIN_HAND).consumesAction();
|
||||
bot.updateItemInHand(InteractionHand.MAIN_HAND);
|
||||
return false;
|
||||
} else {
|
||||
bot.releaseUsingItem();
|
||||
tickToRelease = drawingTick;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCommand(@Nullable ServerPlayer player, @NotNull CommandArgumentResult result) {
|
||||
super.loadCommand(player, result);
|
||||
this.setDrawingTick(result.readInt(20));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CompoundTag save(@NotNull CompoundTag nbt) {
|
||||
super.save(nbt);
|
||||
nbt.putInt("drawingTick", this.drawingTick);
|
||||
nbt.putInt("tickToRelease", this.tickToRelease);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
this.drawingTick = nbt.getInt("drawingTick").orElseThrow();
|
||||
this.tickToRelease = nbt.getInt("tickToRelease").orElseThrow();
|
||||
}
|
||||
|
||||
public int getDrawingTick() {
|
||||
return drawingTick;
|
||||
}
|
||||
|
||||
public ShootAction setDrawingTick(int drawingTick) {
|
||||
this.drawingTick = drawingTick;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ public class SneakAction extends AbstractBotAction<SneakAction> {
|
||||
|
||||
@Override
|
||||
public void loadCommand(@Nullable ServerPlayer player, @NotNull CommandArgumentResult result) {
|
||||
this.setTickDelay(0).setNumber(1);
|
||||
this.setInitialTickDelay(0).setInitialTickInterval(1).setInitialNumber(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,7 +17,7 @@ public class SwimAction extends AbstractBotAction<SwimAction> {
|
||||
|
||||
@Override
|
||||
public void loadCommand(@Nullable ServerPlayer player, @NotNull CommandArgumentResult result) {
|
||||
this.setTickDelay(0).setNumber(-1);
|
||||
this.setInitialTickDelay(0).setInitialTickInterval(1).setInitialNumber(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,7 @@ public class AlwaysSendDataConfig extends AbstractBotConfig<Boolean> {
|
||||
private boolean value;
|
||||
|
||||
public AlwaysSendDataConfig() {
|
||||
super(NAME, CommandArgument.of(CommandArgumentType.BOOLEAN).setTabComplete(0, List.of("true", "false")));
|
||||
super(NAME, CommandArgument.of(CommandArgumentType.BOOLEAN).setSuggestion(0, List.of("true", "false")));
|
||||
this.value = LeavesConfig.modify.fakeplayer.canSendDataAlways;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,6 @@ public class AlwaysSendDataConfig extends AbstractBotConfig<Boolean> {
|
||||
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
this.setValue(nbt.getBoolean(NAME));
|
||||
this.setValue(nbt.getBoolean(NAME).orElseThrow());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.leavesmc.leaves.bot.agent.configs;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.leavesmc.leaves.bot.agent.AbstractBotConfig;
|
||||
import org.leavesmc.leaves.command.CommandArgument;
|
||||
@@ -13,7 +14,7 @@ public class SimulationDistanceConfig extends AbstractBotConfig<Integer> {
|
||||
public static final String NAME = "simulation_distance";
|
||||
|
||||
public SimulationDistanceConfig() {
|
||||
super(NAME, CommandArgument.of(CommandArgumentType.INTEGER).setTabComplete(0, List.of("2", "10", "<INT 2 - 32>")));
|
||||
super(NAME, CommandArgument.of(CommandArgumentType.INTEGER).setSuggestion(0, Pair.of(List.of("2", "10"), "<INT 2 - 32>")));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,6 +40,6 @@ public class SimulationDistanceConfig extends AbstractBotConfig<Integer> {
|
||||
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
this.setValue(nbt.getInt(NAME));
|
||||
this.setValue(nbt.getInt(NAME).orElseThrow());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class SkipSleepConfig extends AbstractBotConfig<Boolean> {
|
||||
public static final String NAME = "skip_sleep";
|
||||
|
||||
public SkipSleepConfig() {
|
||||
super(NAME, CommandArgument.of(CommandArgumentType.BOOLEAN).setTabComplete(0, List.of("true", "false")));
|
||||
super(NAME, CommandArgument.of(CommandArgumentType.BOOLEAN).setSuggestion(0, List.of("true", "false")));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,6 +35,6 @@ public class SkipSleepConfig extends AbstractBotConfig<Boolean> {
|
||||
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
this.setValue(nbt.getBoolean(NAME));
|
||||
this.setValue(nbt.getBoolean(NAME).orElseThrow());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class SpawnPhantomConfig extends AbstractBotConfig<Boolean> {
|
||||
private boolean value;
|
||||
|
||||
public SpawnPhantomConfig() {
|
||||
super(NAME, CommandArgument.of(CommandArgumentType.BOOLEAN).setTabComplete(0, List.of("true", "false")));
|
||||
super(NAME, CommandArgument.of(CommandArgumentType.BOOLEAN).setSuggestion(0, List.of("true", "false")));
|
||||
this.value = LeavesConfig.modify.fakeplayer.canSpawnPhantom;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,6 @@ public class SpawnPhantomConfig extends AbstractBotConfig<Boolean> {
|
||||
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
this.setValue(nbt.getBoolean(NAME));
|
||||
this.setValue(nbt.getBoolean(NAME).orElseThrow());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public class TickTypeConfig extends AbstractBotConfig<ServerBot.TickType> {
|
||||
private ServerBot.TickType value;
|
||||
|
||||
public TickTypeConfig() {
|
||||
super(NAME, CommandArgument.of(TICK_TYPE_ARGUMENT).setTabComplete(0, List.of("network", "entity_list")));
|
||||
super(NAME, CommandArgument.of(TICK_TYPE_ARGUMENT).setSuggestion(0, List.of("network", "entity_list")));
|
||||
this.value = LeavesConfig.modify.fakeplayer.tickType;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,6 @@ public class TickTypeConfig extends AbstractBotConfig<ServerBot.TickType> {
|
||||
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
this.setValue(TICK_TYPE_ARGUMENT.parse(nbt.getString(NAME)));
|
||||
this.setValue(TICK_TYPE_ARGUMENT.parse(nbt.getString(NAME).orElseThrow()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package org.leavesmc.leaves.bot.subcommands;
|
||||
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
@@ -18,6 +22,7 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
|
||||
@@ -165,10 +170,7 @@ public class BotActionCommand implements LeavesSubcommand {
|
||||
list.add(String.valueOf(i));
|
||||
}
|
||||
} else {
|
||||
AbstractBotAction<?> action = Actions.getForName(args[1]);
|
||||
if (action != null) {
|
||||
list.addAll(action.getArgument().tabComplete(args.length - 3));
|
||||
}
|
||||
return Collections.singletonList("<" + args[1] + " not found>");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,6 +178,40 @@ public class BotActionCommand implements LeavesSubcommand {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Suggestions> tabSuggestion(CommandSender sender, String subCommand, String[] args, Location location, SuggestionsBuilder builder) {
|
||||
if (!LeavesConfig.modify.fakeplayer.canUseAction) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (args.length >= 3) {
|
||||
if (args[1].equals("stop")) {
|
||||
return null;
|
||||
}
|
||||
AbstractBotAction<?> action = Actions.getForName(args[1]);
|
||||
if (action != null) {
|
||||
Pair<List<String>, String> results = action.getArgument().suggestion(args.length - 3, sender, args[args.length - 1]);
|
||||
|
||||
if (results == null || results.getLeft() == null) {
|
||||
return builder.buildFuture();
|
||||
}
|
||||
|
||||
builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1);
|
||||
for (String s : results.getLeft()) {
|
||||
if (results.getRight() != null) {
|
||||
builder.suggest(s, Component.literal(results.getRight()));
|
||||
} else {
|
||||
builder.suggest(s);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.buildFuture();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tabCompletes() {
|
||||
return LeavesConfig.modify.fakeplayer.canUseAction;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package org.leavesmc.leaves.bot.subcommands;
|
||||
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -17,6 +21,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
|
||||
@@ -90,12 +95,7 @@ public class BotConfigCommand implements LeavesSubcommand {
|
||||
}
|
||||
|
||||
if (args.length >= 3) {
|
||||
Configs<?> config = Configs.getConfig(args[1]);
|
||||
if (config != null) {
|
||||
list.addAll(bot.getConfig(config).getArgument().tabComplete(args.length - 3));
|
||||
} else {
|
||||
return Collections.singletonList("<" + args[1] + " not found>");
|
||||
}
|
||||
return Collections.singletonList("<" + args[1] + " not found>");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,43 @@ public class BotConfigCommand implements LeavesSubcommand {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Suggestions> tabSuggestion(CommandSender sender, String subCommand, String[] args, Location location, SuggestionsBuilder builder) {
|
||||
if (!LeavesConfig.modify.fakeplayer.canModifyConfig) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (args.length >= 3) {
|
||||
ServerBot bot = BotList.INSTANCE.getBotByName(args[0]);
|
||||
if (bot == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Configs<?> config = Configs.getConfig(args[1]);
|
||||
if (config != null) {
|
||||
AbstractBotConfig<?> botConfig = bot.getConfig(config);
|
||||
Pair<List<String>, String> results = botConfig.getArgument().suggestion(args.length - 3, sender, args[args.length - 1]);
|
||||
|
||||
if (results == null || results.getLeft() == null) {
|
||||
return builder.buildFuture();
|
||||
}
|
||||
|
||||
builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1);
|
||||
for (String s : results.getLeft()) {
|
||||
if (results.getRight() != null) {
|
||||
builder.suggest(s, Component.literal(results.getRight()));
|
||||
} else {
|
||||
builder.suggest(s);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.buildFuture();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tabCompletes() {
|
||||
return LeavesConfig.modify.fakeplayer.canModifyConfig;
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.leavesmc.leaves.LeavesConfig;
|
||||
import org.leavesmc.leaves.LeavesLogger;
|
||||
import org.leavesmc.leaves.bot.BotCreateState;
|
||||
import org.leavesmc.leaves.bot.BotList;
|
||||
import org.leavesmc.leaves.bot.BotUtil;
|
||||
import org.leavesmc.leaves.command.LeavesSubcommand;
|
||||
import org.leavesmc.leaves.event.bot.BotCreateEvent;
|
||||
|
||||
@@ -30,7 +31,8 @@ public class BotCreateCommand implements LeavesSubcommand {
|
||||
}
|
||||
|
||||
String botName = args[0];
|
||||
if (this.canCreate(sender, botName)) {
|
||||
String fullName = BotUtil.getFullName(botName);
|
||||
if (this.canCreate(sender, fullName)) {
|
||||
BotCreateState.Builder builder = BotCreateState.builder(botName, Bukkit.getWorlds().getFirst().getSpawnLocation()).createReason(BotCreateEvent.CreateReason.COMMAND).creator(sender);
|
||||
|
||||
if (args.length >= 2) {
|
||||
|
||||
@@ -50,7 +50,7 @@ public class BotLoadCommand implements LeavesSubcommand {
|
||||
BotList botList = BotList.INSTANCE;
|
||||
|
||||
if (args.length <= 1) {
|
||||
list.addAll(botList.getSavedBotList().getAllKeys());
|
||||
list.addAll(botList.getSavedBotList().keySet());
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
@@ -13,11 +13,13 @@ public class SimpleBytebufManager implements BytebufManager {
|
||||
this.internal = internal;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void registerListener(Plugin plugin, PacketListener listener) {
|
||||
internal.listenerMap.put(listener, plugin);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void unregisterListener(Plugin plugin, PacketListener listener) {
|
||||
internal.listenerMap.remove(listener);
|
||||
|
||||
@@ -270,6 +270,11 @@ public class WrappedBytebuf implements Bytebuf {
|
||||
return new WrappedBytebuf(this.buf.copy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retain() {
|
||||
this.buf.retain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
return this.buf.release();
|
||||
|
||||
@@ -31,10 +31,12 @@ import org.leavesmc.leaves.bytebuf.packet.PacketType;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.leavesmc.leaves.bytebuf.packet.PacketType.*;
|
||||
|
||||
@SuppressWarnings({"deprecation", "rawtypes", "unchecked"})
|
||||
public class InternalBytebufHandler {
|
||||
|
||||
private class PacketHandler extends ChannelDuplexHandler {
|
||||
@@ -87,6 +89,17 @@ public class InternalBytebufHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static final List<String> PACKET_PACKAGES = List.of(
|
||||
"net.minecraft.network.protocol.common",
|
||||
"net.minecraft.network.protocol.configuration",
|
||||
"net.minecraft.network.protocol.cookie",
|
||||
"net.minecraft.network.protocol.game",
|
||||
"net.minecraft.network.protocol.handshake",
|
||||
"net.minecraft.network.protocol.login",
|
||||
"net.minecraft.network.protocol.ping",
|
||||
"net.minecraft.network.protocol.status"
|
||||
);
|
||||
|
||||
public final Map<PacketListener, Plugin> listenerMap = new HashMap<>();
|
||||
private final BytebufManager manager = new SimpleBytebufManager(this);
|
||||
private final ImmutableMap<PacketType, StreamCodec> type2CodecMap;
|
||||
@@ -94,26 +107,18 @@ public class InternalBytebufHandler {
|
||||
|
||||
public InternalBytebufHandler() {
|
||||
ImmutableMap.Builder<PacketType, StreamCodec> builder = ImmutableMap.builder();
|
||||
|
||||
for (PacketType packet : PacketType.values()) {
|
||||
Class<?> packetClass;
|
||||
try {
|
||||
packetClass = Class.forName("net.minecraft.network.protocol.game." + packet.name() + "Packet");
|
||||
} catch (ClassNotFoundException e) {
|
||||
String className = packet.name() + "Packet";
|
||||
for (String basePackage : PACKET_PACKAGES) {
|
||||
try {
|
||||
packetClass = Class.forName("net.minecraft.network.protocol.common." + packet.name() + "Packet");
|
||||
} catch (ClassNotFoundException e2) {
|
||||
try {
|
||||
packetClass = Class.forName("net.minecraft.network.protocol.ping." + packet.name() + "Packet");
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
continue;
|
||||
}
|
||||
Class<?> packetClass = Class.forName(basePackage + "." + className);
|
||||
Field field = packetClass.getDeclaredField("STREAM_CODEC");
|
||||
field.setAccessible(true);
|
||||
builder.put(packet, (StreamCodec) field.get(null));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
Field field = packetClass.getDeclaredField("STREAM_CODEC");
|
||||
builder.put(packet, (StreamCodec<FriendlyByteBuf, net.minecraft.network.protocol.Packet<?>>) field.get(null));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
builder.put(ClientboundMoveEntityPos, ClientboundMoveEntityPacket.Pos.STREAM_CODEC);
|
||||
@@ -232,4 +237,4 @@ public class InternalBytebufHandler {
|
||||
codec.encode(buf, nmsPacket);
|
||||
return new Packet(type, new WrappedBytebuf(buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,29 @@
|
||||
package org.leavesmc.leaves.command;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class CommandArgument {
|
||||
|
||||
public static final CommandArgument EMPTY = new CommandArgument();
|
||||
|
||||
private static final Pair<List<String>, String> EMPTY_SUGGESTION_RESULT = Pair.of(List.of(), null);
|
||||
private static final BiFunction<CommandSender, String, Pair<List<String>, String>> EMPTY_SUGGESTION = (sender, arg) -> EMPTY_SUGGESTION_RESULT;
|
||||
|
||||
private final List<BiFunction<CommandSender, String, Pair<List<String>, String>>> suggestions;
|
||||
private final List<CommandArgumentType<?>> argumentTypes;
|
||||
private final List<List<String>> tabComplete;
|
||||
|
||||
private CommandArgument(CommandArgumentType<?>... argumentTypes) {
|
||||
this.argumentTypes = List.of(argumentTypes);
|
||||
this.tabComplete = new ArrayList<>();
|
||||
this.suggestions = new ArrayList<>();
|
||||
for (int i = 0; i < argumentTypes.length; i++) {
|
||||
tabComplete.add(new ArrayList<>());
|
||||
suggestions.add(EMPTY_SUGGESTION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,29 +31,31 @@ public class CommandArgument {
|
||||
return new CommandArgument(argumentTypes);
|
||||
}
|
||||
|
||||
public List<String> tabComplete(int n) {
|
||||
if (tabComplete.size() > n) {
|
||||
return tabComplete.get(n);
|
||||
} else {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
public CommandArgument setTabComplete(int index, List<String> list) {
|
||||
tabComplete.set(index, list);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandArgument setAllTabComplete(List<List<String>> tabComplete) {
|
||||
this.tabComplete.clear();
|
||||
this.tabComplete.addAll(tabComplete);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<CommandArgumentType<?>> getArgumentTypes() {
|
||||
return argumentTypes;
|
||||
}
|
||||
|
||||
public CommandArgument setSuggestion(int n, BiFunction<CommandSender, String, Pair<List<String>, String>> suggestion) {
|
||||
this.suggestions.set(n, suggestion);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandArgument setSuggestion(int n, Pair<List<String>, String> suggestion) {
|
||||
return this.setSuggestion(n, (sender, arg) -> suggestion);
|
||||
}
|
||||
|
||||
public CommandArgument setSuggestion(int n, List<String> tabComplete) {
|
||||
return this.setSuggestion(n, Pair.of(tabComplete, null));
|
||||
}
|
||||
|
||||
public Pair<List<String>, String> suggestion(int n, CommandSender sender, String arg) {
|
||||
if (suggestions.size() > n) {
|
||||
return suggestions.get(n).apply(sender, arg);
|
||||
} else {
|
||||
return EMPTY_SUGGESTION.apply(sender, arg);
|
||||
}
|
||||
}
|
||||
|
||||
public CommandArgumentResult parse(int index, String @NotNull [] args) {
|
||||
Object[] result = new Object[argumentTypes.size()];
|
||||
Arrays.fill(result, null);
|
||||
|
||||
@@ -14,7 +14,12 @@ import org.bukkit.permissions.PermissionDefault;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.command.subcommands.*;
|
||||
import org.leavesmc.leaves.command.subcommands.ConfigCommand;
|
||||
import org.leavesmc.leaves.command.subcommands.CounterCommand;
|
||||
import org.leavesmc.leaves.command.subcommands.PeacefulModeSwitchCommand;
|
||||
import org.leavesmc.leaves.command.subcommands.ReloadCommand;
|
||||
import org.leavesmc.leaves.command.subcommands.ReportCommand;
|
||||
import org.leavesmc.leaves.command.subcommands.UpdateCommand;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -15,7 +15,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -57,22 +56,15 @@ public class LeavesCommandUtil {
|
||||
ArrayList<String> results = Lists.newArrayList();
|
||||
|
||||
if (!collection.isEmpty()) {
|
||||
Iterator iterator = Iterables.transform(collection, Functions.toStringFunction()).iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
String s1 = (String) iterator.next();
|
||||
|
||||
for (String s1 : Iterables.transform(collection, Functions.toStringFunction())) {
|
||||
if (matches(last, s1) && (sender.hasPermission(basePermission + s1) || sender.hasPermission(overridePermission))) {
|
||||
results.add(s1);
|
||||
}
|
||||
}
|
||||
|
||||
if (results.isEmpty()) {
|
||||
iterator = collection.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Object object = iterator.next();
|
||||
|
||||
for (Object object : collection) {
|
||||
if (object instanceof ResourceLocation && matches(last, ((ResourceLocation) object).getPath())) {
|
||||
results.add(String.valueOf(object));
|
||||
}
|
||||
@@ -122,6 +114,7 @@ public class LeavesCommandUtil {
|
||||
}
|
||||
|
||||
// Copy from org/bukkit/command/defaults/HelpCommand.java
|
||||
|
||||
/**
|
||||
* Computes the Dameraur-Levenshtein Distance between two strings. Adapted
|
||||
* from the algorithm at <a href="http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance">Wikipedia: Damerau–Levenshtein distance</a>
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.leavesmc.leaves.LeavesConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// TODO merge to /leaves blockupdate
|
||||
public class NoBlockUpdateCommand extends Command {
|
||||
|
||||
private static boolean noBlockUpdate = false;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.leavesmc.leaves.config;
|
||||
|
||||
public class InternalConfigProvider implements LeavesConfigProvider {
|
||||
|
||||
public static final InternalConfigProvider INSTANCE = new InternalConfigProvider();
|
||||
|
||||
public LeavesConfigValue getConfig(String configNode) {
|
||||
return new LeavesConfigValue(GlobalConfigManager.getVerifiedConfig(configNode).get());
|
||||
}
|
||||
|
||||
public void setConfig(String configNode, LeavesConfigValue configValue) {
|
||||
GlobalConfigManager.getVerifiedConfig(configNode);
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public class CraftBot extends CraftPlayer implements Bot {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) {
|
||||
public boolean teleport(Location location, PlayerTeleportEvent.@NotNull TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) {
|
||||
Preconditions.checkArgument(location != null, "location cannot be null");
|
||||
Preconditions.checkState(location.getWorld().equals(this.getWorld()), "[Leaves] Fakeplayers do not support changing world, Please use leaves fakeplayer-api instead!");
|
||||
return super.teleport(location, cause, flags);
|
||||
|
||||
@@ -26,12 +26,7 @@ public class CraftBotManager implements BotManager {
|
||||
|
||||
public CraftBotManager() {
|
||||
this.botList = MinecraftServer.getServer().getBotList();
|
||||
this.botViews = Collections.unmodifiableList(Lists.transform(botList.bots, new Function<ServerBot, CraftBot>() {
|
||||
@Override
|
||||
public CraftBot apply(ServerBot bot) {
|
||||
return bot.getBukkitEntity();
|
||||
}
|
||||
}));
|
||||
this.botViews = Collections.unmodifiableList(Lists.transform(botList.bots, bot -> bot.getBukkitEntity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// This file is licensed under the MIT license.
|
||||
package org.leavesmc.leaves.plugin;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.leavesmc.leaves.plugin.Features.*;
|
||||
|
||||
public class ServerFeatureManager implements FeatureManager {
|
||||
public static ServerFeatureManager INSTANCE = new ServerFeatureManager();
|
||||
private final Set<String> availableFeatures = new HashSet<>();
|
||||
|
||||
private ServerFeatureManager() {
|
||||
availableFeatures.addAll(Set.of(
|
||||
FAKEPLAYER,
|
||||
PHOTOGRAPHER
|
||||
));
|
||||
if (Boolean.getBoolean("leavesclip.enable.mixin")) {
|
||||
availableFeatures.add(MIXIN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAvailableFeatures() {
|
||||
return availableFeatures;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFeatureAvailable(String feature) {
|
||||
return availableFeatures.contains(feature);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// This file is licensed under the MIT license.
|
||||
package org.leavesmc.leaves.plugin.provider.configuration;
|
||||
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
@ConfigSerializable
|
||||
public class FeaturesConfiguration {
|
||||
private List<String> required = List.of();
|
||||
private List<String> optional = List.of();
|
||||
|
||||
public List<String> getRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
public List<String> getOptional() {
|
||||
return optional;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// This file is licensed under the MIT license.
|
||||
package org.leavesmc.leaves.plugin.provider.configuration;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -11,9 +12,10 @@ import io.papermc.paper.plugin.provider.configuration.serializer.PermissionConfi
|
||||
import io.papermc.paper.plugin.provider.configuration.serializer.constraints.PluginConfigConstraints;
|
||||
import io.papermc.paper.plugin.provider.configuration.type.PermissionConfiguration;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.gson.GsonConfigurationLoader;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
@@ -21,25 +23,23 @@ import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
@ConfigSerializable
|
||||
public class LeavesPluginMeta extends PaperPluginMeta {
|
||||
private List<String> mixins;
|
||||
static final ApiVersion MINIMUM = ApiVersion.getOrCreateVersion("1.21");
|
||||
private FeaturesConfiguration features = new FeaturesConfiguration();
|
||||
private MixinConfiguration mixin = new MixinConfiguration();
|
||||
static final ApiVersion MINIMUM = ApiVersion.getOrCreateVersion("1.21.4");
|
||||
|
||||
public static LeavesPluginMeta create(BufferedReader reader) throws ConfigurateException {
|
||||
HoconConfigurationLoader loader = HoconConfigurationLoader.builder()
|
||||
.prettyPrinting(true)
|
||||
.emitComments(true)
|
||||
.emitJsonCompatible(true)
|
||||
GsonConfigurationLoader loader = GsonConfigurationLoader.builder()
|
||||
.source(() -> reader)
|
||||
.defaultOptions((options) ->
|
||||
options.serializers((serializers) ->
|
||||
serializers.register(new ScalarSerializer<>(ApiVersion.class) {
|
||||
@Override
|
||||
public ApiVersion deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
public ApiVersion deserialize(final @NotNull Type type, final @NotNull Object obj) throws SerializationException {
|
||||
try {
|
||||
final ApiVersion version = ApiVersion.getOrCreateVersion(obj.toString());
|
||||
if (version.isOlderThan(MINIMUM)) {
|
||||
@@ -52,7 +52,7 @@ public class LeavesPluginMeta extends PaperPluginMeta {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final ApiVersion item, final Predicate<Class<?>> typeSupported) {
|
||||
protected @NotNull Object serialize(final ApiVersion item, final @NotNull Predicate<Class<?>> typeSupported) {
|
||||
return item.getVersionString();
|
||||
}
|
||||
})
|
||||
@@ -70,21 +70,30 @@ public class LeavesPluginMeta extends PaperPluginMeta {
|
||||
)
|
||||
)
|
||||
.build();
|
||||
CommentedConfigurationNode node = loader.load();
|
||||
ConfigurationNode node = loader.load();
|
||||
LegacyPaperMeta.migrate(node);
|
||||
LeavesPluginMeta pluginConfiguration = node.require(LeavesPluginMeta.class);
|
||||
|
||||
if (!node.node("author").virtual()) {
|
||||
pluginConfiguration.authors = ImmutableList.<String>builder()
|
||||
var authorNode = node.node("author");
|
||||
if (!authorNode.virtual()) {
|
||||
String author = authorNode.getString();
|
||||
var authorsBuilder = ImmutableList.<String>builder();
|
||||
if (author != null) {
|
||||
authorsBuilder.add(author);
|
||||
}
|
||||
pluginConfiguration.authors = authorsBuilder
|
||||
.addAll(pluginConfiguration.authors)
|
||||
.add(node.node("author").getString())
|
||||
.build();
|
||||
}
|
||||
|
||||
return pluginConfiguration;
|
||||
}
|
||||
|
||||
public List<String> getMixins() {
|
||||
return mixins;
|
||||
public FeaturesConfiguration getFeatures() {
|
||||
return features;
|
||||
}
|
||||
|
||||
public MixinConfiguration getMixin() {
|
||||
return mixin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// This file is licensed under the MIT license.
|
||||
package org.leavesmc.leaves.plugin.provider.configuration;
|
||||
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.meta.PostProcess;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings({"FieldMayBeFinal", "unused"})
|
||||
@ConfigSerializable
|
||||
public class MixinConfiguration {
|
||||
private String packageName;
|
||||
private List<String> mixins = List.of();
|
||||
private String accessWidener;
|
||||
|
||||
@PostProcess
|
||||
public void postProcess() {
|
||||
if (mixins.isEmpty()) return;
|
||||
if (packageName == null) {
|
||||
throw new IllegalStateException("Already define mixins: " + mixins + ", but no mixin package-name provided");
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getMixins() {
|
||||
return mixins;
|
||||
}
|
||||
|
||||
public String getAccessWidener() {
|
||||
return accessWidener;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,8 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@LeavesProtocol(namespace = "appleskin")
|
||||
public class AppleSkinProtocol {
|
||||
@LeavesProtocol.Register(namespace = "appleskin")
|
||||
public class AppleSkinProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "appleskin";
|
||||
|
||||
@@ -41,64 +41,52 @@ public class AppleSkinProtocol {
|
||||
|
||||
@ProtocolHandler.PlayerJoin
|
||||
public static void onPlayerLoggedIn(@NotNull ServerPlayer player) {
|
||||
if (LeavesConfig.protocol.appleskin.enable) {
|
||||
resetPlayerData(player);
|
||||
}
|
||||
resetPlayerData(player);
|
||||
}
|
||||
|
||||
@ProtocolHandler.PlayerLeave
|
||||
public static void onPlayerLoggedOut(@NotNull ServerPlayer player) {
|
||||
if (LeavesConfig.protocol.appleskin.enable) {
|
||||
subscribedChannels.remove(player);
|
||||
resetPlayerData(player);
|
||||
}
|
||||
subscribedChannels.remove(player);
|
||||
resetPlayerData(player);
|
||||
}
|
||||
|
||||
@ProtocolHandler.MinecraftRegister(ignoreId = true)
|
||||
public static void onPlayerSubscribed(@NotNull ServerPlayer player, String channel) {
|
||||
if (LeavesConfig.protocol.appleskin.enable) {
|
||||
subscribedChannels.computeIfAbsent(player, k -> new HashSet<>()).add(channel);
|
||||
}
|
||||
@ProtocolHandler.MinecraftRegister(onlyNamespace = true)
|
||||
public static void onPlayerSubscribed(@NotNull ServerPlayer player, ResourceLocation id) {
|
||||
subscribedChannels.computeIfAbsent(player, k -> new HashSet<>()).add(id.getPath());
|
||||
}
|
||||
|
||||
@ProtocolHandler.Ticker
|
||||
public static void tick() {
|
||||
if (LeavesConfig.protocol.appleskin.enable) {
|
||||
if (MinecraftServer.getServer().getTickCount() % LeavesConfig.protocol.appleskin.syncTickInterval != 0) {
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<ServerPlayer, Set<String>> entry : subscribedChannels.entrySet()) {
|
||||
ServerPlayer player = entry.getKey();
|
||||
FoodData data = player.getFoodData();
|
||||
|
||||
for (Map.Entry<ServerPlayer, Set<String>> entry : subscribedChannels.entrySet()) {
|
||||
ServerPlayer player = entry.getKey();
|
||||
FoodData data = player.getFoodData();
|
||||
|
||||
for (String channel : entry.getValue()) {
|
||||
switch (channel) {
|
||||
case "saturation" -> {
|
||||
float saturation = data.getSaturationLevel();
|
||||
Float previousSaturation = previousSaturationLevels.get(player);
|
||||
if (previousSaturation == null || saturation != previousSaturation) {
|
||||
ProtocolUtils.sendPayloadPacket(player, SATURATION_KEY, buf -> buf.writeFloat(saturation));
|
||||
previousSaturationLevels.put(player, saturation);
|
||||
}
|
||||
for (String channel : entry.getValue()) {
|
||||
switch (channel) {
|
||||
case "saturation" -> {
|
||||
float saturation = data.getSaturationLevel();
|
||||
Float previousSaturation = previousSaturationLevels.get(player);
|
||||
if (previousSaturation == null || saturation != previousSaturation) {
|
||||
ProtocolUtils.sendBytebufPacket(player, SATURATION_KEY, buf -> buf.writeFloat(saturation));
|
||||
previousSaturationLevels.put(player, saturation);
|
||||
}
|
||||
}
|
||||
|
||||
case "exhaustion" -> {
|
||||
float exhaustion = data.exhaustionLevel;
|
||||
Float previousExhaustion = previousExhaustionLevels.get(player);
|
||||
if (previousExhaustion == null || Math.abs(exhaustion - previousExhaustion) >= MINIMUM_EXHAUSTION_CHANGE_THRESHOLD) {
|
||||
ProtocolUtils.sendPayloadPacket(player, EXHAUSTION_KEY, buf -> buf.writeFloat(exhaustion));
|
||||
previousExhaustionLevels.put(player, exhaustion);
|
||||
}
|
||||
case "exhaustion" -> {
|
||||
float exhaustion = data.exhaustionLevel;
|
||||
Float previousExhaustion = previousExhaustionLevels.get(player);
|
||||
if (previousExhaustion == null || Math.abs(exhaustion - previousExhaustion) >= MINIMUM_EXHAUSTION_CHANGE_THRESHOLD) {
|
||||
ProtocolUtils.sendBytebufPacket(player, EXHAUSTION_KEY, buf -> buf.writeFloat(exhaustion));
|
||||
previousExhaustionLevels.put(player, exhaustion);
|
||||
}
|
||||
}
|
||||
|
||||
case "natural_regeneration" -> {
|
||||
boolean regeneration = player.serverLevel().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION);
|
||||
Boolean previousRegeneration = previousNaturalRegeneration.get(player);
|
||||
if (previousRegeneration == null || regeneration != previousRegeneration) {
|
||||
ProtocolUtils.sendPayloadPacket(player, NATURAL_REGENERATION_KEY, buf -> buf.writeBoolean(regeneration));
|
||||
previousNaturalRegeneration.put(player, regeneration);
|
||||
}
|
||||
case "natural_regeneration" -> {
|
||||
boolean regeneration = player.serverLevel().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION);
|
||||
Boolean previousRegeneration = previousNaturalRegeneration.get(player);
|
||||
if (previousRegeneration == null || regeneration != previousRegeneration) {
|
||||
ProtocolUtils.sendBytebufPacket(player, NATURAL_REGENERATION_KEY, buf -> buf.writeBoolean(regeneration));
|
||||
previousNaturalRegeneration.put(player, regeneration);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,9 +96,7 @@ public class AppleSkinProtocol {
|
||||
|
||||
@ProtocolHandler.ReloadServer
|
||||
public static void onServerReload() {
|
||||
if (!LeavesConfig.protocol.appleskin.enable) {
|
||||
disableAllPlayer();
|
||||
}
|
||||
disableAllPlayer();
|
||||
}
|
||||
|
||||
public static void disableAllPlayer() {
|
||||
@@ -124,4 +110,14 @@ public class AppleSkinProtocol {
|
||||
previousSaturationLevels.remove(player);
|
||||
previousNaturalRegeneration.remove(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int tickerInterval(String tickerID) {
|
||||
return LeavesConfig.protocol.appleskin.syncTickInterval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return LeavesConfig.protocol.appleskin.enable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,8 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.leavesmc.leaves.protocol.core.LeavesProtocolManager.EmptyPayload;
|
||||
|
||||
@LeavesProtocol(namespace = "bbor")
|
||||
public class BBORProtocol {
|
||||
@LeavesProtocol.Register(namespace = "bbor")
|
||||
public class BBORProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "bbor";
|
||||
|
||||
@@ -43,6 +41,8 @@ public class BBORProtocol {
|
||||
private static final Map<Integer, Set<BBoundingBox>> playerBoundingBoxesCache = new HashMap<>();
|
||||
private static final Map<ResourceLocation, Map<BBoundingBox, Set<BBoundingBox>>> dimensionCache = new ConcurrentHashMap<>();
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
||||
@Contract("_ -> new")
|
||||
public static ResourceLocation id(String path) {
|
||||
return ResourceLocation.tryBuild(PROTOCOL_ID, path);
|
||||
@@ -50,10 +50,8 @@ public class BBORProtocol {
|
||||
|
||||
@ProtocolHandler.Ticker
|
||||
public static void tick() {
|
||||
if (LeavesConfig.protocol.bborProtocol) {
|
||||
for (var playerEntry : players.entrySet()) {
|
||||
sendBoundingToPlayer(playerEntry.getKey(), playerEntry.getValue());
|
||||
}
|
||||
for (var playerEntry : players.entrySet()) {
|
||||
sendBoundingToPlayer(playerEntry.getKey(), playerEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,50 +66,41 @@ public class BBORProtocol {
|
||||
|
||||
@ProtocolHandler.PlayerJoin
|
||||
public static void onPlayerLoggedIn(@NotNull ServerPlayer player) {
|
||||
if (LeavesConfig.protocol.bborProtocol) {
|
||||
ServerLevel overworld = MinecraftServer.getServer().overworld();
|
||||
ProtocolUtils.sendPayloadPacket(player, INITIALIZE_CLIENT, buf -> {
|
||||
buf.writeLong(overworld.getSeed());
|
||||
buf.writeInt(overworld.levelData.getSpawnPos().getX());
|
||||
buf.writeInt(overworld.levelData.getSpawnPos().getZ());
|
||||
});
|
||||
sendStructureList(player);
|
||||
}
|
||||
ServerLevel overworld = MinecraftServer.getServer().overworld();
|
||||
ProtocolUtils.sendBytebufPacket(player, INITIALIZE_CLIENT, buf -> {
|
||||
buf.writeLong(overworld.getSeed());
|
||||
buf.writeInt(overworld.levelData.getSpawnPos().getX());
|
||||
buf.writeInt(overworld.levelData.getSpawnPos().getZ());
|
||||
});
|
||||
sendStructureList(player);
|
||||
}
|
||||
|
||||
@ProtocolHandler.PlayerLeave
|
||||
public static void onPlayerLoggedOut(@NotNull ServerPlayer player) {
|
||||
if (LeavesConfig.protocol.bborProtocol) {
|
||||
players.remove(player.getId());
|
||||
playerBoundingBoxesCache.remove(player.getId());
|
||||
}
|
||||
players.remove(player.getId());
|
||||
playerBoundingBoxesCache.remove(player.getId());
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = EmptyPayload.class, payloadId = "subscribe")
|
||||
public static void onPlayerSubscribed(@NotNull ServerPlayer player, EmptyPayload payload) {
|
||||
if (LeavesConfig.protocol.bborProtocol) {
|
||||
players.put(player.getId(), player);
|
||||
sendBoundingToPlayer(player.getId(), player);
|
||||
}
|
||||
@ProtocolHandler.BytebufReceiver(key = "subscribe")
|
||||
public static void onPlayerSubscribed(@NotNull ServerPlayer player, FriendlyByteBuf buf) {
|
||||
players.put(player.getId(), player);
|
||||
sendBoundingToPlayer(player.getId(), player);
|
||||
}
|
||||
|
||||
@ProtocolHandler.ReloadDataPack
|
||||
public static void onDataPackReload() {
|
||||
if (LeavesConfig.protocol.bborProtocol) {
|
||||
players.values().forEach(BBORProtocol::sendStructureList);
|
||||
}
|
||||
players.values().forEach(BBORProtocol::sendStructureList);
|
||||
}
|
||||
|
||||
public static void onChunkLoaded(@NotNull LevelChunk chunk) {
|
||||
if (LeavesConfig.protocol.bborProtocol) {
|
||||
Map<String, StructureStart> structures = new HashMap<>();
|
||||
final Registry<Structure> structureFeatureRegistry = chunk.getLevel().registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
for (var es : chunk.getAllStarts().entrySet()) {
|
||||
final var optional = structureFeatureRegistry.getResourceKey(es.getKey());
|
||||
optional.ifPresent(key -> structures.put(key.location().toString(), es.getValue()));
|
||||
}
|
||||
if (!structures.isEmpty()) {
|
||||
onStructuresLoaded(chunk.getLevel().dimension().location(), structures);
|
||||
}
|
||||
Map<String, StructureStart> structures = new HashMap<>();
|
||||
final Registry<Structure> structureFeatureRegistry = chunk.getLevel().registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
for (var es : chunk.getAllStarts().entrySet()) {
|
||||
final var optional = structureFeatureRegistry.getResourceKey(es.getKey());
|
||||
optional.ifPresent(key -> structures.put(key.location().toString(), es.getValue()));
|
||||
}
|
||||
if (!structures.isEmpty()) {
|
||||
onStructuresLoaded(chunk.getLevel().dimension().location(), structures);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +137,7 @@ public class BBORProtocol {
|
||||
final Registry<Structure> structureRegistry = player.server.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
final Set<String> structureIds = structureRegistry.entrySet().stream()
|
||||
.map(e -> e.getKey().location().toString()).collect(Collectors.toSet());
|
||||
ProtocolUtils.sendPayloadPacket(player, STRUCTURE_LIST_SYNC, buf -> {
|
||||
ProtocolUtils.sendBytebufPacket(player, STRUCTURE_LIST_SYNC, buf -> {
|
||||
buf.writeVarInt(structureIds.size());
|
||||
structureIds.forEach(buf::writeUtf);
|
||||
});
|
||||
@@ -168,7 +157,7 @@ public class BBORProtocol {
|
||||
}
|
||||
|
||||
Set<BBoundingBox> boundingBoxes = boundingBoxMap.get(key);
|
||||
ProtocolUtils.sendPayloadPacket(player, ADD_BOUNDING_BOX, buf -> {
|
||||
ProtocolUtils.sendBytebufPacket(player, ADD_BOUNDING_BOX, buf -> {
|
||||
buf.writeResourceLocation(entry.getKey());
|
||||
key.serialize(buf);
|
||||
if (boundingBoxes != null && boundingBoxes.size() > 1) {
|
||||
@@ -186,6 +175,7 @@ public class BBORProtocol {
|
||||
for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().getPlayers()) {
|
||||
onPlayerLoggedIn(player);
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public static void loggedOutAllPlayer() {
|
||||
@@ -201,8 +191,27 @@ public class BBORProtocol {
|
||||
return dimensionCache.computeIfAbsent(dimensionId, dt -> new ConcurrentHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
boolean active = LeavesConfig.protocol.bborProtocol;
|
||||
if (!active && initialized) {
|
||||
initialized = false;
|
||||
loggedOutAllPlayer();
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
private record BBoundingBox(String type, BlockPos min, BlockPos max) {
|
||||
|
||||
private static int combineHashCodes(int @NotNull ... hashCodes) {
|
||||
final int prime = 31;
|
||||
int result = 0;
|
||||
for (int hashCode : hashCodes) {
|
||||
result = prime * result + hashCode;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void serialize(@NotNull FriendlyByteBuf buf) {
|
||||
buf.writeChar('S');
|
||||
buf.writeInt(type.hashCode());
|
||||
@@ -214,14 +223,5 @@ public class BBORProtocol {
|
||||
public int hashCode() {
|
||||
return combineHashCodes(min.hashCode(), max.hashCode());
|
||||
}
|
||||
|
||||
private static int combineHashCodes(int @NotNull ... hashCodes) {
|
||||
final int prime = 31;
|
||||
int result = 0;
|
||||
for (int hashCode : hashCodes) {
|
||||
result = prime * result + hashCode;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package org.leavesmc.leaves.protocol;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
@@ -17,14 +19,12 @@ import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
@LeavesProtocol(namespace = "carpet")
|
||||
public class CarpetServerProtocol {
|
||||
@LeavesProtocol.Register(namespace = "carpet")
|
||||
public class CarpetServerProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "carpet";
|
||||
public static final String VERSION = ProtocolUtils.buildProtocolVersion(PROTOCOL_ID);
|
||||
|
||||
private static final ResourceLocation HELLO_ID = CarpetServerProtocol.id("hello");
|
||||
|
||||
private static final String HI = "69";
|
||||
private static final String HELLO = "420";
|
||||
|
||||
@@ -42,7 +42,7 @@ public class CarpetServerProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = CarpetPayload.class, payloadId = "hello")
|
||||
@ProtocolHandler.PayloadReceiver(payload = CarpetPayload.class)
|
||||
private static void handleHello(@NotNull ServerPlayer player, @NotNull CarpetServerProtocol.CarpetPayload payload) {
|
||||
if (LeavesConfig.protocol.leavesCarpetSupport) {
|
||||
if (payload.nbt.contains(HELLO)) {
|
||||
@@ -54,6 +54,11 @@ public class CarpetServerProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class CarpetRules {
|
||||
|
||||
private static final Map<String, CarpetRule> rules = new HashMap<>();
|
||||
@@ -99,22 +104,13 @@ public class CarpetServerProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
public record CarpetPayload(CompoundTag nbt) implements LeavesCustomPayload<CarpetPayload> {
|
||||
public record CarpetPayload(CompoundTag nbt) implements LeavesCustomPayload {
|
||||
@ID
|
||||
private static final ResourceLocation HELLO_ID = CarpetServerProtocol.id("hello");
|
||||
|
||||
@New
|
||||
public CarpetPayload(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
this(buf.readNbt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
buf.writeNbt(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ResourceLocation id() {
|
||||
return HELLO_ID;
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<FriendlyByteBuf, CarpetPayload> CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.COMPOUND_TAG, CarpetPayload::nbt, CarpetPayload::new
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package org.leavesmc.leaves.protocol;
|
||||
import com.google.common.collect.Sets;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -22,39 +24,33 @@ import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@LeavesProtocol(namespace = "litematica-server-paster")
|
||||
public class LMSPasterProtocol {
|
||||
@LeavesProtocol.Register(namespace = "litematica-server-paster")
|
||||
public class LMSPasterProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String MOD_ID = "litematica-server-paster";
|
||||
public static final String MOD_VERSION = "1.3.5";
|
||||
|
||||
private static final ResourceLocation PACKET_ID = ResourceLocation.fromNamespaceAndPath(MOD_ID, "network_v2");
|
||||
|
||||
private static final Map<ServerGamePacketListenerImpl, StringBuilder> VERY_LONG_CHATS = new WeakHashMap<>();
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = LmsPasterPayload.class, payloadId = "network_v2")
|
||||
@ProtocolHandler.PayloadReceiver(payload = LmsPasterPayload.class)
|
||||
public static void handlePackets(ServerPlayer player, LmsPasterPayload payload) {
|
||||
if (!LeavesConfig.protocol.lmsPasterProtocol) {
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = player.getName().getString();
|
||||
int id = payload.getPacketId();
|
||||
CompoundTag nbt = payload.getNbt();
|
||||
int id = payload.id();
|
||||
CompoundTag nbt = payload.nbt();
|
||||
switch (id) {
|
||||
case LMSPasterProtocol.C2S.HI -> {
|
||||
String clientModVersion = nbt.getString("mod_version");
|
||||
String clientModVersion = nbt.getString("mod_version").orElseThrow();
|
||||
LeavesLogger.LOGGER.info(String.format("Player %s connected with %s @ %s", playerName, LMSPasterProtocol.MOD_ID, clientModVersion));
|
||||
ProtocolUtils.sendPayloadPacket(player, LMSPasterProtocol.S2C.build(LMSPasterProtocol.S2C.HI, nbt2 -> nbt2.putString("mod_version", LMSPasterProtocol.MOD_VERSION)));
|
||||
ProtocolUtils.sendPayloadPacket(player, LMSPasterProtocol.S2C.build(LMSPasterProtocol.S2C.ACCEPT_PACKETS, nbt2 -> nbt2.putIntArray("ids", C2S.ALL_PACKET_IDS)));
|
||||
}
|
||||
case LMSPasterProtocol.C2S.CHAT -> {
|
||||
String message = nbt.getString("chat");
|
||||
String message = nbt.getString("chat").orElseThrow();
|
||||
triggerCommand(player, playerName, message);
|
||||
}
|
||||
case LMSPasterProtocol.C2S.VERY_LONG_CHAT_START -> VERY_LONG_CHATS.put(player.connection, new StringBuilder());
|
||||
case LMSPasterProtocol.C2S.VERY_LONG_CHAT_CONTENT -> {
|
||||
String segment = nbt.getString("segment");
|
||||
String segment = nbt.getString("segment").orElseThrow();
|
||||
getVeryLongChatBuilder(player).ifPresent(builder -> builder.append(segment));
|
||||
}
|
||||
case LMSPasterProtocol.C2S.VERY_LONG_CHAT_END -> {
|
||||
@@ -76,6 +72,11 @@ public class LMSPasterProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return LeavesConfig.protocol.lmsPasterProtocol;
|
||||
}
|
||||
|
||||
private static class C2S {
|
||||
public static final int HI = 0;
|
||||
public static final int CHAT = 1;
|
||||
@@ -115,36 +116,17 @@ public class LMSPasterProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
public static class LmsPasterPayload implements LeavesCustomPayload<LmsPasterPayload> {
|
||||
private final int id;
|
||||
private final CompoundTag nbt;
|
||||
public record LmsPasterPayload(int id, CompoundTag nbt) implements LeavesCustomPayload {
|
||||
@ID
|
||||
private static final ResourceLocation PACKET_ID = ResourceLocation.fromNamespaceAndPath(MOD_ID, "network_v2");
|
||||
|
||||
public LmsPasterPayload(int id, CompoundTag nbt) {
|
||||
this.id = id;
|
||||
this.nbt = nbt;
|
||||
}
|
||||
|
||||
@New
|
||||
public LmsPasterPayload(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
this(buf.readVarInt(), buf.readNbt());
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
buf.writeVarInt(this.id);
|
||||
buf.writeNbt(this.nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return PACKET_ID;
|
||||
}
|
||||
|
||||
public int getPacketId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public CompoundTag getNbt() {
|
||||
return this.nbt;
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<FriendlyByteBuf, LmsPasterPayload> CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.VAR_INT,
|
||||
LmsPasterPayload::id,
|
||||
ByteBufCodecs.COMPOUND_TAG,
|
||||
LmsPasterPayload::nbt,
|
||||
LmsPasterPayload::new
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package org.leavesmc.leaves.protocol;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
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.server.level.ServerLevel;
|
||||
@@ -34,10 +36,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static org.leavesmc.leaves.protocol.core.LeavesProtocolManager.EmptyPayload;
|
||||
|
||||
@LeavesProtocol(namespace = "pca")
|
||||
public class PcaSyncProtocol {
|
||||
@LeavesProtocol.Register(namespace = "pca")
|
||||
public class PcaSyncProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "pca";
|
||||
|
||||
@@ -67,28 +67,18 @@ public class PcaSyncProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = EmptyPayload.class, payloadId = "cancel_sync_block_entity")
|
||||
private static void cancelSyncBlockEntityHandler(ServerPlayer player, EmptyPayload payload) {
|
||||
if (!LeavesConfig.protocol.pca.enable) {
|
||||
return;
|
||||
}
|
||||
@ProtocolHandler.BytebufReceiver(key = "cancel_sync_block_entity")
|
||||
private static void cancelSyncBlockEntityHandler(ServerPlayer player, FriendlyByteBuf buf) {
|
||||
PcaSyncProtocol.clearPlayerWatchBlock(player);
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = EmptyPayload.class, payloadId = "cancel_sync_entity")
|
||||
private static void cancelSyncEntityHandler(ServerPlayer player, EmptyPayload payload) {
|
||||
if (!LeavesConfig.protocol.pca.enable) {
|
||||
return;
|
||||
}
|
||||
@ProtocolHandler.BytebufReceiver(key = "cancel_sync_entity")
|
||||
private static void cancelSyncEntityHandler(ServerPlayer player, FriendlyByteBuf buf) {
|
||||
PcaSyncProtocol.clearPlayerWatchEntity(player);
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = SyncBlockEntityPayload.class, payloadId = "sync_block_entity")
|
||||
@ProtocolHandler.PayloadReceiver(payload = SyncBlockEntityPayload.class)
|
||||
private static void syncBlockEntityHandler(ServerPlayer player, SyncBlockEntityPayload payload) {
|
||||
if (!LeavesConfig.protocol.pca.enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftServer server = MinecraftServer.getServer();
|
||||
BlockPos pos = payload.pos;
|
||||
ServerLevel world = player.serverLevel();
|
||||
@@ -127,12 +117,8 @@ public class PcaSyncProtocol {
|
||||
});
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = SyncEntityPayload.class, payloadId = "sync_entity")
|
||||
@ProtocolHandler.PayloadReceiver(payload = SyncEntityPayload.class)
|
||||
private static void syncEntityHandler(ServerPlayer player, SyncEntityPayload payload) {
|
||||
if (!LeavesConfig.protocol.pca.enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftServer server = MinecraftServer.getServer();
|
||||
int entityId = payload.entityId;
|
||||
ServerLevel world = player.serverLevel();
|
||||
@@ -154,12 +140,12 @@ public class PcaSyncProtocol {
|
||||
}
|
||||
}
|
||||
case OPS -> {
|
||||
if (!(entity instanceof ServerBot) && server.getPlayerList().isOp(player.gameProfile)) {
|
||||
if (!(entity instanceof ServerBot) && !server.getPlayerList().isOp(player.gameProfile)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
case OPS_AND_SELF -> {
|
||||
if (!(entity instanceof ServerBot) && server.getPlayerList().isOp(player.gameProfile) && entity != player) {
|
||||
if (!(entity instanceof ServerBot) && !server.getPlayerList().isOp(player.gameProfile) && entity != player) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -191,13 +177,13 @@ public class PcaSyncProtocol {
|
||||
}
|
||||
|
||||
public static void enablePcaSyncProtocol(@NotNull ServerPlayer player) {
|
||||
ProtocolUtils.sendEmptyPayloadPacket(player, ENABLE_PCA_SYNC_PROTOCOL);
|
||||
ProtocolUtils.sendEmptyPacket(player, ENABLE_PCA_SYNC_PROTOCOL);
|
||||
lock.lock();
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public static void disablePcaSyncProtocol(@NotNull ServerPlayer player) {
|
||||
ProtocolUtils.sendEmptyPayloadPacket(player, DISABLE_PCA_SYNC_PROTOCOL);
|
||||
ProtocolUtils.sendEmptyPacket(player, DISABLE_PCA_SYNC_PROTOCOL);
|
||||
}
|
||||
|
||||
public static void updateEntity(@NotNull ServerPlayer player, @NotNull Entity entity) {
|
||||
@@ -347,87 +333,62 @@ public class PcaSyncProtocol {
|
||||
PcaSyncProtocol.clearPlayerWatchEntity(player);
|
||||
}
|
||||
|
||||
public record UpdateEntityPayload(ResourceLocation dimension, int entityId, CompoundTag tag) implements LeavesCustomPayload<UpdateEntityPayload> {
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return LeavesConfig.protocol.pca.enable;
|
||||
}
|
||||
|
||||
public record UpdateEntityPayload(ResourceLocation dimension, int entityId, CompoundTag tag) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
public static final ResourceLocation UPDATE_ENTITY = PcaSyncProtocol.id("update_entity");
|
||||
|
||||
@New
|
||||
public UpdateEntityPayload(ResourceLocation location, FriendlyByteBuf byteBuf) {
|
||||
this(byteBuf.readResourceLocation(), byteBuf.readInt(), byteBuf.readNbt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull FriendlyByteBuf buf) {
|
||||
buf.writeResourceLocation(this.dimension);
|
||||
buf.writeInt(this.entityId);
|
||||
buf.writeNbt(this.tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return UPDATE_ENTITY;
|
||||
}
|
||||
@Codec
|
||||
public static final StreamCodec<FriendlyByteBuf, UpdateEntityPayload> CODEC = StreamCodec.composite(
|
||||
ResourceLocation.STREAM_CODEC,
|
||||
UpdateEntityPayload::dimension,
|
||||
ByteBufCodecs.INT,
|
||||
UpdateEntityPayload::entityId,
|
||||
ByteBufCodecs.COMPOUND_TAG,
|
||||
UpdateEntityPayload::tag,
|
||||
UpdateEntityPayload::new
|
||||
);
|
||||
}
|
||||
|
||||
public record UpdateBlockEntityPayload(ResourceLocation dimension, BlockPos blockPos, CompoundTag tag) implements LeavesCustomPayload<UpdateBlockEntityPayload> {
|
||||
public record UpdateBlockEntityPayload(ResourceLocation dimension, BlockPos blockPos, CompoundTag tag) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
private static final ResourceLocation UPDATE_BLOCK_ENTITY = PcaSyncProtocol.id("update_block_entity");
|
||||
|
||||
@New
|
||||
public UpdateBlockEntityPayload(ResourceLocation location, @NotNull FriendlyByteBuf byteBuf) {
|
||||
this(byteBuf.readResourceLocation(), byteBuf.readBlockPos(), byteBuf.readNbt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull FriendlyByteBuf buf) {
|
||||
buf.writeResourceLocation(this.dimension);
|
||||
buf.writeBlockPos(this.blockPos);
|
||||
buf.writeNbt(this.tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return UPDATE_BLOCK_ENTITY;
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<FriendlyByteBuf, UpdateBlockEntityPayload> CODEC = StreamCodec.composite(
|
||||
ResourceLocation.STREAM_CODEC,
|
||||
UpdateBlockEntityPayload::dimension,
|
||||
BlockPos.STREAM_CODEC,
|
||||
UpdateBlockEntityPayload::blockPos,
|
||||
ByteBufCodecs.COMPOUND_TAG,
|
||||
UpdateBlockEntityPayload::tag,
|
||||
UpdateBlockEntityPayload::new
|
||||
);
|
||||
}
|
||||
|
||||
public record SyncBlockEntityPayload(BlockPos pos) implements LeavesCustomPayload<SyncBlockEntityPayload> {
|
||||
|
||||
public record SyncBlockEntityPayload(BlockPos pos) implements LeavesCustomPayload {
|
||||
@ID
|
||||
public static final ResourceLocation SYNC_BLOCK_ENTITY = PcaSyncProtocol.id("sync_block_entity");
|
||||
|
||||
@New
|
||||
public SyncBlockEntityPayload(ResourceLocation id, @NotNull FriendlyByteBuf buf) {
|
||||
this(buf.readBlockPos());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull FriendlyByteBuf buf) {
|
||||
buf.writeBlockPos(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ResourceLocation id() {
|
||||
return SYNC_BLOCK_ENTITY;
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<FriendlyByteBuf, SyncBlockEntityPayload> CODEC = StreamCodec.composite(
|
||||
BlockPos.STREAM_CODEC, SyncBlockEntityPayload::pos, SyncBlockEntityPayload::new
|
||||
);
|
||||
}
|
||||
|
||||
public record SyncEntityPayload(int entityId) implements LeavesCustomPayload<SyncEntityPayload> {
|
||||
|
||||
public record SyncEntityPayload(int entityId) implements LeavesCustomPayload {
|
||||
@ID
|
||||
public static final ResourceLocation SYNC_ENTITY = PcaSyncProtocol.id("sync_entity");
|
||||
|
||||
@New
|
||||
public SyncEntityPayload(ResourceLocation id, @NotNull FriendlyByteBuf buf) {
|
||||
this(buf.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull FriendlyByteBuf buf) {
|
||||
buf.writeInt(entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ResourceLocation id() {
|
||||
return SYNC_ENTITY;
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<FriendlyByteBuf, SyncEntityPayload> CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.INT, SyncEntityPayload::entityId, SyncEntityPayload::new
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import org.leavesmc.leaves.LeavesConfig;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
|
||||
@LeavesProtocol(namespace = {"xaerominimap", "xaeroworldmap"})
|
||||
public class XaeroMapProtocol {
|
||||
@LeavesProtocol.Register(namespace = "xaerominimap_or_xaeroworldmap_i_dont_care")
|
||||
public class XaeroMapProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID_MINI = "xaerominimap";
|
||||
public static final String PROTOCOL_ID_WORLD = "xaeroworldmap";
|
||||
@@ -29,14 +29,19 @@ public class XaeroMapProtocol {
|
||||
|
||||
public static void onSendWorldInfo(@NotNull ServerPlayer player) {
|
||||
if (LeavesConfig.protocol.xaeroMapProtocol) {
|
||||
ProtocolUtils.sendPayloadPacket(player, MINIMAP_KEY, buf -> {
|
||||
ProtocolUtils.sendBytebufPacket(player, MINIMAP_KEY, buf -> {
|
||||
buf.writeByte(0);
|
||||
buf.writeInt(LeavesConfig.protocol.xaeroMapServerID);
|
||||
});
|
||||
ProtocolUtils.sendPayloadPacket(player, WORLDMAP_KEY, buf -> {
|
||||
ProtocolUtils.sendBytebufPacket(player, WORLDMAP_KEY, buf -> {
|
||||
buf.writeByte(0);
|
||||
buf.writeInt(LeavesConfig.protocol.xaeroMapServerID);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return LeavesConfig.protocol.xaeroMapProtocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.leavesmc.leaves.protocol.bladeren;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
@@ -17,15 +18,12 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@LeavesProtocol(namespace = "bladeren")
|
||||
public class BladerenProtocol {
|
||||
@LeavesProtocol.Register(namespace = "bladeren")
|
||||
public class BladerenProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "bladeren";
|
||||
public static final String PROTOCOL_VERSION = ProtocolUtils.buildProtocolVersion(PROTOCOL_ID);
|
||||
|
||||
private static final ResourceLocation HELLO_ID = id("hello");
|
||||
private static final ResourceLocation FEATURE_MODIFY_ID = id("feature_modify");
|
||||
|
||||
private static final Map<String, BiConsumer<ServerPlayer, CompoundTag>> registeredFeatures = new HashMap<>();
|
||||
|
||||
@Contract("_ -> new")
|
||||
@@ -33,50 +31,49 @@ public class BladerenProtocol {
|
||||
return ResourceLocation.tryBuild(PROTOCOL_ID, path);
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = BladerenHelloPayload.class, payloadId = "hello")
|
||||
@ProtocolHandler.PayloadReceiver(payload = BladerenHelloPayload.class)
|
||||
private static void handleHello(@NotNull ServerPlayer player, @NotNull BladerenHelloPayload payload) {
|
||||
if (LeavesConfig.protocol.bladeren.enable) {
|
||||
String clientVersion = payload.version;
|
||||
CompoundTag tag = payload.nbt;
|
||||
String clientVersion = payload.version;
|
||||
CompoundTag tag = payload.nbt;
|
||||
|
||||
LeavesLogger.LOGGER.info("Player " + player.getScoreboardName() + " joined with bladeren " + clientVersion);
|
||||
LeavesLogger.LOGGER.info("Player " + player.getScoreboardName() + " joined with bladeren " + clientVersion);
|
||||
|
||||
if (tag != null) {
|
||||
CompoundTag featureNbt = tag.getCompound("Features");
|
||||
for (String name : featureNbt.getAllKeys()) {
|
||||
if (registeredFeatures.containsKey(name)) {
|
||||
registeredFeatures.get(name).accept(player, featureNbt.getCompound(name));
|
||||
}
|
||||
if (tag != null) {
|
||||
CompoundTag featureNbt = tag.getCompound("Features").orElseThrow();
|
||||
for (String name : featureNbt.keySet()) {
|
||||
if (registeredFeatures.containsKey(name)) {
|
||||
registeredFeatures.get(name).accept(player, featureNbt.getCompound(name).orElseThrow());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = BladerenFeatureModifyPayload.class, payloadId = "feature_modify")
|
||||
@ProtocolHandler.PayloadReceiver(payload = BladerenFeatureModifyPayload.class)
|
||||
private static void handleModify(@NotNull ServerPlayer player, @NotNull BladerenFeatureModifyPayload payload) {
|
||||
if (LeavesConfig.protocol.bladeren.enable) {
|
||||
String name = payload.name;
|
||||
CompoundTag tag = payload.nbt;
|
||||
String name = payload.name;
|
||||
CompoundTag tag = payload.nbt;
|
||||
|
||||
if (registeredFeatures.containsKey(name)) {
|
||||
registeredFeatures.get(name).accept(player, tag);
|
||||
}
|
||||
if (registeredFeatures.containsKey(name)) {
|
||||
registeredFeatures.get(name).accept(player, tag);
|
||||
}
|
||||
}
|
||||
|
||||
@ProtocolHandler.PlayerJoin
|
||||
public static void onPlayerJoin(@NotNull ServerPlayer player) {
|
||||
if (LeavesConfig.protocol.bladeren.enable) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
LeavesFeatureSet.writeNBT(tag);
|
||||
ProtocolUtils.sendPayloadPacket(player, new BladerenHelloPayload(PROTOCOL_VERSION, tag));
|
||||
}
|
||||
CompoundTag tag = new CompoundTag();
|
||||
LeavesFeatureSet.writeNBT(tag);
|
||||
ProtocolUtils.sendPayloadPacket(player, new BladerenHelloPayload(PROTOCOL_VERSION, tag));
|
||||
}
|
||||
|
||||
public static void registerFeature(String name, BiConsumer<ServerPlayer, CompoundTag> consumer) {
|
||||
registeredFeatures.put(name, consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return LeavesConfig.protocol.bladeren.enable;
|
||||
}
|
||||
|
||||
public static class LeavesFeatureSet {
|
||||
|
||||
private static final Map<String, LeavesFeature> features = new HashMap<>();
|
||||
@@ -108,43 +105,33 @@ public class BladerenProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
public record BladerenFeatureModifyPayload(String name, CompoundTag nbt) implements LeavesCustomPayload<BladerenFeatureModifyPayload> {
|
||||
public record BladerenFeatureModifyPayload(String name, CompoundTag nbt) implements LeavesCustomPayload {
|
||||
|
||||
@New
|
||||
public BladerenFeatureModifyPayload(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
this(buf.readUtf(), buf.readNbt());
|
||||
}
|
||||
@ID
|
||||
private static final ResourceLocation FEATURE_MODIFY_ID = id("feature_modify");
|
||||
|
||||
@Override
|
||||
public void write(@NotNull FriendlyByteBuf buf) {
|
||||
buf.writeUtf(name);
|
||||
buf.writeNbt(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ResourceLocation id() {
|
||||
return FEATURE_MODIFY_ID;
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<FriendlyByteBuf, BladerenFeatureModifyPayload> CODEC = StreamCodec.of(
|
||||
(buf, payload) -> {
|
||||
buf.writeUtf(payload.name());
|
||||
buf.writeNbt(payload.nbt());
|
||||
},
|
||||
buffer -> new BladerenFeatureModifyPayload(buffer.readUtf(), buffer.readNbt())
|
||||
);
|
||||
}
|
||||
|
||||
public record BladerenHelloPayload(String version, CompoundTag nbt) implements LeavesCustomPayload<BladerenHelloPayload> {
|
||||
public record BladerenHelloPayload(String version, CompoundTag nbt) implements LeavesCustomPayload {
|
||||
|
||||
@New
|
||||
public BladerenHelloPayload(ResourceLocation location, @NotNull FriendlyByteBuf buf) {
|
||||
this(buf.readUtf(64), buf.readNbt());
|
||||
}
|
||||
@ID
|
||||
private static final ResourceLocation HELLO_ID = id("hello");
|
||||
|
||||
@Override
|
||||
public void write(@NotNull FriendlyByteBuf buf) {
|
||||
buf.writeUtf(version);
|
||||
buf.writeNbt(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ResourceLocation id() {
|
||||
return HELLO_ID;
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<FriendlyByteBuf, BladerenHelloPayload> CODEC = StreamCodec.of(
|
||||
(buf, payload) -> {
|
||||
buf.writeUtf(payload.version());
|
||||
buf.writeNbt(payload.nbt());
|
||||
},
|
||||
buffer -> new BladerenHelloPayload(buffer.readUtf(64), buffer.readNbt())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,13 +15,11 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.OptionalDouble;
|
||||
|
||||
@LeavesProtocol(namespace = "bladeren")
|
||||
public class MsptSyncProtocol {
|
||||
@LeavesProtocol.Register(namespace = "bladeren")
|
||||
public class MsptSyncProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "bladeren";
|
||||
|
||||
private static final ResourceLocation MSPT_SYNC = id("mspt_sync");
|
||||
|
||||
private static final List<ServerPlayer> players = new ArrayList<>();
|
||||
|
||||
@Contract("_ -> new")
|
||||
@@ -32,7 +30,7 @@ public class MsptSyncProtocol {
|
||||
@ProtocolHandler.Init
|
||||
public static void init() {
|
||||
BladerenProtocol.registerFeature("mspt_sync", (player, compoundTag) -> {
|
||||
if (compoundTag.getString("Value").equals("true")) {
|
||||
if (compoundTag.getStringOr("Value", "").equals("true")) {
|
||||
onPlayerSubmit(player);
|
||||
} else {
|
||||
onPlayerLoggedOut(player);
|
||||
@@ -42,36 +40,37 @@ public class MsptSyncProtocol {
|
||||
|
||||
@ProtocolHandler.PlayerLeave
|
||||
public static void onPlayerLoggedOut(@NotNull ServerPlayer player) {
|
||||
if (LeavesConfig.protocol.bladeren.msptSyncProtocol) {
|
||||
players.remove(player);
|
||||
}
|
||||
players.remove(player);
|
||||
}
|
||||
|
||||
@ProtocolHandler.Ticker
|
||||
public static void tick() {
|
||||
if (LeavesConfig.protocol.bladeren.msptSyncProtocol) {
|
||||
if (players.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftServer server = MinecraftServer.getServer();
|
||||
if (server.getTickCount() % LeavesConfig.protocol.bladeren.msptSyncTickInterval == 0) {
|
||||
OptionalDouble msptArr = Arrays.stream(server.getTickTimesNanos()).average();
|
||||
if (msptArr.isPresent()) {
|
||||
double mspt = msptArr.getAsDouble() * 1.0E-6D;
|
||||
double tps = 1000.0D / Math.max(mspt, 50);
|
||||
players.forEach(player -> ProtocolUtils.sendPayloadPacket(player, MSPT_SYNC, buf -> {
|
||||
buf.writeDouble(mspt);
|
||||
buf.writeDouble(tps);
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (players.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
MinecraftServer server = MinecraftServer.getServer();
|
||||
OptionalDouble msptArr = Arrays.stream(server.getTickTimesNanos()).average();
|
||||
if (msptArr.isPresent()) {
|
||||
double mspt = msptArr.getAsDouble() * 1.0E-6D;
|
||||
double tps = 1000.0D / Math.max(mspt, 50);
|
||||
players.forEach(player -> ProtocolUtils.sendBytebufPacket(player, MSPT_SYNC, buf -> {
|
||||
buf.writeDouble(mspt);
|
||||
buf.writeDouble(tps);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public static void onPlayerSubmit(@NotNull ServerPlayer player) {
|
||||
if (LeavesConfig.protocol.bladeren.msptSyncProtocol) {
|
||||
players.add(player);
|
||||
}
|
||||
players.add(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int tickerInterval(String tickerID) {
|
||||
return LeavesConfig.protocol.bladeren.msptSyncTickInterval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return LeavesConfig.protocol.bladeren.msptSyncProtocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package org.leavesmc.leaves.protocol.chatimage;
|
||||
|
||||
public class ChatImageIndex {
|
||||
|
||||
public int index;
|
||||
public int total;
|
||||
public String url;
|
||||
public String bytes;
|
||||
|
||||
public ChatImageIndex(int index, int total, String url, String bytes) {
|
||||
this.index = index;
|
||||
this.total = total;
|
||||
this.url = url;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@ import java.util.UUID;
|
||||
|
||||
import static org.leavesmc.leaves.protocol.chatimage.ServerBlockCache.SERVER_BLOCK_CACHE;
|
||||
|
||||
@LeavesProtocol(namespace = "chatimage")
|
||||
public class ChatImageProtocol {
|
||||
@LeavesProtocol.Register(namespace = "chatimage")
|
||||
public class ChatImageProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "chatimage";
|
||||
public static final Gson gson = new Gson();
|
||||
@@ -27,12 +27,8 @@ public class ChatImageProtocol {
|
||||
return ResourceLocation.tryBuild(PROTOCOL_ID, path);
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = FileChannelPayload.class, payloadId = "get_file_channel")
|
||||
public static void serverFileChannelReceived(ServerPlayer player, FileChannelPayload payload) {
|
||||
if (!LeavesConfig.protocol.chatImageProtocol) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = FileChannelPayload.class)
|
||||
public void serverFileChannelReceived(ServerPlayer player, FileChannelPayload payload) {
|
||||
MinecraftServer server = MinecraftServer.getServer();
|
||||
String res = payload.message();
|
||||
ChatImageIndex title = gson.fromJson(res, ChatImageIndex.class);
|
||||
@@ -52,12 +48,8 @@ public class ChatImageProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = FileInfoChannelPayload.class, payloadId = "file_info")
|
||||
public static void serverGetFileChannelReceived(ServerPlayer player, FileInfoChannelPayload packet) {
|
||||
if (!LeavesConfig.protocol.chatImageProtocol) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = FileInfoChannelPayload.class)
|
||||
public void serverGetFileChannelReceived(ServerPlayer player, FileInfoChannelPayload packet) {
|
||||
String url = packet.message();
|
||||
Map<Integer, String> list = SERVER_BLOCK_CACHE.getBlock(url);
|
||||
if (list == null) {
|
||||
@@ -69,4 +61,12 @@ public class ChatImageProtocol {
|
||||
ProtocolUtils.sendPayloadPacket(player, new DownloadFileChannelPayload(entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return LeavesConfig.protocol.chatImageProtocol;
|
||||
}
|
||||
|
||||
public record ChatImageIndex(int index, int total, String url, String bytes) {
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,18 @@
|
||||
package org.leavesmc.leaves.protocol.chatimage;
|
||||
|
||||
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 org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
|
||||
public record DownloadFileChannelPayload(String message) implements LeavesCustomPayload<DownloadFileChannelPayload> {
|
||||
public record DownloadFileChannelPayload(String message) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
private static final ResourceLocation ID = ChatImageProtocol.id("download_file_channel");
|
||||
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, DownloadFileChannelPayload> CODEC =
|
||||
StreamCodec.composite(ByteBufCodecs.STRING_UTF8, DownloadFileChannelPayload::message, DownloadFileChannelPayload::new);
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
CODEC.encode(ProtocolUtils.decorate(buf), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@New
|
||||
public static DownloadFileChannelPayload create(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
return CODEC.decode(ProtocolUtils.decorate(buf));
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, DownloadFileChannelPayload> CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.STRING_UTF8, DownloadFileChannelPayload::message, DownloadFileChannelPayload::new
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,18 @@
|
||||
package org.leavesmc.leaves.protocol.chatimage;
|
||||
|
||||
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 org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
|
||||
public record FileChannelPayload(String message) implements LeavesCustomPayload<FileChannelPayload> {
|
||||
public record FileChannelPayload(String message) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
private static final ResourceLocation ID = ChatImageProtocol.id("get_file_channel");
|
||||
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, FileChannelPayload> CODEC =
|
||||
StreamCodec.composite(ByteBufCodecs.STRING_UTF8, FileChannelPayload::message, FileChannelPayload::new);
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
CODEC.encode(ProtocolUtils.decorate(buf), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@New
|
||||
public static FileChannelPayload create(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
return CODEC.decode(ProtocolUtils.decorate(buf));
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, FileChannelPayload> CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.STRING_UTF8, FileChannelPayload::message, FileChannelPayload::new
|
||||
);
|
||||
}
|
||||
@@ -1,32 +1,18 @@
|
||||
package org.leavesmc.leaves.protocol.chatimage;
|
||||
|
||||
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 org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
|
||||
public record FileInfoChannelPayload(String message) implements LeavesCustomPayload<FileInfoChannelPayload> {
|
||||
public record FileInfoChannelPayload(String message) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
private static final ResourceLocation ID = ChatImageProtocol.id("file_info");
|
||||
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, FileInfoChannelPayload> CODEC =
|
||||
StreamCodec.composite(ByteBufCodecs.STRING_UTF8, FileInfoChannelPayload::message, FileInfoChannelPayload::new);
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
CODEC.encode(ProtocolUtils.decorate(buf), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@New
|
||||
public static FileInfoChannelPayload create(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
return CODEC.decode(ProtocolUtils.decorate(buf));
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, FileInfoChannelPayload> CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.STRING_UTF8, FileInfoChannelPayload::message, FileInfoChannelPayload::new
|
||||
);
|
||||
}
|
||||
@@ -19,15 +19,15 @@ public class ServerBlockCache {
|
||||
public Cache<String, Map<Integer, String>> blockCache = CacheBuilder.newBuilder().expireAfterAccess(60, TimeUnit.SECONDS).build();
|
||||
public Cache<String, Integer> fileCount = CacheBuilder.newBuilder().expireAfterAccess(60, TimeUnit.SECONDS).build();
|
||||
|
||||
public Map<Integer, String> createBlock(ChatImageIndex title, String imgBytes) {
|
||||
public Map<Integer, String> createBlock(ChatImageProtocol.ChatImageIndex title, String imgBytes) {
|
||||
try {
|
||||
Map<Integer, String> blocks = this.blockCache.get(title.url, HashMap::new);
|
||||
blocks.put(title.index, imgBytes);
|
||||
this.blockCache.put(title.url, blocks);
|
||||
this.fileCount.put(title.url, title.total);
|
||||
Map<Integer, String> blocks = this.blockCache.get(title.url(), HashMap::new);
|
||||
blocks.put(title.index(), imgBytes);
|
||||
this.blockCache.put(title.url(), blocks);
|
||||
this.fileCount.put(title.url(), title.total());
|
||||
return blocks;
|
||||
} catch (Exception e) {
|
||||
LeavesLogger.LOGGER.warning("Failed to create block for title " + title.url + ": " + e);
|
||||
LeavesLogger.LOGGER.warning("Failed to create block for title " + title.url() + ": " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.leavesmc.leaves.protocol.core;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -10,20 +9,22 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
public interface LeavesCustomPayload<T extends LeavesCustomPayload<T>> extends CustomPacketPayload {
|
||||
public interface LeavesCustomPayload extends CustomPacketPayload {
|
||||
|
||||
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface New {
|
||||
}
|
||||
|
||||
void write(FriendlyByteBuf buf);
|
||||
|
||||
ResourceLocation id();
|
||||
Type<? extends CustomPacketPayload> LEAVES_TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("leaves", "custom_payload"));
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
default Type<T> type() {
|
||||
return new CustomPacketPayload.Type<>(id());
|
||||
default @NotNull Type<? extends CustomPacketPayload> type() {
|
||||
return LEAVES_TYPE;
|
||||
}
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ID {
|
||||
}
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Codec {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,17 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface LeavesProtocol {
|
||||
String[] namespace();
|
||||
}
|
||||
public interface LeavesProtocol {
|
||||
|
||||
boolean isActive();
|
||||
|
||||
default int tickerInterval(String tickerID) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Register {
|
||||
String namespace();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,23 @@
|
||||
package org.leavesmc.leaves.protocol.core;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.bukkit.event.player.PlayerKickEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.leavesmc.leaves.LeavesLogger;
|
||||
import org.leavesmc.leaves.protocol.core.invoker.BytebufReceiverInvokerHolder;
|
||||
import org.leavesmc.leaves.protocol.core.invoker.EmptyInvokerHolder;
|
||||
import org.leavesmc.leaves.protocol.core.invoker.InitInvokerHolder;
|
||||
import org.leavesmc.leaves.protocol.core.invoker.MinecraftRegisterInvokerHolder;
|
||||
import org.leavesmc.leaves.protocol.core.invoker.PayloadReceiverInvokerHolder;
|
||||
import org.leavesmc.leaves.protocol.core.invoker.PlayerInvokerHolder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.JarURLConnection;
|
||||
@@ -22,8 +25,6 @@ import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -35,266 +36,288 @@ import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
// TODO refactor
|
||||
public class LeavesProtocolManager {
|
||||
|
||||
private static final Class<?>[] PAYLOAD_PARAMETER_TYPES = {ResourceLocation.class, FriendlyByteBuf.class};
|
||||
|
||||
private static final LeavesLogger LOGGER = LeavesLogger.LOGGER;
|
||||
|
||||
private static final Map<LeavesProtocol, Map<ProtocolHandler.PayloadReceiver, Executable>> KNOWN_TYPES = new HashMap<>();
|
||||
private static final Map<LeavesProtocol, Map<ProtocolHandler.PayloadReceiver, Method>> KNOW_RECEIVERS = new HashMap<>();
|
||||
private static Set<ResourceLocation> ALL_KNOWN_ID = new HashSet<>();
|
||||
private static final Map<Class<? extends LeavesCustomPayload>, PayloadReceiverInvokerHolder> PAYLOAD_RECEIVERS = new HashMap<>();
|
||||
private static final Map<Class<? extends LeavesCustomPayload>, ResourceLocation> IDS = new HashMap<>();
|
||||
private static final Map<Class<? extends LeavesCustomPayload>, StreamCodec<? super RegistryFriendlyByteBuf, LeavesCustomPayload>> CODECS = new HashMap<>();
|
||||
private static final Map<ResourceLocation, StreamCodec<? super RegistryFriendlyByteBuf, LeavesCustomPayload>> ID2CODEC = new HashMap<>();
|
||||
|
||||
private static final List<Method> TICKERS = new ArrayList<>();
|
||||
private static final List<Method> PLAYER_JOIN = new ArrayList<>();
|
||||
private static final List<Method> PLAYER_LEAVE = new ArrayList<>();
|
||||
private static final List<Method> RELOAD_SERVER = new ArrayList<>();
|
||||
private static final Map<LeavesProtocol, Map<ProtocolHandler.MinecraftRegister, Method>> MINECRAFT_REGISTER = new HashMap<>();
|
||||
private static final Map<String, BytebufReceiverInvokerHolder> STRICT_BYTEBUF_RECEIVERS = new HashMap<>();
|
||||
private static final Map<String, BytebufReceiverInvokerHolder> NAMESPACED_BYTEBUF_RECEIVERS = new HashMap<>();
|
||||
private static final List<BytebufReceiverInvokerHolder> GENERIC_BYTEBUF_RECEIVERS = new ArrayList<>();
|
||||
|
||||
private static final Map<String, MinecraftRegisterInvokerHolder> STRICT_MINECRAFT_REGISTER = new HashMap<>();
|
||||
private static final Map<String, MinecraftRegisterInvokerHolder> NAMESPACED_MINECRAFT_REGISTER = new HashMap<>();
|
||||
private static final List<MinecraftRegisterInvokerHolder> WILD_MINECRAFT_REGISTER = new ArrayList<>();
|
||||
|
||||
private static final List<EmptyInvokerHolder<ProtocolHandler.Ticker>> TICKERS = new ArrayList<>();
|
||||
|
||||
private static final List<PlayerInvokerHolder<ProtocolHandler.PlayerJoin>> PLAYER_JOIN = new ArrayList<>();
|
||||
private static final List<PlayerInvokerHolder<ProtocolHandler.PlayerLeave>> PLAYER_LEAVE = new ArrayList<>();
|
||||
private static final List<EmptyInvokerHolder<ProtocolHandler.ReloadServer>> RELOAD_SERVER = new ArrayList<>();
|
||||
private static final List<EmptyInvokerHolder<ProtocolHandler.ReloadDataPack>> RELOAD_DATAPACK = new ArrayList<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void init() {
|
||||
for (Class<?> clazz : getClasses("org.leavesmc.leaves.protocol")) {
|
||||
final LeavesProtocol protocol = clazz.getAnnotation(LeavesProtocol.class);
|
||||
if (protocol != null) {
|
||||
Set<Method> methods;
|
||||
try {
|
||||
Method[] publicMethods = clazz.getMethods();
|
||||
Method[] privateMethods = clazz.getDeclaredMethods();
|
||||
methods = new HashSet<>(publicMethods.length + privateMethods.length, 1.0f);
|
||||
Collections.addAll(methods, publicMethods);
|
||||
Collections.addAll(methods, privateMethods);
|
||||
} catch (NoClassDefFoundError error) {
|
||||
LOGGER.severe("Failed to load class " + clazz.getName() + " due to missing dependencies, " + error.getCause() + ": " + error.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
Map<ProtocolHandler.PayloadReceiver, Executable> map = KNOWN_TYPES.getOrDefault(protocol, new HashMap<>());
|
||||
for (final Method method : methods) {
|
||||
if (method.isBridge() || method.isSynthetic() || !Modifier.isStatic(method.getModifiers())) {
|
||||
if (LeavesCustomPayload.class.isAssignableFrom(clazz) && !clazz.equals(LeavesCustomPayload.class)) {
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
if (!Modifier.isStatic(field.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
method.setAccessible(true);
|
||||
|
||||
final ProtocolHandler.Init init = method.getAnnotation(ProtocolHandler.Init.class);
|
||||
if (init != null) {
|
||||
try {
|
||||
method.invoke(null);
|
||||
} catch (InvocationTargetException | IllegalAccessException exception) {
|
||||
LOGGER.severe("Failed to invoke init method " + method.getName() + " in " + clazz.getName() + ", " + exception.getCause() + ": " + exception.getMessage());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.PayloadReceiver receiver = method.getAnnotation(ProtocolHandler.PayloadReceiver.class);
|
||||
if (receiver != null) {
|
||||
try {
|
||||
boolean found = false;
|
||||
for (Method payloadMethod : receiver.payload().getDeclaredMethods()) {
|
||||
if (payloadMethod.isAnnotationPresent(LeavesCustomPayload.New.class)) {
|
||||
if (Arrays.equals(payloadMethod.getParameterTypes(), PAYLOAD_PARAMETER_TYPES) && payloadMethod.getReturnType() == receiver.payload() && Modifier.isStatic(payloadMethod.getModifiers())) {
|
||||
payloadMethod.setAccessible(true);
|
||||
map.put(receiver, payloadMethod);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
Constructor<? extends LeavesCustomPayload<?>> constructor = receiver.payload().getConstructor(PAYLOAD_PARAMETER_TYPES);
|
||||
if (constructor.isAnnotationPresent(LeavesCustomPayload.New.class)) {
|
||||
constructor.setAccessible(true);
|
||||
map.put(receiver, constructor);
|
||||
} else {
|
||||
throw new NoSuchMethodException();
|
||||
}
|
||||
}
|
||||
} catch (NoSuchMethodException exception) {
|
||||
LOGGER.severe("Failed to find constructor for " + receiver.payload().getName() + ", " + exception.getCause() + ": " + exception.getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!KNOW_RECEIVERS.containsKey(protocol)) {
|
||||
KNOW_RECEIVERS.put(protocol, new HashMap<>());
|
||||
}
|
||||
|
||||
KNOW_RECEIVERS.get(protocol).put(receiver, method);
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.Ticker ticker = method.getAnnotation(ProtocolHandler.Ticker.class);
|
||||
if (ticker != null) {
|
||||
TICKERS.add(method);
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.PlayerJoin playerJoin = method.getAnnotation(ProtocolHandler.PlayerJoin.class);
|
||||
if (playerJoin != null) {
|
||||
PLAYER_JOIN.add(method);
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.PlayerLeave playerLeave = method.getAnnotation(ProtocolHandler.PlayerLeave.class);
|
||||
if (playerLeave != null) {
|
||||
PLAYER_LEAVE.add(method);
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.ReloadServer reloadServer = method.getAnnotation(ProtocolHandler.ReloadServer.class);
|
||||
if (reloadServer != null) {
|
||||
RELOAD_SERVER.add(method);
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.MinecraftRegister minecraftRegister = method.getAnnotation(ProtocolHandler.MinecraftRegister.class);
|
||||
if (minecraftRegister != null) {
|
||||
if (!MINECRAFT_REGISTER.containsKey(protocol)) {
|
||||
MINECRAFT_REGISTER.put(protocol, new HashMap<>());
|
||||
}
|
||||
|
||||
MINECRAFT_REGISTER.get(protocol).put(minecraftRegister, method);
|
||||
}
|
||||
}
|
||||
KNOWN_TYPES.put(protocol, map);
|
||||
}
|
||||
}
|
||||
|
||||
for (LeavesProtocol protocol : KNOWN_TYPES.keySet()) {
|
||||
Map<ProtocolHandler.PayloadReceiver, Executable> map = KNOWN_TYPES.get(protocol);
|
||||
for (ProtocolHandler.PayloadReceiver receiver : map.keySet()) {
|
||||
if (receiver.sendFabricRegister() && !receiver.ignoreId()) {
|
||||
for (String payloadId : receiver.payloadId()) {
|
||||
for (String namespace : protocol.namespace()) {
|
||||
ALL_KNOWN_ID.add(ResourceLocation.tryBuild(namespace, payloadId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ALL_KNOWN_ID = ImmutableSet.copyOf(ALL_KNOWN_ID);
|
||||
}
|
||||
|
||||
public static LeavesCustomPayload<?> decode(ResourceLocation id, FriendlyByteBuf buf) {
|
||||
for (LeavesProtocol protocol : KNOWN_TYPES.keySet()) {
|
||||
if (!ArrayUtils.contains(protocol.namespace(), id.getNamespace())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<ProtocolHandler.PayloadReceiver, Executable> map = KNOWN_TYPES.get(protocol);
|
||||
for (ProtocolHandler.PayloadReceiver receiver : map.keySet()) {
|
||||
if (receiver.ignoreId() || ArrayUtils.contains(receiver.payloadId(), id.getPath())) {
|
||||
try {
|
||||
if (map.get(receiver) instanceof Constructor<?> constructor) {
|
||||
return (LeavesCustomPayload<?>) constructor.newInstance(id, buf);
|
||||
} else if (map.get(receiver) instanceof Method method) {
|
||||
return (LeavesCustomPayload<?>) method.invoke(null, id, buf);
|
||||
final LeavesCustomPayload.ID id = field.getAnnotation(LeavesCustomPayload.ID.class);
|
||||
if (id != null && field.getType().equals(ResourceLocation.class)) {
|
||||
IDS.put((Class<? extends LeavesCustomPayload>) clazz, (ResourceLocation) field.get(null));
|
||||
}
|
||||
} catch (InvocationTargetException | InstantiationException | IllegalAccessException exception) {
|
||||
LOGGER.warning("Failed to create payload for " + id + " in " + ArrayUtils.toString(protocol.namespace()) + ", " + exception.getCause() + ": " + exception.getMessage());
|
||||
buf.readBytes(buf.readableBytes());
|
||||
return new ErrorPayload(id, protocol.namespace(), receiver.payloadId());
|
||||
final LeavesCustomPayload.Codec codec = field.getAnnotation(LeavesCustomPayload.Codec.class);
|
||||
if (codec != null && field.getType().equals(StreamCodec.class)) {
|
||||
CODECS.put((Class<? extends LeavesCustomPayload>) clazz, (StreamCodec<? super RegistryFriendlyByteBuf, LeavesCustomPayload>) field.get(null));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void handlePayload(ServerPlayer player, LeavesCustomPayload<?> payload) {
|
||||
if (payload instanceof ErrorPayload errorPayload) {
|
||||
player.connection.disconnect(Component.literal("Payload " + Arrays.toString(errorPayload.packetID) + " from " + Arrays.toString(errorPayload.protocolID) + " error"), PlayerKickEvent.Cause.INVALID_PAYLOAD);
|
||||
return;
|
||||
}
|
||||
|
||||
for (LeavesProtocol protocol : KNOW_RECEIVERS.keySet()) {
|
||||
if (!ArrayUtils.contains(protocol.namespace(), payload.type().id().getNamespace())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<ProtocolHandler.PayloadReceiver, Method> map = KNOW_RECEIVERS.get(protocol);
|
||||
for (ProtocolHandler.PayloadReceiver receiver : map.keySet()) {
|
||||
if (payload.getClass() == receiver.payload()) {
|
||||
if (receiver.ignoreId() || ArrayUtils.contains(receiver.payloadId(), payload.type().id().getPath())) {
|
||||
try {
|
||||
map.get(receiver).invoke(null, player, payload);
|
||||
} catch (InvocationTargetException | IllegalAccessException exception) {
|
||||
LOGGER.warning("Failed to handle payload " + payload.type().id() + " in " + ArrayUtils.toString(protocol.namespace()) + ", " + exception.getCause() + ": " + exception.getMessage());
|
||||
final LeavesProtocol.Register register = clazz.getAnnotation(LeavesProtocol.Register.class);
|
||||
if (register == null) {
|
||||
continue;
|
||||
}
|
||||
LeavesProtocol protocol;
|
||||
try {
|
||||
Constructor<?> constructor = clazz.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
protocol = (LeavesProtocol) constructor.newInstance();
|
||||
} catch (Throwable throwable) {
|
||||
LOGGER.severe("Failed to load class " + clazz.getName() + ". " + throwable);
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.isBridge() || method.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
method.setAccessible(true);
|
||||
|
||||
final ProtocolHandler.Init init = method.getAnnotation(ProtocolHandler.Init.class);
|
||||
if (init != null) {
|
||||
InitInvokerHolder holder = new InitInvokerHolder(protocol, method, init);
|
||||
try {
|
||||
holder.invoke();
|
||||
} catch (RuntimeException exception) {
|
||||
LOGGER.severe("Failed to invoke init method " + method.getName() + " in " + clazz.getName() + ", " + exception.getCause() + ": " + exception.getMessage());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.PayloadReceiver payloadReceiver = method.getAnnotation(ProtocolHandler.PayloadReceiver.class);
|
||||
if (payloadReceiver != null) {
|
||||
PAYLOAD_RECEIVERS.put(payloadReceiver.payload(), new PayloadReceiverInvokerHolder(protocol, method, payloadReceiver));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.BytebufReceiver bytebufReceiver = method.getAnnotation(ProtocolHandler.BytebufReceiver.class);
|
||||
if (bytebufReceiver != null) {
|
||||
String key = bytebufReceiver.key();
|
||||
BytebufReceiverInvokerHolder holder = new BytebufReceiverInvokerHolder(protocol, method, bytebufReceiver);
|
||||
if (bytebufReceiver.onlyNamespace()) {
|
||||
NAMESPACED_BYTEBUF_RECEIVERS.put(key.isEmpty() ? register.namespace() : key, holder);
|
||||
} else {
|
||||
if (key.isEmpty()) {
|
||||
GENERIC_BYTEBUF_RECEIVERS.add(holder);
|
||||
} else {
|
||||
if (key.contains(":")) {
|
||||
STRICT_BYTEBUF_RECEIVERS.put(key, holder);
|
||||
} else {
|
||||
STRICT_BYTEBUF_RECEIVERS.put(register.namespace() + ":" + key, holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.Ticker ticker = method.getAnnotation(ProtocolHandler.Ticker.class);
|
||||
if (ticker != null) {
|
||||
TICKERS.add(new EmptyInvokerHolder<>(protocol, method, ticker));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.PlayerJoin playerJoin = method.getAnnotation(ProtocolHandler.PlayerJoin.class);
|
||||
if (playerJoin != null) {
|
||||
PLAYER_JOIN.add(new PlayerInvokerHolder<>(protocol, method, playerJoin));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.PlayerLeave playerLeave = method.getAnnotation(ProtocolHandler.PlayerLeave.class);
|
||||
if (playerLeave != null) {
|
||||
PLAYER_LEAVE.add(new PlayerInvokerHolder<>(protocol, method, playerLeave));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.ReloadServer reloadServer = method.getAnnotation(ProtocolHandler.ReloadServer.class);
|
||||
if (reloadServer != null) {
|
||||
RELOAD_SERVER.add(new EmptyInvokerHolder<>(protocol, method, reloadServer));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.ReloadDataPack reloadDataPack = method.getAnnotation(ProtocolHandler.ReloadDataPack.class);
|
||||
if (reloadDataPack != null) {
|
||||
RELOAD_DATAPACK.add(new EmptyInvokerHolder<>(protocol, method, reloadDataPack));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.MinecraftRegister minecraftRegister = method.getAnnotation(ProtocolHandler.MinecraftRegister.class);
|
||||
if (minecraftRegister != null) {
|
||||
String key = minecraftRegister.key();
|
||||
MinecraftRegisterInvokerHolder holder = new MinecraftRegisterInvokerHolder(protocol, method, minecraftRegister);
|
||||
if (minecraftRegister.onlyNamespace()) {
|
||||
NAMESPACED_MINECRAFT_REGISTER.put(key.isEmpty() ? register.namespace() : key, holder);
|
||||
} else {
|
||||
if (key.isEmpty()) {
|
||||
WILD_MINECRAFT_REGISTER.add(holder);
|
||||
} else {
|
||||
if (key.contains(":")) {
|
||||
STRICT_MINECRAFT_REGISTER.put(key, holder);
|
||||
} else {
|
||||
STRICT_MINECRAFT_REGISTER.put(register.namespace() + ":" + key, holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var idInfo : IDS.entrySet()) {
|
||||
var codec = CODECS.get(idInfo.getKey());
|
||||
if (codec == null) {
|
||||
throw new IllegalArgumentException("Payload " + idInfo.getKey() + " is not configured correctly");
|
||||
}
|
||||
ID2CODEC.put(idInfo.getValue(), codec);
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleTick() {
|
||||
if (!TICKERS.isEmpty()) {
|
||||
try {
|
||||
for (Method method : TICKERS) {
|
||||
method.invoke(null);
|
||||
}
|
||||
} catch (InvocationTargetException | IllegalAccessException exception) {
|
||||
LOGGER.warning("Failed to tick, " + exception.getCause() + ": " + exception.getMessage());
|
||||
public static LeavesCustomPayload decode(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
var codec = ID2CODEC.get(location);
|
||||
if (codec == null) {
|
||||
return null;
|
||||
}
|
||||
return codec.decode(ProtocolUtils.decorate(buf));
|
||||
}
|
||||
|
||||
public static void encode(FriendlyByteBuf buf, LeavesCustomPayload payload) {
|
||||
var location = IDS.get(payload.getClass());
|
||||
var codec = CODECS.get(payload.getClass());
|
||||
if (location == null || codec == null) {
|
||||
throw new IllegalArgumentException("Payload " + payload.getClass() + " is not configured correctly " + location + " " + codec);
|
||||
}
|
||||
buf.writeResourceLocation(location);
|
||||
codec.encode(ProtocolUtils.decorate(buf), payload);
|
||||
}
|
||||
|
||||
public static void handlePayload(ServerPlayer player, LeavesCustomPayload payload) {
|
||||
PayloadReceiverInvokerHolder holder;
|
||||
if ((holder = PAYLOAD_RECEIVERS.get(payload.getClass())) != null) {
|
||||
holder.invoke(player, payload);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean handleBytebuf(ServerPlayer player, ResourceLocation location, ByteBuf buf) {
|
||||
RegistryFriendlyByteBuf buf1 = ProtocolUtils.decorate(buf);
|
||||
BytebufReceiverInvokerHolder holder;
|
||||
if ((holder = STRICT_BYTEBUF_RECEIVERS.get(location.toString())) != null) {
|
||||
holder.invoke(player, buf1);
|
||||
return true;
|
||||
}
|
||||
if ((holder = NAMESPACED_BYTEBUF_RECEIVERS.get(location.getNamespace())) != null) {
|
||||
if (holder.invoke(player, buf1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (var holder1 : GENERIC_BYTEBUF_RECEIVERS) {
|
||||
if (holder1.invoke(player, buf1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void handleTick(long tickCount) {
|
||||
for (var tickerInfo : TICKERS) {
|
||||
if (tickCount % tickerInfo.owner().tickerInterval(tickerInfo.handler().tickerId()) == 0) {
|
||||
tickerInfo.invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void handlePlayerJoin(ServerPlayer player) {
|
||||
if (!PLAYER_JOIN.isEmpty()) {
|
||||
try {
|
||||
for (Method method : PLAYER_JOIN) {
|
||||
method.invoke(null, player);
|
||||
}
|
||||
} catch (InvocationTargetException | IllegalAccessException exception) {
|
||||
LOGGER.warning("Failed to handle player join, " + exception.getCause() + ": " + exception.getMessage());
|
||||
}
|
||||
sendKnownId(player);
|
||||
for (var join : PLAYER_JOIN) {
|
||||
join.invoke(player);
|
||||
}
|
||||
|
||||
ProtocolUtils.sendPayloadPacket(player, new FabricRegisterPayload(ALL_KNOWN_ID));
|
||||
}
|
||||
|
||||
public static void handlePlayerLeave(ServerPlayer player) {
|
||||
if (!PLAYER_LEAVE.isEmpty()) {
|
||||
try {
|
||||
for (Method method : PLAYER_LEAVE) {
|
||||
method.invoke(null, player);
|
||||
}
|
||||
} catch (InvocationTargetException | IllegalAccessException exception) {
|
||||
LOGGER.warning("Failed to handle player leave, " + exception.getCause() + ": " + exception.getMessage());
|
||||
}
|
||||
for (var leave : PLAYER_LEAVE) {
|
||||
leave.invoke(player);
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleServerReload() {
|
||||
if (!RELOAD_SERVER.isEmpty()) {
|
||||
try {
|
||||
for (Method method : RELOAD_SERVER) {
|
||||
method.invoke(null);
|
||||
}
|
||||
} catch (InvocationTargetException | IllegalAccessException exception) {
|
||||
LOGGER.warning("Failed to handle server reload, " + exception.getCause() + ": " + exception.getMessage());
|
||||
}
|
||||
for (var reload : RELOAD_SERVER) {
|
||||
reload.invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleDataPackReload() {
|
||||
for (var reload : RELOAD_DATAPACK) {
|
||||
reload.invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleMinecraftRegister(String channelId, ServerPlayer player) {
|
||||
for (LeavesProtocol protocol : MINECRAFT_REGISTER.keySet()) {
|
||||
String[] channel = channelId.split(":");
|
||||
if (!ArrayUtils.contains(protocol.namespace(), channel[0])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<ProtocolHandler.MinecraftRegister, Method> map = MINECRAFT_REGISTER.get(protocol);
|
||||
for (ProtocolHandler.MinecraftRegister register : map.keySet()) {
|
||||
if (register.ignoreId() || ArrayUtils.contains(register.channelId(), channel[1])) {
|
||||
try {
|
||||
map.get(register).invoke(null, player, channel[1]);
|
||||
} catch (InvocationTargetException | IllegalAccessException exception) {
|
||||
LOGGER.warning("Failed to handle minecraft register, " + exception.getCause() + ": " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
ResourceLocation location = ResourceLocation.tryParse(channelId);
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var wildHolder : WILD_MINECRAFT_REGISTER) {
|
||||
wildHolder.invoke(player, location);
|
||||
}
|
||||
|
||||
MinecraftRegisterInvokerHolder holder;
|
||||
if ((holder = STRICT_MINECRAFT_REGISTER.get(location.toString())) != null) {
|
||||
holder.invoke(player, location);
|
||||
}
|
||||
if ((holder = NAMESPACED_MINECRAFT_REGISTER.get(location.getNamespace())) != null) {
|
||||
holder.invoke(player, location);
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendKnownId(ServerPlayer player) {
|
||||
Set<String> set = new HashSet<>();
|
||||
PAYLOAD_RECEIVERS.forEach((clazz, holder) -> {
|
||||
if (holder.owner().isActive()) {
|
||||
set.add(IDS.get(clazz).toString());
|
||||
}
|
||||
});
|
||||
STRICT_BYTEBUF_RECEIVERS.forEach((key, holder) -> {
|
||||
if (holder.owner().isActive()) {
|
||||
set.add(key);
|
||||
}
|
||||
});
|
||||
ProtocolUtils.sendBytebufPacket(player, ResourceLocation.fromNamespaceAndPath("minecraft", "register"), buf -> {
|
||||
ResourceLocation channel;
|
||||
for (Iterator<String> var3 = set.iterator(); var3.hasNext(); buf.writeBytes(channel.toString().getBytes(StandardCharsets.US_ASCII))) {
|
||||
channel = ResourceLocation.parse(var3.next());
|
||||
buf.writeByte(0);
|
||||
}
|
||||
buf.writerIndex(Math.max(buf.writerIndex() - 1, 0));
|
||||
});
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getClasses(String pack) {
|
||||
@@ -371,63 +394,4 @@ public class LeavesProtocolManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record ErrorPayload(ResourceLocation id, String[] protocolID, String[] packetID) implements LeavesCustomPayload<ErrorPayload> {
|
||||
@Override
|
||||
public void write(@NotNull FriendlyByteBuf buf) {
|
||||
}
|
||||
}
|
||||
|
||||
public record EmptyPayload(ResourceLocation id) implements LeavesCustomPayload<EmptyPayload> {
|
||||
@New
|
||||
public EmptyPayload(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
this(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull FriendlyByteBuf buf) {
|
||||
}
|
||||
}
|
||||
|
||||
public record LeavesPayload(FriendlyByteBuf data, ResourceLocation id) implements LeavesCustomPayload<LeavesPayload> {
|
||||
@New
|
||||
public LeavesPayload(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
this(new FriendlyByteBuf(buf.readBytes(buf.readableBytes())), location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
buf.writeBytes(data);
|
||||
}
|
||||
}
|
||||
|
||||
public record FabricRegisterPayload(Set<ResourceLocation> channels) implements LeavesCustomPayload<FabricRegisterPayload> {
|
||||
|
||||
public static final ResourceLocation CHANNEL = ResourceLocation.withDefaultNamespace("register");
|
||||
|
||||
@New
|
||||
public FabricRegisterPayload(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
this(buf.readCollection(HashSet::new, FriendlyByteBuf::readResourceLocation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
boolean first = true;
|
||||
|
||||
ResourceLocation channel;
|
||||
for (Iterator<ResourceLocation> var3 = this.channels.iterator(); var3.hasNext(); buf.writeBytes(channel.toString().getBytes(StandardCharsets.US_ASCII))) {
|
||||
channel = var3.next();
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
buf.writeByte(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return CHANNEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,21 @@ public class ProtocolHandler {
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PayloadReceiver {
|
||||
Class<? extends LeavesCustomPayload<?>> payload();
|
||||
Class<? extends LeavesCustomPayload> payload();
|
||||
}
|
||||
|
||||
String[] payloadId() default "";
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface BytebufReceiver {
|
||||
String key() default "";
|
||||
|
||||
boolean ignoreId() default false;
|
||||
|
||||
boolean sendFabricRegister() default true;
|
||||
boolean onlyNamespace() default false;
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Ticker {
|
||||
int delay() default 0;
|
||||
String tickerId() default "";
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@@ -48,8 +50,13 @@ public class ProtocolHandler {
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MinecraftRegister {
|
||||
String[] channelId() default "";
|
||||
String key() default "";
|
||||
|
||||
boolean ignoreId() default false;
|
||||
boolean onlyNamespace() default false;
|
||||
}
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ReloadDataPack {
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.leavesmc.leaves.protocol.core;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.papermc.paper.ServerBuildInfo;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.network.protocol.common.custom.DiscardedPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -16,34 +18,24 @@ import java.util.function.Function;
|
||||
|
||||
public class ProtocolUtils {
|
||||
|
||||
private static final Function<ByteBuf, RegistryFriendlyByteBuf> bufDecorator = RegistryFriendlyByteBuf.decorator(MinecraftServer.getServer().registryAccess());
|
||||
private static final Function<ByteBuf, RegistryFriendlyByteBuf> bufDecorator = buf -> buf instanceof RegistryFriendlyByteBuf registry ? registry : new RegistryFriendlyByteBuf(buf, MinecraftServer.getServer().registryAccess());
|
||||
|
||||
public static String buildProtocolVersion(String protocol) {
|
||||
return protocol + "-leaves-" + ServerBuildInfo.buildInfo().asString(ServerBuildInfo.StringRepresentation.VERSION_SIMPLE);
|
||||
}
|
||||
|
||||
public static void sendEmptyPayloadPacket(ServerPlayer player, ResourceLocation id) {
|
||||
player.connection.send(new ClientboundCustomPayloadPacket(new LeavesProtocolManager.EmptyPayload(id)));
|
||||
public static void sendEmptyPacket(ServerPlayer player, ResourceLocation id) {
|
||||
player.internalConnection.send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, null)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static void sendPayloadPacket(@NotNull ServerPlayer player, ResourceLocation id, Consumer<FriendlyByteBuf> consumer) {
|
||||
player.connection.send(new ClientboundCustomPayloadPacket(new LeavesCustomPayload() {
|
||||
@Override
|
||||
public void write(@NotNull FriendlyByteBuf buf) {
|
||||
consumer.accept(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ResourceLocation id() {
|
||||
return id;
|
||||
}
|
||||
}));
|
||||
public static void sendBytebufPacket(@NotNull ServerPlayer player, ResourceLocation id, Consumer<? super RegistryFriendlyByteBuf> consumer) {
|
||||
RegistryFriendlyByteBuf buf = decorate(Unpooled.buffer());
|
||||
consumer.accept(buf);
|
||||
player.internalConnection.send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, ByteBufUtil.getBytes(buf))));
|
||||
}
|
||||
|
||||
public static void sendPayloadPacket(ServerPlayer player, CustomPacketPayload payload) {
|
||||
player.connection.send(new ClientboundCustomPayloadPacket(payload));
|
||||
player.internalConnection.send(new ClientboundCustomPayloadPacket(payload));
|
||||
}
|
||||
|
||||
public static RegistryFriendlyByteBuf decorate(ByteBuf buf) {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
public abstract class AbstractInvokerHolder<T> {
|
||||
|
||||
protected final LeavesProtocol owner;
|
||||
protected final Method invoker;
|
||||
protected final T handler;
|
||||
protected final Class<?> returnType;
|
||||
protected final Class<?>[] parameterTypes;
|
||||
|
||||
protected AbstractInvokerHolder(LeavesProtocol owner, Method invoker, T handler, @Nullable Class<?> returnType, @NotNull Class<?>... parameterTypes) {
|
||||
this.owner = owner;
|
||||
this.invoker = invoker;
|
||||
this.handler = handler;
|
||||
this.returnType = returnType;
|
||||
this.parameterTypes = parameterTypes;
|
||||
|
||||
validateMethodSignature();
|
||||
}
|
||||
|
||||
protected void validateMethodSignature() {
|
||||
if (returnType != null && !returnType.isAssignableFrom(invoker.getReturnType())) {
|
||||
throw new IllegalArgumentException("Return type mismatch in " + owner.getClass().getName() + "#" + invoker.getName() +
|
||||
": expected " + returnType.getName() + " but found " + invoker.getReturnType().getName());
|
||||
}
|
||||
|
||||
Class<?>[] methodParamTypes = invoker.getParameterTypes();
|
||||
if (methodParamTypes.length != parameterTypes.length) {
|
||||
throw new IllegalArgumentException("Parameter count mismatch in " + owner.getClass().getName() + "#" + invoker.getName() +
|
||||
": expected " + parameterTypes.length + " but found " + methodParamTypes.length);
|
||||
}
|
||||
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
if (!parameterTypes[i].isAssignableFrom(methodParamTypes[i])) {
|
||||
throw new IllegalArgumentException("Parameter type mismatch in " + owner.getClass().getName() + "#" + invoker.getName() +
|
||||
" at index " + i + ": expected " + parameterTypes[i].getName() + " but found " + methodParamTypes[i].getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LeavesProtocol owner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public T handler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
protected Object invoke0(boolean force, Object... args) {
|
||||
if (!force && !owner.isActive()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (Modifier.isStatic(invoker.getModifiers())) {
|
||||
return invoker.invoke(null, args);
|
||||
} else {
|
||||
return invoker.invoke(owner, args);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BytebufReceiverInvokerHolder extends AbstractInvokerHolder<ProtocolHandler.BytebufReceiver> {
|
||||
public BytebufReceiverInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.BytebufReceiver handler) {
|
||||
super(owner, invoker, handler, null, ServerPlayer.class, FriendlyByteBuf.class);
|
||||
}
|
||||
|
||||
public boolean invoke(ServerPlayer player, FriendlyByteBuf buf) {
|
||||
return invoke0(false, player, buf) instanceof Boolean b && b;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class EmptyInvokerHolder<T> extends AbstractInvokerHolder<T> {
|
||||
public EmptyInvokerHolder(LeavesProtocol owner, Method invoker, T handler) {
|
||||
super(owner, invoker, handler, null);
|
||||
}
|
||||
|
||||
public void invoke() {
|
||||
invoke0(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class InitInvokerHolder extends AbstractInvokerHolder<ProtocolHandler.Init> {
|
||||
public InitInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.Init handler) {
|
||||
super(owner, invoker, handler, null);
|
||||
}
|
||||
|
||||
public void invoke() {
|
||||
invoke0(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class MinecraftRegisterInvokerHolder extends AbstractInvokerHolder<ProtocolHandler.MinecraftRegister> {
|
||||
public MinecraftRegisterInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.MinecraftRegister handler) {
|
||||
super(owner, invoker, handler, null, ServerPlayer.class, ResourceLocation.class);
|
||||
}
|
||||
|
||||
public void invoke(ServerPlayer player, ResourceLocation id) {
|
||||
invoke0(false, player, id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class PayloadReceiverInvokerHolder extends AbstractInvokerHolder<ProtocolHandler.PayloadReceiver> {
|
||||
public PayloadReceiverInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.PayloadReceiver handler) {
|
||||
super(owner, invoker, handler, null, ServerPlayer.class, handler.payload());
|
||||
}
|
||||
|
||||
public void invoke(ServerPlayer player, LeavesCustomPayload payload) {
|
||||
invoke0(false, player, payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class PlayerInvokerHolder<T> extends AbstractInvokerHolder<T> {
|
||||
public PlayerInvokerHolder(LeavesProtocol owner, Method invoker, T handler) {
|
||||
super(owner, invoker, handler, null, ServerPlayer.class);
|
||||
}
|
||||
|
||||
public void invoke(ServerPlayer player) {
|
||||
invoke0(false, player);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ 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.animal.sniffer.Sniffer;
|
||||
import net.minecraft.world.entity.monster.ZombieVillager;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
@@ -55,6 +56,7 @@ import org.leavesmc.leaves.protocol.jade.provider.IServerExtensionProvider;
|
||||
import org.leavesmc.leaves.protocol.jade.provider.ItemStorageExtensionProvider;
|
||||
import org.leavesmc.leaves.protocol.jade.provider.ItemStorageProvider;
|
||||
import org.leavesmc.leaves.protocol.jade.provider.block.BeehiveProvider;
|
||||
import org.leavesmc.leaves.protocol.jade.provider.block.BlockNameProvider;
|
||||
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;
|
||||
@@ -64,7 +66,6 @@ import org.leavesmc.leaves.protocol.jade.provider.block.HopperLockProvider;
|
||||
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;
|
||||
@@ -78,26 +79,26 @@ 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 org.leavesmc.leaves.protocol.servux.litematics.utils.NbtUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@LeavesProtocol(namespace = "jade")
|
||||
public class JadeProtocol {
|
||||
|
||||
public static PriorityStore<ResourceLocation, IJadeProvider> priorities;
|
||||
private static List<Block> shearableBlocks = null;
|
||||
@LeavesProtocol.Register(namespace = "jade")
|
||||
public class JadeProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "jade";
|
||||
public static final String PROTOCOL_VERSION = "7";
|
||||
|
||||
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 = WrappedHierarchyLookup.forAccessor();
|
||||
private static final Set<ServerPlayer> enabledPlayers = new HashSet<>();
|
||||
|
||||
public static PriorityStore<ResourceLocation, IJadeProvider> priorities;
|
||||
private static List<Block> shearableBlocks = null;
|
||||
|
||||
@Contract("_ -> new")
|
||||
public static ResourceLocation id(String path) {
|
||||
return ResourceLocation.tryBuild(PROTOCOL_ID, path);
|
||||
@@ -113,7 +114,7 @@ public class JadeProtocol {
|
||||
priorities = new PriorityStore<>(IJadeProvider::getDefaultPriority, IJadeProvider::getUid);
|
||||
|
||||
// core plugin
|
||||
blockDataProviders.register(BlockEntity.class, ObjectNameProvider.ForBlock.INSTANCE);
|
||||
blockDataProviders.register(BlockEntity.class, BlockNameProvider.INSTANCE);
|
||||
|
||||
// universal plugin
|
||||
entityDataProviders.register(Entity.class, ItemStorageProvider.getEntity());
|
||||
@@ -133,6 +134,7 @@ public class JadeProtocol {
|
||||
|
||||
entityDataProviders.register(Chicken.class, NextEntityDropProvider.INSTANCE);
|
||||
entityDataProviders.register(Armadillo.class, NextEntityDropProvider.INSTANCE);
|
||||
entityDataProviders.register(Sniffer.class, NextEntityDropProvider.INSTANCE);
|
||||
|
||||
entityDataProviders.register(ZombieVillager.class, ZombieVillagerProvider.INSTANCE);
|
||||
|
||||
@@ -150,9 +152,10 @@ public class JadeProtocol {
|
||||
blockDataProviders.register(ChiseledBookShelfBlockEntity.class, ChiseledBookshelfProvider.INSTANCE);
|
||||
blockDataProviders.register(TrialSpawnerBlockEntity.class, MobSpawnerCooldownProvider.INSTANCE);
|
||||
|
||||
itemStorageProviders.register(CampfireBlock.class, CampfireProvider.INSTANCE);
|
||||
|
||||
blockDataProviders.idMapped();
|
||||
entityDataProviders.idMapped();
|
||||
itemStorageProviders.register(CampfireBlock.class, CampfireProvider.INSTANCE);
|
||||
|
||||
blockDataProviders.loadComplete(priorities);
|
||||
entityDataProviders.loadComplete(priorities);
|
||||
@@ -161,12 +164,8 @@ public class JadeProtocol {
|
||||
rebuildShearableBlocks();
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = ClientHandshakePayload.class, payloadId = "client_handshake")
|
||||
@ProtocolHandler.PayloadReceiver(payload = ClientHandshakePayload.class)
|
||||
public static void clientHandshake(ServerPlayer player, ClientHandshakePayload payload) {
|
||||
if (!LeavesConfig.protocol.jadeProtocol) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!payload.protocolVersion().equals(PROTOCOL_VERSION)) {
|
||||
player.sendSystemMessage(Component.literal("You are using a different version of Jade than the server. Please update Jade or report to the server operator").withColor(0xff0000));
|
||||
return;
|
||||
@@ -180,12 +179,8 @@ public class JadeProtocol {
|
||||
enabledPlayers.remove(player);
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = RequestEntityPayload.class, payloadId = "request_entity")
|
||||
@ProtocolHandler.PayloadReceiver(payload = RequestEntityPayload.class)
|
||||
public static void requestEntityData(ServerPlayer player, RequestEntityPayload payload) {
|
||||
if (!LeavesConfig.protocol.jadeProtocol) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftServer.getServer().execute(() -> {
|
||||
EntityAccessor accessor = payload.data().unpack(player);
|
||||
if (accessor == null) {
|
||||
@@ -220,12 +215,8 @@ public class JadeProtocol {
|
||||
});
|
||||
}
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = RequestBlockPayload.class, payloadId = "request_block")
|
||||
@ProtocolHandler.PayloadReceiver(payload = RequestBlockPayload.class)
|
||||
public static void requestBlockData(ServerPlayer player, RequestBlockPayload payload) {
|
||||
if (!LeavesConfig.protocol.jadeProtocol) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftServer server = MinecraftServer.getServer();
|
||||
server.execute(() -> {
|
||||
BlockAccessor accessor = payload.data().unpack(player);
|
||||
@@ -263,9 +254,7 @@ public class JadeProtocol {
|
||||
LeavesLogger.LOGGER.warning("Error while saving data for block " + accessor.getBlockState());
|
||||
}
|
||||
}
|
||||
tag.putInt("x", pos.getX());
|
||||
tag.putInt("y", pos.getY());
|
||||
tag.putInt("z", pos.getZ());
|
||||
NbtUtils.writeBlockPosToTag(pos, tag);
|
||||
tag.putString("BlockId", BuiltInRegistries.BLOCK.getKey(block).toString());
|
||||
|
||||
ProtocolUtils.sendPayloadPacket(player, new ReceiveDataPayload(tag));
|
||||
@@ -274,11 +263,9 @@ public class JadeProtocol {
|
||||
|
||||
@ProtocolHandler.ReloadServer
|
||||
public static void onServerReload() {
|
||||
if (LeavesConfig.protocol.jadeProtocol) {
|
||||
rebuildShearableBlocks();
|
||||
for (ServerPlayer player : enabledPlayers) {
|
||||
ProtocolUtils.sendPayloadPacket(player, new ServerHandshakePayload(Collections.emptyMap(), shearableBlocks, blockDataProviders.mappedIds(), entityDataProviders.mappedIds()));
|
||||
}
|
||||
rebuildShearableBlocks();
|
||||
for (ServerPlayer player : enabledPlayers) {
|
||||
ProtocolUtils.sendPayloadPacket(player, new ServerHandshakePayload(Collections.emptyMap(), shearableBlocks, blockDataProviders.mappedIds(), entityDataProviders.mappedIds()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,4 +280,9 @@ public class JadeProtocol {
|
||||
LeavesLogger.LOGGER.severe("Failed to collect shearable blocks");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return LeavesConfig.protocol.jadeProtocol;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import net.minecraft.world.phys.HitResult;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface Accessor<T extends HitResult> {
|
||||
|
||||
Level getLevel();
|
||||
|
||||
Player getPlayer();
|
||||
@@ -18,15 +17,6 @@ public interface Accessor<T extends HitResult> {
|
||||
|
||||
T getHitResult();
|
||||
|
||||
/**
|
||||
* @return {@code true} if the dedicated server has Jade installed.
|
||||
*/
|
||||
boolean isServerConnected();
|
||||
|
||||
boolean showDetails();
|
||||
|
||||
@Nullable
|
||||
Object getTarget();
|
||||
|
||||
float tickRate();
|
||||
}
|
||||
|
||||
@@ -17,17 +17,13 @@ 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) {
|
||||
public AccessorImpl(Level level, Player player, Supplier<T> hit) {
|
||||
this.level = level;
|
||||
this.player = player;
|
||||
this.hit = hit;
|
||||
this.serverConnected = serverConnected;
|
||||
this.showDetails = showDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,22 +57,4 @@ public abstract class AccessorImpl<T extends HitResult> implements Accessor<T> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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;
|
||||
@@ -22,16 +21,12 @@ public interface BlockAccessor extends Accessor<BlockHitResult> {
|
||||
|
||||
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);
|
||||
@@ -46,5 +41,4 @@ public interface BlockAccessor extends Accessor<BlockHitResult> {
|
||||
|
||||
BlockAccessor build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.leavesmc.leaves.protocol.jade.accessor;
|
||||
|
||||
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;
|
||||
@@ -30,7 +29,7 @@ public class BlockAccessorImpl extends AccessorImpl<BlockHitResult> implements B
|
||||
private final Supplier<BlockEntity> blockEntity;
|
||||
|
||||
private BlockAccessorImpl(Builder builder) {
|
||||
super(builder.level, builder.player, Suppliers.ofInstance(builder.hit), builder.connected, builder.showDetails);
|
||||
super(builder.level, builder.player, Suppliers.ofInstance(builder.hit));
|
||||
blockState = builder.blockState;
|
||||
blockEntity = builder.blockEntity;
|
||||
}
|
||||
@@ -55,11 +54,6 @@ public class BlockAccessorImpl extends AccessorImpl<BlockHitResult> implements B
|
||||
return getHitResult().getBlockPos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getSide() {
|
||||
return getHitResult().getDirection();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getTarget() {
|
||||
@@ -67,11 +61,8 @@ public class BlockAccessorImpl extends AccessorImpl<BlockHitResult> implements B
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -88,12 +79,6 @@ public class BlockAccessorImpl extends AccessorImpl<BlockHitResult> implements B
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder showDetails(boolean showDetails) {
|
||||
this.showDetails = showDetails;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder hit(BlockHitResult hit) {
|
||||
this.hit = hit;
|
||||
@@ -116,8 +101,6 @@ public class BlockAccessorImpl extends AccessorImpl<BlockHitResult> implements B
|
||||
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();
|
||||
@@ -132,15 +115,15 @@ public class BlockAccessorImpl extends AccessorImpl<BlockHitResult> implements B
|
||||
|
||||
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
|
||||
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) {
|
||||
@@ -149,13 +132,12 @@ public class BlockAccessorImpl extends AccessorImpl<BlockHitResult> implements B
|
||||
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();
|
||||
.level(player.level())
|
||||
.player(player)
|
||||
.hit(hit)
|
||||
.blockState(blockState)
|
||||
.blockEntity(blockEntity)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ public interface EntityAccessor extends Accessor<EntityHitResult> {
|
||||
|
||||
Builder player(Player player);
|
||||
|
||||
Builder showDetails(boolean showDetails);
|
||||
|
||||
default Builder hit(EntityHitResult hit) {
|
||||
return hit(() -> hit);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class EntityAccessorImpl extends AccessorImpl<EntityHitResult> implements
|
||||
private final Supplier<Entity> entity;
|
||||
|
||||
public EntityAccessorImpl(Builder builder) {
|
||||
super(builder.level, builder.player, builder.hit, builder.connected, builder.showDetails);
|
||||
super(builder.level, builder.player, builder.hit);
|
||||
entity = builder.entity;
|
||||
}
|
||||
|
||||
@@ -41,11 +41,8 @@ public class EntityAccessorImpl extends AccessorImpl<EntityHitResult> implements
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -61,11 +58,6 @@ public class EntityAccessorImpl extends AccessorImpl<EntityHitResult> implements
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder showDetails(boolean showDetails) {
|
||||
this.showDetails = showDetails;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder hit(Supplier<EntityHitResult> hit) {
|
||||
@@ -83,8 +75,6 @@ public class EntityAccessorImpl extends AccessorImpl<EntityHitResult> implements
|
||||
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;
|
||||
@@ -98,26 +88,25 @@ public class EntityAccessorImpl extends AccessorImpl<EntityHitResult> implements
|
||||
|
||||
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
|
||||
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();
|
||||
.level(player.level())
|
||||
.player(player)
|
||||
.entity(entity)
|
||||
.hit(Suppliers.memoize(() -> new EntityHitResult(entity.get(), hitVec)))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,19 @@
|
||||
package org.leavesmc.leaves.protocol.jade.payload;
|
||||
|
||||
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 org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
||||
|
||||
public record ClientHandshakePayload(String protocolVersion) implements LeavesCustomPayload<ClientHandshakePayload> {
|
||||
public record ClientHandshakePayload(String protocolVersion) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
private static final ResourceLocation PACKET_CLIENT_HANDSHAKE = JadeProtocol.id("client_handshake");
|
||||
|
||||
@Codec
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, ClientHandshakePayload> CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.STRING_UTF8,
|
||||
ClientHandshakePayload::protocolVersion,
|
||||
ClientHandshakePayload::new);
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
CODEC.encode(ProtocolUtils.decorate(buf), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return PACKET_CLIENT_HANDSHAKE;
|
||||
}
|
||||
|
||||
@New
|
||||
public static ClientHandshakePayload create(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
return CODEC.decode(ProtocolUtils.decorate(buf));
|
||||
}
|
||||
}
|
||||
ByteBufCodecs.STRING_UTF8, ClientHandshakePayload::protocolVersion, ClientHandshakePayload::new
|
||||
);
|
||||
}
|
||||
@@ -2,27 +2,19 @@ package org.leavesmc.leaves.protocol.jade.payload;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
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> {
|
||||
public record ReceiveDataPayload(CompoundTag tag) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
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;
|
||||
}
|
||||
@Codec
|
||||
private static final StreamCodec<FriendlyByteBuf, ReceiveDataPayload> CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.COMPOUND_TAG, ReceiveDataPayload::tag, ReceiveDataPayload::new
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
||||
import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
||||
import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessorImpl;
|
||||
@@ -20,9 +17,12 @@ 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> {
|
||||
public record RequestBlockPayload(BlockAccessorImpl.SyncData data, List<@Nullable IServerDataProvider<BlockAccessor>> dataProviders) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
private static final ResourceLocation PACKET_REQUEST_BLOCK = JadeProtocol.id("request_block");
|
||||
|
||||
@Codec
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, RequestBlockPayload> CODEC = StreamCodec.composite(
|
||||
BlockAccessorImpl.SyncData.STREAM_CODEC,
|
||||
RequestBlockPayload::data,
|
||||
@@ -32,20 +32,4 @@ public record RequestBlockPayload(BlockAccessorImpl.SyncData data, List<@Nullabl
|
||||
$ -> Objects.requireNonNull(blockDataProviders.idMapper()).getIdOrThrow($))),
|
||||
RequestBlockPayload::dataProviders,
|
||||
RequestBlockPayload::new);
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
CODEC.encode(ProtocolUtils.decorate(buf), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ResourceLocation id() {
|
||||
return PACKET_REQUEST_BLOCK;
|
||||
}
|
||||
|
||||
@New
|
||||
public static RequestBlockPayload create(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
return CODEC.decode(ProtocolUtils.decorate(buf));
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
||||
import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
||||
import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessorImpl;
|
||||
@@ -20,9 +17,12 @@ 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> {
|
||||
public record RequestEntityPayload(EntityAccessorImpl.SyncData data, List<@Nullable IServerDataProvider<EntityAccessor>> dataProviders) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
private static final ResourceLocation PACKET_REQUEST_ENTITY = JadeProtocol.id("request_entity");
|
||||
|
||||
@Codec
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, RequestEntityPayload> CODEC = StreamCodec.composite(
|
||||
EntityAccessorImpl.SyncData.STREAM_CODEC,
|
||||
RequestEntityPayload::data,
|
||||
@@ -33,21 +33,4 @@ public record RequestEntityPayload(EntityAccessorImpl.SyncData data, List<@Nulla
|
||||
)),
|
||||
RequestEntityPayload::dataProviders,
|
||||
RequestEntityPayload::new);
|
||||
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
CODEC.encode(ProtocolUtils.decorate(buf), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ResourceLocation id() {
|
||||
return PACKET_REQUEST_ENTITY;
|
||||
}
|
||||
|
||||
@New
|
||||
public static RequestEntityPayload create(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
return CODEC.decode(ProtocolUtils.decorate(buf));
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,12 @@ 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.world.level.block.Block;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
||||
|
||||
import java.util.List;
|
||||
@@ -19,9 +17,12 @@ import java.util.Map;
|
||||
|
||||
import static org.leavesmc.leaves.protocol.jade.util.JadeCodec.PRIMITIVE_STREAM_CODEC;
|
||||
|
||||
public record ServerHandshakePayload(Map<ResourceLocation, Object> serverConfig, List<Block> shearableBlocks, List<ResourceLocation> blockProviderIds, List<ResourceLocation> entityProviderIds) implements LeavesCustomPayload<ServerHandshakePayload> {
|
||||
public record ServerHandshakePayload(Map<ResourceLocation, Object> serverConfig, List<Block> shearableBlocks, List<ResourceLocation> blockProviderIds, List<ResourceLocation> entityProviderIds) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
private static final ResourceLocation PACKET_SERVER_HANDSHAKE = JadeProtocol.id("server_handshake");
|
||||
|
||||
@Codec
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, ServerHandshakePayload> CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.map(Maps::newHashMapWithExpectedSize, ResourceLocation.STREAM_CODEC, PRIMITIVE_STREAM_CODEC),
|
||||
ServerHandshakePayload::serverConfig,
|
||||
@@ -31,21 +32,6 @@ public record ServerHandshakePayload(Map<ResourceLocation, Object> serverConfig,
|
||||
ServerHandshakePayload::blockProviderIds,
|
||||
ByteBufCodecs.<ByteBuf, ResourceLocation>list().apply(ResourceLocation.STREAM_CODEC),
|
||||
ServerHandshakePayload::entityProviderIds,
|
||||
ServerHandshakePayload::new);
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
CODEC.encode(ProtocolUtils.decorate(buf), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return PACKET_SERVER_HANDSHAKE;
|
||||
}
|
||||
|
||||
@New
|
||||
public static ServerHandshakePayload create(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
return CODEC.decode(ProtocolUtils.decorate(buf));
|
||||
}
|
||||
}
|
||||
|
||||
ServerHandshakePayload::new
|
||||
);
|
||||
}
|
||||
@@ -37,52 +37,6 @@ public enum ItemStorageExtensionProvider implements IServerExtensionProvider<Ite
|
||||
|
||||
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.getContainerLootTable() != 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 -> {
|
||||
@@ -131,8 +85,54 @@ public enum ItemStorageExtensionProvider implements IServerExtensionProvider<Ite
|
||||
return null;
|
||||
}
|
||||
|
||||
@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.getContainerLootTable() != 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultPriority() {
|
||||
return IServerExtensionProvider.super.getDefaultPriority() + 1000;
|
||||
return 9999;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,7 @@ 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 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");
|
||||
|
||||
@@ -37,14 +36,6 @@ public abstract class ItemStorageProvider<T extends Accessor<?>> implements ISer
|
||||
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();
|
||||
@@ -83,6 +74,14 @@ public abstract class ItemStorageProvider<T extends Accessor<?>> implements ISer
|
||||
|
||||
@Override
|
||||
public int getDefaultPriority() {
|
||||
return 9999;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.leavesmc.leaves.protocol.jade.provider.block;
|
||||
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.ComponentSerialization;
|
||||
import net.minecraft.network.chat.contents.TranslatableContents;
|
||||
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 net.minecraft.world.level.block.state.properties.ChestType;
|
||||
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 BlockNameProvider implements StreamServerDataProvider<BlockAccessor, Component> {
|
||||
INSTANCE;
|
||||
|
||||
private static final ResourceLocation CORE_OBJECT_NAME = JadeProtocol.id("object_name");
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Component streamData(@NotNull BlockAccessor accessor) {
|
||||
if (!(accessor.getBlockEntity() instanceof Nameable nameable)) {
|
||||
return null;
|
||||
}
|
||||
if (nameable instanceof ChestBlockEntity && accessor.getBlock() instanceof ChestBlock && accessor.getBlockState().getValue(ChestBlock.TYPE) != ChestType.SINGLE) {
|
||||
MenuProvider menuProvider = accessor.getBlockState().getMenuProvider(accessor.getLevel(), accessor.getPosition());
|
||||
if (menuProvider != null) {
|
||||
Component name = menuProvider.getDisplayName();
|
||||
if (!(name.getContents() instanceof TranslatableContents contents) || !"container.chestDouble".equals(contents.getKey())) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
} else if (nameable.hasCustomName()) {
|
||||
return nameable.getDisplayName();
|
||||
}
|
||||
return accessor.getBlockEntity().components().get(DataComponents.ITEM_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamCodec<RegistryFriendlyByteBuf, Component> streamCodec() {
|
||||
return ComponentSerialization.STREAM_CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getUid() {
|
||||
return CORE_OBJECT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultPriority() {
|
||||
return -10100;
|
||||
}
|
||||
}
|
||||
@@ -34,10 +34,10 @@ public enum BrewingStandProvider implements StreamServerDataProvider<BlockAccess
|
||||
|
||||
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);
|
||||
ByteBufCodecs.VAR_INT,
|
||||
Data::fuel,
|
||||
ByteBufCodecs.VAR_INT,
|
||||
Data::time,
|
||||
Data::new);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ 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.ItemStorageProvider;
|
||||
import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
||||
|
||||
public enum ChiseledBookshelfProvider implements StreamServerDataProvider<BlockAccessor, ItemStack> {
|
||||
@@ -31,9 +32,13 @@ public enum ChiseledBookshelfProvider implements StreamServerDataProvider<BlockA
|
||||
return ItemStack.OPTIONAL_STREAM_CODEC;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ResourceLocation getUid() {
|
||||
return MC_CHISELED_BOOKSHELF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultPriority() {
|
||||
return ItemStorageProvider.getBlock().getDefaultPriority() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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;
|
||||
@@ -8,7 +7,6 @@ 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;
|
||||
@@ -21,20 +19,13 @@ public enum FurnaceProvider implements StreamServerDataProvider<BlockAccessor, F
|
||||
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());
|
||||
public @NotNull Data streamData(@NotNull BlockAccessor accessor) {
|
||||
AbstractFurnaceBlockEntity furnace = (AbstractFurnaceBlockEntity) accessor.getBlockEntity();
|
||||
return new Data(
|
||||
furnaceTag.getInt("CookTime"),
|
||||
furnaceTag.getInt("CookTimeTotal"),
|
||||
List.of(furnace.getItem(0), furnace.getItem(1), furnace.getItem(2)));
|
||||
furnace.cookingTimer,
|
||||
furnace.cookingTotalTime,
|
||||
List.of(furnace.getItem(0), furnace.getItem(1), furnace.getItem(2))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,12 +40,12 @@ public enum FurnaceProvider implements StreamServerDataProvider<BlockAccessor, F
|
||||
|
||||
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);
|
||||
ByteBufCodecs.VAR_INT,
|
||||
Data::progress,
|
||||
ByteBufCodecs.VAR_INT,
|
||||
Data::total,
|
||||
ItemStack.OPTIONAL_LIST_STREAM_CODEC,
|
||||
Data::inventory,
|
||||
Data::new);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,4 +29,9 @@ public enum HopperLockProvider implements StreamServerDataProvider<BlockAccessor
|
||||
public ResourceLocation getUid() {
|
||||
return MC_HOPPER_LOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultPriority() {
|
||||
return BlockNameProvider.INSTANCE.getDefaultPriority() + 10;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package org.leavesmc.leaves.protocol.jade.provider.block;
|
||||
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.ComponentSerialization;
|
||||
import net.minecraft.network.chat.contents.TranslatableContents;
|
||||
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 net.minecraft.world.level.block.state.properties.ChestType;
|
||||
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 && accessor.getBlockState().getValue(ChestBlock.TYPE) != ChestType.SINGLE) {
|
||||
MenuProvider menuProvider = accessor.getBlockState().getMenuProvider(accessor.getLevel(), accessor.getPosition());
|
||||
if (menuProvider != null) {
|
||||
Component name = menuProvider.getDisplayName();
|
||||
if (!(name.getContents() instanceof TranslatableContents contents) || !"container.chestDouble".equals(contents.getKey())) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
} else if (nameable.hasCustomName()) {
|
||||
return nameable.getDisplayName();
|
||||
}
|
||||
return accessor.getBlockEntity().components().get(DataComponents.ITEM_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamCodec<RegistryFriendlyByteBuf, Component> streamCodec() {
|
||||
return ComponentSerialization.STREAM_CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getUid() {
|
||||
return CORE_OBJECT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultPriority() {
|
||||
return -10100;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ 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.EntityReference;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.OwnableEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
||||
@@ -19,6 +21,16 @@ public enum AnimalOwnerProvider implements StreamServerDataProvider<EntityAccess
|
||||
|
||||
private static final ResourceLocation MC_ANIMAL_OWNER = JadeProtocol.mc_id("animal_owner");
|
||||
|
||||
public static UUID getOwnerUUID(Entity entity) {
|
||||
if (entity instanceof OwnableEntity ownableEntity) {
|
||||
EntityReference<LivingEntity> reference = ownableEntity.getOwnerReference();
|
||||
if (reference != null) {
|
||||
return reference.getUUID();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String streamData(@NotNull EntityAccessor accessor) {
|
||||
return CommonUtil.getLastKnownUsername(getOwnerUUID(accessor.getEntity()));
|
||||
@@ -29,13 +41,6 @@ public enum AnimalOwnerProvider implements StreamServerDataProvider<EntityAccess
|
||||
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;
|
||||
|
||||
@@ -2,8 +2,10 @@ package org.leavesmc.leaves.protocol.jade.provider.entity;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
||||
import net.minecraft.world.entity.animal.Chicken;
|
||||
import net.minecraft.world.entity.animal.armadillo.Armadillo;
|
||||
import net.minecraft.world.entity.animal.sniffer.Sniffer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
||||
import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
||||
@@ -25,6 +27,11 @@ public enum NextEntityDropProvider implements IServerDataProvider<EntityAccessor
|
||||
if (!armadillo.isBaby() && armadillo.scuteTime < max) {
|
||||
tag.putInt("NextScuteIn", armadillo.scuteTime);
|
||||
}
|
||||
} else if (accessor.getEntity() instanceof Sniffer sniffer) {
|
||||
long time = sniffer.getBrain().getTimeUntilExpiry(MemoryModuleType.SNIFF_COOLDOWN);
|
||||
if (time > 0 && time < max) {
|
||||
tag.putInt("NextSniffIn", (int) time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
package org.leavesmc.leaves.protocol.jade.tool;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
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.item.component.Tool;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ShearsToolHandler extends SimpleToolHandler {
|
||||
public class ShearsToolHandler {
|
||||
|
||||
private static final ShearsToolHandler INSTANCE = new ShearsToolHandler();
|
||||
|
||||
private final List<ItemStack> tools;
|
||||
|
||||
public ShearsToolHandler() {
|
||||
this.tools = List.of(Items.SHEARS.getDefaultInstance());
|
||||
}
|
||||
|
||||
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();
|
||||
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 super.test(state, world, pos);
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
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();
|
||||
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
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;
|
||||
@@ -21,10 +18,6 @@ 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;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class HierarchyLookup<T extends IJadeProvider> implements IHierarchyLooku
|
||||
return resultCache.get(clazz, () -> {
|
||||
List<T> list = Lists.newArrayList();
|
||||
getInternal(clazz, list);
|
||||
list = ImmutableList.sortedCopyOf(Comparator.comparingInt(JadeProtocol.priorities::byValue), list);
|
||||
list = ImmutableList.sortedCopyOf(COMPARATOR, list);
|
||||
if (singleton && !list.isEmpty()) {
|
||||
return ImmutableList.of(list.getFirst());
|
||||
}
|
||||
@@ -135,5 +135,4 @@ public class HierarchyLookup<T extends IJadeProvider> implements IHierarchyLooku
|
||||
idMapper = createIdMapper();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,15 +4,20 @@ 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.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.stream.Stream;
|
||||
|
||||
public interface IHierarchyLookup<T extends IJadeProvider> {
|
||||
|
||||
Comparator<IJadeProvider> COMPARATOR = Comparator.comparingInt(provider -> JadeProtocol.priorities.byValue(provider));
|
||||
|
||||
default IHierarchyLookup<? extends T> cast() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ 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 net.minecraft.world.item.component.TooltipDisplay;
|
||||
import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
||||
|
||||
import java.util.List;
|
||||
@@ -17,15 +18,17 @@ 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 -> {
|
||||
private static final Predicate<ItemStack> SHOWN = 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)) {
|
||||
if (stack.getOrDefault(DataComponents.TOOLTIP_DISPLAY, TooltipDisplay.DEFAULT).hideTooltip()) {
|
||||
return false;
|
||||
}
|
||||
if (stack.hasNonDefault(DataComponents.CUSTOM_MODEL_DATA) || stack.hasNonDefault(DataComponents.ITEM_MODEL)) {
|
||||
CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
|
||||
for (String key : tag.keySet()) {
|
||||
if (key.toLowerCase(Locale.ENGLISH).endsWith("clear") && tag.getBooleanOr(key, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -65,7 +68,7 @@ public class ItemCollector<T> {
|
||||
AtomicInteger count = new AtomicInteger();
|
||||
iterator.populate(container).forEach(stack -> {
|
||||
count.incrementAndGet();
|
||||
if (NON_EMPTY.test(stack)) {
|
||||
if (SHOWN.test(stack)) {
|
||||
ItemDefinition def = new ItemDefinition(stack);
|
||||
items.addTo(def, stack.getCount());
|
||||
}
|
||||
|
||||
@@ -50,6 +50,25 @@ public class LootTableMineableCollector {
|
||||
return list;
|
||||
}
|
||||
|
||||
public static boolean isCorrectConditions(@NotNull List<LootItemCondition> conditions, ItemStack toolItem) {
|
||||
if (conditions.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LootItemCondition condition = conditions.getFirst();
|
||||
if (condition instanceof MatchTool(Optional<ItemPredicate> predicate)) {
|
||||
ItemPredicate itemPredicate = 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;
|
||||
}
|
||||
|
||||
private boolean doLootTable(LootTable lootTable) {
|
||||
if (lootTable == null || lootTable == LootTable.EMPTY) {
|
||||
return false;
|
||||
@@ -87,23 +106,4 @@ public class LootTableMineableCollector {
|
||||
}
|
||||
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(Optional<ItemPredicate> predicate)) {
|
||||
ItemPredicate itemPredicate = 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;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user