跳转至内容
  • [原创][KubeJS][Mod]如何在1.21.1NeoForge编写一个KubeJS的附属Mod

    已移动 魔改早教
    8
    0 赞同
    8 帖子
    37 浏览
    忆然
    @LirxOwO 虾头栗子,看我keybindjs仓库去
  • [原创][1.21.X][Neoforge][modding]CodecCodec你的!

    已移动 魔改早教 1.21.x modding neoforge
    1
    1 赞同
    1 帖子
    13 浏览
    QiHuang02Q
    总览一、数据驱动的基石二、什么是Codec?2.1 核心概念2.2 工作流程三、为什么我们要使用 Codec?3.1 如果没有 Codec:手动解析的痛点3.2 Codec 的核心优势 一、数据驱动的基石 在目前的Minecraft(1.13+)模组开发中,数据驱动已成为主流。无论是自定义生物群系、新的配方类型还是某些复杂的方块行为,我们都倾向于将配置信息存储在 JSON 文件中,而不是硬编码在Java代码里。这极大地提高了模组的灵活性和可配置性。 然而,如何安全、高效地在 JSON 数据和游戏内的 Java 对象之间进行转换呢?这正是 Codec 发挥作用的地方。本文将简单地探讨 Codec 的概念、用途和优势,并结合我的 PortalTransform 模组中的代码进行实例分析。所以有一些不完全正确的地方请指出。 二、什么是Codec? 2.1 核心概念 Codec(编解码器)这个词在百度百科中的解释是一个能够对一个信号或者一个数据流进行变换的设备或者程序。而我的世界中的 Codec 指的是一个由Mojang开发并深度集成到Minecraft中的双向数据转换框架。 你可以将其简单的理解为一个高度智能化的“翻译官”,它的职责是在两种完全不同的“语言”之间进行精确翻译: 语言A: 游戏内存中的 Java 对象 (Object)。这是程序逻辑可以直接理解和操作的结构。 语言B: 用于存储和传输的数据格式 (Data Format),通常是 JSON 或 NBT。 Codec 的本质是定义一套完整的、双向的映射规则,用来规定一个 Java 对象是如何被序列化(保存)为 Json,以及一个 Json 文件是如何被反序列化(加载)成一个 Java 对象。 2.2 工作流程 Codec 的的工作包含两个方向: 1、编码 / 序列化: 方向:Java 对象 -> 某种 数据格式 (JSON/NBT) 用途:当你需要将游戏中的一个对象保存到玩家的硬盘(如世界存档)或通过网络发送给客户端时。 2、解码 / 反序列化: 方向:某种 数据格式 (JSON/NBT) -> Java 对象 用途:当游戏启动或加载资源时,从数据包的 JSON 文件或世界存档的 NBT 中读取数据,并将其转换为游戏逻辑可以使用的对象。 三、为什么我们要使用 Codec? 有些开发者可能会想:“我自己用 GSON 或其他库手动解析JSON不也可以吗?” 答案是可以,但这是一种非常脆弱、低效且容易出错的方式。 3.1 如果没有 Codec:手动解析的痛点 想象一下,如果让你手动解析某个Json或者NBT的数据,你需要编写类似下面这样的伪代码: 假如手动解析副产物数据。 你可能需要经历一下步骤: 1. 检查字段是否存在 2. 检查字段类型是否正确 3. 手动解析嵌套对象 4. 处理可选字段和默认值 5. 调用构造函数 6. 另外,你还需要编写一个 toJson() 方法来执行反向操作! 这种方式的缺点显而易见:代码冗长、大量重复的检查、难以维护、并且与Minecraft原版的数据加载/报错系统脱节。 3.2 Codec 的核心优势 健壮性:Codec 自动处理字段缺失、类型错误,并能提供非常清晰的错误日志,指出哪个文件、哪个字段出了问题。 代码简洁:将上百行手动解析和序列化的代码,浓缩为几行声明式的定义。逻辑清晰,意图明确。 可组合性:你可以像搭积木一样组合 Codec。例如,直接复用 BlockPos.CODEC 来处理坐标,无需关心其内部实现。 可扩展性:可以轻松添加可选字段和默认值。例如,使用 .optionalFieldOf("field", defaultValue)。 生态集成:Codec 是Minecraft数据系统的“一等公民”。使用它意味着你的数据可以被原版的命令重载,享受游戏的数据版本修复(DataFixer)等高级功能。
  • [原创][Mod]通过特定格式文字进行查找结构

    妙妙工具 forge mixin 1.18.2
    1
    0 赞同
    1 帖子
    22 浏览
    昨天没有做东西,今天做K
    故事的起因是有帮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||,用正则表达式进行匹配到对应的结构格式文字,然后修改原文字中的内容。 这差不多都就是本次代码的全部内容了。
  • 已经,没有modding的理由了

    壁画石窟
    5
    0 赞同
    5 帖子
    36 浏览
    真冬M
    @不是椰浆 尼的牌子豪多
  • [原创]使用kjs进行文件的删除

    灵感大王 1.20.1 forge kubejs unsafe
    4
    0 赞同
    4 帖子
    91 浏览
    草莓呜咩B
    @芒果凍布丁 我揣测Client可能被安全化了,所以loadClass,能直接用的话就安全多了呢。
  • [原创][Mod]基于opengl取色的hsv色盘屏幕

    妙妙工具 1.20.1 forge render
    5
    0 赞同
    5 帖子
    48 浏览
    不是客服M
    没有教程的话,哇达西?
  • 在这测试一下各种功能

    壁画石窟
    7
    0 赞同
    7 帖子
    93 浏览
    不是客服M
    标题重要吗?? Java Java Js Python public class AaaJava() { // How to write jvav???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? } public class AaaJava() { // How to write jvav???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? } function EvilKotlin () { // How to write Kotlin?? } def zakoPython (): # How to write python?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 你好 吗 隐藏 嘻嘻 额我也不知道为什么这个是Improtant. 嗯这个确实像Warning. 哦还算像Info吧 总览标题重要吗?? 标题
  • 养老向的物品抽奖机:虚空草莓

    灵感大王 kubejs 作物 养老 forge
    2
    0 赞同
    2 帖子
    30 浏览
    忆然
    呜,硬编码名称
  • 我喜欢你

    壁画石窟
    8
    1 赞同
    8 帖子
    34 浏览
    昨天没有做东西,今天做K
    @忆然 在 我喜欢你 中说: @read 补药啊,没有你我的对话框谁来补啊 会有的
  • 论坛怎么蓝蓝的

    壁画石窟
    2
    0 赞同
    2 帖子
    20 浏览
    不是椰浆
    有吗(
  • 0 赞同
    3 帖子
    57 浏览
    sdjgeS
    补药在1.21.1偷走我的钱包
  • 0 赞同
    1 帖子
    22 浏览
    忆然
    本文使用:CC-BY-NC-SA 4.0协议 kjs本身提供的物品注册比较有限,在注册某些kjs未提供的item的时候我们就需要用到createCustom 如果有需要的item注册可以在本文下方留言,会考虑更新 createCustom注册model是没有的,也就是你还得去写一份model.json(这部分可以参考原版wiki) 下面是使用createCustom去注册一个弓的例子 let $BowItem = Java.loadClass("net.minecraft.world.item.BowItem") let $Item$Properties = Java.loadClass("net.minecraft.world.item.Item$Properties") StartupEvents.registry("item", event => { event.createCustom("modid:item_name", () => { let properties = new $Item$Properties() //修改耐久 为0则无耐久属性 properties.durability(0) //修改最大堆叠数量 properties.stacksTo(1) //修改稀有度 properties.rarity("epic") //创建新的bowitem let item = new $BowItem(properties) //返回新的bowitem进行注册 return item }) })
  • 0 赞同
    4 帖子
    38 浏览
    QiHuang02Q
    这里贴一份1.21.1版本的实现
  • 2 赞同
    2 帖子
    20 浏览
    半梦
    是幻梦吉斯,我们有救了
  • 1 赞同
    14 帖子
    137 浏览
    sdjgeS
    补药偷走我的钱包
  • [搬运][Windows][JSON-i18n]一款JSON文件快速本地化的翻译工具

    妙妙工具
    1
    0 赞同
    1 帖子
    25 浏览
    不是椰浆
    项目地址:MonianHello/JSON-i18n: JSON文件快速本地化的翻译工具 以下介绍为项目地址readme,因介绍已较为详细,故不另行编写 本帖内不提供二次分发文件,请前往项目地址自行下载! JSON-i18n JSON文件快速本地化的翻译工具 部分功能参考自CFPATools/Minecraft-Mods-Translator: Mods Translator for Minecraft 1.16+ (github.com) [image: image-20230608112735258.png?raw=true] 主要功能: 对接Minecraft模组翻译参考词典 (mcmod.cn),可以在程序内直接进行查询 对接文本翻译_机器翻译-百度AI开放平台 (baidu.com),可以一键对全文进行机器翻译 可以快速替换值中的单词而不会影响键名 支持切换深色模式与浅色模式,支持修改ui文字样式大小、保存布局后再次启动后自动应用、(进阶)提供对ui的高度自定义设置 程序提供五个快捷键: Ctrl+F 跳转至搜索 Ctrl+H 跳转至替换 Ctrl+Shift+A 全选替换候选项 Ctrl+Up(方向键上) 跳转至审阅模式上一个键名 Ctrl+Down(方向键下) 跳转至审阅模式下一个键名 详细说明: 首次启动: 首次启动后需要设置工作目录,设置完成后也可以在左上角 选项-首选项中修改 注意:请避免通过直接修改config.ini的方式修改配置,由于不同设备的文本编辑器编码方式可能不同,错误的编码方式会导致程序异常。如果出现此类情况请删除config.ini以初始化程序 外观设置: 程序内支持修改全局字体及大小,在左上角 选项-首选项中修改。使用鼠标滚轮可以快速调整不同的字体及大小,方便预览。同时支持切换深色模式 界面说明: 程序左侧为文件浏览区域,可以快速选择需要打开的json文件 程序右侧分别是查询栏和替换栏 程序中间为操作区域,用来编辑json文件,在浏览模式下点击行号可以快速跳转到审阅模式 菜单功能: 上方菜单栏中有以下四个功能: 首选项 保存当前布局 一键清空空格 安全模式保存(在保存文件按钮失效时使用) 左侧文件浏览区域中可以右键文件呼出菜单,有以下四个功能: 在资源管理器中打开 移动到回收站 复制并重命名 重命名 翻译功能: 翻译功能需要首先前往百度智能云-管理中心 (baidu.com)获取免费测试资源(500万字符/年),后续将陆续支持其他翻译api。 使用前需要在配置文件中填入获取到的接口ak/sk,具体步骤见下文。 测试成功后,可以点击左下角 翻译文件按钮,程序将自动对全文进行翻译。此时翻译并不会直接替换原文,需要用户进行进一步校对。如不需要,可以点击左下角 复制机翻按钮,一键替换译文与原文。完成后点击左下角 保存文件按钮即可保存更改。 [image: image-20230608115821872.png?raw=true] 翻译接口领取步骤: 1、登录百度账号,选择领取 文本翻译-通用版 [image: image-20230608115139348.png?raw=true] 2、创建应用,接口选择 文本翻译-通用版,其他内容无要求 [image: image-20230608115356481.png?raw=true] 3、复制ak与sk到程序中,测试成功后即可使用 [image: image-20230608115533624.png?raw=true] [image: image-20230608115621227.png?raw=true]
  • 常见问题 Q&A

    已固定 论坛事务
    4
    2 赞同
    4 帖子
    93 浏览
    不是椰浆
    与问题无关的回复将会被删除
  • 【发帖必读】妙妙工具版版规与发帖规范

    已固定 已锁定 妙妙工具
    1
    0 赞同
    1 帖子
    15 浏览
    不是椰浆
    总览第一章 板块定位第二章 发帖规范第三章 违规行为第四章 附则 第一章 板块定位 第一条 核心宗旨 妙妙工具板块致力于分享实用技术资源,包括但不限于: 原创或转载的程序、网页工具 KubeJS/CrT魔改脚本、工具集、配置集、Lib库 可复用的代码轮子、开发模板 其他可提升效率的技术解决方案 第二条 内容导向 鼓励发布完整度高、逻辑清晰、注释规范的作品,倡导技术交流与开源精神。 第二章 发帖规范 第三条 标题格式 一、基础格式 [原创/搬运][工具平台][工具英文名——工具译名] 其他说明与描述 说明: 原创/搬运:必填,标明内容性质(搬运需注明原出处); 工具平台:必填,标明工具类型或适用平台(如 Windows / Forge / KubeJS 6 / 在线工具 等); 工具名称: 有中英文名:格式为 英文名——中文译名; 无中文译名:可仅写英文名; 无英文名:可仅写中文名; 其他说明:选填,补充版本、功能亮点或短评(如 v3.2.1更新 / 便捷翻译工具)。 二、注意事项 标题中英文间用 短破折号 ——(非短横线 -); 标题中方括号使用英文字符[],而不使用中文字符【】 禁止添加夸张符号(如 !!! 【爆款】); 平台分类需简洁明确,避免模糊表述(如 [Minecraft] 应改为 [Minecraft 1.20.1-1.21.X])。 三、格式示例 [转载][Windows][JSON-i18n]一款JSON文件快速本地化的翻译工具 [转载][CrT 1.12.2][GrassUtils]基于CraftTweaker的便捷工具类集合 第四条 版权声明 原创内容:需在正文显著位置标注原创声明以及授权协议; 搬运内容: 一般情况下禁止二次转载(即“二转”),原搬运贴年久失修例外(超过三个大版本更新未同步内容); 若原作者注明转载需要授权,或原作品协议不允许转载,需在正文顶部展示授权协议截图/链接; 二次分发需要在协议允许的情况下进行,或获取原作者授权,需在正文顶部展示授权协议截图/链接; 衍生作品:若涉及二改、二次分发或反向工程,必须符合原始协议条款,否则视为剽窃。 第五条 安全警示 内容若包含以下操作,必须添加 unsafe 标签并在正文详细说明风险: 修改系统关键文件 静默执行的操作 涉及敏感权限 存在数据丢失/泄露风险的功能 (示例): 本脚本涉及对系统文件进行修改的操作! 第六条 质量管控 禁止发布以下低质量内容: 功能重复:与已有工具核心功能高度相似; 代码简陋:无异常处理、无注释、逻辑混乱的“玩具代码”; 可替代性强:可通过现有工具组合或简单命令实现同等效果; 描述模糊:未提供使用场景、参数说明或效果演示。 注:若承诺改进,需在标题添加 [持续更新] 并公示开发计划(如更新日志)。 第三章 违规行为 第七条 绝对禁止 剽窃:直接复制他人代码未标注来源,或篡改版权声明; 黑箱分发:对闭源工具进行逆向工程并违规传播; 恶意组件:植入后门、挖矿代码、数据爬虫等危害性内容; 虚假更新:标注 [持续更新] 但超30天无实质进展且未说明原因。 第八条 内容删除标准 未标注 [unsafe] 的高风险工具; 未提供授权证明的搬运内容; 被3名以上用户举报核实为低创作品。 第九条 违规处罚 违规类型 处理措施 未标注[unsafe] 警告+强制编辑 低创内容 删帖+禁止3日内发同类主题 剽窃/黑箱分发 永久封禁账号+全论坛置顶晒尸 第四章 附则 第十条 本规则自发布之日起生效,最终解释权归VariedMC管理组所有。
  • 强制加载并渲染特定区块

    灵感大王 区块 渲染 forge mixin
    5
    1 赞同
    5 帖子
    47 浏览
    忆然
    @Mafuyu 区块强制加载有用(点头
  • 谁来测测我的?

    壁画石窟
    2
    0 赞同
    2 帖子
    21 浏览
    不是客服M
    cool