Decompiled source of PlantEasilyFix v1.2.2

plugins/PlantEasilyFix/PlantEasilyFix.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("PlantEasilyFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.2.0")]
[assembly: AssemblyInformationalVersion("1.2.2")]
[assembly: AssemblyProduct("PlantEasilyFix")]
[assembly: AssemblyTitle("PlantEasilyFix")]
[assembly: AssemblyVersion("1.2.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PlantEasilyFix
{
	[BepInPlugin("s6652289.PlantEasilyFix", "PlantEasily Fix", "1.2.2")]
	public class PlantEasilyFixPlugin : BaseUnityPlugin
	{
		public const string Guid = "s6652289.PlantEasilyFix";

		public const string Version = "1.2.2";

		internal static ManualLogSource L;

		private Harmony _harmony;

		private bool _patchedGrid;

		private bool _patchedReplant;

		private bool _gridGaveUp;

		private bool _replantGaveUp;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> VerboseLog;

		internal static ConfigEntry<bool> SameCropReplant;

		private static FieldInfo _gridVersionField;

		private static int _fixCount;

		private static FieldInfo _extraGhostsField;

		private static FieldInfo _lastUpdatedField;

		private static MethodInfo _maxActiveGhostsGetter;

		private static MethodInfo _columnsGetter;

		private static FieldInfo _modConfigInstanceField;

		private static MethodInfo _getGhostObject;

		private static MethodInfo _getGhostCache;

		private static MethodInfo _getGhostPosition;

		private static MethodInfo _updateGhostTransform;

		private static int _repositionCalls;

		private static int _repositionTotal;

		private static FieldInfo _lastSelectedField;

		private static int _replantOverrideCount;

		private void Awake()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			L = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "启用本补丁。关闭后重启游戏即等同于未安装。\nEnable this patch. Turn off and restart to disable entirely.");
			VerboseLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLog", false, "每次修正网格版本号 / 补摆幽灵时输出日志(排查问题用;正常游玩建议保持关闭)。\nLog every grid-version bump and ghost reposition (for troubleshooting; keep off for normal play).");
			SameCropReplant = ((BaseUnityPlugin)this).Config.Bind<bool>("Replant", "SameCropReplant", true, "自动补种时,按【被收获的那种作物】补种,而不是统一补成你最近选中的那一种。\n关掉 → 恢复 PlantEasily 原行为(收什么都补成你当前手持耕耘机选中的作物)。\n改动本项无需重启游戏,下一次补种立即生效。\nReplant each crop as the very crop you harvested, instead of always using the plant you last selected with the cultivator. Turn off to restore the original PlantEasily behaviour.");
			if (!Enabled.Value)
			{
				L.LogInfo((object)"已在配置中禁用,补丁未挂载。");
				return;
			}
			_harmony = new Harmony("s6652289.PlantEasilyFix");
			((MonoBehaviour)this).StartCoroutine(PatchWhenReady());
		}

		private IEnumerator PatchWhenReady()
		{
			for (int i = 0; i < 120; i++)
			{
				if (_patchedGrid && _patchedReplant)
				{
					break;
				}
				try
				{
					if (!_patchedGrid && !_gridGaveUp)
					{
						Type type = AccessTools.TypeByName("Advize_PlantEasily.GhostGrid");
						if (type != null)
						{
							PatchGrid(type);
						}
					}
					if (!_patchedReplant && !_replantGaveUp)
					{
						Type type2 = AccessTools.TypeByName("Advize_PlantEasily.PlacementState");
						if (type2 != null)
						{
							PatchReplant(type2);
						}
					}
				}
				catch (Exception ex)
				{
					L.LogError((object)("挂载补丁时异常:" + ex));
				}
				yield return (object)new WaitForSecondsRealtime(1f);
			}
			if (!_patchedGrid || !_patchedReplant)
			{
				L.LogWarning((object)string.Format("补丁挂载结果:网格幽灵坐标={0}、按作物补种={1}。未挂上的通常是「没装 PlantEasily」这一正常情况(可忽略);若已安装请检查 PlantEasily 是否加载失败或版本已变化。", _patchedGrid ? "已生效" : "未生效", _patchedReplant ? "已生效" : "未生效"));
			}
		}

		private void PatchGrid(Type ghostGrid)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(ghostGrid, "BuildGrid", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				_gridGaveUp = true;
				L.LogError((object)"找不到 GhostGrid.BuildGrid —— 补丁 1/3 未挂上(PlantEasily 版本可能已变化)");
				return;
			}
			_gridVersionField = AccessTools.Field(ghostGrid, "_gridVersion");
			if (_gridVersionField == null)
			{
				_gridGaveUp = true;
				L.LogError((object)"找不到 GhostGrid._gridVersion —— 补丁 1/3 未挂上(PlantEasily 版本可能已变化)");
				return;
			}
			ResolveRepositionHandles(ghostGrid);
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(PlantEasilyFixPlugin), "BuildGridPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_patchedGrid = true;
			if (_getGhostPosition != null && _updateGhostTransform != null && _lastUpdatedField != null)
			{
				L.LogInfo((object)"补丁 1/3 已生效:网格重建后强制刷新幽灵坐标,并当场补摆全部网格格位(避免大网格下部分幽灵叠在同一点)。");
			}
			else
			{
				L.LogInfo((object)"补丁 1/3 已生效:网格重建后强制刷新幽灵坐标。(补摆所需的 PlantEasily 内部方法未全部找到,大网格补摆已降级关闭;若仍出现重叠请回报版本号。)");
			}
		}

		private static bool RequireArity(MethodInfo method, int expected, bool hasInstance, string label)
		{
			if (method == null)
			{
				L.LogWarning((object)("补摆降级:未找到 " + label));
				return false;
			}
			int num = method.GetParameters().Length;
			if (num != expected)
			{
				L.LogError((object)$"补摆降级:{label} 的参数个数不符 —— PlantEasily 给的是 {num} 个,本补丁按 {expected} 个调用;继续调用会抛 TargetParameterCountException 并被静默吞掉。已停用大网格补摆(补丁 1/2 不受影响)。请把 PlantEasily 版本号回报给补丁作者。");
				return false;
			}
			if (!method.IsStatic && !hasInstance)
			{
				L.LogError((object)$"补摆降级:{label} 是**实例**成员,但调用时没有 target 实例;继续调用会抛 TargetException(Non-static method requires a target.)并被静默吞掉。已停用大网格补摆(补丁 1/2 不受影响)。请把 PlantEasily 版本号回报给补丁作者。");
				return false;
			}
			return true;
		}

		private static void ResolveRepositionHandles(Type ghostGrid)
		{
			try
			{
				_extraGhostsField = AccessTools.Field(ghostGrid, "ExtraGhosts");
				if (_extraGhostsField == null)
				{
					L.LogWarning((object)"补摆降级:未找到 GhostGrid.ExtraGhosts");
				}
				_maxActiveGhostsGetter = AccessTools.PropertyGetter(ghostGrid, "MaxActiveGhosts");
				if (_maxActiveGhostsGetter == null)
				{
					_maxActiveGhostsGetter = AccessTools.Method(ghostGrid, "get_MaxActiveGhosts", (Type[])null, (Type[])null);
				}
				if (!RequireArity(_maxActiveGhostsGetter, 0, hasInstance: false, "GhostGrid.MaxActiveGhosts"))
				{
					_maxActiveGhostsGetter = null;
				}
				Type type = AccessTools.TypeByName("Advize_PlantEasily.ModContext");
				if (type != null)
				{
					_modConfigInstanceField = AccessTools.Field(type, "config");
				}
				if (_modConfigInstanceField == null)
				{
					L.LogWarning((object)"补摆降级:未找到 ModContext.config(拿不到 ModConfig 实例)");
				}
				Type type2 = AccessTools.TypeByName("Advize_PlantEasily.ModConfig");
				if (type2 != null)
				{
					_columnsGetter = AccessTools.PropertyGetter(type2, "Columns");
				}
				if (!RequireArity(_columnsGetter, 0, _modConfigInstanceField != null, "ModConfig.Columns"))
				{
					_columnsGetter = null;
				}
				_getGhostObject = AccessTools.Method(ghostGrid, "GetGhostObject", (Type[])null, (Type[])null);
				if (!RequireArity(_getGhostObject, 1, hasInstance: false, "GhostGrid.GetGhostObject"))
				{
					_getGhostObject = null;
				}
				_getGhostCache = AccessTools.Method(ghostGrid, "GetGhostCache", (Type[])null, (Type[])null);
				if (!RequireArity(_getGhostCache, 1, hasInstance: false, "GhostGrid.GetGhostCache"))
				{
					_getGhostCache = null;
				}
				_getGhostPosition = AccessTools.Method(ghostGrid, "GetGhostPosition", (Type[])null, (Type[])null);
				if (!RequireArity(_getGhostPosition, 3, hasInstance: false, "GhostGrid.GetGhostPosition"))
				{
					_getGhostPosition = null;
				}
				_updateGhostTransform = AccessTools.Method(ghostGrid, "UpdateGhostTransform", (Type[])null, (Type[])null);
				if (!RequireArity(_updateGhostTransform, 2, hasInstance: false, "GhostGrid.UpdateGhostTransform"))
				{
					_updateGhostTransform = null;
				}
				Type type3 = AccessTools.TypeByName("Advize_PlantEasily.GhostCache");
				if (type3 != null)
				{
					_lastUpdatedField = AccessTools.Field(type3, "lastUpdatedVersion");
				}
				if (_lastUpdatedField == null)
				{
					L.LogWarning((object)"补摆降级:未找到 GhostCache.lastUpdatedVersion");
				}
			}
			catch (Exception ex)
			{
				L.LogError((object)("解析补摆所需的 PlantEasily 成员时异常(补摆将降级关闭):" + ex.Message));
			}
		}

		internal static void BuildGridPostfix()
		{
			try
			{
				if (_gridVersionField == null)
				{
					return;
				}
				int num = (int)_gridVersionField.GetValue(null);
				_gridVersionField.SetValue(null, num + 1);
				_fixCount++;
				if (VerboseLog != null && VerboseLog.Value)
				{
					L.LogInfo((object)$"[修复 {_fixCount}] BuildGrid → _gridVersion {num} → {num + 1}(幽灵坐标缓存已失效)");
				}
			}
			catch (Exception ex)
			{
				L.LogError((object)("修正网格版本号失败(本次不影响游戏,重叠可能复现):" + ex.Message));
			}
			RepositionAllGhosts(_fixCount.ToString());
		}

		private static void RepositionAllGhosts(string tag)
		{
			if (_getGhostPosition == null || _updateGhostTransform == null || _lastUpdatedField == null || _getGhostObject == null || _getGhostCache == null || _maxActiveGhostsGetter == null || _columnsGetter == null || _modConfigInstanceField == null)
			{
				return;
			}
			try
			{
				object value = _modConfigInstanceField.GetValue(null);
				if (value == null)
				{
					return;
				}
				int num = (int)_maxActiveGhostsGetter.Invoke(null, null);
				int num2 = (int)_columnsGetter.Invoke(value, null);
				if (num <= 0 || num2 <= 0)
				{
					return;
				}
				int num3 = ((_gridVersionField != null) ? ((int)_gridVersionField.GetValue(null)) : 0);
				int num4 = 0;
				int num5 = 0;
				for (int i = 1; i <= num; i++)
				{
					object? obj = _getGhostObject.Invoke(null, new object[1] { i });
					GameObject val = (GameObject)((obj is GameObject) ? obj : null);
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					int num6 = i / num2;
					int num7 = i % num2;
					object obj2 = _getGhostPosition.Invoke(null, new object[3] { num6, num7, i });
					if (obj2 != null)
					{
						_updateGhostTransform.Invoke(null, new object[2] { val, obj2 });
						num4++;
						object obj3 = _getGhostCache.Invoke(null, new object[1] { val });
						if (obj3 != null)
						{
							_lastUpdatedField.SetValue(obj3, num3);
							num5++;
						}
					}
				}
				_repositionTotal += num4;
				_repositionCalls++;
				if (_repositionCalls == 1 || (VerboseLog != null && VerboseLog.Value))
				{
					L.LogInfo((object)$"[补摆 {tag}] 网格 {num + 1} 格(MaxActiveGhosts={num}, Columns={num2})→ 已摆正 {num4} 个幽灵、同步 {num5} 个坐标缓存;累计补摆 {_repositionCalls} 次 / {_repositionTotal} 个。");
				}
			}
			catch (Exception ex)
			{
				L.LogError((object)("补摆幽灵坐标失败(本次退回原分批节奏,重叠可能复现):" + ex.Message));
			}
		}

		private void PatchReplant(Type placementState)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(placementState, "SetReferences", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				_replantGaveUp = true;
				L.LogError((object)"找不到 PlacementState.SetReferences —— 补丁 2 未挂上(PlantEasily 版本可能已变化)");
				return;
			}
			_lastSelectedField = AccessTools.Field(placementState, "LastSelectedPlantName");
			if (_lastSelectedField == null)
			{
				_replantGaveUp = true;
				L.LogError((object)"找不到 PlacementState.LastSelectedPlantName —— 补丁 2 未挂上(PlantEasily 版本可能已变化)");
			}
			else
			{
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(PlantEasilyFixPlugin), "SetReferencesPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_patchedReplant = true;
				L.LogInfo((object)"补丁 2/3 已生效:自动补种将按【被收获的那种作物】进行(原行为是统一补成最近选中的那一种)。");
			}
		}

		internal static void SetReferencesPostfix()
		{
			try
			{
				if ((SameCropReplant != null && !SameCropReplant.Value) || _lastSelectedField == null)
				{
					return;
				}
				object value = _lastSelectedField.GetValue(null);
				if (value != null)
				{
					_lastSelectedField.SetValue(null, null);
					_replantOverrideCount++;
					if (_replantOverrideCount == 1)
					{
						L.LogInfo((object)$"首次拦截成功:LastSelectedPlantName「{value}」→ 置空,此后补种按实际收获的作物进行。");
					}
					else if (VerboseLog != null && VerboseLog.Value)
					{
						L.LogInfo((object)$"[补种修正 {_replantOverrideCount}] LastSelectedPlantName「{value}」→ 置空");
					}
				}
			}
			catch (Exception ex)
			{
				L.LogError((object)("压制补种覆盖失败(本次补种可能仍沿用原行为):" + ex.Message));
			}
		}
	}
}