
PalDungeonCompass - 罗盘上的地下城与遗物
地下城传送门、宝箱和遗物雕像出现在每个在线玩家的罗盘上,无论队伍中没有通巴特或诺克斯。它从服务器端驱动游戏自身的搜索技能,因此对等性是结构性的:技能能找到什么,它就能找到什么。服务器端——客户端无需安装任何内容,包括主机玩家。
查看大图[size=5][b]地下城传送门与遗物雕像显示在所有人罗盘上——无需队伍中有搜索帕鲁[/b][/size]
该模组从服务器端驱动游戏自身的搜索技能,因此每位在线玩家都能看到这些技能本应显示的内容:
[code] Tombat (CatBat) 地下城传送门和地图物件——宝箱、掉落物堆 Nox 遗物雕像(雕像)[/code] 两者同时显示在同一罗盘上,与游戏中同时携带两只帕鲁在队伍中时的表现完全一致。
[size=4][b]服务器端。客户端无需安装任何内容。[/b][/size]
纯 Lua 实现,由专用服务器上的 UE4SS 加载。PC、Xbox 和 PlayStation 玩家都能获得相同的行为,无需改动任何文件。
[b]已在原生 Linux 专用服务器上进行了生产环境测试[/b],使用的是我们的 GLIBC 2.28 UE4SS 构建版本——该页面是实现 Linux 运行的关键,此处列为必备依赖。Windows 专用服务器上则使用官方 UE4SS。
在帕鲁世界 [b]v1.0.2.101103[/b]、UE4SS 3.0.1、原生 Linux(BisectHosting)环境下测量。
[line]
[size=4][b]为什么这能够实现[/b][/size]
兴趣点进入 PalLocationManager,游戏自带 PalLocationReplicator、FastPalLocationRepInfoArray 和 PalLocationRepInfo。[b]列表是同步复制的[/b]——客户端只绘制服务器注册的内容。罗盘本身不做任何本地决定;它甚至已经准备好了地下城传送门组件(WBP_IngameCompass_dungeonPortal)。
这与捕获准星的情况相反,准星的百分比在客户端内部计算,任何服务器端操作都无法改变它。
[size=4][b]机制[/b][/size]
以下序列不是推测得出的。它是在真实服务器上通过读取钩子捕获的,当时一只真正的 Tombat 正在使用技能:
[code] BP_AIActionSearchDungeonMapObject_C (伙伴控制器上的 AI 动作) PalUtility:GetCoopSkillSearchSystem(self) -> PalGameInstance 上的单例 system:CreateSearchObject(class) -> 搜索对象 search:Start(FVector origin, int32 rank, FGuid requester) SearchDungeonPortalAndMapObjects(...) 每次 Start 调用一次 search:Tick(float delta, PalCoopSkillSearchLocationRegister) 每帧执行 OnAddedLocationForCompass(FGuid, PalLocationPoint_MapObject) 每个点一次[/code] 该模组按间隔时间为每位玩家重复执行 Start 和 Tick。其余全部使用游戏自身的代码。
[b]为什么模组需要驱动 Tick。[/b]Start 不会发布任何内容——它只负责收集。将点交给注册表的是 Tick,而在游戏中执行 Tick 的是伙伴帕鲁的 AI 动作,逐帧运行。这正是队伍中没有伙伴时缺失的部分。在同一位置实测开启和关闭 Tick 的结果:
[code] tick 开启 10 个点,随后 4 个点 tick 关闭 0 个点,两次都是[/code] 没有 Tick 不是“范围变小”,而是完全无效。
10 到 4 的变化还说明了另一个有用的事实:OnAddedLocationForCompass 仅针对[ i]新的[/i]点触发。重复扫描成本很低,而且知识会不断积累。
[b]搜索类刻意使用游戏自带的类。[/b]使用游戏类而不是手动列出类别,可以确保结构上的一致性:技能能找到什么,它就找什么——如果补丁修改了列表,两者会同时变化。
[size=4][b]搜索是声呐式的,而非圆形范围[/b][/size]
游戏数据表,按帕鲁等级:
[code] 等级 1 初始半径 10000 不扩张 等级 5 初始半径 20000 +5000/秒[/code] 等级 5 的初始半径因技能而异(Tombat 为 20000,Nox 为 25000),这就是为什么等级是按[ i]条目[/i]配置的。模组传递等级 5。
由此带来两个调优要点:
[list] [][b]intervalSeconds 必须大于 sweepSeconds。[/b]扫描中途重启会将半径重置为最小值,远距离探测永远无法实现[/] [][b]sweepSeconds 决定最终探测范围[/b]——初始半径加上每秒 5000,上限受 GetSearchRangeMax 限制[/] [/list] [line]
[size=4][b]安装[/b][/size]
[code] ue4ss/Mods/PalDungeonCompass/ |- enabled.txt <- 必需 |- Scripts/ |- main.lua |- config.lua[/code] 要禁用,请将 enabled.txt 重命名为 enabled.txt.off。
[size=4][b]配置[/b][/size]
[code] intervalSeconds 20 每次扫描开始之间的间隔秒数 sweepSeconds 12 模组通过调用 Tick 驱动每次扫描的时长 tickMs 200 每次 Tick 调用之间的间隔毫秒数 searches Tombat+Nox 搜索列表;每个条目包含包名、等级和标签 requesterGuid "player" "player" 使用 PlayerUId;"zero" 使用空 GUID minPlayerLevel 0 最低等级;0 表示不限制 logCycles false 每个周期输出一行 logVerbose false 诊断噪音 logSearchDetail false 记录每次扫描注册的点数 summaryEveryCycles 30 每 N 个周期输出一行摘要;0 表示禁用[/code] [b]请关闭日志功能。[/b]开启 logCycles 和 logSearchDetail 后,在有两位玩家在线的情况下,模组在 37 分钟内写入了 331 行日志——比服务器上所有其他模组的总和还多。摘要行是您需要的存活证明:
[code] summary: 30 cycles, 58 sweep(s), 214 new point(s) on the compass[/code] 摘要中没有任何点并不意味着故障,而是表示附近区域已经被完全注册。
[size=4][b]尚未确认的事项[/b][/size]
[b]FGuid 的含义。[/b]类型已测量,但含义尚未确定。证据指向“发起请求的玩家”——PalLocationBase:IsRequestedPlayer 存在,且名称表带有 RequestPlayerUId 和 ByRequestPlayerUId。如果这个推断正确,图标将只对请求者显示,这在繁忙的服务器上正是您想要的。如果使用“player”时图标不显示,请将 requesterGuid 切换为“zero”。
[b]最终探测范围的实际数值。[/b]GetSearchRangeMax 从未被测量过,因此 12 秒可能多于或少于实际需要。这并不影响正确性,只影响模组的探测距离。
[size=4][b]任何修改代码的人都需要注意的警告[/b][/size]
[b]周期之间缓存的游戏 userdata 在每次使用前必须重新验证。[/b]没有任何对象能“永久”到可以跳过这一步。搜索类通过 LoadAsset 进入内存,没有强引用持有它,UE 的垃圾回收器会将其回收。未经重新验证的缓存会将指向已释放内存的指针传递给 CreateSearchObject——而在该模组中,这恰好发生在玩家加入服务器的时刻。
这是通过惨痛教训学到的:日志中频繁出现的“Asset was found but not loaded”行看起来像是缓存未能保持,因此有效性检查被替换成了 nil 检查。随后发生了两次 Signal=11 崩溃,都发生在玩家连接的时刻。那 73 次重新加载正是模组从垃圾回收中恢复的过程。而那个本应支持移除保护的数字,恰好证明了保护机制在工作。
[size=4][b]如果您在为 Linux 服务器编写模组,请阅读以下内容[/b][/size]
并非所有 UE4SS 调度机制都能在 Linux 构建版本上触发:
[code] RegisterHook 正常 ExecuteInGameThread 正常 ExecuteInGameThreadWithDelay 正常,且准时 ExecuteWithDelay 永不触发 LoopAsync 永不触发[/code] 此外:以错误参数个数调用成员函数会导致进程终止,pcall 无法保护您——故障发生在 lua_pcallk 之下的 C++ 层。并且不要按值构建结构体;FTransform 曾因 16 字节对齐问题导致服务器宕机。
详细说明和解决办法请参阅 UE4SS Linux 构建页面。
[size=4][b]源码[/b][/size]
完整源码、技术文档和问题追踪器: github.com/prado1506/palworld-PalDungeonCompass
这是已在原生 Linux 专用服务器上验证的服务器端帕鲁世界模组集合的一部分。它们共同依赖的加载器在此处。
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。