using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Audio; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("LogicalReplicator")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("LogicalReplicator")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("24d3e958-fc8c-4f4b-a53c-41d760263c32")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace LogicalReplicator; public static class ReplicatorCore { public static bool IsBurning = false; public static bool IsSynthesizing = false; public static float BurnTimeRemaining = 0f; public static float SynthTimeRemaining = 0f; public static ItemData ItemInSlot; private static string selectedBlueprint; private static float selectedBlueprintCost = 0f; private static int synthesizeAmount = 1; private static Coroutine burnRoutine; private static Coroutine synthRoutine; private static GameObject activeBurnSfx; private static GameObject activeSynthSfx; public static void ResetBurnSlot() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) ItemInSlot = null; if ((Object)(object)ReplicatorUI.ItemIconImage != (Object)null) { ReplicatorUI.ItemIconImage.sprite = null; ((Graphic)ReplicatorUI.ItemIconImage).color = new Color(1f, 1f, 1f, 0f); } if ((Object)(object)ReplicatorUI.StatusText != (Object)null) { ReplicatorUI.StatusText.text = "Поместите предмет..."; } ReplicatorUI.SetButtonState(ReplicatorUI.ActionButton, interactable: false, "Абсорбировать"); if ((Object)(object)ReplicatorUI.ProgressBar != (Object)null) { ReplicatorUI.ProgressBar.value = 0f; } if ((Object)(object)ReplicatorUI.BurnSlotImage != (Object)null) { ReplicatorUI.RemoveTooltip(((Component)ReplicatorUI.BurnSlotImage).gameObject); } } public static void HandleClose() { if (!IsBurning && ItemInSlot != null) { ((Humanoid)Player.m_localPlayer).GetInventory().AddItem(ItemInSlot); ResetBurnSlot(); } } public static string GetPrefabName(ItemData itemData) { if (itemData == null) { return ""; } if ((Object)(object)itemData.m_dropPrefab != (Object)null) { return ((Object)itemData.m_dropPrefab).name; } if ((Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items != null) { foreach (GameObject item in ObjectDB.instance.m_items) { ItemDrop component = item.GetComponent(); if ((Object)(object)component != (Object)null && component.m_itemData.m_shared.m_name == itemData.m_shared.m_name) { return ((Object)item).name; } } } return itemData.m_shared.m_name; } public static float GetBiomassValue(ItemData itemData) { if (itemData == null) { return 0f; } string prefabName = GetPrefabName(itemData); if (prefabName == "BiomassCube") { return 100f; } if (prefabName == "BiomassCrate") { return 1000f; } Recipe val = null; foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if ((Object)(object)recipe.m_item != (Object)null && recipe.m_item.m_itemData.m_shared.m_name == itemData.m_shared.m_name) { val = recipe; break; } } if ((Object)(object)val != (Object)null && val.m_resources != null && val.m_resources.Length != 0) { float num = 0f; Requirement[] resources = val.m_resources; foreach (Requirement val2 in resources) { if ((Object)(object)val2.m_resItem != (Object)null) { num += val2.m_resItem.m_itemData.m_shared.m_weight * (float)(val2.m_amount + val2.m_amountPerLevel * Mathf.Max(0, itemData.m_quality - 1)); } } if (num > 0f) { return num / (float)Mathf.Max(1, val.m_amount); } } return itemData.m_shared.m_weight; } public static void OnBurnClicked() { if (IsBurning) { if (burnRoutine != null) { ((MonoBehaviour)ReplicatorPlugin.Instance).StopCoroutine(burnRoutine); } CleanupBurnVFX(); IsBurning = false; if (ItemInSlot != null) { ((Humanoid)Player.m_localPlayer).GetInventory().AddItem(ItemInSlot); } ResetBurnSlot(); } else if (ItemInSlot != null) { ReplicatorUI.SetButtonState(ReplicatorUI.ActionButton, interactable: true, "[ ОТМЕНА ]"); ReplicatorVFX.PlaySafeSound("sfx_smelter_add_ore", "sfx_build_hammer_metal"); float num = GetBiomassValue(ItemInSlot) * (float)ItemInSlot.m_stack; float burnTime = Mathf.Max(1f, num); float gainedMass = num * ReplicatorPlugin.MassMultiplier.Value; string prefabName = GetPrefabName(ItemInSlot); if (prefabName == "BiomassCube" || prefabName == "BiomassCrate") { gainedMass = num; burnTime = 3f; } if (ReplicatorPlugin.InstantBurnEnabled.Value) { FinishBurn(prefabName, gainedMass); } else { burnRoutine = ((MonoBehaviour)ReplicatorPlugin.Instance).StartCoroutine(BurnRoutine(burnTime, prefabName, gainedMass)); } } } private static void CleanupBurnVFX() { if ((Object)(object)activeBurnSfx != (Object)null) { Object.Destroy((Object)(object)activeBurnSfx); } if ((Object)(object)ReplicatorVFX.BurnLight != (Object)null) { ((MonoBehaviour)ReplicatorPlugin.Instance).StartCoroutine(ReplicatorVFX.FadeLightOut(ReplicatorVFX.BurnLight, 1.5f)); } activeBurnSfx = null; ReplicatorVFX.ResetBurnVisuals(); } private static IEnumerator BurnRoutine(float burnTime, string prefabName, float gainedMass) { IsBurning = true; BurnTimeRemaining = burnTime; if ((Object)(object)ReplicatorUI.ProgressBar != (Object)null) { ReplicatorUI.ProgressBar.maxValue = burnTime; } activeBurnSfx = ReplicatorVFX.CreateLoopingSound(((Component)Player.m_localPlayer).transform, ReplicatorPlugin.BurnSoundVolume.Value, "smelter", "charcoal_kiln", "fire_pit"); double lastWorldTime = ZNet.instance.GetTimeSeconds(); while (BurnTimeRemaining > 0f) { double currentWorldTime = ZNet.instance.GetTimeSeconds(); float delta = (float)(currentWorldTime - lastWorldTime); lastWorldTime = currentWorldTime; if (delta > 0f) { BurnTimeRemaining -= delta; } float progress = Mathf.Clamp01(1f - BurnTimeRemaining / burnTime); if ((Object)(object)activeBurnSfx != (Object)null) { AudioSource src = activeBurnSfx.GetComponent(); if ((Object)(object)src != (Object)null) { src.volume = ReplicatorPlugin.BurnSoundVolume.Value; } } if ((Object)(object)ReplicatorUI.StatusText != (Object)null) { ReplicatorUI.StatusText.text = $"Разборка: {Mathf.CeilToInt(Mathf.Max(0f, BurnTimeRemaining))} сек. ({Mathf.RoundToInt(progress * 100f)}%)"; } if ((Object)(object)ReplicatorUI.ProgressBar != (Object)null) { ReplicatorUI.ProgressBar.value = burnTime - Mathf.Max(0f, BurnTimeRemaining); } if (ReplicatorPlugin.EnableBurnGlow.Value && (Object)(object)ReplicatorVFX.BurnLight != (Object)null) { ReplicatorVFX.BurnLight.intensity = Mathf.Clamp(progress * 5f, 0f, 1f) * ReplicatorVFX.BurnLightMax; } ReplicatorVFX.AnimateBurnModel(progress); yield return (object)new WaitForSeconds(0.1f); } FinishBurn(prefabName, gainedMass); } private static void FinishBurn(string prefabName, float gainedMass) { ReplicatorDB.LearnItem(prefabName); ReplicatorDB.StoredMass += gainedMass; ReplicatorVFX.PlaySafeSound("sfx_blob_alert", "sfx_mud_tick"); ReplicatorVFX.PlaySafeEffect(((Component)Player.m_localPlayer).transform, false, "vfx_blood_hit", "vfx_blob_hit"); ((Character)Player.m_localPlayer).Message((MessageType)1, $"[Репликатор] Абсорбция завершена. +{gainedMass:F1} БМ", 0, (Sprite)null); ReplicatorUI.UpdateGrid(); ReplicatorUI.UpdateEpm(); CleanupBurnVFX(); ResetBurnSlot(); IsBurning = false; } public static void SelectBlueprint(string itemName, float costPerItem) { if (!IsSynthesizing) { selectedBlueprint = itemName; selectedBlueprintCost = costPerItem; synthesizeAmount = 1; ReplicatorVFX.PlaySafeSound("sfx_gui_button"); UpdateSynthesisUI(); } } public static void ChangeAmount(int delta) { if (!IsSynthesizing && !string.IsNullOrEmpty(selectedBlueprint)) { int num = ((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : 10); SetAmount(synthesizeAmount + delta * num); } } public static void SetAmount(int amount) { if (!IsSynthesizing && !string.IsNullOrEmpty(selectedBlueprint)) { synthesizeAmount = Mathf.Clamp(amount, 1, 9999); ReplicatorVFX.PlaySafeSound("sfx_gui_button"); UpdateSynthesisUI(); } } private static void UpdateSynthesisUI() { if (string.IsNullOrEmpty(selectedBlueprint)) { return; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(selectedBlueprint); if (!((Object)(object)itemPrefab == (Object)null)) { float num = selectedBlueprintCost * (float)synthesizeAmount; if ((Object)(object)ReplicatorUI.SelectedNameText != (Object)null) { ReplicatorUI.SelectedNameText.text = $"{Localization.instance.Localize(itemPrefab.GetComponent().m_itemData.m_shared.m_name)} ({num:F1} БМ)"; } float num2 = ((selectedBlueprint == "BiomassCube" || selectedBlueprint == "BiomassCrate") ? 3f : num); if ((Object)(object)ReplicatorUI.SynthesisTimerText != (Object)null) { ReplicatorUI.SynthesisTimerText.text = $"Время: {Mathf.CeilToInt(Mathf.Max(1f, num2))} сек"; } if ((Object)(object)ReplicatorUI.amountInputField != (Object)null && !ReplicatorUI.amountInputField.isFocused) { ReplicatorUI.amountInputField.text = synthesizeAmount.ToString(); } else if ((Object)(object)ReplicatorUI.AmountText != (Object)null && (Object)(object)ReplicatorUI.amountInputField == (Object)null) { ReplicatorUI.AmountText.text = synthesizeAmount.ToString(); } if (!IsSynthesizing) { ReplicatorUI.SetButtonState(ReplicatorUI.SynthesizeButton, ReplicatorDB.StoredMass >= num, "Синтезировать"); } } } public static void OnSynthesizeClicked() { if (IsSynthesizing) { if (synthRoutine != null) { ((MonoBehaviour)ReplicatorPlugin.Instance).StopCoroutine(synthRoutine); } CleanupSynthVFX(); IsSynthesizing = false; UpdateSynthesisUI(); } else { if (string.IsNullOrEmpty(selectedBlueprint)) { return; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(selectedBlueprint); float num = selectedBlueprintCost * (float)synthesizeAmount; if (!((Object)(object)itemPrefab == (Object)null) && !(ReplicatorDB.StoredMass < num)) { ReplicatorUI.SetButtonState(ReplicatorUI.SynthesizeButton, interactable: true, "[ ОТМЕНА ]"); ReplicatorVFX.PlaySafeSound("sfx_forge_use", "sfx_chest_open"); float time = Mathf.Max(1f, num); if (selectedBlueprint == "BiomassCube" || selectedBlueprint == "BiomassCrate") { time = 3f; } if (ReplicatorPlugin.InstantBurnEnabled.Value) { FinishSynthesis(itemPrefab, num, synthesizeAmount); } else { synthRoutine = ((MonoBehaviour)ReplicatorPlugin.Instance).StartCoroutine(SynthRoutine(time, num, itemPrefab, synthesizeAmount)); } } } } private static void CleanupSynthVFX() { if ((Object)(object)activeSynthSfx != (Object)null) { Object.Destroy((Object)(object)activeSynthSfx); } if ((Object)(object)ReplicatorVFX.SynthLight != (Object)null) { ((MonoBehaviour)ReplicatorPlugin.Instance).StartCoroutine(ReplicatorVFX.FadeLightOut(ReplicatorVFX.SynthLight, 1.5f)); } ReplicatorVFX.ResetSynthVisuals(); } public static void TriggerOverloadBurst() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } Animator componentInChildren = ((Component)Player.m_localPlayer).GetComponentInChildren(); Transform val = ((componentInChildren != null) ? componentInChildren.GetBoneTransform((HumanBodyBones)8) : null) ?? ((Component)Player.m_localPlayer).transform; Vector3 val2 = val.position + val.forward * 0.5f; ReplicatorVFX.PlaySafeEffectAt(val2, "vfx_sledge_lightning_hit", "vfx_HitSparks", "vfx_lightning"); ReplicatorVFX.PlaySafeSound("sfx_lightning_hit", "sfx_sledge_hit"); HitData val3 = new HitData(); val3.m_damage.m_lightning = 0.1f; val3.m_point = val2; ((Character)Player.m_localPlayer).ApplyDamage(val3, true, false, (DamageModifier)0); Collider[] array = Physics.OverlapSphere(val2, 4f); Collider[] array2 = array; foreach (Collider val4 in array2) { Character componentInParent = ((Component)val4).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)Player.m_localPlayer) { componentInParent.ApplyDamage(val3, true, false, (DamageModifier)0); } } } private static IEnumerator SynthRoutine(float time, float totalCost, GameObject prefab, int amount) { IsSynthesizing = true; SynthTimeRemaining = time; bool isOverloaded = totalCost >= 500f; activeSynthSfx = ReplicatorVFX.CreateLoopingSound(((Component)Player.m_localPlayer).transform, ReplicatorPlugin.SynthSoundVolume.Value, "piece_spinningwheel", "portal_wood", "forge"); double lastWorldTime = ZNet.instance.GetTimeSeconds(); while (SynthTimeRemaining > 0f) { double currentWorldTime = ZNet.instance.GetTimeSeconds(); float delta = (float)(currentWorldTime - lastWorldTime); lastWorldTime = currentWorldTime; if (delta > 0f) { SynthTimeRemaining -= delta; } float progress = Mathf.Clamp01(1f - SynthTimeRemaining / time); float glowProgress = Mathf.Clamp01(progress * 2f); if ((Object)(object)activeSynthSfx != (Object)null) { AudioSource src = activeSynthSfx.GetComponent(); if ((Object)(object)src != (Object)null) { src.volume = ReplicatorPlugin.SynthSoundVolume.Value; } } if ((Object)(object)ReplicatorUI.SynthesisTimerText != (Object)null) { ReplicatorUI.SynthesisTimerText.text = $"Синтез... {Mathf.CeilToInt(Mathf.Max(0f, SynthTimeRemaining))} сек ({Mathf.RoundToInt(progress * 100f)}%)"; } if (ReplicatorPlugin.EnableSynthGlow.Value && (Object)(object)ReplicatorVFX.SynthLight != (Object)null) { float maxIntensity = (isOverloaded ? (ReplicatorVFX.SynthLightMax * 2f) : ReplicatorVFX.SynthLightMax); ReplicatorVFX.SynthLight.intensity = Mathf.Lerp(0f, maxIntensity, glowProgress); } ReplicatorVFX.AnimateSynthModel(glowProgress); if (isOverloaded && progress > 0.8f && Random.value < 0.1f) { TriggerOverloadBurst(); } yield return (object)new WaitForSeconds(0.1f); } FinishSynthesis(prefab, totalCost, amount); } private static void FinishSynthesis(GameObject prefab, float totalCost, int amount) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) ReplicatorDB.StoredMass -= totalCost; ReplicatorUI.UpdateEpm(); if ((Object)(object)Player.m_localPlayer != (Object)null) { Transform transform = ((Component)Player.m_localPlayer).transform; Vector3 val = transform.position + Vector3.up * 1.5f + transform.forward * 0.5f; int num = amount; int maxStackSize = prefab.GetComponent().m_itemData.m_shared.m_maxStackSize; while (num > 0) { int num2 = Mathf.Min(num, maxStackSize); GameObject val2 = Object.Instantiate(prefab, val, Quaternion.identity); val2.GetComponent().m_itemData.m_stack = num2; Rigidbody component = val2.GetComponent(); if ((Object)(object)component != (Object)null) { component.AddForce(transform.forward * 4f + Vector3.up * 2f, (ForceMode)2); } num -= num2; } ReplicatorVFX.PlaySafeSound("sfx_lootspawn", "sfx_chest_close"); ReplicatorVFX.PlaySafeEffect(transform, false, "vfx_lootspawn", "vfx_sledge_iron_hit"); ((Character)Player.m_localPlayer).Message((MessageType)2, $"[Репликатор] Синтезировано: x{amount}!", 0, (Sprite)null); } CleanupSynthVFX(); IsSynthesizing = false; UpdateSynthesisUI(); } public static void OnSleepTimeSkipped(float realSecondsSkipped) { if (!(realSecondsSkipped <= 0f)) { if (IsBurning && BurnTimeRemaining > 0f) { BurnTimeRemaining -= realSecondsSkipped; ReplicatorPlugin.ModLogger.LogInfo((object)$"[Репликатор] Пропущено {realSecondsSkipped:F1} сек. абсорбции из-за сна."); } if (IsSynthesizing && SynthTimeRemaining > 0f) { SynthTimeRemaining -= realSecondsSkipped; ReplicatorPlugin.ModLogger.LogInfo((object)$"[Репликатор] Пропущено {realSecondsSkipped:F1} сек. синтеза из-за сна."); } } } } public static class ReplicatorDB { private const string KeyItems = "LearnedReplications"; private const string KeyMass = "ReplicatorMass"; public static float StoredMass { get { if ((Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.m_customData.TryGetValue("ReplicatorMass", out var value) && float.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } return 0f; } set { if ((Object)(object)Player.m_localPlayer != (Object)null) { Player.m_localPlayer.m_customData["ReplicatorMass"] = value.ToString(CultureInfo.InvariantCulture); } } } public static void LearnItem(string prefabName) { if (!((Object)(object)Player.m_localPlayer == (Object)null) && !string.IsNullOrEmpty(prefabName)) { List learnedItems = GetLearnedItems(); if (!learnedItems.Contains(prefabName)) { learnedItems.Add(prefabName); Player.m_localPlayer.m_customData["LearnedReplications"] = string.Join(",", learnedItems); } } } public static List GetLearnedItems() { if ((Object)(object)Player.m_localPlayer == (Object)null) { return new List(); } if (Player.m_localPlayer.m_customData.TryGetValue("LearnedReplications", out var value) && !string.IsNullOrEmpty(value)) { return new List(value.Split(new char[1] { ',' })); } return new List(); } } [HarmonyPatch(typeof(Player), "TakeInput")] public static class PlayerTakeInputPatch { public static void Postfix(ref bool __result) { if (ReplicatorUI.IsOpen && ReplicatorUI.IsTyping()) { __result = false; } } } [HarmonyPatch(typeof(InventoryGui), "Update")] public static class InventoryGuiUpdatePatch { public static bool Prefix() { if (ReplicatorUI.IsOpen && ReplicatorUI.IsTyping()) { if (Input.GetKeyDown((KeyCode)27)) { EventSystem.current.SetSelectedGameObject((GameObject)null); return false; } return false; } return true; } } [HarmonyPatch(typeof(InventoryGui), "ShowSplitDialog")] public static class InventorySplitPanelZOrderPatch { public static void Postfix(InventoryGui __instance) { if ((Object)(object)__instance.m_splitPanel != (Object)null) { Canvas val = ((Component)__instance.m_splitPanel).GetComponent(); if ((Object)(object)val == (Object)null) { val = ((Component)__instance.m_splitPanel).gameObject.AddComponent(); ((Component)__instance.m_splitPanel).gameObject.AddComponent(); } val.overrideSorting = true; val.sortingOrder = 1005; } } } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] public static class InventoryQuickTransferPatch { public static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (ReplicatorUI.IsOpen && item != null && Input.GetKey((KeyCode)306) && ReplicatorCore.ItemInSlot == null) { ReplicatorCore.ItemInSlot = item.Clone(); ((Humanoid)Player.m_localPlayer).GetInventory().RemoveItem(item); ReplicatorUI.ItemIconImage.sprite = ReplicatorCore.ItemInSlot.m_shared.m_icons[0]; ((Graphic)ReplicatorUI.ItemIconImage).color = Color.white; ReplicatorUI.SetButtonState(ReplicatorUI.ActionButton, interactable: true, "Абсорбировать"); string prefabName = ReplicatorCore.GetPrefabName(ReplicatorCore.ItemInSlot); float num = ReplicatorCore.GetBiomassValue(ReplicatorCore.ItemInSlot) * (float)ReplicatorCore.ItemInSlot.m_stack; float num2 = num * ReplicatorPlugin.MassMultiplier.Value; if (prefabName == "BiomassCube" || prefabName == "BiomassCrate") { num2 = num; } ReplicatorUI.StatusText.text = $"Выход: {num2:F1} БМ (x{ReplicatorCore.ItemInSlot.m_stack})"; if ((Object)(object)ReplicatorUI.BurnSlotImage != (Object)null) { ReplicatorUI.ApplyTooltip(((Component)ReplicatorUI.BurnSlotImage).gameObject, Localization.instance.Localize(ReplicatorCore.ItemInSlot.m_shared.m_name), ReplicatorCore.ItemInSlot.GetTooltip(-1)); } ReplicatorVFX.PlaySafeSound("sfx_gui_button"); return false; } return true; } } [HarmonyPatch(typeof(Player), "OnSpawned")] public static class PlayerVisualAttachmentPatch { public static void Postfix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { ReplicatorVFX.AttachModelToPlayer(__instance); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class ZNetSceneRegistrationPatch { public static void Postfix(ZNetScene __instance) { ReplicatorShared.RegisterToZNetScene(__instance); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class ObjectDBRegistrationPatchAwake { public static void Postfix(ObjectDB __instance) { ReplicatorShared.RegisterToObjectDB(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public static class ObjectDBRegistrationPatchCopy { public static void Postfix(ObjectDB __instance) { ReplicatorShared.RegisterToObjectDB(__instance); } } [HarmonyPatch(typeof(Inventory), "GetTotalWeight")] public static class InventoryWeightPatch { public static void Postfix(Inventory __instance, ref float __result) { if ((Object)(object)Player.m_localPlayer != (Object)null && __instance == ((Humanoid)Player.m_localPlayer).GetInventory()) { __result += ReplicatorDB.StoredMass / 10f; } } } [HarmonyPatch(typeof(EnvMan), "FixedUpdate")] public static class EnvManTimeJumpPatch { private static double lastGameTime = -1.0; public static void Postfix(EnvMan __instance) { if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } double timeSeconds = ZNet.instance.GetTimeSeconds(); if (lastGameTime > 0.0) { double num = timeSeconds - lastGameTime; if (num > 300.0) { float num2 = ((__instance.m_dayLengthSec > 0) ? ((float)__instance.m_dayLengthSec) : 1800f); float realSecondsSkipped = (float)num * (num2 / 86400f); ReplicatorCore.OnSleepTimeSkipped(realSecondsSkipped); } } lastGameTime = timeSeconds; } } [BepInPlugin("com.sellivira.logicalreplicator", "Logical Replicator", "1.1.3")] public class ReplicatorPlugin : BaseUnityPlugin { public const string ModGUID = "com.sellivira.logicalreplicator"; public const string ModName = "Logical Replicator"; public const string ModVersion = "1.1.3"; private readonly Harmony harmony = new Harmony("com.sellivira.logicalreplicator"); public static ManualLogSource ModLogger; public static ReplicatorPlugin Instance; public static ConfigEntry InstantBurnEnabled; public static ConfigEntry ToggleUiKey; public static ConfigEntry MassMultiplier; public static ConfigEntry EnableBurnGlow; public static ConfigEntry EnableSynthGlow; public static ConfigEntry SynthSoundVolume; public static ConfigEntry BurnSoundVolume; public static ConfigEntry UiPosition; public static ConfigEntry IsUiLocked; private void Awake() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) Instance = this; ModLogger = ((BaseUnityPlugin)this).Logger; InstantBurnEnabled = ((BaseUnityPlugin)this).Config.Bind("1. Разработка", "Мгновенное сжигание", false, "Отключает таймеры."); ToggleUiKey = ((BaseUnityPlugin)this).Config.Bind("2. Управление", "Хоткей интерфейса", new KeyboardShortcut((KeyCode)278, Array.Empty()), "Кнопка открытия окна репликатора."); MassMultiplier = ((BaseUnityPlugin)this).Config.Bind("3. Баланс", "Множитель массы", 2f, new ConfigDescription("Дюп-фактор: 1.0 = честно.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); EnableBurnGlow = ((BaseUnityPlugin)this).Config.Bind("4. Эффекты", "Свечение при абсорбции", true, "Включает бордовый источник света."); EnableSynthGlow = ((BaseUnityPlugin)this).Config.Bind("4. Эффекты", "Свечение при синтезе", true, "Включает циановый источник света."); SynthSoundVolume = ((BaseUnityPlugin)this).Config.Bind("4. Эффекты", "Громкость звука синтеза", 0.35f, new ConfigDescription("Громкость звука работы (0.0 - 1.0)", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); BurnSoundVolume = ((BaseUnityPlugin)this).Config.Bind("4. Эффекты", "Громкость звука сжигания", 0.8f, new ConfigDescription("Громкость звука костра (0.0 - 1.0)", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); UiPosition = ((BaseUnityPlugin)this).Config.Bind("5. Интерфейс", "Позиция окна", Vector2.zero, "Сохраненные координаты окна на экране."); IsUiLocked = ((BaseUnityPlugin)this).Config.Bind("5. Интерфейс", "Закрепить окно", false, "Блокирует перетаскивание окна."); ReplicatorShared.LoadAssetBundle(); harmony.PatchAll(); ModLogger.LogInfo((object)"Плагин Logical Replicator v1.1.3 инициализирован."); } private void Update() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Player.m_localPlayer == (Object)null)) { if ((Object)(object)ReplicatorVFX.Instance == (Object)null && (Object)(object)ReplicatorShared.Prefab != (Object)null) { ReplicatorVFX.AttachModelToPlayer(Player.m_localPlayer); } bool flag = false; KeyboardShortcut value = ToggleUiKey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && !Console.IsVisible() && !Chat.instance.HasFocus()) { ReplicatorUI.Toggle(); flag = true; } if (!flag && ReplicatorUI.IsOpen && (Object)(object)InventoryGui.instance != (Object)null && !InventoryGui.IsVisible()) { ReplicatorUI.ForceClose(); } ReplicatorUI.HandleInventoryClicks(); } } } public static class ReplicatorShared { public static GameObject Prefab; public static GameObject UiPrefab; public static GameObject BiomassCube; public static GameObject BiomassCrate; public static void LoadAssetBundle() { string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "replicator_assets"); if (!File.Exists(text)) { return; } AssetBundle val = AssetBundle.LoadFromFile(text); if (!((Object)(object)val != (Object)null)) { return; } GameObject[] array = val.LoadAllAssets(); foreach (GameObject val2 in array) { if ((Object)(object)val2.GetComponent() != (Object)null || ((Object)val2).name.Contains("UI")) { UiPrefab = val2; } else if (((Object)val2).name == "BiomassCube") { BiomassCube = val2; } else if (((Object)val2).name == "BiomassCrate") { BiomassCrate = val2; } else if ((Object)(object)val2.GetComponentInChildren() != (Object)null || (Object)(object)val2.GetComponentInChildren() != (Object)null) { Prefab = val2; } } if ((Object)(object)Prefab == (Object)null) { Prefab = val.LoadAllAssets()[0]; } InitializePrefab(BiomassCube); InitializePrefab(BiomassCrate); val.Unload(false); } private static void InitializePrefab(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return; } ItemDrop component = prefab.GetComponent(); if ((Object)(object)component != (Object)null && component.m_itemData != null) { component.m_itemData.m_dropPrefab = prefab; if (((Object)prefab).name == "BiomassCube") { component.m_itemData.m_shared.m_name = "Логический-Биомассивный куб"; component.m_itemData.m_shared.m_description = "Предмет, созданный Логическим Репликатором, отход весом 10 кг, но имеющий материальную ценность БМ 100."; } else if (((Object)prefab).name == "BiomassCrate") { component.m_itemData.m_shared.m_name = "Логический-Биомассивный ящик"; component.m_itemData.m_shared.m_description = "Огромный спрессованный контейнер биомассы. Вес 100 кг, материальная ценность БМ 1000."; } } int num = LayerMask.NameToLayer("item"); prefab.layer = ((num != -1) ? num : 12); if ((Object)(object)prefab.GetComponent() == (Object)null) { prefab.AddComponent(); } if ((Object)(object)prefab.GetComponent() == (Object)null) { prefab.AddComponent(); } if ((Object)(object)prefab.GetComponent() == (Object)null) { prefab.AddComponent(); } } public static void RegisterToZNetScene(ZNetScene zns) { if (!((Object)(object)zns == (Object)null)) { RegisterPrefabToZNetScene(zns, BiomassCube); RegisterPrefabToZNetScene(zns, BiomassCrate); } } public static void RegisterToObjectDB(ObjectDB odb) { if (!((Object)(object)odb == (Object)null)) { RegisterItemToObjectDB(odb, BiomassCube); RegisterItemToObjectDB(odb, BiomassCrate); } } private static void RegisterPrefabToZNetScene(ZNetScene zns, GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { if (!zns.m_prefabs.Contains(prefab)) { zns.m_prefabs.Add(prefab); } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); if (AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(zns) is Dictionary dictionary && !dictionary.ContainsKey(stableHashCode)) { dictionary[stableHashCode] = prefab; } } } private static void RegisterItemToObjectDB(ObjectDB odb, GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { if (!odb.m_items.Contains(prefab)) { odb.m_items.Add(prefab); } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); if (AccessTools.Field(typeof(ObjectDB), "m_itemByHash").GetValue(odb) is Dictionary dictionary && !dictionary.ContainsKey(stableHashCode)) { dictionary[stableHashCode] = prefab; } } } } public class DraggableUI : MonoBehaviour, IDragHandler, IEventSystemHandler, IEndDragHandler { public RectTransform target; public void OnDrag(PointerEventData eventData) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (!ReplicatorPlugin.IsUiLocked.Value) { Canvas val = (((Object)(object)InventoryGui.instance != (Object)null) ? ((Component)InventoryGui.instance).GetComponentInParent() : null); float num = (((Object)(object)val != (Object)null) ? val.scaleFactor : 1f); RectTransform obj = target; obj.anchoredPosition += eventData.delta / num; } } public void OnEndDrag(PointerEventData eventData) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (!ReplicatorPlugin.IsUiLocked.Value) { ReplicatorPlugin.UiPosition.Value = target.anchoredPosition; ((BaseUnityPlugin)ReplicatorPlugin.Instance).Config.Save(); } } } public static class ReplicatorUI { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__28_0; public static UnityAction <>9__28_1; public static UnityAction <>9__28_2; public static UnityAction <>9__28_3; public static UnityAction <>9__28_4; internal void b__28_0(string val) { if (int.TryParse(val, out var result)) { ReplicatorCore.SetAmount(result); } else { ReplicatorCore.SetAmount(1); } } internal void b__28_1() { ReplicatorPlugin.IsUiLocked.Value = !ReplicatorPlugin.IsUiLocked.Value; ((BaseUnityPlugin)ReplicatorPlugin.Instance).Config.Save(); UpdateLockButtonVisuals(); ReplicatorVFX.PlaySafeSound("sfx_gui_button"); } internal void b__28_2() { ReplicatorCore.ChangeAmount(1); } internal void b__28_3() { ReplicatorCore.ChangeAmount(-1); } internal void b__28_4(string q) { CurrentSearchQuery = q.ToLower(); UpdateGrid(); } } private static GameObject uiInstance; private static CanvasGroup uiCanvasGroup; public static Image BurnSlotImage; public static Image ItemIconImage; public static Button ActionButton; public static Text StatusText; public static Text EpmCounter; public static Slider ProgressBar; private static Transform gridContainer; private static GameObject itemTemplate; public static Button SynthesizeButton; public static Text SynthesisTimerText; public static Text SelectedNameText; public static Text AmountText; public static InputField searchBar; public static InputField amountInputField; public static string CurrentSearchQuery = ""; private static GameObject vanillaTooltipPrefab; public static bool IsOpen { get; private set; } = false; private static GameObject GetVanillaTooltipPrefab() { if ((Object)(object)vanillaTooltipPrefab != (Object)null) { return vanillaTooltipPrefab; } if ((Object)(object)InventoryGui.instance != (Object)null && (Object)(object)InventoryGui.instance.m_playerGrid != (Object)null) { GameObject elementPrefab = InventoryGui.instance.m_playerGrid.m_elementPrefab; if ((Object)(object)elementPrefab != (Object)null) { UITooltip component = elementPrefab.GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_tooltipPrefab != (Object)null) { vanillaTooltipPrefab = component.m_tooltipPrefab; return vanillaTooltipPrefab; } } } return null; } public static void ApplyTooltip(GameObject target, string topic, string text) { if ((Object)(object)target == (Object)null) { return; } GameObject val = GetVanillaTooltipPrefab(); if ((Object)(object)val == (Object)null) { UITooltip component = target.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } return; } UITooltip val2 = target.GetComponent(); if ((Object)(object)val2 == (Object)null) { val2 = target.AddComponent(); } val2.m_tooltipPrefab = val; val2.m_topic = topic; val2.m_text = text; } public static void RemoveTooltip(GameObject target) { if (!((Object)(object)target == (Object)null)) { UITooltip component = target.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } } } public static bool IsTyping() { bool flag = (Object)(object)searchBar != (Object)null && searchBar.isFocused; bool flag2 = (Object)(object)amountInputField != (Object)null && amountInputField.isFocused; return flag || flag2; } public static void Toggle() { //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ReplicatorShared.UiPrefab == (Object)null) { return; } if ((Object)(object)uiInstance == (Object)null) { if ((Object)(object)InventoryGui.instance == (Object)null) { return; } uiInstance = Object.Instantiate(ReplicatorShared.UiPrefab); uiInstance.SetActive(true); uiInstance.transform.SetParent(((Component)InventoryGui.instance).transform, false); GraphicRaycaster component = uiInstance.GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } CanvasScaler component2 = uiInstance.GetComponent(); if ((Object)(object)component2 != (Object)null) { Object.DestroyImmediate((Object)(object)component2); } Canvas component3 = uiInstance.GetComponent(); if ((Object)(object)component3 != (Object)null) { Object.DestroyImmediate((Object)(object)component3); } RectTransform component4 = uiInstance.GetComponent(); if ((Object)(object)component4 != (Object)null) { component4.anchorMin = Vector2.zero; component4.anchorMax = Vector2.one; component4.offsetMin = Vector2.zero; component4.offsetMax = Vector2.zero; ((Transform)component4).localScale = Vector3.one; } SetupReferences(); } IsOpen = !IsOpen; if ((Object)(object)uiCanvasGroup != (Object)null) { uiCanvasGroup.alpha = (IsOpen ? 1f : 0f); uiCanvasGroup.blocksRaycasts = IsOpen; uiCanvasGroup.interactable = IsOpen; } if (IsOpen) { UpdateGrid(); UpdateEpm(); UpdateLockButtonVisuals(); if ((Object)(object)InventoryGui.instance != (Object)null && !InventoryGui.IsVisible()) { InventoryGui.instance.Show((Container)null, 1); } if ((Object)(object)uiInstance != (Object)null && (Object)(object)InventoryGui.instance != (Object)null) { if ((Object)(object)InventoryGui.instance.m_splitPanel != (Object)null) { uiInstance.transform.SetSiblingIndex(((Component)InventoryGui.instance.m_splitPanel).transform.GetSiblingIndex()); } else { uiInstance.transform.SetAsLastSibling(); } } } else { ReplicatorCore.HandleClose(); } } public static void ForceClose() { if (IsOpen && !((Object)(object)uiCanvasGroup == (Object)null)) { IsOpen = false; uiCanvasGroup.alpha = 0f; uiCanvasGroup.blocksRaycasts = false; uiCanvasGroup.interactable = false; ReplicatorCore.HandleClose(); } } private static void SetupReferences() { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) //IL_0467: Expected O, but got Unknown //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Expected O, but got Unknown //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_0494: Expected O, but got Unknown //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Expected O, but got Unknown //IL_04e1: Unknown result type (might be due to invalid IL or missing references) //IL_04e6: Unknown result type (might be due to invalid IL or missing references) //IL_04ec: Expected O, but got Unknown //IL_0519: Unknown result type (might be due to invalid IL or missing references) //IL_051e: Unknown result type (might be due to invalid IL or missing references) //IL_0524: Expected O, but got Unknown uiCanvasGroup = uiInstance.GetComponent(); if ((Object)(object)uiCanvasGroup == (Object)null) { uiCanvasGroup = uiInstance.AddComponent(); } Transform val = uiInstance.transform.Find("MainPanel"); if ((Object)(object)val == (Object)null) { val = ((uiInstance.transform.childCount > 0) ? uiInstance.transform.GetChild(0) : uiInstance.transform); } if ((Object)(object)((Component)val).GetComponent() == (Object)null) { DraggableUI draggableUI = ((Component)val).gameObject.AddComponent(); draggableUI.target = (RectTransform)(object)((val is RectTransform) ? val : null); if (ReplicatorPlugin.UiPosition.Value != Vector2.zero) { draggableUI.target.anchoredPosition = ReplicatorPlugin.UiPosition.Value; } } Transform obj = FindChild(uiInstance.transform, "SlotBackground"); BurnSlotImage = ((obj != null) ? ((Component)obj).GetComponent() : null); Transform obj2 = FindChild(uiInstance.transform, "ItemIcon"); ItemIconImage = ((obj2 != null) ? ((Component)obj2).GetComponent() : null); Transform obj3 = FindChild(uiInstance.transform, "ActionButton"); ActionButton = ((obj3 != null) ? ((Component)obj3).GetComponent