HumansWithGender - 服务器端人类性别

HumansWithGender - 服务器端人类性别

原版游戏中的商人、士兵和村庄NPC没有性别,也不显示任何图标。本模组根据每个NPC的标识符为其分配一个稳定的性别,使同一NPC始终获得相同的性别。覆盖新生成的角色以及世界中已有的所有NPC。服务器端——客户端无需安装任何内容。

为幻兽帕鲁的人类赋予性别

帕鲁有雄性和雌性之分。但人类——商人、士兵、村庄NPC——没有:游戏将它们视为无性别,并且在界面中完全不显示性别图标。

这个模组为每个人类稳定地分配一个性别。同一个NPC总是获得相同的性别,因为性别的选择取决于其标识符,而不是每次访问时随机决定。

服务端模组。客户端无需安装任何东西。

纯Lua编写,在专用服务器上通过UE4SS加载。PC、Xbox和PlayStation玩家都能获得相同的行为,无需修改任何客户端文件。

已在原生Linux专用服务器上经过生产环境测试,使用的是我们的GLIBC 2.28 UE4SS构建 - 该页面是让这一切在Linux上运行的关键组件,此处将其列为前置要求。在Windows专用服务器上,则使用官方UE4SS。

已在Palworld v1.0.2.101103、UE4SS 3.0.1、原生Linux(BisectHosting)环境下进行测量。


安装

ue4ss/Mods/HumansWithGender/
|- enabled.txt          <- 空文件,但必需
|- Scripts/
   |- main.lua
   |- config.lua

在服务器停止时复制进去。启动后,在UE4SS.log中确认:

Loaded; hook=ok, firstSweep=30s, sweepInterval=120s, sweepVia=ExecuteInGameThreadWithDelay

该行中有两项很重要。 hook=ok 意味着新生成的NPC将被覆盖;sweepVia= 意味着对已有NPC的扫描功能正常。如果显示 sweepVia=none,则模组只有一半功能生效 - 请参阅下方的调度说明。

然后,走过一个村庄:

BP_NPC_Female_Soldier_C ... -> Female

工作原理

采用两条路径,因为单一路径无法覆盖所有情况:

  • OnInitializedCharacter 钩子 - 捕获从此刻起生成的每个人类
  • 周期性扫描 - 捕获服务器启动时已在世界中的人,以及之后从帕鲁箱中取出的人

如果没有第二条路径,只有新生成的NPC会获得性别,而既有的村庄最终会呈现性别混杂的状态。这种症状很容易被误认为是"模组只对部分NPC生效"。

配置

所有配置都在 Scripts/config.lua 中。

modEnabled              true    开启模组
firstSweepDelaySeconds    30    首次扫描前的等待时间
sweepIntervalSeconds    120    扫描间隔(0 = 仅执行一次)
logAssignments          true    每个获得性别的人类记录一行日志
logAssignmentLimit        20    日志行数上限,避免日志刷屏
logSweepSummary         true    每次扫描记录一行摘要,包含数量

设置30秒等待是因为模组启动时世界仍在加载中。过早扫描会发现很少的目标。

  • 大型服务器,NPC众多 - sweepIntervalSeconds = 300
  • 验证后清理日志 - logAssignments = false
  • 仅扫描一次 - sweepIntervalSeconds = 0

已知限制

性别是装饰性的。 它改变了图标和身份标识;但不会启用繁殖功能或改变行为。(如果你想让人类真正繁殖,请参阅 BreedHumans,该模组需要 pak 文件才能实现。)

帕鲁箱中的人类 只有在他们返回世界后,于下一次扫描时才会被处理。

性别选择是稳定但随机的。 它基于NPC的标识符,因此与模型外观不匹配。一个看起来是男性的士兵可能会被标记为女性。

致谢与差异

改编自 Remi 的 Add Genders to Humans。针对此构建进行了三项修复:

  • FindAllOf("PalNPC") 找不到任何东西 - 该类在此环境中不存在。替换为 PalCharacter 并加上人类过滤器
  • 未播种的随机数生成器 - 没有 math.randomseed,每次启动都会产生相同的序列
  • 指向已销毁对象的有效包装器 - IsValid() 对已销毁对象可能返回 true,对其进行方法调用会引发原生错误,而 Lua 的 pcall 无法捕获,导致服务器崩溃。修复方法是在任何调用前检查 GetAddress() == 0

如果你正在为Linux服务器编写模组,请阅读此内容

并非所有 UE4SS 调度机制都能在 Linux 构建上触发:

RegisterHook                    正常
ExecuteInGameThread             正常
ExecuteInGameThreadWithDelay    正常,且准时
ExecuteWithDelay                从不触发
LoopAsync                       从不触发

此模组的早期版本使用 ExecuteWithDelay 进行首次扫描,使用 LoopAsync 进行后续扫描。结果:扫描从未运行。钩子正常工作,所以新NPC获得了性别,而旧NPC没有——这正是"只对部分NPC生效"的症状。

当前版本使用 ExecuteInGameThreadWithDelay,同时保留其他机制作为在其可用的构建上的回退方案,并会将实际使用的机制写入日志。

详细信息和解决方法请参见 UE4SS Linux 构建页面

源代码

完整源代码、技术文档和问题追踪器: github.com/prado1506/palworld-HumansWithGender

这是一个在原生Linux专用服务器上验证过的服务端Palworld模组集合的一部分。它们所依赖的加载器位于此处