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;
}
}
}