You are viewing a potentially older version of this package. View all versions.
khalil-Scrap_Clean-1.2.0 icon

Scrap Clean

Press F to enter clean mode and remove dropped items or player-placed objects. Aim at a target to highlight it, or sweep a ground-hugging dashed circle to clear everything inside it.

By khalil
Date uploaded 5 days ago
Version 1.2.0
Download link khalil-Scrap_Clean-1.2.0.zip
Downloads 80
Dependency string khalil-Scrap_Clean-1.2.0

This mod requires the following mods to function

BepInEx-BepInExPack_PEAK-5.4.75301 icon
BepInEx-BepInExPack_PEAK

BepInEx pack for PEAK. Preconfigured and ready to use.

Preferred version: 5.4.75301

README

Scrap Clean(废料清理)

PEAK 的清理模组:一键清理掉落物与放置物。

安装

  1. 通过模组管理器(r2modman / Thunderstore Mod Manager)安装,或手动解压到 BepInEx/plugins/。
  2. 前置依赖:BepInExPack PEAK。

使用

操作 效果
F 进入 / 退出清理模式
滚动滚轮 在「单选清理」与「范围清理」之间切换(无界,每滚一次换一个模式)
鼠标左键 执行清理

清理模式会记住你上次用的子模式:在范围清理下按 F 退出,下次进入还是范围清理 (该偏好写在配置文件的 General/LastMode,跨游戏重启也保留)。

屏幕下方常驻一张信息卡片:上排是当前模式与可执行动作,下排是当前会清理哪个目标、 它有多远、能不能清。模式切换与结果反馈以带滚动动画的短提示出现。

单选清理

按视线挑选:准星指向的掉落物或放置物会被高亮,左键清理它。

判定顺序为「距离上限(默认 100 米)→ 在视野锥内 → 无地形遮挡 → 与准星夹角最小」, 所以不在玩家眼中的东西不会被选中,也不会被误清理。

判定基于物体的视觉包围盒而不是它的坐标原点:像大炮(原点在底座)、 墙上的踏板菇(原点在墙面接触点)这类目标,用原点做判定会被自己的地面 / 墙面挡住而永远选不中。 包围盒只统计实心几何(网格 / 蒙皮网格 / 线段 / 精灵),不统计粒子与拖尾: 粒子系统的包围盒是「当前存活粒子」的范围,便携炉的常驻烟雾会把代表点顶到 40 米高空。

范围清理

视线中会出现一个贴合表面的虚线圆形(半径 3 米,可配置)。圆心是准星命中的那个点, 圆环沿该点的表面法线展开并逐点吸附到真实几何体上: 地面贴地、墙面贴墙、斜坡沿坡面起伏,不会穿模。

圆内的所有掉落物与放置物会被一起清理。

什么是「掉落物」和「放置物」

  • 掉落物:任何被丢在地上的道具(Item.itemState == Ground)。 手里拿的、背包里的永远不会被清理。
  • 放置物:玩家使用道具后留在地图上的物体。已确认支持:
    • 绳索锚点(绳索炮 / 绳索卷轴打出的锚点)与其绳索
    • 岩钉(ClimbingSpikeHammered,含劣质岩钉)
    • 检查点旗帜(Flag_Planted_Checkpoint)
    • 便携炉(PortableStovetop_Placed)
    • 侦察兵大炮(ScoutCannon_Placed)
    • 踏板菇 / 弹跳菇 / 满血蘑菇 / 云真菌的「已放置」形态
    • 魔法豆藤蔓(MagicBeanVine)
    • 锁链(ChainShootable)
    • 系在玩家身上的气球(TiedBalloon)

世界生成的地形、岩石、建筑、木质平台等固定景物绝不会被清理。 判定依据是「运行时由 PUN 生成」+「名字或组件命中白名单」+「不在排除名单里」。 排除名单里是关卡脚本生成、或只在本地预览的物体,例如登顶流程用的 RopeAnchorHelicopter 与 RopeDynamicHelicopter(清掉会让玩家无法通关)、关卡装饰用的 RopeAnchorWithRope、 世界岩钉 PickAxeHammered_Shitty、以及放置预览 RopePreview。

多人联机说明

清理分三条路径,全部依据 PUN 的实际规则实现:

  1. 自己的东西 → 直接删除。
  2. 别人的掉落物 → 物品允许接管所有权,抢过来后删除。
  3. 别人的放置物 → PUN 禁止转移这类物体的所有权, Scrap Clean 会向该物体的所有者客户端发送一个自定义事件(事件码 190),由对方代为删除。

对端装了模组时由对方删除,所有权账目最干净;对端没装模组或迟迟没有响应时, 模组会在一小段等待后由本机接管所有权完成清理(需保持 Network/AllowOwnershipTakeover 开启)。 接管意味着本机会短暂伪造该物体的所有者编号,删除失败时会还原。

可以用 Network/AllowOwnershipTakeover = false 完全关闭跨玩家清理。

配置

配置文件:BepInEx/config/com.zhuanban.peak.scrapclean.cfg

项 默认 说明
General/ToggleKey F 开关快捷键
General/SingleRange 100 单选清理的视线判定距离上限(米),范围 5~300
General/AreaRadius 3 范围清理圆半径(米),范围 0.5~20
General/LastMode Single 上次退出时用的子模式,由模组自动写入(Single / Area)
Filter/CleanDroppedItems true 是否清理掉落物
Filter/CleanPlacedObjects true 是否清理放置物
Network/AllowOwnershipTakeover true 是否允许跨玩家清理
UI/ToastSeconds 2 文字提示停留时间(秒)
Debug/VerboseLogs false 详细诊断日志(排查问题时才打开)

按键冲突

游戏自带的 InputActions 没有占用 F,因此默认使用 F,不会与游戏功能冲突。

清理模式只接管鼠标左键与滚轮(进入期间它们只用于清理), 移动、跳跃、交互、语音等全部保持正常。 右键在清理模式下同样被抑制,避免误用手持道具的次要功能。

已知边界

  • 清理别人的放置物需要对方也在线:模组会先请求对方代删; 对方没有安装模组或迟迟没有响应时,模组会在一小段等待后由本机接管所有权完成清理。
  • 跨版本联机:清理请求带固定载荷标识,与 1.1.0 及更早版本互不识别。 跨版本联机时"清理别人的放置物"会被忽略,并在日志里留一条限流告警(本机清理不受影响)。
  • 绳索需要连带处理:绳索本体与锚点是两次独立实例化, 模组会把锚点对应的绳索一起登记;跨客户端时由持有绳索的那一端在执行删除时一并处理。
  • 场景自带的绳索可能被清理:关卡里的锚点在加入房间时会拉出一根绳索,它同样是运行时生成, 因此也在候选范围内。锚点本身已在排除名单里清不掉,所以删掉绳索后会留下一个裸锚点。
  • 范围清理受视线影响:圆心是准星命中的表面点,准星没打到任何表面时不会显示圆环。
  • 高亮覆盖面:模组使用游戏原生的 _Interactable 材质属性做高亮,与游戏悬停高亮同一条路径。 少数材质(例如便携炉火焰粒子的 Universal Render Pipeline/Lit、云雾菇的云)没有该属性, 对这些渲染器高亮不可见,但目标本体通常另有支持的材质,清理功能也不受影响。
  • 无 PhotonView 的放置物扫不到:Constructable 在预制体没有 PhotonView 时会改用 Object.Instantiate 生成,这类物体不出现在 PhotonView 扫描结果里。 3.0.1 里只有开发用预制体属于这一类。
  • 死亡与观战期间无法清理:这两种状态下清理模式会自动退出,回到存活状态后按 F 重新进入。
  • 仅支持键鼠:开关、滚轮切换与左键清理都读鼠标与键盘,手柄暂不支持。
  • 活体生物:蝎子 / 青蛙等身上带 MobItem : Item,走动时状态就是 Ground, 因此也会被当作掉落物清理(这是刻意保留的行为)。
给开发者:构建与代码结构

构建

dotnet build -c Release

默认输出到 bin\Release\ScrapClean.dll 并自动复制到 BepInEx/plugins/。 游戏目录可用 -p:GameRoot=... 覆盖,或用 -p:DeployToGame=false 关闭自动部署。

目录结构

src/
  ScrapCleanPlugin.cs   生命周期与 Harmony 挂载
  ScrapCleanConfig.cs   BepInEx 配置
  CleanMode.cs          主状态机(输入 / 扫描 / 高亮 / 清理 / 通知)
  TargetScanner.cs      候选目标的扫描与分类
  Cleaner.cs            删除执行(三条网络路径)
  CleanRequestRelay.cs  跨客户端清理请求(自定义事件)
  HighlightRenderer.cs  原生 _Interactable 属性高亮
  GroundRing.cs         贴合表面的虚线圆环
  CleanUI.cs            信息卡片与滚动提示
  ScrapCleanPalette.cs  配色与字号
  ScrapCleanWarmup.cs   加载期间的一次性预热
  CenterCache.cs        视觉包围盒与代表点
  HarmonyPatches.cs     CharacterInput.Sample 后置补丁(输入抑制)
  SCInput.cs            输入读取
  SCLog.cs              日志
tools/                  研究脚本(资产探测、预热字符表、封面生成,不参与构建)

界面文案与预热字符表

CleanUI.PrimeCorpus 必须覆盖所有会显示的字符,否则首次显示新字形时仍会掉帧。 改了任何界面文案后运行:

python tools/gen_prime_corpus.py

把输出替换 PrimeCorpus 里非 ASCII 的那几行即可;ASCII 前缀两行要保留,否则数字与字母会在首次显示时才生成字形。

CHANGELOG

Changelog

1.2.0

修复

  • 便携炉(以及任何带长寿命粒子特效的目标)永远清不掉。 代表点原先取「所有渲染器的包围盒并集」,而粒子系统的包围盒是当前存活粒子的范围: 便携炉身上的 VFX_Smoke_Off 是 looping + prewarm + playOnAwake,会撑出一条 80 米的烟柱, 把代表点顶到 40 米高空并逐帧漂移。结果单选模式算出的准星夹角永远过大(无高亮、信息条不显示它), 范围模式算出的三维距离永远超出半径(圆环罩住也清不掉)。 现在包围盒只采纳实心几何(Mesh / SkinnedMesh / Line / Sprite),排除粒子与拖尾, 并以非 trigger 碰撞体、再以 pivot 依次兜底。 同一原因导致的其它目标:ScoutsHonor(永久)、侦察兵大炮、四种蘑菇落地实体、魔法豆藤蔓、 云雾菇、蜡烛 / 灯笼 / 火把(点燃后)—— 全部一并修好。
  • 清理模式可能被意外退出:HighlightRenderer 用接口引用判空, 而接口上的 == null 不遵守 UnityEngine.Object 的重载,目标在悬停中被销毁时会抛 MissingReferenceException,冒泡到主循环后把玩家踢出模式。现在先转成 Object 再判空。
  • 伪造的跨客户端清理请求可以删掉别人手里的道具。入站事件现在要求固定的载荷标识, 并按与本地点击完全相同的规则复核目标(掉落物必须仍在地上且处于激活状态、手持卷轴绳索拒绝、 放置物必须在白名单形状内),同一目标的入站请求 5 秒内只处理一次。
  • 所有权接管失败后不回滚:EnsureLocalOwnership 失败时直接返回,伪造的本地所有权会永久残留。 现在两条失败路径都还原;且原所有者编号为 0 时不再写回(PUN 的 setter 会把 0 解析成房主)。
  • 误报清理成功:PhotonNetwork.RemoveInstantiatedGO 在 AppQuits 时静默返回、不抛异常, 旧判据会当成成功。现在以目标是否真的失活作为判据,本地无网络路径也先失活再销毁。
  • 关掉菜单 / Alt-Tab 后凭空切一次模式:失焦期间不再响应滚轮,被 UI 阻塞时与回焦时都会清掉残留冷却。
  • 绳索锚点删除顺序:改为先删锚点、成功后再删绳索,避免锚点删除失败时留下无绳锚点。
  • 范围清理失败日志刷屏:一次失败曾按目标数量逐条输出,现在合并为一条限流告警。

改进

  • 清理模式会记住上次用的子模式:在范围清理下退出,下次进入仍是范围清理。 偏好写在 General/LastMode,跨游戏重启保留。
  • 界面重做:常驻卡片(模式 + 可执行动作 / 当前目标 + 可清理状态)与瞬时提示分离, 配色、字号、行高统一到 ScrapCleanPalette;提示符号限定在字体必然包含的字符集内。
  • 目标显示名本地化:放置物优先用游戏自己的 IInteractible.GetName(), 其次内置中文名,最后才退回 prefab 名(不再出现 PortableStovetop_Placed 这种内部名)。
  • 偏角降级为排障信息:只在 Debug/VerboseLogs 打开时显示,平时只显示距离与可清理状态。
  • 消除首次按 F 的卡顿:加载画面期间以 alpha 0 预热面板(TMP 字形与图集)、 圆环材质(URP 变体编译)与候选扫描;预热失败可重试,面板显示中绝不预热。
  • 放置物白名单按 3.0.1 资产实测重整:新增排除名单,剔除登顶脚本生成的 RopeAnchorHelicopter / RopeDynamicHelicopter 等关卡专用预制体(删掉会破坏通关), 并去掉零引用的死资产。
  • 扫描与视线判定降本:形状判定只看根物体组件、已登记候选改哈希表、遮挡射线忽略目标自身、 拒绝诊断改为惰性求值。
  • 运行期把手工改到 20 米以上的 AreaRadius 钳回 20 米。配置项的取值范围本来就是 0.5~20, 但旧版本运行期允许到 50,两者不一致。
  • 收到旧版本格式的清理请求时会留一条限流告警,不再静默丢弃。
  • 持续滚动只算一次手势:一次长拨(自由滚轮 / 平滑滚动)不会再把模式来回切好几次。
  • 目标不可清理时不再显示距离:那一行改为优先放"为什么清不掉"。

已知边界

  • 场景自带的绳索(由关卡里的锚点在加入房间时拉出)同样是运行时生成,仍可能被清理。
  • 跨版本联机时,旧版本客户端发来的清理请求会被忽略,并在日志里留一条限流告警 (本机清理不受影响)。
  • 完全不带 PhotonView 的放置物扫不到。3.0.1 里只有开发用预制体属于这一类。

1.1.0

修复

  • 多人联机下,自己扔出的蘑菇类放置物无法清理(踏板菇 / 弹跳菇 / 满血蘑菇 / 云雾菇)。 这些落地实体是在持有者客户端创建的,而所有权信息可能被 PUN 的缓存判错, 导致模组误以为"东西是别人的",只发出一句请求后就再无下文(界面一直显示"已请求清理")。 现在模组会正确识别"这台机器就是它的创建者/所有者",直接就地清理。
  • 清理对方物品时的兜底:如果对方客户端没有安装本模组、或迟迟没有响应, 模组会在一小段等待后由本机接管所有权并完成清理,不再无限期停留在"已请求清理"。 这条兜底只在 Network/AllowOwnershipTakeover 开启时生效。
  • 绳索更换所有者后可能残留:删除绳索锚点时,若绳索视图的所有权缓存同样出错, 会留下一根悬空的绳子。现在锚点与绳索使用同一套所有权判定。
  • 清理失败时不再误报成功:之前若所有权获取失败,界面仍会显示"已清理", 现在会如实提示失败原因。

改进

  • 清理日志补充了 Owner / Creator / 本地玩家编号,便于排查联机问题。

1.0.0

首发版本。

功能

  • F 进入 / 退出清理模式。
  • 单选清理:按视线挑选目标 —— 准星指向的掉落物或放置物会被高亮,左键清理它。 判定顺序为「距离上限 → 在视野锥内 → 无地形遮挡 → 与准星夹角最小」, 因此不在玩家眼中的东西不会被选中。距离上限默认 100 米。
  • 范围清理:视线中出现一个贴合表面的虚线圆形(默认半径 3 米), 圆心是准星命中的那个点,圆环沿命中面的法线展开并逐点吸附到真实几何体上: 地面贴地、墙面贴墙、斜坡沿坡面起伏。圆内的所有掉落物与放置物会被一起清理。
  • 滚轮在两种模式之间切换(无界,每滚一次换一个模式)。
  • 进入模式、退出模式、切换模式都有明确的文字提示与上下滚动动画,文字停留 2 秒后自行消失。
  • 常驻信息条实时显示当前会清理哪个目标。

目标识别

  • 掉落物:任何被丢在地上的道具(Item.itemState == Ground)。 手里拿的、背包里的永远不会被清理。
  • 放置物:玩家使用道具后留在地图上的物体 —— 绳索锚点与其绳索、岩钉(含劣质岩钉)、 检查点旗帜、便携炉、侦察兵大炮、踏板菇 / 弹跳菇 / 满血蘑菇 / 云真菌的已放置形态、 魔法豆藤蔓、锁链与丛林藤蔓、系在玩家身上的气球。
  • 世界生成的地形、岩石、建筑、木质平台等固定景物绝不会被清理。

高亮

  • 复用游戏原生的 _Interactable 材质属性(与游戏自身的悬停高亮同一条路径), 零额外渲染开销,视觉风格与原生一致。

多人联机

清理分三条路径,全部依据 PUN 的实际规则实现:

  1. 自己的东西 → 直接删除。
  2. 别人的掉落物 → 物品是 OwnershipOption.Takeover,抢过所有权后删除。
  3. 别人的放置物 → PUN 禁止转移这类物体的所有权, 模组会向该物体的所有者客户端发送一个自定义事件(事件码 190),由对方代为删除。 对端也需要安装本模组,否则该物体保留不动(安全失败,绝不越权破坏别人的世界)。

输入

  • 清理模式只接管鼠标左键与滚轮;移动、跳跃、交互、语音全部保持正常。
  • 左键的"松开"事件会保留,因为游戏自身的绳索、攀爬、长按施法状态机用它做收尾。

配置

配置文件:BepInEx/config/com.zhuanban.peak.scrapclean.cfg

项 默认 说明
General/ToggleKey F 开关快捷键
General/SingleRange 100 单选清理的视线判定距离上限(米),范围 5~300
General/AreaRadius 3 范围清理圆半径(米),范围 0.5~20
Filter/CleanDroppedItems true 是否清理掉落物
Filter/CleanPlacedObjects true 是否清理放置物
Network/AllowOwnershipTakeover true 是否允许跨玩家清理
UI/ToastSeconds 2 文字提示停留时间(秒)
Debug/VerboseLogs false 详细诊断日志(排查问题时才打开)

已知边界

  • 固定所有权的放置物依赖对端响应:对端没装模组时清不掉。这是 PUN 的硬限制,模组不会绕过它。
  • 范围清理受视线影响:准星没打到任何表面时不会显示圆环。
  • 高亮覆盖面:极少数材质没有 _Interactable 属性,对这些渲染器高亮不可见,但清理功能正常。
  • 活体生物:蝎子 / 青蛙等身上带 MobItem : Item,走动时状态就是 Ground, 因此也会被当作掉落物清理(这是刻意保留的行为)。