using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("WZC_AutoExtractionPoint")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("WZC_AutoExtractionPoint")]
[assembly: AssemblyTitle("WZC_AutoExtractionPoint")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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;
}
}
}
[BepInPlugin("wzc.repo.auto_extraction_point", "A.WZC_AutoExtractionPoint", "1.0.0")]
public sealed class WzcAutoExtractionPointPlugin : BaseUnityPlugin
{
public const string PluginGuid = "wzc.repo.auto_extraction_point";
public const string PluginName = "A.WZC_AutoExtractionPoint";
public const string PluginVersion = "1.0.0";
private const string InfoSection = "模组信息";
private const string FeatureSection = "A.自动开启提取点";
private const string PriorityFarthest = "最远";
private const string PriorityNearest = "最近";
private static readonly FieldInfo RoundDirectorExtractionPointListField = typeof(RoundDirector).GetField("extractionPointList", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly FieldInfo RoundDirectorExtractionPointActiveField = typeof(RoundDirector).GetField("extractionPointActive", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly FieldInfo RoundDirectorExtractionPointsCompletedField = typeof(RoundDirector).GetField("extractionPointsCompleted", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly FieldInfo RoundDirectorExtractionPointsField = typeof(RoundDirector).GetField("extractionPoints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly FieldInfo RoundDirectorAllExtractionPointsCompletedField = typeof(RoundDirector).GetField("allExtractionPointsCompleted", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly FieldInfo RoundDirectorExtractionPointCurrentField = typeof(RoundDirector).GetField("extractionPointCurrent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly FieldInfo ExtractionPointCurrentStateField = typeof(ExtractionPoint).GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly FieldInfo ExtractionPointIsShopField = typeof(ExtractionPoint).GetField("isShop", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly FieldInfo ExtractionPointIsLockedField = typeof(ExtractionPoint).GetField("isLocked", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly MethodInfo ExtractionPointOnClickMethod = typeof(ExtractionPoint).GetMethod("OnClick", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private readonly Dictionary<int, float> extractionDistanceMap = new Dictionary<int, float>();
private ConfigEntry<string> moduleNameInfo;
private ConfigEntry<string> moduleVersionInfo;
private ConfigEntry<string> contactInfo;
private ConfigEntry<bool> featureEnabled;
private ConfigEntry<string> priorityMode;
private Harmony harmony;
private RoundDirector lastRoundDirector;
private bool firstExtractionPointCaptured;
private Vector3 firstExtractionPointPosition;
private bool activationQueued;
private ExtractionPoint queuedExtractionPoint;
private float queuedActivationTime;
private float nextAutoScanTime;
private const float AutoScanInterval = 0.75f;
private const float QueuedActivationDelay = 0.35f;
public static WzcAutoExtractionPointPlugin Instance { get; private set; }
private void Awake()
{
Instance = this;
BindConfig();
ApplyPatches();
((BaseUnityPlugin)this).Logger.LogInfo((object)"WZC_AutoExtractionPoint loaded.");
}
private void Update()
{
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)RoundDirector.instance != (Object)(object)lastRoundDirector)
{
lastRoundDirector = RoundDirector.instance;
ResetRuntimeState();
}
if (!IsHostAuthority())
{
return;
}
if (!IsFeatureEnabled())
{
ResetQueuedActivation();
}
else if ((Object)(object)RoundDirector.instance == (Object)null || !SemiFunc.RunIsLevel())
{
ResetQueuedActivation();
}
else if (!activationQueued)
{
TryAutoQueueNextExtractionPoint();
}
else
{
if (Time.time < queuedActivationTime || GetExtractionPointActive(RoundDirector.instance) || GetAllExtractionPointsCompleted(RoundDirector.instance))
{
return;
}
ExtractionPoint val = queuedExtractionPoint;
ResetQueuedActivation();
if (!((Object)(object)val == (Object)null))
{
State val3 = (State)((ExtractionPointCurrentStateField?.GetValue(val) is State val2) ? ((int)val2) : 0);
object obj = ExtractionPointIsLockedField?.GetValue(val);
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
bool flag2 = (byte)((uint)num & (flag ? 1u : 0u)) != 0;
try
{
ExtractionPointOnClickMethod?.Invoke(val, null);
((BaseUnityPlugin)this).Logger.LogInfo((object)$"Auto activated next extraction point via native OnClick. Candidate={((Object)val).name}, State={val3}, Locked={flag2}");
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to auto activate next extraction point: " + ex.GetType().Name + ": " + ex.Message));
}
}
}
}
private void OnDestroy()
{
if (harmony != null)
{
harmony.UnpatchSelf();
harmony = null;
}
if (Instance == this)
{
Instance = null;
}
}
private void BindConfig()
{
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Expected O, but got Unknown
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Expected O, but got Unknown
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Expected O, but got Unknown
//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: Expected O, but got Unknown
moduleNameInfo = ((BaseUnityPlugin)this).Config.Bind<string>("模组信息", "模组名称", "WZC_自动开启提取点", new ConfigDescription("当前模组的中文名称。此处仅用于显示,不影响功能。", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 1000,
CustomDrawer = DrawInfo,
ReadOnly = true
}
}));
moduleNameInfo.Value = "WZC_自动开启提取点";
moduleVersionInfo = ((BaseUnityPlugin)this).Config.Bind<string>("模组信息", "模组版本号", "1.0.0", new ConfigDescription("当前模组版本号。此处仅用于显示,不影响功能。", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 990,
CustomDrawer = DrawInfo,
ReadOnly = true
}
}));
moduleVersionInfo.Value = "1.0.0";
contactInfo = ((BaseUnityPlugin)this).Config.Bind<string>("模组信息", "REPO交流QQ群", "824639225", new ConfigDescription("REPO 游戏交流、BUG 反馈、优化建议、功能请求请加 QQ 群。此处仅用于显示,不影响功能。", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 980,
CustomDrawer = DrawInfo,
ReadOnly = true
}
}));
contactInfo.Value = "824639225";
featureEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("A.自动开启提取点", "启用", true, ConfigDescriptionWithOrder("只需主机安装即可生效。第一个提取点仍然手动开启,完成后自动开启下一个提取点。", 900));
priorityMode = ((BaseUnityPlugin)this).Config.Bind<string>("A.自动开启提取点", "打开提取点优先", "最远", new ConfigDescription("以第一个手动开启的提取点作为距离映射原点,后续自动开启下一个提取点时按最远或最近优先。默认最远。", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "最远", "最近" }), new object[1]
{
new ConfigurationManagerAttributes
{
Order = 890
}
}));
}
private void ApplyPatches()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Expected O, but got Unknown
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
harmony = new Harmony("wzc.repo.auto_extraction_point.patch");
MethodInfo methodInfo = AccessTools.Method(typeof(RoundDirector), "ExtractionPointsUnlockRPC", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(ExtractionPoint), "OnClick", (Type[])null, (Type[])null);
if (methodInfo2 != null)
{
harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(WzcAutoExtractionPointPlugin), "ExtractionPointOnClickPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
if (methodInfo != null)
{
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(WzcAutoExtractionPointPlugin), "ExtractionPointsUnlockRpcPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
private bool IsFeatureEnabled()
{
if (featureEnabled != null)
{
return featureEnabled.Value;
}
return false;
}
private static bool IsHostAuthority()
{
try
{
return SemiFunc.IsMasterClientOrSingleplayer();
}
catch
{
return false;
}
}
private void ResetRuntimeState()
{
//IL_0013: 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)
extractionDistanceMap.Clear();
firstExtractionPointCaptured = false;
firstExtractionPointPosition = Vector3.zero;
ResetQueuedActivation();
nextAutoScanTime = 0f;
}
private void ResetQueuedActivation()
{
activationQueued = false;
queuedExtractionPoint = null;
queuedActivationTime = 0f;
}
private void TryAutoQueueNextExtractionPoint()
{
if ((Object)(object)RoundDirector.instance == (Object)null || Time.time < nextAutoScanTime)
{
return;
}
nextAutoScanTime = Time.time + 0.75f;
if (firstExtractionPointCaptured)
{
int extractionPointsCompleted = GetExtractionPointsCompleted(RoundDirector.instance);
int extractionPointsTotal = GetExtractionPointsTotal(RoundDirector.instance);
if (extractionPointsCompleted > 0 && extractionPointsTotal > 0 && extractionPointsCompleted < extractionPointsTotal && !GetAllExtractionPointsCompleted(RoundDirector.instance) && !GetExtractionPointActive(RoundDirector.instance))
{
QueueNextExtractionPointActivation(fromUnlockEvent: false);
}
}
}
private void CaptureFirstExtractionPoint(ExtractionPoint extractionPoint)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
if (!firstExtractionPointCaptured && !((Object)(object)extractionPoint == (Object)null))
{
firstExtractionPointCaptured = true;
firstExtractionPointPosition = ((Component)extractionPoint).transform.position;
RebuildDistanceMap();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Captured first manual extraction point as distance origin.");
}
}
private void RebuildDistanceMap()
{
//IL_003c: 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)
extractionDistanceMap.Clear();
List<ExtractionPoint> extractionPoints = GetExtractionPoints();
for (int i = 0; i < extractionPoints.Count; i++)
{
ExtractionPoint val = extractionPoints[i];
if (!((Object)(object)val == (Object)null) && !IsShopExtractionPoint(val))
{
extractionDistanceMap[((Object)val).GetInstanceID()] = Vector3.Distance(firstExtractionPointPosition, ((Component)val).transform.position);
}
}
}
private List<ExtractionPoint> GetExtractionPoints()
{
List<ExtractionPoint> list = new List<ExtractionPoint>();
if ((Object)(object)RoundDirector.instance == (Object)null || !(RoundDirectorExtractionPointListField?.GetValue(RoundDirector.instance) is List<GameObject> list2))
{
return list;
}
for (int i = 0; i < list2.Count; i++)
{
GameObject val = list2[i];
if (!((Object)(object)val == (Object)null))
{
ExtractionPoint component = val.GetComponent<ExtractionPoint>();
if ((Object)(object)component != (Object)null)
{
list.Add(component);
}
}
}
return list;
}
private ExtractionPoint ChooseNextExtractionPoint()
{
List<ExtractionPoint> extractionPoints = GetExtractionPoints();
ExtractionPoint val = null;
float num = 0f;
bool flag = string.Equals(priorityMode?.Value, "最近", StringComparison.Ordinal);
for (int i = 0; i < extractionPoints.Count; i++)
{
ExtractionPoint val2 = extractionPoints[i];
if (!IsCandidateExtractionPoint(val2))
{
continue;
}
float mappedDistance = GetMappedDistance(val2);
if ((Object)(object)val == (Object)null)
{
val = val2;
num = mappedDistance;
}
else if (flag)
{
if (mappedDistance < num)
{
val = val2;
num = mappedDistance;
}
}
else if (mappedDistance > num)
{
val = val2;
num = mappedDistance;
}
}
return val;
}
private bool IsCandidateExtractionPoint(ExtractionPoint extractionPoint)
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Invalid comparison between Unknown and I4
if ((Object)(object)extractionPoint == (Object)null || IsShopExtractionPoint(extractionPoint))
{
return false;
}
if (!(ExtractionPointCurrentStateField?.GetValue(extractionPoint) is State val))
{
return false;
}
return (int)val == 1;
}
private float GetMappedDistance(ExtractionPoint extractionPoint)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)extractionPoint == (Object)null)
{
return float.MaxValue;
}
int instanceID = ((Object)extractionPoint).GetInstanceID();
if (extractionDistanceMap.TryGetValue(instanceID, out var value))
{
return value;
}
value = Vector3.Distance(firstExtractionPointPosition, ((Component)extractionPoint).transform.position);
extractionDistanceMap[instanceID] = value;
return value;
}
private bool GetExtractionPointActive(RoundDirector roundDirector)
{
bool flag = default(bool);
int num;
if ((Object)(object)roundDirector != (Object)null && RoundDirectorExtractionPointActiveField != null)
{
object value = RoundDirectorExtractionPointActiveField.GetValue(roundDirector);
if (value is bool)
{
flag = (bool)value;
num = 1;
}
else
{
num = 0;
}
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
private int GetExtractionPointsCompleted(RoundDirector roundDirector)
{
if ((Object)(object)roundDirector != (Object)null)
{
object obj = RoundDirectorExtractionPointsCompletedField?.GetValue(roundDirector);
if (obj is int)
{
return (int)obj;
}
}
return 0;
}
private int GetExtractionPointsTotal(RoundDirector roundDirector)
{
if ((Object)(object)roundDirector != (Object)null && RoundDirectorExtractionPointsField?.GetValue(roundDirector) is int num && num > 0)
{
return num;
}
int num2 = 0;
List<ExtractionPoint> extractionPoints = GetExtractionPoints();
for (int i = 0; i < extractionPoints.Count; i++)
{
if ((Object)(object)extractionPoints[i] != (Object)null)
{
num2++;
}
}
return num2;
}
private bool GetAllExtractionPointsCompleted(RoundDirector roundDirector)
{
bool flag = default(bool);
int num;
if ((Object)(object)roundDirector != (Object)null && RoundDirectorAllExtractionPointsCompletedField != null)
{
object value = RoundDirectorAllExtractionPointsCompletedField.GetValue(roundDirector);
if (value is bool)
{
flag = (bool)value;
num = 1;
}
else
{
num = 0;
}
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
private static bool IsShopExtractionPoint(ExtractionPoint extractionPoint)
{
bool flag = default(bool);
int num;
if ((Object)(object)extractionPoint != (Object)null && ExtractionPointIsShopField != null)
{
object value = ExtractionPointIsShopField.GetValue(extractionPoint);
if (value is bool)
{
flag = (bool)value;
num = 1;
}
else
{
num = 0;
}
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
private void QueueNextExtractionPointActivation(bool fromUnlockEvent)
{
if (!firstExtractionPointCaptured || (Object)(object)RoundDirector.instance == (Object)null)
{
return;
}
ExtractionPoint val = ChooseNextExtractionPoint();
if (!((Object)(object)val == (Object)null))
{
if (ExtractionPointOnClickMethod == null)
{
float mappedDistance = GetMappedDistance(val);
((BaseUnityPlugin)this).Logger.LogWarning((object)$"Failed to queue next extraction point because native OnClick method was unavailable. Candidate={((Object)val).name}, Distance={mappedDistance:0.##}");
}
else if (!activationQueued || !((Object)(object)queuedExtractionPoint == (Object)(object)val))
{
queuedExtractionPoint = val;
queuedActivationTime = Time.time + 0.35f;
activationQueued = true;
((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Queued next extraction point auto activation. Source={0}, Priority={1}, Candidate={2}, Distance={3:0.##}", fromUnlockEvent ? "UnlockEvent" : "PeriodicScan", priorityMode?.Value, ((Object)val).name, GetMappedDistance(val)));
}
}
}
private void DrawInfo(ConfigEntryBase entry)
{
GUILayout.Label(entry.BoxedValue?.ToString() ?? string.Empty, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
}
private static ConfigDescription ConfigDescriptionWithOrder(string description, int order)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected O, but got Unknown
return new ConfigDescription(description, (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = order
}
});
}
private static void ExtractionPointOnClickPostfix(ExtractionPoint __instance)
{
WzcAutoExtractionPointPlugin instance = Instance;
if (!((Object)(object)instance == (Object)null) && instance.IsFeatureEnabled() && IsHostAuthority() && !((Object)(object)__instance == (Object)null) && !((Object)(object)RoundDirector.instance == (Object)null) && SemiFunc.RunIsLevel() && !instance.firstExtractionPointCaptured && instance.GetExtractionPointsCompleted(RoundDirector.instance) <= 0)
{
((BaseUnityPlugin)instance).Logger.LogInfo((object)"ExtractionPoint.OnClick observed on first extraction point candidate.");
instance.CaptureFirstExtractionPoint(__instance);
}
}
private static void ExtractionPointsUnlockRpcPostfix(RoundDirector __instance)
{
WzcAutoExtractionPointPlugin instance = Instance;
if (!((Object)(object)instance == (Object)null) && instance.IsFeatureEnabled() && IsHostAuthority() && !((Object)(object)__instance == (Object)null) && SemiFunc.RunIsLevel())
{
int extractionPointsCompleted = instance.GetExtractionPointsCompleted(__instance);
int extractionPointsTotal = instance.GetExtractionPointsTotal(__instance);
bool allExtractionPointsCompleted = instance.GetAllExtractionPointsCompleted(__instance);
((BaseUnityPlugin)instance).Logger.LogInfo((object)$"Extraction points unlocked. Completed={extractionPointsCompleted}, Total={extractionPointsTotal}, Active={instance.GetExtractionPointActive(__instance)}, AllCompleted={allExtractionPointsCompleted}");
if (!(extractionPointsCompleted <= 0 || extractionPointsTotal <= 0 || extractionPointsCompleted >= extractionPointsTotal || allExtractionPointsCompleted))
{
instance.QueueNextExtractionPointActivation(fromUnlockEvent: true);
}
}
}
}
internal sealed class ConfigurationManagerAttributes
{
public bool? ShowRangeAsPercent;
public Action<ConfigEntryBase> CustomDrawer;
public bool? Browsable;
public string Category;
public object DefaultValue;
public bool? HideDefaultButton;
public bool? HideSettingName;
public string Description;
public string DispName;
public int? Order;
public bool? ReadOnly;
public bool? IsAdvanced;
}