s6652289-EasyPortal icon

EasyPortal

[AI-generated] Every 5 s, finds portals within 60 m, highlights them for 10 s and draws a screen arrow with tag and distance. Places a named map pin (portal icon) once per portal and removes it when the portal is gone. Client-only.

Last updated 2 months ago
Total downloads 113
Total rating 0 
Categories Mods AI Generated
Dependency string s6652289-EasyPortal-1.0.4
Dependants 0 other packages depend on this package

This mod requires the following mods to function

denikson-BepInExPack_Valheim-5.4.2350 icon
denikson-BepInExPack_Valheim

BepInEx pack for Valheim. Preconfigured with the correct entry point for mods and preferred defaults for the community.

Preferred version: 5.4.2350

README

EasyPortal

传送门探测器。 纯客户端模组 —— 每 5 秒扫一遍周围 60 米内的传送门,探测到就高亮 10 秒、 在屏幕上用箭头指向它(带标签名与距离),并在地图上按标签名自动打图钉。

AI 生成声明:本模组由 AI 智能体(WorkBuddy)在用户的明确需求与逐项验收下编写; 需求描述、交互设计与发布决定均由用户主导。

功能

# 功能 默认 配置节
1 每 N 秒探测周围 R 米内的传送门 5 秒 / 60 米 1 - Detection
2 探测到就高亮 M 秒(光柱 + 脉动点光) 10 秒 1 - Detection / 2 - Highlight
3 屏幕上画箭头指向它,显示标签名 + 距离(m) 开 3 - Screen Marker
4 地图上按标签名打图钉;同名旧图钉自动挪过来 开 4 - Map Pin
5 传送门群(家里那一片)整体跳过 开 1 - Detection
6 已标记过的传送门不再重复检测 开 4 - Map Pin
7 传送门被拆 → 自动删除地图标记 开 4 - Map Pin

1.0.3 改动: ① 标签底衬改成 OreFinder 同款(不画底块、纯黑描边),并修掉"文字被乘黑"的 bug → LabelBackground; ② 已标记过的门不再重复检测(不再重复高亮 / 重复建图标)→ SkipAlreadyPinned; ③ 门被拆掉会自动删掉地图图标 → 由 SkipAlreadyPinned 一并启用。 详见 CHANGELOG.md。

1.0.2 改动: ① 地图图钉图标默认改为 Portal,且已有的同名图钉会自动换成新图标(不必手动删); ② 修掉两处误导性日志/策略 —— 传送后"登记册为空"属正常,不再错报 Warning; 兜底扫描改为带冷却重试(原来只试一次)。

已标记不重复 & 被拆自动清理(SkipAlreadyPinned)

行为 说明
门第一次被探测到 高亮 M 秒 + 建图钉 + 记入追踪表
之后再探测到同一个门 直接略过 —— 不再高亮、不再画箭头、不再重复建图钉
门被拆掉 玩家在它附近、连续 2 轮探测不到 → 自动删掉地图图钉
门被搬走重建 是新的网络对象 id → 当作新门重新标记(图钉在新位置重新出现)

🔑 识别「同一个门」用的是游戏的网络对象 id(ZDOID),不是标签名。 这点很重要:如果按标签名识别,「搬门」(拆掉重建、标签没变但位置变了) 就会被误判成"已标记过"而永远不再标记。

⚠️ 两条防误删约束(避免图钉莫名其妙消失):

  • 只在玩家靠近时才判定被拆 —— 远处的门无法验证(ZDO 按距离流式加载,查不到 ≠ 被删)。 玩家走远时保留图钉并重置计数,不会因为"走远了"而删掉。
  • 需要连续 2 轮探测不到 —— 单轮漏看可能是瞬时抖动(刚传送完、场景还在加载)。

想回到旧行为(每次靠近都重新高亮)把 SkipAlreadyPinned 设为 false, 再配合 1 - Detection → RehighlightOnRedetect 使用。

传送门群(建在一起的门)整体跳过

家里的传送门通常是建在一起的。如果逐个高亮 + 逐个建图钉,等于在一个地图坐标上叠一堆图标、 屏幕上还挂一排箭头。所以本模组会先把探测到的门按物理位置聚簇, 任何一片里门数达到 ClusterSkipMin 就整片都不标记(不高亮、不画箭头、不建图钉)。

配置(1 - Detection) 默认 说明
SkipClusters true 总开关。关掉就按普通规则逐个处理
ClusterRadius 20 米 判定「聚在一起」的间距。链式判定 —— 一排门只要彼此相邻,就会连成同一大片
ClusterSkipMin 2 一片里达到几个门就整体跳过

判定用的是本轮探测到的、且会参与标记的门(没起名的门不算),所以刚放下一个还没命名的门, 不会把旁边正常的门误带进"群"里。

想让小规模(两三个门)照常标记、只有大群才跳过,把 ClusterSkipMin 调大即可。

被跳过的门若此前已建过同名图钉,会被一并清掉(受 TakeOverSameName 约束), 免得地图上留一个永不更新的图标。

地图图钉的规则(重点)

情况 行为
该位置附近已有同名图钉 什么都不做("已经有图标了不用标记")
该标签只探测到 1 个传送门,且地图上同名图钉在别处 删掉旧位置的、在新位置重建("=> 移动了同标签传送门,不用手工去删旧图标")
该标签同时探测到多个传送门 各自保一个图钉,互不删除
没设标签的传送门 默认跳过,不标记也不高亮

最后一条是多加的保护:原版里两个同标签的传送门是互相连通的(很常见), 若不加区分,两头会被反复"删旧建新",图钉一直在闪。 只有"该标签当前只看到一个门"时才执行自动迁移 —— 那才是真正的"把门搬走了"。

⚠️ TakeOverSameName 开启时会一并接管你手工放的同名图钉。 不想要就把它关掉(那样只补建、不删除)。

配置

BepInEx/config/easyportal.client.only.cfg

  • 1 - Detection
    • Radius 60 / ScanInterval 5 / ActiveSeconds 10 —— 三个主参数
    • RequireTag:没名字的门是否跳过(默认跳过)
    • RehighlightOnRedetect:默认 false —— 每个门只高亮一次,站在自己家门口不会一直亮; 想让范围内的门一直保持高亮就改 true
    • ToggleKey:游戏里开关用的快捷键(默认未绑定,别和 OreFinder 的 F9 撞)
  • 2 - Highlight
    • BeamColor 格式 R,G,B,A,默认 0.95,0.62,0.10,0.75(琥珀色半透明)
    • BeamHeight 22 / BeamWidth 0.6 / LightRange 12 / LightIntensity 2
  • 3 - Screen Marker
    • ArrowSize 26 / FontSize 16 / EdgeMargin 60 / ShowDistance true
  • 4 - Map Pin —— 见上面那张规则表
  • 5 - Debug → Verbose:排查用,每次扫描与建图钉都打日志

⚠️ 改完必须重启游戏(BepInEx 只在插件 Awake 读一次配置)。

实现要点(来自 IL 实证,2026-09-17)

  • 传送门类叫 TeleportWorld(不叫 Portal);标签名读 TeleportWorld.GetText(), 其内部是 ZDO 字符串 ZDOVars.s_tag 再过一遍敏感词过滤。
  • 枚举传送门:不在扫描时全场景搜 —— Valheim 的 ZDO 是按距离流式实例化的, 远处的门根本不在场景里,搜也搜不到,而且每 5 秒搜一遍代价太大。 改为 TeleportWorld.Awake 时登记进册(PortalRegistry),扫描时只做"剔除已销毁 + 距离筛选"。 另带一条兜底:登记册为空时会用 ZNetScene.m_instances(反射)扫一次并打警告, 免得像 EasyGear 1.0.0 那样静默失效。
  • 地图图钉走原版 Minimap.AddPin / RemovePin(public)。 参数照抄原版玩家放图钉的调用方式(ShowPinNameInput 的 IL):类型由 PinIcon 决定, save=true 跟着地图存档。RemovePin 内部会 DestroyPinMarker,图标与名字标签一起清掉。 Minimap.PinType / Minimap.PinData 是 Minimap 的嵌套类型(踩过,编译期才会发现)。
  • 换图钉图标为什么必须"删旧建新":Minimap.UpdatePins 的 IL 显示 m_iconElement.set_sprite(m_icon) 只在 UI 元素被重建时才执行 (先判 m_uiElement == null 或父节点不对)⇒ 已存在的图钉不会重新 set_sprite, 光改 PinData.m_icon 字段界面不会刷新。所以本模组在检测到图标不符时删掉重建。 另有防死循环保护:AddPin 在类型不可用时会悄悄把类型改写成 Dot, 若不设限就会无限删建 —— 故每个标签最多升级一次(IconUpgradeTried)。
  • 屏幕箭头走 IMGUI(OnGUI),完全不碰游戏的 uGUI 层级 —— 所以不怕后续版本改 UI 预制体。世界坐标 → 屏幕用 Camera.main.WorldToViewportPoint, 相机背后的情况要手动把镜像坐标翻回来。
  • 中文字体:IMGUI 内置字体没有中文字形,直接画中文会是方块。 解发是 Font.CreateDynamicFontFromOSFont 从系统字体现造一个(优先"微软雅黑")。
  • 箭头/底色贴图用 Texture2D.SetPixels32 运行时生成,不依赖任何美术资源。

兼容性

  • 纯客户端:无 Jotunn、无 ServerSync、无 NetworkCompatibilityAttribute(NotEnforced)。
  • 联机:主机与其他玩家都不需要装;只读场景与本地地图数据,不改任何网络权威数据。
  • 与 OreFinder 功能重叠但不冲突 (都往地图加图钉,但图钉互不干扰)。默认快捷键未绑定,避免与它的 F9 撞车。

安装

r2modman「Install from file」选 EasyPortal-1.0.0.zip, 或把 EasyPortal.dll 丢进 BepInEx/plugins/。 前置:BepInExPack_Valheim 5.4.2350。

版本

  • 1.0.0(2026-09-17):首个版本。