using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using OniroDev.Patches; using Unity.Collections; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("WeedKillerAdjuster")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("WeedKiller Adjuster - Ported to v81")] [assembly: AssemblyFileVersion("2.0.0.0")] [assembly: AssemblyInformationalVersion("2.0.0")] [assembly: AssemblyProduct("WeedKillerAdjuster")] [assembly: AssemblyTitle("WeedKillerAdjuster")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 OniroDev { [BepInPlugin("OniroDev.WeedKillerAdjuster", "WeedKillerAdjuster", "2.0.0")] public class WeedKillerAdjusterBase : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("OniroDev.WeedKillerAdjuster"); public static WeedKillerAdjusterBase Instance { get; private set; } private void Awake() { Instance = this; WeedKillerAdjusterLogger.Initialize("OniroDev.WeedKillerAdjuster"); WeedKillerAdjusterLogger.Log("WeedKillerAdjuster starting up (OniroDev.WeedKillerAdjuster)"); new WeedKillerConfig(((BaseUnityPlugin)this).Config); WeedKillerAdjusterLogger.Log("Applying patches..."); _harmony.PatchAll(typeof(WeedKillerPatch)); _harmony.PatchAll(typeof(WeedKillerConfig)); WeedKillerAdjusterLogger.Log("Patches applied successfully."); } } internal static class PluginInfo { internal const string PLUGIN_GUID = "OniroDev.WeedKillerAdjuster"; internal const string PLUGIN_NAME = "WeedKillerAdjuster"; internal const string PLUGIN_VERSION = "2.0.0"; } public static class WeedKillerAdjusterLogger { private static ManualLogSource _logSource; public static void Initialize(string pluginGUID) { _logSource = Logger.CreateLogSource(pluginGUID); } public static void Log(object message) { ManualLogSource logSource = _logSource; if (logSource != null) { logSource.LogInfo(message); } } public static void LogWarning(object message) { ManualLogSource logSource = _logSource; if (logSource != null) { logSource.LogWarning(message); } } public static void LogError(object message) { ManualLogSource logSource = _logSource; if (logSource != null) { logSource.LogError(message); } } } public class WeedKillerConfig { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnRequestSync; public static HandleNamedMessageDelegate <1>__OnReceiveSync; } public static ConfigEntry weedKillRate; public static ConfigEntry weedKillTank; public static ConfigEntry usesBattery; private static WeedKillerConfig _default; private static WeedKillerConfig _synced; private float _killRate; private float _killTank; private bool _battery; public static bool IsSynced { get; private set; } private static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager; private static bool IsHost => NetworkManager.Singleton.IsHost; private static bool IsClient => NetworkManager.Singleton.IsClient; public WeedKillerConfig(ConfigFile configFile) { configFile.SaveOnConfigSet = false; weedKillRate = configFile.Bind("Weed Killer Settings", "Vain Shroud Kill Rate", 1f, "Multiplier for kill rate of Vain Shrouds. Set to 7 to kill them 7x faster than normal."); weedKillTank = configFile.Bind("Weed Killer Settings", "Weed Killer Base Fuel Tank", 1f, "Multiplier for fuel tank capacity. Set to 7 for 7x more spray fuel."); usesBattery = configFile.Bind("Weed Killer Settings", "Use Battery Charges", false, "When true, the weed killer uses battery charges and can be recharged on the ship. When enabled, the Fuel Tank multiplier is ignored."); ClearOrphanedEntries(configFile); configFile.Save(); configFile.SaveOnConfigSet = true; _default = this; _synced = this; SnapshotFromConfig(); WeedKillerAdjusterLogger.Log($"Config loaded — killRate={weedKillRate.Value}, killTank={weedKillTank.Value}, battery={usesBattery.Value}"); } private void SnapshotFromConfig() { _killRate = weedKillRate.Value; _killTank = weedKillTank.Value; _battery = usesBattery.Value; } private static byte[] Serialize(WeedKillerConfig cfg) { byte[] array = new byte[9]; Buffer.BlockCopy(BitConverter.GetBytes(cfg._killRate), 0, array, 0, 4); Buffer.BlockCopy(BitConverter.GetBytes(cfg._killTank), 0, array, 4, 4); array[8] = (byte)(cfg._battery ? 1 : 0); return array; } private static WeedKillerConfig Deserialize(byte[] data) { return new WeedKillerConfig { _killRate = BitConverter.ToSingle(data, 0), _killTank = BitConverter.ToSingle(data, 4), _battery = (data[8] != 0) }; } private WeedKillerConfig() { } private static void ApplySynced(WeedKillerConfig cfg) { weedKillRate.Value = cfg._killRate; weedKillTank.Value = cfg._killTank; usesBattery.Value = cfg._battery; _synced = cfg; IsSynced = true; WeedKillerAdjusterLogger.Log("Config synced from host."); } private static void RevertSync() { if (_default != null) { weedKillRate.Value = _default._killRate; weedKillTank.Value = _default._killTank; usesBattery.Value = _default._battery; _synced = _default; IsSynced = false; WeedKillerAdjusterLogger.Log("Config reverted to local defaults."); } } public static void RequestSync() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (!IsClient) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(0, (Allocator)2, -1); try { MessageManager.SendNamedMessage("OniroDev.WeedKillerAdjuster_OnRequestConfigSync", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } public static void OnRequestSync(ulong clientId, FastBufferReader _) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (!IsHost) { return; } WeedKillerAdjusterLogger.Log($"Config sync request from client {clientId}"); byte[] array = Serialize(_default); int num = array.Length; FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(num + 4, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0); MessageManager.SendNamedMessage("OniroDev.WeedKillerAdjuster_OnReceiveConfigSync", clientId, val, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } public static void OnReceiveSync(ulong _, FastBufferReader reader) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!((FastBufferReader)(ref reader)).TryBeginRead(4)) { WeedKillerAdjusterLogger.LogError("Config sync error: could not read length."); return; } int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); if (!((FastBufferReader)(ref reader)).TryBeginRead(num)) { WeedKillerAdjusterLogger.LogError("Config sync error: could not read payload."); return; } byte[] data = new byte[num]; ((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0); try { ApplySynced(Deserialize(data)); } catch (Exception arg) { WeedKillerAdjusterLogger.LogError($"Config sync deserialization failed: {arg}"); } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] public static void InitializeLocalPlayer() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (IsHost) { CustomMessagingManager messageManager = MessageManager; object obj = <>O.<0>__OnRequestSync; if (obj == null) { HandleNamedMessageDelegate val = OnRequestSync; <>O.<0>__OnRequestSync = val; obj = (object)val; } messageManager.RegisterNamedMessageHandler("OniroDev.WeedKillerAdjuster_OnRequestConfigSync", (HandleNamedMessageDelegate)obj); IsSynced = true; return; } IsSynced = false; CustomMessagingManager messageManager2 = MessageManager; object obj2 = <>O.<1>__OnReceiveSync; if (obj2 == null) { HandleNamedMessageDelegate val2 = OnReceiveSync; <>O.<1>__OnReceiveSync = val2; obj2 = (object)val2; } messageManager2.RegisterNamedMessageHandler("OniroDev.WeedKillerAdjuster_OnReceiveConfigSync", (HandleNamedMessageDelegate)obj2); RequestSync(); } [HarmonyPostfix] [HarmonyPatch(typeof(GameNetworkManager), "StartDisconnect")] public static void PlayerLeave() { RevertSync(); } private static void ClearOrphanedEntries(ConfigFile configFile) { if (AccessTools.Property(typeof(ConfigFile), "OrphanedEntries")?.GetValue(configFile) is Dictionary dictionary) { dictionary.Clear(); } } } } namespace OniroDev.Patches { public class WeedKillerPatch { private static readonly FieldRef _sprayCanTankRef = AccessTools.FieldRefAccess("sprayCanTank"); private static readonly FieldRef _killWeedSpeedRef = TryGetKillWeedSpeedRef(); private static readonly FieldRef _isSprayingRef = AccessTools.FieldRefAccess("isSpraying"); private static readonly Dictionary _tempCanTank = new Dictionary(); private static FieldRef TryGetKillWeedSpeedRef() { FieldInfo fieldInfo = AccessTools.Field(typeof(SprayPaintItem), "killWeedSpeed"); if (fieldInfo == null) { WeedKillerAdjusterLogger.LogWarning("SprayPaintItem.killWeedSpeed not found in this game version. weedKillRate multiplier will be applied to drain rate instead."); return null; } return AccessTools.FieldRefAccess(fieldInfo); } [HarmonyPatch(typeof(SprayPaintItem), "Start")] [HarmonyPostfix] public static void WeedKillerKillRatePatch(SprayPaintItem __instance) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown if (_killWeedSpeedRef != null) { float num = _killWeedSpeedRef.Invoke(__instance) * WeedKillerConfig.weedKillRate.Value; _killWeedSpeedRef.Invoke(__instance) = num; WeedKillerAdjusterLogger.Log($"killWeedSpeed scaled to {num} (x{WeedKillerConfig.weedKillRate.Value})"); } if (__instance.isWeedKillerSprayBottle && WeedKillerConfig.usesBattery.Value) { ((GrabbableObject)__instance).insertedBattery = new Battery(false, _sprayCanTankRef.Invoke(__instance)); ((GrabbableObject)__instance).itemProperties.requiresBattery = true; WeedKillerAdjusterLogger.Log("Weed killer battery mode enabled."); } } [HarmonyPatch(typeof(GrabbableObject), "ChargeBatteries")] [HarmonyPrefix] private static void WeedKillerChargeBatteries(GrabbableObject __instance) { SprayPaintItem val = (SprayPaintItem)(object)((__instance is SprayPaintItem) ? __instance : null); if (val != null && val.isWeedKillerSprayBottle && WeedKillerConfig.usesBattery.Value) { _sprayCanTankRef.Invoke(val) = ((GrabbableObject)val).insertedBattery.charge; } } [HarmonyPatch(typeof(SprayPaintItem), "LateUpdate")] [HarmonyPrefix] private static void PreWeedKillerLateUpdate(SprayPaintItem __instance) { _tempCanTank[__instance] = _sprayCanTankRef.Invoke(__instance); } [HarmonyPatch(typeof(SprayPaintItem), "LateUpdate")] [HarmonyPostfix] private static void PostWeedKillerLateUpdate(SprayPaintItem __instance) { if (!__instance.isWeedKillerSprayBottle) { return; } bool flag = _isSprayingRef.Invoke(__instance); if (((GrabbableObject)__instance).isHeld && flag) { if (_killWeedSpeedRef != null) { if (!_tempCanTank.TryGetValue(__instance, out var value)) { return; } float num = Mathf.Max(value - Time.deltaTime / (15f * WeedKillerConfig.weedKillTank.Value), 0f); _sprayCanTankRef.Invoke(__instance) = num; } else { float num2 = _sprayCanTankRef.Invoke(__instance); float num3 = Time.deltaTime * (WeedKillerConfig.weedKillRate.Value - 1f) / (15f * WeedKillerConfig.weedKillTank.Value); _sprayCanTankRef.Invoke(__instance) = Mathf.Max(num2 - num3, 0f); } } if (WeedKillerConfig.usesBattery.Value) { ((GrabbableObject)__instance).insertedBattery.charge = _sprayCanTankRef.Invoke(__instance); } } [HarmonyPatch(typeof(SprayPaintItem), "OnDestroy")] [HarmonyPostfix] private static void WeedKillerOnDestroy(SprayPaintItem __instance) { _tempCanTank.Remove(__instance); } } }