跳转到内容

灵魂军械库

一个为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了啊!


我不知道漏了什么,但是:

  1. 拉弓时不会像原版那样视野拉近
  2. 拉弓时在物品栏里的图标会在拉弓状态和“没有拉弓”状态之间抽搐,一帧拉弓一帧不拉的,很奇怪。

最新的奇异bug:

我的箭是有追踪功能的,但是它会在半空中以正常抛物线飞着,然后突然瞬移到应在的落点。

很奇怪,太奇怪了。


最终结果:当你做Arrow的tick()时,不要”!level.isClientSide”,那会导致数据不同步。

目前我的推测是: 客户端的箭和服务端的箭各飞各的,服务端的箭在发射时和落地后会分别跟客户端同步一次信息,中间则是各自算自己的,所以才会出现那种诡异的“瞬移”现象 —— 服务端知道它在转弯,但客户端认为“我不转弯,我直飞”。


此前灵魂箭的追踪算法是寻找距离自己最近的生物,但是最后的手感特别奇怪,而且会经常出现“瞄A打B”的情况。

如果不能做到“瞄A打A”而是“就近原则”,那不就是近战武器了吗?那我还不如拿那把灵魂剑。

于是,我安装了一个功能,在射击时会检测一定范围内距离玩家准星最近的生物并让箭去追踪那个生物,而不是距离玩家最近的那个。

然后嘛——那个瞬移问题再次出现。理论上它的原因是,服务端里已经知道了“我要追踪这个人”,但在客户端里,要追踪的生物仍然是null,所以飞直线,直到射中了,数据同步,再瞬移过去。

这下有点难解决,因为之前跑”就近原则“的时候,追踪目标完全由箭自己决定,我可以直接去掉”!level.isClientSide”来让服务端和客户端同时知道“我要射它”。

但是现在不行。我得看看怎么把LivingEntity作为数据从Server Side同步到Client Side.


问题修好了,但是手感依旧怪异,脱靶率也很高。

而且更严重的是:玩家必须能无遮挡看到敌人的身体中心,也就是说玩家低打高会完全失去追踪能力。

此外,箭也总是会去追踪敌人身体中心,所以如果敌人在一格方块的矮墙后面,就会被追踪到掩体上。

目前想法如下:

  1. 关于必须看到敌人身体中心点问题:我可以调整获取追踪目标的算法,改为搜索同一个人的三个点:眼睛,中心和脚底,其中一个过关就行。或者,我可以用混合方案:如果玩家在射出时没追到敌人,箭会改为使用刚刚被我删掉的Plan B,即就近原则追踪。
  2. 关于箭追踪到掩体问题:每tick对target的三个点进行一次ray cast,并选择成功cast的那个点进行追踪?看起来没什么问题,但是玩家PC会很 “感谢” 我的。
  3. 关于手感问题:调参,我可能需要做一个“距离敌人越近,追踪力度越强”的设计?
  4. 或者干脆,我把追踪半径改低一点,这样玩家不会依赖追踪,前两个问题也会被掩盖掉,毕竟追踪能力主要是用于特殊技能的“扇形射击”的。
  5. 以及,我可能要关掉灵魂箭的重力影响。

笑死我了,关掉重力以后手感问题直接被完全解决。

箭追踪到掩体上的概率也明显降低了。

大道至简啊。

现在只需要修改一下目标算法,让玩家能看到三个点中的一个(眼睛,中心,脚)就行了。

为什么要有脚坐标?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模组进行数值测试。

基本上,这三四天是把弓的技能系统搞定了,下一个去搞剑的新系统吧。