Valheim
You are viewing a potentially older version of this package. View Latest Version
Install with App

Details

Date Uploaded
4 weeks ago
Downloads
1.9K
Size
16KB
ADDatHost Valheim hosting
30% off

PlantEasily Fix

给 Advize-PlantEasily 打的两个行为修正补丁(纯客户端,不改写 PlantEasily 任何文件):

# 修什么 一句话
1 重叠种植 网格种植时整片作物全部叠在同一个点 → 摆正
2 自动补种 收什么都补成同一种 → 改成每种作物各补各的
项 值
适用模组 Advize-PlantEasily 2.2.0(2.0.0+ 逻辑相同,理论通用)
本补丁版本 1.1.0
前置 BepInEx 5.4.2333+
类型 客户端补丁(单人 / 联机客户端皆可,主机无需安装)
依赖 无(未安装 PlantEasily 时静默不做事)

补丁 1 · 重叠种植

症状

用 PlantEasily 一次种一片时,整片作物全部叠在同一个点上。 实测:4×4 = 15 个额外幽灵,坐标完全相同。

例(修复前的探针日志):

ghost[0..14] 全部 pos = (2062.731, 49.423, -4402.94)
不同坐标数 = 1 / 15
落点 1..15  全部 pos = (2062.731, 49.423, -4402.94)

根因

作者代码里有两处设计撞在一起:

① GhostGrid.InitializeGhosts 先把所有幽灵叠在一点

// 重建网格时,每个额外幽灵的位置被直接设成「主幽灵位置」
ExtraGhosts[i].transform.position = 主幽灵位置;

② 真正摆开坐标靠 GhostGrid.Update,但它有脏检查会早退

// GhostGrid.UpdateGhost
if (cache.lastUpdatedVersion == _gridVersion)
    return;                      // ← 判定"已是最新",直接返回,不更新位置

③ 而 GhostCache.Init 不重置 lastUpdatedVersion

// GhostCache.Init —— 只设 piece / plant
this.piece = go.GetComponent<Piece>();
this.plant = go.GetComponent<Plant>();
// ★ 没有重置 lastUpdatedVersion ★

④ 触发点在批量种植协程的末尾

// <BulkPlanting>d__10.MoveNext 尾部(IL 偏移 +0389 起)
_isPlanting = false;
Player.SetupPlacementGhost();      // ← 重建幽灵网格
ReEnableRenderers(...);

SetupPlacementGhost → BuildGrid → GrowPoolIfNeeded(复用旧幽灵池)+ InitializeGhosts ⇒ 位置被重设为"全叠住",而复用幽灵身上残留的 lastUpdatedVersion 仍等于当前 _gridVersion ⇒ 下一帧 UpdateGhost 全部早退 ⇒ 位置永远停在"全叠住"状态。

修复方式

在 GhostGrid.BuildGrid 之后让版本号 +1:

[HarmonyPostfix]
static void BuildGridPostfix()
{
    int before = (int)_gridVersionField.GetValue(null);
    _gridVersionField.SetValue(null, before + 1);   // 让所有幽灵缓存失效
}

所有幽灵的缓存立即失效 ⇒ 下一帧 GhostGrid.Update 必定重算每个幽灵的网格坐标 ⇒ 玩家点击种植时幽灵已经摆正。

_gridVersion 是 private static int,只有 UpdateGridVersion() 会写它, 且该函数只会 +1 或保持不变、绝不回退,所以外部 +1 不破坏其单调性。 全局搜索确认它是纯模组内部使用(readonly 初始化 + 两处使用),无跨模组引用。

修复效果(探针实测,同一台机器)

修复前 修复后
幽灵不同坐标数 1 / 15 15 / 15
落点坐标 15 个完全相同 15 个各不相同

修复后日志(探针版):

[修复] BuildGrid 完成 → _gridVersion 340 → 341
[诊断] Update 后已恢复正常:15 个幽灵分布到 15 种不同坐标 —— 修复生效

连续 88 次网格重建(含多次种植)全部正常。


补丁 2 · 自动补种按「被收获的那种作物」

症状

开着 [Harvesting]ReplantOnHarvest 时,收任何作物都补种成"你最近用耕耘机选中的那一种"。 于是混种地块越收越单一:今天最后种的是胡萝卜,明天收大麦、收萝卜,全给你补胡萝卜。

根因(InteractPatches.Prefix 第二重载的 IL 逐条实证)

IL 偏移 逻辑
003D–0042 读 PlacementState.LastSelectedPlantName 并 IsNullOrEmpty
0049 非空 ⇒ 查表键 = LastSelectedPlantName ← ★统一补种走这条
0050 为空 ⇒ 查表键 = Utils.GetPrefabName(被收获物) ← 各补各的走这条
005C ReplantDB.Registry.TryGetValue(键, out db),失败 ⇒ 不补种(交回原版)
006C ModContext.PrefabRefs.TryGetValue(db.PlantName, out Piece)
0090 Player.HaveRequirements / m_noPlacementCost 检查
00A6 PlacementController.PlacePiece(localPlayer, 被收获物, Plant.prefab)
00C6 Player.ConsumeResources

LastSelectedPlantName 的唯一写点是 PlacementState.SetReferences (方法开头先置 null,仅当幽灵身上有 Plant 组件时才重新赋值), 而它的唯一调用者是 GhostGrid.InitializeGhosts ⇒ 只要种过一次某种作物,这个值就长期留着"那一种"。

该字段的读取点只有两处(已用全程序集成员反查确认,非推测):

  1. InteractPatches.Prefix —— 决定补种哪一种;
  2. HoverTextPatches.Postfix —— 拼悬停提示 Replant as: X。

两处都带 IsNullOrEmpty 分支,空值是合法状态(该字段在 .cctor 里初始就是 null) ⇒ 把它压制为 null 只会让两边都退回"按被收获物"分支,没有别的副作用。

顺带一提:ReplantDB.Registry 里同时登记了 Pickable 名与 Plant 名两套键 (ModInitPatches.Prefix 里 Registry.Add(pickable.name, db)), 所以"按被收获物查表"这条路本来就是通的 —— 只是被上面那个非空值挡住了。

修复方式

[HarmonyPostfix]
static void SetReferencesPostfix()
{
    if (LastSelectedPlantName == null) return;       // 本来就是空,不动
    LastSelectedPlantName = null;                    // 让它退回"按被收获物"分支
}

怎么自己在游戏里验证

  1. 看提示:悬停一株成熟作物,hover 文本会多一行 Replant as: <绿>X</绿> —— X 就是本次实际会补种的那种。修复后收大麦应显示大麦,收胡萝卜应显示胡萝卜。
  2. 看日志:BepInEx/LogOutput.log 里会出现 首次拦截成功:LastSelectedPlantName「…」→ 置空,此后补种按实际收获的作物进行。
  3. 想对比原行为:把 [Replant] SameCropReplant 改成 false,不用重启游戏, 下一次补种立刻恢复"统一成一种"。

配置

首次运行会在 BepInEx/config/s6652289.PlantEasilyFix.cfg 生成:

项 默认 说明
[General] Enabled true 总开关。关掉并重启即等同于未安装
[General] VerboseLog false 每次修正写一行日志(排查用)。正常游玩建议关闭
[Replant] SameCropReplant true 补种是否按「被收获的那种作物」。改完立即生效,无需重启

安装

手动:把 PlantEasilyFix.dll 放进 BepInEx/plugins/。

r2modman:直接拖入本 zip,或把整个包放进 %APPDATA%\r2modmanPlus-local\Valheim\profiles\<profile>\BepInEx\plugins\PlantEasilyFix\。


安全性

  • 补丁 1 只动一个 int 版本号,补丁 2 只置一个静态字符串为 null —— 不碰位置、资源、存档数据;
  • 不修改 PlantEasily 的任何配置项,无需改 advize.PlantEasily.cfg;
  • 未安装 PlantEasily 时,本插件等 2 分钟后静默退出,不做任何事;
  • 所有反射调用都包在 try/catch 里 —— 补丁自身出问题最多是"这一次没修到", 不会让游戏崩溃;
  • PlantEasily 版本变化导致方法/字段找不到时,只记一条 Error 并放弃该条补丁,不影响游戏;
  • 两条补丁互相独立:某一条挂不上不影响另一条。

卸载

删掉 PlantEasilyFix.dll 即可。没有任何持久化改动需要还原(配置项只影响本插件自身)。


备注

  • 本补丁是给第三方模组打的行为修正,不改写 PlantEasily 的文件; PlantEasily 作者一旦自行修复,本补丁可直接卸载。
  • 与其它补丁/模组无冲突:只挂两个 postfix(GhostGrid.BuildGrid、 PlacementState.SetReferences),都不改原方法返回值。

AI 生成(AI-generated)

Thunderstore development is made possible with ads. Please consider making an exception to your adblock.