跳转至内容

[原创][Mod]通过特定格式文字进行查找结构

妙妙工具
1 1 76 1
  • 故事的起因是有帮twf写模组时,需要用到查找结构指令显示坐标给玩家,但是玩家不一定有权限或者ftbq发送并不会sendmessage给玩家,所以有了此代码。
    我也将结构查找的功能写成了一个类,可以直接拿去用。

    public class StructureLocator {
        private static final ResourceKey<Registry<ConfiguredStructureFeature<?, ?>>> STRUCTURE_REGISTRY_KEY =
                Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY;
    
        /**
         * 根据单个结构 ResourceLocation(如 "minecraft:village" 或者自定义 mod:id)查找最近的那个点。
         *
         * @param level     当前维度
         * @param center    中心搜索点
         * @param id        结构的 ResourceLocation
         * @param radius    搜索半径(方块数)
         * @param skipKnown 是否跳过已探索过的结构
         * @return 如果找到,返回 Pair(结构坐标, Holder<该结构>); 找不到则 empty()
         */
        public static Optional<Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>>> findNearest(
                ServerLevel level,
                BlockPos center,
                ResourceLocation id,
                int radius,
                boolean skipKnown
        ) {
            Registry<ConfiguredStructureFeature<?, ?>> registry =
                    level.registryAccess().registryOrThrow(STRUCTURE_REGISTRY_KEY);
    
            ResourceKey<ConfiguredStructureFeature<?, ?>> key =
                    ResourceKey.create(STRUCTURE_REGISTRY_KEY, id);
    
            Holder<ConfiguredStructureFeature<?, ?>> holder =
                    registry.getHolder(key).orElse(null);
            if (holder == null) return Optional.empty();
    
            HolderSet<ConfiguredStructureFeature<?, ?>> holderSet = HolderSet.direct(holder);
            Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>> result =
                    level.getChunkSource()
                            .getGenerator()
                            .findNearestMapFeature(level, holderSet, center, radius, skipKnown);
    
            return Optional.ofNullable(result);
        }
    
        /**
         * 根据 TagKey(像 "#minecraft:village")来查找最近的结构。
         *
         * @param level     当前维度
         * @param center    中心搜索点
         * @param tagKey    结构 TagKey(Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY 下的 Tag)
         * @param radius    搜索半径
         * @param skipKnown 是否跳过已探索结构
         * @return 如果找到,返回 Pair(结构坐标, Holder<该结构>); 找不到则 empty()
         */
        public static Optional<Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>>> findNearestByTag(
                ServerLevel level,
                BlockPos center,
                TagKey<ConfiguredStructureFeature<?, ?>> tagKey,
                int radius,
                boolean skipKnown
        ) {
            Registry<ConfiguredStructureFeature<?, ?>> registry =
                    level.registryAccess().registryOrThrow(STRUCTURE_REGISTRY_KEY);
    
            HolderSet<ConfiguredStructureFeature<?, ?>> holderSet =
                    registry.getOrCreateTag(tagKey);
            Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>> result =
                    level.getChunkSource()
                            .getGenerator()
                            .findNearestMapFeature(level, holderSet, center, radius, skipKnown);
    
            return Optional.ofNullable(result);
        }
    
        /**
         * 把查到的结果格式化成一个聊天用的组件(绿色坐标 + 距离)。
         *
         * @param structureName 你想显示的结构名称(如 "minecraft:village" 或 "#minecraft:village")
         * @param origin        搜索中心
         * @param pair          findNearest 返回的 Pair
         * @param translateKey  翻译 key,通常用 "commands.locate.success"
         */
        public static Component formatLocateResult(
                String structureName,
                BlockPos origin,
                Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>> pair,
                String translateKey
        ) {
            BlockPos found = pair.getFirst();
            int distance = Mth.floor(
                    dist(origin.getX(), origin.getZ(), found.getX(), found.getZ())
            );
    
            MutableComponent coords = ComponentUtils.wrapInSquareBrackets(
                            new TranslatableComponent("chat.coordinates", found.getX(), "~", found.getZ())
                    );
    
            return new TranslatableComponent(
                    translateKey, structureName, coords, distance
            );
        }
    
        private static float dist(int x1, int z1, int x2, int z2) {
            int dx = x2 - x1, dz = z2 - z1;
            return Mth.sqrt((float) (dx * dx + dz * dz));
        }
    }
    

    这部分代码就是查找结构有关的类了,通过获取ConfiguredStructureFeature的注册表,然后再获取结构的Holder类,再给ChunkGenerator的findNearestMapFeature方法去获取到BlockPos。

    @Mixin(ServerPlayer.class)
    public class ServerPlayerMixin {
        @ModifyArg(method = "sendMessage(Lnet/minecraft/network/chat/Component;Lnet/minecraft/network/chat/ChatType;Ljava/util/UUID;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/game/ClientboundChatPacket;<init>(Lnet/minecraft/network/chat/Component;Lnet/minecraft/network/chat/ChatType;Ljava/util/UUID;)V"), index = 0)
        public Component modifyMessage(Component component){
            MutableComponent mutableComponent = component.copy();
            String message = mutableComponent.getString();
            ServerPlayer serverPlayer = (ServerPlayer) (Object) this;
            if (message.contains("<structure>") && message.contains("</structure>")) {
                String structure = message.replaceAll(".*<structure>(.*?)</structure>.*", "$1");
                BlockPos center = serverPlayer.blockPosition();
                Optional<Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>>> holderPair = StructureLocator.findNearest(
                        serverPlayer.getLevel(),
                        center,
                        new ResourceLocation(structure),
                        100,
                        false
                );
                AtomicReference<String> replace = new AtomicReference<>();
                holderPair.ifPresentOrElse(pair -> {
                    Component component1 = StructureLocator.formatLocateResult(structure, center, pair, "commands.locate.success");
                    replace.set(component1.getString());
                }, () -> {
                    replace.set(new TranslatableComponent("commands.locate.failed", structure).getString());
                });
                Style style = component.getStyle();
                mutableComponent = new TextComponent(message.replaceAll("<structure>(.*?)</structure>", "§a%s§r".formatted(replace.get()))).withStyle(style);
            }
            return mutableComponent;
        }
    }
    

    这段mixin则是注入ServerPlayer的sendMessage方法,修改new ClientboundChatPacket(message, type, sender)的message参数,||因为我偷懒,所以没用MixinExtra||,用正则表达式进行匹配到对应的结构格式文字,然后修改原文字中的内容。

    这差不多都就是本次代码的全部内容了。


相关推荐


  • [原创][数据包][持续更新]NuQuest模组中的对话框使用示例

    妙妙工具
    1
    0 赞同
    1 帖子
    133 浏览
    昨天没做东西,今天也没K
    很多人在催这玩意,但是也有人不知道这玩意怎么用,那我今天来教教大家吧。 数据包路径 关于数据包的路径存放 目前的路径是在nu_quest/dialog下的 完整路径就是data/nu_quest/dialog 代码会自动检测这个路径下的全部文件,包括子文件夹,所以大可放心整理问题。 编写数据包 那现在我们就来介绍如何写对话了 { "dialogueId": "intro", "dialogTexts": [ { "title": "dialog.nuquest.intro.title", "text": "dialog.nuquest.intro.text", "imageGroup": { "image": "foo:textures/gui/npc.png", "x": "0", "y": "(screenheight / 3 * 2) - 64", "width": 64, "height": 64, "uOffset": 0, "vOffset": 0, "uWidth": 64, "vHeight": 64, "textureWidth": 64, "textureHeight": 64 }, "soundGroup": { "sound": "minecraft:entity.villager.yes", "volume": 1.0, "pitch": 1.0 }, "textEffect": { "name": "typewriter" }, "params": { "speed": 2 } } ], "dialogActionDatas": [ { "message": "dialog.nuquest.intro.continue", "action": { "name": "dialog", "params": { "dialogId": "foo:intro_2" } } }, { "message": "dialog.nuquest.intro.exit", "action": { "name": "close" } } ] } 这是目前对话中可用的全部功能 在最外级的json元素中主要有三个,分别是dialogueId,dialogTexts,dialogActionDatas dialogueId定义了这个动画的id名,调用时也是通过id名来查找,而dialogTexts是一个列表,里面存放了对话的文本内容,dialogActionDatas是选项按钮,在对话文字全部播放完后则会出现。
  • [原创][KubeJS]kubejs获取玩家所处坐标的结构

    妙妙工具 kubejs
    1
    1 赞同
    1 帖子
    110 浏览
    忆然
    本文使用:CC-BY-NC-SA 4.0协议 直接上代码 在此推荐下来自ZZZank的ProbeJS Legacy (已经支持1.20.1了(喜)) /** * 获取实体坐标的所有结构 * @param {Internal.Entity} entity * @returns {$StructureStart_[]} */ function getAllStructuresAt(entity) { let structureList = [] /**@type {$ServerLevel_} */ let serverLevel = entity.level let entityPos = entity.block.pos /** @type {Internal.Structure[]} */ let structureArray = serverLevel.structureManager().getAllStructuresAt(entityPos).keySet().toArray() for (let structure of structureArray) { let structureStart = serverLevel.structureManager().getStructureAt(entityPos, structure) if (structureStart.isValid()) { structureList.push(structureStart) } } return structureList }
  • 1 赞同
    14 帖子
    296 浏览
    sdjgeS
    补药偷走我的钱包