Decompiled source of PlanetVeinBurier v1.0.1

plugins\PlanetVeinBurier.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NebulaAPI;
using NebulaAPI.GameState;
using NebulaAPI.Networking;
using NebulaAPI.Packets;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("PlanetVeinBurier")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("PlanetVeinBurier")]
[assembly: AssemblyTitle("PlanetVeinBurier")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PlanetVeinBurier
{
	internal static class NebulaCompat
	{
		public static bool Active { get; private set; }

		public static bool IsClientFlag { get; private set; }

		public static int LocalPlayerId
		{
			get
			{
				try
				{
					IMultiplayerSession multiplayerSession = NebulaModAPI.MultiplayerSession;
					return (((multiplayerSession != null) ? multiplayerSession.LocalPlayer : null) == null) ? (-1) : multiplayerSession.LocalPlayer.Id;
				}
				catch
				{
					return -1;
				}
			}
		}

		public static string LocalPlayerName
		{
			get
			{
				try
				{
					IMultiplayerSession multiplayerSession = NebulaModAPI.MultiplayerSession;
					object obj;
					if (multiplayerSession == null)
					{
						obj = null;
					}
					else
					{
						ILocalPlayer localPlayer = multiplayerSession.LocalPlayer;
						if (localPlayer == null)
						{
							obj = null;
						}
						else
						{
							IPlayerData data = localPlayer.Data;
							obj = ((data != null) ? data.Username : null);
						}
					}
					string text = (string)obj;
					return string.IsNullOrEmpty(text) ? "玩家" : text;
				}
				catch
				{
					return "玩家";
				}
			}
		}

		public static void Initialize()
		{
			try
			{
				NebulaModAPI.RegisterPackets(Assembly.GetExecutingAssembly());
				NebulaModAPI.OnMultiplayerGameStarted = (Action)Delegate.Combine(NebulaModAPI.OnMultiplayerGameStarted, new Action(OnMultiplayerGameStarted));
				NebulaModAPI.OnMultiplayerGameEnded = (Action)Delegate.Combine(NebulaModAPI.OnMultiplayerGameEnded, new Action(OnMultiplayerGameEnded));
				Plugin.Log.LogInfo((object)"[联机] 已检测到 Nebula,联机同步已就绪。");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"[联机] Nebula 兼容层初始化失败:{arg}");
			}
		}

		private static void OnMultiplayerGameStarted()
		{
			Active = NebulaModAPI.IsMultiplayerActive;
			IsClientFlag = Active && NebulaModAPI.MultiplayerSession.LocalPlayer.IsClient;
			Plugin.Log.LogInfo((object)("[联机] 对局开始(本机身份:" + (IsClientFlag ? "客户端" : "主机") + ")"));
		}

		private static void OnMultiplayerGameEnded()
		{
			Active = false;
			IsClientFlag = false;
			Plugin.Log.LogInfo((object)"[联机] 对局结束。");
		}

		public static void Broadcast(VeinReformPacket packet)
		{
			if (!Active || !Plugin.EnableBroadcast.Value)
			{
				return;
			}
			try
			{
				IMultiplayerSession multiplayerSession = NebulaModAPI.MultiplayerSession;
				if (((multiplayerSession != null) ? multiplayerSession.LocalPlayer : null) != null && multiplayerSession.LocalPlayer.IsClient)
				{
					multiplayerSession.Network.SendPacket<VeinReformPacket>(packet);
					Plugin.Log.LogInfo((object)string.Format("[联机] 已将动作发送给主机(行星 {0},{1})", packet.PlanetId, packet.IsReform ? "填埋" : "恢复"));
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"[联机] 广播动作失败:{arg}");
			}
		}

		public static void RelayToStar(VeinReformPacket packet, INebulaConnection sender)
		{
			if (!Active || !Plugin.EnableBroadcast.Value)
			{
				return;
			}
			try
			{
				INetworkProvider network = NebulaModAPI.MultiplayerSession.Network;
				int starId = packet.StarId;
				if (starId > 0)
				{
					if (sender != null)
					{
						network.SendPacketToStarExclude<VeinReformPacket>(packet, starId, sender);
					}
					else
					{
						network.SendPacketToStar<VeinReformPacket>(packet, starId);
					}
					Plugin.Log.LogInfo((object)$"[联机] 主机已把动作转发给星系 {starId} 内的其他玩家。");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"[联机] 主机转发失败:{arg}");
			}
		}

		public static bool IsLocalPlayer(int playerId)
		{
			if (!Active)
			{
				return false;
			}
			try
			{
				IMultiplayerSession multiplayerSession = NebulaModAPI.MultiplayerSession;
				if (((multiplayerSession != null) ? multiplayerSession.LocalPlayer : null) == null)
				{
					return false;
				}
				return multiplayerSession.LocalPlayer.Id == playerId;
			}
			catch
			{
				return false;
			}
		}
	}
	[BepInPlugin("planetveinburier", "Planet Vein Burier", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("DSPGAME.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "planetveinburier";

		public const string NAME = "Planet Vein Burier";

		public const string VERSION = "1.0.1";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		internal static ConfigEntry<KeyboardShortcut> ToggleKey;

		internal static ConfigEntry<int> GroundType;

		internal static ConfigEntry<int> GroundColor;

		internal static ConfigEntry<bool> EnableBroadcast;

		internal static ConfigEntry<int> DedupeWindowSeconds;

		private bool _updateErrorLogged;

		internal static string ToggleKeyDisplay => _toggleKeyName(ToggleKey.Value);

		private void Awake()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("快捷键", "一键填埋/恢复矿脉", new KeyboardShortcut((KeyCode)109, (KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)306,
				(KeyCode)304
			}), "在行星上按 Ctrl+Shift+M:第一次按=填埋全部矿脉,第二次按=恢复矿脉。可在本文件中改键。");
			GroundType = ((BaseUnityPlugin)this).Config.Bind<int>("改造", "地面类型", -1, new ConfigDescription("-1=自动保持当前地面外观(推荐);0=原生地面;其他值=沙盒改造界面的地面类型编号", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[17]
			{
				-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
				9, 10, 11, 12, 13, 14, 15
			}), Array.Empty<object>()));
			GroundColor = ((BaseUnityPlugin)this).Config.Bind<int>("改造", "地面颜色", -1, "-1=自动保持当前地面颜色(推荐);>=0 为沙盒改造界面的颜色编号");
			EnableBroadcast = ((BaseUnityPlugin)this).Config.Bind<bool>("联机", "广播动作", true, "联机时,填埋/恢复动作自动广播:客户端先发给主机,主机再广播给其他玩家。");
			DedupeWindowSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("联机", "去重窗口(秒)", 5, "同一行星在此时间窗口内执行过的相同动作不会被重复应用(防止 Nebula 原生包与本模组包重复叠加)。");
			_harmony = new Harmony("planetveinburier");
			_harmony.PatchAll(typeof(ReformObserverPatches));
			if (Chainloader.PluginInfos.ContainsKey("dsp.nebula-multiplayer"))
			{
				NebulaCompat.Initialize();
			}
			Log.LogInfo((object)("Planet Vein Burier v1.0.1 by 妙妙在路上 已加载,快捷键:" + ToggleKeyDisplay + "(配置文件:BepInEx/config/planetveinburier.cfg)"));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (GameMain.data == null)
				{
					return;
				}
				PlanetData localPlanet = GameMain.localPlanet;
				KeyboardShortcut value = ToggleKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					if (localPlanet?.factory == null)
					{
						Notify("需要降落到行星表面,才能填埋 / 恢复矿脉");
					}
					else
					{
						VeinReformService.ToggleCurrentPlanet();
					}
				}
			}
			catch (Exception arg)
			{
				if (!_updateErrorLogged)
				{
					_updateErrorLogged = true;
					Log.LogWarning((object)$"Update 异常(仅报告一次):{arg}");
				}
			}
		}

		internal static void Notify(string message)
		{
			Log.LogInfo((object)("[提示] " + message));
			try
			{
				UIRealtimeTip.Popup(message, false, 0);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("弹出原版提示失败:" + ex.Message));
			}
		}

		private static string _toggleKeyName(KeyboardShortcut k)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>();
			if (HasModifier(k, (KeyCode)306) || HasModifier(k, (KeyCode)305))
			{
				list.Add("Ctrl");
			}
			if (HasModifier(k, (KeyCode)304) || HasModifier(k, (KeyCode)303))
			{
				list.Add("Shift");
			}
			if (HasModifier(k, (KeyCode)308) || HasModifier(k, (KeyCode)307))
			{
				list.Add("Alt");
			}
			list.Add(((object)((KeyboardShortcut)(ref k)).MainKey/*cast due to .constrained prefix*/).ToString());
			return string.Join("+", list.ToArray());
		}

		private static bool HasModifier(KeyboardShortcut k, KeyCode code)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (((KeyboardShortcut)(ref k)).Modifiers == null)
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref k)).Modifiers)
			{
				if (modifier == code)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class ReformObserverPatches
	{
		[HarmonyPatch(typeof(PlanetFactory))]
		internal static class PlanetReformObserver
		{
			[HarmonyPostfix]
			[HarmonyPatch("PlanetReformAll")]
			public static void PlanetReformAll_Postfix(PlanetFactory __instance, int type, int color, bool bury)
			{
				VeinReformTracker.Record(__instance.planetId, isReform: true, type, color);
				if (bury)
				{
					VeinReformTracker.SetBuried(__instance.planetId, buried: true);
				}
			}

			[HarmonyPostfix]
			[HarmonyPatch("PlanetReformRevert")]
			public static void PlanetReformRevert_Postfix(PlanetFactory __instance)
			{
				VeinReformTracker.Record(__instance.planetId, isReform: false, 0, 0);
				VeinReformTracker.SetBuried(__instance.planetId, buried: false);
			}
		}
	}
	public class VeinReformPacket
	{
		public int PlanetId { get; set; }

		public bool IsReform { get; set; }

		public int ReformType { get; set; }

		public int ReformColor { get; set; }

		public int StarId { get; set; }

		public int OriginPlayerId { get; set; }

		public string PlayerName { get; set; }

		public VeinReformPacket()
		{
		}

		public VeinReformPacket(int planetId, bool isReform, int reformType, int reformColor)
		{
			PlanetId = planetId;
			IsReform = isReform;
			ReformType = reformType;
			ReformColor = reformColor;
			OriginPlayerId = NebulaCompat.LocalPlayerId;
			PlayerName = NebulaCompat.LocalPlayerName;
			if (GameMain.data != null && GameMain.localPlanet != null && GameMain.localPlanet.star != null)
			{
				StarId = GameMain.localPlanet.star.id;
			}
		}
	}
	[RegisterPacketProcessor]
	public class VeinReformPacketProcessor : BasePacketProcessor<VeinReformPacket>
	{
		public override void ProcessPacket(VeinReformPacket packet, INebulaConnection conn)
		{
			if (!NebulaCompat.IsLocalPlayer(packet.OriginPlayerId))
			{
				if (base.IsHost)
				{
					Plugin.Log.LogInfo((object)string.Format("[联机·主机] 收到 {0} 的动作:{1} 行星 {2}", packet.PlayerName, packet.IsReform ? "填埋" : "恢复", packet.PlanetId));
					VeinReformService.ApplyRemote(packet);
					NebulaCompat.RelayToStar(packet, conn);
				}
				else
				{
					Plugin.Log.LogInfo((object)string.Format("[联机·客户端] 收到 {0} 的动作:{1} 行星 {2}", packet.PlayerName, packet.IsReform ? "填埋" : "恢复", packet.PlanetId));
					VeinReformService.ApplyRemote(packet);
				}
			}
		}
	}
	internal static class VeinReformService
	{
		public static void ToggleCurrentPlanet()
		{
			PlanetData localPlanet = GameMain.localPlanet;
			PlanetFactory val = localPlanet?.factory;
			if (val != null)
			{
				if (!VeinReformTracker.IsBuried(val))
				{
					BuryVeins(localPlanet, val);
				}
				else
				{
					RestoreVeins(localPlanet, val);
				}
			}
		}

		public static void BuryVeins(PlanetData planet, PlanetFactory factory)
		{
			var (num, num2) = ResolveStyle(factory);
			Plugin.Log.LogInfo((object)$"[填埋] {planet.displayName} (id={planet.id}) PlanetReformAll(type={num}, color={num2}, bury=true)");
			factory.PlanetReformAll(num, num2, true);
			VeinReformTracker.SetBuried(planet.id, buried: true);
			Plugin.Notify("已填埋「" + planet.displayName + "」的矿脉,再按 " + Plugin.ToggleKeyDisplay + " 恢复矿脉");
			NebulaCompat.Broadcast(new VeinReformPacket(planet.id, isReform: true, num, num2));
		}

		public static void RestoreVeins(PlanetData planet, PlanetFactory factory)
		{
			Plugin.Log.LogInfo((object)$"[恢复] {planet.displayName} (id={planet.id}) PlanetReformRevert()");
			factory.PlanetReformRevert();
			VeinReformTracker.SetBuried(planet.id, buried: false);
			Plugin.Notify("已恢复「" + planet.displayName + "」的矿脉,再按 " + Plugin.ToggleKeyDisplay + " 填埋矿脉");
			NebulaCompat.Broadcast(new VeinReformPacket(planet.id, isReform: false, 0, 0));
		}

		public static void ApplyRemote(VeinReformPacket packet)
		{
			PlanetFactory val = GameMain.galaxy.PlanetById(packet.PlanetId)?.factory;
			if (val == null)
			{
				Plugin.Log.LogDebug((object)$"[联机] 行星 {packet.PlanetId} 未加载,跳过即时应用(加载时自动同步)。");
			}
			else if (!VeinReformTracker.HasRecent(packet.PlanetId, packet.IsReform, packet.ReformType, packet.ReformColor))
			{
				if (packet.IsReform)
				{
					val.PlanetReformAll(packet.ReformType, packet.ReformColor, true);
					VeinReformTracker.SetBuried(packet.PlanetId, buried: true);
				}
				else
				{
					val.PlanetReformRevert();
					VeinReformTracker.SetBuried(packet.PlanetId, buried: false);
				}
			}
		}

		private static (int type, int color) ResolveStyle(PlanetFactory factory)
		{
			int value = Plugin.GroundType.Value;
			int value2 = Plugin.GroundColor.Value;
			if (value >= 0 && value2 >= 0)
			{
				return (type: value, color: value2);
			}
			PlatformSystem platformSystem = factory.platformSystem;
			if (platformSystem?.reformData == null)
			{
				return (type: (value >= 0) ? value : 0, color: (value2 >= 0) ? value2 : 0);
			}
			int num = platformSystem.reformData.Length;
			if (num <= 0)
			{
				return (type: 0, color: 0);
			}
			int num2 = 0;
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			for (int i = 0; i < num; i++)
			{
				int reformType = platformSystem.GetReformType(i);
				int reformColor = platformSystem.GetReformColor(i);
				if (reformType != 0 || reformColor != 0)
				{
					num2++;
					int key = reformType * 1000 + reformColor;
					dictionary.TryGetValue(key, out var value3);
					dictionary[key] = value3 + 1;
				}
			}
			if (num2 * 2 > num && dictionary.Count > 0)
			{
				int num3 = 0;
				int num4 = 0;
				foreach (KeyValuePair<int, int> item in dictionary)
				{
					if (item.Value > num4)
					{
						num4 = item.Value;
						num3 = item.Key;
					}
				}
				return (type: num3 / 1000, color: num3 % 1000);
			}
			return (type: (value >= 0) ? value : 0, color: (value2 >= 0) ? value2 : 0);
		}
	}
	internal static class VeinReformTracker
	{
		private struct Entry
		{
			public bool IsReform;

			public int Type;

			public int Color;

			public DateTime At;
		}

		private static readonly Dictionary<int, Entry> Recent = new Dictionary<int, Entry>();

		private static readonly Dictionary<int, bool> BuriedState = new Dictionary<int, bool>();

		public static void Record(int planetId, bool isReform, int type, int color)
		{
			Recent[planetId] = new Entry
			{
				IsReform = isReform,
				Type = type,
				Color = color,
				At = DateTime.UtcNow
			};
		}

		public static void SetBuried(int planetId, bool buried)
		{
			BuriedState[planetId] = buried;
		}

		public static bool HasRecent(int planetId, bool isReform, int type, int color)
		{
			if (!Recent.TryGetValue(planetId, out var value))
			{
				return false;
			}
			if (value.IsReform != isReform)
			{
				return false;
			}
			if (DateTime.UtcNow - value.At > TimeSpan.FromSeconds(Plugin.DedupeWindowSeconds.Value))
			{
				return false;
			}
			if (!isReform)
			{
				return true;
			}
			if (value.Type == type)
			{
				return value.Color == color;
			}
			return false;
		}

		public static bool IsBuried(PlanetFactory factory)
		{
			if (((factory != null) ? factory.planet : null) == null)
			{
				return false;
			}
			int id = factory.planet.id;
			if (BuriedState.TryGetValue(id, out var value))
			{
				return value;
			}
			return IsPlanetReformed(factory);
		}

		public static bool IsPlanetReformed(PlanetFactory factory)
		{
			PlatformSystem val = factory?.platformSystem;
			if (val?.reformData == null)
			{
				return false;
			}
			byte[] reformData = val.reformData;
			for (int i = 0; i < reformData.Length; i++)
			{
				if (reformData[i] != 0)
				{
					return true;
				}
			}
			return false;
		}
	}
}