using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Kai")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("REPOrt")]
[assembly: AssemblyTitle("REPOrt")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[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;
}
}
}
namespace REPOrt
{
public static class DeliveryTracker
{
private class StationSnapshot
{
public string StationName;
public int HaulGoal;
public int HaulTotal;
public DateTime Time;
public List<ExtractedItem> ExtractedItems { get; set; }
}
private class StationRuntime
{
public string StationName;
public int HaulGoal;
public int HaulTotal;
public DateTime LastUpdate;
public StationRuntime(string name)
{
StationName = name;
}
}
[HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "DestroyObject")]
private class Patch_DestroyObject
{
private static void Prefix(PhysGrabObjectImpactDetector __instance, bool effects)
{
if ((Object)(object)__instance?.valuableObject != (Object)null)
{
int id = ((Object)__instance.valuableObject).GetInstanceID();
int num = _haulList.RemoveAll((ExtractedItem i) => i.InstanceId == id);
REPOrt.VLog($"[REPOrt] ForceRemove (Destroy): {((Object)__instance.valuableObject).name}, ID={id}, Removed={num}");
}
}
}
[HarmonyPatch(typeof(ValuableObject), "AddToDollarHaulList")]
private class Patch_AddToDollarHaulList
{
private static void Postfix(ValuableObject __instance)
{
ExtractedItem extractedItem = new ExtractedItem
{
Name = ((Object)__instance).name,
Value = (int)__instance.dollarValueCurrent,
InstanceId = ((Object)__instance).GetInstanceID()
};
_haulList.Add(extractedItem);
REPOrt.VLog($"[REPOrt] HaulList Add: {extractedItem.Name}, Value={extractedItem.Value}");
}
}
[HarmonyPatch(typeof(ValuableObject), "RemoveFromDollarHaulList")]
private class Patch_RemoveFromDollarHaulList
{
private static void Postfix(ValuableObject __instance)
{
int id = ((Object)__instance).GetInstanceID();
int num = _haulList.RemoveAll((ExtractedItem i) => i.InstanceId == id);
REPOrt.VLog($"[REPOrt] HaulList Remove: {((Object)__instance).name}, ID={id}, Removed={num}");
}
}
private static int _stationCounter = 0;
private static readonly Dictionary<string, StationSnapshot> _confirmed = new Dictionary<string, StationSnapshot>();
private static readonly Dictionary<string, StationRuntime> _runtimes = new Dictionary<string, StationRuntime>();
private static readonly List<ExtractedItem> _haulList = new List<ExtractedItem>();
public static IReadOnlyDictionary<string, StationDeliveryInfo> Confirmed => _confirmed.ToDictionary<KeyValuePair<string, StationSnapshot>, string, StationDeliveryInfo>((KeyValuePair<string, StationSnapshot> kv) => kv.Key, (KeyValuePair<string, StationSnapshot> kv) => new StationDeliveryInfo
{
Value = 0,
Time = kv.Value.Time.ToString("o"),
ExtractedItems = new List<ExtractedItem>(),
HaulGoal = kv.Value.HaulGoal,
HaulTotal = kv.Value.HaulTotal,
UnknownSigned = 0
});
public static int GetDeliveredValue()
{
int num = 0;
foreach (KeyValuePair<string, StationSnapshot> item in _confirmed)
{
num += item.Value.HaulTotal;
}
return num;
}
public static void MarkComplete(string stationName, int goal, int haulTotal)
{
string text = $"{stationName}_{++_stationCounter}";
List<ExtractedItem> list = _haulList.ToList();
int num = list.Sum((ExtractedItem i) => i.Value);
int num2 = num - haulTotal;
StationSnapshot value = new StationSnapshot
{
StationName = text,
HaulGoal = goal,
HaulTotal = haulTotal,
Time = DateTime.UtcNow,
ExtractedItems = list
};
_confirmed[text] = value;
REPOrt.VLog("[REPOrt] Snapshot frozen (Complete): " + text + ", " + $"Goal={goal}, Total={haulTotal}, Value={num}, Unknown={num2}, Items={list.Count}");
_haulList.Clear();
}
public static Dictionary<string, StationDeliveryInfo> Flush()
{
Dictionary<string, StationDeliveryInfo> dictionary = new Dictionary<string, StationDeliveryInfo>();
foreach (KeyValuePair<string, StationSnapshot> item in _confirmed)
{
StationSnapshot value = item.Value;
dictionary[item.Key] = new StationDeliveryInfo
{
Value = (item.Value.ExtractedItems?.Sum((ExtractedItem i) => i.Value) ?? 0),
Time = item.Value.Time.ToString("o"),
ExtractedItems = (item.Value.ExtractedItems ?? new List<ExtractedItem>()),
HaulGoal = item.Value.HaulGoal,
HaulTotal = item.Value.HaulTotal,
UnknownSigned = (item.Value.ExtractedItems?.Sum((ExtractedItem i) => i.Value) ?? 0) - item.Value.HaulTotal
};
}
REPOrt.VLog("[REPOrt] Delivery dump: " + JsonConvert.SerializeObject((object)dictionary, (Formatting)1));
Reset();
return dictionary;
}
public static void Reset()
{
_confirmed.Clear();
_runtimes.Clear();
_stationCounter = 0;
REPOrt.VLog("[REPOrt] DeliveryTracker Reset()");
}
public static void Observe(ExtractionPoint ep, string source)
{
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Expected I4, but got Unknown
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
string name = ((Object)ep).name;
int value = Traverse.Create((object)ep).Field<int>("haulGoal").Value;
int value2 = Traverse.Create((object)ep).Field<int>("haulCurrent").Value;
int value3 = Traverse.Create((object)ep).Field<int>("haulPrevious").Value;
State value4 = Traverse.Create((object)ep).Field<State>("currentState").Value;
REPOrt.VLog($"[REPOrt] Station={name}, Goal={value}, Current={value2}, Previous={value3}, Source={source}, State={value4}");
switch (value4 - 4)
{
case 0:
case 2:
case 4:
REPOrt.VLog($"[REPOrt] Snapshot candidate: {name} (state={value4})");
break;
case 1:
if (_confirmed.Remove(name))
{
REPOrt.VLog("[REPOrt] Snapshot discarded (Cancel): " + name);
}
break;
case 3:
break;
}
}
}
[HarmonyPatch(typeof(ExtractionPoint), "StateSet")]
internal class Patch_ExtractionPoint_StateSet
{
private static void Prefix(ExtractionPoint __instance, State newState)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: 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_0053: Unknown result type (might be due to invalid IL or missing references)
int value = Traverse.Create((object)__instance).Field<int>("haulCurrent").Value;
int value2 = Traverse.Create((object)__instance).Field<int>("haulPrevious").Value;
State value3 = Traverse.Create((object)__instance).Field<State>("currentState").Value;
REPOrt.VLog($"[REPOrt] (Prefix) {((Object)__instance).name} {value3} -> {newState}, " + $"Current={value}, Previous={value2}");
}
private static void Postfix(ExtractionPoint __instance, State newState)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Invalid comparison between Unknown and I4
DeliveryTracker.Observe(__instance, "StateSet");
if ((int)newState == 7)
{
int value = Traverse.Create((object)__instance).Field<int>("haulGoal").Value;
int value2 = Traverse.Create((object)__instance).Field<int>("haulCurrent").Value;
DeliveryTracker.MarkComplete(((Object)__instance).name, value, value2);
}
}
}
[HarmonyPatch(typeof(ExtractionPoint), "StateSetRPC")]
internal class Patch_ExtractionPoint_StateSetRPC
{
private static void Postfix(ExtractionPoint __instance, State state)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Invalid comparison between Unknown and I4
DeliveryTracker.Observe(__instance, "StateSetRPC");
if ((int)state == 7)
{
int value = Traverse.Create((object)__instance).Field<int>("haulGoal").Value;
int value2 = Traverse.Create((object)__instance).Field<int>("haulCurrent").Value;
}
}
}
public static class DestroyedTracker
{
private static HashSet<int> destroyedIDs = new HashSet<int>();
private static Dictionary<int, int> degradedMap = new Dictionary<int, int>();
public static int DestroyedLost = 0;
public static void Reset()
{
DestroyedLost = 0;
destroyedIDs.Clear();
degradedMap.Clear();
}
public static void RecordBreak(ValuableObject obj, float valueLost)
{
if ((Object)(object)obj == (Object)null)
{
return;
}
int instanceID = ((Object)obj).GetInstanceID();
int num = Mathf.RoundToInt(valueLost);
if (num > 0)
{
if (!degradedMap.ContainsKey(instanceID))
{
degradedMap[instanceID] = 0;
}
degradedMap[instanceID] += num;
REPOrt.Logger.LogInfo((object)$"[REPOrt] Break: {((Object)obj).name} degraded +{num}, totalDegraded={degradedMap[instanceID]}");
}
}
public static void RecordDestroy(ValuableObject obj)
{
if (!((Object)(object)obj == (Object)null))
{
int instanceID = ((Object)obj).GetInstanceID();
if (!destroyedIDs.Contains(instanceID))
{
destroyedIDs.Add(instanceID);
int num = Mathf.RoundToInt(obj.dollarValueOriginal);
int num2 = (degradedMap.ContainsKey(instanceID) ? degradedMap[instanceID] : 0);
int num3 = Mathf.Max(0, num - num2);
DestroyedLost += num2 + num3;
REPOrt.Logger.LogInfo((object)$"[REPOrt] Destroy: {((Object)obj).name} lost {num2}+{num3}={num2 + num3}, total={DestroyedLost}");
degradedMap.Remove(instanceID);
}
}
}
public static int CalcLost()
{
int num = DestroyedLost;
foreach (KeyValuePair<int, int> item in degradedMap)
{
num += item.Value;
}
REPOrt.Logger.LogInfo((object)$"[REPOrt] CalcLost: TotalLost={num}");
return num;
}
}
[HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "Break")]
internal class Patch_PhysGrabObjectImpactDetector_Break
{
private static void Prefix(PhysGrabObjectImpactDetector __instance, float valueLost, Vector3 _contactPoint, int breakLevel, bool _forceBreak)
{
if ((Object)(object)__instance?.valuableObject != (Object)null)
{
DestroyedTracker.RecordBreak(__instance.valuableObject, valueLost);
}
}
}
[HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "DestroyObject")]
internal class Patch_PhysGrabObjectImpactDetector_DestroyObject
{
private static void Prefix(PhysGrabObjectImpactDetector __instance, bool effects)
{
if ((Object)(object)__instance?.valuableObject != (Object)null)
{
DestroyedTracker.RecordDestroy(__instance.valuableObject);
}
}
}
[HarmonyPatch(typeof(EnemyHealth), "Death")]
internal class Patch_EnemyHealth_Death
{
[HarmonyPostfix]
private static void Post_Death(EnemyHealth __instance)
{
EnemyKillTracker.RegisterKillFromHealth(__instance, "Death");
}
}
[HarmonyPatch(typeof(EnemyHealth), "DeathRPC")]
internal class Patch_EnemyHealth_DeathRPC
{
[HarmonyPostfix]
private static void Post_DeathRPC(EnemyHealth __instance)
{
EnemyKillTracker.RegisterKillFromHealth(__instance, "DeathRPC");
}
}
public static class EnemyKillTracker
{
public static readonly List<EnemyKillRecord> KillRecords = new List<EnemyKillRecord>();
private static readonly Dictionary<int, DateTime> LastKilled = new Dictionary<int, DateTime>();
private static readonly TimeSpan DuplicateThreshold = TimeSpan.FromSeconds(2.0);
private static readonly TimeSpan EarlyDeathThreshold = TimeSpan.FromSeconds(10.0);
public static DateTime StageStartTime { get; set; } = DateTime.MinValue;
public static void Reset()
{
KillRecords.Clear();
LastKilled.Clear();
}
public static void Reset(DateTime stageStart)
{
KillRecords.Clear();
LastKilled.Clear();
StageStartTime = stageStart;
}
public static void RegisterKillFromHealth(EnemyHealth health, string source)
{
if (!((Object)(object)health == (Object)null) && !((Object)(object)health.enemy == (Object)null))
{
Enemy enemy = health.enemy;
DateTime utcNow = DateTime.UtcNow;
int instanceID = ((Object)((Component)enemy).gameObject).GetInstanceID();
if (StageStartTime != DateTime.MinValue && utcNow - StageStartTime < EarlyDeathThreshold)
{
REPOrt.Logger.LogDebug((object)$"[REPOrt] Ignored early kill (<10s): {((Object)enemy).name}, ID={((Object)((Component)enemy).gameObject).GetInstanceID()}");
return;
}
EnemySpawnRecord value;
string type = ((!EnemySpawnTracker.SpawnedRecords.TryGetValue(instanceID, out value)) ? (((Object)(object)enemy.EnemyParent != (Object)null) ? ((Object)enemy.EnemyParent).name.Replace("(Clone)", "") : ((Object)((Component)enemy).gameObject).name.Replace("(Clone)", "")) : value.Type);
EnemyKillRecord enemyKillRecord = new EnemyKillRecord
{
InstanceId = instanceID,
Type = type,
Time = DateTime.UtcNow.ToString("o"),
KilledBy = "Unknown"
};
RegisterKill(enemyKillRecord);
REPOrt.Logger.LogInfo((object)$"[REPOrt] Enemy killed ({source}): {enemyKillRecord.Type}, ID={enemyKillRecord.InstanceId}");
}
}
public static List<EnemyKillRecord> ToList()
{
return KillRecords.Select((EnemyKillRecord r) => new EnemyKillRecord
{
InstanceId = r.InstanceId,
Type = r.Type,
Time = r.Time,
KilledBy = r.KilledBy
}).ToList();
}
public static void RegisterKill(EnemyKillRecord rec)
{
if (LastKilled.TryGetValue(rec.InstanceId, out var value) && DateTime.UtcNow - value < DuplicateThreshold)
{
REPOrt.Logger.LogDebug((object)$"[REPOrt] Duplicate kill ignored: {rec.Type}, ID={rec.InstanceId}");
return;
}
KillRecords.Add(rec);
LastKilled[rec.InstanceId] = DateTime.UtcNow;
REPOrt.Logger.LogDebug((object)$"[REPOrt] Saved EnemyKill: {rec.Type}, ID={rec.InstanceId}, Time={rec.Time}");
}
}
[HarmonyPatch(typeof(Enemy))]
internal class Patch_Enemy_Spawn
{
[HarmonyPostfix]
[HarmonyPatch("Spawn")]
private static void Post_Spawn(Enemy __instance)
{
if ((Object)(object)__instance != (Object)null)
{
EnemySpawnTracker.RegisterSpawn(__instance);
}
}
}
[HarmonyPatch(typeof(EnemyDirector))]
internal class Patch_EnemyDirector_PickEnemies
{
[HarmonyPostfix]
[HarmonyPatch("PickEnemies")]
private static void Post_PickEnemies(List<EnemySetup> _enemiesList)
{
if (_enemiesList != null && _enemiesList.Count > 0)
{
EnemySpawnTracker.RegisterExpected(_enemiesList);
REPOrt.Logger.LogInfo((object)("[REPOrt] Registered expected enemies: " + string.Join(", ", _enemiesList.Select((EnemySetup s) => ((s != null) ? ((Object)s).name : null) ?? "null"))));
}
}
}
[HarmonyPatch(typeof(RunManager))]
internal class Patch_RunManager_SetRunLevel
{
[HarmonyPostfix]
[HarmonyPatch("SetRunLevel")]
private static void Post_SetRunLevel()
{
EnemySpawnTracker.Reset();
REPOrt.Logger.LogInfo((object)"[REPOrt] EnemySpawnTracker reset at stage start");
}
}
public static class EnemySpawnTracker
{
public static readonly Dictionary<int, EnemySpawnRecord> SpawnedRecords = new Dictionary<int, EnemySpawnRecord>();
public static readonly List<string> ExpectedNames = new List<string>();
public static void Reset()
{
SpawnedRecords.Clear();
ExpectedNames.Clear();
}
public static void RegisterExpected(List<EnemySetup> setups)
{
foreach (EnemySetup setup in setups)
{
if ((Object)(object)setup == (Object)null)
{
continue;
}
if (((Object)setup).name.StartsWith("Enemy Group"))
{
foreach (GameObject spawnObject in setup.spawnObjects)
{
if ((Object)(object)spawnObject != (Object)null)
{
ExpectedNames.Add(((Object)spawnObject).name.Replace("(Clone)", ""));
}
}
}
else
{
ExpectedNames.Add(((Object)setup).name);
}
}
}
public static void RegisterSpawn(Enemy enemy)
{
int instanceID = ((Object)((Component)enemy).gameObject).GetInstanceID();
string text = (((Object)(object)enemy.EnemyParent != (Object)null) ? ((Object)enemy.EnemyParent).name.Replace("(Clone)", "") : ((Object)((Component)enemy).gameObject).name.Replace("(Clone)", ""));
EnemySpawnRecord value = new EnemySpawnRecord
{
InstanceId = instanceID,
Type = text
};
if (!SpawnedRecords.ContainsKey(instanceID))
{
SpawnedRecords[instanceID] = value;
REPOrt.Logger.LogInfo((object)$"[REPOrt] Saved EnemySpawn: {text}, ID={instanceID}");
}
else
{
REPOrt.Logger.LogDebug((object)$"[REPOrt] Duplicate spawn ignored: {text}, ID={instanceID}");
}
}
public static List<EnemySpawnRecord> ToList()
{
return SpawnedRecords.Values.ToList();
}
}
public static class ModDetector
{
public static bool IsModded { get; private set; }
public static List<string> DetectedMods { get; private set; } = new List<string>();
public static void ScanMods()
{
try
{
DetectedMods.Clear();
foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
{
PluginInfo value = pluginInfo.Value;
if (!(value.Metadata.GUID == "Kai.REPOrt"))
{
DetectedMods.Add(value.Metadata.Name);
}
}
string path = Path.Combine(Paths.BepInExRootPath, "plugins");
if (Directory.Exists(path))
{
string[] files = Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories);
foreach (string path2 in files)
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path2);
if (!fileNameWithoutExtension.Equals("Kai-REPOrt", StringComparison.OrdinalIgnoreCase) && !fileNameWithoutExtension.Equals("REPOrt", StringComparison.OrdinalIgnoreCase) && !DetectedMods.Contains(fileNameWithoutExtension))
{
DetectedMods.Add(fileNameWithoutExtension);
}
}
string[] directories = Directory.GetDirectories(path);
foreach (string path3 in directories)
{
string fileName = Path.GetFileName(path3);
if (!fileName.Equals("Kai-REPOrt", StringComparison.OrdinalIgnoreCase) && !fileName.Equals("REPOrt", StringComparison.OrdinalIgnoreCase) && !DetectedMods.Contains(fileName))
{
DetectedMods.Add(fileName);
}
}
}
IsModded = DetectedMods.Count > 0;
REPOrt.Logger.LogInfo((object)$"[REPOrt] Mod scan complete. IsModded={IsModded}, Count={DetectedMods.Count}");
}
catch (Exception arg)
{
REPOrt.Logger.LogError((object)$"[REPOrt] Mod scan failed: {arg}");
}
}
}
[HarmonyPatch(typeof(LevelGenerator), "Generate")]
public static class Patch_LevelGenerator
{
[HarmonyPostfix]
public static void OnLevelGenerated(LevelGenerator __instance)
{
try
{
Level levelCurrent = RunManager.instance.levelCurrent;
if ((Object)(object)levelCurrent == (Object)null)
{
REPOrt.Logger.LogWarning((object)"[REPOrt] LevelGenerator.Generate called, but levelCurrent is null");
return;
}
string name = ((Object)levelCurrent).name;
string mapName;
string text = StageUtil.DetectStageType(name, out mapName);
if (text == null)
{
REPOrt.Logger.LogInfo((object)("[REPOrt] Ignored scene: " + name));
return;
}
REPOrt.Logger.LogInfo((object)("[REPOrt] Level started: " + name + " -> StageType=" + text + ", MapName=" + mapName));
StageRecord rec = new StageRecord
{
StageName = text,
LevelNum = 0,
StartedAt = DateTime.UtcNow.ToString("o"),
EndedAt = DateTime.UtcNow.ToString("o"),
MapName = mapName
};
REPOrtSave.AddStageRecord(text, rec);
if (text == "GameOver")
{
REPOrtSave.FinalizeSession();
}
}
catch (Exception arg)
{
REPOrt.Logger.LogError((object)$"[REPOrt] Patch_LevelGenerator error: {arg}");
}
}
}
[HarmonyPatch(typeof(SceneManager))]
public static class Patch_SceneManager
{
[HarmonyPostfix]
[HarmonyPatch(typeof(SceneManager), "Internal_ActiveSceneChanged")]
public static void ActiveSceneChanged(Scene previousActiveScene, Scene newActiveScene)
{
string name = ((Scene)(ref newActiveScene)).name;
string mapName;
string text = StageUtil.DetectStageType(name, out mapName);
if (text == null)
{
REPOrt.Logger.LogInfo((object)("[REPOrt] Ignored scene: " + name));
return;
}
if (!REPOrtSave.HasSession)
{
string runSessionId = $"REPO_SAVE_{DateTime.Now:yyyy_MM_dd_HH_mm_ss}";
REPOrtSave.StartOrAttachSession(runSessionId);
}
REPOrt.Logger.LogInfo((object)("[REPOrt] Level started: " + name + " -> StageType=" + text + ", MapName=" + mapName));
StageRecord rec = new StageRecord
{
StageName = text,
LevelNum = 0,
StartedAt = DateTime.UtcNow.ToString("o"),
EndedAt = DateTime.UtcNow.ToString("o"),
MapName = mapName
};
REPOrtSave.AddStageRecord(text, rec);
if (text == "GameOver")
{
REPOrtSave.FinalizeSession();
}
}
}
[HarmonyPatch(typeof(StatsManager), "SaveGame")]
internal class StatsManager_SaveGame_Patch
{
private static void Prefix(string fileName)
{
try
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
REPOrtSave.StartOrAttachSession(fileNameWithoutExtension);
REPOrt.Logger.LogInfo((object)("[REPOrt] SaveGame hooked, session id = " + fileNameWithoutExtension));
}
catch (Exception arg)
{
REPOrt.Logger.LogError((object)$"[REPOrt] Error in SaveGame patch: {arg}");
}
}
}
[HarmonyPatch(typeof(StatsManager), "LoadGame")]
internal class StatsManager_LoadGame_Patch
{
private static void Prefix(string fileName)
{
try
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
REPOrtSave.StartOrAttachSession(fileNameWithoutExtension);
REPOrtSave.UpdateModInfo();
REPOrt.Logger.LogInfo((object)("[REPOrt] LoadGame hooked, session id = " + fileNameWithoutExtension));
}
catch (Exception arg)
{
REPOrt.Logger.LogError((object)$"[REPOrt] Error in LoadGame patch: {arg}");
}
}
}
public static class PlayerTracker
{
private static readonly string[] UpgradeKeys = new string[11]
{
"playerUpgradeHealth", "playerUpgradeStamina", "playerUpgradeExtraJump", "playerUpgradeLaunch", "playerUpgradeMapPlayerCount", "playerUpgradeSpeed", "playerUpgradeStrength", "playerUpgradeThrow", "playerUpgradeRange", "playerUpgradeCrouchRest",
"playerUpgradeTumbleWings"
};
public static void RecordPlayers(StageRecord record)
{
StatsManager instance = StatsManager.instance;
if ((Object)(object)instance == (Object)null)
{
return;
}
foreach (KeyValuePair<string, string> playerName in instance.playerNames)
{
string key = playerName.Key;
string value = playerName.Value;
Dictionary<string, int> dictionary = instance.FetchPlayerUpgrades(key);
Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
if (dictionary != null)
{
foreach (KeyValuePair<string, int> item2 in dictionary)
{
string text = (item2.Key.StartsWith("playerUpgrade") ? item2.Key.Substring("playerUpgrade".Length) : item2.Key);
dictionary2[text] = item2.Value;
REPOrt.Logger.LogInfo((object)$"[REPOrt] Upgrade {value}: {text} = {item2.Value}");
}
}
else
{
REPOrt.Logger.LogInfo((object)("[REPOrt] No upgrades for " + value));
}
PlayerSnapshot item = new PlayerSnapshot
{
Name = value,
Upgrades = dictionary2
};
record.Players.Add(item);
}
}
}
[BepInPlugin("Kai.REPOrt", "REPOrt", "1.15.1")]
public class REPOrt : BaseUnityPlugin
{
internal static bool VerboseDeliveryLog;
internal static bool DeliveryLiteMode;
private static string _lastConfirmedStageType;
private static string _lastMapName;
internal static REPOrt Instance { get; private set; }
internal static ManualLogSource Logger => Instance._logger;
private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;
internal Harmony? Harmony { get; set; }
internal static void VLog(string msg)
{
if (VerboseDeliveryLog)
{
Logger.LogInfo((object)msg);
}
}
private void Awake()
{
Instance = this;
((Component)this).gameObject.transform.parent = null;
((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
Patch();
SceneManager.activeSceneChanged += OnActiveSceneChanged;
ModDetector.ScanMods();
REPOrtSave.CleanupOrphanSessions();
Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
}
private void OnEnable()
{
SceneManager.activeSceneChanged += OnActiveSceneChanged;
}
private void OnDisable()
{
SceneManager.activeSceneChanged -= OnActiveSceneChanged;
}
private void OnActiveSceneChanged(Scene prev, Scene next)
{
string mapName;
string text = StageUtil.DetectStageType(((Scene)(ref next)).name, out mapName);
if (text == null)
{
Logger.LogInfo((object)("[REPOrt] Ignored scene: " + ((Scene)(ref next)).name));
return;
}
Logger.LogInfo((object)("[REPOrt] Level started: " + ((Scene)(ref next)).name + " -> StageType=" + text + ", MapName=" + mapName));
if (!string.IsNullOrEmpty(_lastConfirmedStageType))
{
Logger.LogInfo((object)("[REPOrt] Closing previous stage: " + _lastConfirmedStageType + " -> " + text));
REPOrtSave.MarkPreviousStage(_lastConfirmedStageType, text);
}
if (!REPOrtSave.HasSession)
{
string runSessionId = $"REPO_SAVE_{DateTime.Now:yyyy_MM_dd_HH_mm_ss}";
REPOrtSave.StartOrAttachSession(runSessionId);
}
else
{
Logger.LogInfo((object)"[REPOrt] Continuing existing session");
}
StageRecord rec = new StageRecord
{
StageName = text,
StartedAt = DateTime.UtcNow.ToString("o"),
EndedAt = DateTime.UtcNow.ToString("o"),
MapName = mapName
};
REPOrtSave.AddStageRecord(text, rec);
if (string.Equals(text, "GameOver", StringComparison.OrdinalIgnoreCase))
{
REPOrtSave.FinalizeSession();
_lastConfirmedStageType = null;
}
else
{
_lastConfirmedStageType = text;
_lastMapName = mapName;
}
if (string.Equals(text, "Main", StringComparison.OrdinalIgnoreCase))
{
EnemyKillTracker.Reset(DateTime.UtcNow);
EnemySpawnTracker.Reset();
DestroyedTracker.Reset();
DeliveryTracker.Reset();
Logger.LogInfo((object)"[REPOrt] EnemyKillTracker reset at Main start");
}
Dictionary<string, StationDeliveryInfo> dictionary = DeliveryTracker.Flush();
Logger.LogInfo((object)("[REPOrt] Delivery dump: " + JsonConvert.SerializeObject((object)dictionary, (Formatting)1)));
}
internal void Patch()
{
//IL_0019: 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_0020: Expected O, but got Unknown
//IL_0025: Expected O, but got Unknown
if (Harmony == null)
{
Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
Harmony val2 = val;
Harmony = val;
}
Harmony.PatchAll();
}
internal void Unpatch()
{
Harmony? harmony = Harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
private void Update()
{
}
}
public static class REPOrtSave
{
private static RunSession _current;
private static string _dir;
private static string _currentPath;
public static bool HasSession => _current != null;
public static void StartOrAttachSession(string runSessionId)
{
_dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "..\\LocalLow\\semiwork\\Repo\\REPOrtGallery", runSessionId);
Directory.CreateDirectory(_dir);
_currentPath = Path.Combine(_dir, "session_current.json");
if (File.Exists(_currentPath))
{
string text = File.ReadAllText(_currentPath);
_current = JsonConvert.DeserializeObject<RunSession>(text);
REPOrt.Logger.LogInfo((object)("[REPOrt] Session " + runSessionId + " attached"));
return;
}
_current = new RunSession
{
RunSessionId = runSessionId,
StartedAt = DateTime.UtcNow.ToString("o"),
LastUpdatedAt = DateTime.UtcNow.ToString("o")
};
UpdateModInfo();
Save();
REPOrt.Logger.LogInfo((object)("[REPOrt] Session " + runSessionId + " started"));
}
public static void AddStageRecord(string stageName, StageRecord rec)
{
if (!HasSession)
{
string text = $"REPO_SAVE_{DateTime.Now:yyyy_MM_dd_HH_mm_ss}";
REPOrt.Logger.LogInfo((object)("[REPOrt] Starting new session " + text));
StartOrAttachSession(text);
}
else
{
REPOrt.Logger.LogInfo((object)"[REPOrt] Continuing existing session");
}
if (_current == null)
{
return;
}
string prev = _current.LastStageType?.Trim();
if (!string.IsNullOrEmpty(prev))
{
bool? cleared = null;
switch (prev.ToLowerInvariant())
{
case "main":
if (stageName.Equals("Shop", StringComparison.OrdinalIgnoreCase))
{
cleared = true;
}
else if (stageName.Equals("GameOver", StringComparison.OrdinalIgnoreCase))
{
cleared = false;
}
break;
case "shop":
if (stageName.Equals("Lobby", StringComparison.OrdinalIgnoreCase))
{
cleared = true;
}
break;
case "lobby":
if (stageName.Equals("Main", StringComparison.OrdinalIgnoreCase))
{
cleared = true;
}
break;
}
if (cleared.HasValue)
{
int num = _current.Stages.FindLastIndex((StageRecord s) => s != null && s.StageName != null && s.StageName.Trim().Equals(prev, StringComparison.OrdinalIgnoreCase) && !s.Cleared.HasValue);
REPOrt.Logger.LogInfo((object)$"[REPOrt] Auto-close prev from JSON: prev={prev}, next={stageName}, idx={num}");
if (num >= 0)
{
StageRecord stageRecord = _current.Stages[num];
stageRecord.Cleared = cleared;
stageRecord.EndedAt = DateTime.UtcNow.ToString("o");
DateTime dateTime = DateTime.Parse(stageRecord.StartedAt);
DateTime dateTime2 = DateTime.Parse(stageRecord.EndedAt);
stageRecord.ElapsedTimeSec = (dateTime2 - dateTime).TotalSeconds;
if (stageRecord.StageName.Equals("Main", StringComparison.OrdinalIgnoreCase))
{
stageRecord.DestroyedValue = DestroyedTracker.CalcLost();
REPOrt.Logger.LogInfo((object)$"[REPOrt] Stage {stageRecord.StageName} DestroyedValue={stageRecord.DestroyedValue}");
stageRecord.DeliveredValue = DeliveryTracker.GetDeliveredValue();
stageRecord.DeliveryPerStation = DeliveryTracker.Flush();
stageRecord.EnemiesSpawned = EnemySpawnTracker.ToList();
stageRecord.EnemiesKilled = EnemyKillTracker.ToList();
PlayerTracker.RecordPlayers(stageRecord);
StatsManager instance = StatsManager.instance;
stageRecord.Balance = ((instance != null) ? instance.GetRunStatCurrency() : 0);
REPOrt.Logger.LogInfo((object)("[REPOrt] Stage " + stageRecord.StageName + " DeliveryPerStation=" + JsonConvert.SerializeObject((object)stageRecord.DeliveryPerStation, (Formatting)1)));
DestroyedTracker.Reset();
DeliveryTracker.Reset();
EnemySpawnTracker.Reset();
EnemyKillTracker.Reset();
}
if (stageRecord.StageName.Equals("Shop", StringComparison.OrdinalIgnoreCase))
{
try
{
StatsManager instance2 = StatsManager.instance;
stageRecord.Balance = ((instance2 != null) ? instance2.GetRunStatCurrency() : 0);
DeliveryTracker.Reset();
REPOrt.Logger.LogInfo((object)$"[REPOrt] Money updated ({stageRecord.StageName} end) -> {_current.Money}");
}
catch (Exception arg)
{
REPOrt.Logger.LogWarning((object)$"[REPOrt] Money fetch failed: {arg}");
}
}
if (stageRecord.StageName.Equals("Lobby", StringComparison.OrdinalIgnoreCase))
{
PlayerTracker.RecordPlayers(stageRecord);
}
_current.Stages[num] = stageRecord;
Save();
}
}
}
StatsManager instance3 = StatsManager.instance;
int finalLevel = (rec.LevelNum = (1 + ((instance3 != null) ? new int?(instance3.GetRunStatLevel()) : null)) ?? ((RunManager.instance?.levelsCompleted ?? 0) + 1));
StageRecord stageRecord2 = rec;
if (stageRecord2.StartedAt == null)
{
string text3 = (stageRecord2.StartedAt = DateTime.UtcNow.ToString("o"));
}
stageRecord2 = rec;
if (stageRecord2.EndedAt == null)
{
string text3 = (stageRecord2.EndedAt = DateTime.UtcNow.ToString("o"));
}
DateTime dateTime3 = DateTime.Parse(rec.StartedAt);
DateTime dateTime4 = DateTime.Parse(rec.EndedAt);
rec.ElapsedTimeSec = (dateTime4 - dateTime3).TotalSeconds;
stageRecord2 = rec;
if (!stageRecord2.Cleared.HasValue)
{
stageRecord2.Cleared = null;
}
REPOrt.Logger.LogInfo((object)("[REPOrt] Adding stage: " + JsonConvert.SerializeObject((object)rec, (Formatting)1)));
_current.Stages.Add(rec);
if (stageName.Equals("Main", StringComparison.OrdinalIgnoreCase))
{
DestroyedTracker.Reset();
REPOrt.Logger.LogInfo((object)"[REPOrt] DestroyedTracker reset at Main start");
}
_current.LastStageType = stageName;
_current.PlayerName = StatsManager.instance.playerNames.Values.Distinct().ToList();
RunSession current = _current;
StatsManager instance4 = StatsManager.instance;
current.Money = ((instance4 != null) ? instance4.GetRunStatCurrency() : 0);
RunSession current2 = _current;
StatsManager instance5 = StatsManager.instance;
current2.TotalHaul = ((instance5 != null) ? instance5.GetRunStatTotalHaul() : 0);
_current.FinalLevel = finalLevel;
if ((Object)(object)RunManager.instance != (Object)null)
{
int moonLevel = RunManager.instance.moonLevel;
_current.CurrentMoon = RunManager.instance.MoonGetName(moonLevel);
}
else
{
_current.CurrentMoon = "Unknown";
}
_current.LastUpdatedAt = DateTime.UtcNow.ToString("o");
Save();
REPOrt.Logger.LogInfo((object)("[REPOrt] Stage " + stageName + " appended -> " + _currentPath));
REPOrt.Logger.LogInfo((object)("[REPOrt] Stage " + stageName + " appended"));
}
internal static void MarkLastUnresolvedStage(string nextStage)
{
if (_current != null)
{
int num = _current.Stages.FindLastIndex((StageRecord s) => !s.Cleared.HasValue);
if (num >= 0)
{
StageRecord stageRecord = _current.Stages[num];
MarkPreviousStage(stageRecord.StageName, nextStage);
}
}
}
internal static void MarkPreviousStage(string prevStage, string nextStage)
{
string prevStage2 = prevStage;
if (_current == null || string.IsNullOrWhiteSpace(prevStage2))
{
return;
}
int num = _current.Stages.FindLastIndex((StageRecord s) => s != null && s.StageName != null && s.StageName.Equals(prevStage2, StringComparison.OrdinalIgnoreCase) && !s.Cleared.HasValue);
if (num < 0)
{
return;
}
StageRecord stageRecord = _current.Stages[num];
bool? cleared = null;
switch (prevStage2.ToLowerInvariant())
{
case "main":
if (nextStage.Equals("Shop", StringComparison.OrdinalIgnoreCase))
{
cleared = true;
}
else if (nextStage.Equals("GameOver", StringComparison.OrdinalIgnoreCase))
{
cleared = false;
}
break;
case "shop":
if (nextStage.Equals("Lobby", StringComparison.OrdinalIgnoreCase))
{
cleared = true;
}
break;
case "lobby":
if (nextStage.Equals("Main", StringComparison.OrdinalIgnoreCase))
{
cleared = true;
}
break;
}
if (cleared.HasValue)
{
stageRecord.Cleared = cleared;
stageRecord.EndedAt = DateTime.UtcNow.ToString("o");
DateTime dateTime = DateTime.Parse(stageRecord.StartedAt);
DateTime dateTime2 = DateTime.Parse(stageRecord.EndedAt);
stageRecord.ElapsedTimeSec = (dateTime2 - dateTime).TotalSeconds;
_current.Stages[num] = stageRecord;
Save();
REPOrt.Logger.LogInfo((object)("[REPOrt] Stage closed: " + JsonConvert.SerializeObject((object)stageRecord, (Formatting)1)));
}
}
public static void FinalizeSession(string reason = "GameOver")
{
if (_current != null)
{
_current.FinalizedAt = DateTime.UtcNow.ToString("o");
_current.FinalizeReason = reason;
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "..\\LocalLow\\semiwork\\Repo\\REPOrtGallery");
string text = Path.Combine(path, "Finalized");
Directory.CreateDirectory(text);
string path2 = Path.Combine(text, $"session_final_{DateTime.Now:yyyy_MM_dd_HH_mm_ss}.json");
string contents = JsonConvert.SerializeObject((object)_current, (Formatting)1);
File.WriteAllText(path2, contents);
REPOrt.Logger.LogInfo((object)("[REPOrt] finalized -> " + Path.GetFileName(path2) + " (moved to Finalized/)"));
if (File.Exists(_currentPath))
{
File.Delete(_currentPath);
REPOrt.Logger.LogInfo((object)"[REPOrt] session_current.json deleted after finalization");
}
}
}
private static void Save()
{
string contents = JsonConvert.SerializeObject((object)_current, (Formatting)1);
File.WriteAllText(_currentPath, contents);
REPOrt.Logger.LogInfo((object)"[REPOrt] session_current.json saved");
}
public static StageRecord GetCurrentStage()
{
return _current?.Stages?.LastOrDefault();
}
public static void CleanupOrphanSessions()
{
try
{
string text = Path.Combine(Application.persistentDataPath, "REPOrtGallery");
if (!Directory.Exists(text))
{
return;
}
string[] directories = Directory.GetDirectories(text, "REPO_SAVE_*");
string[] array = directories;
foreach (string text2 in array)
{
string path = Path.Combine(text2, "session_current.json");
if (!File.Exists(path))
{
continue;
}
string text3 = File.ReadAllText(path);
if (text3.Contains("\"Cycles\": []"))
{
string text4 = Path.Combine(text, "Quarantine");
Directory.CreateDirectory(text4);
string fileName = Path.GetFileName(text2);
string text5 = Path.Combine(text4, fileName);
if (Directory.Exists(text5))
{
Directory.Delete(text5, recursive: true);
}
Directory.Move(text2, text5);
REPOrt.Logger.LogInfo((object)("[REPOrt] Orphan session moved to Quarantine: " + fileName));
}
}
}
catch (Exception arg)
{
REPOrt.Logger.LogError((object)$"[REPOrt] Cleanup failed: {arg}");
}
}
public static void UpdateModInfo()
{
if (_current != null)
{
bool isModded = ModDetector.IsModded;
List<string> detectedMods = new List<string>(ModDetector.DetectedMods);
if (isModded)
{
_current.IsModded = true;
}
_current.DetectedMods = detectedMods;
ModSnapshot snapshot = new ModSnapshot
{
Timestamp = DateTime.UtcNow.ToString("o"),
IsModded = isModded,
DetectedMods = detectedMods
};
if (!_current.ModHistory.Any((ModSnapshot h) => h.IsModded == snapshot.IsModded && h.DetectedMods.SequenceEqual(snapshot.DetectedMods)))
{
_current.ModHistory.Add(snapshot);
}
_current.LastUpdatedAt = DateTime.UtcNow.ToString("o");
Save();
REPOrt.Logger.LogInfo((object)$"[REPOrt] Mod info updated (IsModded={_current.IsModded}, HistoryCount={_current.ModHistory.Count})");
}
}
}
[Serializable]
public class RunSession
{
public string RunSessionId { get; set; }
public List<StageRecord> Stages { get; set; } = new List<StageRecord>();
public string StartedAt { get; set; }
public string LastUpdatedAt { get; set; }
public string FinalizedAt { get; set; }
public string FinalizeReason { get; set; }
public bool IsModded { get; set; }
public List<string> DetectedMods { get; set; } = new List<string>();
public List<ModSnapshot> ModHistory { get; set; } = new List<ModSnapshot>();
public string LastStageType { get; set; }
public List<string> PlayerName { get; set; }
public double TotalPlayTimeSec { get; set; }
public int FinalLevel { get; set; }
public int TotalDeaths { get; set; }
public int Money { get; set; }
public int TotalHaul { get; set; }
public string CurrentMoon { get; set; }
}
[Serializable]
public class StageRecord
{
public string StageName { get; set; }
public int LevelNum { get; set; }
public string StartedAt { get; set; }
public string EndedAt { get; set; }
public string MapName { get; set; }
public bool? Cleared { get; set; }
public double ElapsedTimeSec { get; set; }
public int DeliveredValue { get; set; }
public int DestroyedValue { get; set; }
public Dictionary<string, StationDeliveryInfo> DeliveryPerStation { get; set; } = new Dictionary<string, StationDeliveryInfo>();
public List<EnemySpawnRecord> EnemiesSpawned { get; set; } = new List<EnemySpawnRecord>();
public List<EnemyKillRecord> EnemiesKilled { get; set; } = new List<EnemyKillRecord>();
public List<PlayerSnapshot> Players { get; set; } = new List<PlayerSnapshot>();
public int Balance { get; set; }
}
public class StationDeliveryInfo
{
public int Value { get; set; }
public string Time { get; set; }
public List<ExtractedItem> ExtractedItems { get; set; } = new List<ExtractedItem>();
public int HaulGoal { get; set; }
public int HaulTotal { get; set; }
public int UnknownSigned { get; set; }
public int UnknownPlus => Math.Max(0, UnknownSigned);
public int UnknownMinus => Math.Max(0, -UnknownSigned);
}
public sealed class EnemySpawnRecord
{
public int InstanceId { get; set; }
public string Type { get; set; }
}
public class EnemyKillRecord
{
public int InstanceId { get; set; }
public string Type { get; set; } = "";
public string Time { get; set; } = "";
public string KilledBy { get; set; } = "Unknown";
}
public class ExtractedItem
{
public string Name { get; set; }
public int Value { get; set; }
public int InstanceId { get; set; }
}
public class PlayerSnapshot
{
public string Name { get; set; }
public Dictionary<string, int> Upgrades { get; set; } = new Dictionary<string, int>();
}
[Serializable]
public class ModSnapshot
{
public string Timestamp { get; set; }
public bool IsModded { get; set; }
public List<string> DetectedMods { get; set; } = new List<string>();
}
public static class StageUtil
{
private static readonly HashSet<string> KnownMaps = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Museum", "Manor", "Arctic", "Wizard" };
public static string DetectStageType(string sceneName, out string mapName)
{
mapName = null;
if (string.IsNullOrWhiteSpace(sceneName))
{
return null;
}
string text = sceneName.Trim();
if (text.IndexOf("Main Menu", StringComparison.OrdinalIgnoreCase) >= 0)
{
return null;
}
if (text.IndexOf("Shop", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "Shop";
}
if (text.IndexOf("Lobby", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "Lobby";
}
if (text.IndexOf("Arena", StringComparison.OrdinalIgnoreCase) >= 0 || text.Equals("GameOver", StringComparison.OrdinalIgnoreCase))
{
return "GameOver";
}
if (text.StartsWith("Level - ", StringComparison.OrdinalIgnoreCase))
{
string text2 = text.Substring("Level - ".Length).Trim();
if (KnownMaps.Contains(text2))
{
mapName = text2;
return "Main";
}
if (text2.Equals("Shop", StringComparison.OrdinalIgnoreCase))
{
return "Shop";
}
if (text2.Equals("Lobby", StringComparison.OrdinalIgnoreCase))
{
return "Lobby";
}
if (text2.Equals("GameOver", StringComparison.OrdinalIgnoreCase) || text2.Equals("Arena", StringComparison.OrdinalIgnoreCase))
{
return "GameOver";
}
return null;
}
if (KnownMaps.Contains(text))
{
mapName = text;
return "Main";
}
return null;
}
}
}