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 ContinueGame v1.0.2
BepInEx/plugins/ContinueGame/ContinueGame.dll
Decompiled a week agousing System; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("ContinueGame")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2+7a0536a753a423517acb829c94b61c6565ec97b7")] [assembly: AssemblyProduct("ContinueGame")] [assembly: AssemblyTitle("ContinueGame")] [assembly: AssemblyVersion("1.0.2.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ContinueGame { [BepInPlugin("Slikfoul.ContinueGame", "ContinueGame", "1.0.2")] public sealed class ContinueGamePlugin : BaseUnityPlugin { [HarmonyPatch(typeof(FejdStartup), "Start")] private static class MenuPatch { private static void Postfix(FejdStartup __instance) { Instance?.CreateButton(__instance); } } [HarmonyPatch(typeof(FejdStartup), "JoinServer")] private static class JoinPatch { private static void Prefix(FejdStartup __instance) { Instance?.CaptureJoin(__instance); } } [HarmonyPatch(typeof(FejdStartup), "OnStartGame")] private static class OrdinaryJoinPatch { private static void Prefix() { Instance?.CancelPending(); } } [HarmonyPatch(typeof(ZNet), "SendPeerInfo")] private static class PasswordPatch { private static void Prefix(ZNet __instance, string password) { Instance?.CapturePassword(__instance, password); } private static void Postfix(ZNet __instance) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if (!__instance.IsServer() && (int)ZNet.GetConnectionStatus() == 1) { Instance?._loadingScreen?.Advance(LoadingStage.Authenticating); } } } [HarmonyPatch(typeof(FejdStartup), "TransitionToMainScene")] private static class LoadingStartPatch { private static void Prefix(FejdStartup __instance) { Instance?.BeginLoading(__instance); } } [HarmonyPatch(typeof(FejdStartup), "LoadMainScene")] private static class WorldLoadingPatch { private static void Prefix() { Instance?._loadingScreen?.Advance(LoadingStage.LoadingScene); } } [HarmonyPatch(typeof(ZNet), "ClientConnect")] private static class ConnectingPatch { private static void Prefix() { Instance?._loadingScreen?.Advance(LoadingStage.Connecting); } } [HarmonyPatch(typeof(ZNet), "RPC_ClientHandshake")] private static class HandshakePatch { private static void Prefix(ZNet __instance, bool needPassword) { if (!__instance.IsServer()) { Instance?._loadingScreen?.Advance(needPassword ? LoadingStage.SendingPassword : LoadingStage.Authenticating); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private static class WorldInfoPatch { private static void Prefix(ZNet __instance) { if (!__instance.IsServer()) { Instance?._loadingScreen?.Advance(LoadingStage.ReceivingWorld); } } } [HarmonyPatch(typeof(Hud), "UpdateBlackScreen")] private static class NativeLoadingPatch { private static void Postfix(Hud __instance) { Instance?.UpdateNativeLoading(__instance); } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static PopupButtonCallback <>9__33_0; internal void <Warning>b__33_0() { UnifiedPopup.Pop(); } } public const string PluginId = "Slikfoul.ContinueGame"; internal static ContinueGamePlugin Instance; private static readonly FieldInfo PasswordField = AccessTools.Field(typeof(FejdStartup), "<ServerPassword>k__BackingField"); private Harmony _harmony; private PrivateSessionStorage _storage; private SessionRecord _saved; private SessionRecord _pending; private string _pendingPassword; private bool _passwordInjected; private string _previousPassword; private Button _button; private FejdStartup _menu; private bool _busy; private bool _loadingScheduled; private string _label; private TMP_Text[] _tmpLabels; private Text[] _textLabels; private CrossPlatformPasswordProtection _passwordProtection; private ContinueLoadingScreen _loadingScreen; private bool Russian { get { if (Localization.instance != null) { return Localization.instance.GetSelectedLanguage() == "Russian"; } return false; } } private string Text(string ru, string en) { if (!Russian) { return en; } return ru; } private void Awake() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown Instance = this; if (PasswordField == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Required Valheim password integration is unavailable."); return; } _harmony = new Harmony("Slikfoul.ContinueGame"); _harmony.PatchAll(typeof(ContinueGamePlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ContinueGame loaded."); } private void InitializeStorage() { _saved = null; _storage = null; _passwordProtection = null; try { string saveDataPath = Utils.GetSaveDataPath((FileSource)2); if (string.IsNullOrWhiteSpace(saveDataPath)) { throw new IOException("Local save directory is unavailable."); } _storage = new PrivateSessionStorage(Paths.ConfigPath, Path.GetFullPath(saveDataPath)); _passwordProtection = _storage.PasswordProtection; _saved = _storage.Load(); } catch (Exception) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Saved session could not be read. Join normally to save a new session."); } } private void OnDestroy() { CancelPending(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } internal void CancelPending() { _loadingScreen?.Dispose(); _loadingScreen = null; RestorePassword(); _pending = null; _pendingPassword = null; _busy = false; _loadingScheduled = false; } private void RestorePassword() { if (_passwordInjected) { PasswordField.SetValue(null, _previousPassword); _previousPassword = null; _passwordInjected = false; } } private void Update() { //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Invalid comparison between Unknown and I4 //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Invalid comparison between Unknown and I4 //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Invalid comparison between Unknown and I4 if (_loadingScreen != null) { try { _loadingScreen.Tick(); if (_loadingScreen.IsFinished) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Native loading artwork is ready; Continue preloading panel hidden."); _loadingScreen = null; } } catch (Exception) { _loadingScreen.Dispose(); _loadingScreen = null; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Loading visuals could not be updated; connection will continue normally."); } } if ((Object)(object)_button != (Object)null) { string text = Text("Продолжить", "Continue"); if (text != _label) { TMP_Text[] tmpLabels = _tmpLabels; for (int i = 0; i < tmpLabels.Length; i++) { tmpLabels[i].text = text; } Text[] textLabels = _textLabels; for (int i = 0; i < textLabels.Length; i++) { textLabels[i].text = text; } _label = text; } ((Selectable)_button).interactable = _saved != null && !_busy; } if (_pending != null && (Object)(object)_menu != (Object)null) { if (((MonoBehaviour)_menu).IsInvoking("LoadMainSceneIfBackendSelected")) { _loadingScheduled = true; } else if (_loadingScheduled && !_menu.m_loading.activeSelf) { CancelPending(); } } if (_pending == null || (Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return; } ConnectionStatus connectionStatus = ZNet.GetConnectionStatus(); if ((int)connectionStatus > 2) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Connection did not succeed; keeping the last successful session."); CancelPending(); return; } if ((int)connectionStatus == 2) { _loadingScreen?.Advance(LoadingStage.LoadingArea); } if ((int)connectionStatus != 2 || (Object)(object)Game.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } try { PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); if (playerProfile != null) { _pending.CharacterFilename = playerProfile.GetFilename(); _pending.CharacterId = playerProfile.GetPlayerID(); _storage.Save(_pending, _pendingPassword ?? ""); _saved = _pending; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Last successful server and character saved; password protected."); } } catch (Exception) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"The successful session could not be saved. The previous session was kept."); } finally { CancelPending(); } } internal void CaptureJoin(FejdStartup startup) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) try { ServerJoinData serverToJoin = startup.GetServerToJoin(); if (((ServerJoinData)(ref serverToJoin)).IsValid) { _pending = RecordServer(serverToJoin); if (!_passwordInjected) { _pendingPassword = null; } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Tracking a server connection attempt."); } } catch (Exception) { CancelPending(); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not track the connection; ordinary joining remains available."); } } internal void CapturePassword(ZNet network, string password) { if (_pending != null && !network.IsServer()) { _pendingPassword = password ?? ""; RestorePassword(); } } private unsafe static SessionRecord RecordServer(ServerJoinData server) { //IL_002f: 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_0035: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected I4, but got Unknown //IL_0091: 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_00c2: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) SessionRecord sessionRecord = new SessionRecord { ServerOwner = (((PlatformUserID)(ref server.m_owner)).IsValid ? ((object)(*(PlatformUserID*)(&server.m_owner))/*cast due to .constrained prefix*/).ToString() : null) }; ServerJoinDataType type = server.m_type; switch (type - 1) { case 2: { sessionRecord.ServerKind = "Dedicated"; ServerJoinDataDedicated dedicated = ((ServerJoinData)(ref server)).Dedicated; sessionRecord.Address = ((ServerJoinDataDedicated)(ref dedicated)).m_host; sessionRecord.Port = ((ServerJoinData)(ref server)).Dedicated.m_port; break; } case 0: { sessionRecord.ServerKind = "Steam"; ulong steamID = ((ServerJoinData)(ref server)).SteamUser.m_joinUserID.m_SteamID; sessionRecord.Address = steamID.ToString(CultureInfo.InvariantCulture); break; } case 1: sessionRecord.ServerKind = "PlayFab"; sessionRecord.Address = ((ServerJoinData)(ref server)).PlayFabUser.m_remotePlayerId; break; default: throw new InvalidOperationException("Unsupported server type."); } return sessionRecord; } private static ServerJoinData RestoreServer(SessionRecord record) { //IL_003f: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) ServerJoinData result = default(ServerJoinData); switch (record.ServerKind) { case "Dedicated": ((ServerJoinData)(ref result))..ctor(new ServerJoinDataDedicated(record.Address, (ushort)record.Port)); break; case "Steam": ((ServerJoinData)(ref result))..ctor(new ServerJoinDataSteamUser(ulong.Parse(record.Address, CultureInfo.InvariantCulture))); break; case "PlayFab": ((ServerJoinData)(ref result))..ctor(new ServerJoinDataPlayFabUser(record.Address)); break; default: throw new InvalidDataException("Unsupported server type."); } PlatformUserID owner = default(PlatformUserID); if (PlatformUserID.TryParse(record.ServerOwner, ref owner)) { result.m_owner = owner; } return result; } private void Continue() { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) if (_saved == null || (Object)(object)_menu == (Object)null || _busy) { return; } try { _busy = true; BeginLoading(_menu); PlayerProfile val = null; foreach (PlayerProfile allPlayerProfile in SaveSystem.GetAllPlayerProfiles()) { if (allPlayerProfile.GetFilename() == _saved.CharacterFilename && allPlayerProfile.GetPlayerID() == _saved.CharacterId) { val = allPlayerProfile; break; } } if (val == null) { CancelPending(); Warning(Text("Сохранённый персонаж не найден. Войдите обычным способом, чтобы сохранить новый вход.", "The saved character was not found. Join normally to save a new session.")); return; } AccessTools.Method(typeof(FejdStartup), "SelectCharacter", (Type[])null, (Type[])null).Invoke(_menu, new object[2] { val.GetFilename(), val.m_fileSource }); _loadingScreen?.Advance(LoadingStage.RestoringPassword); string text; try { text = _passwordProtection.Unprotect(_saved.ProtectedPassword); } catch (Exception) { CancelPending(); Warning(Text("Не удалось прочитать сохранённый пароль. Войдите обычным способом и введите пароль снова.", "The saved password could not be read. Join normally and enter your password again.")); return; } _previousPassword = (string)PasswordField.GetValue(null); _passwordInjected = true; PasswordField.SetValue(null, (text.Length == 0) ? null : text); _pendingPassword = text; _loadingScreen?.Advance(LoadingStage.FindingServer); _menu.SetServerToJoin(RestoreServer(_saved)); _menu.JoinServer(); if (!((MonoBehaviour)_menu).IsInvoking("LoadMainSceneIfBackendSelected") && !ZNet.HasServerHost() && (_saved.ServerKind != "PlayFab" || PlayFabManager.IsLoggedIn)) { CancelPending(); } } catch (Exception) { CancelPending(); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Continue could not start. Ordinary joining remains available."); Warning(Text("Не удалось начать подключение. Войдите на сервер обычным способом.", "The connection could not be started. Join the server normally.")); } } private void Warning(string message) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //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_0030: Expected O, but got Unknown string text = Text("Продолжить", "Continue"); object obj = <>c.<>9__33_0; if (obj == null) { PopupButtonCallback val = delegate { UnifiedPopup.Pop(); }; <>c.<>9__33_0 = val; obj = (object)val; } UnifiedPopup.Push((PopupBase)new WarningPopup(text, message, (PopupButtonCallback)obj, false)); } internal void BeginLoading(FejdStartup startup) { if (!_busy || _loadingScreen != null) { return; } try { _loadingScreen = new ContinueLoadingScreen(startup); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Continue loading screen shown."); } catch (Exception) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Loading visuals could not be created; connection will continue normally."); } } internal void UpdateNativeLoading(Hud hud) { if (_loadingScreen == null) { return; } try { _loadingScreen.HandOffToNative(hud); } catch (Exception) { _loadingScreen.Dispose(); _loadingScreen = null; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Preloading UI could not be hidden; connection will continue normally."); } } internal void CreateButton(FejdStartup startup) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown //IL_0179: 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_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) CancelPending(); InitializeStorage(); _menu = startup; try { if ((Object)(object)startup.m_menuList.transform.Find("ContinueGameButton") != (Object)null) { return; } Button[] componentsInChildren = startup.m_menuList.GetComponentsInChildren<Button>(true); Button val = null; Button[] array = componentsInChildren; foreach (Button val2 in array) { if (((Object)val2).name == "StartGame" || ((Object)val2).name == "Start") { val = val2; break; } } if ((Object)(object)val == (Object)null && componentsInChildren.Length != 0) { val = componentsInChildren[0]; } if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("Main menu button not found."); } _button = Object.Instantiate<Button>(val, ((Component)val).transform.parent); ((Object)_button).name = "ContinueGameButton"; _button.onClick = new ButtonClickedEvent(); ((UnityEvent)_button.onClick).AddListener(new UnityAction(Continue)); _tmpLabels = ((Component)_button).GetComponentsInChildren<TMP_Text>(true); _textLabels = ((Component)_button).GetComponentsInChildren<Text>(true); _label = null; ((Component)_button).transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex()); RectTransform component = ((Component)val).GetComponent<RectTransform>(); RectTransform component2 = ((Component)_button).GetComponent<RectTransform>(); if ((Object)(object)((Component)((Component)val).transform.parent).GetComponent<LayoutGroup>() == (Object)null) { Rect rect = component.rect; float num = ((Rect)(ref rect)).height + 8f; float num2 = float.MaxValue; array = componentsInChildren; foreach (Button val3 in array) { if (!((Object)(object)((Component)val3).transform.parent != (Object)(object)((Component)val).transform.parent)) { float num3 = Mathf.Abs(((Component)val3).GetComponent<RectTransform>().anchoredPosition.y - component.anchoredPosition.y); if (num3 > 1f) { num2 = Mathf.Min(num2, num3); } } } if (num2 != float.MaxValue) { num = num2; } component2.anchoredPosition = component.anchoredPosition + new Vector2(0f, num); } ((Component)_button).gameObject.SetActive(true); ((Selectable)_button).interactable = _saved != null; AccessTools.Field(typeof(FejdStartup), "m_menuButtons").SetValue(startup, (_saved != null) ? startup.m_menuList.GetComponentsInChildren<Button>() : componentsInChildren); Navigation navigation = ((Selectable)_button).navigation; ((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)val; ((Selectable)_button).navigation = navigation; if (_saved != null) { navigation = ((Selectable)val).navigation; ((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_button; ((Selectable)val).navigation = navigation; } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Continue button added to the main menu."); } catch (Exception) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Continue button could not be added; ordinary joining remains available."); } } } internal sealed class ContinueLoadingScreen : IDisposable { private static readonly Color Gold = new Color(0.92f, 0.76f, 0.44f, 1f); private static readonly string[] RussianStages = new string[9] { "Выбор персонажа", "Восстановление пароля", "Поиск сервера", "Загрузка игровой сцены", "Подключение к серверу", "Передача пароля", "Проверка входа", "Получение данных мира", "Загрузка области мира" }; private static readonly string[] EnglishStages = new string[9] { "Selecting character", "Restoring password", "Finding server", "Loading game scene", "Connecting to server", "Sending password", "Authenticating", "Receiving world data", "Loading world area" }; private readonly LoadingState _state = new LoadingState(); private readonly GameObject _root; private readonly CanvasGroup _visibility; private readonly TMP_Text _stageText; private readonly RectTransform _shine; private readonly Texture2D _shineTexture; private readonly Sprite _shineSprite; private readonly float _startedAt; public bool IsFinished { get; private set; } private static bool Russian { get { if (Localization.instance != null) { return Localization.instance.GetSelectedLanguage() == "Russian"; } return false; } } public ContinueLoadingScreen(FejdStartup startup) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Expected O, but got Unknown //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) _root = new GameObject("ContinueGamePreloading", new Type[4] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(CanvasGroup) }); try { Object.DontDestroyOnLoad((Object)(object)_root); Canvas component = _root.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 32000; CanvasScaler component2 = _root.GetComponent<CanvasScaler>(); component2.uiScaleMode = (ScaleMode)1; component2.referenceResolution = new Vector2(1920f, 1080f); component2.matchWidthOrHeight = 0.5f; _visibility = _root.GetComponent<CanvasGroup>(); _visibility.interactable = false; _visibility.blocksRaycasts = false; _startedAt = Time.unscaledTime; Image obj = Add<Image>("Backdrop", (Transform)null); Stretch(((Graphic)obj).rectTransform); ((Graphic)obj).color = new Color(0.025f, 0.022f, 0.016f, 1f); ((Graphic)obj).raycastTarget = false; TMP_Text componentInChildren = startup.m_menuList.GetComponentInChildren<TMP_Text>(true); TMP_Text obj2 = Label("Title", componentInChildren, 40f); obj2.text = "Loading"; Place(obj2.rectTransform, new Vector2(0.5f, 0.55f), new Vector2(1000f, 80f)); _stageText = Label("CurrentStage", componentInChildren, 30f); Place(_stageText.rectTransform, new Vector2(0.5f, 0.45f), new Vector2(1100f, 80f)); Image obj3 = Add<Image>("BarBorder", (Transform)null); Place(((Graphic)obj3).rectTransform, new Vector2(0.5f, 0.39f), new Vector2(564f, 12f)); ((Graphic)obj3).color = new Color(Gold.r, Gold.g, Gold.b, 0.32f); ((Graphic)obj3).raycastTarget = false; Image val = Add<Image>("BarTrack", (Transform)null); Place(((Graphic)val).rectTransform, new Vector2(0.5f, 0.39f), new Vector2(560f, 8f)); ((Graphic)val).color = new Color(0.1f, 0.08f, 0.04f, 1f); ((Graphic)val).raycastTarget = false; ((Component)val).gameObject.AddComponent<RectMask2D>(); _shineTexture = new Texture2D(96, 1, (TextureFormat)4, false); ((Texture)_shineTexture).wrapMode = (TextureWrapMode)1; for (int i = 0; i < 96; i++) { float num = Mathf.Sin((float)Math.PI * (float)i / 95f); _shineTexture.SetPixel(i, 0, new Color(Gold.r, Gold.g, Gold.b, num * num)); } _shineTexture.Apply(false, true); _shineSprite = Sprite.Create(_shineTexture, new Rect(0f, 0f, 96f, 1f), new Vector2(0.5f, 0.5f)); Image val2 = Add<Image>("BarGlow", ((Component)val).transform); val2.sprite = _shineSprite; ((Graphic)val2).raycastTarget = false; _shine = ((Graphic)val2).rectTransform; Place(_shine, new Vector2(0f, 0.5f), new Vector2(190f, 8f)); Tick(); } catch { Dispose(); throw; } } public void Advance(LoadingStage stage) { _state.Advance(stage); } public void HandOffToNative(Hud hud) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (!IsFinished && !((Object)(object)hud == (Object)null) && !((Object)(object)hud.m_loadingScreen == (Object)null)) { Image loadingImage = hud.m_loadingImage; bool artworkVisible = (Object)(object)loadingImage != (Object)null && ((Behaviour)loadingImage).isActiveAndEnabled && (Object)(object)loadingImage.sprite != (Object)null && ((Graphic)loadingImage).color.a > 0f && (Object)(object)((Graphic)loadingImage).canvas != (Object)null && ((Behaviour)((Graphic)loadingImage).canvas).isActiveAndEnabled && ((Graphic)loadingImage).canvasRenderer.GetInheritedAlpha() > 0f; bool worldLoadingActive = (Object)(object)hud.m_loadingProgress != (Object)null && hud.m_loadingProgress.activeInHierarchy; _state.ObserveNativeLoading(((Component)hud.m_loadingScreen).gameObject.activeInHierarchy, hud.m_loadingScreen.alpha, worldLoadingActive, artworkVisible); if (_state.Completed) { Dispose(); } } } public void Tick() { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) if (IsFinished) { return; } HandOffToNative(Hud.instance); if (!IsFinished) { string text = (Russian ? RussianStages : EnglishStages)[(int)_state.Stage]; if (_stageText.text != text) { _stageText.text = text; } float num = Mathf.Repeat((Time.unscaledTime - _startedAt + 0.9f) / 2.6f, 1f); _shine.anchoredPosition = new Vector2(Mathf.Lerp(-95f, 655f, Mathf.SmoothStep(0f, 1f, num)), 0f); _visibility.alpha = ((UnifiedPopup.IsVisible() || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.InPasswordDialog())) ? 0f : 1f); } } private TMP_Text Label(string name, TMP_Text template, float size) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI val = Add<TextMeshProUGUI>(name, (Transform)null); if ((Object)(object)template != (Object)null) { ((TMP_Text)val).font = template.font; ((TMP_Text)val).fontSharedMaterial = template.fontSharedMaterial; } ((TMP_Text)val).fontSize = size; ((Graphic)val).color = Gold; ((TMP_Text)val).alignment = (TextAlignmentOptions)514; ((Graphic)val).raycastTarget = false; return (TMP_Text)(object)val; } private T Add<T>(string name, Transform parent = null) where T : Component { //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) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(((Object)(object)parent != (Object)null) ? parent : _root.transform, false); return val.AddComponent<T>(); } private static void Stretch(RectTransform rect) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; Vector2 offsetMin = (rect.offsetMax = Vector2.zero); rect.offsetMin = offsetMin; } private static void Place(RectTransform rect, Vector2 anchor, Vector2 size) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_002d: Unknown result type (might be due to invalid IL or missing references) Vector2 anchorMin = (rect.anchorMax = anchor); rect.anchorMin = anchorMin; rect.pivot = new Vector2(0.5f, 0.5f); rect.sizeDelta = size; rect.anchoredPosition = Vector2.zero; } public void Dispose() { if (!IsFinished) { IsFinished = true; if ((Object)(object)_root != (Object)null) { _root.SetActive(false); Object.Destroy((Object)(object)_root); } if ((Object)(object)_shineSprite != (Object)null) { Object.Destroy((Object)(object)_shineSprite); } if ((Object)(object)_shineTexture != (Object)null) { Object.Destroy((Object)(object)_shineTexture); } } } } public enum LoadingStage { SelectingCharacter, RestoringPassword, FindingServer, LoadingScene, Connecting, SendingPassword, Authenticating, ReceivingWorld, LoadingArea } public sealed class LoadingState { public LoadingStage Stage { get; private set; } public bool Completed { get; private set; } public void Advance(LoadingStage stage) { if (!Completed && stage > Stage) { Stage = stage; } } public void ObserveNativeLoading(bool active, float alpha, bool worldLoadingActive, bool artworkVisible) { if (active && alpha > 0f && worldLoadingActive && artworkVisible) { Completed = true; } } } public static class PasswordProtection { private struct DataBlob { public int Length; public IntPtr Data; } [DllImport("crypt32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CryptProtectData(ref DataBlob input, string description, IntPtr entropy, IntPtr reserved, IntPtr prompt, int flags, out DataBlob output); [DllImport("crypt32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CryptUnprotectData(ref DataBlob input, IntPtr description, IntPtr entropy, IntPtr reserved, IntPtr prompt, int flags, out DataBlob output); [DllImport("kernel32.dll")] private static extern IntPtr LocalFree(IntPtr memory); public static string Protect(string password) { if (string.IsNullOrEmpty(password)) { return ""; } return Convert.ToBase64String(Transform(Encoding.UTF8.GetBytes(password), protect: true)); } public static string Unprotect(string protectedPassword) { if (string.IsNullOrEmpty(protectedPassword)) { return ""; } byte[] array = Transform(Convert.FromBase64String(protectedPassword), protect: false); try { return Encoding.UTF8.GetString(array); } finally { Array.Clear(array, 0, array.Length); } } private static byte[] Transform(byte[] bytes, bool protect) { if (Environment.OSVersion.Platform != PlatformID.Win32NT) { throw new PlatformNotSupportedException("Password protection requires Windows."); } DataBlob input = new DataBlob { Length = bytes.Length, Data = Marshal.AllocHGlobal(bytes.Length) }; DataBlob output = default(DataBlob); try { Marshal.Copy(bytes, 0, input.Data, bytes.Length); if (!(protect ? CryptProtectData(ref input, "ContinueGame", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 1, out output) : CryptUnprotectData(ref input, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 1, out output))) { throw new Win32Exception(Marshal.GetLastWin32Error()); } byte[] array = new byte[output.Length]; Marshal.Copy(output.Data, array, 0, array.Length); return array; } finally { for (int i = 0; i < input.Length; i++) { Marshal.WriteByte(input.Data, i, 0); } Marshal.FreeHGlobal(input.Data); if (output.Data != IntPtr.Zero) { if (!protect) { for (int j = 0; j < output.Length; j++) { Marshal.WriteByte(output.Data, j, 0); } } LocalFree(output.Data); } Array.Clear(bytes, 0, bytes.Length); } } } public sealed class CrossPlatformPasswordProtection { private readonly PortablePasswordProtection _portable; public CrossPlatformPasswordProtection(string keyDirectory) { _portable = new PortablePasswordProtection(keyDirectory); } public string Protect(string password) { if (Environment.OSVersion.Platform != PlatformID.Win32NT) { return _portable.Protect(password); } return PasswordProtection.Protect(password); } public string Unprotect(string password) { if (password == null || !password.StartsWith("portable-v1:", StringComparison.Ordinal)) { return PasswordProtection.Unprotect(password); } return _portable.Unprotect(password); } } public sealed class PortablePasswordProtection { public const string Prefix = "portable-v1:"; private readonly string _directory; private readonly string _keyPath; public PortablePasswordProtection(string directory) { _directory = Path.GetFullPath(directory); _keyPath = Path.Combine(_directory, "password.key"); } private byte[] ReadKey(bool create) { if (!Directory.Exists(_directory)) { if (!create) { throw new FileNotFoundException("Password key is missing."); } Directory.CreateDirectory(_directory); } if (!File.Exists(_keyPath) && create) { byte[] array = new byte[64]; using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create()) { randomNumberGenerator.GetBytes(array); } bool flag = false; try { using FileStream fileStream = new FileStream(_keyPath, FileMode.CreateNew, FileAccess.Write, FileShare.None); flag = true; fileStream.Write(array, 0, array.Length); fileStream.Flush(flushToDisk: true); } catch { if (flag) { try { File.Delete(_keyPath); } catch (IOException) { } } throw; } finally { Array.Clear(array, 0, array.Length); } } if (!File.Exists(_keyPath)) { throw new FileNotFoundException("Password key is missing."); } if (new FileInfo(_keyPath).Length != 64) { throw new CryptographicException("Invalid password key."); } return File.ReadAllBytes(_keyPath); } public string Protect(string password) { if (string.IsNullOrEmpty(password)) { return ""; } byte[] array = ReadKey(create: true); byte[] bytes = Encoding.UTF8.GetBytes(password); byte[] array2 = new byte[32]; byte[] array3 = new byte[32]; Buffer.BlockCopy(array, 0, array2, 0, 32); Buffer.BlockCopy(array, 32, array3, 0, 32); try { using Aes aes = Aes.Create(); aes.Key = array2; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.GenerateIV(); byte[] array4; using (ICryptoTransform cryptoTransform = aes.CreateEncryptor()) { array4 = cryptoTransform.TransformFinalBlock(bytes, 0, bytes.Length); } byte[] array5 = new byte[17 + array4.Length + 32]; array5[0] = 1; Buffer.BlockCopy(aes.IV, 0, array5, 1, 16); Buffer.BlockCopy(array4, 0, array5, 17, array4.Length); using (HMACSHA256 hMACSHA = new HMACSHA256(array3)) { Buffer.BlockCopy(hMACSHA.ComputeHash(array5, 0, array5.Length - 32), 0, array5, array5.Length - 32, 32); } return "portable-v1:" + Convert.ToBase64String(array5); } finally { Array.Clear(bytes, 0, bytes.Length); Array.Clear(array, 0, array.Length); Array.Clear(array2, 0, array2.Length); Array.Clear(array3, 0, array3.Length); } } public string Unprotect(string password) { if (string.IsNullOrEmpty(password)) { return ""; } if (!password.StartsWith("portable-v1:", StringComparison.Ordinal)) { throw new CryptographicException("Unknown password format."); } byte[] array = Convert.FromBase64String(password.Substring("portable-v1:".Length)); if (array.Length < 65 || array[0] != 1 || (array.Length - 49) % 16 != 0) { throw new CryptographicException("Invalid encrypted password."); } byte[] array2 = ReadKey(create: false); byte[] array3 = new byte[32]; byte[] array4 = new byte[32]; Buffer.BlockCopy(array2, 0, array3, 0, 32); Buffer.BlockCopy(array2, 32, array4, 0, 32); try { using (HMACSHA256 hMACSHA = new HMACSHA256(array4)) { byte[] array5 = hMACSHA.ComputeHash(array, 0, array.Length - 32); int num = 0; for (int i = 0; i < 32; i++) { num |= array5[i] ^ array[array.Length - 32 + i]; } if (num != 0) { throw new CryptographicException("Password authentication failed."); } } using Aes aes = Aes.Create(); aes.Key = array3; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; byte[] array6 = new byte[16]; Buffer.BlockCopy(array, 1, array6, 0, 16); aes.IV = array6; byte[] array7; using (ICryptoTransform cryptoTransform = aes.CreateDecryptor()) { array7 = cryptoTransform.TransformFinalBlock(array, 17, array.Length - 49); } try { return Encoding.UTF8.GetString(array7); } finally { Array.Clear(array7, 0, array7.Length); } } finally { Array.Clear(array2, 0, array2.Length); Array.Clear(array3, 0, array3.Length); Array.Clear(array4, 0, array4.Length); } } } public sealed class PrivateSessionStorage { private readonly SessionStore _store; public readonly CrossPlatformPasswordProtection PasswordProtection; public readonly string DirectoryPath; public static string ResolveDirectory(string configDirectory, string dataRoot) { if (string.IsNullOrWhiteSpace(dataRoot) || !Path.IsPathRooted(dataRoot)) { throw new IOException("The local Valheim save directory is unavailable."); } string text = Path.GetFullPath(configDirectory).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); string s = ((Environment.OSVersion.Platform == PlatformID.Win32NT) ? text.ToUpperInvariant() : text); string path; using (SHA256 sHA = SHA256.Create()) { path = BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(s))).Replace("-", "").ToLowerInvariant(); } string fullPath = Path.GetFullPath(Path.Combine(dataRoot, "ContinueGame", path)); string text2 = Path.GetDirectoryName(Path.GetDirectoryName(text)).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); char directorySeparatorChar = Path.DirectorySeparatorChar; string value = text2 + directorySeparatorChar; StringComparison comparisonType = ((Environment.OSVersion.Platform == PlatformID.Win32NT) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); if (fullPath.StartsWith(value, comparisonType)) { throw new IOException("Private data must be outside the mod profile."); } return fullPath; } public PrivateSessionStorage(string configDirectory, string dataRoot) { DirectoryPath = ResolveDirectory(configDirectory, dataRoot); _store = new SessionStore(Path.Combine(DirectoryPath, "last-session.json")); PasswordProtection = new CrossPlatformPasswordProtection(Path.Combine(DirectoryPath, "keys")); } public SessionRecord Load() { SessionRecord sessionRecord = _store.Load(); if (sessionRecord != null) { PasswordProtection.Unprotect(sessionRecord.ProtectedPassword); } return sessionRecord; } public void Save(SessionRecord record, string password) { if (record == null) { throw new InvalidDataException("Invalid session."); } password = password ?? ""; Directory.CreateDirectory(DirectoryPath); record.ProtectedPassword = PasswordProtection.Protect(password); _store.Save(record); SessionRecord sessionRecord = _store.Load(); if (sessionRecord == null || sessionRecord.ProtectedPassword != record.ProtectedPassword || PasswordProtection.Unprotect(sessionRecord.ProtectedPassword) != password) { throw new InvalidDataException("Private session verification failed."); } } } [DataContract] public sealed class SessionRecord { [DataMember] public int Version = 1; [DataMember] public string ServerKind; [DataMember] public string Address; [DataMember] public int Port; [DataMember] public string ServerOwner; [DataMember] public string CharacterFilename; [DataMember] public long CharacterId; [DataMember] public string ProtectedPassword; public bool IsValid() { if (Version != 1 || string.IsNullOrWhiteSpace(CharacterFilename) || string.IsNullOrWhiteSpace(Address) || ProtectedPassword == null) { return false; } if (ServerKind == "Dedicated") { if (Port > 0) { return Port <= 65535; } return false; } if (ServerKind == "PlayFab") { return true; } if (ServerKind == "Steam" && ulong.TryParse(Address, out var result)) { return result != 0; } return false; } } public sealed class SessionStore { private readonly string _path; public SessionStore(string path) { _path = path; } public SessionRecord Load() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (!File.Exists(_path)) { return null; } if (new FileInfo(_path).Length > 65536) { throw new InvalidDataException("Saved session is too large."); } using FileStream fileStream = File.OpenRead(_path); SessionRecord sessionRecord = (SessionRecord)((XmlObjectSerializer)new DataContractJsonSerializer(typeof(SessionRecord))).ReadObject((Stream)fileStream); if (sessionRecord == null || !sessionRecord.IsValid()) { throw new InvalidDataException("Invalid saved session."); } return sessionRecord; } public void Save(SessionRecord record) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (record == null || !record.IsValid()) { throw new InvalidDataException("Invalid session."); } Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(_path))); string text = _path + ".tmp"; try { using (FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None)) { ((XmlObjectSerializer)new DataContractJsonSerializer(typeof(SessionRecord))).WriteObject((Stream)fileStream, (object)record); fileStream.Flush(flushToDisk: true); } if (File.Exists(_path)) { File.Replace(text, _path, null); } else { File.Move(text, _path); } } finally { if (File.Exists(text)) { File.Delete(text); } } } } }