Decompiled source of WorldDumper v0.6.1

WorldDumper.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.SceneManagement;
using WorldDumper.Dumpers;
using WorldDumper.Formats;
using WorldDumper.Jsonl;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("WorldDumper")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Log everything in White Knuckle world. Writes .jsonl files with all events, entites, levels, etc.")]
[assembly: AssemblyFileVersion("0.6.1.0")]
[assembly: AssemblyInformationalVersion("0.6.1+e676f891e750e19658be9647334c427b1b58f5c6")]
[assembly: AssemblyProduct("WorldDumper")]
[assembly: AssemblyTitle("WorldDumper")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.6.1.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
[Serializable]
public class Position3
{
	public float x = tr.position.x;

	public float y = tr.position.y;

	public float z = tr.position.z;

	public Position3(Transform tr)
	{
	}//IL_0002: 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_0024: Unknown result type (might be due to invalid IL or missing references)

}
namespace WorldDumper
{
	[BepInPlugin("shishyando.WK.WorldDumper", "WorldDumper", "0.6.1")]
	public class WorldDumperPlugin : BaseUnityPlugin
	{
		internal static WorldDumperPlugin Instance;

		internal static ManualLogSource Beep;

		private Harmony _harmony;

		public static bool Playing;

		public static ConfigEntry<string> LogsDir;

		public static ConfigEntry<bool> LogGameObjectIds;

		public static ConfigEntry<bool> SortLogsAfterRun;

		private void Awake()
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			Instance = this;
			Beep = ((BaseUnityPlugin)this).Logger;
			LogsDir = ((BaseUnityPlugin)this).Config.Bind<string>("Logging", "Directory", Path.Combine(Paths.BepInExRootPath, "WorldDumperOutput"), "Directory for WorldDumper logs");
			LogGameObjectIds = ((BaseUnityPlugin)this).Config.Bind<bool>("Logging", "LogGameObjectIds", false, "If true, WorldDumper will dump some unique ids (e.g. GameObject.InstanceID, GameObject.SiblingIdx) for game object formats");
			SortLogsAfterRun = ((BaseUnityPlugin)this).Config.Bind<bool>("Logging", "SortLogsAfterRun", false, "If true, WorldDumper will sort the logs after the run (may be useful for diffing)");
			_harmony = new Harmony("shishyando.WK.WorldDumper");
			Beep.LogInfo((object)"shishyando.WK.WorldDumper is loaded");
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			SceneManager.sceneLoaded += OnSceneLoaded;
			Instance._harmony.PatchAll();
		}

		public void OnSceneLoaded(Scene s, LoadSceneMode m)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Beep.LogInfo((object)$"OnSceneLoaded: {((Scene)(ref s)).name} (mode: {m})");
			if (((Scene)(ref s)).name == "Game-Main")
			{
				Start();
			}
		}

		public void OnSceneUnloaded(Scene s)
		{
			Beep.LogInfo((object)("OnSceneUnloaded: " + ((Scene)(ref s)).name));
			if (((Scene)(ref s)).name == "Game-Main")
			{
				Stop();
			}
		}

		public static void Start()
		{
			if (!TryToRotateLogs())
			{
				return;
			}
			Playing = true;
			List<Perk> perkAssets = CL_AssetManager.GetFullCombinedAssetDatabase().perkAssets;
			foreach (Perk item in perkAssets)
			{
				PerkDumper.DumpPerk(item, "GameStart");
			}
		}

		public static void Stop()
		{
			Playing = false;
			Jsonler.DisposeWriters();
		}

		public static bool TryToRotateLogs()
		{
			Jsonler.DisposeWriters();
			try
			{
				string text = Path.Combine(Paths.BepInExRootPath, LogsDir.Value + "_prev");
				if (Directory.Exists(text))
				{
					Directory.Delete(text, recursive: true);
				}
				if (!Directory.Exists(text))
				{
					Directory.CreateDirectory(text);
				}
				DirectoryInfo directoryInfo = Directory.CreateDirectory(LogsDir.Value);
				foreach (FileInfo item in directoryInfo.EnumerateFiles())
				{
					item.MoveTo(Path.Combine(text, item.Name));
				}
				return true;
			}
			catch (Exception arg)
			{
				Beep.LogError((object)$"Recreating logs directory failed: {arg}");
				Stop();
				return false;
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "shishyando.WK.WorldDumper";

		public const string PLUGIN_NAME = "WorldDumper";

		public const string PLUGIN_VERSION = "0.6.1";
	}
}
namespace WorldDumper.Patches
{
	[HarmonyPatch(typeof(App_PerkPage), "GenerateCards", new Type[] { typeof(bool) })]
	public static class App_PerkPage_GenerateCards_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(bool refresh, App_PerkPage __instance)
		{
			if (WorldDumperPlugin.Playing)
			{
				PerkDumper.DumpPerkPage(__instance, "App_PerkPage_GenerateCards", refresh);
			}
		}
	}
	[HarmonyPatch(typeof(ENV_ArtifactDevice), "Start")]
	public static class ENV_ArtifactDevice_Start_Patcher
	{
		public static readonly FieldRef<ENV_ArtifactDevice, List<Item_Object>> spawnedArtifactsRef = AccessTools.FieldRefAccess<ENV_ArtifactDevice, List<Item_Object>>("spawnedArtifacts");

		[HarmonyPriority(0)]
		public static void Finalizer(ENV_ArtifactDevice __instance)
		{
			if (!WorldDumperPlugin.Playing)
			{
				return;
			}
			foreach (Item_Object item in spawnedArtifactsRef.Invoke(__instance))
			{
				ItemObjectDumper.Dump(item, "ENV_ArtifactDevice_Start", ((Component)__instance).transform);
			}
		}
	}
	[HarmonyPatch(typeof(ENV_VendingMachine), "GenerateOptions")]
	public static class ENV_VendingMachine_GenerateOptions_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(ENV_VendingMachine __instance)
		{
			if (WorldDumperPlugin.Playing)
			{
				VendingMachineDumper.Dump(__instance, "ENV_VendingMachine_GenerateOptions");
			}
		}
	}
	[HarmonyPatch(typeof(GameEntity), "Start")]
	public static class GameEntity_Start_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(GameEntity __instance)
		{
			if (WorldDumperPlugin.Playing)
			{
				GameEntityDumper.Dump(__instance, "GameEntity_Start");
			}
		}
	}
	[HarmonyPatch(typeof(Item_Object), "Start")]
	public static class Item_Object_Start_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(Item_Object __instance)
		{
			if (WorldDumperPlugin.Playing)
			{
				ItemObjectDumper.Dump(__instance, "Item_Object_Start");
			}
		}
	}
	[HarmonyPatch(typeof(M_Level), "Initialize")]
	public static class M_Level_Initialize_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(M_Level __instance)
		{
			if (WorldDumperPlugin.Playing)
			{
				LevelDumper.Dump(__instance, "M_Level_Initialize");
			}
		}
	}
	[HarmonyPatch(typeof(SessionEvent), "StartEvent")]
	public static class SessionEvent_StartEvent_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(SessionEvent __instance)
		{
			if (WorldDumperPlugin.Playing)
			{
				SessionEventDumper.Dump(__instance, "SessionEvent_StartEvent");
			}
		}
	}
	[HarmonyPatch(typeof(UT_ObjectSpawner), "Spawn", new Type[] { })]
	public static class UT_ObjectSpawner_Spawn_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(UT_ObjectSpawner __instance)
		{
			if (WorldDumperPlugin.Playing)
			{
				GameObjectDumper.Dump(((Component)__instance).gameObject, "UT_ObjectSpawner_Spawn");
			}
		}
	}
	[HarmonyPatch(typeof(UT_ObjectSpawner), "Spawn", new Type[] { typeof(GameObject) })]
	public static class UT_ObjectSpawner_SpawnGameObject_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(GameObject o)
		{
			if (WorldDumperPlugin.Playing)
			{
				GameObjectDumper.Dump(o, "UT_ObjectSpawner_SpawnGameObject");
			}
		}
	}
	[HarmonyPatch(typeof(UT_ObjectSpawner), "SpawnAtTransform")]
	public static class UT_ObjectSpawner_SpawnAtTransform_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(UT_ObjectSpawner __instance)
		{
			if (WorldDumperPlugin.Playing && (Object)(object)__instance.spawnObject != (Object)null)
			{
				GameObjectDumper.Dump(__instance.spawnObject, "UT_ObjectSpawner_SpawnAtTransform");
			}
		}
	}
	[HarmonyPatch(typeof(UT_RadiusSpawner), "Spawn")]
	public static class UT_RadiusSpawner_Spawn_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(UT_RadiusSpawner __instance)
		{
			if (!WorldDumperPlugin.Playing)
			{
				return;
			}
			if ((Object)(object)__instance.spawnTable != (Object)null)
			{
				try
				{
					SpawnTableAsset randomSpawnObject = __instance.spawnTable.GetRandomSpawnObject();
					if (randomSpawnObject != null)
					{
						GameObject randomPrefab = randomSpawnObject.GetRandomPrefab();
						if ((Object)(object)randomPrefab != (Object)null)
						{
							GameObjectDumper.Dump(randomPrefab, "UT_RadiusSpawner_SpawnTable");
						}
					}
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("Failed to dump spawn table object: " + ex.Message));
				}
			}
			if (__instance.spawnObjects == null || __instance.spawnObjects.Count <= 0)
			{
				return;
			}
			foreach (GameObject spawnObject in __instance.spawnObjects)
			{
				if ((Object)(object)spawnObject != (Object)null)
				{
					GameObjectDumper.Dump(spawnObject, "UT_RadiusSpawner_SpawnObjects");
				}
			}
		}
	}
	[HarmonyPatch(typeof(UT_SpawnChance), "Start")]
	public static class UT_SpawnChance_Start_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(UT_SpawnChance __instance)
		{
			if (WorldDumperPlugin.Playing)
			{
				GameObjectDumper.Dump(((Component)__instance).gameObject, "UT_SpawnChance_Start");
			}
		}
	}
	[HarmonyPatch(typeof(UT_SpawnEntity), "Spawn")]
	public static class UT_SpawnEntity_Spawn_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(UT_SpawnEntity __instance)
		{
			if (!WorldDumperPlugin.Playing)
			{
				return;
			}
			if (__instance.randomizeObjects != null && __instance.randomizeObjects.Count > 0)
			{
				foreach (GameObject randomizeObject in __instance.randomizeObjects)
				{
					if ((Object)(object)randomizeObject != (Object)null)
					{
						GameObjectDumper.Dump(randomizeObject, "UT_SpawnEntity_RandomizeObjects");
					}
				}
			}
			if ((Object)(object)__instance.spawnObject != (Object)null)
			{
				GameObjectDumper.Dump(__instance.spawnObject, "UT_SpawnEntity_SpawnObject");
			}
		}
	}
	[HarmonyPatch(typeof(UT_SpawnEntity), "SpawnCustom")]
	public static class UT_SpawnEntity_SpawnCustom_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(GameObject g)
		{
			if (WorldDumperPlugin.Playing && (Object)(object)g != (Object)null)
			{
				GameObjectDumper.Dump(g, "UT_SpawnEntity_SpawnCustom");
			}
		}
	}
	[HarmonyPatch(typeof(UT_SPT_Spawner), "Spawn")]
	public static class UT_SPT_Spawner_Spawn_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(UT_SPT_Spawner __instance)
		{
			if (!WorldDumperPlugin.Playing || !((Object)(object)__instance.spawnTable != (Object)null))
			{
				return;
			}
			try
			{
				SpawnTableAsset randomSpawnObject = __instance.spawnTable.GetRandomSpawnObject();
				if (randomSpawnObject != null && randomSpawnObject.prefabs != null)
				{
					GameObject randomPrefab = randomSpawnObject.GetRandomPrefab();
					if ((Object)(object)randomPrefab != (Object)null)
					{
						GameObjectDumper.Dump(randomPrefab, "UT_SPT_Spawner_SpawnTable");
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Failed to dump spawn table object: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(UT_TriggerSpawner), "Spawn")]
	public static class UT_TriggerSpawner_Spawn_Patcher
	{
		[HarmonyPriority(0)]
		public static void Finalizer(UT_TriggerSpawner __instance)
		{
			if (!WorldDumperPlugin.Playing)
			{
				return;
			}
			if ((Object)(object)__instance.spawnTable != (Object)null)
			{
				try
				{
					SpawnTableAsset randomSpawnObject = __instance.spawnTable.GetRandomSpawnObject();
					if (randomSpawnObject != null)
					{
						GameObject randomPrefab = randomSpawnObject.GetRandomPrefab();
						if ((Object)(object)randomPrefab != (Object)null)
						{
							GameObjectDumper.Dump(randomPrefab, "UT_TriggerSpawner_SpawnTable");
						}
					}
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("Failed to dump spawn table object: " + ex.Message));
				}
			}
			if (__instance.spawnObjects == null || __instance.spawnObjects.Count <= 0)
			{
				return;
			}
			foreach (GameObject spawnObject in __instance.spawnObjects)
			{
				if ((Object)(object)spawnObject != (Object)null)
				{
					GameObjectDumper.Dump(spawnObject, "UT_TriggerSpawner_SpawnObjects");
				}
			}
		}
	}
}
namespace WorldDumper.Jsonl
{
	public static class Jsonler
	{
		private static readonly ConcurrentDictionary<string, Lazy<TextWriter>> Writers = new ConcurrentDictionary<string, Lazy<TextWriter>>();

		private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings
		{
			ReferenceLoopHandling = (ReferenceLoopHandling)1,
			Formatting = (Formatting)0,
			NullValueHandling = (NullValueHandling)0
		};

		public static void Dump<T>(T data, string prefix)
		{
			if (data != null)
			{
				string path = Path.Combine(WorldDumperPlugin.LogsDir.Value, prefix + "_" + typeof(T).Name + ".jsonl");
				string line = JsonConvert.SerializeObject((object)data, SerializerSettings);
				WriteLine(path, line);
			}
		}

		public static void DisposeWriters()
		{
			foreach (KeyValuePair<string, Lazy<TextWriter>> writer in Writers)
			{
				if (writer.Value.IsValueCreated)
				{
					writer.Value.Value.Dispose();
				}
			}
			if (WorldDumperPlugin.SortLogsAfterRun.Value)
			{
				foreach (string key in Writers.Keys)
				{
					string[] array = File.ReadAllLines(key, Encoding.UTF8);
					Array.Sort(array, (IComparer<string>?)StringComparer.Ordinal);
					File.WriteAllLines(key, array, Encoding.UTF8);
				}
			}
			Writers.Clear();
		}

		private static void WriteLine(string path, string line)
		{
			TextWriter value = Writers.GetOrAdd(path, CreateLazy).Value;
			value.WriteLine(line);
		}

		private static Lazy<TextWriter> CreateLazy(string path)
		{
			return new Lazy<TextWriter>(delegate
			{
				FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
				StreamWriter writer = new StreamWriter(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), 65536)
				{
					AutoFlush = true,
					NewLine = "\n"
				};
				return TextWriter.Synchronized(writer);
			}, LazyThreadSafetyMode.ExecutionAndPublication);
		}
	}
}
namespace WorldDumper.Formats
{
	[Serializable]
	public class GameEntityFormat
	{
		public string EntityID;

		public GameObjectFormat GameObject;

		public string EntityType;

		public string Tag;

		public Position3 Position;

		public LevelFormat Level;
	}
	[Serializable]
	public class GameObjectFormat
	{
		public string Name;

		public string ParentName;

		public string Path;

		public Position3 Position;

		public bool Active;

		public int InstanceId;

		public int SiblingIdx;
	}
	[Serializable]
	public class ItemObjectFormat
	{
		public string PrefabName;

		public string ItemName;

		public string ItemTag;

		public GameObjectFormat GameObject;

		public LevelFormat Level;
	}
	[Serializable]
	public class LevelFormat
	{
		public string LevelName;

		public string RegionName;

		public string SubregionName;

		public int Seed;

		public bool IsLastLevel;

		public bool Flipped;

		public bool Active;

		public int InstanceId;
	}
	[Serializable]
	public class PerkPageFormat
	{
		public string PerkPageType;

		public GameObjectFormat GameObject;

		public int Seed;

		public int MinCards;

		public int MaxCards;

		public List<PerkCardFormat> PerkCards;

		public bool AfterRefresh;
	}
	[Serializable]
	public class PerkCardFormat
	{
		public string Name;

		public PerkFormat PerkInfo;
	}
	[Serializable]
	public class PerkFormat
	{
		public string Title;

		public string Description;

		public string Id;

		public int Cost;

		public string SpawnPool;
	}
	[Serializable]
	public class SessionEventFormat
	{
		public string Id;

		public string StartCheck;

		public List<string> EventModules;

		public LevelFormat StartLevel;
	}
	[Serializable]
	public class VendingPurchaseFormat
	{
		public string PrefabName;

		public float Chance;

		public int Price;
	}
	[Serializable]
	public class VendingMachineFormat
	{
		public string VendorId;

		public VendingPurchaseFormat[] PurchaseArray;

		public int LocalSeed;

		public bool RandomGeneration;

		public LevelFormat Level;

		public GameObjectFormat GameObject;
	}
}
namespace WorldDumper.Dumpers
{
	public static class AsIsDumper
	{
		public static void Dump<T>(T obj, string preifx)
		{
			Jsonler.Dump(obj, preifx);
		}
	}
	public static class GameEntityDumper
	{
		public static void Dump(GameEntity e, string prefix)
		{
			GameEntityFormat data = new GameEntityFormat
			{
				EntityID = e.entityPrefabID,
				EntityType = e.objectType,
				Tag = ((Component)e).tag,
				Position = new Position3(((Component)e).gameObject.transform),
				Level = LevelDumper.FormatLevelOf(((Component)e).transform),
				GameObject = GameObjectDumper.FormatGameObject(((Component)e).gameObject)
			};
			Jsonler.Dump(data, prefix + "_" + ((Component)e).tag);
		}
	}
	public static class GameObjectDumper
	{
		public static void Dump(GameObject obj, string prefix)
		{
			Jsonler.Dump(FormatGameObject(obj), prefix);
		}

		public static GameObjectFormat FormatGameObject(GameObject obj)
		{
			GameObjectFormat obj2 = new GameObjectFormat
			{
				Name = ((Object)obj).name,
				Position = new Position3(obj.transform)
			};
			Transform parent = obj.transform.parent;
			object obj3;
			if (parent == null)
			{
				obj3 = null;
			}
			else
			{
				GameObject gameObject = ((Component)parent).gameObject;
				obj3 = ((gameObject != null) ? ((Object)gameObject).name : null);
			}
			if (obj3 == null)
			{
				obj3 = "<root>";
			}
			obj2.ParentName = (string)obj3;
			obj2.Path = GetPath(obj.transform);
			obj2.Active = obj.activeSelf;
			obj2.InstanceId = (WorldDumperPlugin.LogGameObjectIds.Value ? ((Object)obj).GetInstanceID() : 0);
			obj2.SiblingIdx = (WorldDumperPlugin.LogGameObjectIds.Value ? obj.transform.GetSiblingIndex() : 0);
			return obj2;
		}

		private static string GetPath(Transform t)
		{
			StringBuilder stringBuilder = new StringBuilder(((Object)t).name);
			Transform parent = t.parent;
			while ((Object)(object)parent != (Object)null)
			{
				stringBuilder.Insert(0, ((Object)parent).name + "/");
				parent = parent.parent;
			}
			return stringBuilder.ToString();
		}
	}
	public static class ItemObjectDumper
	{
		public static void Dump(Item_Object obj, string prefix, Transform customTr = null, bool dumpGameObject = true)
		{
			Jsonler.Dump(FormatItemObject(obj, customTr, dumpGameObject), prefix);
		}

		public static ItemObjectFormat FormatItemObject(Item_Object it, Transform customTr = null, bool dumpGameObject = false)
		{
			return new ItemObjectFormat
			{
				ItemName = it.itemData.itemName,
				ItemTag = it.itemData.itemTag,
				PrefabName = it.itemData.prefabName,
				GameObject = (dumpGameObject ? GameObjectDumper.FormatGameObject(((Component)it).gameObject) : null),
				Level = (LevelDumper.FormatLevelOf(customTr) ?? LevelDumper.FormatLevelOf(((Component)it).transform) ?? null)
			};
		}
	}
	public static class LevelDumper
	{
		public static readonly FieldRef<M_Level, bool> flippedRef = AccessTools.FieldRefAccess<M_Level, bool>("flipped");

		public static void Dump(M_Level lvl, string prefix)
		{
			Jsonler.Dump(FormatLevel(lvl), prefix);
		}

		public static LevelFormat FormatLevel(M_Level lvl)
		{
			return new LevelFormat
			{
				InstanceId = (WorldDumperPlugin.LogGameObjectIds.Value ? ((Object)lvl).GetInstanceID() : 0),
				LevelName = lvl.levelName,
				IsLastLevel = lvl.lastLevel,
				RegionName = (lvl.region?.regionName ?? "no_region_name"),
				SubregionName = (lvl.subRegion?.subregionName ?? "no_subregion_name"),
				Flipped = flippedRef.Invoke(lvl),
				Seed = lvl.GetLevelSeed(),
				Active = ((Component)lvl).gameObject.activeSelf
			};
		}

		public static LevelFormat FormatLevelOf(Transform tr)
		{
			M_Level val = LevelOf(tr);
			return Object.op_Implicit((Object)(object)val) ? FormatLevel(val) : null;
		}

		public static M_Level LevelOf(Transform tr)
		{
			if ((Object)(object)tr == (Object)null)
			{
				return null;
			}
			return ((Component)tr).GetComponentInParent<M_Level>(true);
		}
	}
	public static class PerkDumper
	{
		public static readonly FieldRef<App_PerkPage, List<App_PerkPage_Card>> cardsRef = AccessTools.FieldRefAccess<App_PerkPage, List<App_PerkPage_Card>>("cards");

		private static readonly FieldRef<App_PerkPage, OS_Manager> osRef = (FieldRef<App_PerkPage, OS_Manager>)(object)AccessTools.FieldRefAccess<OS_Manager>(typeof(App_PerkPage), "os");

		public static void DumpPerkPage(App_PerkPage page, string prefix, bool refresh)
		{
			PerkPageFormat perkPageFormat = new PerkPageFormat();
			perkPageFormat.PerkPageType = ((object)(PerkPageType)(ref page.perkPageType)).ToString();
			perkPageFormat.GameObject = GameObjectDumper.FormatGameObject(((Component)page).gameObject);
			perkPageFormat.Seed = osRef.Invoke(page).worldInterface.GetSeed();
			perkPageFormat.MinCards = page.minCards;
			perkPageFormat.MaxCards = page.maxCards;
			perkPageFormat.PerkCards = cardsRef.Invoke(page).ConvertAll(ConvertPerkCard);
			perkPageFormat.AfterRefresh = refresh;
			PerkPageFormat perkPageFormat2 = perkPageFormat;
			perkPageFormat2.GameObject.Position = new Position3(((Component)osRef.Invoke(page).worldInterface).transform);
			Jsonler.Dump(perkPageFormat2, prefix);
		}

		public static PerkCardFormat ConvertPerkCard(App_PerkPage_Card card)
		{
			return new PerkCardFormat
			{
				Name = ((Object)card).name,
				PerkInfo = FormatPerk(card.perk)
			};
		}

		public static void DumpPerk(Perk perk, string prefix)
		{
			Jsonler.Dump(FormatPerk(perk), prefix);
		}

		public static PerkFormat FormatPerk(Perk perk)
		{
			return new PerkFormat
			{
				Title = perk.GetTitle(false),
				Description = perk.GetDescription(false, false, false),
				Id = perk.id,
				Cost = perk.cost,
				SpawnPool = ((object)(PerkPool)(ref perk.spawnPool)).ToString()
			};
		}
	}
	public static class SessionEventDumper
	{
		public static readonly FieldRef<SessionEvent, M_Level> startLevelRef = AccessTools.FieldRefAccess<SessionEvent, M_Level>("startLevel");

		public static void Dump(SessionEvent e, string prefix)
		{
			SessionEventFormat data = new SessionEventFormat
			{
				Id = e.id,
				StartCheck = ((object)(EventStart)(ref e.startCheck)).ToString(),
				EventModules = e.modules.ConvertAll((SessionEventModule x) => x.name),
				StartLevel = LevelDumper.FormatLevel(startLevelRef.Invoke(e))
			};
			Jsonler.Dump(data, prefix);
		}
	}
	public static class VendingMachineDumper
	{
		public static readonly FieldRef<ENV_VendingMachine, int> localSeedRef = AccessTools.FieldRefAccess<ENV_VendingMachine, int>("localSeed");

		public static void Dump(ENV_VendingMachine vendo, string prefix)
		{
			VendingMachineFormat vendingMachineFormat = new VendingMachineFormat();
			vendingMachineFormat.VendorId = vendo.vendorId;
			vendingMachineFormat.PurchaseArray = Array.ConvertAll(vendo.buttons, GetPurchase);
			vendingMachineFormat.LocalSeed = localSeedRef.Invoke(vendo);
			vendingMachineFormat.RandomGeneration = vendo.randomGeneration;
			vendingMachineFormat.Level = LevelDumper.FormatLevelOf(((Component)vendo).transform);
			vendingMachineFormat.GameObject = GameObjectDumper.FormatGameObject(((Component)vendo).gameObject);
			VendingMachineFormat data = vendingMachineFormat;
			Jsonler.Dump(data, prefix);
		}

		public static VendingPurchaseFormat GetPurchase(VendingButton button)
		{
			return new VendingPurchaseFormat
			{
				PrefabName = ((Object)button.purchase.itemObject).name,
				Chance = button.purchase.chance,
				Price = button.purchase.price
			};
		}
	}
}