You are viewing a potentially older version of this package. View all versions.
Zichen-CarryFriend-1.0.4 icon

CarryFriend

Carry your teammates! Hold E to carry/drop, hold R to request a carry, hold X to carry all nearby players or drop everyone. Six mount positions (vertical carry / on head / on back / orbit / train queue / cradle), up to 20 passengers, host-synced config.

By Zichen
Date uploaded 2 weeks ago
Version 1.0.4
Download link Zichen-CarryFriend-1.0.4.zip
Downloads 2914
Dependency string Zichen-CarryFriend-1.0.4

This mod requires the following mods to function

BepInEx-BepInExPack-5.4.2100 icon
BepInEx-BepInExPack

BepInEx pack for Mono Unity games. Preconfigured and ready to use.

Preferred version: 5.4.2100

README

背起队友 / CarryFriend

支持 R.E.P.O. v0.4+。 交流 QQ 群:824639225

Scroll down for English ↓

功能说明

本模组允许你背起队友,用于在联机游戏中进行救助与娱乐。

  • 背起/放下:对准队友,长按 "E" 键(默认 0.6 秒,判定时间由房主配置决定)。完全无手持与抓取限制,手中拿着手电筒、道具或者左键抓握住对方身体,均能正常长按交互背负。
  • 请求被背:对准活着的队友,长按 "R" 键。
  • 一键背起/全部放下:长按 "X" 键(读条满后触发)。没背人时自动背起半径 10 米内所有存活队友(由近到远,受「最大背负数量」限制,带 3 秒内置冷却);背了人时一键全部放下(放下无冷却)。
  • 主动下车:被背着时,按下 [Space] 空格键,或者长按 "E" / "R" 键,或者用鼠标左键抓住队友后背加血点即可下来。
  • 自由动作:被背着时仅屏蔽了 WASD 移动。你依然可以自由转头环顾、使用手部抓取周围物品、以及按 F1-F6 播放所有表情动作。
  • 六种悬挂位置:房主可配置被背队友的悬挂位置——垂直背起(默认)、头顶上(叠罗汉)、背上(圆弧)、环绕飞行(卫星环)、火车队列、身前怀抱,均天然适配多人(最多 20 人)。
  • 房主参数强同步:房主设定的悬挂位置、背起垂直高度、最大背人数量、读条时长在多人联机时自动同步给客机,双端表现一致。
  • 倒地背负、中途加入与复活自愈:支持背负倒地(Downed)队友;Postfix 逻辑加装 try-catch 保护,适配中途加入模组与纯净版联机;复活瞬间自动重置关系并恢复移动。

配置说明

分组 配置项 默认值 说明
A.模组信息 语言 English 配置文件显示语言,支持中文与英文。
B.全局设置 模组启用 开启 关闭后模组完全失效,不占用性能。
C.时间设置 按住E背起时间 (秒) 0.6 长按所需的按键判定时长。由房主控制生效。
D.规则设置 悬挂位置 垂直背起 被背队友的悬挂位置(垂直背起/头顶上/背上/环绕飞行/火车队列/身前怀抱)。由房主控制生效。
D.规则设置 背起垂直高度 2.3 所有悬挂位置共用的统一挂载垂直高度(米),范围 0.1~20。由房主控制生效。
D.规则设置 最大背负数量 20 单人同时背负的最大数量(1~20,20 即不限制)。由房主控制生效。

English

Features

Carry your teammates on your back!

  • Carry/Drop: Aim at your teammate, hold "E" (default 0.6s, hold duration based on host config). No item holding or physical grab restrictions—you can carry teammates even if you are holding flashlights/tools, or physically grabbing them.
  • Request to be Carried: Aim at a live teammate, hold "R".
  • Carry All / Drop All: Hold "X" (triggers after the progress bar fills). When not carrying anyone, automatically carries all nearby teammates within a 10m radius (nearest first, capped by "Max Carry Count", with a 3s internal cooldown). When carrying, drops everyone at once (drop has no cooldown).
  • Dismount: While carried, press Jump [Space], hold "E" or "R", or grab the carrier's back healing spot to get down.
  • Free Action: Only WASD movement is blocked while carried. You can still look around, grab items, and press F1-F6 to use all expressions/emotes.
  • Six Carry Positions: Host can configure where carried teammates are mounted—Vertical Line (default), Head Top (stacking), Back (arc), Orbit (satellite ring), Train, Front—all naturally support multiple passengers (up to 20).
  • Host Sync: The host's carry position, carry height, max carry count, and hold duration are automatically synced to all clients for a consistent experience.
  • Downed Carry, Late Join & Revive Adaptations: Supports carrying downed teammates; Postfix logic wrapped in try-catch for seamless late-join and vanilla compatibility; auto-resets on revive.

Settings

Group Setting Default Description
A.Mod Info Language English Display language for config options (supports English and Chinese).
B.Global Mod Enabled On Toggle to enable/disable the mod.
C.Timers Interact Hold Duration (s) 0.6 Hold duration required to carry, drop, or request to be carried. Managed by Host.
D.Rules Carry Position Vertical Line Where carried players are mounted (Vertical Line / Head Top / Back / Orbit / Train / Front). Managed by Host.
D.Rules Carry Height 2.3 Unified vertical mounting height (meters) for all carry positions, range 0.1~20. Managed by Host.
D.Rules Max Carry Count 20 Maximum number of players a single person can carry (1~20, 20 = unlimited). Managed by Host.

CHANGELOG

1.0.4

  • 默认悬挂位置改为「垂直背起」,X 键背起加 3 秒内置冷却:
    • Carry Position(悬挂位置)默认值由「头顶上」改为「垂直背起」(CarryPositionMode 兜底、HostCarryPosition 字段、配置 Bind 默认值、ResetState 重置值四处同步修改)。
    • X 键「一键背起」新增 3 秒内置冷却(_xKeyCarryCooldown,触发后每帧递减);冷却期间长按 X 无法触发背起,「全部放下」不受冷却影响,可随时触发。
  • 头顶上叠罗汉间距微调:stackHeight 由 0.5m 调整为 0.6m,被背者之间上下堆叠距离略微拉大。
  • X 键改为长按读条,支持一键背起与全部放下:
    • 原「按一下 X 立即背起」改为「长按 X 读条」(满 RequiredHoldTime 后触发)。
    • 没背人时长按 X = 一键背起附近所有玩家;背了人时长按 X = 全部放下。
    • 读条期间锁定动作类型(_xKeyIsRelease),防止状态翻转导致动作错乱;OnGUI 新增 X 键读条进度显示(放下天蓝色、背起绿色)。
  • 背起垂直高度默认值 3.8m → 2.3m:Carry Height 配置默认值、CarryHeight() 兜底、HostCarryHeight 字段、ResetState 重置值四处同步改为 2.3m。
  • 最大背负数量改为 1~20 真实数量,滑到最大即 20(不限制):
    • 原用 AcceptableValueRange<int>(1, 6),第 6 档为「不限制」哨兵值,REPOConfig 滑条只显示数字「6」无法体现「无限」语义。
    • 改为 AcceptableValueRange<int>(1, 20),删除 UnlimitedCarryCount=6 哨兵逻辑,EffectiveMaxCarryCount() / EffectiveHostMaxCarryCount() 改为 Mathf.Clamp(v, 1, 20),直接用真实数量(20 = 游戏最大人数)。
  • 修复 ForceReleaseAllCarried 死人头类型误判(P1):
    • 原用 _lateAvatarCache.ContainsKey(tid) 判断被背目标类型,但该缓存存放活人 viewId 且会被多条清理路径 Remove;背人者死亡触发强制释放时缓存可能已清空,导致活人乘客被误判为死人头,下车走 targetType==2 分支(FindDeathHeadByViewID 返回 null 直接 return),乘客残留在背上。
    • 改为按实际对象类型判定:先用 FindPlayerAvatarByViewID 找活人,找不到才用 FindPlayerDeathHeadByViewID 判定死人头。
  • 清理开发期遗留的运行期调试日志:将 LateUpdate 每 120 帧乘客位置日志、强制 tumble 状态日志、孤儿 trigger 恢复日志、每次背起 trigger 数量日志等高频 LogInfo 移除或降级为 LogDebug(默认不输出),减少日志刷屏与字符串拼接 GC 压力。
  • 修复 ResetState 下车定位用错 carrier 的语义 bug:
    • 场景切换/销毁时清理所有背起关系,原代码用本地玩家 local 作为所有被背者的下车落点基准,而非实际的背人者(ActiveCarries 的 value),导致落点偏到本地玩家附近而非实际背人者附近。
    • 修复:改为取 pair.Value(实际背人者)作为 DropPlayerPositioning 的 carrier 参数;背人者已不存在时才退回用 local。
  • 修复「按 X 一键背起附近所有玩家」在房主端双重计数、导致实际背起人数减半的 bug:
    • 此前修复客机端冗余发送时引入了 requestedThisBatch 乐观计数,但房主端 ProcessCarryTransfer 会即时更新 ActiveCarries,myCarriedCount 本已正确递增,却又叠加 requestedThisBatch,导致 myCarriedCount + requestedThisBatch 双重计数、提前 break。
    • 后果:房主端一键背起(默认上限 5 人)实际只能背起约 3 人。
    • 修复:房主端改用真实承载数 myCarriedCount 判断,客机端仍用 myCarriedCount + requestedThisBatch 乐观计数。
  • 新增「防链式背起」检查:ProcessCarryTransfer 现在会拒绝「背人者自己正被别人背」的请求,防止被背者再背别人造成环状/链式状态错乱。
  • 修复跨房间配置残留:ResetState 现在会重置房主同步配置(悬挂位置/背起高度/人数上限/读条时间)为默认值,避免换房间后客机短暂使用旧房主的残留配置。
  • 修复放下提示的死人头重复计数,并清理死代码:
    • 修复 OnGUI 里 totalCount 对 _myCarriedHead 重复 +1 的问题:GetMyCarriedTargets() 已包含死人头(ActiveCarries 的 key 同时含活人与死人头 ViewID),再额外 +1 会误判为多人导致提示文字错误。
    • 清理两处死代码:CarriedPlayerRotOffset(从未使用的 Quaternion 常量)与 _cachedCarrierDead(只赋值从不读取的死字段,carrier 死亡判断已改为直接调用 GetPlayerDeadSet)。
  • 修复「背起读条时间」配置在客机端不生效的 bug:
    • 此前 RequiredHoldTime() 在所有端都返回本地配置值,客机端背起/下车的读条时长由客机自己的配置决定,而非房主配置,导致双端读条速度不一致(房主设 2 秒、客机仍为默认 0.6 秒)。
    • 现改为与 CarryHeight() 一致:客机端返回房主同步的 HostRequiredHoldTime,确保读条时长双端一致。
  • 清理冗余握手发送:移除背起按键第一帧的旧握手查询发送(已由 Update() 中周期性握手重试统一接管)。
  • 强化非主机(客机)端的联机可靠性:
    • 修复握手一次性发送、无超时重试的缺陷:客机在未确认房主安装模组前,每 2 秒重发一次握手查询包(此前若握手包丢失或房主模组未就绪,客机将永久无法背起任何人)。
    • 握手响应时房主立即向该客机定向下发当前配置(悬挂位置/背起高度/人数上限),新进房的客机无需再等待下一个 5 秒周期同步,进房即可获得与房主一致的位置计算。
  • 新增「火车队列」与「身前怀抱」两种悬挂位置:
    • Carry Position(悬挂位置)新增第五种「火车队列(人体蜈蚣式)」:乘客在背人者正后方一字排开,第 1 人贴背(0.5m),其后每人往后递增 0.5m,形成直线队列,朝向跟随背人者。
    • 新增第六种「身前怀抱」:乘客在背人者正前方左右对称铺开(第 1 人居中,多人左右交替展开,间距 0.5m),脸朝背人者(180° 反转,面对面)。
    • 两种模式高度均由「背起垂直高度」配置控制,均天然适配多人(最多 20 人)。
    • 配置同步 int 映射扩展:背上=0 / 头顶上=1 / 环绕飞行=2 / 垂直背起=3 / 火车队列=4 / 身前怀抱=5。
  • 「最大背负数量」新增「不限制」档位,并适配多人位置排布:
    • Max Carry Count(最大背负数量)可调范围由 1~5 扩为 1~6,其中 6 = 不限制(实际最多 20 人,即游戏人数上限)。
    • EffectiveMaxCarryCount() / EffectiveHostMaxCarryCount() 在值 >= 6 时返回 20(避免用 int.MaxValue 引发潜在索引问题),所有数量上限检查点自动适配。
    • 背上模式圆弧参数改为随人数自适应:张角从 2 人 70° 逐步张开至最多 180°,半径从 0.52m 增长到 2.0m,避免多人重叠。
    • 头顶上(向上堆叠)、环绕飞行(360° 等分)、垂直背起(左右对称)三种模式本身对多人天然自适应,无需额外处理。
  • 新增「垂直背起」悬挂位置(左右一字排开):
    • Carry Position(悬挂位置)新增第四种「垂直背起」:乘客在头顶基准高度(由「背起垂直高度」配置控制)沿左右水平一字排开,居中对称分布——第 1 人在正中间,之后交替向右、向左对称铺开,左右间距与叠罗汉间距一致(0.5m)。
    • 所有人同一高度、不叠加,朝向跟随背人者(脸朝其面对方向)。
    • 配置同步 int 映射扩展:背上=0 / 头顶上=1 / 环绕飞行=2 / 垂直背起=3。
  • 头顶上叠罗汉间距减半:stackHeight 由 1.0m 调整为 0.5m,被背者之间更紧凑。
  • 新增「按 X 一键背起附近所有玩家」:
    • 按下 X 键,自动背起以自己为中心、半径 10 米内的所有存活可背队友(按距离从近到远依次背起,最多受「最大背负数量」上限约束)。
    • 自动排除自己、已死亡、已 disabled(非翻滚)、已在任何人背上的玩家;单次按键触发(避免按住期间重复发送网络事件)。
    • 房主路径走 ProcessCarryTransfer 权威处理(自带上限与重复校验),客机路径走 SendCarryEventToHost 请求房主;房主未装模组时提示。
    • 注:原拟用 T 键,但游戏默认将 T 绑定为聊天(Chat),会冲突,故改用空闲的 X 键。
  • 统一「背起垂直高度」配置(对所有悬挂位置生效),并放大可调范围:
    • 删除原先两个高度配置项(背上专用的 Carry Height Offset 被背起挂载高度、头顶/环绕专用的 Head Top Height 头顶/环绕基准高度),合并为单一配置项 Carry Height(背起垂直高度)。
    • 新配置项对所有三种悬挂位置(背上 / 头顶上 / 环绕飞行)统一生效,从背人者中心竖直向上计算挂载高度,默认 3.8m。
    • 可调范围由原先的 0.1~2.0 / 1.0~8.0 统一放大为 0.1~20.0,方便自由调节高度。
    • 配置同步包由 6 元素精简为 5 元素(移除已废弃的 CarryHeightOffset,保留统一的 CarryHeight),接收端用 data.Length >= 5 向后兼容。
  • 修复配置同步致命 bug(P0):
    • 配置同步包扩展为 5 元素后,接收端仍用 data[3] 读取 actionType,而 actionType=7 实际在 data[4](data[3] 已变成 CarryPosition),导致 actionType==7 永远不成立,房主的"最大背负数量""悬挂位置"等配置完全无法同步到客机。
    • 现改为读取数组最后一个元素 data[data.Length-1],同时兼容 4 元素普通事件与 5 元素配置同步;并补齐 CarryPosition 三枚举值解析(背上/头顶上/环绕飞行)。
  • 修复配置同步致命 bug(P0):
    • 配置同步包扩展为 5 元素后,接收端仍用 data[3] 读取 actionType,而 actionType=7 实际在 data[4](data[3] 已变成 CarryPosition),导致 actionType==7 永远不成立,房主的"最大背负数量""悬挂位置"等配置完全无法同步到客机。
    • 现改为读取数组最后一个元素 data[data.Length-1],同时兼容 4 元素普通事件与 5 元素配置同步;并补齐 CarryPosition 三枚举值解析(背上/头顶上/环绕飞行)。
  • 最大背负数量调整为 5,默认 5,两种模式统一受此数量控制:
    • Max Carry Count(最大背负数量)默认值由 1 改为 5,可调范围由 1~3 扩到 1~5。
    • 头顶上模式不再"无人数限制"(原为 int.MaxValue),改为与背上模式一样统一受"最大背负数量"配置控制。
    • 背上模式改为真正的圆弧排布:乘客沿以背人者正后方为弧心的一段圆弧从左到右均匀铺开(用三角函数计算,人数越多包裹张角越大),支持 1~5 人,不再出现位置重叠。
  • 新增"悬挂位置"配置开关(背上 / 头顶上):
    • 新增 Carry Position(悬挂位置)配置项,由房主控制并同步到所有客机。
    • 背上:沿用原有挂载方式,乘客挂在背人者正后方(0.45m)并沿圆弧铺开。
    • 头顶上(默认):乘客从背人者头顶正中心垂直向上逐个堆叠,每多一人向上叠加 1.0m,朝向跟随背人者(脸朝背人者面对方向)。
    • 环绕飞行(卫星环):所有乘客绕背人者竖直轴水平环绕、固定不旋转,按上车顺序等角度均匀分布(第 1 人在正后方不挡前方视野,其余逆时针依次环绕成"后→右→前→左"顺序),只有人数变化时才重新排布;所有乘客脸朝外(背离背人者)。
    • 统一抽取 CalcCarryPose 方法计算挂载坐标/朝向,被背者自算、背人者算乘客、分布式死人头牵引三处共用,杜绝逻辑分叉。
  • 加固 HurtCollider.PlayerHurt 伤害拦截 Patch(P0):
    • PlayerHurt 是游戏 private 方法,按名字 Patch 无编译期保障。游戏更新(重命名/改参/改重载)会导致 Patch 静默失效,房主被背时高速撞飞队友的伤害拦截形同虚设。
    • 现于模组加载时用反射断言方法签名(参数必须为单个 PlayerAvatar 且返回 void),校验通过才启用拦截;校验失败立即输出错误日志并安全禁用该拦截,杜绝静默失效。
  • 修复乘客刚体 isKinematic 与游戏原版每帧重写的竞态(P0):
    • 游戏 PlayerTumble.Update 每帧根据 isTumbling 状态重写 rb.isKinematic,乘客被背时处于 isTumbling=true,原版每帧把刚体设回非 kinematic,与模组在 LateUpdate 里的锁定形成每帧拉锯,存在物理撕裂风险。
    • 现新增 PlayerTumble.Update 的 Postfix,在原版逻辑执行完毕后立即对被背乘客的刚体强制锁回 kinematic,时序优于 LateUpdate,从根本上消除拉锯。
  • 新增被背乘客碰撞体 isTrigger 残留兜底(P1):
    • 被背乘客的 Collider 会被设为 isTrigger=true,正常放下/清理路径会恢复;但玩家掉线、崩溃或游戏异常退出时可能永久残留,导致该玩家永久穿墙/穿物。
    • 现新增 OnApplicationQuit 强制恢复所有记录在案的 trigger 碰撞体,并每 5 秒扫描一次 CarryTriggerColliders 中已不在 ActiveCarries 的孤儿条目并自动恢复,杜绝残留。
  • 收敛 SetPassengerTumbleOverrideTime 的双路径强写(P1):
    • 原实现同时做"本地强写 private 字段" + "RPC 发 Master",两条路径无互斥。
    • 经排查,游戏源码中非 MasterClient 端在 PlayerTumble.Update 会提前 return,本地强写对非 Master 端无效。现收敛为:本地即权威端(Master + 本地乘客)时本地强写立即生效,否则走官方 RPC 由 Master 权威端设置,消除冗余与两端不一致隐患。

1.0.3

  • 彻底解决“一个人同时背起两个人”或“两人循环互背套娃”的 Bug:
    • 在背人/请求被背指令的最开始位置引入了双向互斥验证。若检测到参与背人的任何一方(司机/乘客)已经存在于全网背人记录中,则直接静默拦截并清空读条,防范多重挂载。
    • 在 Master Client 同步机制和客户端发送事件瞬间,引入了本地状态占位锁定,完全消除了由于网络高延迟(RTT)并发连点造成的双重背人/冲突背人。
  • 解决由于联机解绑广播导致“无关玩家同时被强制下车”的致命 Bug:
    • 修复了 HandleCarryAction 在收到释放动作(actionType 2)时,误将 _isCarrying 和 _isBeingCarried 作为通用状态判定,从而导致场上任何一处解绑发生都会强制将所有其他正在背人的无辜玩家同时强制放下的严重 Bug。现改为仅针对当前广播对应 ViewID 的具体玩家进行精确状态解绑与重置。
  • 彻底消除被背乘客高速移动时的“滋滋”摩擦风噪声:
    • 针对被背起玩家(如主机)处于 isTumbling 倒地状态高速移动时,会频繁触发游戏原生 PlayerCollisionController 中代表坠落风噪声的 soundFallLoop 现象,在本地 LateUpdate 中对其每一帧调用 OverrideDisableFallLoop(0.2f) 强行阻断。彻底去除了在高速移动时耳机里传来的烦人风噪“滋滋”声。
  • 物理碰撞 OnCollisionStay 高频查找性能缓存优化:
    • 针对在 PhysGrabObjectImpactDetector.OnCollisionStay 碰撞静音拦截中高频调用 GetComponentInParent 造成的 CPU 开销,引入了 DetectorTumbleCache 和 DetectorHeadCache 静态缓存字典。利用碰撞检测器 InstanceID 做 O(1) 静态查表,完美规避了每帧碰撞时向上遍历组件的性能负担,且场景重载时自动清理。
  • 跨场景数据残留与内存泄漏修复:
    • 注册了 SceneManager.sceneLoaded 监听,在重开或切换地图时强制执行 ResetState(),自动清空所有全局缓存字典与延迟碰撞恢复队列(PendingRestores),确保跨场景内存干净,杜绝网络幽灵残留。
  • 被背尸体(死人头)复活瞬间自动下车解绑:
    • 在 UpdateCarryLogic 检测中,加入了对 _myCarriedHead.playerAvatar 存活状态的即时扫描。一旦检测到被背的死尸头部玩家已被复活,立刻强制执行解绑,无需等待 3 秒轮询,做到复活下车毫秒级顺发响应。
  • 启用与优化分布式死人头物理拉扯(主客机物理牵引效果完全对齐):
    • 激活了原本未在底层调用的 ExecuteDistributedHeadCarryDummy 分布式辅助物理同步。当死尸头部的物理所有权拥有者(如死亡玩家自身)检测到自己被背起时,由所有权端直接模拟拉扯并向全网同步物理,防止由于 Photon 所有权转移延迟导致非主客机看到的牵引、摆动不同步问题。
    • 在计算中加入了 !_isCarrying 保护拦截,规避了背人者自身客户端重复计算物理受力的 Bug。
  • 新增多乘客背负散开定位与房主参数强同步:
    • 重新调整多人背负的空间对齐排布,背负 2 人和 3 人时由原先的直线平铺修改为带包裹感的“半径圆弧排布”(左右侧人偏前侧,中间人偏后侧),拉近乘客间距,使视觉效果更加贴合协调。
    • 房主设定的最大承载上限(Max Carry Count)与挂载垂直高度(CarryHeightOffset)在多人联机时自动强同步至所有安装了模组的好友客户端,解决多端视角分歧和乘客抖动,下车长按读条时间仍保留由各自本地配置决定。
    • 修复多人同时下车时,由于注销顺序与字典移除顺序冲突导致除一人落于身前、其余两人传送回最初被背起起点的问题。现在按照下车乘客索引安全地在司机后方左右侧分散落下,并强制刷新网络插值缓存,杜绝原地闪回。
  • 纯净版(无模组)玩家背负体验全面自愈与修复:
    • 彻底攻克未装模组的乘客在背上按空格意外起立、被放下后必定瞬移回原起点的原版同步 Bug。
    • 背人者或主机本地每 0.1 秒轮询并检测乘客起立状态,一旦非模组乘客意外起立,自动通过 TumbleRequest 强行将其击倒以维持布娃娃状态;下车瞬间调用原版底层 PhysGrabObject.Teleport 同步物理瞬间移动,强制覆盖无模组玩家本地的刚体坐标,保证其在下车点稳妥站立。
  • 手持道具下车与加血复活卡死漏洞修复:
    • 移除被背起下车时的“手持物品限制”。现在玩家手持加血注射器、药包等任何道具时,依然可以长按 E 或 R 正常下车。
    • 修复了被背乘客在被队友长按加血扶起(Revive)后,其背负状态仍残留在网络字典中,导致起身瞬间立刻被吸回背上并锁死控制的 Bug。现通过 Harmony 拦截 ReviveRPC,在任何加血复活发生时,瞬间在全端完全重置并清空该玩家的背负缓存并恢复控制器。
  • 完美适配中途加入(LateJoinNow)模组与稳定性保障:
    • 对 PlayerAvatar.Start 与 PlayerAvatar.ReviveRPC 的 Postfix 补丁增设了绝对安全的 try-catch 保护外壳以及 ViewID <= 0 早期未就绪状态检测,完全避免了中途加入玩家由于网络组件未就绪而抛出异常打断进房流程,实现了对中途加入模组和无模组环境的完美双向适配。
  • 默认配置参数微调:
    • 将默认的最大背负人数限制由 3 微调为更为克制和符合原版大厅体验的 1(房主依然可以通过配置文件随时改回最多 3 人)。
  • 彻底取消背起时的手持道具与物理抓人限制:
    • 在 E/R 键上车长按判定中完全移除了 isLocalHolding 和 isTargetHolding。无论背人者还是被背者手中是否持有手电筒、针剂、电磁铁等任意手持道具,或司机是否正在物理抓取拖拽队友的身体,均可以直接长按交互背起(背负成功后系统自动释放物理抓握,杜绝卡死或粘连)。
  • 支持对倒地(Downed)的队友进行对准交互背起:
    • 针对游戏在玩家被击倒(Downed)时会将 isDisabled 设为 true 的机制,在射线碰撞检测与角度配对列表筛选中,增加了对倒地布娃娃(Tumble)状态的特许放行。解决了对准躺在地上的倒地队友按住 E 毫无反应、无法触发背人读条的顽疾。
    • 在离线清理 CleanupOfflineCarries 循环中同步加上了倒地状态下的离线放行保护,避免正常被背着的倒地队友由于 isDisabled 状态被意外从背上卸载。
  • 修复客机配置转型 InvalidCastException 导致最大载人数无法同步的致命网络 Bug:
    • 修正了客机在大厅同步房主配置数据包(类型 7)时,因直接强转装箱 float 数据类型导致 C# 抛出 InvalidCastException 异常并打断后续逻辑的漏洞。
    • 现改用 Convert 进行安全数据转型,确保房主设定的最大背人上限(如最多 3 人)与高度偏置能正确覆盖同步至所有已装模组的客机客户端,消除了“房主设了可背 3 人而客机始终只能背 1 人”的参数分歧。

1.0.1

  • 彻底解决背人时向后退(按 S 键)被后面背的人挡住、难移动的物理 Bug:
    • 问题分析:由于控制本地玩家运动的 PlayerController GameObject 与负责网络同步的 PlayerAvatar 在 GameObject 层级上物理分离。此前我们用 GetComponentsInChildren<Collider> 对两者收集碰撞体时,漏掉了本地唯一的 PlayerController.instance 上的 Capsule 物理身体碰撞体。这导致背人者本地的移动物理碰撞盒和背后挂着的布娃娃骨骼碰撞体依然在物理世界发生硬碰发生阻挡,导致后退时被乘客身体死死挡住,极难向后移动。
    • 彻底解决阻挡:在 SetCollisionIgnore 和 SetCollisionIgnoreHead 碰撞忽略控制中,额外引入了对本地 PlayerController.instance 身上所有子 Collider 碰撞体的自动合并提取。不管是司机还是乘客,在背人期间其本地 PlayerController 物理盒与对方所有的 PlayerAvatar / PlayerTumble 物理盒全部应用 IgnoreCollision 彻底忽略,后退没有任何摩擦和体积撞击阻力,行云流水!
  • 彻底解决本地乘客端物理撕裂导致的“视角偏置歪斜、拉扯卡死走不动、相机视点在原地、下车闪回原地”恶性 Bug:
    • 分离的 PlayerController 同步锁定:不仅锁死 PlayerAvatar,在本地 LateUpdate 里,只要乘客是本地玩家,同步将其分离的 PlayerController.instance.transform 及挂载的 Rigidbody 也强锁至背人者背后的位置。这彻底解决了由于 PlayerController GameObject 与 PlayerAvatar 物理分离,在被背起期间 PlayerController 仍然停留在原地,导致本地视点/相机一动不动留在原地不跟随、且在下车(放下)瞬间身体被瞬间拉回原地的恶性 Bug。
    • 无条件物理锁死:将 LateUpdate 中的乘客 Rigidbody 和 Tumble 布娃娃刚体的 kinematic 锁定及背后坐标对齐改为无条件执行(不再受 !GetPlayerIsLocal 保护)。这确保了乘客在自己本地客户端也完美跟从,两端物理彻底对齐。
    • 本地控制器与输入封锁:当本地玩家作为乘客时,在 Update 帧中强行将本地 PlayerController.enabled 设为 false,锁死刚体速度为零。在下车(HandleCarryAction)和异常重置(ResetState)瞬间重新激活还原,从源头根除了主客双端控制器的物理拉扯。
    • 屏蔽 tumble 倒地暗角与镜头拉远:在本地乘客被背起期间,通过反射强行锁定 overrideTumbleUIDisableTimer = 1.0f。这完美消除了 Tumble 滚地时产生的黑色暗角渐变和很远很奇怪的 OverrideZoomSet 焦距,使其在队友背后获得非常稳定平顺的视角。
    • 修复长按 R 无法下车进度条重置 Bug:修改了 UpdateCarryLogic 顶端的清零过滤,仅在既不背人也不被背(!_isCarrying && !_isBeingCarried)的空闲状态下才将 _releaseTimer 归零,彻底解决了此前因被背时被高频强制清零导致长按下车进度条动不了的严重 Bug。
  • 按键分流与角色状态隔离。根据本地角色状态隔离交互按键:背人者(Carrier)状态下仅支持长按 "E" 键将乘客放下;被背乘客(Passenger)状态下仅支持长按 "R" 键从背后主动挣脱下车。彻底避免了乘客在别人背后拿取地上物资或开箱交互时误触发下车判定的冲突。
  • 终极屏蔽被背乘客高频物理碰撞、连续滋滋电流声与火花特效,并加入测试版限流 Debug 日志输出:
    • 问题分析:在联机中,Unity 的 Tumble 布娃娃骨骼碰撞体状态若被游戏其他脚本(如玩家受击、倒地状态刷新)频繁重置或重新激活,会导致我们应用的 Physics.IgnoreCollision 在物理引擎内部被自动失效还原,从而令被背者与背人者发生物理重叠解穿透,触发 PhysGrabObjectImpactDetector 强烈的物理碰撞反馈与火花、连续撞击声(听上去类似滋滋的电流声)。
    • 解决方案:引入 Harmony Patch,拦截 PhysGrabObjectImpactDetector.OnCollisionStay 的前置 Prefix 执行。一旦检测到碰撞对象是正处于背负关系中的活人乘客(IsPassenger)或死人头,强制返回 false 拦截掉,彻底根绝碰撞 Stay 的发声、火花与物理效果。
    • 测试日志输出:在 HurtCollider.PlayerHurt 以及 OnCollisionStay 拦截核心处,植入了 BepInEx 测试日志输出。为保护磁盘 I/O 效率,日志输出做了每秒限流 1 条的保护,可在联机日志中清晰观察到如 [CarryFriend TestLog] 拦截并屏蔽被背乘客 X 的击飞伤害 等活跃防飞天与静音日志。
    • 名字对齐:公开了 GetPlayerName 接口,使外部 Patch 日志能够打印对齐了 MoreUI 汉化/改名模组的最真实昵称。
  • 终极拦截房主(Host)被背高速跑动时撞飞队友的 Bug:
    • 原因定位:房主(MasterClient)作为游戏世界物理的权威端,其倒地刚体的速度计算极其敏感且会作为全局判定。当房主被客机背负高速奔跑时,房主本地的布娃娃速度必然突破 4f 激活伤害检测器。虽然其他客户端本地尝试关闭了房主身上的碰撞,但由于受害检测 HurtCollider.PlayerHurt 只在受害者(背人客机)本地权威响应,导致房主本地广播的伤害直接将客机在客机本地弹飞。
    • 解决方案:引入 Harmony Patch,拦截 HurtCollider.PlayerHurt 方法的执行前置(Prefix)。在判定触发时,若伤害来源的 HurtCollider 挂载在正处于背人关系中(ActiveCarries)的被背乘客或死尸头部时,强制拦截并返回 false 跳过整个伤害与物理击退逻辑。该拦截为底层根源切断,100% 杜绝了由于房主作为世界权威触发击飞广播把人撞飞的现象。
  • 恢复死尸头部(PlayerDeathHead)的 1.0.0 原版物理牵引与所有权同步机制:
    • 彻底撤销了 kinematic 位置锁死,还原了死人头被背负时的动态布娃娃物理效果。
    • 背人者直接抢占所有权:在 FixedUpdate 中,一旦本地判定为背着死人头的背人者,便直接对死人头调用 headPv.RequestOwnership() 抢占其 Photon network 物理控制权,并在背人者本地客户端每帧执行物理速度拉扯跟随。
    • 该方案为 1.0.0 原版最稳定的物理拉扯结构,能 100% 杜绝联机客机背死人头不同步及动作僵硬脱节的问题。
  • 修复死尸头部(PlayerDeathHead)在背着走动后放下时,会瞬间被拉扯瞬移回最初背起“原地”的网络物理同步 Bug。在放下时强行使所有客户端(包括拥有死人头所有权的 Owner)重写死人头的世界坐标、速度并释放,保证在当前实时位置平滑落地。
  • 修复背起死尸头部(PlayerDeathHead)时物理碰撞穿透导致背人玩家被顶起或飞天的 Bug。背起状态下直接强行 disable 死人头身上所有的 Collider 组件(消除其体积),放下时自动 re-enable 还原,彻底根治与其他物理/辅抓模组的挤压冲突。
  • 优化背起扫描机制,加入可交互物品防误触屏蔽。当准心看着物理抓取物体(PhysGrabObject)、固定抓取件(StaticGrabObject)或任意 Item 物品时,主动退避背人扫描且不弹提示框,确保玩家拿取物资与拾取装备交互的绝对优先权。
  • 新增长按 R 键被队友背起(主动请求上车)的功能,支持本地向 3.5 米内活人队友读条请求被其背在背后,与长按 E 背起互补且完美复用物理挂载 and 网络同步通道。
  • 修复当玩家背起房主(Host)时碰撞忽略失效导致房主与玩家重叠反弹、把人弹飞的抖动 Bug。
  • 引入了每 10 帧自动周期性刷新和重新强制应用背人者与乘客之间碰撞忽略的逻辑,避免中途因 Tumble 关节碰撞体重新激活而导致忽略失效。

1.0.0

  • 模组初始发布,支持在清醒状态下长按 E 背起或放下队友,以及背起死尸头部道具。
  • 采用全新的物理挂载载人系统,队友挂载在背后偏上并转脸朝外,利用倒地(Tumble)布娃娃物理实现自然的摆动悬挂。
  • 支持被背玩家穿墙物理(自动切换 Trigger),下车或重置时自动还原。
  • 完善的无模组原版客户端兼容下车判定:
    1. 乘客按空格起立:在冷却 1.5 秒后,背人者客户端检测到乘客 isTumbling 同步变为 false,即刻在全网断开背人状态。
    2. 乘客抓背加血下车:乘客用准心指着背人者后背抓取加血包,背人者端在 Update 里进行网络同步判定,触发瞬间下车。
  • 精准的防掉线卡死检测:每 3.0 秒执行一次全局离线清理,若被背者或背人者中途退出、断连被销毁,自动复位本地状态,100% 杜绝卡死。
  • 支持背人者死亡、被怪兽击倒等异常时,自动安全释放下车。
  • 支持非主机客户端与主机的安全握手握包判定,防止房主没装引发联机冲突。