灵魂军械库
一个为Minecraft编写的模组,设计核心为“滚雪球”
By Ice_Kube | 2026-03-28
突发奇想,做一个模组吧。
事实上,我几年前就有这个模组的想法了,一直在我的大脑里打转。
或许我应该现在开始。
好了,文件夹创造完毕。
完成了灵魂剑的灵魂积累,衰减与加伤。
与上次的实现不同,这次使用lazy update的方式 —— 因为InventoryTicks只在玩家背包里才会运行。我希望在背包,物品栏里,地上,都可以衰减灵魂。
我不希望玩家从刷怪塔里装满灵魂以后塞进末影箱或模组的背包里直接带到战场。
尝试了google gemini接入cline作为coding agent —— 大失所望。
这家伙完全不知道什么叫“最小侵入式改动”,而且plan模式写着跟没写似的。
还是乖乖回到claude了。
不过,可能我要的实现方式比较别致,claude一直误解。
虽然说总比我手写要快就是了。
在手上的时候会一直进行“re-equip animation”,就是从视线下方往上平移的那段动画。因为每tick进行一次,显得很抽搐。
原因是因为每tick都在修改NBT tag,而每次修改都会自动导致一次动画。
修复完毕。
怎么砍铁傀儡时灵魂值积攒永远不是100整?
我需要安装一个Neat血条显示来看看什么个事。
什么情况?为什么Neat不能正常运行?
Mixin注入失败?是我的Forge版本太新了吗?
刚刚从47.4.17降级到47.4.10,依旧不行。
降级到了47.3.0.
结果把我自己的程序搞坏了。
超!
修改计划:用Jade.
什么叫Jade也不行???
天啊,不会真要我F3看血条吧?
杀了我吧
Mixin问题。
但是正式打包进游戏里的时候不会有这个情况。
我想…如果手动加入sponge mixin,或许可以解决问题?
这是coremod的正常操作,不会搞坏项目。
成了。
我认为这应该是因为开发版的forge gradle根本没有 mixin,所以其他模组尝试运行mixin时才会失败。
不存在所谓“自带版本过时”问题,因为最新版sponge mixin已经是五年前的东西了。
这样也能解释为什么构建出来的正式版在运行时没有问题 —— 要么是forge mod loader自带mixin,要么是某些需要mixin的模组带着它加载了。
Forge啊,你到底还有什么惊喜给我?
通过Neat和Jade,正常解决了“100血的铁傀儡打出120的灵魂”的问题 —— 若对方血量小于本次攻击伤害,那么最后会直接增加攻击伤害的灵魂量而不是对方血量。
此外,还有个问题,是从float转到int时出现的:如果没蓄满力就攻击,可能导致灵魂积攒量小于总伤害量,因为小数点在转为int时被抹去了。
修改方式不算简单,但也不算很难 —— 把存储灵魂值用的int改为float就行。
把灵魂弓给整上了,不过有一些设计稿里的内容仍然缺失,而且跟灵魂剑一样用的是原版图标作为占位。
依旧不能完全相信AI,后面花了不少时间调整程序,但是总比我自己要来的高效。
跑个测试 —— 哎怎么右手这么抽搐?
re-equip animation!!
我大E了啊!
我不知道漏了什么,但是:
- 拉弓时不会像原版那样视野拉近
- 拉弓时在物品栏里的图标会在拉弓状态和“没有拉弓”状态之间抽搐,一帧拉弓一帧不拉的,很奇怪。
最新的奇异bug:
我的箭是有追踪功能的,但是它会在半空中以正常抛物线飞着,然后突然瞬移到应在的落点。
很奇怪,太奇怪了。
最终结果:当你做Arrow的tick()时,不要”!level.isClientSide”,那会导致数据不同步。
目前我的推测是: 客户端的箭和服务端的箭各飞各的,服务端的箭在发射时和落地后会分别跟客户端同步一次信息,中间则是各自算自己的,所以才会出现那种诡异的“瞬移”现象 —— 服务端知道它在转弯,但客户端认为“我不转弯,我直飞”。
此前灵魂箭的追踪算法是寻找距离自己最近的生物,但是最后的手感特别奇怪,而且会经常出现“瞄A打B”的情况。
如果不能做到“瞄A打A”而是“就近原则”,那不就是近战武器了吗?那我还不如拿那把灵魂剑。
于是,我安装了一个功能,在射击时会检测一定范围内距离玩家准星最近的生物并让箭去追踪那个生物,而不是距离玩家最近的那个。
然后嘛——那个瞬移问题再次出现。理论上它的原因是,服务端里已经知道了“我要追踪这个人”,但在客户端里,要追踪的生物仍然是null,所以飞直线,直到射中了,数据同步,再瞬移过去。
这下有点难解决,因为之前跑”就近原则“的时候,追踪目标完全由箭自己决定,我可以直接去掉”!level.isClientSide”来让服务端和客户端同时知道“我要射它”。
但是现在不行。我得看看怎么把LivingEntity作为数据从Server Side同步到Client Side.
问题修好了,但是手感依旧怪异,脱靶率也很高。
而且更严重的是:玩家必须能无遮挡看到敌人的身体中心,也就是说玩家低打高会完全失去追踪能力。
此外,箭也总是会去追踪敌人身体中心,所以如果敌人在一格方块的矮墙后面,就会被追踪到掩体上。
目前想法如下:
- 关于必须看到敌人身体中心点问题:我可以调整获取追踪目标的算法,改为搜索同一个人的三个点:眼睛,中心和脚底,其中一个过关就行。或者,我可以用混合方案:如果玩家在射出时没追到敌人,箭会改为使用刚刚被我删掉的Plan B,即就近原则追踪。
- 关于箭追踪到掩体问题:每tick对target的三个点进行一次ray cast,并选择成功cast的那个点进行追踪?看起来没什么问题,但是玩家PC会很 “感谢” 我的。
- 关于手感问题:调参,我可能需要做一个“距离敌人越近,追踪力度越强”的设计?
- 或者干脆,我把追踪半径改低一点,这样玩家不会依赖追踪,前两个问题也会被掩盖掉,毕竟追踪能力主要是用于特殊技能的“扇形射击”的。
- 以及,我可能要关掉灵魂箭的重力影响。
笑死我了,关掉重力以后手感问题直接被完全解决。
箭追踪到掩体上的概率也明显降低了。
大道至简啊。
现在只需要修改一下目标算法,让玩家能看到三个点中的一个(眼睛,中心,脚)就行了。
为什么要有脚坐标?MC玩家热衷于给生物修脚。
从一开始写灵魂弓的时候,就已经有“拉弓时物品栏标志抽搐”的神秘情况了。
我稍微排查了一下,目前怀疑是每tick都更新一次tag,而目前算法判定方式是”getUseItem() == stack”,这就巧了 —— 每tick会更新一次tag,而更新tag会让游戏认为“不是同一个stack”,于是出现“在拉弓与没拉之间反复横跳”的抽搐。
修改方式很简单:抛弃原版的if itemstack = itemstack而是转用 “UUID验证”
沉寂了将近一个月,主要是忙于处理一些现实的事情。
这段时间我也不是什么都没做。通过分析Botania的程序,我将shader安装到GUI元素上来实现了花里胡哨的视觉效果,用于在HUD上显示灵魂值,以及标示灵魂值超过200的部分。
赞美Vazkii.
对于超过200的部分,我想要创建一个类似于水波的视觉效果,那咋搞?几个月的Unity和Unreal经验告诉我:柏林噪声。
但是我在纯手写的GLSL,并没有现成的柏林噪声函数,而AI也建议我“要不别用柏林噪声了,用几个sine函数叠加”。
Nope.
我就要用柏林噪声。
所以——
——我从shadertoy上复制粘贴了一个。
你在期待什么?手写柏林噪声?我不造车轮,谢谢。
说到造车轮——我开始怀念Unity和UE了,渲染配置比MC好做多了,商业引擎的图形交互页面让我不至于在代码里反复调参,shader graph和UE material graph这类工具也让我不需要每次修改shader都重新启动一次游戏。
Anyway,还有一个情况。
我在制作边缘半透明shader的时候,出现了一个相当诡异的情况:有一大半的区域都是纯色,而不是半透明,而在接近边缘的时候会出现一条看起来像是不透明度恒定的区域。
为什么alpha = 0.5的时候还是不透明的纯色??
花了大半天到处排查,最后发现是什么情况呢:
我本来以为我的程序是在渲染GUI结束时被调用一次的,但是我没注意到我挂载的event是在 “每次渲染Overlay的时候被调用”。
什么意思?这是什么文字游戏?
每个”HUD元件”,也就是你的血条,物品栏,经验条…它们都是一个”Overlay”。
也就是说,我的渲染程序不是在整个HUD渲染完后才被调用,而是在每个元件渲染完后都被调用一次。
翻译:我的每个额外元件(比如灵魂条)被反复渲染了10+次。
我先前没有发现,是因为我渲染的东西都是不透明的,十多个在同一个位置同时存在的HUD元件互相覆盖叠加,最后玩家只能看到”在顶层的那个元件”,对玩家和我而言,就是”只有一个被渲染”。
damn.
没什么好说的,这几天制作了一个简化的注册系统,用于注册技能,因为我不希望把所有技能硬编码,此来可以方便我后续的增减技能。
然后嘛,安装了五个技能,暂时跳过了“连锁”技能,因为有点难做。
原设计的伤害也是比较爆炸,所以都经过了不同程度的削弱。
除了连射技能,因为视觉效果不够强。
目前只能改掉最明显的那部分数值失衡问题,剩下的…得等。等我把模组做好,然后带上暮色森林和Dungeon Now Loading模组进行数值测试。
基本上,这三四天是把弓的技能系统搞定了,下一个去搞剑的新系统吧。
连着三个月没有更新了。老实说我也忘了为什么四月三十日以后我就没什么大动静了。
总之是沉寂了一段时间,然后七月初跑回来干了点大事,干到现在。
倒没什么特别戏剧性的展开,不像我写的另一篇文章那样。就是纯粹的加功能,找bug,修bug。
我不想写流水账,所以这段时间做的内容,我这里就简要带过了:
- 四月三十日前,完成了弓的所有技能,除了连锁外。并且完成了剑的制作。然后进入两个月的沉寂
- 七月份回归后,完成了视觉效果,又花了几个小时去音效网站上找素材,最后在AE里合成了一个听着还不错的音效。
- 搞完了灵魂原胚,远古城市Global Loot Modifier,灵魂铸造系统。
如果你看过我的设计稿的话,应该能得出结论了。
是的没错,这个模组最难的两座大山(技能系统,铸造系统)已经完成了。接下来也差不多是收尾段了,剩下要做的东西基本上都能直接复用已有系统。
My estimation? 八月份前应该可以完成所有代码部分,然后开始摇人进入数值测试。
但这其中也并非没有变故。
知道为什么我说“完成所有代码部分”么?因为非代码部分,我完不成。
试着上Asprite搞了几天贴图,结论是我完全没有艺术细胞。
更糟的是,几个月之前联系的美工实在是忙碌,没法参与。
我也不能去怪罪他,毕竟医学生,你懂的。
所以,我自然而然地把他移出了名单。毕竟当时也主要是我厚着脸皮去要求他的,也没有提供什么回报,再像个债主一样追着屁股撵,那不是太不当人了?
随后花了一点时间,遍历了一次我的整个朋友圈,根本没有可用人才,太糟了。
好吧,也并非不是“没有可用人才”…我在discord上认识一个有不错艺术天赋的美国姐妹,对方也正值Summer Holiday。
遂自行出资为其购置Aseprite,并提供先前已经整理好的参考图和需求。
也是搞上跨国人才雇佣了哈。
Who’d have thought? I’m not even graduated from college.
美工产出了相当不错的贴图,拿来用了。
事实上,我已经计划了当事情解决后,给她$20-25的等价物品 / 游戏,或者干脆直接打她卡上,作为酬谢。
我不喜欢欠人情债,理不清扯还乱。或者用一个稍微形而上的说法,货币发明出来不就是为了精确清算”人情”的吗。
不过,我目前还没告诉她这一点,留到最后当个惊喜吧。我怕“德西效应”,毕竟她已经自愿答应了帮忙。
接下来,说回模组本身。
首先是搞完了所有技能的解锁,其中铸造系统被爆改了好几次,花掉了不少时间。毕竟刚出来的算是半成品吧,想不到这么多可能的使用场景。
然后,就是灵魂盔甲了。
我设计里的“灵魂狂怒”期间玩家视野边缘将要有蓝色的渐变视觉效果。
我原本设计的是干脆直接根据x和y的值线性计算alpha,代码长得大概是这样:
float tex = max(abs(texCoord0.x),abs(texCoord0.y)); color.a = clamp((tex - edge) / (1.0 - edge), 0.0, 1.0);理论上,在x和y的交界处,也就是对角线上,颜色值将会与水平和数值线相同,不会有明显差异。
然而,在实际测试中,出现了非常明显的一条沿着对角线的淡色 “折痕”
我完全无法理解原因,理论上它的数值应该相同????
然后我去找了AI,毕竟没有人类的知识广度可以与商业LLM相比。
他的回复是说,这是一种叫做“马赫带效应”的视觉错觉, “人类对对亮度的变化率的变化(二阶导数)极其敏感” ,而我原有算法中梯度是直接转过去的。
我真特么——
我听完恨不得直接对免疫系统通报眼球位置了
不过AI倒也给了一个补救方案:用 “超椭圆范数” ,And no, I have no idea what it is.
完成了所有东西,包括各种技能和盔甲的实装。
老实说,有一件事我感觉有点烦人 —— 我用的AI在写代码时总会“过度注释”,写很多废话,我后面还得一点点删。
然后嘛,启动了playtest,找到并修复了很多bug:
- 服务端错误调用客户端method导致开服时现场崩溃,此乃首杀
- 技能切换的提示音错误被其他人听到
- 服务端和客户端的配置文件不同步时,灵魂条的渲染会出问题。通过自己写网络同步客户端配置文件解决。
以及找到了一些游戏性上的问题:
- 成就系统缺失,这个原本规划了,我纯属忘了。
- 机制过于复杂,难以摸索,需要借助Patchouli模组制作游戏内引导书
- 未开技能的白板灵魂护甲数值 实在太脆了! 一摸就碎,没开技能时几乎没有可玩性,跟“保护IV铁套”相比更是差远了。因此,白板数值被提升到钻石甲级别。
- 护甲技能要攒太久,用得又太快 —— “入不敷出”虽然是设计选择,但这差距实在是太大了!护甲的消耗速度被直接砍半,同时也降低了全套护甲的灵魂总上限。
- 护甲,对,还是这玩意的加强…开技能的免伤比例提升。它开技能后的性能必须远高于全套保护IV的下界合金套,毕竟前者的防护性能是全时段覆盖。(原数值实在太保守了…为什么MC原版数值这么膨胀啊?)
- 护甲,尤其是护腿部分,开技能时虽然加了移速但还是会被方块卡脚,极大降低爽快程度,现在让玩家像骑马一样”直接走上一格高度”。
- 此外,降低了剑气的消耗,以提升其实用性。
- 正在考虑降低剑的回血消耗。
- 至于弓,三位测试员均给出了9/10的高分。剩下那一分在哪?未启动时的拉弓体验过于便秘。设计如此。
- 灵魂武器的铸造进度经常卡在499 / 500,毕竟计数器在内部用的是浮点,就算0.1的伤害都会导致铸造失败而需要打个新Warden。需求降低至450。
总结:策划一定要会玩游戏
什么叫成就系统把技能系统炸了?
事情是这样:我加了一个成就,然后弓的技能直接就坏掉了。
怎么坏的?连射和箭雨技能从每4 tick一次直接变成了每tick一次,而且还不再消耗灵魂!
为什么?为什么我加了一个成就,技能直接坏掉了?
在IDE, Git和AI之间来回往返,我渐渐拼凑出了原因:
当配置项没有被从硬盘读取时,它们默认值就为0,如果在这之前有其他程序尝试读取配置项,就会获得”0”作为返回值.之前这不可能发生,因为技能的class的实例化不可能晚于游戏启动,这个时候配置项就已经被读取并写入静态内存。
但是,为了做“解锁所有灵魂弓技能”成就,我加了个”弓可用技能”static列表,这一举动看似与bug无关,但却直接导致弓技能的实例化先于配置读取,于是各大技能便读取了 “0” 作为它们的消耗和冷却,因为此时配置项仍未被写入。
然后,各大技能理所当然的认为自己的消耗和冷却都是0了…
再梳理一次:
- 做了一个”解锁所有灵魂弓技能”的成就,需要一个所有弓技能的列表来判断玩家是否全部解锁了。
- 于是加了一个static列表。这个列表引用了所有技能的实例。
- Java的static字段在类加载时初始化。
- 类加载的顺序取决于谁先被引用。
- 这个新列表的存在改变了类加载顺序,导致技能类在配置文件被读取之前就实例化了。
- 实例化时技能去读取自己的冷却和消耗,配置还没加载,拿到的是默认值0。
- 冷却0意味着每tick都能发射,消耗0意味着无限弹药。
这谁想得到啊??
Patchouli完成了。
即使有AI协助,这还用了我如此久时间。
而且AI也太喜欢用破折号了,大致一看满地都是破折号,哪个正经人会这样写文章啊??
接下来,该准备发布了。
大失败。
老实说,我觉得我模组的品质一定是在线的。
体量略小,但机制非常复杂,属于是“小而精”精品模组了。
CurseForge发布后立刻沉底,这完全合理,他们总是倾向于推送那些本来就很多人下载的模组,而不是那些“新来的”。
在主页不翻个五分钟找不到我,所以我从一开始也没有指望CurseForge。
所以我在发布的同时就在同步制作我的模组宣传片,尝试走B站这条路。
成片的品质,至少我身边的人认为,很好,很高。
但是情况还是不对,发布两天了播放量还是没有过千,其中还有几个是我用自己的人脉摇过来的。
目前为止没想到让别人知道我这个模组的方式。
结论很明显:这个耗时半年的项目,大失败。
但我暂时还不会放弃。我再做一点事,尝试救一下这个模组,然后呢…
如果没救成的话,原定的2.0更新计划就会被废掉,为我的其他项目让路,但我仍会保证这个模组更新。在我真正离开前,它至少得支持1.21.x和26.x版本。
该日志记录于模组发布4天后,B站宣传片播放量:约500。Youtube播放量:未发布。CurseForge下载量:17. Modrinth下载量:仍未过审
是时候研发我的救场计划了。
首先,我的模组宣传片更像是“教学”而不是“宣传”,整体节奏参照的是高粉丝精品TF2 Youtuber Jontohil2的视频风格:先是一个高成本高品质快节奏短片引入,然后再细细讲解。
我的节奏也是一样:0-10秒是Blender短片,10-50是快节奏超燃混剪,然后再淡出开始细细介绍。
这个结构很好理解:前一分钟吸引游客注意力,展示自己“大制作”,然后再讲解。
看起来这条路对于模组而言走不通,原因未知,我需要换一个思路。仍在制作的英文版宣传片也可以扔一边了。
我应该做一个更适合模组宣传片的视频脚本,不要再介绍机制了。
但无论如何,这总会是个大工程。
整体救场计划如下:2
- 去mcmod.cn,创出我的模组页面,一个下午内可以搞好,大多数文案直接复制粘贴设计稿就行。
- 去Reddit. More specifically: r/feedthebeast. 研究一个具有吸引力的介绍文案和一段视觉上吸引人的五秒内GIF。这将花去另一个下午。
- 找那些喜欢做模组介绍的YouTuber / up主,看看能不能在100人民币以内买几个商单。能让对方无偿制作视频倒是更好。这只是个模组,我不会付高价尝试推广它。
- 重新设计宣传视频,务必在90秒内展现所有设计亮点,而不是用7分钟细细解释,玩家完全可以自己滚去读Patchouli。
3 & 4 将同时平行进行。
我相信我的程序能力和设计水准,现在只是没人知道这个模组存在而已。
可选:把长视频的前50秒摘出来单独发布,尝试骗过平台推流机制。但整个50秒其实是击杀混剪,没介绍那些“独特”的机制,获客率堪忧。
目标:将下载量救场至2000
仔细想想,长视频并非不能“获客”,Dungeon Now Loading也是用超长视频+详细介绍来获得流量的,这也是我当初决定使用长视频而不是Create Aeronautics那样的短Trailer形式的主要原因。
他们的标题也非常朴实无华:“Dungeon Now Loading | The Labyrinth (Mod Showcase)”
总播放60万,而且我记得很清楚,它刚被发布没两个月就被推到了我的面前。整个下来完全就是模组说明书而不是Trailer。
我和他整个视频结构几乎是同构的,甚至我开头吸引力比他还高——拜托,那可是高投入的Blender动画啊?
为什么会这样?我不知道,事到如今只能解释为运气了。
60万,600K,对我的那不到1000.
好吧,或许推流周期还没到,谁知道会不会在一个月以后平台突然抽风猛推?这种事情在B站又不是没发生过。
也可能Youtube用户天然喜欢这种长视频?毕竟很多主流Youtube视频都有个人的嘴跟机关枪似的说个不停.不过我的视频没有配音,纯文字,不知道会不会是劣势。
无论如何,毕竟翻译工作已经做一半了,有了这些原因以后,不做完倒有点显得不太对了。这算沉没成本谬误吗?可能吧。
如果真的是运气因素的话,换个平台换个语言再投一次,也算是再来一次投骰子检测运气了。
优先级更改:先继续做完这个英文版长视频,再去做上面的计划吧。
嘿,我突然记起来,我的guidebook没有合成配方??!!这下完蛋了
我9.1的时候推了一次更新,提供了合成配方,今天一看发现这个新文件在Curseforge上的下载量又+16
基本上属于翻倍了?
我推测可能是因为我更新了,所以Curseforge短暂的把我推进了Latest Mods里,吸引了又一堆人,这也能解释为什么数量差不多。
所以我有个最新的拉下载量的手段:不断推送小更新,保持它一直在Latest…
这也太寒碜了吧??再说了,这个效率,两天18?我不如去乞讨(笑死我了)
另外,这几天有点忙,写mcmod介绍又需要一点灵感,而我在忙的时候搞不出灵感.此外,视频搞好了,明天就发YouTube (明天是周五)
额…
YouTube的视频播放量才65,甚至远低于Bilibili的视频…?????
即使我用的是英文??我还专门翻译了呢
OK 我现在怀疑Dungeon Now Loading那个视频确实花钱买了油管推流。因为他只有第一个视频有这么高播放,后面一个比一个低,跌落速度极高。
另,mcmod还未开工。