aboutsummaryrefslogtreecommitdiff
path: root/ShiftOS_TheReturn/SaveSystem.cs
diff options
context:
space:
mode:
authorMichael VanOverbeek <[email protected]>2017-05-21 13:05:31 +0000
committerMichael VanOverbeek <[email protected]>2017-05-21 13:05:31 +0000
commit68785f73f027b9dd4555b9f1ab7a22a1ca8794f8 (patch)
treef0c6dea13195bc516f90c2aa29cf85fa1488f6cf /ShiftOS_TheReturn/SaveSystem.cs
parent76b54853ba726179f9fddb30c6f838991b7aa71a (diff)
parent9999324bd7751f536741c108322766421dae1a52 (diff)
downloadshiftos_thereturn-68785f73f027b9dd4555b9f1ab7a22a1ca8794f8.tar.gz
shiftos_thereturn-68785f73f027b9dd4555b9f1ab7a22a1ca8794f8.tar.bz2
shiftos_thereturn-68785f73f027b9dd4555b9f1ab7a22a1ca8794f8.zip
Merge branch 'master' of https://github.com/shiftos-game/ShiftOS
I should hire Ash Ketchum to do this for me. He'd do a better job.
Diffstat (limited to 'ShiftOS_TheReturn/SaveSystem.cs')
-rw-r--r--ShiftOS_TheReturn/SaveSystem.cs565
1 files changed, 565 insertions, 0 deletions
diff --git a/ShiftOS_TheReturn/SaveSystem.cs b/ShiftOS_TheReturn/SaveSystem.cs
new file mode 100644
index 0000000..9c812c7
--- /dev/null
+++ b/ShiftOS_TheReturn/SaveSystem.cs
@@ -0,0 +1,565 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2017 Michael VanOverbeek and ShiftOS devs
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+//#define ONLINEMODE
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.IO;
+using Newtonsoft.Json;
+using ShiftOS.Objects;
+using ShiftOS.Objects.ShiftFS;
+using oobe = ShiftOS.Engine.OutOfBoxExperience;
+using static System.Net.Mime.MediaTypeNames;
+
+namespace ShiftOS.Engine
+{
+ [Obsolete("Use the servers.conf file instead.")]
+ public class EngineConfig
+ {
+ public bool ConnectToMud = true;
+ public string MudDefaultIP = "dome.rol.im";
+ public int MudDefaultPort = 13370;
+ }
+
+ /// <summary>
+ /// Management class for the ShiftOS save system.
+ /// </summary>
+ public static class SaveSystem
+ {
+ /// <summary>
+ /// Boolean representing whether the system is shutting down.
+ /// </summary>
+ public static bool ShuttingDown = false;
+
+ /// <summary>
+ /// Gets or sets the current logged in client-side user.
+ /// </summary>
+ public static ClientSave CurrentUser { get; set; }
+
+ /// <summary>
+ /// Boolean representing whether the save system is ready to be used.
+ /// </summary>
+ public static bool Ready = false;
+
+ /// <summary>
+ /// Occurs before the save system connects to the ShiftOS Digital Society.
+ /// </summary>
+ public static event Action PreDigitalSocietyConnection;
+
+ /// <summary>
+ /// Gets or sets the current server-side save file.
+ /// </summary>
+ public static Save CurrentSave { get; set; }
+
+ /// <summary>
+ /// Start the entire ShiftOS engine.
+ /// </summary>
+ /// <param name="useDefaultUI">Whether ShiftOS should initiate it's Windows Forms front-end.</param>
+ public static void Begin(bool useDefaultUI = true)
+ {
+ AppDomain.CurrentDomain.UnhandledException += (o, a) =>
+ {
+ CrashHandler.Start((Exception)a.ExceptionObject);
+ };
+
+ if (!System.IO.File.Exists(Paths.SaveFile))
+ {
+ var root = new ShiftOS.Objects.ShiftFS.Directory();
+ root.Name = "System";
+ root.permissions = UserPermissions.Guest;
+ System.IO.File.WriteAllText(Paths.SaveFile, JsonConvert.SerializeObject(root));
+ }
+
+ if (Utils.Mounts.Count == 0)
+ Utils.Mount(System.IO.File.ReadAllText(Paths.SaveFile));
+ Paths.Init();
+
+ Localization.SetupTHETRUEDefaultLocals();
+ SkinEngine.Init();
+
+ TerminalBackend.OpenTerminal();
+
+ TerminalBackend.InStory = true;
+ var thread = new Thread(new ThreadStart(() =>
+ {
+ //Do not uncomment until I sort out the copyright stuff... - Michael
+ //AudioManager.Init();
+
+ var defaultConf = new EngineConfig();
+ if (System.IO.File.Exists("engineconfig.json"))
+ defaultConf = JsonConvert.DeserializeObject<EngineConfig>(System.IO.File.ReadAllText("engineconfig.json"));
+ else
+ {
+ System.IO.File.WriteAllText("engineconfig.json", JsonConvert.SerializeObject(defaultConf, Formatting.Indented));
+ }
+
+ Thread.Sleep(350);
+ Console.WriteLine("ShiftKernel v0.4.2");
+ Console.WriteLine("(MIT) DevX 2017, Very Little Rights Reserved");
+ Console.WriteLine("");
+ Console.WriteLine("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR");
+ Console.WriteLine("IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,");
+ Console.WriteLine("FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE");
+ Console.WriteLine("AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER");
+ Console.WriteLine("LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,");
+ Console.WriteLine("OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE");
+ Console.WriteLine("SOFTWARE.");
+ Console.WriteLine("");
+ Thread.Sleep(250);
+ Console.WriteLine("[init] Kernel boot complete.");
+ Console.WriteLine("[sfs] Loading SFS driver v3");
+ Thread.Sleep(100);
+ Console.WriteLine("[sfs] 4096 blocks read.");
+ Console.WriteLine("[simpl-conf] Reading configuration files (global-3.conf)");
+
+ Console.WriteLine("[inetd] Connecting to network...");
+
+ Ready = false;
+
+ if (PreDigitalSocietyConnection != null)
+ {
+ PreDigitalSocietyConnection?.Invoke();
+
+ while (!Ready)
+ {
+ Thread.Sleep(10);
+ }
+ }
+
+ if (defaultConf.ConnectToMud == true)
+ {
+ bool guidReceived = false;
+ ServerManager.GUIDReceived += (str) =>
+ {
+ //Connection successful! Stop waiting!
+ guidReceived = true;
+ Console.WriteLine("[inetd] Connection successful.");
+ };
+
+ try
+ {
+
+ ServerManager.Initiate(UserConfig.Get().DigitalSocietyAddress, UserConfig.Get().DigitalSocietyPort);
+ //This haults the client until the connection is successful.
+ while (ServerManager.thisGuid == new Guid())
+ {
+ Thread.Sleep(10);
+ }
+ Console.WriteLine("[inetd] DHCP GUID recieved, finished setup");
+ FinishBootstrap();
+ }
+ catch (Exception ex)
+ {
+ //No errors, this never gets called.
+ Console.WriteLine("[inetd] SEVERE: " + ex.Message);
+ Thread.Sleep(3000);
+ ServerManager.StartLANServer();
+ while (ServerManager.thisGuid == new Guid())
+ {
+ Thread.Sleep(10);
+ }
+ Console.WriteLine("[inetd] DHCP GUID recieved, finished setup");
+ FinishBootstrap();
+ }
+ }
+ else
+ {
+ ServerManager.StartLANServer();
+ }
+
+ //Nothing happens past this point - but the client IS connected! It shouldn't be stuck in that while loop above.
+
+
+ }));
+ thread.IsBackground = true;
+ thread.Start();
+ }
+
+ /// <summary>
+ /// Finish bootstrapping the engine.
+ /// </summary>
+ private static void FinishBootstrap()
+ {
+ KernelWatchdog.Log("mud_handshake", "handshake successful: kernel watchdog access code is \"" + ServerManager.thisGuid.ToString() + "\"");
+
+ ServerMessageReceived savehandshake = null;
+
+ savehandshake = (msg) =>
+ {
+ if (msg.Name == "mud_savefile")
+ {
+ CurrentSave = JsonConvert.DeserializeObject<Save>(msg.Contents);
+ ServerManager.MessageReceived -= savehandshake;
+ }
+ else if (msg.Name == "mud_login_denied")
+ {
+ oobe.PromptForLogin();
+ ServerManager.MessageReceived -= savehandshake;
+ }
+ };
+ ServerManager.MessageReceived += savehandshake;
+
+
+ ReadSave();
+
+ while (CurrentSave == null)
+ {
+ Thread.Sleep(10);
+ }
+
+ Localization.SetupTHETRUEDefaultLocals();
+
+ Shiftorium.Init();
+
+ while (CurrentSave.StoryPosition < 1)
+ {
+ Thread.Sleep(10);
+ }
+
+ Thread.Sleep(75);
+
+ Thread.Sleep(50);
+ Console.WriteLine("[usr-man] Accepting logins on local tty 1.");
+
+ Sysname:
+ bool waitingForNewSysName = false;
+ bool gobacktosysname = false;
+
+ if (string.IsNullOrWhiteSpace(CurrentSave.SystemName))
+ {
+ Infobox.PromptText("Enter a system name", "Your system does not have a name. All systems within the digital society must have a name. Please enter one.", (name) =>
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ Infobox.Show("Invalid name", "Please enter a valid name.", () =>
+ {
+ gobacktosysname = true;
+ waitingForNewSysName = false;
+ });
+ else if (name.Length < 5)
+ Infobox.Show("Value too small.", "Your system name must have at least 5 characters in it.", () =>
+ {
+ gobacktosysname = true;
+ waitingForNewSysName = false;
+ });
+ else
+ {
+ CurrentSave.SystemName = name;
+ if (!string.IsNullOrWhiteSpace(CurrentSave.UniteAuthToken))
+ {
+ var unite = new Unite.UniteClient("http://getshiftos.ml", CurrentSave.UniteAuthToken);
+ unite.SetSysName(name);
+ }
+ SaveSystem.SaveGame();
+ gobacktosysname = false;
+ waitingForNewSysName = false;
+ }
+ });
+
+
+ }
+
+ while (waitingForNewSysName)
+ {
+ Thread.Sleep(10);
+ }
+
+ if (gobacktosysname)
+ {
+ goto Sysname;
+ }
+
+ if (CurrentSave.Users == null)
+ CurrentSave.Users = new List<ClientSave>();
+
+
+ if (CurrentSave.Users.Count == 0)
+ {
+ CurrentSave.Users.Add(new ClientSave
+ {
+ Username = "root",
+ Password = "",
+ Permissions = UserPermissions.Root
+ });
+ Console.WriteLine("[usr-man] WARN: No users found. Creating new user with username \"root\", with no password.");
+ }
+ TerminalBackend.InStory = false;
+
+ TerminalBackend.PrefixEnabled = false;
+
+ if (LoginManager.ShouldUseGUILogin)
+ {
+ Action<ClientSave> Completed = null;
+ Completed += (user) =>
+ {
+ CurrentUser = user;
+ LoginManager.LoginComplete -= Completed;
+ };
+ LoginManager.LoginComplete += Completed;
+ Desktop.InvokeOnWorkerThread(() =>
+ {
+ LoginManager.PromptForLogin();
+ });
+ while (CurrentUser == null)
+ {
+ Thread.Sleep(10);
+ }
+ }
+ else
+ {
+
+ Login:
+ string username = "";
+ int progress = 0;
+ bool goback = false;
+ TextSentEventHandler ev = null;
+ ev = (text) =>
+ {
+ if (progress == 0)
+ {
+ string loginstr = CurrentSave.SystemName + " login: ";
+ string getuser = text.Remove(0, loginstr.Length);
+ if (!string.IsNullOrWhiteSpace(getuser))
+ {
+ if (CurrentSave.Users.FirstOrDefault(x => x.Username == getuser) == null)
+ {
+ Console.WriteLine("User not found.");
+ goback = true;
+ progress++;
+ TerminalBackend.TextSent -= ev;
+ return;
+ }
+ username = getuser;
+ progress++;
+ }
+ else
+ {
+ Console.WriteLine("Username not provided.");
+ TerminalBackend.TextSent -= ev;
+ goback = true;
+ progress++;
+ }
+ }
+ else if (progress == 1)
+ {
+ string passwordstr = "password: ";
+ string getpass = text.Remove(0, passwordstr.Length);
+ var user = CurrentSave.Users.FirstOrDefault(x => x.Username == username);
+ if (user.Password == getpass)
+ {
+ Console.WriteLine("Welcome to ShiftOS.");
+ CurrentUser = user;
+ Thread.Sleep(2000);
+ progress++;
+ }
+ else
+ {
+ Console.WriteLine("Access denied.");
+ goback = true;
+ progress++;
+ }
+ TerminalBackend.TextSent -= ev;
+ }
+ };
+ TerminalBackend.TextSent += ev;
+
+ Console.Write(CurrentSave.SystemName + " login: ");
+ while (progress == 0)
+ {
+ Thread.Sleep(10);
+ }
+ if (goback)
+ goto Login;
+ Console.Write("password: ");
+ while (progress == 1)
+ Thread.Sleep(10);
+ if (goback)
+ goto Login;
+ }
+ TerminalBackend.PrefixEnabled = true;
+ Shiftorium.LogOrphanedUpgrades = true;
+ Desktop.InvokeOnWorkerThread(new Action(() =>
+ {
+ ShiftOS.Engine.Scripting.LuaInterpreter.RunSft(Paths.GetPath("kernel.sft"));
+ }));
+
+
+ Desktop.InvokeOnWorkerThread(new Action(() => Desktop.PopulateAppLauncher()));
+ GameReady?.Invoke();
+ }
+
+ /// <summary>
+ /// Delegate type for events with no caller objects or event arguments. You can use the () => {...} (C#) lambda expression with this delegate
+ /// </summary>
+ public delegate void EmptyEventHandler();
+
+ /// <summary>
+ /// Gets a list of all client-side users.
+ /// </summary>
+ public static List<ClientSave> Users
+ {
+ get
+ {
+ return CurrentSave.Users;
+ }
+ }
+
+ /// <summary>
+ /// Occurs when the engine is loaded and the game can take over.
+ /// </summary>
+ public static event EmptyEventHandler GameReady;
+
+ /// <summary>
+ /// Deducts a set amount of Codepoints from the save file... and sends them to a place where they'll never be seen again.
+ /// </summary>
+ /// <param name="amount">The amount of Codepoints to deduct.</param>
+ public static void TransferCodepointsToVoid(long amount)
+ {
+ if (amount < 0)
+ throw new ArgumentOutOfRangeException("We see what you did there. Trying to pull Codepoints from the void? That won't work.");
+ CurrentSave.Codepoints -= amount;
+ NotificationDaemon.AddNotification(NotificationType.CodepointsSent, amount);
+ }
+
+ /// <summary>
+ /// Restarts the game.
+ /// </summary>
+ public static void Restart()
+ {
+ TerminalBackend.InvokeCommand("sos.shutdown");
+ System.Windows.Forms.Application.Restart();
+ }
+
+ /// <summary>
+ /// Requests the save file from the server. If authentication fails, this will cause the user to be prompted for their website login and a new save will be created if none is associated with the login.
+ /// </summary>
+ public static void ReadSave()
+ {
+ //Migrate old saves.
+ if(System.IO.Directory.Exists("C:\\ShiftOS2"))
+ {
+ Console.WriteLine("Old save detected. Migrating filesystem to MFS...");
+ foreach (string file in System.IO.Directory.EnumerateDirectories("C:\\ShiftOS2")
+.Select(d => new DirectoryInfo(d).FullName))
+ {
+ if(!Utils.DirectoryExists(file.Replace("C:\\ShiftOS2\\", "0:/").Replace("\\", "/")))
+ Utils.CreateDirectory(file.Replace("C:\\ShiftOS2\\", "0:/").Replace("\\", "/"));
+ }
+ foreach (string file in System.IO.Directory.EnumerateFiles("C:\\ShiftOS2"))
+ {
+
+ string rfile = Path.GetFileName(file);
+ Utils.WriteAllBytes(file.Replace("C:\\ShiftOS2\\", "0:/").Replace("\\", "/"), System.IO.File.ReadAllBytes(file));
+ Console.WriteLine("Exported file " + file);
+ }
+
+ }
+
+
+ if (Utils.FileExists(Paths.SaveFileInner))
+ {
+ oobe.ShowSaveTransfer(JsonConvert.DeserializeObject<Save>(Utils.ReadAllText(Paths.SaveFileInner)));
+ }
+ else
+ {
+ if (Utils.FileExists(Paths.GetPath("user.dat")))
+ {
+ string token = Utils.ReadAllText(Paths.GetPath("user.dat"));
+
+ ServerManager.SendMessage("mud_token_login", token);
+ }
+ else
+ {
+ NewSave();
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// Creates a new save, starting the Out Of Box Experience (OOBE).
+ /// </summary>
+ public static void NewSave()
+ {
+ AppearanceManager.Invoke(new Action(() =>
+ {
+ CurrentSave = new Save();
+ CurrentSave.Codepoints = 0;
+ CurrentSave.Upgrades = new Dictionary<string, bool>();
+ Shiftorium.Init();
+ oobe.Start(CurrentSave);
+ }));
+ }
+
+ /// <summary>
+ /// Saves the game to the server, updating website stats if possible.
+ /// </summary>
+ public static void SaveGame()
+ {
+ if(!Shiftorium.Silent)
+ Console.WriteLine("");
+ if(!Shiftorium.Silent)
+ Console.Write("{SE_SAVING}... ");
+ if (SaveSystem.CurrentSave != null)
+ {
+ Utils.WriteAllText(Paths.GetPath("user.dat"), CurrentSave.UniteAuthToken);
+ ServerManager.SendMessage("mud_save", JsonConvert.SerializeObject(CurrentSave, Formatting.Indented));
+ }
+ if (!Shiftorium.Silent)
+ Console.WriteLine(" ...{DONE}.");
+ System.IO.File.WriteAllText(Paths.SaveFile, Utils.ExportMount(0));
+ }
+
+ /// <summary>
+ /// Transfers codepoints from an arbitrary character to the save file.
+ /// </summary>
+ /// <param name="who">The character name</param>
+ /// <param name="amount">The amount of Codepoints.</param>
+ public static void TransferCodepointsFrom(string who, long amount)
+ {
+ if (amount < 0)
+ throw new ArgumentOutOfRangeException("We see what you did there... You can't just give a fake character Codepoints like that. It's better if you transfer them to the void.");
+ NotificationDaemon.AddNotification(NotificationType.CodepointsReceived, amount);
+ CurrentSave.Codepoints += amount;
+ }
+ }
+
+ /// <summary>
+ /// Delegate for handling Terminal text input.
+ /// </summary>
+ /// <param name="text">The text inputted by the user (including prompt text).</param>
+ public delegate void TextSentEventHandler(string text);
+
+ /// <summary>
+ /// Denotes that this Terminal command or namespace is for developers.
+ /// </summary>
+ public class DeveloperAttribute : Attribute
+ {
+
+ }
+}