Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CENI v1.0.0
plugins/CENI/CENI.dll
Decompiled 9 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using BiggerBazaar; using HG; using HG.Reflection; using IL.RoR2; using Mono.Cecil; using Mono.Cecil.Cil; using MonoMod.Cil; using MonoMod.RuntimeDetour.HookGen; using On.RoR2; using On.RoR2.UI; using PSTinyJson; using ProperSave.Components; using ProperSave.Data; using ProperSave.Old; using ProperSave.Old.Data; using ProperSave.Old.SaveData; using ProperSave.Old.SaveData.Artifacts; using ProperSave.Old.SaveData.Runs; using ProperSave.SaveData; using ProperSave.SaveData.Artifacts; using ProperSave.SaveData.Runs; using ProperSave.TinyJson; using ProperSave.Utils; using R2API; using RoR2; using RoR2.Artifacts; using RoR2.CharacterAI; using RoR2.ContentManagement; using RoR2.ExpansionManagement; using RoR2.Networking; using RoR2.Skills; using RoR2.Stats; using RoR2.UI; using ShareSuite; using TMPro; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.UI; using Zio; using Zio.FileSystems; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: OptIn] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] namespace PSTinyJson { public static class JSONParser { [ThreadStatic] private static Stack<List<string>> splitArrayPool; [ThreadStatic] private static StringBuilder stringBuilder; [ThreadStatic] private static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoCache; [ThreadStatic] private static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfoCache; public static T FromJson<T>(this string json) { return (T)json.FromJson(typeof(T)); } public static object FromJson(this string json, Type type) { if (propertyInfoCache == null) { propertyInfoCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>(); } if (fieldInfoCache == null) { fieldInfoCache = new Dictionary<Type, Dictionary<string, FieldInfo>>(); } if (stringBuilder == null) { stringBuilder = new StringBuilder(); } if (splitArrayPool == null) { splitArrayPool = new Stack<List<string>>(); } stringBuilder.Length = 0; for (int i = 0; i < json.Length; i++) { char c = json[i]; if (c == '"') { i = AppendUntilStringEnd(appendEscapeCharacter: true, i, json); } else if (!char.IsWhiteSpace(c)) { stringBuilder.Append(c); } } return ParseValue(type, stringBuilder.ToString()); } private static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json) { stringBuilder.Append(json[startIdx]); for (int i = startIdx + 1; i < json.Length; i++) { if (json[i] == '\\') { if (appendEscapeCharacter) { stringBuilder.Append(json[i]); } stringBuilder.Append(json[i + 1]); i++; } else { if (json[i] == '"') { stringBuilder.Append(json[i]); return i; } stringBuilder.Append(json[i]); } } return json.Length - 1; } private static List<string> Split(string json) { List<string> list = ((splitArrayPool.Count > 0) ? splitArrayPool.Pop() : new List<string>()); list.Clear(); if (json.Length == 2) { return list; } int num = 0; stringBuilder.Length = 0; for (int i = 1; i < json.Length - 1; i++) { switch (json[i]) { case '[': case '{': num++; break; case ']': case '}': num--; break; case '"': i = AppendUntilStringEnd(appendEscapeCharacter: true, i, json); continue; case ',': case ':': if (num == 0) { list.Add(stringBuilder.ToString()); stringBuilder.Length = 0; continue; } break; } stringBuilder.Append(json[i]); } list.Add(stringBuilder.ToString()); return list; } internal static object ParseValue(Type type, string json) { if (type == typeof(string)) { if (json.Length <= 2) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(json.Length); for (int i = 1; i < json.Length - 1; i++) { if (json[i] == '\\' && i + 1 < json.Length - 1) { int num = "\"\\nrtbf/".IndexOf(json[i + 1]); if (num >= 0) { stringBuilder.Append("\"\\\n\r\t\b\f/"[num]); i++; continue; } if (json[i + 1] == 'u' && i + 5 < json.Length - 1) { uint result = 0u; if (uint.TryParse(json.Substring(i + 2, 4), NumberStyles.AllowHexSpecifier, null, out result)) { stringBuilder.Append((char)result); i += 5; continue; } } } stringBuilder.Append(json[i]); } return stringBuilder.ToString(); } if (type.IsPrimitive) { return Convert.ChangeType(json, type, CultureInfo.InvariantCulture); } if (type == typeof(decimal)) { decimal.TryParse(json, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2); return result2; } if (json == "null") { return null; } if (type.IsEnum) { if (json[0] == '"') { json = json.Substring(1, json.Length - 2); try { return Enum.Parse(type, json, ignoreCase: false); } catch { return 0; } } return Convert.ChangeType(json, Enum.GetUnderlyingType(type)); } if (type.IsArray) { Type elementType = type.GetElementType(); if (json[0] != '[' || json[json.Length - 1] != ']') { return null; } List<string> list = Split(json); Array array = Array.CreateInstance(elementType, list.Count); for (int j = 0; j < list.Count; j++) { array.SetValue(ParseValue(elementType, list[j]), j); } splitArrayPool.Push(list); return array; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) { Type type2 = type.GetGenericArguments()[0]; if (json[0] != '[' || json[json.Length - 1] != ']') { return null; } List<string> list2 = Split(json); IList list3 = (IList)type.GetConstructor(new Type[1] { typeof(int) }).Invoke(new object[1] { list2.Count }); for (int k = 0; k < list2.Count; k++) { list3.Add(ParseValue(type2, list2[k])); } splitArrayPool.Push(list2); return list3; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { Type[] genericArguments = type.GetGenericArguments(); Type type3 = genericArguments[0]; Type type4 = genericArguments[1]; if (type3 != typeof(string)) { return null; } if (json[0] != '{' || json[json.Length - 1] != '}') { return null; } List<string> list4 = Split(json); if (list4.Count % 2 != 0) { return null; } IDictionary dictionary = (IDictionary)type.GetConstructor(new Type[1] { typeof(int) }).Invoke(new object[1] { list4.Count / 2 }); for (int l = 0; l < list4.Count; l += 2) { if (list4[l].Length > 2) { string key = list4[l].Substring(1, list4[l].Length - 2); object value = ParseValue(type4, list4[l + 1]); dictionary.Add(key, value); } } return dictionary; } if (type == typeof(object)) { return ParseAnonymousValue(json); } if (json[0] == '{' && json[json.Length - 1] == '}') { return ParseObject(type, json); } return null; } private static object ParseAnonymousValue(string json) { if (json.Length == 0) { return null; } if (json[0] == '{' && json[json.Length - 1] == '}') { List<string> list = Split(json); if (list.Count % 2 != 0) { return null; } Dictionary<string, object> dictionary = new Dictionary<string, object>(list.Count / 2); for (int i = 0; i < list.Count; i += 2) { dictionary.Add(list[i].Substring(1, list[i].Length - 2), ParseAnonymousValue(list[i + 1])); } return dictionary; } if (json[0] == '[' && json[json.Length - 1] == ']') { List<string> list2 = Split(json); List<object> list3 = new List<object>(list2.Count); for (int j = 0; j < list2.Count; j++) { list3.Add(ParseAnonymousValue(list2[j])); } return list3; } if (json[0] == '"' && json[json.Length - 1] == '"') { return json.Substring(1, json.Length - 2).Replace("\\", string.Empty); } if (char.IsDigit(json[0]) || json[0] == '-') { if (json.Contains(".")) { double.TryParse(json, NumberStyles.Float, CultureInfo.InvariantCulture, out var result); return result; } int.TryParse(json, out var result2); return result2; } if (json == "true") { return true; } if (json == "false") { return false; } return null; } private static Dictionary<string, T> CreateMemberNameDictionary<T>(T[] members) where T : MemberInfo { Dictionary<string, T> dictionary = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase); foreach (T val in members) { if (val.IsDefined(typeof(IgnoreDataMemberAttribute), inherit: true)) { continue; } string name = val.Name; if (val.IsDefined(typeof(DataMemberAttribute), inherit: true)) { DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(val, typeof(DataMemberAttribute), inherit: true); if (!string.IsNullOrEmpty(dataMemberAttribute.Name)) { name = dataMemberAttribute.Name; } } dictionary.Add(name, val); } return dictionary; } private static object ParseObject(Type type, string json) { object uninitializedObject = FormatterServices.GetUninitializedObject(type); List<string> list = Split(json); if (list.Count % 2 != 0) { return uninitializedObject; } if (!fieldInfoCache.TryGetValue(type, out var value)) { value = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)); fieldInfoCache.Add(type, value); } if (!propertyInfoCache.TryGetValue(type, out var value2)) { value2 = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)); propertyInfoCache.Add(type, value2); } for (int i = 0; i < list.Count; i += 2) { if (list[i].Length > 2) { string key = list[i].Substring(1, list[i].Length - 2); string json2 = list[i + 1]; PropertyInfo value4; if (value.TryGetValue(key, out var value3)) { DiscoverObjectTypeAttribute customAttribute = value3.GetCustomAttribute<DiscoverObjectTypeAttribute>(); value3.SetValue(uninitializedObject, ParseValue(customAttribute?.GetObjectType(uninitializedObject) ?? value3.FieldType, json2)); } else if (value2.TryGetValue(key, out value4)) { DiscoverObjectTypeAttribute customAttribute2 = value4.GetCustomAttribute<DiscoverObjectTypeAttribute>(); value4.SetValue(uninitializedObject, ParseValue(customAttribute2?.GetObjectType(uninitializedObject) ?? value4.PropertyType, json2), null); } } } return uninitializedObject; } } public static class JSONWriter { public static string ToJson(this object item) { StringBuilder stringBuilder = new StringBuilder(); AppendValue(stringBuilder, item); return stringBuilder.ToString(); } private static void AppendValue(StringBuilder stringBuilder, object item) { if (item == null) { stringBuilder.Append("null"); return; } Type type = item.GetType(); if (type == typeof(string)) { stringBuilder.Append('"'); string text = (string)item; for (int i = 0; i < text.Length; i++) { if (text[i] < ' ' || text[i] == '"' || text[i] == '\\') { stringBuilder.Append('\\'); int num = "\"\\\n\r\t\b\f".IndexOf(text[i]); if (num >= 0) { stringBuilder.Append("\"\\nrtbf"[num]); } else { stringBuilder.AppendFormat("u{0:X4}", (uint)text[i]); } } else { stringBuilder.Append(text[i]); } } stringBuilder.Append('"'); return; } if (type == typeof(byte) || type == typeof(int) || type == typeof(long) || type == typeof(uint) || type == typeof(ulong)) { stringBuilder.Append(item.ToString()); return; } if (type == typeof(float)) { stringBuilder.Append(((float)item).ToString(CultureInfo.InvariantCulture)); return; } if (type == typeof(double)) { stringBuilder.Append(((double)item).ToString(CultureInfo.InvariantCulture)); return; } if (type == typeof(bool)) { stringBuilder.Append(((bool)item) ? "true" : "false"); return; } if (type.IsEnum) { stringBuilder.Append('"'); stringBuilder.Append(item.ToString()); stringBuilder.Append('"'); return; } if (item is IList) { stringBuilder.Append('['); bool flag = true; IList list = item as IList; for (int j = 0; j < list.Count; j++) { if (flag) { flag = false; } else { stringBuilder.Append(','); } AppendValue(stringBuilder, list[j]); } stringBuilder.Append(']'); return; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { if (type.GetGenericArguments()[0] != typeof(string)) { stringBuilder.Append("{}"); return; } stringBuilder.Append('{'); IDictionary dictionary = item as IDictionary; bool flag2 = true; foreach (object key in dictionary.Keys) { if (flag2) { flag2 = false; } else { stringBuilder.Append(','); } stringBuilder.Append('"'); stringBuilder.Append((string)key); stringBuilder.Append("\":"); AppendValue(stringBuilder, dictionary[key]); } stringBuilder.Append('}'); return; } stringBuilder.Append('{'); bool flag3 = true; FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy); for (int k = 0; k < fields.Length; k++) { if (fields[k].IsDefined(typeof(IgnoreDataMemberAttribute), inherit: true)) { continue; } object value = fields[k].GetValue(item); if (value != null) { if (flag3) { flag3 = false; } else { stringBuilder.Append(','); } stringBuilder.Append('"'); stringBuilder.Append(GetMemberName(fields[k])); stringBuilder.Append("\":"); AppendValue(stringBuilder, value); } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy); for (int l = 0; l < properties.Length; l++) { if (!properties[l].CanRead || properties[l].IsDefined(typeof(IgnoreDataMemberAttribute), inherit: true)) { continue; } object value2 = properties[l].GetValue(item, null); if (value2 != null) { if (flag3) { flag3 = false; } else { stringBuilder.Append(','); } stringBuilder.Append('"'); stringBuilder.Append(GetMemberName(properties[l])); stringBuilder.Append("\":"); AppendValue(stringBuilder, value2); } } stringBuilder.Append('}'); } private static string GetMemberName(MemberInfo member) { if (member.IsDefined(typeof(DataMemberAttribute), inherit: true)) { DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(member, typeof(DataMemberAttribute), inherit: true); if (!string.IsNullOrEmpty(dataMemberAttribute.Name)) { return dataMemberAttribute.Name; } } return member.Name; } } } namespace ProperSave { public static class Extensions { public static int DifferenceCount<T>(this IEnumerable<T> collection, IEnumerable<T> second) { List<T> list = second.ToList(); int num = 0; foreach (T item in collection) { if (!list.Remove(item)) { num++; } } return num + list.Count; } public static int AddOrIndexOf<T>(this List<T> list, T value) { int num = list.IndexOf(value); if (num < 0) { list.Add(value); return list.Count - 1; } return num; } public static T GetSafe<T>(this List<T> list, int index) { if (list == null || list.Count < (uint)index) { return default(T); } return list[index]; } } public static class LanguageConsts { public static readonly string PROPER_SAVE_TITLE_CONTINUE_DESC = "PROPER_SAVE_TITLE_CONTINUE_DESC"; public static readonly string PROPER_SAVE_TITLE_CONTINUE = "PROPER_SAVE_TITLE_CONTINUE"; public static readonly string PROPER_SAVE_TITLE_LOAD = "PROPER_SAVE_TITLE_LOAD"; public static readonly string PROPER_SAVE_CHAT_SAVE = "PROPER_SAVE_CHAT_SAVE"; public static readonly string PROPER_SAVE_QUIT_DIALOG_SAVED = "PROPER_SAVE_QUIT_DIALOG_SAVED"; public static readonly string PROPER_SAVE_QUIT_DIALOG_SAVED_BEFORE = "PROPER_SAVE_QUIT_DIALOG_SAVED_BEFORE"; public static readonly string PROPER_SAVE_QUIT_DIALOG_NOT_SAVED = "PROPER_SAVE_QUIT_DIALOG_NOT_SAVED"; public static readonly string PROPER_SAVE_TOOLTIP_LOAD_TITLE = "PROPER_SAVE_TOOLTIP_LOAD_TITLE"; public static readonly string PROPER_SAVE_TOOLTIP_LOAD_DESCRIPTION_BODY = "PROPER_SAVE_TOOLTIP_LOAD_DESCRIPTION_BODY"; public static readonly string PROPER_SAVE_TOOLTIP_LOAD_DESCRIPTION_CHARACTER = "PROPER_SAVE_TOOLTIP_LOAD_DESCRIPTION_CHARACTER"; public static readonly string PROPER_SAVE_TOOLTIP_LOAD_CONTENT_MISMATCH = "PROPER_SAVE_TOOLTIP_LOAD_CONTENT_MISMATCH"; public static readonly string PROPER_SAVE_CHAT_SAVE_FAILED = "PROPER_SAVE_CHAT_SAVE_FAILED"; public static readonly string PROPER_SAVE_SELECT_SAVE_TITLE = "PROPER_SAVE_SELECT_SAVE_TITLE"; public static readonly string PROPER_SAVE_SELECT_SAVE_DESCRIPTION = "PROPER_SAVE_SELECT_SAVE_DESCRIPTION"; public static readonly string PROPER_SAVE_SELECT_SAVE_BUTTON = "PROPER_SAVE_SELECT_SAVE_BUTTON"; public static readonly string PROPER_SAVE_SELECT_SAVE_CANCEL = "PROPER_SAVE_SELECT_SAVE_CANCEL"; public static readonly string PROPER_SAVE_DELETE_SAVE = "PROPER_SAVE_DELETE_SAVE"; public static readonly string PROPER_SAVE_DELETE_SAVE_TITLE = "PROPER_SAVE_DELETE_SAVE_TITLE"; public static readonly string PROPER_SAVE_DELETE_SAVE_DESCRIPTION = "PROPER_SAVE_DELETE_SAVE_DESCRIPTION"; public static readonly string PROPER_SAVE_DELETE_CONFIRM_TITLE = "PROPER_SAVE_DELETE_CONFIRM_TITLE"; public static readonly string PROPER_SAVE_DELETE_CONFIRM_DESCRIPTION = "PROPER_SAVE_DELETE_CONFIRM_DESCRIPTION"; public static readonly string PROPER_SAVE_DELETE_CONFIRM_YES = "PROPER_SAVE_DELETE_CONFIRM_YES"; public static readonly string PROPER_SAVE_SELECT_HINT = "PROPER_SAVE_SELECT_HINT"; public static readonly string PROPER_SAVE_BACK_HINT = "PROPER_SAVE_BACK_HINT"; public static readonly string PROPER_SAVE_MOUSE_SELECT_HINT = "PROPER_SAVE_MOUSE_SELECT_HINT"; public static readonly string PROPER_SAVE_ESC_HINT = "PROPER_SAVE_ESC_HINT"; } public static class Loading { private static bool isLoading; public static bool IsLoading { get { return isLoading; } internal set { if (isLoading != value) { isLoading = value; if (isLoading) { Loading.OnLoadingStarted?.Invoke(CurrentSave); } else { Loading.OnLoadingEnded?.Invoke(CurrentSave); } } } } public static bool FirstRunStage { get; internal set; } public static SaveFile CurrentSave => ProperSavePlugin.CurrentSave?.Body; public static event Action<SaveFile> OnLoadingStarted; public static event Action<SaveFile> OnLoadingEnded; internal static void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown Run.Start += new Manipulator(RunStart); TeamManager.Start += new hook_Start(TeamManagerStart); } internal static void UnregisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown Run.Start -= new Manipulator(RunStart); TeamManager.Start -= new hook_Start(TeamManagerStart); } private static void TeamManagerStart(orig_Start orig, TeamManager self) { orig.Invoke(self); if (IsLoading) { CurrentSave.LoadTeam(); IsLoading = false; } } private static void RunStart(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); val.EmitDelegate<Func<bool>>((Func<bool>)delegate { FirstRunStage = true; if (IsLoading) { ProperSavePlugin.InstanceLogger.LogInfo((object)("Loading save file " + ProperSavePlugin.CurrentSave.FileName)); CurrentSave.LoadRun(); CurrentSave.LoadArtifacts(); CurrentSave.LoadPlayers(); } else { ProperSavePlugin.CurrentSave = null; } return IsLoading; }); val.Emit(OpCodes.Brfalse, val.Next); val.Emit(OpCodes.Ret); } internal static IEnumerator LoadLobby() { SaveFileMetadata currentLobbySaveMetadata = SaveFileMetadata.GetCurrentLobbySaveMetadata(); yield return LoadLobby(currentLobbySaveMetadata); } internal static IEnumerator LoadLobby(SaveFileMetadata metadata) { if ((Object)(object)PreGameController.instance == (Object)null) { ProperSavePlugin.InstanceLogger.LogInfo((object)"PreGameController instance not found"); yield break; } NetworkManagerSystem singleton = NetworkManagerSystem.singleton; if (singleton != null && singleton.desiredHost.hostingParameters.listen && !PlatformSystems.lobbyManager.ownsLobby) { ProperSavePlugin.InstanceLogger.LogInfo((object)"You must be a lobby leader to load the game"); yield break; } if (metadata == null) { ProperSavePlugin.InstanceLogger.LogInfo((object)"Save file for current users is not found"); yield break; } UPath? filePath = metadata.FilePath; if (!filePath.HasValue) { ProperSavePlugin.InstanceLogger.LogInfo((object)"Metadata doesn't contain file name for the save file"); yield break; } if (!ProperSavePlugin.SavesFileSystem.FileExists(filePath.Value)) { ProperSavePlugin.InstanceLogger.LogInfo((object)$"File \"{filePath}\" is not found"); yield break; } metadata.ReadBody(); ProperSavePlugin.CurrentSave = metadata; IsLoading = true; if (metadata.Header.ContentHash != ProperSavePlugin.ContentHash) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Loading run but content mismatch detected which may result in errors"); } PreGameController.instance.StartRun(); } [ConCommand(/*Could not decode attribute arguments.*/)] internal static void LoadForce(ConCommandArgs args) { string text = ((ConCommandArgs)(ref args)).TryGetArgString(0); if (string.IsNullOrWhiteSpace(text) || !File.Exists(text)) { Debug.LogError((object)"Incorrect path"); return; } SaveFileMetadata saveFileMetadata = new SaveFileMetadata(); try { saveFileMetadata.ReadForce(text); ProperSavePlugin.CurrentSave = saveFileMetadata; IsLoading = true; } catch (Exception ex) { Debug.LogWarning((object)("Failed to load save file at path \"" + text + "\"")); ProperSavePlugin.InstanceLogger.LogError((object)ex); ResetLoading(); } if (saveFileMetadata.Header.ContentHash != ProperSavePlugin.ContentHash) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Loading run but content mismatch detected which may result in errors"); } if (Object.op_Implicit((Object)(object)PreGameController.instance)) { if (NetworkUser.readOnlyInstancesList.Count > 0) { Debug.LogWarning((object)"Force loading only allowed for 1 player in lobby"); ResetLoading(); } else { PreGameController.instance.StartRun(); } } else { ((MonoBehaviour)ProperSavePlugin.Instance).StartCoroutine(LoadForceCoroutine()); } static void ResetLoading() { ProperSavePlugin.CurrentSave = null; IsLoading = false; } } private static IEnumerator LoadForceCoroutine() { Console.instance.SubmitCmd((NetworkUser)null, "host 0", false); yield return (object)new WaitUntil((Func<bool>)(() => (Object)(object)PreGameController.instance != (Object)null)); PreGameController.instance.StartRun(); } } internal static class LobbyUI { private class SaveDialogCloseWatcher : MonoBehaviour { public SimpleDialogBox dialog; public Action onCancel; private float delay = 0.4f; private bool closing; private void Update() { if (!closing) { delay -= Time.unscaledDeltaTime; if (!(delay > 0f) && (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)331))) { closing = true; GameObject obj = (((Object)(object)dialog.rootObject != (Object)null) ? dialog.rootObject : ((Component)dialog).gameObject); onCancel?.Invoke(); Object.Destroy((Object)(object)obj); } } } } private class CompactSaveDialogButton : MonoBehaviour { } private class SaveDialogInputLegendController : MonoBehaviour { public MPEventSystem eventSystem; public InputBindingDisplayController selectGlyph; public InputBindingDisplayController backGlyph; private void Update() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 bool visible = (Object)(object)eventSystem != (Object)null && (int)eventSystem.currentInputSource == 1; SetGlyphVisible(selectGlyph, visible); SetGlyphVisible(backGlyph, visible); } private static void SetGlyphVisible(InputBindingDisplayController glyph, bool visible) { if (!((Object)(object)glyph == (Object)null)) { HGTextMeshProUGUI component = ((Component)glyph).GetComponent<HGTextMeshProUGUI>(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = visible; } Transform val = ((Component)glyph).transform.parent.Find("KeyFallback"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(!visible); } } } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__24_1; public static UnityAction <>9__25_0; public static UnityAction <>9__26_1; public static Action <>9__26_2; public static Func<MPButton, bool> <>9__33_0; public static Func<MPButton, Transform> <>9__33_1; public static Func<MPButton, bool> <>9__34_0; internal void <ShowSaveSelectionDialog>b__24_1() { } internal void <ShowDeleteSaveDialog>b__25_0() { } internal void <ShowDeleteConfirmDialog>b__26_1() { ShowSaveSelectionDialog(SaveFileMetadata.GetCurrentLobbySaveMetadatas()); } internal void <ShowDeleteConfirmDialog>b__26_2() { ShowSaveSelectionDialog(SaveFileMetadata.GetCurrentLobbySaveMetadatas()); } internal bool <ApplyConfirmDialogLayout>b__33_0(MPButton button) { return (Object)(object)((Component)button).GetComponentInParent<SaveDialogInputLegendController>() == (Object)null; } internal Transform <ApplyConfirmDialogLayout>b__33_1(MPButton button) { return ((Component)button).transform; } internal bool <WrapSaveDialogNavigation>b__34_0(MPButton button) { return (Object)(object)((Component)button).GetComponentInParent<SaveDialogInputLegendController>() == (Object)null; } } private static GameObject lobbyButton; private static GameObject lobbySubmenuLegend; private static GameObject lobbyGlyphAndDescription; private static TooltipProvider tooltipProvider; private static GamepadTooltipProvider gamepadTooltipProvider; private static SaveFileMetadata lastFileMetadata; private static TooltipContent lastTooltipContent; private const float DialogWidth = 640f; private const float SaveButtonHeight = 86f; private const float CompactButtonHeight = 52f; private const float LegendHeight = 42f; private const float ConfirmRowHeight = 56f; private const float ConfirmButtonWidth = 230f; private const float ConfirmButtonHeight = 48f; private const float LegendItemWidth = 260f; private const float LegendItemHeight = 30f; public static void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown CharacterSelectController.Awake += new hook_Awake(CharacterSelectControllerAwake); NetworkUser.onPostNetworkUserStart += new NetworkUserGenericDelegate(NetworkUserOnPostNetworkUserStart); NetworkUser.onNetworkUserLost += new NetworkUserGenericDelegate(NetworkUserOnNetworkUserLost); } public static void UnregisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown CharacterSelectController.Awake -= new hook_Awake(CharacterSelectControllerAwake); NetworkUser.onPostNetworkUserStart -= new NetworkUserGenericDelegate(NetworkUserOnPostNetworkUserStart); NetworkUser.onNetworkUserLost -= new NetworkUserGenericDelegate(NetworkUserOnNetworkUserLost); } private static void NetworkUserOnNetworkUserLost(NetworkUser networkUser) { UpdateLobbyControls(networkUser); } private static void NetworkUserOnPostNetworkUserStart(NetworkUser networkUser) { UpdateLobbyControls(); } private static void CharacterSelectControllerAwake(orig_Awake orig, CharacterSelectController self) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Invalid comparison between Unknown and I4 //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Expected O, but got Unknown //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Expected O, but got Unknown //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Expected O, but got Unknown try { GameObject gameObject = ((Component)((Component)self).transform.GetChild(2).GetChild(4).GetChild(0)).gameObject; lobbyButton = Object.Instantiate<GameObject>(gameObject, gameObject.transform.parent); InputSourceFilter[] components = ((Component)self).GetComponents<InputSourceFilter>(); foreach (InputSourceFilter val in components) { if ((int)val.requiredInputSource == 0) { Array.Resize(ref val.objectsToFilter, val.objectsToFilter.Length + 1); val.objectsToFilter[val.objectsToFilter.Length - 1] = lobbyButton; break; } } ((Object)lobbyButton).name = "[CENI] Load"; tooltipProvider = lobbyButton.AddComponent<TooltipProvider>(); RectTransform component = lobbyButton.GetComponent<RectTransform>(); component.anchorMin = new Vector2(1f, 1.5f); component.anchorMax = new Vector2(1f, 1.5f); HGButton component2 = lobbyButton.GetComponent<HGButton>(); component2.hoverToken = LanguageConsts.PROPER_SAVE_TITLE_CONTINUE_DESC; lobbyButton.GetComponent<LanguageTextMeshController>().token = LanguageConsts.PROPER_SAVE_TITLE_LOAD; ((Button)component2).onClick = new ButtonClickedEvent(); ((UnityEvent)((Button)component2).onClick).AddListener(new UnityAction(LoadOnInputEvent)); GameObject gameObject2 = ((Component)((Component)self).transform.GetChild(2).GetChild(4).GetChild(1)).gameObject; lobbySubmenuLegend = Object.Instantiate<GameObject>(gameObject2, gameObject2.transform.parent); components = ((Component)self).GetComponents<InputSourceFilter>(); foreach (InputSourceFilter val2 in components) { if ((int)val2.requiredInputSource == 1) { Array.Resize(ref val2.objectsToFilter, val2.objectsToFilter.Length + 1); val2.objectsToFilter[val2.objectsToFilter.Length - 1] = lobbySubmenuLegend; break; } } ((Object)lobbySubmenuLegend).name = "[CENI] SubmenuLegend"; UIJuice component3 = lobbySubmenuLegend.GetComponent<UIJuice>(); OnEnableEvent component4 = lobbySubmenuLegend.GetComponent<OnEnableEvent>(); ((UnityEventBase)component4.action).RemoveAllListeners(); component4.action.AddListener(new UnityAction(component3.TransitionPanFromTop)); component4.action.AddListener(new UnityAction(component3.TransitionAlphaFadeIn)); RectTransform component5 = lobbySubmenuLegend.GetComponent<RectTransform>(); component5.anchorMin = new Vector2(1f, 1f); component5.anchorMax = new Vector2(1f, 2f); lobbyGlyphAndDescription = ((Component)lobbySubmenuLegend.transform.GetChild(0)).gameObject; lobbyGlyphAndDescription.SetActive(true); InputBindingDisplayController component6 = ((Component)lobbyGlyphAndDescription.transform.GetChild(0)).GetComponent<InputBindingDisplayController>(); component6.actionName = "UISubmitTertiary"; Transform child = lobbyGlyphAndDescription.transform.GetChild(1); LanguageTextMeshController component7 = ((Component)lobbyGlyphAndDescription.transform.GetChild(2)).GetComponent<LanguageTextMeshController>(); Object.Destroy((Object)(object)((Component)child).gameObject); component7.token = LanguageConsts.PROPER_SAVE_TITLE_LOAD; for (int j = 1; j < lobbySubmenuLegend.transform.childCount; j++) { Object.Destroy((Object)(object)((Component)lobbySubmenuLegend.transform.GetChild(j)).gameObject); } HoldGamepadInputEvent holdGamepadInputEvent = ((Component)self).gameObject.AddComponent<HoldGamepadInputEvent>(); ((HGGamepadInputEvent)holdGamepadInputEvent).actionName = "UISubmitTertiary"; ((HGGamepadInputEvent)holdGamepadInputEvent).enabledObjectsIfActive = Array.Empty<GameObject>(); ((HGGamepadInputEvent)holdGamepadInputEvent).actionEvent = new UnityEvent(); ((HGGamepadInputEvent)holdGamepadInputEvent).actionEvent.AddListener(new UnityAction(LoadOnInputEvent)); gamepadTooltipProvider = ((Component)component6).gameObject.AddComponent<GamepadTooltipProvider>(); gamepadTooltipProvider.inputEvent = holdGamepadInputEvent; UpdateLobbyControls(); } catch (Exception ex) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Failed while adding lobby buttons"); ProperSavePlugin.InstanceLogger.LogError((object)ex); } orig.Invoke(self); } private static void LoadOnInputEvent() { if ((Object)(object)Run.instance != (Object)null) { ProperSavePlugin.InstanceLogger.LogInfo((object)"Can't load while run is active"); return; } if (Loading.IsLoading) { ProperSavePlugin.InstanceLogger.LogInfo((object)"Already loading"); return; } List<SaveFileMetadata> currentLobbySaveMetadatas = SaveFileMetadata.GetCurrentLobbySaveMetadatas(); if (currentLobbySaveMetadatas.Count == 0) { ProperSavePlugin.InstanceLogger.LogInfo((object)"Save file for current users is not found"); } else { ShowSaveSelectionDialog(currentLobbySaveMetadatas); } } private static void UpdateLobbyControls(NetworkUser exceptUser = null) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) SaveFileMetadata currentLobbySaveMetadata = SaveFileMetadata.GetCurrentLobbySaveMetadata(exceptUser); bool flag = PlatformSystems.lobbyManager.isInLobby == PlatformSystems.lobbyManager.ownsLobby && currentLobbySaveMetadata != null && currentLobbySaveMetadata.FilePath.HasValue && ProperSavePlugin.SavesFileSystem.FileExists(currentLobbySaveMetadata.FilePath.Value); if (currentLobbySaveMetadata != lastFileMetadata) { lastFileMetadata = currentLobbySaveMetadata; try { if (currentLobbySaveMetadata != null) { lastTooltipContent = new TooltipContent { titleToken = LanguageConsts.PROPER_SAVE_TOOLTIP_LOAD_TITLE, overrideBodyText = GetSaveDescription(currentLobbySaveMetadata), titleColor = Color.black, disableBodyRichText = false }; } else { lastTooltipContent = default(TooltipContent); } } catch (Exception ex) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Failed to get information about save file"); ProperSavePlugin.InstanceLogger.LogError((object)ex); flag = false; } } try { if (Object.op_Implicit((Object)(object)lobbyButton)) { HGButton component = lobbyButton.GetComponent<HGButton>(); if (Object.op_Implicit((Object)(object)component)) { ((Selectable)component).interactable = flag; } } if (Object.op_Implicit((Object)(object)tooltipProvider)) { tooltipProvider.SetContent(lastTooltipContent); } } catch { } try { if (Object.op_Implicit((Object)(object)lobbyGlyphAndDescription)) { Color color = (Color)(flag ? Color.white : new Color(0.3f, 0.3f, 0.3f)); ((Graphic)((Component)lobbyGlyphAndDescription.transform.GetChild(0)).GetComponent<HGTextMeshProUGUI>()).color = color; ((Graphic)((Component)lobbyGlyphAndDescription.transform.GetChild(1)).GetComponent<HGTextMeshProUGUI>()).color = color; } if (Object.op_Implicit((Object)(object)gamepadTooltipProvider)) { ((TooltipProvider)gamepadTooltipProvider).SetContent(lastTooltipContent); } } catch { } } private static string GetSaveDescription(SaveFileMetadata saveMetadata) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) SaveFileHeader header = saveMetadata.Header; StringBuilder stringBuilder = new StringBuilder(); HeaderUserData[] users = header.Users; foreach (HeaderUserData userData in users) { NetworkUser val = ((IEnumerable<NetworkUser>)NetworkUser.readOnlyInstancesList).FirstOrDefault((Func<NetworkUser, bool>)delegate(NetworkUser user) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) NetworkUserId val3 = userData.UserId.Load(); return ((NetworkUserId)(ref val3)).Equals(user.id); }); SurvivorDef val2 = SurvivorCatalog.FindSurvivorDefFromBody(BodyCatalog.GetBodyPrefab(userData.Body)); stringBuilder.Append(Language.GetStringFormatted(LanguageConsts.PROPER_SAVE_TOOLTIP_LOAD_DESCRIPTION_CHARACTER, new object[2] { val?.userName, ((Object)(object)val2 != (Object)null) ? Language.GetString(val2.displayNameToken) : "" })); } SceneDef sceneDefFromSceneName = SceneCatalog.GetSceneDefFromSceneName(header.SceneName); DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(header.Difficulty); int time = header.Time; int stageClearCount = header.StageClearCount; return Language.GetStringFormatted(LanguageConsts.PROPER_SAVE_TOOLTIP_LOAD_DESCRIPTION_BODY, new object[6] { stringBuilder.ToString(), Object.op_Implicit((Object)(object)sceneDefFromSceneName) ? Language.GetString(sceneDefFromSceneName.nameToken) : "", (stageClearCount + 1).ToString(), $"{time / 60:00}:{time % 60:00}", (difficultyDef != null) ? Language.GetString(difficultyDef.nameToken) : "", (header.ContentHash != ProperSavePlugin.ContentHash) ? Language.GetString(LanguageConsts.PROPER_SAVE_TOOLTIP_LOAD_CONTENT_MISMATCH) : "" }); } private static void ShowSaveSelectionDialog(List<SaveFileMetadata> saves) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown EventSystem current = EventSystem.current; SimpleDialogBox val = SimpleDialogBox.Create((MPEventSystem)(object)((current is MPEventSystem) ? current : null)); if ((Object)(object)val == (Object)null) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Failed to create save selection dialog"); return; } val.headerToken = new TokenParamsPair { token = LanguageConsts.PROPER_SAVE_SELECT_SAVE_TITLE }; val.descriptionToken = new TokenParamsPair { token = LanguageConsts.PROPER_SAVE_SELECT_SAVE_DESCRIPTION }; foreach (SaveFileMetadata safe in saves) { SaveFileMetadata captured = safe; val.AddActionButton((UnityAction)delegate { ((MonoBehaviour)ProperSavePlugin.Instance).StartCoroutine(Loading.LoadLobby(captured)); }, LanguageConsts.PROPER_SAVE_TITLE_LOAD, true, Array.Empty<object>()); SetLastButtonContent(val, GetSaveButtonDescription(safe), GetSavePortrait(safe)); } val.AddActionButton((UnityAction)delegate { ShowDeleteSaveDialog(saves); }, LanguageConsts.PROPER_SAVE_DELETE_SAVE, true, Array.Empty<object>()); MarkLastButtonCompact(val); object obj = <>c.<>9__24_1; if (obj == null) { UnityAction val2 = delegate { }; <>c.<>9__24_1 = val2; obj = (object)val2; } val.AddActionButton((UnityAction)obj, LanguageConsts.PROPER_SAVE_SELECT_SAVE_CANCEL, true, Array.Empty<object>()); MarkLastButtonCompact(val); AddCloseWatcher(val); ((MonoBehaviour)ProperSavePlugin.Instance).StartCoroutine(DelayedSaveDialogLayout(val)); } private static void ShowDeleteSaveDialog(List<SaveFileMetadata> saves) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown EventSystem current = EventSystem.current; SimpleDialogBox val = SimpleDialogBox.Create((MPEventSystem)(object)((current is MPEventSystem) ? current : null)); if ((Object)(object)val == (Object)null) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Failed to create delete save dialog"); return; } val.headerToken = new TokenParamsPair { token = LanguageConsts.PROPER_SAVE_DELETE_SAVE_TITLE }; val.descriptionToken = new TokenParamsPair { token = LanguageConsts.PROPER_SAVE_DELETE_SAVE_DESCRIPTION }; foreach (SaveFileMetadata safe in saves) { SaveFileMetadata captured = safe; val.AddActionButton((UnityAction)delegate { ShowDeleteConfirmDialog(captured); }, LanguageConsts.PROPER_SAVE_DELETE_SAVE, true, Array.Empty<object>()); SetLastButtonContent(val, GetSaveButtonDescription(safe), GetSavePortrait(safe)); } object obj = <>c.<>9__25_0; if (obj == null) { UnityAction val2 = delegate { }; <>c.<>9__25_0 = val2; obj = (object)val2; } val.AddActionButton((UnityAction)obj, LanguageConsts.PROPER_SAVE_SELECT_SAVE_CANCEL, true, Array.Empty<object>()); MarkLastButtonCompact(val); AddCloseWatcher(val); ((MonoBehaviour)ProperSavePlugin.Instance).StartCoroutine(DelayedSaveDialogLayout(val)); } private static void ShowDeleteConfirmDialog(SaveFileMetadata save) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown EventSystem current = EventSystem.current; SimpleDialogBox val = SimpleDialogBox.Create((MPEventSystem)(object)((current is MPEventSystem) ? current : null)); if ((Object)(object)val == (Object)null) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Failed to create delete confirmation dialog"); return; } val.headerToken = new TokenParamsPair { token = LanguageConsts.PROPER_SAVE_DELETE_CONFIRM_TITLE }; val.descriptionToken = new TokenParamsPair { token = LanguageConsts.PROPER_SAVE_DELETE_CONFIRM_DESCRIPTION }; val.AddActionButton((UnityAction)delegate { SaveFileMetadata.DeleteSave(save); UpdateLobbyControls(); }, LanguageConsts.PROPER_SAVE_DELETE_CONFIRM_YES, true, Array.Empty<object>()); object obj = <>c.<>9__26_1; if (obj == null) { UnityAction val2 = delegate { ShowSaveSelectionDialog(SaveFileMetadata.GetCurrentLobbySaveMetadatas()); }; <>c.<>9__26_1 = val2; obj = (object)val2; } val.AddActionButton((UnityAction)obj, LanguageConsts.PROPER_SAVE_SELECT_SAVE_CANCEL, true, Array.Empty<object>()); AddCloseWatcher(val, delegate { ShowSaveSelectionDialog(SaveFileMetadata.GetCurrentLobbySaveMetadatas()); }); ((MonoBehaviour)ProperSavePlugin.Instance).StartCoroutine(DelayedSaveDialogLayout(val, confirmLayout: true)); } private static string GetSaveButtonDescription(SaveFileMetadata saveMetadata) { //IL_005a: 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) SaveFileHeader header = saveMetadata.Header; string text = ""; if (header.Users.Length != 0) { SurvivorDef val = SurvivorCatalog.FindSurvivorDefFromBody(BodyCatalog.GetBodyPrefab(header.Users[0].Body)); text = (((Object)(object)val != (Object)null) ? Language.GetString(val.displayNameToken) : ""); } SceneDef sceneDefFromSceneName = SceneCatalog.GetSceneDefFromSceneName(header.SceneName); DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(header.Difficulty); int time = header.Time; return Language.GetStringFormatted(LanguageConsts.PROPER_SAVE_SELECT_SAVE_BUTTON, new object[6] { text, Object.op_Implicit((Object)(object)sceneDefFromSceneName) ? Language.GetString(sceneDefFromSceneName.nameToken) : header.SceneName, (header.StageClearCount + 1).ToString(), $"{time / 60:00}:{time % 60:00}", (difficultyDef != null) ? Language.GetString(difficultyDef.nameToken) : "", "" }); } private static Texture GetSavePortrait(SaveFileMetadata saveMetadata) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) try { SaveFileHeader header = saveMetadata.Header; if (header.Users.Length == 0) { return null; } GameObject bodyPrefab = BodyCatalog.GetBodyPrefab(header.Users[0].Body); CharacterBody val = (Object.op_Implicit((Object)(object)bodyPrefab) ? bodyPrefab.GetComponent<CharacterBody>() : null); return Object.op_Implicit((Object)(object)val) ? val.portraitIcon : null; } catch { return null; } } private static void SetLastButtonContent(SimpleDialogBox dialog, string text, Texture portrait) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: 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) try { RectTransform buttonContainer = dialog.buttonContainer; if ((Object)(object)buttonContainer == (Object)null || ((Transform)buttonContainer).childCount == 0) { return; } Transform child = ((Transform)buttonContainer).GetChild(((Transform)buttonContainer).childCount - 1); if ((Object)(object)portrait != (Object)null) { AddPortraitToButton(child, portrait); } LanguageTextMeshController[] componentsInChildren = ((Component)child).GetComponentsInChildren<LanguageTextMeshController>(); for (int i = 0; i < componentsInChildren.Length; i++) { ((Behaviour)componentsInChildren[i]).enabled = false; } HGTextMeshProUGUI componentInChildren = ((Component)child).GetComponentInChildren<HGTextMeshProUGUI>(); if ((Object)(object)componentInChildren != (Object)null) { ((TMP_Text)componentInChildren).text = text; ((TMP_Text)componentInChildren).enableWordWrapping = true; ((TMP_Text)componentInChildren).alignment = (TextAlignmentOptions)4097; ((TMP_Text)componentInChildren).fontSize = 18f; RectTransform component = ((Component)componentInChildren).GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null && (Object)(object)portrait != (Object)null) { component.offsetMin = new Vector2(component.offsetMin.x + 78f, component.offsetMin.y); } } } catch (Exception ex) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Failed to set save button content"); ProperSavePlugin.InstanceLogger.LogError((object)ex); } } private static void AddPortraitToButton(Transform button, Texture portrait) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("[CENI] Portrait", new Type[2] { typeof(RectTransform), typeof(RawImage) }); RectTransform component = val.GetComponent<RectTransform>(); ((Transform)component).SetParent(button, false); component.anchorMin = new Vector2(0f, 0.5f); component.anchorMax = new Vector2(0f, 0.5f); component.pivot = new Vector2(0f, 0.5f); component.anchoredPosition = new Vector2(12f, 0f); component.sizeDelta = new Vector2(64f, 64f); RawImage component2 = val.GetComponent<RawImage>(); component2.texture = portrait; ((Graphic)component2).color = Color.white; ((Graphic)component2).raycastTarget = false; } private static IEnumerator DelayedSaveDialogLayout(SimpleDialogBox dialog, bool confirmLayout = false) { yield return null; if (confirmLayout) { ApplyConfirmDialogLayout(dialog); } else { ApplySaveDialogLayout(dialog); } } private static void ApplySaveDialogLayout(SimpleDialogBox dialog) { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) try { RectTransform buttonContainer = dialog.buttonContainer; if ((Object)(object)buttonContainer == (Object)null) { return; } AddInputLegend(dialog); LayoutGroup[] components = ((Component)buttonContainer).GetComponents<LayoutGroup>(); foreach (LayoutGroup obj in components) { ((Behaviour)obj).enabled = false; Object.DestroyImmediate((Object)(object)obj, true); } VerticalLayoutGroup obj2 = ((Component)buttonContainer).gameObject.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 8f; ((LayoutGroup)obj2).childAlignment = (TextAnchor)1; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = false; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; for (int j = 0; j < ((Transform)buttonContainer).childCount; j++) { Transform child = ((Transform)buttonContainer).GetChild(j); if ((Object)(object)((Component)child).GetComponent<SaveDialogInputLegendController>() != (Object)null) { ConfigureInputLegendLayout(child); continue; } float num = (((Object)(object)((Component)child).GetComponent<CompactSaveDialogButton>() != (Object)null) ? 52f : 86f); RectTransform component = ((Component)child).GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { component.sizeDelta = new Vector2(640f, num); } SetLayoutElement(((Component)child).gameObject, 640f, num); } ContentSizeFitter obj3 = ((Component)buttonContainer).GetComponent<ContentSizeFitter>() ?? ((Component)buttonContainer).gameObject.AddComponent<ContentSizeFitter>(); obj3.verticalFit = (FitMode)2; obj3.horizontalFit = (FitMode)2; WrapSaveDialogNavigation(buttonContainer); LayoutRebuilder.ForceRebuildLayoutImmediate(buttonContainer); } catch (Exception ex) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Failed to apply save selection layout"); ProperSavePlugin.InstanceLogger.LogError((object)ex); } } private static void ApplyConfirmDialogLayout(SimpleDialogBox dialog) { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) try { RectTransform buttonContainer = dialog.buttonContainer; if ((Object)(object)buttonContainer == (Object)null) { return; } AddInputLegend(dialog); LayoutGroup[] components = ((Component)buttonContainer).GetComponents<LayoutGroup>(); foreach (LayoutGroup obj in components) { ((Behaviour)obj).enabled = false; Object.DestroyImmediate((Object)(object)obj, true); } List<Transform> list = (from button in ((Component)buttonContainer).GetComponentsInChildren<MPButton>(true) where (Object)(object)((Component)button).GetComponentInParent<SaveDialogInputLegendController>() == (Object)null select ((Component)button).transform).Distinct().ToList(); Transform obj2 = ((Transform)buttonContainer).Find("[CENI] Confirm Button Row"); RectTransform val = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null); if ((Object)(object)val == (Object)null) { val = new GameObject("[CENI] Confirm Button Row", new Type[3] { typeof(RectTransform), typeof(HorizontalLayoutGroup), typeof(LayoutElement) }).GetComponent<RectTransform>(); ((Transform)val).SetParent((Transform)(object)buttonContainer, false); ((Transform)val).SetSiblingIndex(0); } SetCenteredRect(val, 640f, 56f); foreach (Transform item in list) { item.SetParent((Transform)(object)val, false); } HorizontalLayoutGroup component = ((Component)val).GetComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)component).spacing = 96f; ((LayoutGroup)component).childAlignment = (TextAnchor)4; ((HorizontalOrVerticalLayoutGroup)component).childControlWidth = false; ((HorizontalOrVerticalLayoutGroup)component).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)component).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)component).childForceExpandHeight = false; SetLayoutElement(((Component)val).gameObject, 640f, 56f); foreach (Transform item2 in list) { RectTransform component2 = ((Component)item2).GetComponent<RectTransform>(); if ((Object)(object)component2 != (Object)null) { SetCenteredRect(component2, 230f, 48f); } SetLayoutElement(((Component)item2).gameObject, 230f, 48f); } VerticalLayoutGroup obj3 = ((Component)buttonContainer).gameObject.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj3).spacing = 8f; ((LayoutGroup)obj3).childAlignment = (TextAnchor)1; ((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false; ConfigureInputLegendLayout(((Transform)buttonContainer).Find("[CENI] Save Input Legend")); ContentSizeFitter obj4 = ((Component)buttonContainer).GetComponent<ContentSizeFitter>() ?? ((Component)buttonContainer).gameObject.AddComponent<ContentSizeFitter>(); obj4.verticalFit = (FitMode)2; obj4.horizontalFit = (FitMode)2; WrapSaveDialogNavigation(buttonContainer); LayoutRebuilder.ForceRebuildLayoutImmediate(buttonContainer); } catch (Exception ex) { ProperSavePlugin.InstanceLogger.LogWarning((object)"Failed to apply delete confirmation layout"); ProperSavePlugin.InstanceLogger.LogError((object)ex); } } private static void WrapSaveDialogNavigation(RectTransform container) { //IL_003f: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) List<MPButton> list = (from button in ((Component)container).GetComponentsInChildren<MPButton>() where (Object)(object)((Component)button).GetComponentInParent<SaveDialogInputLegendController>() == (Object)null select button).ToList(); if (list.Count != 0) { for (int num = 0; num < list.Count; num++) { Navigation val = default(Navigation); ((Navigation)(ref val)).mode = (Mode)4; Navigation navigation = val; ((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)list[(num - 1 + list.Count) % list.Count]; ((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)list[(num + 1) % list.Count]; ((Navigation)(ref navigation)).selectOnLeft = ((Navigation)(ref navigation)).selectOnUp; ((Navigation)(ref navigation)).selectOnRight = ((Navigation)(ref navigation)).selectOnDown; ((Selectable)list[num]).navigation = navigation; } } } private static void AddInputLegend(SimpleDialogBox dialog) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown RectTransform val = dialog?.buttonContainer; if (!((Object)(object)val == (Object)null) && !((Object)(object)((Transform)val).Find("[CENI] Save Input Legend") != (Object)null)) { GameObject val2 = new GameObject("[CENI] Save Input Legend", new Type[3] { typeof(RectTransform), typeof(HorizontalLayoutGroup), typeof(SaveDialogInputLegendController) }); RectTransform component = val2.GetComponent<RectTransform>(); ((Transform)component).SetParent((Transform)(object)val, false); component.sizeDelta = new Vector2(640f, 42f); ConfigureInputLegendLayout(val2.transform); HorizontalLayoutGroup component2 = val2.GetComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)component2).spacing = 74f; ((LayoutGroup)component2).padding = new RectOffset(10, 0, 8, 0); ((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = false; SaveDialogInputLegendController component3 = val2.GetComponent<SaveDialogInputLegendController>(); ref MPEventSystem eventSystem = ref component3.eventSystem; EventSystem current = EventSystem.current; eventSystem = (MPEventSystem)(object)((current is MPEventSystem) ? current : null); component3.selectGlyph = AddLegendItem(component, "UISubmit", LanguageConsts.PROPER_SAVE_MOUSE_SELECT_HINT, LanguageConsts.PROPER_SAVE_SELECT_HINT); component3.backGlyph = AddLegendItem(component, "UICancel", LanguageConsts.PROPER_SAVE_ESC_HINT, LanguageConsts.PROPER_SAVE_BACK_HINT); } } private static void ConfigureInputLegendLayout(Transform legend) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)legend == (Object)null)) { RectTransform component = ((Component)legend).GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { component.sizeDelta = new Vector2(640f, 42f); } SetLayoutElement(((Component)legend).gameObject, 640f, 42f); } } private static InputBindingDisplayController AddLegendItem(RectTransform parent, string actionName, string keyToken, string textToken) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(actionName + " Legend", new Type[3] { typeof(RectTransform), typeof(HorizontalLayoutGroup), typeof(LayoutElement) }); RectTransform component = val.GetComponent<RectTransform>(); ((Transform)component).SetParent((Transform)(object)parent, false); component.sizeDelta = new Vector2(260f, 30f); HorizontalLayoutGroup component2 = val.GetComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)component2).spacing = 7f; ((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = false; ConfigureLayoutElement(val.GetComponent<LayoutElement>(), 260f, 30f); GameObject val2 = new GameObject("Glyph", new Type[1] { typeof(RectTransform) }); val2.SetActive(false); RectTransform component3 = val2.GetComponent<RectTransform>(); ((Transform)component3).SetParent((Transform)(object)component, false); component3.sizeDelta = new Vector2(28f, 28f); HGTextMeshProUGUI obj = val2.AddComponent<HGTextMeshProUGUI>(); ((TMP_Text)obj).fontSize = 18f; ((TMP_Text)obj).alignment = (TextAlignmentOptions)514; InputBindingDisplayController val3 = val2.AddComponent<InputBindingDisplayController>(); val3.actionName = actionName; val3.useExplicitInputSource = true; val3.explicitInputSource = (InputSource)1; val2.SetActive(true); GameObject val4 = new GameObject("KeyFallback", new Type[1] { typeof(RectTransform) }); val4.SetActive(false); RectTransform component4 = val4.GetComponent<RectTransform>(); ((Transform)component4).SetParent((Transform)(object)component, false); component4.sizeDelta = new Vector2(160f, 28f); HGTextMeshProUGUI obj2 = val4.AddComponent<HGTextMeshProUGUI>(); ((TMP_Text)obj2).fontSize = 14f; ((TMP_Text)obj2).alignment = (TextAlignmentOptions)4097; ((TMP_Text)obj2).enableWordWrapping = false; val4.AddComponent<LanguageTextMeshController>().token = keyToken; val4.SetActive(true); GameObject val5 = new GameObject("Label", new Type[1] { typeof(RectTransform) }); val5.SetActive(false); RectTransform component5 = val5.GetComponent<RectTransform>(); ((Transform)component5).SetParent((Transform)(object)component, false); component5.sizeDelta = new Vector2(90f, 28f); HGTextMeshProUGUI obj3 = val5.AddComponent<HGTextMeshProUGUI>(); ((TMP_Text)obj3).fontSize = 14f; ((TMP_Text)obj3).alignment = (TextAlignmentOptions)4097; ((TMP_Text)obj3).enableWordWrapping = false; val5.AddComponent<LanguageTextMeshController>().token = textToken; val5.SetActive(true); return val3; } private static SaveDialogCloseWatcher AddCloseWatcher(SimpleDialogBox dialog, Action onCancel = null) { SaveDialogCloseWatcher saveDialogCloseWatcher = GetDialogRoot(dialog).AddComponent<SaveDialogCloseWatcher>(); saveDialogCloseWatcher.dialog = dialog; saveDialogCloseWatcher.onCancel = onCancel; return saveDialogCloseWatcher; } private static GameObject GetDialogRoot(SimpleDialogBox dialog) { if (!((Object)(object)dialog.rootObject != (Object)null)) { return ((Component)dialog).gameObject; } return dialog.rootObject; } private static void SetCenteredRect(RectTransform rect, float width, float height) { //IL_000b: 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) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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) rect.anchorMin = new Vector2(0.5f, 0.5f); rect.anchorMax = new Vector2(0.5f, 0.5f); rect.pivot = new Vector2(0.5f, 0.5f); rect.anchoredPosition = Vector2.zero; rect.sizeDelta = new Vector2(width, height); } private static void SetLayoutElement(GameObject target, float width, float height) { ConfigureLayoutElement(target.GetComponent<LayoutElement>() ?? target.AddComponent<LayoutElement>(), width, height); } private static void ConfigureLayoutElement(LayoutElement element, float width, float height) { element.minWidth = width; element.preferredWidth = width; element.minHeight = height; element.preferredHeight = height; element.flexibleWidth = 0f; element.flexibleHeight = 0f; } private static void MarkLastButtonCompact(SimpleDialogBox dialog) { RectTransform val = dialog?.buttonContainer; if (!((Object)(object)val == (Object)null) && ((Transform)val).childCount != 0) { Transform child = ((Transform)val).GetChild(((Transform)val).childCount - 1); if ((Object)(object)((Component)child).GetComponent<CompactSaveDialogButton>() == (Object)null) { ((Component)child).gameObject.AddComponent<CompactSaveDialogButton>(); } } } } internal class LostNetworkUser : MonoBehaviour { private static readonly Dictionary<CharacterMaster, LostNetworkUser> lostUsers = new Dictionary<CharacterMaster, LostNetworkUser>(); private CharacterMaster master; public uint lunarCoins; public NetworkUserId userID; public BodyIndex bodyIndexPreference; private void Awake() { master = ((Component)this).GetComponent<CharacterMaster>(); lostUsers[master] = this; } private void OnDestroy() { lostUsers.Remove(master); } public static bool TryGetUser(CharacterMaster master, out LostNetworkUser lostUser) { if (!Object.op_Implicit((Object)(object)master) || !lostUsers.TryGetValue(master, out lostUser)) { lostUser = null; return false; } return true; } public static void Subscribe() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown NetworkUser.onNetworkUserLost += new NetworkUserGenericDelegate(OnNetworkUserLost); } public static void Unsubscribe() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown NetworkUser.onNetworkUserLost -= new NetworkUserGenericDelegate(OnNetworkUserLost); } private static void OnNetworkUserLost(NetworkUser networkUser) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)networkUser.master)) { LostNetworkUser lostNetworkUser = ((Component)networkUser.master).gameObject.AddComponent<LostNetworkUser>(); lostNetworkUser.lunarCoins = networkUser.lunarCoins; lostNetworkUser.userID = networkUser.id; lostNetworkUser.bodyIndexPreference = networkUser.bodyIndexPreference; } } } internal static class ModCompat { public const string BiggerBazaarGUID = "com.MagnusMagnuson.BiggerBazaar"; public const string ShareSuiteGUID = "com.funkfrog_sipondo.sharesuite"; public static bool IsBBLoaded { get; private set; } public static bool IsSSLoaded { get; private set; } public static bool IsR2APIDifficultyLoaded { get; private set; } private static Dictionary<MethodInfo, Action<ILContext>> RegisteredILHooks { get; } = new Dictionary<MethodInfo, Action<ILContext>>(); public static void GatherLoadedPlugins() { IsBBLoaded = Chainloader.PluginInfos.ContainsKey("com.MagnusMagnuson.BiggerBazaar"); IsSSLoaded = Chainloader.PluginInfos.ContainsKey("com.funkfrog_sipondo.sharesuite"); IsR2APIDifficultyLoaded = Chainloader.PluginInfos.ContainsKey("com.bepis.r2api.difficulty"); } public static void RegisterHooks() { if (IsBBLoaded) { try { RegisterBBHooks(); } catch (Exception ex) { ProperSavePlugin.InstanceLogger.LogError((object)"Failed to add support for BiggerBazaar"); ProperSavePlugin.InstanceLogger.LogError((object)ex); } } } public static void UnregisterHooks() { foreach (KeyValuePair<MethodInfo, Action<ILContext>> registeredILHook in RegisteredILHooks) { HookEndpointManager.Unmodify((MethodBase)registeredILHook.Key, (Delegate)registeredILHook.Value); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void RegisterBBHooks() { MethodInfo method = typeof(BiggerBazaar).Assembly.GetType("BiggerBazaar.Bazaar").GetMethod("StartBazaar", BindingFlags.Instance | BindingFlags.Public); Action<ILContext> action = BBHook; HookEndpointManager.Modify((MethodBase)method, (Delegate)action); RegisteredILHooks.Add(method, action); } private static void BBHook(ILContext il) { //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) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_005c: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) Type type = typeof(BiggerBazaar).Assembly.GetType("BiggerBazaar.Bazaar"); ILCursor val = new ILCursor(il); int index = val.Index; val.Index = index + 1; Instruction next = val.Next; val.Emit(OpCodes.Call, (MethodBase)typeof(Loading).GetProperty("FirstRunStage").GetGetMethod()); val.Emit(OpCodes.Brfalse, next); val.Emit(OpCodes.Ldarg_0); val.Emit(OpCodes.Call, (MethodBase)type.GetMethod("ResetBazaarPlayers")); val.Emit(OpCodes.Ldarg_0); val.Emit(OpCodes.Call, (MethodBase)type.GetMethod("CalcDifficultyCoefficient")); } public static void LoadShareSuiteMoney(uint money) { try { if (IsSSLoaded) { ((MonoBehaviour)ProperSavePlugin.Instance).StartCoroutine(LoadShareSuiteMoneyInternal(money)); } } catch (Exception ex) { ProperSavePlugin.InstanceLogger.LogError((object)ex); } } [MethodImpl(MethodImplOptions.NoInlining)] private static IEnumerator LoadShareSuiteMoneyInternal(uint money) { yield return (object)new WaitUntil((Func<bool>)(() => !MoneySharingHooks.MapTransitionActive)); MoneySharingHooks.SharedMoneyValue = (int)money; } public static void ShareSuiteMapTransition() { try { if (IsSSLoaded) { ShareSuiteMapTransitionInternal(); } } catch (Exception ex) { ProperSavePlugin.InstanceLogger.LogError((object)ex); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void ShareSuiteMapTransitionInternal() { MoneySharingHooks.MapTransitionActive = true; } [MethodImpl(MethodImplOptions.NoInlining)] internal static DifficultyIndex FindR2APIDifficultyIndex(string nameToken) { //IL_001f: 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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) foreach (var (result, val3) in DifficultyAPI.difficultyDefinitions) { if (val3.nameToken == nameToken) { return result; } } return (DifficultyIndex)(-1); } } [BepInPlugin("com.Jaosnake.CENI", "C.E.N.I", "1.0.0")] public class ProperSavePlugin : BaseUnityPlugin { public const string GUID = "com.Jaosnake.CENI"; public const string Name = "C.E.N.I"; public const string Version = "1.0.0"; internal const int MaxSaveSlotsPerCharacter = 5; private static readonly char[] invalidSubDirectoryCharacters = new char[3] { '\\', '/', '.' }; internal static ProperSavePlugin Instance { get; private set; } internal static ManualLogSource InstanceLogger { get { ProperSavePlugin instance = Instance; if (instance == null) { return null; } return ((BaseUnityPlugin)instance).Logger; } } internal static FileSystem SavesFileSystem { get; private set; } internal static UPath SavesPath { get; private set; } = UPath.op_Implicit("/ProperSave") / UPath.op_Implicit("Saves"); private static string SavesDirectory { get; set; } internal static SaveFileMetadata CurrentSave { get; set; } internal static string ContentHash { get; private set; } internal static ConfigEntry<bool> UseCloudStorage { get; private set; } internal static ConfigEntry<string> CloudStorageSubDirectory { get; private set; } internal static ConfigEntry<string> UserSavesDirectory { get; private set; } internal static ConfigEntry<bool> Resilient { get; private set; } private void Start() { Instance = this; UseCloudStorage = ((BaseUnityPlugin)this).Config.Bind<bool>("Main", "UseCloudStorage", false, "Store files in Steam/EpicGames cloud. Enabling this feature would not preserve current saves and disabling it wouldn't clear the cloud."); CloudStorageSubDirectory = ((BaseUnityPlugin)this).Config.Bind<string>("Main", "CloudStorageSubDirectory", "", "Sub directory name for cloud storage. Changing it allows to use different save files for different mod profiles."); UserSavesDirectory = ((BaseUnityPlugin)this).Config.Bind<string>("Main", "SavesDirectory", "", "Directory where save files will be stored. \"ProperSave\" directory will be created in the directory you have specified. If the directory doesn't exist the default one will be used."); Resilient = ((BaseUnityPlugin)this).Config.Bind<bool>("Main", "Resilient", true, "Save file type. True - entries from catalogs will be saved by name instead of index, which should have less issue on mod list change, but has bigger save file size. False - the old way, entries from catalogs are saved by index, which works for non-changing mod list, save file size is much lower."); RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, (Action)delegate { InitSaveFileSystem(); ProperSave.Old.SaveFileMetadata.MigrateAll(); SaveFileMetadata.PopulateSavesMetadata(); }); ModCompat.GatherLoadedPlugins(); ModCompat.RegisterHooks(); Saving.RegisterHooks(); Loading.RegisterHooks(); LobbyUI.RegisterHooks(); LostNetworkUser.Subscribe(); Language.collectLanguageRootFolders += CollectLanguageRootFolders; ContentManager.onContentPacksAssigned += ContentManagerOnContentPacksAssigned; } private void InitSaveFileSystem() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown if (UseCloudStorage.Value) { SavesFileSystem = RoR2Application.cloudStorage; if (!string.IsNullOrWhiteSpace(CloudStorageSubDirectory.Value)) { if (CloudStorageSubDirectory.Value.IndexOfAny(invalidSubDirectoryCharacters) != -1) { ((BaseUnityPlugin)this).Logger.LogError((object)"Config entry \"CloudStorageSubDirectory\" contains invalid characters. Falling back to default location."); } else { SavesPath /= UPath.op_Implicit(CloudStorageSubDirectory.Value); } } return; } if (!string.IsNullOrWhiteSpace(UserSavesDirectory.Value)) { if (!Directory.Exists(UserSavesDirectory.Value)) { ((BaseUnityPlugin)this).Logger.LogError((object)"SavesDirectory from the config doesn't exists, using Application.persistentDataPath"); SavesDirectory = Application.persistentDataPath; } else { SavesDirectory = UserSavesDirectory.Value; } } else { SavesDirectory = Application.persistentDataPath; } if (string.IsNullOrWhiteSpace(SavesDirectory)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Application.persistentDataPath is empty. Use SavesDirectory config option to specify a folder."); } PhysicalFileSystem val = new PhysicalFileSystem(); SavesFileSystem = (FileSystem)new SubFileSystem((IFileSystem)(object)val, ((FileSystem)val).ConvertPathFromInternal(SavesDirectory), true); } private void Destroy() { Instance = null; ModCompat.UnregisterHooks(); Saving.UnregisterHooks(); Loading.UnregisterHooks(); LobbyUI.UnregisterHooks(); LostNetworkUser.Unsubscribe(); Language.collectLanguageRootFolders -= CollectLanguageRootFolders; ContentManager.onContentPacksAssigned -= ContentManagerOnContentPacksAssigned; } public void CollectLanguageRootFolders(List<string> folders) { folders.Add(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Language")); } private void ContentManagerOnContentPacksAssigned(ReadOnlyArray<ReadOnlyContentPack> contentPacks) { //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) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) MD5 mD = MD5.Create(); StringWriter writer = new StringWriter(); try { Enumerator<ReadOnlyContentPack> enumerator = contentPacks.GetEnumerator(); try { while (enumerator.MoveNext()) { ReadOnlyContentPack current = enumerator.Current; writer.Write(((ReadOnlyContentPack)(ref current)).identifier); writer.Write(';'); WriteCollection<ArtifactDef>(((ReadOnlyContentPack)(ref current)).artifactDefs, "artifactDefs"); WriteCollection<GameObject>(((ReadOnlyContentPack)(ref current)).bodyPrefabs, "bodyPrefabs"); WriteCollection<EquipmentDef>(((ReadOnlyContentPack)(ref current)).equipmentDefs, "equipmentDefs"); WriteCollection<DroneDef>(((ReadOnlyContentPack)(ref current)).droneDefs, "droneDefs"); WriteCollection<ExpansionDef>(((ReadOnlyContentPack)(ref current)).expansionDefs, "expansionDefs"); WriteCollection<GameObject>(((ReadOnlyContentPack)(ref current)).gameModePrefabs, "gameModePrefabs"); WriteCollection<ItemDef>(((ReadOnlyContentPack)(ref current)).itemDefs, "itemDefs"); WriteCollection<ItemTierDef>(((ReadOnlyContentPack)(ref current)).itemTierDefs, "itemTierDefs"); WriteCollection<GameObject>(((ReadOnlyContentPack)(ref current)).masterPrefabs, "masterPrefabs"); WriteCollection<SceneDef>(((ReadOnlyContentPack)(ref current)).sceneDefs, "sceneDefs"); WriteCollection<SkillDef>(((ReadOnlyContentPack)(ref current)).skillDefs, "skillDefs"); WriteCollection<SkillFamily>(((ReadOnlyContentPack)(ref current)).skillFamilies, "skillFamilies"); WriteCollection<SurvivorDef>(((ReadOnlyContentPack)(ref current)).survivorDefs, "survivorDefs"); WriteCollection<UnlockableDef>(((ReadOnlyContentPack)(ref current)).unlockableDefs, "unlockableDefs"); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } ContentHash = Convert.ToBase64String(mD.ComputeHash(Encoding.UTF8.GetBytes(writer.ToString()))); } finally { if (writer != null) { ((IDisposable)writer).Dispose(); } } void WriteCollection<T>(ReadOnlyNamedAssetCollection<T> collection, string collectionName) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) writer.Write(collectionName); int num = 0; AssetEnumerator<T> enumerator2 = collection.GetEnumerator(); try { while (enumerator2.MoveNext()) { T current2 = enumerator2.Current; writer.Write(num); writer.Write('_'); writer.Write(collection.GetAssetName(current2) ?? string.Empty); writer.Write(';'); num++; } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } } } public class SaveFile { internal static readonly int currentVersion = 1; public ProperSave.SaveData.RunData RunData { get; set; } public ProperSave.SaveData.TeamData TeamData { get; set; } public ProperSave.SaveData.RunArtifactsData RunArtifactsData { get; set; } public ProperSave.SaveData.ArtifactsData ArtifactsData { get; set; } public List<ProperSave.SaveData.PlayerData> PlayersData { get; set; } = new List<ProperSave.SaveData.PlayerData>(); public Dictionary<string, ProperSave.Data.ModdedData> ModdedData { get; set; } = new Dictionary<string, ProperSave.Data.ModdedData>(); public static event Action<Dictionary<string, object>> OnGatherSaveData; internal SaveFile() { } internal void FillFromCurrentRun() { RunData = ProperSave.SaveData.RunData.Create(); TeamData = ProperSave.SaveData.TeamData.Create(); RunArtifactsData = ProperSave.SaveData.RunArtifactsData.Create(); ArtifactsData = ProperSave.SaveData.ArtifactsData.Create(); foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { LostNetworkUser lostUser = null; if (Object.op_Implicit((Object)(object)instance.networkUser) || LostNetworkUser.TryGetUser(instance.master, out lostUser)) { PlayersData.Add(ProperSave.SaveData.PlayerData.Create(instance, lostUser)); } } Dictionary<string, object> dictionary = new Dictionary<string, object>(); Delegate[] array = SaveFile.OnGatherSaveData?.GetInvocationList(); if (array != null) { Delegate[] array2 = array; foreach (Delegate obj in array2) { try { ((Action<Dictionary<string, object>>)obj)(dictionary); } catch (Exception ex) { ProperSavePlugin.InstanceLogger.LogError((object)ex); } } } ModdedData = dictionary.ToDictionary((KeyValuePair<string, object> el) => el.Key, (KeyValuePair<string, object> el) => new ProperSave.Data.ModdedData { ObjectType = el.Value.GetType().AssemblyQualifiedName, Value = el.Value }); } internal void LoadRun() { try { LegacyResourcesAPI.Load<GameObject>("Prefabs/PositionIndicators/TeleporterChargingPositionIndicator", true); } catch { } RunData.LoadData(); } internal void LoadArtifacts() { RunArtifactsData.LoadData(); ArtifactsData.LoadData(); } internal void LoadTeam() { TeamData.LoadData(); } internal void LoadPlayers() { if (NetworkUser.readOnlyInstancesList.Count == 1) { ProperSave.SaveData.PlayerData playerData = PlayersData.FirstOrDefault(); if (playerData != null) { NetworkUser player = NetworkUser.readOnlyInstancesList.FirstOrDefault(); playerData.LoadPlayer(player); } return; } List<ProperSave.SaveData.PlayerData> list = PlayersData.ToList(); foreach (NetworkUser user in NetworkUser.readOnlyInstancesList) { ProperSave.SaveData.PlayerData playerData2 = list.FirstOrDefault(delegate(ProperSave.SaveData.PlayerData el) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) NetworkUserId val = el.userId.Load(); return ((NetworkUserId)(ref val)).Equals(user.id); }); if (playerData2 != null) { list.Remove(playerData2); playerData2.LoadPlayer(user); } } } public T GetModdedData<T>(string key) { return (T)ModdedData[key].Value; } internal static SaveFile Read(BinaryReader reader) { SaveFile saveFile = new SaveFile(); int version = reader.ReadInt32(); bool resilient = reader.ReadBoolean(); long offset = reader.ReadInt64(); long position = reader.BaseStream.Position; reader.BaseStream.Seek(offset, SeekOrigin.Begin); string[] array = new string[reader.ReadInt32()]; for (int i = 0; i < array.Length; i++) { array[i] = reader.ReadString(); } long position2 = reader.BaseStream.Position; reader.BaseStream.Seek(position, SeekOrigin.Begin); ReaderContext context = new ReaderContext { Reader = reader, Resilient = resilient, SharedStrings = array, Version = version }; saveFile.ArtifactsData = ProperSave.SaveData.ArtifactsData.Read(context); saveFile.RunData = ProperSave.SaveData.RunData.Read(context); saveFile.RunArtifactsData = ProperSave.SaveData.RunArtifactsData.Read(context); saveFile.TeamData = ProperSave.SaveData.TeamData.Read(context); int num = reader.ReadInt32(); for (int j = 0; j < num; j++) { saveFile.PlayersData.Add(ProperSave.SaveData.PlayerData.Read(context)); } saveFile.ModdedData = ReadModdedData(context); reader.BaseStream.Seek(position2, SeekOrigin.Begin); return saveFile; } private static Dictionary<string, ProperSave.Data.ModdedData> ReadModdedData(ReaderContext context) { return context.Reader.ReadString().FromJson<Dictionary<string, ProperSave.Data.ModdedData>>(); } internal void Write(BinaryWriter writer, bool resilient) { WriterContext writerContext = new WriterContext { Writer = writer, SharedStrings = new List<string>(), Resilient = resilient }; writer.Write(currentVersion); writer.Write(resilient); long position = writer.BaseStream.Position; writer.Write(0L); ArtifactsData.Write(writerContext); RunData.Write(writerContext); RunArtifactsData.Write(writerContext); TeamData.Write(writerContext); writer.Write(PlayersData.Count); for (int i = 0; i < PlayersData.Count; i++) { PlayersData[i].Write(writerContext); } WriteModdedData(writerContext); long position2 = writer.BaseStream.Position; writer.Write(writerContext.SharedStrings.Count); for (int j = 0; j < writerContext.SharedStrings.Count; j++) { writer.Write(writerContext.SharedStrings[j]); } writer.BaseStream.Seek(position, SeekOrigin.Begin); writer.Write(position2); writer.BaseStream.Seek(writer.BaseStream.Length, SeekOrigin.Begin); } private void WriteModdedData(WriterContext context) { context.Writer.Write(ModdedData.ToJson()); } } public class SaveFileHeader { internal static readonly int currentVersion = 1; public DateTime SaveDate { get; internal set; } public string UserProfileId { get; internal set; } public HeaderUserData[] Users { get; internal set; } public GameModeIndex GameMode { get; internal set; } public string SceneName { get; internal set; } public DifficultyIndex Difficulty { get; internal set; } public int Time { get; internal set; } public int StageClearCount { get; internal set; } public string ContentHash { get; internal set; } public void FillFromCurrentRun() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) Users = (from el in PlayerCharacterMasterController.instances.Select(HeaderUserData.Create) where el != null select el).ToArray(); UserProfileId = LocalUserManager.readOnlyLocalUsersList[0].userProfile.fileName; GameMode = Run.instance.gameModeIndex; ContentHash = ProperSavePlugin.ContentHash; Difficulty = Run.instance.selectedDifficulty; Scene activeScene = SceneManager.GetActiveScene(); SceneName = ((Scene)(ref activeScene)).name; StageClearCount = Run.instance.stageClearCount; RunStopwatch runStopwatch = Run.instance.runStopwatch; Time = (runStopwatch.isPaused ? ((int)runStopwatch.offsetFromFixedTime) : ((int)(Run.instance.fixedTime + runStopwatch.offsetFromFixedTime))); } internal static SaveFileHeader Read(BinaryReader reader) { //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) SaveFileHeader saveFileHeader = new SaveFileHeader(); int version = reader.ReadInt32(); bool resilient = reader.ReadBoolean(); long offset = reader.ReadInt64(); long position = reader.BaseStream.Position; reader.BaseStream.Seek(offset, SeekOrigin.Begin); string[] array = new string[reader.ReadInt32()]; for (int i = 0; i < array.Length; i++) { array[i] = reader.ReadString(); } long position2 = reader.BaseStream.Position; reader.BaseStream.Seek(position, SeekOrigin.Begin); ReaderContext context = new ReaderContext { Reader = reader, Resilient = resilient, SharedStrings = array, Version = version }; saveFileHeader.SaveDate = new DateTime(reader.ReadInt64(), DateTimeKind.Utc); saveFileHeader.UserProfileId = reader.ReadString(); saveFileHeader.Users = new HeaderUserData[reader.ReadInt32()]; for (int j = 0; j < saveFileHeader.Users.Length; j++) { saveFileHeader.Users[j] = HeaderUserData.Read(context); } saveFileHeader.GameMode = SharedIndexHelpers.ResolveGameMode(reader.ReadInt32(), context); saveFileHeader.SceneName = reader.ReadString(); saveFileHeader.Difficulty = SharedIndexHelpers.ResolveDifficulty(reader.ReadInt32(), context); saveFileHeader.Time = reader.ReadInt32(); saveFileHeader.StageClearCount = reader.ReadInt32(); saveFileHeader.ContentHash = reader.ReadString(); reader.BaseStream.Seek(position2, SeekOrigin.Begin); return saveFileHeader; } internal void Write(BinaryWriter writer, bool resilient) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) WriterContext writerContext = new WriterContext { Writer = writer, SharedStrings = new List<string>(), Resilient = resilient }; writer.Write(currentVersion); writer.Write(resilient); long position = writer.BaseStream.Position; writer.Write(0L); writer.Write(DateTime.UtcNow.Ticks); writer.Write(UserProfileId); writer.Write(Users.Length); for (int i = 0; i < Users.Length; i++) { Users[i].Write(writerContext); } writer.Write(SharedIndexHelpers.FromGameMode(GameMode, writerContext)); writer.Write(SceneName); writer.Write(SharedIndexHelpers.FromDifficulty(Difficulty, writerContext)); writer.Write(Time); writer.Write(StageClearCount); writer.Write(ContentHash); long position2 = writer.BaseStream.Position; writer.Write(writerContext.SharedStrings.Count); for (int j = 0; j < writerContext.SharedStrings.Count; j++) { writer.Write(writerContext.SharedStrings[j]); } writer.BaseStream.Seek(position, SeekOrigin.Begin); writer.Write(position2); writer.BaseStream.Seek(writer.BaseStream.Length, SeekOrigin.Begin); } } public class SaveFileMetadata { public string FileName { get; internal set; } public bool ForceLoad { get; internal set; } public SaveFileHeader Header { get; internal set; } public long BodyOffset { get; internal set; } public SaveFile Body { get; internal set; } public UPath? FilePath => string.IsNullOrEmpty(FileName) ? UPath.op_Implicit((string)null) : (ProperSavePlugin.SavesPath / UPath.op_Implicit(FileName + ".bin")); internal static List<SaveFileMetadata> SavesMetadata { get; } = new List<SaveFileMetadata>(); internal void FillMetadataForCurrentLobby() { //IL_006a: Unknown res