跳转到主要内容
返回

维护开源项目

写博客是什么感觉?我在很多年前有尝试过使用hexo,后面因为各种原因就没有再继续了。主要没有实质性的内容可以表达的,而且也比较懒。

感觉对于我来说有可能博客是一种自言自语的表达形式吧?博客写给谁看?自己会反复回看吗?还是当作日记?别人会看吗?看得懂吗?合适吗?不管了。

总之我现在尝试下astro,我之前并没有接触过,但本质都是写markdown也无所谓了,说实在markdown我也折腾不来。 但让ai来写博客又感觉没有人随口自由表达沟通的感觉,总之我是想到什么就瞎扯什么了。

我想先聊聊有关我这几年在维护开发哪些开源项目吧。

先说这三个吧。

samp-node是一个插件用来运行node.js代码,用来编写openmultiplayer的脚本,比如核心的游戏模式。

按仓库建立时间来算,我是从22年8月底从0开始做infernus这个库的,刚建库的时候它不叫这个名字,是直到最近两年才开始改名的。

如果你去看更新日志的话,会发现第一个版本是0.9.8,但实际的话在此之前还有很多个版本,只是那个时候还没有按这种tag和changelog模式去更新。

这个库直到今天我才觉得勉强是可用的或者说是勉强到及格线的,它仍然还是一种实验性质的感觉。

我维护的samp-node是fork衍生的,它不是我从0开始做的,原作者amir在21年10月底就已经实质停止维护更新了。

这个项目作为嵌入式node.js api,基于open.mp主要还是32位,其生态里插件/组件也是32位的问题,所以我们也不得不用32位的node,我们需要手动构建libnode

当然open.mp有64位,这个我后面再提。

刚fork维护的时候这个库有很多问题,我决定fork分支后,首先面临的问题是node.js的版本问题,node.js和java比它的版本号是跳动的很快的,时至今日node.js已经更新到26版本了,22, 24, 26作为LTS版本,这个版本问题困扰了我很多年,以32位支持为例, 因为node.js早就抛弃了linux下32位的官方支持,也就是说你需要自己去手动构建打包, 但打包又会有一系列问题,比如:

  1. foo is incompatible with i386 output
  2. '_mm_storeu_si128': target specific option mismatch
  3. openssl-no-asm
  4. Patching OpenSSL .S assembly files
  5. openssl 3.0

第一个问题的话,我们最终解决是不使用64位环境进行交叉编译,而是docker下32位环境构建(i386/debian:bullseye)。

第二个问题的话我们还需要patch这个flag,否则会出问题。

export CXXFLAGS="-march=native -mfpmath=sse"
export CFLAGS="-march=native -mfpmath=sse"

第三个问题的话,我有些不记得了,但我记得它应该是和第二个问题或者第四个问题关联起来的,反正当时不加这个来编译node的话就会报错,后面怎么解决忘了。使用这个的话在一些核心node加密模块或者tls模块会有大幅度的性能折损。总之后面我们总算是能使用asm的情况下编译成功了。

第四个问题的话,是参考github社区的解决方案,它很简单,但是我在这上面花了很长时间才知道这个方案才得以解决。

第五个问题的话,直到open.mp服务器版本在1.5.8以上才解决,没有它的话高版本node.js也会有很多问题。

总之光编译linux下的32位libnode就是很头疼的问题,一直困扰了4年。

编译libnode本身又是十分耗费时间精力的事情,在我自己的电脑上构建windows,linux下的libnode,按一个半小时算的话,32位+64位就是3小时了。

所以直到最近我才利用上github actions的来编译libnode,虽然actions的机器性能限制编译时间比我自己电脑久,但起码它不长时间占用你的电脑来编译,让你可以继续做其他事情,而不是纯等待cpu满载结束。

现在可以让actions来做的话,维护samp-node就比以前简单了,至少按我们目前来说,只考虑22和24版本的话。

我只要在node.js更新版本后,actions也同步运行下得到libnode,然后我再手动更新下samp-node里的node的headers,推送就行。很难想象在过去我手动编译,还得开linux虚拟机等等麻烦操作。

然后每次node版本的变动,samp-node的代码肯定也得改动,因为会有很多破坏性更新或者语法上的变动,这个也很费时间。

还有异步阻塞,Promise不执行等等问题也困扰我很长时间,但后续貌似是通过asyncContext和drainTasks来解决了。

还有个很头疼的问题就是我们在infernus-starter不得不依赖polyfill,在很长一段时间里都是,这又得扯到sampgdk的涉及了,它是用fakeamx的,但有些插件它设计之初就没考虑,最为核心的例子就是raknet,所以你如果要调用native只能用realamx,那也就是说你需要在pawn里写polyfill,反正我是这么称呼它的,总之就是函数嵌套层了。

它的根本解决办法就是fork原作者的插件然后重写来支持fakeamx,但这又会引入新的问题,就是你自己fork后维护的一定是会存在bug的,或者不是按原本作者的逻辑来的等等……

还有就是sourcemap支持问题,现在应该是解决了,很长一段时间里我们都在用source-map-support这个包来代替原生高版本node就支持的sourcemap。

实际还有很多遇到的问题,等我想到再说吧。

总之samp-node是基座,没有这个插件我们压根没法往上层应用去写代码,这么多年下来,也总算解决了一些问题,总算有些进度了,总算勉强可以用了。

然后说到64位,它也是一个让我很头疼的事情。

open.mp是支持64位的,这是个好消息,所以理论上我们应该可以用64位的samp-node对吧?

但是samp-node依赖的sampgdk它不支持64位,这就很扯了,在这一个点上卡住了我很长时间,直到今年配合ai大模型重写部分内容,让sampgdk支持64位,才得以解决,它至少目前能运行了,但我不确定有什么bug。

samp-node支持64位了,又会衍生出新的问题,那其他插件或者三方组件呢? 原来的那些插件组件都基本上是考虑向下兼容的,所以普遍只有32位的,他们从诞生之初就 不是为open.mp考虑的,他们诞生的年代还在samp时代,所以这又只能让你自己fork做64位支持了。

所以在这方面又是花费很多时间精力,也可能会有ai上的需求来解决,也就是说我需要自己 去把流行的一些库都改了。

infernus只是一个库,用来简化原生samp-node提供的api调用,或者说它提供了封装。 infernus生态是monorepo,它有很多子包用来调用不同的插件,组件或者是重写了原来pawn的inc文件,设计目的是为了真正能用typescript来写所有的原本有的pawn生态系统,但这实在是太宏大了,所以也花了很长时间在这上面。

infernus-starter是一个模板,用来快速建立项目上手,其实随便扯一个东西都有话聊。 就说starter吧,它是一个需要不断更新的模板,你做模板需要经常做deps的update,来确保依赖与时俱进,哪怕你哪一天停更了,按你最后一次更新来说也要尽可能的不落后。

对于infernus自身来说可能编译速度还不是很大要求,但对模板使用者来说就不一样了。 早期infernus和infernus-starter都在用rollup做编译,但性能实在是太慢了, 后续我们才迁移到rslib,那会是rslib刚诞生之初我们就用上了,然后直到vite8的出现我们才最终迁移到了vite。

构建工具逐渐rust化来提高性能,这些东西都是时代的产物,包括ai这些,放在某个时间点之前,很多问题是没有很好的解决方案的,就只能忍受着。

包括从eslint迁移升级到oxlint,从prettier迁移升级到oxfmt等等,总之没有社区的帮助自己一个人做所有事实在是太累了。

说实在的维护开源项目真的是个很累的事,包括open.mp也是,目前貌似只有amir这一个头部开发者,但其实大家都一样的,基本上都会被生活琐碎时间困扰,哪来那么多功夫维护在一个东西上面。

搞开源开发,不是以赚钱为目的,当然也通常赚不到钱,还会耗费大量时间精力人力,本身就是一个吃力不讨好的事,完全就是靠热爱用爱发电投入在里面,或者说是你自己确实对这个东西感兴趣才去做的,你也不在乎有没有人用,你就是瞎研究。

如果说今天的open.mp生态,放在10多年前,也许我们可以说是一种超前的设计,如果在过去拥有今天这样庞大的社区,有这么多完善的文档等等,那是一件很幸福的事,但放在今天,到底是谁在2026年还在玩一个老游戏呢?

只能说国外社区的确实是还有大量的人还在玩,但放眼国内还有多少呢,10几年前的时候国内就已经基本上没什么人玩了。

对了之前我有提到生态系统吧,但应该没具体说,就是很多问题都是一个问题解决又牵扯到新的问题的。

光开发core的话,肯定不够啊,每个包都有自己的职责,就是说对于三方语言来编写代码的话,你有了core,但你如果要用到pawn生态的东西,你还要再回头去写pawn代码,这不是一个很头疼的事情吗?你又有pawn代码又有另一个语言的东西,它的复杂度就上去了。 所以最好是一统江湖,如果真正让一个语言来写所有东西,就会有个巨大的任务了,就是 重写所有的pawn生态,至少把流行的pawn库都给重写了。

总之至少我目前重写了很多吧,也没法保证真的能用,它肯定也有很多bug,但就算我停更了不再维护了,也许未来也会有哪个年轻的孩子感兴趣再fork下去自己维护呢?或者推倒我的一切按他们自己的想法来完全重实现呢?

哦对了,还是稍微提一句omp-node吧,它算是samp-node的续作了,它不经过fakeamx,所以从性能和安全性上来说,它一定是遥遥领先的,但从便携性上来说,它又没有过去传统的samp-node的callNative和on事件注册这么方便。至少目前来说是这样吧。然后infernus又完全依赖于callNative和on来做事件注册和函数调用,所以迁移到omp-node是不太现实的,但我们至少现在算攻克了64位不能编译的问题吧,勉强有个64位的samp-node可用,但不保证稳定性和bug,也不是不能用。

顺带一提除了这些库,我还在中文维基上做了很多内容,数千个文档的汉化工作。 当然这种工作量不可能完全是人工来做的,所以利用国内ai大模型信雅达表达的基础上再配合人工微调,而不是传统机翻,它的质量还是可保证的。

因为最早的时候确实是还没有进入到ai时代,确实有很多机翻或者人工翻译的不标准不流畅问题,期间被其他国内玩sa的开发者推倒过一次,就是完全删掉我之前做的工作,总之他们接手后只更新了几个文章,也没保持继续更新,维护了一部分就没动静了,所以后面还是我来做这个事吧。

我是无所谓自己所做的事情被肯定或否定的,只要我做的事情引起社区其他人的关注了,有其他人来推动进步,我能少出一点力,社区能做的更好那是好事啊。

如果你感兴趣可以看看我维护的这些代码,这些代码算不上是高质量的东西,甚至说是很糟糕的东西,我是纯靠兴趣来做的,也不求什么。

这些年我给open.mp捐赠了折算汇率大概1200多元,就是希望这个社区能够更好的发展,当然捐赠完全是看个人意图也不能道德绑架别人去捐赠对吧,但说真的,到底是谁能做到我这一步呢,如果说真的热爱这个游戏,热爱这个圈子?

我自己在维护开源项目上在ai上也投入了大量的钱,关键是我在做这些东西的时候,我还在经历很长时间的失业期……

想到哪说到哪,先这样吧,随缘更新。

未来会更好吗?这个世界会变得更好吗?