Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of RepairDrone v0.1.1
plugins/RepairDrone/RepairDrone.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using REPOLib.Modules; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("saya")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.1.0")] [assembly: AssemblyInformationalVersion("0.1.1")] [assembly: AssemblyProduct("RepairDrone")] [assembly: AssemblyTitle("RepairDrone")] [assembly: AssemblyVersion("0.1.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 RepairDrone { [BepInPlugin("saya.RepairDrone", "RepairDrone", "0.1.1")] [BepInDependency("REPOLib", "4.2.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "saya.RepairDrone"; public const string PluginName = "RepairDrone"; public const string PluginVersion = "0.1.1"; private readonly Harmony _harmony = new Harmony("saya.RepairDrone"); private void Awake() { ((Component)this).transform.SetParent((Transform)null); ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); try { RepairSettings settings = new RepairSettings(((BaseUnityPlugin)this).Config); new RepairService(((BaseUnityPlugin)this).Logger, settings); _harmony.PatchAll(typeof(RepairBatteryValuePatch)); _harmony.PatchAll(typeof(RepairBatteryBarsPatch)); _harmony.PatchAll(typeof(RepairChargingStationPatch)); _harmony.PatchAll(typeof(RepairChargeConditionPatch)); _harmony.PatchAll(typeof(RepairShopStockPatch)); _harmony.PatchAll(typeof(RepairInventoryIconPatch)); _harmony.PatchAll(typeof(RepairBatteryRestorePatch)); _harmony.PatchAll(typeof(RepairBatteryCapturePatch)); _harmony.PatchAll(typeof(RepairStatsPatch)); RepairShopRegistration.Register(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RepairDrone v0.1.1 loaded."); } catch (Exception arg) { _harmony.UnpatchSelf(); ((Behaviour)this).enabled = false; ((BaseUnityPlugin)this).Logger.LogError((object)$"Repair Drone initialization failed: {arg}"); } } private void OnDestroy() { _harmony.UnpatchSelf(); } } internal static class RepairAmount { internal static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } internal static float Request(float current, float original, float budget) { if (!IsFinite(current) || !IsFinite(original) || !IsFinite(budget) || current < 0f || original <= current || budget <= 0f) { return 0f; } double num = (double)original - (double)current; if (!(num <= (double)budget)) { return (float)Math.Floor(budget); } return (float)Math.Ceiling(num); } internal static float Applied(float before, float after) { if (!IsFinite(before) || !IsFinite(after) || before < 0f || after <= before) { return 0f; } return after - before; } } [HarmonyPatch(typeof(ItemBattery), "BatteryFullPercentChangeLogic")] internal static class RepairBatteryValuePatch { private static void Prefix(ItemBattery __instance, out float? __state) { __state = ((SemiFunc.IsMasterClientOrSingleplayer() && Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<RepairDroneController>())) ? new float?(__instance.batteryLife) : ((float?)null)); } private static void Postfix(ItemBattery __instance, float? __state) { if (__state.HasValue) { __instance.batteryLife = __state.Value; } } } [HarmonyPatch] internal static class RepairBatteryBarsPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.DeclaredMethod(typeof(ItemBattery), "Update", (Type[])null, (Type[])null); yield return AccessTools.DeclaredMethod(typeof(ItemBattery), "TryVisualUpdate", (Type[])null, (Type[])null); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo round = AccessTools.Method(typeof(Mathf), "Round", new Type[1] { typeof(float) }, (Type[])null); MethodInfo replacement = AccessTools.Method(typeof(RepairBatteryBarsPatch), "Round", (Type[])null, (Type[])null); MethodInfo chargeLimit = AccessTools.Method(typeof(RepairBatteryBarsPatch), "ChargeLimit", (Type[])null, (Type[])null); int replacements = 0; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, round)) { yield return CodeInstructionExtensions.MoveBlocksFrom(CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Ldarg_0, (object)null), instruction), instruction); yield return new CodeInstruction(OpCodes.Call, (object)replacement); replacements++; continue; } yield return instruction; if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float num && num == 99f) { yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null); yield return new CodeInstruction(OpCodes.Call, (object)chargeLimit); } } if (replacements == 0) { throw new MissingMethodException("No battery rounding calls were found."); } } private static float Round(float value, ItemBattery battery) { if (!SemiFunc.IsMasterClientOrSingleplayer() || !Object.op_Implicit((Object)(object)((Component)battery).GetComponent<RepairDroneController>())) { return Mathf.Round(value); } return RepairEnergy.DisplayBars(value); } private static float ChargeLimit(float value, ItemBattery battery) { if (!SemiFunc.IsMasterClientOrSingleplayer() || !Object.op_Implicit((Object)(object)((Component)battery).GetComponent<RepairDroneController>())) { return value; } return 100f; } } [HarmonyPatch] internal static class RepairChargingStationPatch { private static readonly FieldRef<ItemBattery, int> ReadBars = AccessTools.FieldRefAccess<ItemBattery, int>("batteryLifeInt"); private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.DeclaredMethod(typeof(ChargingStation), "UpdateItemsInRange", (Type[])null, (Type[])null); yield return AccessTools.DeclaredMethod(typeof(ChargingStation), "ChargeAreaCheck", (Type[])null, (Type[])null); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { FieldInfo field = AccessTools.Field(typeof(ItemBattery), "batteryLifeInt"); MethodInfo replacement = AccessTools.Method(typeof(RepairChargingStationPatch), "ChargeBars", (Type[])null, (Type[])null); int replacements = 0; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.LoadsField(instruction, field, false)) { instruction.opcode = OpCodes.Call; instruction.operand = replacement; replacements++; } yield return instruction; } if (replacements == 0) { throw new MissingFieldException("No charging station battery comparisons were found."); } } private static int ChargeBars(ItemBattery battery) { if (SemiFunc.IsMasterClientOrSingleplayer() && Object.op_Implicit((Object)(object)((Component)battery).GetComponent<RepairDroneController>())) { if (!RepairEnergy.NeedsCharge(battery.batteryLife)) { return battery.batteryBars; } return battery.batteryBars - 1; } return ReadBars.Invoke(battery); } } [HarmonyPatch(typeof(SemiFunc), "BatteryChargeCondition")] internal static class RepairChargeConditionPatch { private static void Postfix(ItemBattery battery, ref bool __result) { if (Object.op_Implicit((Object)(object)battery) && SemiFunc.IsMasterClientOrSingleplayer() && Object.op_Implicit((Object)(object)((Component)battery).GetComponent<RepairDroneController>())) { __result = !battery.isUnchargable && RepairEnergy.NeedsCharge(battery.batteryLife); } } } internal static class RepairBatterySave { internal const string DictionaryKey = "sayaRepairDroneBatteryV1"; internal static void Capture(IDictionary<string, int> records, string name, float percent) { if (!string.IsNullOrEmpty(name) && RepairAmount.IsFinite(percent) && !(percent < 0f) && !(percent > 100f)) { records[name] = BitConverter.SingleToInt32Bits(percent); } } internal static bool TryRestore(IDictionary<string, int> records, string name, out float percent) { percent = 0f; if (string.IsNullOrEmpty(name) || !records.TryGetValue(name, out var value)) { return false; } float num = BitConverter.Int32BitsToSingle(value); if (!RepairAmount.IsFinite(num) || num < 0f || num > 100f) { return false; } percent = num; return true; } } internal sealed class RepairDroneController : MonoBehaviour, ITargetingCondition { private static readonly FieldRef<ItemDrone, PhysGrabObject> Target = AccessTools.FieldRefAccess<ItemDrone, PhysGrabObject>("magnetTargetPhysGrabObject"); private static readonly FieldRef<ItemEquippable, bool> Equipped = AccessTools.FieldRefAccess<ItemEquippable, bool>("isEquipped"); private static readonly FieldRef<ItemDrone, bool> MagnetActive = AccessTools.FieldRefAccess<ItemDrone, bool>("magnetActive"); private static readonly FieldRef<ItemBattery, int> BatteryBars = AccessTools.FieldRefAccess<ItemBattery, int>("batteryLifeInt"); private readonly RepairPulseClock _clock = new RepairPulseClock(); private readonly RepairEnergy _energy = new RepairEnergy(); private RepairService _owner; private ManualLogSource _log; private ItemDrone _drone; private ItemEquippable _equippable; private ItemToggle _toggle; private PhysGrabObject _body; private ItemBattery _battery; private PhysGrabObject? _previousTarget; private void Start() { if (_owner == null && Object.op_Implicit((Object)(object)((Component)this).GetComponent<RepairShopItem>())) { RepairService instance = RepairService.Instance; if (instance != null) { Initialize(instance, instance.Log); } } } internal void Initialize(RepairService owner, ManualLogSource log) { _owner = owner; _log = log; _drone = ((Component)this).GetComponent<ItemDrone>(); _equippable = ((Component)this).GetComponent<ItemEquippable>(); _toggle = ((Component)this).GetComponent<ItemToggle>(); _body = ((Component)this).GetComponent<PhysGrabObject>(); _battery = ((Component)this).GetComponent<ItemBattery>(); if (!Object.op_Implicit((Object)(object)_drone) || !Object.op_Implicit((Object)(object)_equippable) || !Object.op_Implicit((Object)(object)_toggle) || !Object.op_Implicit((Object)(object)_body) || !Object.op_Implicit((Object)(object)_battery)) { throw new InvalidOperationException("The repair drone is missing a required vanilla component."); } _drone.targetValuables = true; _drone.targetPlayers = (_drone.targetEnemies = (_drone.targetNonValuables = false)); _battery.autoDrain = false; } public bool CustomTargetingCondition(GameObject target) { if (_owner != null && _owner.DroneEnabled && Object.op_Implicit((Object)(object)target)) { return RepairService.NeedsRepair(target.GetComponent<PhysGrabObject>()); } return false; } private void Update() { //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Invalid comparison between Unknown and I4 //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Invalid comparison between Unknown and I4 if (_owner == null || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } try { _energy.Observe(_battery.batteryLife); RepairShopItem component = ((Component)this).GetComponent<RepairShopItem>(); if (Object.op_Implicit((Object)(object)component) && !component.BatteryReady) { ResetProgress(); return; } if (!_owner.DroneEnabled || Equipped.Invoke(_equippable) || !_toggle.toggleState || _body.dead) { ResetProgress(); if (!_owner.DroneEnabled && _toggle.toggleState) { _toggle.ToggleItem(false, -1); } return; } if (_energy.Percent <= 0.0) { StopRepair("Battery is empty."); return; } _body.OverrideZeroGravity(0.1f); _body.OverrideDrag(1f, 0.1f); _body.OverrideAngularDrag(10f, 0.1f); PhysGrabObject val = Target.Invoke(_drone); bool flag = Object.op_Implicit((Object)(object)val) && !val.dead && ((Component)val).gameObject.activeInHierarchy && MagnetActive.Invoke(_drone) && ((int)_drone.currentState == 3 || (int)_drone.currentState == 2); bool flag2 = _clock.AdvanceConnection(Object.op_Implicit((Object)(object)val) ? ((Object)val).GetInstanceID() : 0, flag, Time.deltaTime, _owner.DroneInterval); if (!flag) { _previousTarget = null; return; } if ((Object)(object)_previousTarget != (Object)(object)val) { _previousTarget = val; _log.LogDebug((object)"Repair drone connected to a valuable."); } if (!RepairService.NeedsRepair(val)) { StopRepair("Target is fully repaired."); } else if (flag2) { float fullChargeRepairValue = _owner.FullChargeRepairValue; float budget = _energy.Budget(fullChargeRepairValue, _owner.DroneAmount); float num = _owner.Repair(val, budget); _battery.batteryLife = _energy.Consume(num, fullChargeRepairValue); if (Object.op_Implicit((Object)(object)component)) { component.Capture(); } _log.LogDebug((object)FormattableString.Invariant($"Repair battery: applied={num:R} remaining={_energy.Percent:F6}% capacity={fullChargeRepairValue:R}.")); if (_energy.Percent <= 0.0) { StopRepair("Battery is empty."); } else if (num <= 0f) { StopRepair("No repair was observed; stopped without retrying."); } else if (!RepairService.NeedsRepair(val)) { StopRepair("Target is fully repaired."); } } } catch (Exception arg) { ((Behaviour)this).enabled = false; _log.LogError((object)$"Repair drone disabled: {arg}"); _toggle.ToggleItem(false, -1); } } private void StopRepair(string reason) { ResetProgress(); _toggle.ToggleItem(false, -1); _log.LogDebug((object)("Repair drone stopped: " + reason)); } private void ResetProgress() { _clock.Reset(); _previousTarget = null; } } internal sealed class RepairEnergy { private float _published = 100f; internal double Percent { get; private set; } = 100.0; internal void Observe(float batteryPercent) { if (batteryPercent != _published) { Percent = (RepairAmount.IsFinite(batteryPercent) ? Math.Max(0f, Math.Min(100f, batteryPercent)) : 0f); _published = (float)Percent; } } internal float Budget(float capacity, float pulse) { if (!RepairAmount.IsFinite(capacity) || !RepairAmount.IsFinite(pulse) || capacity <= 0f || pulse <= 0f) { return 0f; } return (float)Math.Min(pulse, Percent * (double)capacity / 100.0); } internal float Consume(float applied, float capacity) { if (RepairAmount.IsFinite(applied) && applied > 0f && RepairAmount.IsFinite(capacity) && capacity > 0f) { Percent = Math.Max(0.0, Percent - (double)applied * 100.0 / (double)capacity); } if (RepairAmount.IsFinite(capacity) && capacity > 0f && Percent * (double)capacity / 100.0 < 0.999999) { Percent = 0.0; } if (Percent < 1E-10) { Percent = 0.0; } _published = (float)Percent; return _published; } internal static float DisplayBars(float scaledBars) { if (!RepairAmount.IsFinite(scaledBars)) { return 0f; } return (float)Math.Ceiling(Math.Max(0f, scaledBars - 1E-06f)); } internal static bool NeedsCharge(float percent) { if (RepairAmount.IsFinite(percent) && percent >= 0f) { return percent < 100f; } return false; } } internal sealed class RepairInventoryIcon : MonoBehaviour { private static readonly FieldRef<ItemAttributes, bool> HasIcon = AccessTools.FieldRefAccess<ItemAttributes, bool>("hasIcon"); private Texture2D? _renderedTexture; internal IEnumerator Generate(ItemAttributes attributes) { yield return null; SemiIconMaker componentInChildren = ((Component)this).GetComponentInChildren<SemiIconMaker>(true); BatteryVisualLogic componentInChildren2 = ((Component)this).GetComponentInChildren<BatteryVisualLogic>(true); bool active = Object.op_Implicit((Object)(object)componentInChildren2) && ((Component)componentInChildren2).gameObject.activeSelf; try { if (Object.op_Implicit((Object)(object)componentInChildren2)) { ((Component)componentInChildren2).gameObject.SetActive(false); } Sprite val = componentInChildren.CreateIconFromRenderTexture((string)null); if (!Object.op_Implicit((Object)(object)val)) { RepairService? instance = RepairService.Instance; if (instance != null) { instance.Log.LogError((object)"Repair Drone inventory icon rendering failed."); } } else { attributes.icon = val; _renderedTexture = val.texture; HasIcon.Invoke(attributes) = true; } } finally { if (Object.op_Implicit((Object)(object)componentInChildren2)) { ((Component)componentInChildren2).gameObject.SetActive(active); } if (Object.op_Implicit((Object)(object)componentInChildren)) { ((Component)componentInChildren).gameObject.SetActive(false); } } } private void OnDestroy() { if (Object.op_Implicit((Object)(object)_renderedTexture)) { Object.Destroy((Object)(object)_renderedTexture); } } } [HarmonyPatch(typeof(ItemAttributes), "GenerateIcon")] internal static class RepairInventoryIconPatch { private static bool Prefix(ItemAttributes __instance, ref IEnumerator __result) { RepairInventoryIcon component = ((Component)__instance).GetComponent<RepairInventoryIcon>(); if (!Object.op_Implicit((Object)(object)component)) { return true; } __result = component.Generate(__instance); return false; } } internal sealed class RepairPulseClock { private float _elapsed; private int? _target; internal void Reset() { _elapsed = 0f; _target = null; } internal bool AdvanceConnection(int target, bool connected, float delta, float interval) { if (!connected) { Reset(); return false; } if (_target != target) { Reset(); _target = target; } return Advance(delta, interval); } internal bool Advance(float delta, float interval) { if (!RepairAmount.IsFinite(delta) || !RepairAmount.IsFinite(interval) || delta < 0f || interval <= 0f) { Reset(); return false; } _elapsed += delta; if (_elapsed < interval) { return false; } _elapsed = 0f; return true; } } internal sealed class RepairService { private static readonly FieldRef<ValuableObject, float> Current = AccessTools.FieldRefAccess<ValuableObject, float>("dollarValueCurrent"); private static readonly FieldRef<ValuableObject, float> Original = AccessTools.FieldRefAccess<ValuableObject, float>("dollarValueOriginal"); private static readonly Action<PhysGrabObjectImpactDetector, float, Vector3> HealLocal = AccessTools.MethodDelegate<Action<PhysGrabObjectImpactDetector, float, Vector3>>(AccessTools.DeclaredMethod(typeof(PhysGrabObjectImpactDetector), "HealLogic", new Type[2] { typeof(float), typeof(Vector3) }, (Type[])null), (object)null, true); internal static RepairService? Instance { get; private set; } internal ManualLogSource Log { get; } internal RepairSettings Settings { get; } internal bool DroneEnabled => true; internal float DroneAmount => Settings.AmountPerPulse; internal float DroneInterval => Settings.PulseSeconds; internal float FullChargeRepairValue => Settings.FullChargeRepairValue; internal bool PreferInShop => Settings.PreferInShop; internal RepairService(ManualLogSource log, RepairSettings settings) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(PhysGrabObjectImpactDetector), "HealRPC", new Type[3] { typeof(float), typeof(Vector3), typeof(PhotonMessageInfo) }, (Type[])null); if ((object)methodInfo == null || !methodInfo.IsDefined(typeof(PunRPC), inherit: false)) { throw new MissingMethodException("The vanilla HealRPC signature is incompatible."); } Log = log; Settings = settings; Instance = this; } internal static bool NeedsRepair(PhysGrabObject target) { if (!Object.op_Implicit((Object)(object)target) || target.dead || !((Component)target).gameObject.activeInHierarchy) { return false; } ValuableObject component = ((Component)target).GetComponent<ValuableObject>(); if (Object.op_Implicit((Object)(object)component)) { return RepairAmount.Request(Current.Invoke(component), Original.Invoke(component), 1f) > 0f; } return false; } internal static string DescribeValue(PhysGrabObject target) { ValuableObject val = (Object.op_Implicit((Object)(object)target) ? ((Component)target).GetComponent<ValuableObject>() : null); if (val == null || !Object.op_Implicit((Object)(object)val)) { return "value=unavailable"; } return FormattableString.Invariant($"current={Current.Invoke(val):R} original={Original.Invoke(val):R}"); } internal float Repair(PhysGrabObject target, float budget) { //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)target) || target.dead || (GameManager.Multiplayer() && !PhotonNetwork.IsMasterClient)) { return 0f; } ValuableObject component = ((Component)target).GetComponent<ValuableObject>(); PhysGrabObjectImpactDetector component2 = ((Component)target).GetComponent<PhysGrabObjectImpactDetector>(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2) || !component2.isValuable) { return 0f; } float num = Current.Invoke(component); float num2 = Original.Invoke(component); float num3 = RepairAmount.Request(num, num2, budget); PhotonView component3 = ((Component)component2).GetComponent<PhotonView>(); if (GameManager.Multiplayer() && (!Object.op_Implicit((Object)(object)component3) || component3.ViewID == 0)) { Log.LogWarning((object)"Repair: the target valuable has no registered PhotonView."); return 0f; } if (num3 > 0f) { if (GameManager.Multiplayer()) { component3.RPC("HealRPC", (RpcTarget)0, new object[2] { num3, target.centerPoint }); } else { HealLocal(component2, num3, target.centerPoint); } } float num4 = Current.Invoke(component); float num5 = RepairAmount.Applied(num, num4); Log.LogDebug((object)FormattableString.Invariant($"Repair: view={(Object.op_Implicit((Object)(object)component3) ? component3.ViewID : 0)} before={num:R} original={num2:R} requested={num3:R} after={num4:R} applied={num5:R}.")); if (num3 > 0f && num5 <= 0f) { Log.LogWarning((object)"Repair: no local increase observed; no success or resource charge recorded."); } return num5; } } internal sealed class RepairSettings { internal float AmountPerPulse => 500f; internal float PulseSeconds => 1f; internal float FullChargeRepairValue => 12000f; internal bool PreferInShop => false; internal RepairSettings(ConfigFile config) { } } internal sealed class RepairShopItem : MonoBehaviour { private static readonly FieldRef<ItemAttributes, string> InstanceName = AccessTools.FieldRefAccess<ItemAttributes, string>("instanceName"); private static readonly FieldRef<StatsManager, Dictionary<string, int>> OwnedItems = AccessTools.FieldRefAccess<StatsManager, Dictionary<string, int>>("item"); private static readonly Action<ItemBattery, int, bool> PublishBars = AccessTools.MethodDelegate<Action<ItemBattery, int, bool>>(AccessTools.DeclaredMethod(typeof(ItemBattery), "BatteryFullPercentChange", (Type[])null, (Type[])null), (object)null, true); private ItemAttributes _attributes; private ItemBattery _battery; internal bool BatteryReady { get; private set; } private void Awake() { _attributes = ((Component)this).GetComponent<ItemAttributes>(); _battery = ((Component)this).GetComponent<ItemBattery>(); } internal void Restore() { BatteryReady = true; if (SemiFunc.IsMasterClientOrSingleplayer()) { string text = InstanceName.Invoke(_attributes); if (!SemiFunc.RunIsShop() && !SemiFunc.RunIsArena() && RepairBatterySave.TryRestore(RepairStatsPatch.Records(StatsManager.instance), text, out var percent)) { _battery.batteryLife = percent; PublishBars(_battery, (int)RepairEnergy.DisplayBars(percent / (100f / (float)_battery.batteryBars)), arg3: false); RepairService.Instance.Log.LogInfo((object)FormattableString.Invariant($"Restored repair battery: item={text} remaining={percent:R}%.")); } Capture(); } } internal void Capture() { if (BatteryReady && Object.op_Implicit((Object)(object)StatsManager.instance) && SemiFunc.IsMasterClientOrSingleplayer() && !SemiFunc.RunIsShop() && !SemiFunc.RunIsArena()) { string text = InstanceName.Invoke(_attributes); if (!string.IsNullOrEmpty(text) && OwnedItems.Invoke(StatsManager.instance).ContainsKey(text)) { RepairBatterySave.Capture(RepairStatsPatch.Records(StatsManager.instance), text, _battery.batteryLife); } } } private void OnDisable() { Capture(); } } [HarmonyPatch(typeof(ItemBattery), "SetBatteryLife")] internal static class RepairBatteryRestorePatch { private static void Postfix(ItemBattery __instance) { RepairShopItem component = ((Component)__instance).GetComponent<RepairShopItem>(); if (Object.op_Implicit((Object)(object)component)) { component.Restore(); } } } [HarmonyPatch(typeof(ItemBattery), "Update")] internal static class RepairBatteryCapturePatch { private static void Postfix(ItemBattery __instance) { RepairShopItem component = ((Component)__instance).GetComponent<RepairShopItem>(); if (Object.op_Implicit((Object)(object)component)) { component.Capture(); } } } [HarmonyPatch(typeof(StatsManager))] internal static class RepairStatsPatch { private static readonly FieldRef<StatsManager, SortedDictionary<string, Dictionary<string, int>>> Dictionaries = AccessTools.FieldRefAccess<StatsManager, SortedDictionary<string, Dictionary<string, int>>>("dictionaryOfDictionaries"); internal static Dictionary<string, int> Records(StatsManager stats) { SortedDictionary<string, Dictionary<string, int>> sortedDictionary = Dictionaries.Invoke(stats); if (!sortedDictionary.TryGetValue("sayaRepairDroneBatteryV1", out var value)) { value = new Dictionary<string, int>(); sortedDictionary.Add("sayaRepairDroneBatteryV1", value); } return value; } [HarmonyPatch("Start")] [HarmonyPostfix] private static void Initialize(StatsManager __instance) { Records(__instance); } [HarmonyPatch("SaveGame")] [HarmonyPrefix] private static void Flush() { if (SemiFunc.IsMasterClientOrSingleplayer()) { RepairShopItem[] array = Object.FindObjectsOfType<RepairShopItem>(true); for (int i = 0; i < array.Length; i++) { array[i].Capture(); } } } [HarmonyPatch("ItemRemove")] [HarmonyPostfix] private static void Remove(StatsManager __instance, string instanceName) { if (!SemiFunc.RunIsArena() && SemiFunc.IsMasterClientOrSingleplayer()) { Records(__instance).Remove(instanceName); } } } internal static class RepairShopRegistration { internal const string ItemId = "Item Drone Repair"; internal const string PrefabId = "Items/Item Drone Repair"; private static GameObject? _templates; internal static Item? Item { get; private set; } internal static GameObject? Template { get; private set; } internal static void Register() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Item)) { GameObject val = Resources.Load<GameObject>("items/Item Drone Indestructible"); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<ItemAttributes>()) || !Object.op_Implicit((Object)(object)val.GetComponent<ItemDroneIndestructible>())) { throw new InvalidOperationException("The vanilla drone template is unavailable."); } _templates = new GameObject("Repair Drone Templates"); ((Object)_templates).hideFlags = (HideFlags)61; _templates.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_templates); GameObject val2 = Object.Instantiate<GameObject>(val, _templates.transform); ((Object)val2).name = "Item Drone Repair"; val2.SetActive(true); ((Behaviour)val2.GetComponent<ItemDroneIndestructible>()).enabled = false; val2.GetComponent<ItemBattery>().autoDrain = false; val2.AddComponent<RepairShopItem>(); val2.AddComponent<RepairDroneController>(); ItemAttributes component = val2.GetComponent<ItemAttributes>(); Item val3 = Object.Instantiate<Item>(component.item); ((Object)val3).name = "Item Drone Repair"; val3.itemName = "Repair Drone"; val3.itemNameLocalized = null; val3.description = "Repairs damaged valuables using battery power."; val3.disabled = false; val3.maxAmount = (val3.maxAmountInShop = 1); val3.minPlayerCount = 1; val3.maxPurchase = false; val3.itemSecretShopType = (itemSecretShopType)0; val3.value = Object.Instantiate<Value>(val3.value); val3.value.valueMin = 3500f; val3.value.valueMax = 4500f; component.item = val3; RepairVisuals.Apply(val2); if (Items.RegisterItem(component) == null) { throw new InvalidOperationException("REPOLib rejected the repair drone item."); } Template = val2; Item = val3; RepairService.Instance.Log.LogInfo((object)"Registered Repair Drone: vanilla shop pricing; full-charge repair=$12000 by default; all players require this item."); } } } [HarmonyPatch(typeof(ShopManager), "GetAllItemsFromStatsManager")] internal static class RepairShopStockPatch { private static void Postfix(ShopManager __instance) { Item item = RepairShopRegistration.Item; if (item == null || !Object.op_Implicit((Object)(object)item) || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } RepairService? instance = RepairService.Instance; if (instance != null && instance.PreferInShop && StatsManager.instance.GetItemPurchased(item) < item.maxAmountInShop) { __instance.potentialItems.RemoveAll((Item candidate) => (Object)(object)candidate == (Object)(object)item); __instance.potentialItems.Add(item); } } } internal static class RepairVisuals { internal const string BundleName = "repairdrone.visuals"; private const string WrenchPath = "assets/repairdrone/repair-wrench.png"; internal static void Apply(GameObject item) { //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) Transform val = item.transform.Find("Drone"); Transform val2 = item.transform.Find("Drone Icon"); ItemAttributes component = item.GetComponent<ItemAttributes>(); ItemDrone component2 = item.GetComponent<ItemDrone>(); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)((Component)val).GetComponent<MeshRenderer>()) || !Object.op_Implicit((Object)(object)((Component)val2).GetComponent<MeshRenderer>()) || !Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.item) || !Object.op_Implicit((Object)(object)component.item.colorPreset) || !Object.op_Implicit((Object)(object)component2) || !Object.op_Implicit((Object)(object)item.GetComponentInChildren<SemiIconMaker>(true))) { throw new InvalidOperationException("The vanilla drone visual hierarchy is unavailable."); } AssetBundle val3 = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "repairdrone.visuals")); if (!Object.op_Implicit((Object)(object)val3)) { throw new InvalidOperationException("Repair Drone visual bundle is missing or invalid."); } try { Texture2D val4 = val3.LoadAsset<Texture2D>("assets/repairdrone/repair-wrench.png"); if (!Object.op_Implicit((Object)(object)val4)) { throw new InvalidOperationException("Repair Drone appearance textures are missing."); } ColorPresets val5 = Object.Instantiate<ColorPresets>(component.item.colorPreset); ((Object)val5).name = "Repair Drone Colors"; val5.colorMain = new Color(0.08f, 0.85f, 0.35f); val5.colorLight = new Color(0.37f, 1f, 0.64f); val5.colorDark = new Color(0.04f, 0.65f, 0.24f); component.item.colorPreset = val5; component2.droneIcon = (Texture)(object)val4; Dictionary<Material, Material> copies = new Dictionary<Material, Material>(); MeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<MeshRenderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { CloneMaterials(componentsInChildren[i], copies, val5.colorMain); } MeshRenderer component3 = ((Component)val2).GetComponent<MeshRenderer>(); CloneMaterials(component3, copies, val5.colorMain); ((Renderer)component3).sharedMaterial.SetTexture("_EmissionMap", (Texture)(object)val4); item.AddComponent<RepairInventoryIcon>(); Validate(item); RepairService.Instance.Log.LogInfo((object)"Loaded Repair Drone appearance: vanilla shell, green lighting, wrench symbol, and green beam."); } finally { val3.Unload(false); } } private static void CloneMaterials(MeshRenderer renderer, Dictionary<Material, Material> copies, Color color) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if (!Object.op_Implicit((Object)(object)val)) { continue; } if (!copies.TryGetValue(val, out Material value)) { value = new Material(val); if (value.HasProperty("_EmissionColor")) { value.SetColor("_EmissionColor", color); } copies.Add(val, value); } sharedMaterials[i] = value; } ((Renderer)renderer).sharedMaterials = sharedMaterials; } internal static void Validate(GameObject item) { string[] array = new string[2] { "Drone", "Drone Icon" }; foreach (string text in array) { Transform val = item.transform.Find(text); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((Component)val).GetComponent<MeshRenderer>()) || !((Renderer)((Component)val).GetComponent<MeshRenderer>()).enabled) { throw new InvalidOperationException("Repair Drone must retain the visible vanilla shell."); } } if (!Object.op_Implicit((Object)(object)item.GetComponent<ItemDrone>().droneIcon) || !Object.op_Implicit((Object)(object)item.GetComponent<RepairInventoryIcon>())) { throw new InvalidOperationException("Repair Drone appearance references did not survive cloning."); } } } }