using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using NebulaAPI;
using NebulaAPI.GameState;
using NebulaAPI.Interfaces;
using NebulaAPI.Networking;
using NebulaAPI.Packets;
using UnityEngine;
using UnityEngine.UI;
[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("DSPMinerMultiplier")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("DSPMinerMultiplier")]
[assembly: AssemblyTitle("DSPMinerMultiplier")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace DSPMinerMultiplier;
[BepInPlugin("com.byboy.dsp.minermultiplier", "DSP Miner Multiplier", "1.3.0")]
public class MinerMultiplierPlugin : BaseUnityPlugin
{
public const string PluginGuid = "com.byboy.dsp.minermultiplier";
public const string PluginName = "DSP Miner Multiplier";
public const string PluginVersion = "1.3.0";
internal static ManualLogSource Log;
public static float MiningMultiplier = 10f;
public static float PowerMultiplier = 1f;
internal static ConfigEntry<float> MiningMultiplierEntry;
private ConfigEntry<float> _miningMultiplier;
private ConfigEntry<KeyCode> _modifierKey;
private ConfigEntry<KeyCode> _toggleKey;
private MultiplierUI _ui;
private void Awake()
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Expected O, but got Unknown
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_0178: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
_miningMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "采矿倍率 MiningMultiplier", 10f, new ConfigDescription("采矿机的采矿速度倍率,范围 1 ~ 1000。耗电按 1~256 线性同步增长。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 1000f), Array.Empty<object>()));
_modifierKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkey", "修饰键 ModifierKey", (KeyCode)308, "与切换键组合使用的修饰键");
_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkey", "切换键 ToggleKey", (KeyCode)282, "与修饰键组合打开/关闭倍率面板");
ApplyMiningMultiplier(_miningMultiplier.Value);
MiningMultiplierEntry = _miningMultiplier;
_miningMultiplier.SettingChanged += delegate
{
if (Math.Abs(_miningMultiplier.Value - MiningMultiplier) > 0.001f)
{
ApplyMiningMultiplier(_miningMultiplier.Value);
}
};
Harmony val = new Harmony("com.byboy.dsp.minermultiplier");
val.PatchAll(typeof(MinerPatches));
val.PatchAll(typeof(DisplayPatches));
_ui = ((Component)this).gameObject.AddComponent<MultiplierUI>();
_ui.Init(_miningMultiplier, _modifierKey, _toggleKey);
InitNebula();
((BaseUnityPlugin)this).Config.Save();
((BaseUnityPlugin)this).Logger.LogInfo((object)(string.Format("{0} {1} 已加载,采矿 {2}x,耗电 {3:F2}x。", "DSP Miner Multiplier", "1.3.0", MiningMultiplier, PowerMultiplier) + $"按 {_modifierKey.Value}+{_toggleKey.Value} 打开倍率面板。" + (NebulaSync.Available ? "Nebula 联机同步已启用。" : "")));
}
private void InitNebula()
{
try
{
if (!Chainloader.PluginInfos.ContainsKey("dsp.nebula-multiplayer-api"))
{
return;
}
NebulaSync.Available = true;
NebulaModAPI.RegisterPackets(Assembly.GetExecutingAssembly());
NebulaModAPI.OnMultiplayerGameStarted = (Action)Delegate.Combine(NebulaModAPI.OnMultiplayerGameStarted, (Action)delegate
{
Log.LogInfo((object)$"联机游戏已开始 (主机={NebulaModAPI.MultiplayerSession.IsServer})");
if (NebulaModAPI.MultiplayerSession.IsServer)
{
NebulaSync.Broadcast();
}
else
{
Log.LogInfo((object)"等待主机同步采矿倍率…");
}
});
NebulaModAPI.OnPlayerJoinedGame = (Action<IPlayerData>)Delegate.Combine(NebulaModAPI.OnPlayerJoinedGame, (Action<IPlayerData>)delegate
{
if (NebulaModAPI.MultiplayerSession != null && NebulaModAPI.MultiplayerSession.IsServer)
{
NebulaSync.Broadcast();
}
});
NebulaModAPI.OnMultiplayerGameEnded = (Action)Delegate.Combine(NebulaModAPI.OnMultiplayerGameEnded, (Action)delegate
{
Log.LogInfo((object)"联机游戏已结束,倍率恢复为本机配置。");
ApplyMiningMultiplier(_miningMultiplier.Value);
});
Log.LogInfo((object)"Nebula API 已接入,联机倍率同步可用。");
}
catch (Exception ex)
{
Log.LogWarning((object)("初始化 Nebula 同步失败(将以单机模式运行): " + ex.Message));
}
}
public static void ApplyMiningMultiplier(float value)
{
value = ((value < 1f) ? 1f : ((value > 1000f) ? 1000f : value));
MiningMultiplier = value;
PowerMultiplier = 1f + (value - 1f) * 255f / 999f;
}
public static void SetMultiplier(ConfigEntry<float> entry, float value)
{
ApplyMiningMultiplier(value);
entry.Value = MiningMultiplier;
NebulaSync.Broadcast();
}
}
public class MinerMultiplierPacket : INetSerializable
{
public float MiningMultiplier { get; set; }
public void Serialize(INetDataWriter writer)
{
writer.Put(MiningMultiplier);
}
public void Deserialize(INetDataReader reader)
{
MiningMultiplier = reader.GetFloat();
}
}
[RegisterPacketProcessor]
public class MinerMultiplierPacketProcessor : BasePacketProcessor<MinerMultiplierPacket>
{
public override void ProcessPacket(MinerMultiplierPacket packet, INebulaConnection conn)
{
MinerMultiplierPlugin.Log.LogInfo((object)$"收到主机同步的采矿倍率: {packet.MiningMultiplier}x");
MinerMultiplierPlugin.ApplyMiningMultiplier(packet.MiningMultiplier);
}
}
public static class NebulaSync
{
public static bool Available { get; set; }
public static void Broadcast()
{
if (!Available || !NebulaModAPI.IsMultiplayerActive)
{
return;
}
try
{
IMultiplayerSession multiplayerSession = NebulaModAPI.MultiplayerSession;
if (multiplayerSession != null && multiplayerSession.IsServer)
{
multiplayerSession.Network.SendPacket<MinerMultiplierPacket>(new MinerMultiplierPacket
{
MiningMultiplier = MinerMultiplierPlugin.MiningMultiplier
});
MinerMultiplierPlugin.Log.LogInfo((object)$"已向客户端广播采矿倍率: {MinerMultiplierPlugin.MiningMultiplier}x");
}
}
catch (Exception ex)
{
MinerMultiplierPlugin.Log.LogWarning((object)("广播倍率失败: " + ex.Message));
}
}
}
[HarmonyPatch]
public static class MinerPatches
{
[HarmonyPatch(typeof(MinerComponent), "InternalUpdate")]
[HarmonyPrefix]
public static void InternalUpdate_Prefix(ref float miningSpeed)
{
miningSpeed *= MinerMultiplierPlugin.MiningMultiplier;
}
[HarmonyPatch(typeof(MinerComponent), "SetPCState")]
[HarmonyPostfix]
public static void SetPCState_Postfix(MinerComponent __instance, PowerConsumerComponent[] pcPool)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: 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)
if (__instance.pcId > 0 && pcPool != null && __instance.pcId < pcPool.Length)
{
double requiredEnergy = (double)(__instance.speedDamper * (float)__instance.speed * (float)__instance.speed) / 100000000.0 * (double)MinerMultiplierPlugin.PowerMultiplier;
((PowerConsumerComponent)(ref pcPool[__instance.pcId])).SetRequiredEnergy(requiredEnergy);
}
}
}
[HarmonyPatch]
public static class DisplayPatches
{
private static readonly Regex LeadingNumber = new Regex("^(\\d+(?:\\.\\d+)?)");
private static readonly Regex NumberBeforeSlashMin = new Regex("(\\d+(?:\\.\\d+)?)( ?)/min");
private static readonly Regex IntegerPerMin = new Regex("^(\\d+) /min$");
private static int _propIndex;
public static string ScaleLeadingNumber(string text, float factor)
{
if (string.IsNullOrEmpty(text) || factor == 1f)
{
return null;
}
Match match = LeadingNumber.Match(text);
if (!match.Success || !float.TryParse(match.Groups[1].Value, out var result))
{
return null;
}
float num = result * factor;
string text2 = ((num >= 100f) ? num.ToString("0") : num.ToString("0.#"));
return text.Substring(0, match.Groups[1].Index) + text2 + text.Substring(match.Groups[1].Index + match.Groups[1].Length);
}
public static string ScalePerMinNumber(string text, float factor)
{
if (string.IsNullOrEmpty(text) || factor == 1f)
{
return null;
}
return NumberBeforeSlashMin.Replace(text, delegate(Match m)
{
if (!float.TryParse(m.Groups[1].Value, out var result))
{
return m.Value;
}
float num = result * factor;
return ((num >= 100f) ? num.ToString("0.#") : num.ToString("0.##")) + m.Groups[2].Value + "/min";
});
}
[HarmonyPatch(typeof(UIMinerWindow), "_OnUpdate")]
[HarmonyPostfix]
public static void UIMinerWindow_OnUpdate_Postfix(UIMinerWindow __instance)
{
Text speedText = __instance.speedText;
if (!((Object)(object)speedText == (Object)null))
{
string text = ScaleLeadingNumber(speedText.text, MinerMultiplierPlugin.MiningMultiplier);
if (text != null)
{
speedText.text = text;
}
}
}
[HarmonyPatch(typeof(BuildingGizmo), "SetGizmoDesc")]
[HarmonyPostfix]
public static void BuildingGizmo_SetGizmoDesc_Postfix(BuildingGizmo __instance)
{
TextMesh buildText = __instance.buildText;
if (!((Object)(object)buildText == (Object)null))
{
string text = ScalePerMinNumber(buildText.text, MinerMultiplierPlugin.MiningMultiplier);
if (text != null)
{
buildText.text = text;
}
}
}
[HarmonyPatch(typeof(ItemProto), "GetPropValue")]
[HarmonyPrefix]
public static void ItemProto_GetPropValue_Prefix(int index)
{
_propIndex = index;
}
[HarmonyPatch(typeof(ItemProto), "GetPropValue")]
[HarmonyPostfix]
public static void ItemProto_GetPropValue_Postfix(ItemProto __instance, ref string __result)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
if (_propIndex == 19 && __result != null && __instance.prefabDesc != null && (int)__instance.prefabDesc.minerType != 0)
{
string text = ScaleLeadingNumber(__result, MinerMultiplierPlugin.MiningMultiplier);
if (text != null)
{
__result = text;
}
}
}
[HarmonyPatch(typeof(UIVeinCollectorPanel), "_OnUpdate")]
[HarmonyPostfix]
public static void UIVeinCollectorPanel_OnUpdate_Postfix(UIVeinCollectorPanel __instance)
{
object? obj = AccessTools.Field(typeof(UIVeinCollectorPanel), "speedText")?.GetValue(__instance);
Text val = (Text)((obj is Text) ? obj : null);
string text = ScaleLeadingNumber((val != null) ? val.text : null, MinerMultiplierPlugin.MiningMultiplier);
if (text != null && (Object)(object)val != (Object)null)
{
val.text = text;
}
}
[HarmonyPatch(typeof(UIControlPanelVeinCollectorPanel), "_OnUpdate")]
[HarmonyPostfix]
public static void UIControlPanelVeinCollectorPanel_OnUpdate_Postfix(UIControlPanelVeinCollectorPanel __instance)
{
object? obj = AccessTools.Field(typeof(UIControlPanelVeinCollectorPanel), "speedText")?.GetValue(__instance);
Text val = (Text)((obj is Text) ? obj : null);
string text = ScaleLeadingNumber((val != null) ? val.text : null, MinerMultiplierPlugin.MiningMultiplier);
if (text != null && (Object)(object)val != (Object)null)
{
val.text = text;
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPostfix]
public static void ResAmountEntry_ValueString_Postfix(UIResAmountEntry __instance, string value)
{
if (!string.IsNullOrEmpty(value))
{
Match match = IntegerPerMin.Match(value);
if (match.Success && float.TryParse(match.Groups[1].Value, out var result))
{
float num = result * MinerMultiplierPlugin.MiningMultiplier;
__instance.valueText.text = $"{num:0} /min";
}
}
}
[HarmonyPatch(typeof(UIControlPanelAdvancedMinerEntry), "_OnUpdate")]
[HarmonyPostfix]
public static void AdvancedMinerEntry_OnUpdate_Postfix(UIControlPanelAdvancedMinerEntry __instance)
{
Text maxChargePowerValue = __instance.maxChargePowerValue;
if (!((Object)(object)maxChargePowerValue == (Object)null))
{
string text = ScaleLeadingNumber(maxChargePowerValue.text, MinerMultiplierPlugin.PowerMultiplier);
if (text != null)
{
maxChargePowerValue.text = text;
}
}
}
}
public class MultiplierUI : MonoBehaviour
{
private ConfigEntry<float> _miningMultiplier;
private ConfigEntry<KeyCode> _modifierKey;
private ConfigEntry<KeyCode> _toggleKey;
private bool _open;
private Rect _windowRect = new Rect(80f, 80f, 340f, 200f);
private string _input = "10";
private bool _inputDirty = true;
public void Init(ConfigEntry<float> miningMultiplier, ConfigEntry<KeyCode> modifierKey, ConfigEntry<KeyCode> toggleKey)
{
_miningMultiplier = miningMultiplier;
_modifierKey = modifierKey;
_toggleKey = toggleKey;
_input = miningMultiplier.Value.ToString("0.#");
}
private void Update()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
bool key = Input.GetKey(_modifierKey.Value);
bool keyDown = Input.GetKeyDown(_toggleKey.Value);
if (key && keyDown)
{
_open = !_open;
if (_open)
{
_input = MinerMultiplierPlugin.MiningMultiplier.ToString("0.#");
_inputDirty = true;
}
}
}
private void OnGUI()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
if (_open)
{
_windowRect = GUILayout.Window(19792, _windowRect, new WindowFunction(DrawWindow), "DSP 采矿倍率 (Alt+F1)", Array.Empty<GUILayoutOption>());
}
}
private void DrawWindow(int id)
{
//IL_020a: Unknown result type (might be due to invalid IL or missing references)
GUILayout.Space(6f);
GUILayout.Label($"当前采矿倍率:{MinerMultiplierPlugin.MiningMultiplier:0.#}x 耗电:{MinerMultiplierPlugin.PowerMultiplier:0.##}x", Array.Empty<GUILayoutOption>());
float num = GUILayout.HorizontalSlider(MinerMultiplierPlugin.MiningMultiplier, 1f, 1000f, Array.Empty<GUILayoutOption>());
if (Math.Abs(num - MinerMultiplierPlugin.MiningMultiplier) > 0.001f)
{
MinerMultiplierPlugin.SetMultiplier(_miningMultiplier, num);
_input = MinerMultiplierPlugin.MiningMultiplier.ToString("0.#");
_inputDirty = true;
}
GUILayout.Space(4f);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("1x", Array.Empty<GUILayoutOption>()))
{
Apply(1f);
}
if (GUILayout.Button("10x", Array.Empty<GUILayoutOption>()))
{
Apply(10f);
}
if (GUILayout.Button("100x", Array.Empty<GUILayoutOption>()))
{
Apply(100f);
}
if (GUILayout.Button("500x", Array.Empty<GUILayoutOption>()))
{
Apply(500f);
}
if (GUILayout.Button("1000x", Array.Empty<GUILayoutOption>()))
{
Apply(1000f);
}
GUILayout.EndHorizontal();
GUILayout.Space(4f);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayout.Label("手动输入:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
string text = GUILayout.TextField(_inputDirty ? _input : _input, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
if (!string.Equals(text, _input))
{
_input = text;
_inputDirty = false;
}
if (GUILayout.Button("应用", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }) && float.TryParse(_input, out var result))
{
Apply(result);
}
GUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label("拖动滑条或点按钮即时生效,并自动保存到配置文件。", Array.Empty<GUILayoutOption>());
GUI.DragWindow(new Rect(0f, 0f, 10000f, 24f));
}
private void Apply(float v)
{
MinerMultiplierPlugin.SetMultiplier(_miningMultiplier, v);
_input = MinerMultiplierPlugin.MiningMultiplier.ToString("0.#");
_inputDirty = true;
}
}