9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

改进totem指令

This commit is contained in:
XiaoMoMi
2025-10-03 22:58:31 +08:00
parent 446d68502c
commit ccda02e468
6 changed files with 68 additions and 15 deletions

View File

@@ -30,10 +30,12 @@ import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.flag.CommandFlag;
import org.incendo.cloud.parser.standard.FloatParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
public class TotemAnimationCommand extends BukkitCommandFeature<CommandSender> {
@@ -46,6 +48,7 @@ public class TotemAnimationCommand extends BukkitCommandFeature<CommandSender> {
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.flag(FlagKeys.SILENT_FLAG)
.flag(CommandFlag.builder("no-sound"))
.required("players", MultiplePlayerSelectorParser.multiplePlayerSelectorParser())
.required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
@@ -53,7 +56,16 @@ public class TotemAnimationCommand extends BukkitCommandFeature<CommandSender> {
return CompletableFuture.completedFuture(plugin().itemManager().cachedTotemSuggestions());
}
}))
.flag(CommandFlag.builder("sound").withComponent(NamespacedKeyParser.namespacedKeyParser()).build())
.optional("sound", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
return CompletableFuture.completedFuture(plugin().soundManager().cachedSoundSuggestions());
}
}))
.optional("volume", FloatParser.floatParser(0f))
.optional("pitch", FloatParser.floatParser(0f, 2f))
.optional("min-volume", FloatParser.floatParser(0f))
.optional("min-pitch", FloatParser.floatParser(0f, 2f))
.handler(context -> {
NamespacedKey namespacedKey = context.get("id");
Key key = Key.of(namespacedKey.namespace(), namespacedKey.value());
@@ -62,6 +74,16 @@ public class TotemAnimationCommand extends BukkitCommandFeature<CommandSender> {
handleFeedback(context, MessageConstants.COMMAND_TOTEM_NOT_TOTEM, Component.text(key.toString()));
return;
}
Optional<NamespacedKey> soundKey = context.optional("sound");
SoundData soundData = null;
if (soundKey.isPresent()) {
float volume = context.getOrDefault("volume", 1.0f);
float pitch = context.getOrDefault("pitch", 1.0f);
float minVolume = context.getOrDefault("min-volume", 1.0f);
float minPitch = context.getOrDefault("min-pitch", 1.0f);
soundData = SoundData.of(KeyUtils.namespacedKey2Key(soundKey.get()), SoundData.SoundValue.ranged(minVolume, volume), SoundData.SoundValue.ranged(minPitch, pitch));
}
boolean removeSound = context.flags().hasFlag("no-sound");
MultiplePlayerSelector selector = context.get("players");
for (Player player : selector.values()) {
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player);
@@ -69,13 +91,11 @@ public class TotemAnimationCommand extends BukkitCommandFeature<CommandSender> {
if (VersionHelper.isOrAbove1_21_2()) {
item.setJavaComponent(ComponentTypes.DEATH_PROTECTION, Map.of());
}
NamespacedKey soundKey = context.flags().get("sound");
SoundData soundData = null;
if (soundKey != null) {
soundData = SoundData.of(KeyUtils.namespacedKey2Key(soundKey), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1);
}
PlayerUtils.sendTotemAnimation(serverPlayer, item, soundData);
// TODO 存在第一次进服 未正确移除图腾声音的问题
PlayerUtils.sendTotemAnimation(serverPlayer, item, soundData, removeSound);
}
// TODO 消息提示
});
}

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.util;
import com.mojang.datafixers.util.Pair;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.item.ComponentTypes;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
@@ -56,15 +57,19 @@ public final class PlayerUtils {
}
}
public static void sendTotemAnimation(Player player, Item<ItemStack> totem, @Nullable SoundData sound) {
public static void sendTotemAnimation(Player player, Item<ItemStack> totem, @Nullable SoundData sound, boolean removeSound) {
List<Object> packets = new ArrayList<>();
try {
Object totemItem = totem.getLiteralObject();
Item<?> previousMainHandItem = player.getItemInHand(InteractionHand.MAIN_HAND);
boolean flag = previousMainHandItem.id().equals(ItemKeys.TOTEM_OF_UNDYING);
boolean isMainHandTotem;
if (VersionHelper.isOrAbove1_21_2()) {
isMainHandTotem = previousMainHandItem.hasComponent(ComponentTypes.DEATH_PROTECTION);
} else {
isMainHandTotem = previousMainHandItem.id().equals(ItemKeys.TOTEM_OF_UNDYING);
}
Object previousOffHandItem = player.getItemInHand(InteractionHand.OFF_HAND).getLiteralObject();
if (flag) {
if (isMainHandTotem) {
packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance(
player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$MAINHAND, BukkitItemManager.instance().uniqueEmptyItem().item().getLiteralObject()))
));
@@ -73,7 +78,7 @@ public final class PlayerUtils {
player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, totemItem))
));
packets.add(NetworkReflections.constructor$ClientboundEntityEventPacket.newInstance(player.serverPlayer(), (byte) 35));
if (flag) {
if (isMainHandTotem) {
packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance(
player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$MAINHAND, previousMainHandItem.getLiteralObject()))
));
@@ -81,12 +86,13 @@ public final class PlayerUtils {
packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance(
player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, previousOffHandItem))
));
if (sound != null) {
if (sound != null || removeSound) {
packets.add(NetworkReflections.constructor$ClientboundStopSoundPacket.newInstance(
FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.totem.use"),
CoreReflections.instance$SoundSource$PLAYERS
));
}
if (sound != null) {
packets.add(FastNMS.INSTANCE.constructor$ClientboundSoundPacket(
FastNMS.INSTANCE.method$Holder$direct(FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(sound.id()), Optional.empty())),
CoreReflections.instance$SoundSource$PLAYERS,
@@ -94,7 +100,6 @@ public final class PlayerUtils {
RandomUtils.generateRandomLong()
));
}
player.sendPackets(packets, false);
} catch (ReflectiveOperationException e) {
BukkitCraftEngine.instance().logger().warn("Failed to send totem animation");

View File

@@ -172,6 +172,7 @@ public abstract class CraftEngine implements Plugin {
// collect illegal characters from minecraft:default font
this.fontManager.delayedLoad();
this.advancementManager.delayedLoad();
this.soundManager.delayedLoad();
if (reloadRecipe) {
// convert data pack recipes
this.recipeManager.delayedLoad();

View File

@@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.*;
import org.incendo.cloud.suggestion.Suggestion;
import java.nio.file.Path;
import java.util.*;
@@ -21,6 +22,7 @@ public abstract class AbstractSoundManager implements SoundManager {
protected final SoundParser soundParser;
protected final SongParser songParser;
protected final Map<Integer, Key> customSoundsInRegistry = new HashMap<>();
protected final List<Suggestion> soundSuggestions = new ArrayList<>();
public AbstractSoundManager(CraftEngine plugin) {
this.plugin = plugin;
@@ -43,6 +45,22 @@ public abstract class AbstractSoundManager implements SoundManager {
this.byId.clear();
this.byNamespace.clear();
this.songs.clear();
this.soundSuggestions.clear();
}
@Override
public void delayedLoad() {
for (Key key : VANILLA_SOUND_EVENTS) {
this.soundSuggestions.add(Suggestion.suggestion(key.asString()));
}
for (Key key : this.byId.keySet()) {
this.soundSuggestions.add(Suggestion.suggestion(key.asString()));
}
}
@Override
public List<Suggestion> cachedSoundSuggestions() {
return this.soundSuggestions;
}
@Override

View File

@@ -57,6 +57,11 @@ public record SoundData(Key id, SoundValue volume, SoundValue pitch) {
}
static SoundValue ranged(float min, float max) {
if (min > max) {
return new Ranged(max, min);
} else if (min == max) {
return SoundValue.fixed(max);
}
return new Ranged(min, max);
}

View File

@@ -3,7 +3,9 @@ package net.momirealms.craftengine.core.sound;
import net.momirealms.craftengine.core.plugin.Manageable;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.util.Key;
import org.incendo.cloud.suggestion.Suggestion;
import java.util.List;
import java.util.Map;
public interface SoundManager extends Manageable {
@@ -12,5 +14,7 @@ public interface SoundManager extends Manageable {
ConfigParser[] parsers();
List<Suggestion> cachedSoundSuggestions();
Map<Key, SoundEvent> sounds();
}