aboutsummaryrefslogtreecommitdiff
path: root/ShiftOS_TheReturn
diff options
context:
space:
mode:
authorAShifter <[email protected]>2017-06-05 09:49:46 -0600
committerAShifter <[email protected]>2017-06-05 09:49:46 -0600
commit61c906e596145bbedd60725c6dcee68c34a27907 (patch)
treecd7a00d501affe96028bfb21a8dec90c2ee63f2c /ShiftOS_TheReturn
parent66ea2cf2fdeeaa025bd22961a0400423233c505d (diff)
parent3e11eca70481841b6e2f2253d667944779cfd5fb (diff)
downloadshiftos_thereturn-61c906e596145bbedd60725c6dcee68c34a27907.tar.gz
shiftos_thereturn-61c906e596145bbedd60725c6dcee68c34a27907.tar.bz2
shiftos_thereturn-61c906e596145bbedd60725c6dcee68c34a27907.zip
Merge remote-tracking branch 'refs/remotes/shiftos-game/master'
Diffstat (limited to 'ShiftOS_TheReturn')
-rw-r--r--ShiftOS_TheReturn/AppearanceManager.cs238
-rw-r--r--ShiftOS_TheReturn/AudioManager.cs68
-rw-r--r--ShiftOS_TheReturn/Commands.cs230
-rw-r--r--ShiftOS_TheReturn/ConsoleEx.cs7
-rw-r--r--ShiftOS_TheReturn/CrashHandler.cs38
-rw-r--r--ShiftOS_TheReturn/Desktop.cs17
-rw-r--r--ShiftOS_TheReturn/IStatusIcon.cs14
-rw-r--r--ShiftOS_TheReturn/KernelWatchdog.cs54
-rw-r--r--ShiftOS_TheReturn/Localization.cs98
-rw-r--r--ShiftOS_TheReturn/LoginManager.cs65
-rw-r--r--ShiftOS_TheReturn/NotificationDaemon.cs57
-rw-r--r--ShiftOS_TheReturn/OutOfBoxExperience.cs11
-rw-r--r--ShiftOS_TheReturn/Paths.cs45
-rw-r--r--ShiftOS_TheReturn/SaveSystem.cs372
-rw-r--r--ShiftOS_TheReturn/Scripting.cs257
-rw-r--r--ShiftOS_TheReturn/Server.cs40
-rw-r--r--ShiftOS_TheReturn/ServerManager.cs168
-rw-r--r--ShiftOS_TheReturn/ShiftOS.Engine.csproj10
-rw-r--r--ShiftOS_TheReturn/ShiftnetSite.cs53
-rw-r--r--ShiftOS_TheReturn/Shiftorium.cs355
-rw-r--r--ShiftOS_TheReturn/Skinning.cs280
-rw-r--r--ShiftOS_TheReturn/Story.cs335
-rw-r--r--ShiftOS_TheReturn/TerminalBackend.cs677
-rw-r--r--ShiftOS_TheReturn/TerminalTextWriter.cs65
-rw-r--r--ShiftOS_TheReturn/TutorialManager.cs8
-rw-r--r--ShiftOS_TheReturn/UniteClient.cs127
-rw-r--r--ShiftOS_TheReturn/UniteTestCommands.cs74
-rw-r--r--ShiftOS_TheReturn/UserManagementCommands.cs89
-rw-r--r--ShiftOS_TheReturn/VirusEngine.cs106
29 files changed, 2405 insertions, 1553 deletions
diff --git a/ShiftOS_TheReturn/AppearanceManager.cs b/ShiftOS_TheReturn/AppearanceManager.cs
index 4c1754e..7cf06c9 100644
--- a/ShiftOS_TheReturn/AppearanceManager.cs
+++ b/ShiftOS_TheReturn/AppearanceManager.cs
@@ -38,9 +38,7 @@ using static ShiftOS.Engine.SaveSystem;
namespace ShiftOS.Engine
{
- /// <summary>
- /// Provides functionality for managing windows within ShiftOS.
- /// </summary>
+ // Provides functionality for managing windows within ShiftOS.
public static class AppearanceManager
{
[Obsolete("Please use Localization.GetAllLanguages().")]
@@ -49,12 +47,7 @@ namespace ShiftOS.Engine
return Localization.GetAllLanguages();
}
- /// <summary>
- /// Sets the title text of the specified window.
- /// </summary>
- /// <param name="window">The window to modify</param>
- /// <param name="title">The title text to use</param>
- /// <exception cref="ArgumentNullException">Thrown if the window is null.</exception>
+ // Sets the title text of the specified window.
public static void SetWindowTitle(IShiftOSWindow window, string title)
{
if (window == null)
@@ -62,11 +55,13 @@ namespace ShiftOS.Engine
winmgr.SetTitle(window, title);
}
+ //HEY LETS FIND THE WINDOWS
public static IEnumerable<Type> GetAllWindowTypes()
{
List<Type> types = new List<Type>();
foreach(var file in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
{
+ // hey if a thing is an exe or a dll show up plz kthx
if(file.EndsWith(".exe") || file.EndsWith(".dll"))
{
try
@@ -84,12 +79,7 @@ namespace ShiftOS.Engine
return types;
}
- /// <summary>
- /// Returns the default window title for a specified <see cref="IShiftOSWindow"/>-inheriting type.
- /// </summary>
- /// <param name="winType">The type to scan</param>
- /// <returns>The default title</returns>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="winType"/> is null.</exception>
+ // hey you know that window we just made appear? well give it its title
public static string GetDefaultTitle(Type winType)
{
if (winType == null)
@@ -104,257 +94,155 @@ namespace ShiftOS.Engine
return winType.Name;
}
- /// <summary>
- /// Current cursor position of the console
- /// </summary>
+ // Current cursor position of the console
public static int CurrentPosition { get; set; }
- /// <summary>
- /// We don't know what this does. It may be gone if it does nothing.
- /// </summary>
+ // We don't know what this does. It may be gone if it does nothing.
public static int LastLength { get; set; }
- /// <summary>
- /// Minimize a window.
- /// </summary>
- /// <param name="form">The window border to minimize.</param>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="form"/> is null.</exception>
- /// <exception cref="EngineModuleDisabledException">Thrown if this part of the engine hasn't been enabled.</exception>
+ // Minimize a window.
public static void Minimize(IWindowBorder form)
{
if (form == null)
+ //FUCK WHY THE FUCK IS THIS NULL
throw new ArgumentNullException("form");
if (winmgr == null)
+ //FUCK THIS PART OF THE ENGINE WASNT TURNED ON YET
throw new EngineModuleDisabledException();
winmgr.Minimize(form);
}
- /// <summary>
- /// Maximizes a window.
- /// </summary>
- /// <param name="form">The window border to maximize.</param>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="form"/> is null.</exception>
- /// <exception cref="EngineModuleDisabledException">Thrown if this engine module hasn't been enabled.</exception>
+ // Maximizes a window! :D
public static void Maximize(IWindowBorder form)
{
if (form == null)
+ //AHHHH SHOULDNT BE NULLLLLL
throw new ArgumentNullException("form");
if (winmgr == null)
+ //WHY ARE YOU DOING THIS PART OF THE ENGINE IT WASNT ENABLED FUCK
throw new EngineModuleDisabledException();
winmgr.Maximize(form);
}
- /// <summary>
- /// Provides a list of all open ShiftOS windows.
- /// </summary>
+ // Provides a list of all open ShiftOS windows.
public static List<IWindowBorder> OpenForms = new List<IWindowBorder>();
- /// <summary>
- /// Decorates a window with a border, then shows the window.
- /// </summary>
- /// <param name="form">The window to decorate and show.</param>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="form"/> is null. </exception>
- /// <exception cref="EngineModuleDisabledException">Thrown if this engine module has not been initiated yet.</exception>
+ // Decorates a window with a border, then shows the window.
public static void SetupWindow(IShiftOSWindow form)
{
if (form == null)
+ //YOU GET THE POINT THIS REALLY SHOULDNT BE NULL
throw new ArgumentNullException("form");
if (winmgr == null)
+ //SAME HERE
throw new EngineModuleDisabledException();
winmgr.SetupWindow(form);
Desktop.ResetPanelButtons();
}
- /// <summary>
- /// Closes the specified window.
- /// </summary>
- /// <param name="win">The window to close.</param>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="win"/> is null. </exception>
- /// <exception cref="EngineModuleDisabledException">Thrown if this engine module has not been initiated yet.</exception>
+ // Closes the specified window. SHOCKED YOU ARE I KNOW, HOW COULD YOU HAVE GUESSED
public static void Close(IShiftOSWindow win)
{
if (win == null)
+ //NOPE SHOULDNT BE NULL
throw new ArgumentNullException("win");
if (winmgr == null)
+ //WHY IS THIS NULL
throw new EngineModuleDisabledException();
winmgr.Close(win);
Desktop.ResetPanelButtons();
}
- /// <summary>
- /// Decorates a window with a border, then shows the window, as a dialog box.
- /// </summary>
- /// <param name="form">The window to decorate and show.</param>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="form"/> is null. </exception>
- /// <exception cref="EngineModuleDisabledException">Thrown if this engine module has not been initiated yet.</exception>
+
+ // Decorates a window with a border, then shows the window, as a dialog box.
public static void SetupDialog(IShiftOSWindow form)
{
if (form == null)
+ //NULLLLLLLLL
throw new ArgumentNullException("form");
if (winmgr == null)
+ //ASGDFHASDGF
throw new EngineModuleDisabledException();
winmgr.SetupDialog(form);
Desktop.ResetPanelButtons();
}
- /// <summary>
- /// The underlying window manager for this engine module
- /// </summary>
+ // The underlying window manager for this engine module
private static WindowManager winmgr = null;
- /// <summary>
- /// Initiate this engine module, and perform mandatory configuration.
- /// </summary>
- /// <param name="mgr">A working, configured <see cref="WindowManager"/> to use as a backend for this module </param>
+ // Initiate this engine module, and perform mandatory configuration.
public static void Initiate(WindowManager mgr)
{
- winmgr = mgr;
+ winmgr = mgr; // A working, configured window manager to use as a backend for this module
}
- /// <summary>
- /// Raised when the engine is entering its shutdown phase. Save your work!
- /// </summary>
+
+ // Raised when the engine is entering its shutdown phase. Save your work!
public static event EmptyEventHandler OnExit;
- /// <summary>
- /// Starts the engine's exit routine, firing the OnExit event.
- /// </summary>
+ // Starts the engine's exit routine, firing the OnExit event.
internal static void Exit()
{
OnExit?.Invoke();
//disconnect from MUD
ServerManager.Disconnect();
+ Desktop.InvokeOnWorkerThread(() =>
+ {
+ Process.GetCurrentProcess().Kill(); //bye bye
+ });
}
- /// <summary>
- /// The current terminal body control.
- /// </summary>
+ // The current terminal body control.
public static ITerminalWidget ConsoleOut { get; set; }
- /// <summary>
- /// Redirects the .NET <see cref="Console"/> to a new <see cref="TerminalTextWriter"/> instance.
- /// </summary>
+ // Redirects the .NET to a new TerminalTextWriter instance.
public static void StartConsoleOut()
{
- Console.SetOut(new TerminalTextWriter());
+ Console.SetOut(new TerminalTextWriter()); //"plz start writing text .NET kthx"
}
- /// <summary>
- /// Invokes an action on the window management thread.
- /// </summary>
- /// <param name="act">The action to invoke</param>
+ // Invokes an action on the window management thread.
public static void Invoke(Action act)
{
winmgr.InvokeAction(act);
}
}
- /// <summary>
- /// Provides the base functionality for a ShiftOS terminal.
- /// </summary>
+ // Provides the base functionality for a ShiftOS terminal.
public interface ITerminalWidget
{
- /// <summary>
- /// Write text to this Terminal.
- /// </summary>
- /// <param name="text">Text to write</param>
- void Write(string text);
- /// <summary>
- /// Write text to this Terminal, followed by a newline.
- /// </summary>
- /// <param name="text">Text to write.</param>
- void WriteLine(string text);
- /// <summary>
- /// Clear the contents of this Terminal.
- /// </summary>
- void Clear();
- /// <summary>
- /// Move the cursor to the last character in the Terminal.
- /// </summary>
- void SelectBottom();
+ void Write(string text); // Actually write text to this Terminal! :D:D:D:D
+ void WriteLine(string text); // Write text to this Terminal, followed by a newline.
+ void Clear(); // Clear the contents of this Terminal, i bet you wouldve never guessed that
+ void SelectBottom(); // Move the cursor to the last character in the Terminal.
}
- /// <summary>
- /// Provides the base functionality for a ShiftOS window manager.
- /// </summary>
+ // makes the window manager actually do its job
public abstract class WindowManager
{
- /// <summary>
- /// Minimizes a window
- /// </summary>
- /// <param name="border">The window border to minimize</param>
- public abstract void Minimize(IWindowBorder border);
-
- /// <summary>
- /// Maximizes a window
- /// </summary>
- /// <param name="border">The window border to maximize</param>
- public abstract void Maximize(IWindowBorder border);
-
- /// <summary>
- /// Closes a window
- /// </summary>
- /// <param name="win">The window to close</param>
- public abstract void Close(IShiftOSWindow win);
-
- /// <summary>
- /// Decorates a window with a window border, then shows it to the user.
- /// </summary>
- /// <param name="win">The window to decorate.</param>
- public abstract void SetupWindow(IShiftOSWindow win);
-
- /// <summary>
- /// Decorates a window with a border, then shows it to the user as a dialog box.
- /// </summary>
- /// <param name="win">The window to decorate</param>
- public abstract void SetupDialog(IShiftOSWindow win);
-
- /// <summary>
- /// Invokes an action on the window management thread.
- /// </summary>
- /// <param name="act">The action to invoke.</param>
- public abstract void InvokeAction(Action act);
-
- /// <summary>
- /// Sets the title text of a window.
- /// </summary>
- /// <param name="win">The window to modify.</param>
- /// <param name="title">The new title text.</param>
- public abstract void SetTitle(IShiftOSWindow win, string title);
+ public abstract void Minimize(IWindowBorder border); // guess what this does
+ public abstract void Maximize(IWindowBorder border); // ooh this too
+ public abstract void Close(IShiftOSWindow win); // omg this probably does something
+ public abstract void SetupWindow(IShiftOSWindow win); // i cant think of what this does
+ public abstract void SetupDialog(IShiftOSWindow win); // how about this???????
+ public abstract void InvokeAction(Action act); // i wonder what this invokes
+ public abstract void SetTitle(IShiftOSWindow win, string title); // what is a title again
}
- /// <summary>
- /// Provides the base functionality for a typical ShiftOS window border.
- /// </summary>
+ // Provides the base functionality for a typical ShiftOS window border, what did you expect
public interface IWindowBorder
{
- /// <summary>
- /// Closes the border along with its window. Unload events should be invoked here.
- /// </summary>
- void Close();
-
- /// <summary>
- /// Gets or sets the title text for the window border.
- /// </summary>
- string Text { get; set; }
-
- /// <summary>
- /// Gets or sets the underlying <see cref="IShiftOSWindow"/> for this border.
- /// </summary>
- IShiftOSWindow ParentWindow { get; set; }
+ void Close(); // CLOSES THE BORDER ALONG WITH ITS WINDOW!!!!!!! HOLY SHIT I DIDNT EXPECT THAT
+ string Text { get; set; } // title text exists now
+ IShiftOSWindow ParentWindow { get; set; } // Gets or sets the underlying for this border.
}
-
- /// <summary>
- /// Provides a way of setting default title text for <see cref="IShiftOSWindow"/> classes.
- /// </summary>
+
+ // Provides a way of setting default title text for classes.
public class DefaultTitleAttribute : Attribute
{
- /// <summary>
- /// Creates a new instance of the <see cref="DefaultTitleAttribute"/>.
- /// </summary>
- /// <param name="title">A default title to associate with this attribute.</param>
+ // oy if you cant find a title this is the one you should use
public DefaultTitleAttribute(string title)
{
Title = title;
@@ -363,17 +251,13 @@ namespace ShiftOS.Engine
public string Title { get; private set; }
}
- /// <summary>
- /// An exception that is thrown when mandatory configuration to run a specific method or module hasn't been done yet.
- /// </summary>
+ // An exception that is thrown when mandatory configuration to run a specific method or module hasn't been done yet.
public class EngineModuleDisabledException : Exception
{
- /// <summary>
- /// Initializes a new instance of the <see cref="EngineModuleDisabledException"/>.
- /// </summary>
+ // FUCK WE DIDNT ORDER THINGS RIGHT
public EngineModuleDisabledException() : base("This engine module has not yet been enabled.")
{
-
+ //FUCK
}
}
}
diff --git a/ShiftOS_TheReturn/AudioManager.cs b/ShiftOS_TheReturn/AudioManager.cs
index a636497..0a1a210 100644
--- a/ShiftOS_TheReturn/AudioManager.cs
+++ b/ShiftOS_TheReturn/AudioManager.cs
@@ -47,9 +47,12 @@ namespace ShiftOS.Engine
/// </summary>
public static void Stop()
{
- _out?.Stop();
- _reader?.Dispose();
- _out?.Dispose();
+ Desktop.InvokeOnWorkerThread(() =>
+ {
+ _out?.Stop();
+ _reader?.Dispose();
+ _out?.Dispose();
+ });
}
/// <summary>
@@ -80,16 +83,29 @@ namespace ShiftOS.Engine
/// <param name="file">The file to play.</param>
public static void Play(string file)
{
- try
+ bool play = true;
+ float volume = 1f;
+ if (SaveSystem.CurrentSave != null)
{
- _reader = new AudioFileReader(file);
- _out = new WaveOut();
- _out.Init(_reader);
- _out.Volume = _provider.Volume;
- _out.Play();
- _out.PlaybackStopped += (o, a) => { PlayCompleted?.Invoke(); };
+ play = (SaveSystem.CurrentSave.SoundEnabled);
+ volume = (float)SaveSystem.CurrentSave.MusicVolume / 100f;
+ }
+ if (play)
+ {
+ try
+ {
+ _reader = new AudioFileReader(file);
+ _out = new WaveOut();
+ _out.Init(_reader);
+ _out.Volume = volume;
+ _out.Play();
+ _out.PlaybackStopped += (o, a) => { PlayCompleted?.Invoke(); };
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Audio error: " + ex.Message);
+ }
}
- catch { }
}
/// <summary>
@@ -98,15 +114,27 @@ namespace ShiftOS.Engine
/// <param name="str">The stream to read from.</param>
public static void PlayStream(Stream str)
{
- var bytes = new byte[str.Length];
- str.Read(bytes, 0, bytes.Length);
- ShiftOS.Engine.AudioManager.Stop();
- if (File.Exists("snd.wav"))
- File.Delete("snd.wav");
- File.WriteAllBytes("snd.wav", bytes);
-
- ShiftOS.Engine.AudioManager.Play("snd.wav");
-
+ try
+ {
+ bool play = true;
+ float volume = 1f;
+ if (SaveSystem.CurrentSave != null)
+ {
+ play = (SaveSystem.CurrentSave.SoundEnabled);
+ volume = (float)SaveSystem.CurrentSave.MusicVolume / 100f;
+ }
+ if (play)
+ {
+ ShiftOS.Engine.AudioManager.Stop();
+ _out = new WaveOut();
+ var mp3 = new WaveFileReader(str);
+ _out.Init(mp3);
+ _out.Volume = volume;
+ _out.Play();
+ _out.PlaybackStopped += (o, a) => { PlayCompleted?.Invoke(); };
+ }
+ }
+ catch { }
}
public static event Action PlayCompleted;
diff --git a/ShiftOS_TheReturn/Commands.cs b/ShiftOS_TheReturn/Commands.cs
index 57d1d34..f37bcb3 100644
--- a/ShiftOS_TheReturn/Commands.cs
+++ b/ShiftOS_TheReturn/Commands.cs
@@ -95,7 +95,7 @@ namespace ShiftOS.Engine
{
TerminalBackend.IsForwardingConsoleWrites = forwarding;
TerminalBackend.ForwardGUID = (forwarding == true) ? fGuid : null;
- Console.WriteLine($"{SaveSystem.CurrentSave.Username} says \"{result}\".");
+ Console.WriteLine($"{SaveSystem.CurrentUser.Username} says \"{result}\".");
TerminalBackend.IsForwardingConsoleWrites = false;
};
Desktop.InvokeOnWorkerThread(new Action(() =>
@@ -233,6 +233,23 @@ namespace ShiftOS.Engine
[Namespace("dev")]
public static class ShiftOSDevCommands
{
+ [Command("buy")]
+ public static bool UnlockUpgrade(Dictionary<string, object> args)
+ {
+ string upg = args["id"].ToString();
+ try
+ {
+ SaveSystem.CurrentSave.Upgrades[upg] = true;
+ Shiftorium.InvokeUpgradeInstalled();
+ SaveSystem.SaveGame();
+ }
+ catch
+ {
+ Console.WriteLine("Upgrade not found.");
+ }
+ return true;
+ }
+
[Command("rock", description = "A little surprise for unstable builds...")]
public static bool ThrowASandwichingRock()
{
@@ -276,6 +293,17 @@ namespace ShiftOS.Engine
return true;
}
+ [Command("restart")]
+ public static bool Restart()
+ {
+ SaveSystem.CurrentSave.Upgrades = new Dictionary<string, bool>();
+ SaveSystem.CurrentSave.Codepoints = 0;
+ SaveSystem.CurrentSave.StoriesExperienced.Clear();
+ SaveSystem.CurrentSave.StoriesExperienced.Add("mud_fundamentals");
+ SaveSystem.SaveGame();
+ Shiftorium.InvokeUpgradeInstalled();
+ return true;
+ }
[Command("freecp")]
public static bool FreeCodepoints(Dictionary<string, object> args)
@@ -283,8 +311,8 @@ namespace ShiftOS.Engine
if (args.ContainsKey("amount"))
try
{
- Int64 codepointsToAdd = Convert.ToInt64(args["amount"].ToString());
- SaveSystem.TransferCodepointsFrom("dev", codepointsToAdd);
+ ulong codepointsToAdd = Convert.ToUInt64(args["amount"].ToString());
+ SaveSystem.CurrentSave.Codepoints += codepointsToAdd;
return true;
}
catch (Exception ex)
@@ -293,7 +321,7 @@ namespace ShiftOS.Engine
return true;
}
- SaveSystem.TransferCodepointsFrom("dev", 1000);
+ SaveSystem.CurrentSave.Codepoints += 1000;
return true;
}
@@ -302,8 +330,13 @@ namespace ShiftOS.Engine
{
foreach (var upg in Shiftorium.GetDefaults())
{
- Shiftorium.Buy(upg.ID, 0);
+ if (!SaveSystem.CurrentSave.Upgrades.ContainsKey(upg.ID))
+ SaveSystem.CurrentSave.Upgrades.Add(upg.ID, true);
+ else
+ SaveSystem.CurrentSave.Upgrades[upg.ID] = true;
}
+ Shiftorium.InvokeUpgradeInstalled();
+ SkinEngine.LoadSkin();
return true;
}
@@ -350,12 +383,67 @@ namespace ShiftOS.Engine
[Namespace("sos")]
public static class ShiftOSCommands
{
+
+ [Command("setsfxenabled", description = "Set whether or not sound effects are enabled in the system.")]
+ [RequiresArgument("value")]
+ public static bool SetSfxEnabled(Dictionary<string, object> args)
+ {
+ try
+ {
+ bool value = Convert.ToBoolean(args["value"].ToString());
+ SaveSystem.CurrentSave.SoundEnabled = value;
+ SaveSystem.SaveGame();
+ }
+ catch
+ {
+ Console.WriteLine("Error: Value must be either true or false.");
+ }
+ return true;
+ }
+
+
+
+ [Command("setmusicenabled", description = "Set whether or not music is enabled in the system.")]
+ [RequiresArgument("value")]
+ public static bool SetMusicEnabled(Dictionary<string, object> args)
+ {
+ try
+ {
+ bool value = Convert.ToBoolean(args["value"].ToString());
+ SaveSystem.CurrentSave.MusicEnabled = value;
+ SaveSystem.SaveGame();
+ }
+ catch
+ {
+ Console.WriteLine("Error: Value must be either true or false.");
+ }
+ return true;
+ }
+
+
+
+ [Command("setsfxvolume", description ="Set the system sound volume to a value between 1 and 100.")]
+ [RequiresArgument("value")]
+ public static bool SetSfxVolume(Dictionary<string, object> args)
+ {
+ int value = int.Parse(args["value"].ToString());
+ if(value >= 0 && value <= 100)
+ {
+ SaveSystem.CurrentSave.MusicVolume = value;
+ SaveSystem.SaveGame();
+ }
+ else
+ {
+ Console.WriteLine("Volume must be between 0 and 100!");
+ }
+ return true;
+ }
+
[RemoteLock]
[Command("shutdown")]
public static bool Shutdown()
{
TerminalBackend.InvokeCommand("sos.save");
- SaveSystem.ShuttingDown = true;
AppearanceManager.Exit();
return true;
}
@@ -389,85 +477,43 @@ namespace ShiftOS.Engine
}
}
- [Command("help", "{COMMAND_HELP_USAGE}", "{COMMAND_HELP_DESCRIPTION}")]
- public static bool Help()
+ [Command("help", "{COMMAND_HELP_USAGE", "{COMMAND_HELP_DESCRIPTION}")]
+ public static bool Help(Dictionary<string, object> args)
{
- foreach (var exec in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
+ var sb = new StringBuilder();
+ sb.AppendLine("Retrieving help data.");
+
+ if (args.ContainsKey("ns"))
{
- if (exec.EndsWith(".exe") || exec.EndsWith(".dll"))
+ string ns = args["ns"].ToString();
+ //First let's check for a command that has this namespace.
+ var cmdtest = TerminalBackend.Commands.FirstOrDefault(x => x.NamespaceInfo.name == ns);
+ if (cmdtest == null) //Namespace not found.
+ sb.AppendLine("Error retrieving help for namespace \"" + ns + "\". Namespace not found.");
+ else
{
- try
+ //Now do the actual scan.
+ sb.AppendLine("Namespace: " + ns);
+ foreach(var cmd in TerminalBackend.Commands.Where(x => x.NamespaceInfo.name == ns))
{
- var asm = Assembly.LoadFile(exec);
-
- var types = asm.GetTypes();
-
- foreach (var type in types)
- {
- if (Shiftorium.UpgradeAttributesUnlocked(type))
- {
- foreach (var a in type.GetCustomAttributes(false))
- {
- if (a is Namespace)
- {
- var ns = a as Namespace;
-
- if (!ns.hide)
- {
- string descp = "{NAMESPACE_" + ns.name.ToUpper() + "_DESCRIPTION}";
- if (descp == Localization.Parse(descp))
- descp = "";
- else
- descp = Shiftorium.UpgradeInstalled("help_description") ? Localization.Parse("{SEPERATOR}" + descp) : "";
-
- Console.WriteLine($"{{NAMESPACE}}{ns.name}" + descp);
-
- foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Static))
- {
- if (Shiftorium.UpgradeAttributesUnlocked(method))
- {
- foreach (var ma in method.GetCustomAttributes(false))
- {
- if (ma is Command)
- {
- var cmd = ma as Command;
-
- if (!cmd.hide)
- {
- string descriptionparse = "{COMMAND_" + ns.name.ToUpper() + "_" + cmd.name.ToUpper() + "_DESCRIPTION}";
- string usageparse = "{COMMAND_" + ns.name.ToUpper() + "_" + cmd.name.ToUpper() + "_USAGE}";
- if (descriptionparse == Localization.Parse(descriptionparse))
- descriptionparse = "";
- else
- descriptionparse = Shiftorium.UpgradeInstalled("help_description") ? Localization.Parse("{SEPERATOR}" + descriptionparse) : "";
-
- if (usageparse == Localization.Parse(usageparse))
- usageparse = "";
- else
- usageparse = Shiftorium.UpgradeInstalled("help_usage") ? Localization.Parse("{SEPERATOR}" + usageparse, new Dictionary<string, string>() {
- {"%ns", ns.name},
- {"%cmd", cmd.name}
- }) : "";
-
- Console.WriteLine($"{{COMMAND}}{ns.name}.{cmd.name}" + usageparse + descriptionparse);
- }
- }
- }
- }
-
- }
- }
-
- }
- }
- }
- }
-
+ string str = cmd.ToString();
+ str = str.Replace(str.Substring(str.LastIndexOf("|")), "");
+ sb.AppendLine(str);
}
- catch { }
+ }
+ }
+ else
+ {
+
+ //print all unique namespaces.
+ foreach(var n in TerminalBackend.Commands.Select(x => x.NamespaceInfo.name).Distinct())
+ {
+ sb.AppendLine("sos.help{ns:\"" + n + "\"}");
}
}
+ Console.WriteLine(sb.ToString());
+
return true;
}
@@ -487,11 +533,33 @@ namespace ShiftOS.Engine
Codepoints: {SaveSystem.CurrentSave.Codepoints}
Upgrades: {SaveSystem.CurrentSave.CountUpgrades()} installed,
- {Shiftorium.GetAvailable().Length} available";
+ {Shiftorium.GetAvailable().Length} available
+
+";
- if (Shiftorium.UpgradeInstalled("mud_control_centre"))
- status += Environment.NewLine + $"Reputation: {SaveSystem.CurrentSave.RawReputation} ({SaveSystem.CurrentSave.Reputation})";
Console.WriteLine(status);
+ Console.WriteLine("Objectives:");
+ try
+ {
+ if (Story.CurrentObjectives.Count > 0)
+ {
+ foreach (var obj in Story.CurrentObjectives)
+ {
+ Console.WriteLine(obj.Name);
+ Console.WriteLine("-------------------------------");
+ Console.WriteLine();
+ Console.WriteLine(obj.Description);
+ }
+ }
+ else
+ {
+ Console.WriteLine(" - No objectives are running. Check back later!");
+ }
+ }
+ catch
+ {
+ Console.WriteLine(" - No objectives are running. Check back later!");
+ }
return true;
}
}
@@ -615,7 +683,7 @@ shiftorium.buy{{upgrade:""{upg.ID}""}}");
cat = args["cat"].ToString();
}
- Dictionary<string, long> upgrades = new Dictionary<string, long>();
+ Dictionary<string, ulong> upgrades = new Dictionary<string, ulong>();
int maxLength = 5;
IEnumerable<ShiftoriumUpgrade> upglist = Shiftorium.GetAvailable();
diff --git a/ShiftOS_TheReturn/ConsoleEx.cs b/ShiftOS_TheReturn/ConsoleEx.cs
index 90f9cc0..74483dc 100644
--- a/ShiftOS_TheReturn/ConsoleEx.cs
+++ b/ShiftOS_TheReturn/ConsoleEx.cs
@@ -48,5 +48,12 @@ namespace ShiftOS.Engine
/// Gets or sets whether text in the Terminal is underlined.
/// </summary>
public static bool Underline { get; set; }
+
+ internal static void Flush()
+ {
+ OnFlush?.Invoke();
+ }
+
+ public static Action OnFlush;
}
}
diff --git a/ShiftOS_TheReturn/CrashHandler.cs b/ShiftOS_TheReturn/CrashHandler.cs
index ed42ea5..48eaf1f 100644
--- a/ShiftOS_TheReturn/CrashHandler.cs
+++ b/ShiftOS_TheReturn/CrashHandler.cs
@@ -41,38 +41,41 @@ namespace ShiftOS.Engine
{
public class GetHardwareInfo
{
+ // returns the processor's name for the crash
public static string GetProcessorName()
{
- string ProcessorName = "";
+ string ProcessorName = ""; // put the processors name in here sometime later
ManagementObjectSearcher mos
- = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_Processor");
+ = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_Processor"); // OI CPU TELL ME YOUR NAME PLZ
foreach (ManagementObject mo in mos.Get())
- ProcessorName = mo["Name"].ToString();
+ ProcessorName = mo["Name"].ToString(); // see told you it puts in it there
return ProcessorName;
}
+ // same as above but instead for the gpu's name for the crash as well
public static string GetGPUName()
{
string GPUName = "";
ManagementObjectSearcher mos
- = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_VideoController");
+ = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_VideoController"); //now can you tell me your name cpu kthx
foreach (ManagementObject mo in mos.Get())
GPUName = mo["Name"].ToString();
return GPUName;
}
+ // oh wow even more same, but this time its RAM AMOUNT oooh nice
public static string GetRAMAmount()
{
var RAMAmount = "";
ManagementObjectSearcher mos
- = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PhysicalMemory");
+ = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PhysicalMemory"); //ram you too how much of you exists
foreach (ManagementObject mo in mos.Get())
RAMAmount = mo["Capacity"].ToString();
- RAMAmount = (RAMAmount + " B");
+ RAMAmount = (RAMAmount + " B"); // ooh and now we add "bytes" to the end
return RAMAmount;
}
@@ -81,22 +84,24 @@ namespace ShiftOS.Engine
public partial class CrashHandler : Form
{
+ //fuck it crashed
public CrashHandler()
{
InitializeComponent();
- //Send the bug to Debugle
- // or alternatively, send to [email protected] OR [email protected]
+ //Send the bug to Unite as a bug report
+ // or alternatively, send to [email protected]
+ // or just on the discord that works too
}
- public static Exception HandledException = null;
+ public static Exception HandledException = null; // this value determines if we can try to set the game back on track or we cant do anything about it
public static void Start(Exception e)
{
if(SaveSystem.CurrentSave != null)
- TerminalBackend.InvokeCommand("sos.save");
+ TerminalBackend.InvokeCommand("sos.save"); // SAVE BEFORE CRASHING
ServerManager.Disconnect();
while (Application.OpenForms.Count > 0)
@@ -108,6 +113,7 @@ namespace ShiftOS.Engine
System.IO.FileInfo fileInfo = new System.IO.FileInfo(assembly.Location);
DateTime lastModified = fileInfo.LastWriteTime;
+ // put all this in a text document
string rtbcrash_Text = $@" === {AssemblyName} has crashed. ===
Game: {AssemblyName}
@@ -179,11 +185,11 @@ Stack trace:
}
- File.WriteAllText("crash.txt", rtbcrash_Text);
+ File.WriteAllText("crash.txt", rtbcrash_Text); // make that text document and put above super long string in it
var result = MessageBox.Show(caption: "ShiftOS - Fatal error", text: "ShiftOS has encountered a fatal error and has been shut down. Info about the error has been saved to a file called crash.txt in the same folder as the active executable. Would you like to try and recover the game session?", buttons: MessageBoxButtons.YesNo);
if(result == DialogResult.Yes)
{
- Application.Restart();
+ Application.Restart(); // tries to restart if user clicks yes, who wouldve guessed
}
}
@@ -197,18 +203,20 @@ Stack trace:
this.Close();
Application.Restart();
}
-
+
+ // make both of those variables that appear in the long string above
public static string AssemblyName { get; private set; }
public static string AssemblyDescription { get; private set; }
+ // get info about the game itself
public static void SetGameMetadata(Assembly assembly)
{
- AssemblyName = assembly.GetName().Name;
+ AssemblyName = assembly.GetName().Name; // name of game
foreach(var attr in assembly.GetCustomAttributes(true))
{
if(attr is AssemblyDescriptionAttribute)
{
- AssemblyDescription = (attr as AssemblyDescriptionAttribute).Description;
+ AssemblyDescription = (attr as AssemblyDescriptionAttribute).Description; // description of the game
}
}
diff --git a/ShiftOS_TheReturn/Desktop.cs b/ShiftOS_TheReturn/Desktop.cs
index bc17a8e..a5e7f43 100644
--- a/ShiftOS_TheReturn/Desktop.cs
+++ b/ShiftOS_TheReturn/Desktop.cs
@@ -102,7 +102,14 @@ namespace ShiftOS.Engine
/// Gets the name of the desktop.
/// </summary>
string DesktopName { get; }
-
+
+ /// <summary>
+ /// Show a notification on the desktop.
+ /// </summary>
+ /// <param name="app">An application ID (for determining what system icon to show the notification alongside)</param>
+ /// <param name="title">The title of the notification.</param>
+ /// <param name="message">Isn't this.... self explanatory?</param>
+ void PushNotification(string app, string title, string message);
/// <summary>
/// Performs most of the skinning and layout handling for the desktop.
@@ -266,6 +273,14 @@ namespace ShiftOS.Engine
{
_desktop.HideAppLauncher();
}
+
+ public static void PushNotification(string app, string title, string msg)
+ {
+ InvokeOnWorkerThread(() =>
+ {
+ _desktop.PushNotification(app, title, msg);
+ });
+ }
}
// sorry i almost killed everything :P
}
diff --git a/ShiftOS_TheReturn/IStatusIcon.cs b/ShiftOS_TheReturn/IStatusIcon.cs
new file mode 100644
index 0000000..f32d1c1
--- /dev/null
+++ b/ShiftOS_TheReturn/IStatusIcon.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ShiftOS.Engine
+{
+ public interface IStatusIcon
+ {
+ void Setup();
+
+ }
+}
diff --git a/ShiftOS_TheReturn/KernelWatchdog.cs b/ShiftOS_TheReturn/KernelWatchdog.cs
index 430d36a..0608c46 100644
--- a/ShiftOS_TheReturn/KernelWatchdog.cs
+++ b/ShiftOS_TheReturn/KernelWatchdog.cs
@@ -10,6 +10,7 @@ namespace ShiftOS.Engine
{
public static class KernelWatchdog
{
+ //store logs into a file
public static void Log(string e, string desc)
{
string line = $"[{DateTime.Now}] <{e}> {desc}";
@@ -36,12 +37,13 @@ namespace ShiftOS.Engine
}
set
{
- if(value == false)
+ if(value == false) // hey game if you want to disconnect from mud do this:
{
foreach(var win in AppearanceManager.OpenForms)
{
foreach(var attr in win.ParentWindow.GetType().GetCustomAttributes(true))
{
+ // prevents disconnect from mud if an application that needs a connection is open
if(attr is MultiplayerOnlyAttribute)
{
ConsoleEx.Bold = true;
@@ -59,63 +61,44 @@ namespace ShiftOS.Engine
}
}
- _mudConnected = value;
+ _mudConnected = value; // connects or disconnects from mud
Desktop.PopulateAppLauncher();
}
}
- public static bool IsSafe(Type type)
+ public static bool IsSafe(TerminalBackend.TerminalCommand cmd)
{
- if (SaveSystem.CurrentUser.Permissions == Objects.UserPermissions.Root)
+ if (!cmd.RequiresElevation)
return true;
-
- foreach (var attrib in type.GetCustomAttributes(false))
+ else
{
- if (attrib is KernelModeAttribute)
- {
- if (SaveSystem.CurrentUser.Permissions == Objects.UserPermissions.Root)
- return true;
+ if (SaveSystem.CurrentUser.Permissions == Objects.UserPermissions.Root)
+ return true;
+ else
return false;
- }
}
- return true;
}
- public static bool IsSafe(MethodInfo type)
- {
- if (SaveSystem.CurrentUser.Permissions == Objects.UserPermissions.Root)
- return true;
-
- foreach (var attrib in type.GetCustomAttributes(false))
- {
- if (attrib is KernelModeAttribute)
- {
- if (SaveSystem.CurrentUser.Permissions == Objects.UserPermissions.Root)
- return true;
- return false;
- }
- }
- return true;
- }
- static string regularUsername = "";
+ static string regularUsername = ""; //put regular username in here later
public static void EnterKernelMode()
{
- regularUsername = SaveSystem.CurrentUser.Username;
- SaveSystem.CurrentUser = SaveSystem.Users.FirstOrDefault(x => x.Username == "root");
+ regularUsername = SaveSystem.CurrentUser.Username; // k for now put user's username in here for the time being
+ SaveSystem.CurrentUser = SaveSystem.Users.FirstOrDefault(x => x.Username == "root"); // now their username is root
}
public static void LeaveKernelMode()
{
- var user = SaveSystem.Users.FirstOrDefault(x => x.Username == regularUsername);
- if (user == null)
- throw new Exception("User not in root mode.");
+ var user = SaveSystem.Users.FirstOrDefault(x => x.Username == regularUsername); //finds username
+ if (user == null)
+ throw new Exception("User not in root mode."); // fuck this means the user isnt root quick throw error
SaveSystem.CurrentUser = user;
}
+ //determines if you can disconnect from mud if there are no applications that currently need to
internal static bool CanRunOffline(Type method)
{
if (MudConnected)
@@ -128,7 +111,8 @@ namespace ShiftOS.Engine
}
return true;
}
-
+
+ //same as above but this time for methods
internal static bool CanRunOffline(MethodInfo method)
{
if (MudConnected)
diff --git a/ShiftOS_TheReturn/Localization.cs b/ShiftOS_TheReturn/Localization.cs
index c1a6bd6..8adfa5a 100644
--- a/ShiftOS_TheReturn/Localization.cs
+++ b/ShiftOS_TheReturn/Localization.cs
@@ -33,6 +33,7 @@ using System.Threading.Tasks;
namespace ShiftOS.Engine
{
+ //define a whole bunch of things that are needed
public interface ILanguageProvider
{
List<string> GetJSONTranscripts();
@@ -51,14 +52,15 @@ namespace ShiftOS.Engine
{
if(_provider == null)
{
- return JsonConvert.DeserializeObject<string[]>(Properties.Resources.languages);
+ return JsonConvert.DeserializeObject<string[]>(Properties.Resources.languages); //collect all the languages availible
}
else
{
- return _provider.GetAllLanguages();
+ return _provider.GetAllLanguages(); //also collect all the languages avalible but from a specific provider this time
}
}
+ //if no local selected, english will be loaded
public static void SetupTHETRUEDefaultLocals()
{
if (_provider == null)
@@ -79,6 +81,7 @@ namespace ShiftOS.Engine
}
}
+ // ignore this not really setup of default no no zone
public static void SetupDefaultLocals(string lines, string path)
{
Utils.WriteAllText(Paths.GetPath(path), lines);
@@ -86,13 +89,8 @@ namespace ShiftOS.Engine
}
- /// <summary>
- /// Takes in a string and parses localization blocks into text blocks in the current language.
- /// </summary>
- /// <example>"{CODEPOINTS}: 0" will come out as "Codepoints: 0" if the current language is english.</example>
- /// <param name="original">The string to parse</param>
- /// <returns>The parsed string.</returns>
- ///
+ // Takes in a string and parses localization blocks into text blocks in the current language.
+ // example: "{CODEPOINTS}: 0" will come out as "Codepoints: 0" if the current language is english
public static string Parse(string original)
{
return Parse(original, new Dictionary<string, string>());
@@ -104,103 +102,85 @@ namespace ShiftOS.Engine
Dictionary<string, string> localizationStrings = new Dictionary<string, string>();
-
try
{
localizationStrings = JsonConvert.DeserializeObject<Dictionary<string, string>>(_provider.GetCurrentTranscript());
}
catch
{
- localizationStrings = JsonConvert.DeserializeObject<Dictionary<string, string>>(Utils.ReadAllText(Paths.GetPath("english.local")));
- }
-
- foreach (var kv in localizationStrings)
- {
- original = original.Replace(kv.Key, kv.Value);
+ localizationStrings = JsonConvert.DeserializeObject<Dictionary<string, string>>(Utils.ReadAllText(Paths.GetPath("english.local"))); //if no provider fall back to english
}
- List<string> orphaned = new List<string>();
- if (Utils.FileExists("0:/dev_orphaned_lang.txt"))
+ foreach (var kv in localizationStrings.Where(x=>original.Contains(x.Key)))
{
- orphaned = JsonConvert.DeserializeObject<List<string>>(Utils.ReadAllText("0:/dev_orphaned_lang.txt"));
+ original = original.Replace(kv.Key, kv.Value); // goes through and replaces all the localization blocks
}
+ //string original2 = Parse(original);
- int start_index = 0;
- int length = 0;
- bool indexing = false;
+ string usernameReplace = "";
+ string domainReplace = "";
- foreach (var c in original)
+ // if the user has saved then store their username and systemname in these string variables please
+ if (SaveSystem.CurrentSave != null)
{
- if (c == '{')
+ try
{
- start_index = original.IndexOf(c);
- indexing = true;
+ usernameReplace = SaveSystem.CurrentUser.Username;
}
-
- if (indexing == true)
+ catch
{
- length++;
- if (c == '}')
- {
- indexing = false;
- string o = original.Substring(start_index, length);
- if (!orphaned.Contains(o))
- {
- orphaned.Add(o);
- }
- start_index = 0;
- length = 0;
- }
+ usernameReplace = "user";
}
- }
-
- if (orphaned.Count > 0)
- {
- Utils.WriteAllText("0:/dev_orphaned_lang.txt", JsonConvert.SerializeObject(orphaned, Formatting.Indented));
- }
-
- //string original2 = Parse(original);
-
- string usernameReplace = "";
- string domainReplace = "";
- if (SaveSystem.CurrentSave != null)
- {
- usernameReplace = SaveSystem.CurrentSave.Username;
- domainReplace = SaveSystem.CurrentSave.SystemName;
+ try
+ {
+ domainReplace = SaveSystem.CurrentSave.SystemName;
+ }
+ catch
+ {
+ domainReplace = "system";
+ }
+
}
string namespaceReplace = "";
string commandReplace = "";
+ // if the user did a command in the terminal and it had a period in it then split it up into the part before the period and the part after and then store them into these two string variables please
if (TerminalBackend.latestCommmand != "" && TerminalBackend.latestCommmand.IndexOf('.') > -1)
{
namespaceReplace = TerminalBackend.latestCommmand.Split('.')[0];
commandReplace = TerminalBackend.latestCommmand.Split('.')[1];
}
+ // if you see these then replace them with what you need to
Dictionary<string, string> defaultReplace = new Dictionary<string, string>() {
{"%username", usernameReplace},
{"%domain", domainReplace},
{"%ns", namespaceReplace},
{"%cmd", commandReplace},
- {"%cp", SaveSystem.CurrentSave?.Codepoints.ToString() },
+#if LOCALIZE_CODEPOINTS
+ { "%cp", SaveSystem.CurrentSave?.Codepoints.ToString() },
+#endif
};
- foreach (KeyValuePair<string, string> replacement in replace)
+ // actually do the replacement
+ foreach (KeyValuePair<string, string> replacement in replace.Where(x => original.Contains(x.Key)))
{
original = original.Replace(replacement.Key, Parse(replacement.Value));
}
- foreach (KeyValuePair<string, string> replacement in defaultReplace)
+ // do the replacement but default
+ foreach (KeyValuePair<string, string> replacement in defaultReplace.Where(x => original.Contains(x.Key)))
{
original = original.Replace(replacement.Key, replacement.Value);
}
- return original;
+ return original; // returns the now replaced string
}
+ // a few things are defined here
public static void RegisterProvider(ILanguageProvider p)
{
_provider = p;
diff --git a/ShiftOS_TheReturn/LoginManager.cs b/ShiftOS_TheReturn/LoginManager.cs
new file mode 100644
index 0000000..d326f2c
--- /dev/null
+++ b/ShiftOS_TheReturn/LoginManager.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using ShiftOS.Objects;
+
+namespace ShiftOS.Engine
+{
+ public static class LoginManager
+ {
+ private static ILoginFrontend _login = null;
+
+ public static void Init(ILoginFrontend login)
+ {
+ _login = login;
+ }
+
+ public static void PromptForLogin()
+ {
+ _login.LoginComplete += (user) =>
+ {
+ LoginComplete?.Invoke(user);
+ };
+ _login.Login();
+ }
+
+ public static bool ShouldUseGUILogin
+ {
+ get
+ {
+ if (_login == null)
+ return false;
+ return _login.UseGUILogin;
+ }
+ }
+
+ public static event Action<ClientSave> LoginComplete;
+ }
+
+ /// <summary>
+ /// Interface for GUI-based logins.
+ /// </summary>
+ public interface ILoginFrontend
+ {
+ /// <summary>
+ /// When implemented, shows the login UI.
+ /// </summary>
+ void Login();
+
+ /// <summary>
+ /// Gets whether the ShiftOS engine should use a GUI-based login system or the default one.
+ /// </summary>
+ bool UseGUILogin { get; }
+
+
+ /// <summary>
+ /// Occurs when the login is complete.
+ /// </summary>
+ event Action<ClientSave> LoginComplete;
+
+
+
+ }
+}
diff --git a/ShiftOS_TheReturn/NotificationDaemon.cs b/ShiftOS_TheReturn/NotificationDaemon.cs
index 77a31fc..0725782 100644
--- a/ShiftOS_TheReturn/NotificationDaemon.cs
+++ b/ShiftOS_TheReturn/NotificationDaemon.cs
@@ -25,6 +25,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
@@ -34,6 +35,36 @@ namespace ShiftOS.Engine
{
public static class NotificationDaemon
{
+ /// <summary>
+ /// Gets a list of all <see cref="IStatusIcon"/> objects that meet their Shiftorium dependencies.
+ /// </summary>
+ /// <returns>An array of <see cref="Type"/>s containing the found objects.</returns>
+ public static Type[] GetAllStatusIcons()
+ {
+ List<Type> lst = new List<Type>();
+ foreach(var exec in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
+ {
+ if(exec.ToLower().EndsWith(".exe") || exec.ToLower().EndsWith(".dll"))
+ {
+ try
+ {
+ var asm = Assembly.LoadFile(exec);
+ foreach(var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IStatusIcon))))
+ {
+ if (Shiftorium.UpgradeAttributesUnlocked(type))
+ {
+ lst.Add(type);
+ }
+ }
+ }
+ catch { }
+ }
+ }
+ return lst.ToArray();
+ }
+
+
+ //if the notifications file already exists then get them
public static Notification[] GetAllFromFile()
{
Notification[] notes = { };
@@ -44,23 +75,25 @@ namespace ShiftOS.Engine
return notes;
}
+ //tells the computer how it likes it to be written in the file
internal static void WriteNotes(Notification[] notes)
{
- Utils.WriteAllText(Paths.GetPath("notifications.dat"), JsonConvert.SerializeObject(notes, Formatting.Indented));
+ Utils.WriteAllText(Paths.GetPath("notifications.dat"), JsonConvert.SerializeObject(notes, Formatting.Indented)); //"write it in there indented pls"
}
- public static event Action<Notification> NotificationMade;
-
+ public static event Action<Notification> NotificationMade; //use this if you want to know when a notification has been made
+
public static void AddNotification(NotificationType note, object data)
{
- var lst = new List<Notification>(GetAllFromFile());
- lst.Add(new Engine.Notification(note, data));
+ var lst = new List<Notification>(GetAllFromFile()); //grabs all current notifications
+ lst.Add(new Engine.Notification(note, data)); //then adds the new one to the list
WriteNotes(lst.ToArray());
- NotificationMade?.Invoke(lst[lst.Count - 1]);
+ NotificationMade?.Invoke(lst[lst.Count - 1]); //says to the program that a notification has indeed been made
}
public static event Action NotificationRead;
+ //for every notification that there is, mark them as read
public static void MarkAllRead()
{
var notes = GetAllFromFile();
@@ -68,30 +101,33 @@ namespace ShiftOS.Engine
MarkRead(i);
}
+ //grabs list of notifcations and if the notification you want to mark as read actually exsists, then it assigns it as read
public static void MarkRead(int note)
{
var notes = GetAllFromFile();
if (note >= notes.Length || note < 0)
throw new ArgumentOutOfRangeException("note", new Exception("You cannot mark a notification that does not exist as read."));
- notes[note].Read = true;
+ notes[note].Read = true; //assigns the specific notification as read
WriteNotes(notes);
NotificationRead?.Invoke();
}
- public static int GetUnreadCount()
+ public static int GetUnreadCount() //use this if you want the unread notification count, but i think you probably already knew that
{
int c = 0;
foreach (var note in GetAllFromFile())
if (note.Read == false)
- c++; //gahh I hate that programming language.
+ c++; //gahh I hate that programming language. //dont we all
return c;
}
}
+ //actually gives the proper data for the notification
public struct Notification
{
+ //defaults for all notificaions
public Notification(NotificationType t, object data)
{
Type = t;
@@ -106,9 +142,10 @@ namespace ShiftOS.Engine
public DateTime Timestamp { get; set; }
}
+ //defines all the possible notificaions that can happen
public enum NotificationType
{
- Generic = 0x00,
+ Generic = 0x00, //lets get generic
MemoReceived = 0x10,
MemoSent = 0x11,
DownloadStarted = 0x20,
diff --git a/ShiftOS_TheReturn/OutOfBoxExperience.cs b/ShiftOS_TheReturn/OutOfBoxExperience.cs
index 6ed9e49..eb8e61d 100644
--- a/ShiftOS_TheReturn/OutOfBoxExperience.cs
+++ b/ShiftOS_TheReturn/OutOfBoxExperience.cs
@@ -45,17 +45,17 @@ namespace ShiftOS.Engine
public static void Init(IOobe oobe)
{
- _oobe = oobe;
+ _oobe = oobe; // takes the oobe and makes it an IOobe
}
public static void Start(Save save)
{
-
+ //if its null then FUCK YOU DID THE WRONG THING
if (_oobe == null)
throw new InvalidOperationException("OOBE frontend not activated! This function can't be used! Please use OutOfBoxExperience.Init() passing an IOobe-implementing object to start the OOBE frontend.");
- _oobe.StartShowing(save);
+ _oobe.StartShowing(save); //tells the save data to start showing the oobe
}
@@ -64,7 +64,7 @@ namespace ShiftOS.Engine
{
Desktop.InvokeOnWorkerThread(new Action(() =>
{
- _oobe.PromptForLogin();
+ _oobe.PromptForLogin(); //prompts for login, what did you expect
}));
}
@@ -72,12 +72,13 @@ namespace ShiftOS.Engine
{
Desktop.InvokeOnWorkerThread(new Action(() =>
{
- _oobe.ShowSaveTransfer(save);
+ _oobe.ShowSaveTransfer(save); //triggers save transfer if not done already
}));
}
}
+ //triggers all the above events
public interface IOobe
{
void StartShowing(Save save);
diff --git a/ShiftOS_TheReturn/Paths.cs b/ShiftOS_TheReturn/Paths.cs
index 10fd7d7..5b75ae6 100644
--- a/ShiftOS_TheReturn/Paths.cs
+++ b/ShiftOS_TheReturn/Paths.cs
@@ -35,8 +35,14 @@ using System.Threading;
namespace ShiftOS.Engine
{
+ /// <summary>
+ /// Management class for ShiftFS path variables.
+ /// </summary>
public static class Paths
{
+ /// <summary>
+ /// Initiate the path system.
+ /// </summary>
public static void Init()
{
Locations = new Dictionary<string, string>();
@@ -88,6 +94,10 @@ namespace ShiftOS.Engine
}
+ /// <summary>
+ /// Gets all full paths without their keynames.
+ /// </summary>
+ /// <returns>A string array representing all paths.</returns>
public static string[] GetAllWithoutKey()
{
List<string> strings = new List<string>();
@@ -99,11 +109,19 @@ namespace ShiftOS.Engine
}
+ /// <summary>
+ /// Get the full path using a path key.
+ /// </summary>
+ /// <param name="id">The path key (folder/filename) for the path.</param>
+ /// <returns>The full path.</returns>
public static string GetPath(string id)
{
return Locations[id];
}
+ /// <summary>
+ /// Checks all directories in the path system to see if they exist, and if not, creates them.
+ /// </summary>
private static void CheckPathExistence()
{
foreach(var path in Locations)
@@ -119,8 +137,14 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Gets or sets a <see cref="Dictionary{string, string}"/> representing all paths in the system.
+ /// </summary>
private static Dictionary<string, string> Locations { get; set; }
+ /// <summary>
+ /// Mounts the ShiftOS shared directory to 1:/, creating the directory if it does not exist.
+ /// </summary>
public static void CreateAndMountSharedFolder()
{
if (!System.IO.Directory.Exists(SharedFolder))
@@ -201,9 +225,7 @@ namespace ShiftOS.Engine
t.Start();
}
-
-
- public static void ScanForDirectories(string folder, int mount)
+ private static void ScanForDirectories(string folder, int mount)
{
foreach (var file in System.IO.Directory.GetFiles(folder))
{
@@ -220,10 +242,27 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Gets the ShiftOS shared folder.
+ /// </summary>
public static string SharedFolder { get { return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\ShiftOS_Shared"; } }
+
+ /// <summary>
+ /// Gets the location of the ShiftOS.mfs file.
+ /// </summary>
public static string SaveFile { get { return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\ShiftOS.mfs"; } }
+
+ /// <summary>
+ /// Gets the path of the inner save file.
+ /// </summary>
+ [Obsolete("Not used.")]
public static string SaveFileInner { get { return Locations["save.json"]; } }
+ /// <summary>
+ /// Add a path to the system.
+ /// </summary>
+ /// <param name="parent">The path's parent directory.</param>
+ /// <param name="path">The filename for the path.</param>
public static void AddPath(string parent, string path)
{
Locations.Add(path, Locations[parent] + "/" + path);
diff --git a/ShiftOS_TheReturn/SaveSystem.cs b/ShiftOS_TheReturn/SaveSystem.cs
index f29e5b8..e98a51e 100644
--- a/ShiftOS_TheReturn/SaveSystem.cs
+++ b/ShiftOS_TheReturn/SaveSystem.cs
@@ -21,6 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+// #define NOSAVE
//#define ONLINEMODE
@@ -39,6 +40,7 @@ using static System.Net.Mime.MediaTypeNames;
namespace ShiftOS.Engine
{
+ [Obsolete("Use the servers.conf file instead.")]
public class EngineConfig
{
public bool ConnectToMud = true;
@@ -46,13 +48,34 @@ namespace ShiftOS.Engine
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>
@@ -98,64 +121,92 @@ namespace ShiftOS.Engine
}
Thread.Sleep(350);
- Console.WriteLine("Initiating kernel...");
+ 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("Reading filesystem...");
+ Console.WriteLine("[init] Kernel boot complete.");
+ Console.WriteLine("[sfs] Loading SFS driver v3");
Thread.Sleep(100);
- Console.WriteLine("Reading configuration...");
+ Console.WriteLine("[sfs] 4096 blocks read.");
+ Console.WriteLine("[simpl-conf] Reading configuration files (global-3.conf)");
+ Console.WriteLine("[termdb] Building command database from filesystem...");
+ TerminalBackend.PopulateTerminalCommands();
+ Console.WriteLine("[inetd] Connecting to network...");
- Console.WriteLine("{CONNECTING_TO_MUD}");
+ Ready = false;
- if (defaultConf.ConnectToMud == true)
+ if (PreDigitalSocietyConnection != null)
{
- bool guidReceived = false;
- ServerManager.GUIDReceived += (str) =>
+ PreDigitalSocietyConnection?.Invoke();
+
+ while (!Ready)
{
+ Thread.Sleep(10);
+ }
+ }
+
+
+
+ bool guidReceived = false;
+ ServerManager.GUIDReceived += (str) =>
+ {
//Connection successful! Stop waiting!
guidReceived = true;
- Console.WriteLine("Connection successful.");
- };
+ Console.WriteLine("[inetd] Connection successful.");
+ };
- try
- {
-
- ServerManager.Initiate("secondary4162.cloudapp.net", 13370);
- //This haults the client until the connection is successful.
- while (ServerManager.thisGuid == new Guid())
- {
- Thread.Sleep(10);
- }
- Console.WriteLine("GUID received - bootstrapping complete.");
- FinishBootstrap();
- }
- catch (Exception ex)
+ try
+ {
+
+ ServerManager.Initiate(UserConfig.Get().DigitalSocietyAddress, UserConfig.Get().DigitalSocietyPort);
+ //This haults the client until the connection is successful.
+ while (ServerManager.thisGuid == new Guid())
{
- //No errors, this never gets called.
- Console.WriteLine("{ERROR}: " + ex.Message);
- Thread.Sleep(3000);
- ServerManager.StartLANServer();
- while (ServerManager.thisGuid == new Guid())
- {
- Thread.Sleep(10);
- }
- Console.WriteLine("GUID received - bootstrapping complete.");
- FinishBootstrap();
+ Thread.Sleep(10);
}
+ Console.WriteLine("[inetd] DHCP GUID recieved, finished setup");
+ FinishBootstrap();
}
- else
+ catch (Exception ex)
{
- ServerManager.StartLANServer();
+ //No errors, this never gets called.
+ Console.WriteLine("[inetd] SEVERE: " + ex.Message);
+ Thread.Sleep(3000);
+ Console.WriteLine("[sys] SEVERE: Cannot connect to server. Shutting down in 5...");
+ Thread.Sleep(1000);
+ Console.WriteLine("[sys] 4...");
+ Thread.Sleep(1000);
+ Console.WriteLine("[sys] 3...");
+ Thread.Sleep(1000);
+ Console.WriteLine("[sys] 2...");
+ Thread.Sleep(1000);
+ Console.WriteLine("[sys] 1...");
+ Thread.Sleep(1000);
+ Console.WriteLine("[sys] Bye bye.");
+ System.Diagnostics.Process.GetCurrentProcess().Kill();
}
//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();
}
- public static void FinishBootstrap()
+ /// <summary>
+ /// Finish bootstrapping the engine.
+ /// </summary>
+ private static void FinishBootstrap()
{
KernelWatchdog.Log("mud_handshake", "handshake successful: kernel watchdog access code is \"" + ServerManager.thisGuid.ToString() + "\"");
@@ -165,13 +216,21 @@ namespace ShiftOS.Engine
{
if (msg.Name == "mud_savefile")
{
- CurrentSave = JsonConvert.DeserializeObject<Save>(msg.Contents);
ServerManager.MessageReceived -= savehandshake;
- }
+ try
+ {
+ CurrentSave = JsonConvert.DeserializeObject<Save>(msg.Contents);
+ }
+ catch
+ {
+ Console.WriteLine("[system] [SEVERE] Cannot parse configuration file.");
+ oobe.PromptForLogin();
+ }
+ }
else if (msg.Name == "mud_login_denied")
{
- oobe.PromptForLogin();
ServerManager.MessageReceived -= savehandshake;
+ oobe.PromptForLogin();
}
};
ServerManager.MessageReceived += savehandshake;
@@ -196,7 +255,7 @@ namespace ShiftOS.Engine
Thread.Sleep(75);
Thread.Sleep(50);
- Console.WriteLine("{SYSTEM_INITIATED}");
+ Console.WriteLine("[usr-man] Accepting logins on local tty 1.");
Sysname:
bool waitingForNewSysName = false;
@@ -204,7 +263,7 @@ namespace ShiftOS.Engine
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)=>
+ 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.", () =>
@@ -248,8 +307,34 @@ namespace ShiftOS.Engine
if (CurrentSave.Users == null)
CurrentSave.Users = new List<ClientSave>();
-
- if(CurrentSave.Users.Count == 0)
+ Console.WriteLine($@"
+ `-:/++++::.`
+ .+ydNMMMMMNNMMMMMNhs/.
+ /yNMMmy+:-` `````.-/ohNMMms-
+ `oNMMh/.`:oydmNMMMMNmhs+- .+dMMm+` Welcome to ShiftOS.
+ `oMMmo``+dMMMMMMMMMMMMMMMMMNh/`.sNMN+
+ :NMN+ -yMMMMMMMNdhyssyyhdmNMMMMNs``sMMd. SYSTEM STATUS:
+ oMMd.`sMMMMMMd+. `/MMMMN+ -mMN: ----------------------
+ oMMh .mMMMMMM/ `-::::-.` :MMMMMMh`.mMM:
+ :MMd .NMMMMMMs .dMMMMMMMMMNddMMMMMMMd`.NMN. Codepoints: {SaveSystem.CurrentSave.Codepoints}
+ mMM. dMMMMMMMo -mMMMMMMMMMMMMMMMMMMMMs /MMy Upgrades: {SaveSystem.CurrentSave.CountUpgrades()} installed
+ :MMh :MMMMMMMMm` .+shmMMMMMMMMMMMMMMMN` NMN` {Shiftorium.GetAvailable().Count()} available
+ oMM+ sMMMMMMMMMN+` `-/smMMMMMMMMMMM: hMM: Filesystems: {Utils.Mounts.Count} filesystems mounted in memory.
+ sMM+ sMMMMMMMMMMMMds/-` .sMMMMMMMMM/ yMM/
+ +MMs +MMMMMMMMMMMMMMMMMmhs:` +MMMMMMMM- dMM- System name: {CurrentSave.SystemName.ToUpper()}
+ .MMm `NMMMMMMMMMMMMMMMMMMMMMo `NMMMMMMd .MMN Users: {Users.Count()} found.
+ hMM+ +MMMMMMmsdNMMMMMMMMMMN/ -MMMMMMN- yMM+
+ `NMN- oMMMMMd `-/+osso+- .mMMMMMN: +MMd
+ -NMN: /NMMMm` :yMMMMMMm- oMMd`
+ -mMMs``sMMMMNdhso++///+oydNMMMMMMNo .hMMh`
+ `yMMm/ .omMMMMMMMMMMMMMMMMMMMMd+``oNMNo
+ -hMMNo. -ohNMMMMMMMMMMMMmy+. -yNMNy`
+ .sNMMms/. `-/+++++/:-` ./yNMMmo`
+ :sdMMMNdyso+++ooshdNMMMdo-
+ `:+yhmNNMMMMNNdhs+-
+ ```` ");
+
+ if (CurrentSave.Users.Count == 0)
{
CurrentSave.Users.Add(new ClientSave
{
@@ -257,76 +342,107 @@ namespace ShiftOS.Engine
Password = "",
Permissions = UserPermissions.Root
});
- Console.WriteLine("No users found. Creating new user with username \"root\", with no password.");
+ Console.WriteLine("[usr-man] WARN: No users found. Creating new user with username \"root\", with no password.");
}
TerminalBackend.InStory = false;
TerminalBackend.PrefixEnabled = false;
- Login:
- string username = "";
- int progress = 0;
- bool goback = false;
- TextSentEventHandler ev = null;
- ev = (text) =>
+ 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
{
- if (progress == 0)
+
+ Login:
+ string username = "";
+ int progress = 0;
+ bool goback = false;
+ TextSentEventHandler ev = null;
+ ev = (text) =>
{
- if (!string.IsNullOrWhiteSpace(text))
+ if (progress == 0)
{
- if (CurrentSave.Users.FirstOrDefault(x => x.Username == text) == null)
+ string loginstr = CurrentSave.SystemName + " login: ";
+ string getuser = text.Remove(0, loginstr.Length);
+ if (!string.IsNullOrWhiteSpace(getuser))
{
- Console.WriteLine("User not found.");
- goback = true;
+ if (CurrentSave.Users.FirstOrDefault(x => x.Username == getuser) == null)
+ {
+ Console.WriteLine();
+ Console.WriteLine("User not found.");
+ goback = true;
+ progress++;
+ TerminalBackend.TextSent -= ev;
+ return;
+ }
+ username = getuser;
progress++;
+ }
+ else
+ {
+ Console.WriteLine();
+ Console.WriteLine("Username not provided.");
TerminalBackend.TextSent -= ev;
- return;
+ goback = true;
+ progress++;
}
- username = text;
- progress++;
}
- else
+ else if (progress == 1)
{
- Console.WriteLine("Username not provided.");
+ 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();
+ Console.WriteLine("Welcome to ShiftOS.");
+ CurrentUser = user;
+ progress++;
+ }
+ else
+ {
+ Console.WriteLine();
+ Console.WriteLine("Access denied.");
+ goback = true;
+ progress++;
+ }
TerminalBackend.TextSent -= ev;
- goback = true;
- progress++;
}
- }
- else if (progress == 1)
+ };
+ TerminalBackend.TextSent += ev;
+ Console.WriteLine();
+ Console.Write(CurrentSave.SystemName + " login: ");
+ ConsoleEx.Flush();
+ while (progress == 0)
{
- var user = CurrentSave.Users.FirstOrDefault(x => x.Username == username);
- if (user.Password == text)
- {
- Console.WriteLine("Welcome to ShiftOS.");
- CurrentUser = user;
- Thread.Sleep(2000);
- progress++;
- }
- else
- {
- Console.WriteLine("Access denied.");
- goback = true;
- progress++;
- }
- TerminalBackend.TextSent -= ev;
+ Thread.Sleep(10);
}
- };
- TerminalBackend.TextSent += ev;
- Console.WriteLine(CurrentSave.SystemName + " login:");
- while(progress == 0)
- {
- Thread.Sleep(10);
+ if (goback)
+ goto Login;
+ Console.WriteLine();
+ Console.Write("password: ");
+ ConsoleEx.Flush();
+ while (progress == 1)
+ Thread.Sleep(10);
+ if (goback)
+ goto Login;
}
- if (goback)
- goto Login;
- Console.WriteLine("password:");
- while (progress == 1)
- Thread.Sleep(10);
- if (goback)
- goto Login;
-
-
TerminalBackend.PrefixEnabled = true;
Shiftorium.LogOrphanedUpgrades = true;
Desktop.InvokeOnWorkerThread(new Action(() =>
@@ -337,10 +453,26 @@ namespace ShiftOS.Engine
Desktop.InvokeOnWorkerThread(new Action(() => Desktop.PopulateAppLauncher()));
GameReady?.Invoke();
+
+ if (!string.IsNullOrWhiteSpace(CurrentSave.PickupPoint))
+ {
+ try
+ {
+ Story.Start(CurrentSave.PickupPoint);
+ TerminalBackend.PrintPrompt();
+ }
+ catch { }
+ }
}
+ /// <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
@@ -349,20 +481,35 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Occurs when the engine is loaded and the game can take over.
+ /// </summary>
public static event EmptyEventHandler GameReady;
- public static void TransferCodepointsToVoid(long amount)
+ /// <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(ulong 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.
@@ -406,6 +553,9 @@ namespace ShiftOS.Engine
}
+ /// <summary>
+ /// Creates a new save, starting the Out Of Box Experience (OOBE).
+ /// </summary>
public static void NewSave()
{
AppearanceManager.Invoke(new Action(() =>
@@ -418,31 +568,57 @@ namespace ShiftOS.Engine
}));
}
+ /// <summary>
+ /// Saves the game to the server, updating website stats if possible.
+ /// </summary>
public static void SaveGame()
{
+#if !NOSAVE
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));
+ Utils.WriteAllText(Paths.GetPath("user.dat"), CurrentSave.UniteAuthToken);
+ var serialisedSaveFile = JsonConvert.SerializeObject(CurrentSave, Formatting.Indented);
+ new Thread(() =>
+ {
+ // please don't do networking on the main thread if you're just going to
+ // discard the response, it's extremely slow
+ ServerManager.SendMessage("mud_save", serialisedSaveFile);
+ })
+ { IsBackground = false }.Start();
}
if (!Shiftorium.Silent)
Console.WriteLine(" ...{DONE}.");
System.IO.File.WriteAllText(Paths.SaveFile, Utils.ExportMount(0));
+#endif
}
- public static void TransferCodepointsFrom(string who, long amount)
+ /// <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, ulong 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
{
diff --git a/ShiftOS_TheReturn/Scripting.cs b/ShiftOS_TheReturn/Scripting.cs
index d96bc98..5021f50 100644
--- a/ShiftOS_TheReturn/Scripting.cs
+++ b/ShiftOS_TheReturn/Scripting.cs
@@ -38,31 +38,65 @@ using System.Net;
namespace ShiftOS.Engine.Scripting
{
+ /// <summary>
+ /// Brings some C# goodies to the Lua system.
+ /// </summary>
[Exposed("strutils")]
public class StringUtils
{
+ /// <summary>
+ /// Checks if a string ends with a specified string.
+ /// </summary>
+ /// <param name="operand">The string to operate on</param>
+ /// <param name="value">The string to check for</param>
+ /// <returns>Whether <paramref name="operand"/> ends with <paramref name="value"/>.</returns>
public bool endswith(string operand, string value)
{
return operand.EndsWith(value);
}
+
+ /// <summary>
+ /// Checks if a string starts with a specified string.
+ /// </summary>
+ /// <param name="operand">The string to operate on</param>
+ /// <param name="value">The string to check for</param>
+ /// <returns>Whether <paramref name="operand"/> starts with <paramref name="value"/>.</returns>
public bool startswith(string operand, string value)
{
return operand.StartsWith(value);
}
+ /// <summary>
+ /// Checks if a string contains a specified string.
+ /// </summary>
+ /// <param name="operand">The string to operate on</param>
+ /// <param name="value">The string to check for</param>
+ /// <returns>Whether <paramref name="operand"/> contains <paramref name="value"/>.</returns>
public bool contains(string operand, string value)
{
return operand.Contains(value);
}
}
-
+ /// <summary>
+ /// DynamicLua wrapper for the ShiftOS engine.
+ /// </summary>
public class LuaInterpreter
{
+ /// <summary>
+ /// The DynamicLua backend.
+ /// </summary>
public dynamic Lua = new DynamicLua.DynamicLua();
+
+ /// <summary>
+ /// Boolean representing whether the script is running.
+ /// </summary>
public bool Running = true;
+ /// <summary>
+ /// Static constructor for the <see cref="LuaInterpreter"/> class.
+ /// </summary>
static LuaInterpreter()
{
ServerManager.MessageReceived += (msg) =>
@@ -83,12 +117,21 @@ namespace ShiftOS.Engine.Scripting
};
}
+ /// <summary>
+ /// Create a .SFT representation of a Lua script.
+ /// </summary>
+ /// <param name="lua">The Lua code to convert</param>
+ /// <returns>Base64 SFT representation.</returns>
public static string CreateSft(string lua)
{
byte[] bytes = Encoding.UTF8.GetBytes(lua);
return Convert.ToBase64String(bytes);
}
+ /// <summary>
+ /// Run a compressed .SFT file as a lua script.
+ /// </summary>
+ /// <param name="sft">The .sft file to run.</param>
public static void RunSft(string sft)
{
if (Utils.FileExists(sft))
@@ -108,8 +151,14 @@ namespace ShiftOS.Engine.Scripting
}
}
+ /// <summary>
+ /// Get the current working directory of the script.
+ /// </summary>
public static string CurrentDirectory { get; private set; }
+ /// <summary>
+ /// Creates a new instance of the <see cref="LuaInterpreter"/> class.
+ /// </summary>
public LuaInterpreter()
{
Lua(@"function totable(clrlist)
@@ -128,6 +177,9 @@ end");
};
}
+ /// <summary>
+ /// Scans the engine, frontend, and all mods for Lua-exposed classes and functions.
+ /// </summary>
public void SetupAPIs()
{
Lua.currentdir = (string.IsNullOrWhiteSpace(CurrentDirectory)) ? "0:" : CurrentDirectory;
@@ -233,7 +285,10 @@ end");
});
}
-
+ /// <summary>
+ /// Executes the specified file as an uncompressed Lua script.
+ /// </summary>
+ /// <param name="file">The file to execute.</param>
public void ExecuteFile(string file)
{
if (Utils.FileExists(file))
@@ -247,13 +302,17 @@ end");
}
}
+ /// <summary>
+ /// Executes the specified string as a Lua script.
+ /// </summary>
+ /// <param name="lua">The Lua code to execute.</param>
public void Execute(string lua)
{
try
{
Console.WriteLine("");
Lua(lua);
- Console.WriteLine($"{SaveSystem.CurrentSave.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ");
+ Console.WriteLine($"{SaveSystem.CurrentUser.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ");
}
catch (Exception e)
{
@@ -279,24 +338,46 @@ end");
}
}
+ /// <summary>
+ /// Lua functions for .sft files.
+ /// </summary>
[Exposed("sft")]
public class SFTFunctions
{
+ /// <summary>
+ /// Make a .sft file from a lua code string
+ /// </summary>
+ /// <param name="lua">The Lua code</param>
+ /// <returns>The resulting .sft string</returns>
public string make(string lua)
{
return LuaInterpreter.CreateSft(lua);
}
+ /// <summary>
+ /// Make a .sft string and save to a specified file.
+ /// </summary>
+ /// <param name="lua">The Lua code to compress</param>
+ /// <param name="outpath">The path to save the compressed .sft file to.</param>
public void makefile(string lua, string outpath)
{
Utils.WriteAllText(outpath, make(lua));
}
+ /// <summary>
+ /// Run a compressed .sft file in the <see cref="LuaInterpreter"/>.
+ /// </summary>
+ /// <param name="inpath">The .sft file to run.</param>
public void run(string inpath)
{
LuaInterpreter.RunSft(inpath);
}
+ /// <summary>
+ /// Reads the specified .sft file and decompresses to it's Lua form.
+ /// </summary>
+ /// <param name="sft">The .sft file to uncompress</param>
+ /// <returns>The resulting Lua code.</returns>
public string unmake(string sft)
{
if (Utils.FileExists(sft))
@@ -310,9 +391,17 @@ end");
}
}
+ /// <summary>
+ /// Network functions for Lua.
+ /// </summary>
[Exposed("net")]
public class NetFunctions
{
+ /// <summary>
+ /// Submit a GET request to the specified URL.
+ /// </summary>
+ /// <param name="url">The URL to open</param>
+ /// <returns>The result from the server</returns>
public string get(string url)
{
return new WebClient().DownloadString(url);
@@ -320,26 +409,48 @@ end");
}
+ /// <summary>
+ /// Console functions for Lua.
+ /// </summary>
[Exposed("console")]
public class ConsoleFunctions
{
+ /// <summary>
+ /// Write text to the console.
+ /// </summary>
+ /// <param name="text">The text to write.</param>
public void write(dynamic text)
{
Console.Write(text.ToString());
}
+ /// <summary>
+ /// Write text to the console, followed by a new line.
+ /// </summary>
+ /// <param name="text">The text to write.</param>
public void writeLine(dynamic text)
{
Console.WriteLine(text.ToString());
}
}
+ /// <summary>
+ /// The main ShiftOS API.
+ /// </summary>
[Exposed("sos")]
public class SystemFunctions
{
- public long getCodepoints() { return SaveSystem.CurrentSave.Codepoints; }
-
+ /// <summary>
+ /// Retrieves the user's Codepoints from the save file.
+ /// </summary>
+ /// <returns>The user's Codepoints.</returns>
+ public ulong getCodepoints() { return SaveSystem.CurrentSave.Codepoints; }
+ /// <summary>
+ /// Run a command in the Terminal.
+ /// </summary>
+ /// <param name="cmd">The command to run, using regular ShiftOS syntax.</param>
+ /// <returns>Whether the command was found and ran.</returns>
public bool runCommand(string cmd)
{
var args = TerminalBackend.GetArgs(ref cmd);
@@ -347,7 +458,11 @@ end");
return TerminalBackend.RunClient(cmd, args);
}
- public void addCodepoints(int cp)
+ /// <summary>
+ /// Adds the specified amount of Codepoints to the save flie.
+ /// </summary>
+ /// <param name="cp">The codepoints to add.</param>
+ public void addCodepoints(uint cp)
{
if (cp > 100 || cp <= 0)
{
@@ -361,128 +476,227 @@ end");
}
}
- [Exposed("mud")]
- public class MUDFunctions
- {
- public void sendDiagnostic(string src, string cat, object val)
- {
- ServerManager.SendMessage("diag_log", $"[{src}] <{cat}>: {val}");
- }
- }
-
+ /// <summary>
+ /// User information API.
+ /// </summary>
[Exposed("userinfo")]
public class UserInfoFunctions
{
+ /// <summary>
+ /// Gets the user name of the currently logged in user.
+ /// </summary>
+ /// <returns>The user's username.</returns>
public string getUsername()
{
- return SaveSystem.CurrentSave.Username;
+ return SaveSystem.CurrentUser.Username;
}
+ /// <summary>
+ /// Retrieves the user's system name.
+ /// </summary>
+ /// <returns>The user's system name.</returns>
public string getSysname()
{
return SaveSystem.CurrentSave.SystemName;
}
+ /// <summary>
+ /// Gets the user's ShiftOS email (username@sysname).
+ /// </summary>
+ /// <returns>The user's email.</returns>
public string getEmail()
{
return getUsername() + "@" + getSysname();
}
}
-
+ /// <summary>
+ /// Infobox API for Lua.
+ /// </summary>
[Exposed("infobox")]
public class InfoboxFunctions
{
+ /// <summary>
+ /// Show a message to the user in an Infobox.
+ /// </summary>
+ /// <param name="title">The title of the Infobox</param>
+ /// <param name="message">The infobox's message</param>
+ /// <param name="callback">A function to run when the user clicks "OK"</param>
public void show(string title, string message, Action callback = null)
{
Infobox.Show(title, message, callback);
}
+ /// <summary>
+ /// Ask a simple yes/no question to the user using an Infobox.
+ /// </summary>
+ /// <param name="title">The title of the Infobox</param>
+ /// <param name="message">The infobox's message</param>
+ /// <param name="callback">A function to run when they choose an option. The boolean argument will be true if the user clicks Yes, and false if they click No.</param>
public void question(string title, string message, Action<bool> callback)
{
Infobox.PromptYesNo(title, message, callback);
}
- public void input(string title, string message, Action<string> callback)
+ /// <summary>
+ /// Prompt the user for text using an Infobox.
+ /// </summary>
+ /// <param name="title">The infobox's title</param>
+ /// <param name="message">The infobox's message</param>
+ /// <param name="callback">A function to run when the user clicks "OK". The string value is the text entered by the user.</param>
+ /// <param name="isPassword">Whether the text box should hide its characters as if it were a password box.</param>
+ public void input(string title, string message, Action<string> callback, bool isPassword = false)
{
- Infobox.PromptText(title, message, callback);
+ Infobox.PromptText(title, message, callback, isPassword);
}
}
+ /// <summary>
+ /// File Skimmer API for Lua.
+ /// </summary>
[Exposed("fileskimmer")]
public class FileSkimmerFunctions
{
+ /// <summary>
+ /// Opens a File Skimmer "Open File" dialog.
+ /// </summary>
+ /// <param name="extensions">Semicolon-separated list of file extensions that the opener should let through the filter.</param>
+ /// <param name="callback">Function to be called when the user chooses a file. The string value is the file's path.</param>
public void openFile(string extensions, Action<string> callback)
{
FileSkimmerBackend.GetFile(extensions.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries), FileOpenerStyle.Open, callback);
}
+ /// <summary>
+ /// Opens a File Skimmer "Save File" dialog.
+ /// </summary>
+ /// <param name="extensions">Semicolon-separated list of file extensions that the opener should let through the filter.</param>
+ /// <param name="callback">Function to be called when the user chooses a file. The string value is the file's path.</param>
public void saveFile(string extensions, Action<string> callback)
{
FileSkimmerBackend.GetFile(extensions.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries), FileOpenerStyle.Save, callback);
}
}
+ /// <summary>
+ /// ShiftFS API for Lua.
+ /// </summary>
[Exposed("fs")]
public class ShiftFSFunctions
{
+ /// <summary>
+ /// Read all text in a file to a string.
+ /// </summary>
+ /// <param name="path">The file path to read</param>
+ /// <returns>The string containing the file's contents.</returns>
public string readAllText(string path)
{
return Utils.ReadAllText(path);
}
+ /// <summary>
+ /// Copy a file from one place to another.
+ /// </summary>
+ /// <param name="i">The source file</param>
+ /// <param name="o">The destination path</param>
public void copy(string i, string o)
{
Utils.WriteAllBytes(o, Utils.ReadAllBytes(i));
}
+ /// <summary>
+ /// Gets all files in the specified directory.
+ /// </summary>
+ /// <param name="dir">The directory to search</param>
+ /// <returns>A string array containing all file paths in the directory.</returns>
public string[] getFiles(string dir)
{
return Utils.GetFiles(dir);
}
+ /// <summary>
+ /// Gets all directories inside a directory.
+ /// </summary>
+ /// <param name="dir">The directory to search</param>
+ /// <returns>A string array containing all directory paths in the directory.</returns>
public string[] getDirectories(string dir)
{
return Utils.GetDirectories(dir);
}
+ /// <summary>
+ /// Read the binary contents of a file to a <see cref="byte"/> array.
+ /// </summary>
+ /// <param name="path">The file path to read.</param>
+ /// <returns>The resulting byte array.</returns>
public byte[] readAllBytes(string path)
{
return Utils.ReadAllBytes(path);
}
+ /// <summary>
+ /// Writes the specified text to a file.
+ /// </summary>
+ /// <param name="path">The file path</param>
+ /// <param name="contents">The text to write</param>
public void writeAllText(string path, string contents)
{
Utils.WriteAllText(path, contents);
}
+ /// <summary>
+ /// Writes the specified binary data to a file.
+ /// </summary>
+ /// <param name="path">The file path.</param>
+ /// <param name="contents">The binary data</param>
public void writeAllBytes(string path, byte[] contents)
{
Utils.WriteAllBytes(path, contents);
}
+ /// <summary>
+ /// Determines whether the specified path exists and is a file.
+ /// </summary>
+ /// <param name="path">The path to search</param>
+ /// <returns>The result of the search.</returns>
public bool fileExists(string path)
{
return Utils.FileExists(path);
}
+ /// <summary>
+ /// Determines whether the specified path exists and is a directory.
+ /// </summary>
+ /// <param name="path">The path to search</param>
+ /// <returns>The result of the search.</returns>
public bool directoryExists(string path)
{
return Utils.DirectoryExists(path);
}
+ /// <summary>
+ /// Deletes the file/directory at the specified path.
+ /// </summary>
+ /// <param name="path">The path to delete</param>
public void delete(string path)
{
Utils.Delete(path);
}
+ /// <summary>
+ /// Creates a new directory at the specified path.
+ /// </summary>
+ /// <param name="path">The path to create</param>
public void createDirectory(string path)
{
Utils.CreateDirectory(path);
}
}
-
+ /// <summary>
+ /// Marks the specified class as a Lua API object.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ExposedAttribute : Attribute
{
/// <summary>
@@ -494,6 +708,9 @@ end");
Name = name;
}
+ /// <summary>
+ /// The API object's name
+ /// </summary>
public string Name { get; private set; }
}
}
diff --git a/ShiftOS_TheReturn/Server.cs b/ShiftOS_TheReturn/Server.cs
new file mode 100644
index 0000000..ddbd15b
--- /dev/null
+++ b/ShiftOS_TheReturn/Server.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using ShiftOS.Objects;
+
+namespace ShiftOS.Engine
+{
+ public interface Server
+ {
+ /// <summary>
+ /// Occurs when someone sends a message to the server.
+ /// </summary>
+ /// <param name="msg">The message from the client.</param>
+ void MessageReceived(ServerMessage msg);
+ }
+
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
+ public class ServerAttribute : Attribute
+ {
+ public ServerAttribute(string name, int port)
+ {
+ Name = name;
+ Port = port;
+ }
+
+
+ /// <summary>
+ /// Gets the name of the server.
+ /// </summary>
+ public string Name { get; }
+
+ /// <summary>
+ /// Gets the port of the server.
+ /// </summary>
+ public int Port { get; }
+
+ }
+}
diff --git a/ShiftOS_TheReturn/ServerManager.cs b/ShiftOS_TheReturn/ServerManager.cs
index 792b38d..1439c0d 100644
--- a/ShiftOS_TheReturn/ServerManager.cs
+++ b/ShiftOS_TheReturn/ServerManager.cs
@@ -36,31 +36,55 @@ using static ShiftOS.Engine.SaveSystem;
using Newtonsoft.Json;
using System.Net.Sockets;
using System.Diagnostics;
+using System.IO;
+using System.Reflection;
namespace ShiftOS.Engine
{
+ /// <summary>
+ /// Digital Society connection management class.
+ /// </summary>
public static class ServerManager
{
+ /// <summary>
+ /// Print connection diagnostic information.
+ /// </summary>
public static void PrintDiagnostics()
{
Console.WriteLine($@"{{CLIENT_DIAGNOSTICS}}
{{GUID}}: {thisGuid}
+Ping: {ServerManager.DigitalSocietyPing} ms
{{CLIENT_DATA}}:
{JsonConvert.SerializeObject(client, Formatting.Indented)}");
}
+ /// <summary>
+ /// Gets the unique identifier for this Digital Society connection. This can be used for peer-to-peer communication between two clients.
+ /// </summary>
public static Guid thisGuid { get; private set; }
- private static NetObjectClient client { get; set; }
+
+ /// <summary>
+ /// Gets the underlying NetSockets client for this connection.
+ /// </summary>
+ public static NetObjectClient client { get; private set; }
+
+
private static bool UserDisconnect = false;
- public static TimeSpan DigitalSocietyPing
+ /// <summary>
+ /// Gets or sets the server response time for the last request made by this client.
+ /// </summary>
+ public static long DigitalSocietyPing
{
get;
private set;
}
+ /// <summary>
+ /// Disconnect from the digital society intentionally.
+ /// </summary>
public static void Disconnect()
{
UserDisconnect = true;
@@ -72,38 +96,59 @@ namespace ShiftOS.Engine
}
+ /// <summary>
+ /// Occurs when you are disconnected from the Digital Society.
+ /// </summary>
public static event EmptyEventHandler Disconnected;
-
- public static void InitiateMUDHack()
+
+ /// <summary>
+ /// Occurs when the unique ID for this client is sent by the server.
+ /// </summary>
+ public static event Action<string> GUIDReceived;
+
+ private static void delegateToServer(ServerMessage msg)
{
- MessageReceived += ServerManager_MessageReceived;
- SendMessage("mudhack_init", "");
+ string[] split = msg.GUID.Split('|');
+ bool finished = false;
+ foreach (var exec in Directory.GetFiles(Environment.CurrentDirectory))
+ {
+ if(exec.ToLower().EndsWith(".exe") || exec.ToLower().EndsWith(".dll"))
+ {
+ try
+ {
+ var asm = Assembly.LoadFile(exec);
+ foreach(var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(Server))))
+ {
+ var attrib = type.GetCustomAttributes().FirstOrDefault(x => x is ServerAttribute) as ServerAttribute;
+ if(attrib != null)
+ {
+ if(split[0] == SaveSystem.CurrentSave.SystemName && split[1] == attrib.Port.ToString())
+ {
+ if (Shiftorium.UpgradeAttributesUnlocked(type))
+ {
+ type.GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(x => x.Name == "MessageReceived")?.Invoke(Activator.CreateInstance(type), null);
+ finished = true;
+ }
+ }
+ }
+ }
+ }
+ catch { }
+ }
+ }
+ if (finished == false)
+ {
+ Forward(split[2], "Error", $"{split[0]}:{split[1]}: connection refused");
+ }
}
- public static event Action<string> ServerPasswordGenerated;
- public static event EmptyEventHandler ServerAccessGranted;
- public static event EmptyEventHandler ServerAccessDenied;
- public static event Action<string> GUIDReceived;
- public static event Action<List<OnlineUser>> UsersReceived;
private static void ServerManager_MessageReceived(ServerMessage msg)
{
switch(msg.Name)
{
- case "mudhack_users":
- UsersReceived?.Invoke(JsonConvert.DeserializeObject<List<OnlineUser>>(msg.Contents));
- break;
- case "mudhack_init":
- ServerPasswordGenerated?.Invoke(msg.Contents);
- break;
- case "mudhack_denied":
- ServerAccessDenied?.Invoke();
- break;
- case "mudhack_granted":
- ServerAccessGranted?.Invoke();
- break;
case "getguid_fromserver":
- if(SaveSystem.CurrentSave.Username == msg.Contents)
+ if(SaveSystem.CurrentUser.Username == msg.Contents)
{
client.Send(new NetObject("yes_i_am", new ServerMessage
{
@@ -113,17 +158,45 @@ namespace ShiftOS.Engine
}));
}
break;
+ case "msgtosys":
+ try
+ {
+ var m = JsonConvert.DeserializeObject<ServerMessage>(msg.Contents);
+ if(m.GUID.Split('|')[2] != thisGuid.ToString())
+ {
+ delegateToServer(m);
+ }
+ }
+ catch { }
+ break;
case "getguid_reply":
GUIDReceived?.Invoke(msg.Contents);
break;
}
}
+ public static void SendMessageToIngameServer(string sysname, int port, string title, string contents)
+ {
+ var smsg = new ServerMessage
+ {
+ Name = title,
+ GUID = $"{sysname}|{port}|{thisGuid.ToString()}",
+ Contents = contents
+ };
+ Forward("all", "msgtosys", JsonConvert.SerializeObject(smsg));
+
+ }
+
public static void Detach_ServerManager_MessageReceived()
{
MessageReceived -= new ServerMessageReceived(ServerManager_MessageReceived);
}
+ /// <summary>
+ /// Initiate a new Digital Society connection.
+ /// </summary>
+ /// <param name="mud_address">The IP address or hostname of the target server</param>
+ /// <param name="port">The target port.</param>
public static void Initiate(string mud_address, int port)
{
client = new NetObjectClient();
@@ -131,6 +204,7 @@ namespace ShiftOS.Engine
{
if (!UserDisconnect)
{
+ Desktop.PushNotification("digital_society_connection", "Disconnected from Digital Society.", "The ShiftOS kernel has been disconnected from the Digital Society. We are attempting to re-connect you.");
TerminalBackend.PrefixEnabled = true;
ConsoleEx.ForegroundColor = ConsoleColor.Red;
ConsoleEx.Bold = true;
@@ -148,7 +222,7 @@ namespace ShiftOS.Engine
{
if (PingTimer.IsRunning)
{
- DigitalSocietyPing = PingTimer.Elapsed;
+ DigitalSocietyPing = PingTimer.ElapsedMilliseconds;
PingTimer.Reset();
}
var msg = a.Data.Object as ServerMessage;
@@ -170,9 +244,9 @@ namespace ShiftOS.Engine
else if(msg.Name == "update_your_cp")
{
var args = JsonConvert.DeserializeObject<Dictionary<string, object>>(msg.Contents);
- if(args["username"] as string == SaveSystem.CurrentSave.Username)
+ if(args["username"] as string == SaveSystem.CurrentUser.Username)
{
- SaveSystem.CurrentSave.Codepoints += (long)args["amount"];
+ SaveSystem.CurrentSave.Codepoints += (ulong)args["amount"];
Desktop.InvokeOnWorkerThread(new Action(() =>
{
Infobox.Show($"MUD Control Centre", $"Someone bought an item in your shop, and they have paid {args["amount"]}, and as such, you have been granted these Codepoints.");
@@ -221,6 +295,11 @@ namespace ShiftOS.Engine
private static Stopwatch PingTimer = new Stopwatch();
+ /// <summary>
+ /// Send a message to the server.
+ /// </summary>
+ /// <param name="name">The message name</param>
+ /// <param name="contents">The message body</param>
public static void SendMessage(string name, string contents)
{
var sMsg = new ServerMessage
@@ -237,38 +316,33 @@ namespace ShiftOS.Engine
private static bool singleplayer = false;
public static bool IsSingleplayer { get { return singleplayer; } }
- public static void StartLANServer()
- {
- singleplayer = true;
- ShiftOS.Server.Program.ServerStarted += (address) =>
- {
- Console.WriteLine($"Connecting to {address}...");
- Initiate(address, 13370);
- };
- Disconnected += () =>
- {
- ShiftOS.Server.Program.Stop();
- };
- ShiftOS.Server.Program.Main(new[] { "" });
-
-
- }
-
-
+ /// <summary>
+ /// Occurs when the server sends a message to this client.
+ /// </summary>
public static event ServerMessageReceived MessageReceived;
- public static void Forward(string targetGUID, string v, string message)
+ /// <summary>
+ /// Send a message to another client.
+ /// </summary>
+ /// <param name="targetGUID">The target client GUID.</param>
+ /// <param name="title">The message title</param>
+ /// <param name="message">The message contents</param>
+ public static void Forward(string targetGUID, string title, string message)
{
var smsg = new ServerMessage
{
GUID = targetGUID,
- Name = v,
+ Name = title,
Contents = message
};
ServerManager.SendMessage("mud_forward", JsonConvert.SerializeObject(smsg));
}
}
+ /// <summary>
+ /// Delegate for handling server messages
+ /// </summary>
+ /// <param name="msg">A server message containing the protocol message name, GUID of the sender, and the contents of the message.</param>
public delegate void ServerMessageReceived(ServerMessage msg);
public class MultiplayerOnlyAttribute : Attribute
diff --git a/ShiftOS_TheReturn/ShiftOS.Engine.csproj b/ShiftOS_TheReturn/ShiftOS.Engine.csproj
index fb33dc5..f70c41e 100644
--- a/ShiftOS_TheReturn/ShiftOS.Engine.csproj
+++ b/ShiftOS_TheReturn/ShiftOS.Engine.csproj
@@ -109,8 +109,10 @@
<Compile Include="FileSkimmerBackend.cs" />
<Compile Include="Infobox.cs" />
<Compile Include="IShiftOSWindow.cs" />
+ <Compile Include="IStatusIcon.cs" />
<Compile Include="KernelWatchdog.cs" />
<Compile Include="Localization.cs" />
+ <Compile Include="LoginManager.cs" />
<Compile Include="NotificationDaemon.cs" />
<Compile Include="OutOfBoxExperience.cs" />
<Compile Include="Paths.cs" />
@@ -123,6 +125,7 @@
</Compile>
<Compile Include="SaveSystem.cs" />
<Compile Include="Scripting.cs" />
+ <Compile Include="Server.cs" />
<Compile Include="ServerManager.cs" />
<Compile Include="ShiftnetSite.cs" />
<Compile Include="Shiftorium.cs" />
@@ -131,10 +134,7 @@
<Compile Include="TerminalBackend.cs" />
<Compile Include="TerminalTextWriter.cs" />
<Compile Include="TutorialManager.cs" />
- <Compile Include="UniteClient.cs" />
- <Compile Include="UniteTestCommands.cs" />
<Compile Include="UserManagementCommands.cs" />
- <Compile Include="VirusEngine.cs" />
<Compile Include="WinOpenAttribute.cs" />
<EmbeddedResource Include="Infobox.resx">
<DependentUpon>Infobox.cs</DependentUpon>
@@ -163,10 +163,6 @@
<Project>{A069089A-8962-4607-B2B2-4CF4A371066E}</Project>
<Name>ShiftOS.Objects</Name>
</ProjectReference>
- <ProjectReference Include="..\ShiftOS.Server\ShiftOS.Server.csproj">
- <Project>{226C63B4-E60D-4949-B4E7-7A2DDBB96776}</Project>
- <Name>ShiftOS.Server</Name>
- </ProjectReference>
</ItemGroup>
<ItemGroup>
<COMReference Include="MediaPlayer">
diff --git a/ShiftOS_TheReturn/ShiftnetSite.cs b/ShiftOS_TheReturn/ShiftnetSite.cs
index 5460171..07b4698 100644
--- a/ShiftOS_TheReturn/ShiftnetSite.cs
+++ b/ShiftOS_TheReturn/ShiftnetSite.cs
@@ -6,13 +6,34 @@ using System.Threading.Tasks;
namespace ShiftOS.Engine
{
+ /// <summary>
+ /// Interface for creating a Shiftnet website.
+ /// </summary>
public interface IShiftnetSite
{
+ /// <summary>
+ /// Called when the page is loaded. Perform data population here.
+ /// </summary>
void Setup();
+
+ /// <summary>
+ /// Occurs when a ShiftOS skin is loaded.
+ /// </summary>
void OnSkinLoad();
+
+ /// <summary>
+ /// Occurs when a Shiftorium upgrade is installed.
+ /// </summary>
void OnUpgrade();
+ /// <summary>
+ /// Invoke this to navigate the parent browser to a specified Shiftnet URL.
+ /// </summary>
event Action<string> GoToUrl;
+
+ /// <summary>
+ /// Invoke this to tell the parent browser to navigate to the previous page.
+ /// </summary>
event Action GoBack;
}
@@ -24,14 +45,35 @@ namespace ShiftOS.Engine
}
+ /// <summary>
+ /// Interface for creating a Shiftnet client.
+ /// </summary>
public interface IShiftnetClient
{
+ /// <summary>
+ /// Navigates the client to a specified Shiftnet URL.
+ /// </summary>
+ /// <param name="url">The URL to navigate to.</param>
void NavigateToUrl(string url);
+
+ /// <summary>
+ /// Refreshes the current page.
+ /// </summary>
void RefreshSite();
}
+ /// <summary>
+ /// Marks this class as a Shiftnet website.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple =false)]
public class ShiftnetSiteAttribute : Attribute
{
+ /// <summary>
+ /// Creates a new instance of the <see cref="ShiftnetSiteAttribute"/> class.
+ /// </summary>
+ /// <param name="url">The URL that links to this site</param>
+ /// <param name="name">The name of this site</param>
+ /// <param name="description">The description of this site</param>
public ShiftnetSiteAttribute(string url, string name, string description)
{
Url = url;
@@ -39,8 +81,19 @@ namespace ShiftOS.Engine
Description = description;
}
+ /// <summary>
+ /// Gets the Shiftnet URL for this site.
+ /// </summary>
public string Url { get; private set; }
+
+ /// <summary>
+ /// Gets the name of this website.
+ /// </summary>
public string Name { get; private set; }
+
+ /// <summary>
+ /// Gets the description of this website.
+ /// </summary>
public string Description { get; private set; }
}
}
diff --git a/ShiftOS_TheReturn/Shiftorium.cs b/ShiftOS_TheReturn/Shiftorium.cs
index ad60134..975939f 100644
--- a/ShiftOS_TheReturn/Shiftorium.cs
+++ b/ShiftOS_TheReturn/Shiftorium.cs
@@ -34,6 +34,9 @@ using System.Diagnostics;
namespace ShiftOS.Engine
{
+ /// <summary>
+ /// Backend class for the Shiftorium.
+ /// </summary>
public static class Shiftorium
{
/// <summary>
@@ -49,11 +52,11 @@ namespace ShiftOS.Engine
public static string[] GetCategories(bool onlyAvailable = true)
{
List<string> cats = new List<string>();
- IEnumerable < ShiftoriumUpgrade > upgrades = GetDefaults();
+ IEnumerable<ShiftoriumUpgrade> upgrades = GetDefaults();
if (onlyAvailable)
upgrades = new List<ShiftoriumUpgrade>(GetAvailable());
- foreach(var upg in upgrades)
+ foreach (var upg in upgrades)
{
if (!cats.Contains(upg.Category))
cats.Add(upg.Category);
@@ -62,11 +65,19 @@ namespace ShiftOS.Engine
return cats.ToArray();
}
+ /// <summary>
+ /// Causes the engine to alert the frontend of a new Shiftorium upgrade install.
+ /// </summary>
public static void InvokeUpgradeInstalled()
{
Installed?.Invoke();
}
+ /// <summary>
+ /// Gets the category of an upgrade.
+ /// </summary>
+ /// <param name="id">The upgrade ID to check</param>
+ /// <returns>"Other" if the upgrade is not found, else, the upgrade category.</returns>
public static string GetCategory(string id)
{
var upg = GetDefaults().FirstOrDefault(x => x.ID == id);
@@ -75,19 +86,35 @@ namespace ShiftOS.Engine
return (upg.Category == null) ? "Other" : upg.Category;
}
+ /// <summary>
+ /// Gets all upgrades in a given category.
+ /// </summary>
+ /// <param name="cat">The category name to search</param>
+ /// <returns>The upgrades in the category.</returns>
public static IEnumerable<ShiftoriumUpgrade> GetAllInCategory(string cat)
{
return GetDefaults().Where(x => x.Category == cat);
}
+ /// <summary>
+ /// Gets whether or not the user has installed all upgrades in a category.
+ /// </summary>
+ /// <param name="cat">The category to search.</param>
+ /// <returns>Boolean value representing whether the user has installed all upgrades in the category.</returns>
public static bool IsCategoryEmptied(string cat)
{
return GetDefaults().Where(x => x.Category == cat).FirstOrDefault(x => x.Installed == false) == null;
}
- public static bool Buy(string id, long cost)
+ /// <summary>
+ /// Buy an upgrade, deducting the specified amount of Codepoints.
+ /// </summary>
+ /// <param name="id">The upgrade ID to buy</param>
+ /// <param name="cost">The amount of Codepoints to deduct</param>
+ /// <returns>True if the upgrade was installed successfully, false if the user didn't have enough Codepoints or the upgrade wasn' found.</returns>
+ public static bool Buy(string id, ulong cost)
{
- if(SaveSystem.CurrentSave.Codepoints >= cost)
+ if (SaveSystem.CurrentSave.Codepoints >= cost)
{
SaveSystem.CurrentSave.Upgrades[id] = true;
TerminalBackend.InvokeCommand("sos.save");
@@ -99,17 +126,22 @@ namespace ShiftOS.Engine
}
else
{
- if(!Silent)
+ if (!Silent)
Console.WriteLine($"{{SHIFTORIUM_NOTENOUGHCP}}: {cost} > {SaveSystem.CurrentSave.Codepoints}");
return false;
}
}
+ /// <summary>
+ /// Determines whether all Shiftorium upgrade attributes for this type have been installed.
+ /// </summary>
+ /// <param name="type">The type to scan</param>
+ /// <returns>Boolean value representing the result of this function.</returns>
public static bool UpgradeAttributesUnlocked(Type type)
{
- foreach(var attr in type.GetCustomAttributes(true))
+ foreach (var attr in type.GetCustomAttributes(true))
{
- if(attr is RequiresUpgradeAttribute)
+ if (attr is RequiresUpgradeAttribute)
{
var rAttr = attr as RequiresUpgradeAttribute;
return rAttr.Installed;
@@ -119,6 +151,11 @@ namespace ShiftOS.Engine
return true;
}
+ /// <summary>
+ /// Determines whether all Shiftorium upgrade attributes for this method have been installed.
+ /// </summary>
+ /// <param name="type">The method to scan</param>
+ /// <returns>Boolean value representing the result of this function.</returns>
public static bool UpgradeAttributesUnlocked(MethodInfo type)
{
foreach (var attr in type.GetCustomAttributes(true))
@@ -133,6 +170,11 @@ namespace ShiftOS.Engine
return true;
}
+ /// <summary>
+ /// Determines whether all Shiftorium upgrade attributes for this property have been installed.
+ /// </summary>
+ /// <param name="type">The property to scan</param>
+ /// <returns>Boolean value representing the result of this function.</returns>
public static bool UpgradeAttributesUnlocked(PropertyInfo type)
{
foreach (var attr in type.GetCustomAttributes(true))
@@ -147,6 +189,11 @@ namespace ShiftOS.Engine
return true;
}
+ /// <summary>
+ /// Determines whether all Shiftorium upgrade attributes for this field have been installed.
+ /// </summary>
+ /// <param name="type">The field to scan</param>
+ /// <returns>Boolean value representing the result of this function.</returns>
public static bool UpgradeAttributesUnlocked(FieldInfo type)
{
foreach (var attr in type.GetCustomAttributes(true))
@@ -161,15 +208,140 @@ namespace ShiftOS.Engine
return true;
}
+ private static List<ShiftoriumUpgrade> upgDb = null;
+
+ public static void CreateUpgradeDatabase()
+ {
+ upgDb = new List<ShiftoriumUpgrade>();
+ //Now we probe for ShiftoriumUpgradeAttributes for mods.
+ foreach (var file in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
+ {
+ if (file.EndsWith(".exe") || file.EndsWith(".dll"))
+ {
+ try
+ {
+ var asm = Assembly.LoadFile(file);
+ foreach (var type in asm.GetTypes())
+ {
+ if (type.GetInterfaces().Contains(typeof(IShiftoriumProvider)))
+ {
+ if (type.GetCustomAttributes().FirstOrDefault(x => x is ShiftoriumProviderAttribute) != null)
+ {
+ var _p = Activator.CreateInstance(type, null) as IShiftoriumProvider;
+ upgDb.AddRange(_p.GetDefaults());
+ }
+ }
+
+
+ ShiftoriumUpgradeAttribute attrib = type.GetCustomAttributes(false).FirstOrDefault(x => x is ShiftoriumUpgradeAttribute) as ShiftoriumUpgradeAttribute;
+ if (attrib != null)
+ {
+ if (upgDb.FirstOrDefault(x => x.ID == attrib.Upgrade) != null)
+ throw new ShiftoriumConflictException(attrib.Upgrade);
+ upgDb.Add(new ShiftoriumUpgrade
+ {
+ Id = attrib.Upgrade,
+ Name = attrib.Name,
+ Cost = attrib.Cost,
+ Description = attrib.Description,
+ Dependencies = attrib.Dependencies,
+ Category = attrib.Category
+ });
+ }
+
+ foreach (var mth in type.GetMethods())
+ {
+ attrib = mth.GetCustomAttributes(false).FirstOrDefault(x => x is ShiftoriumUpgradeAttribute) as ShiftoriumUpgradeAttribute;
+ if (attrib != null)
+ {
+ if (upgDb.FirstOrDefault(x => x.ID == attrib.Upgrade) != null)
+ throw new ShiftoriumConflictException(attrib.Upgrade);
+ upgDb.Add(new ShiftoriumUpgrade
+ {
+ Id = attrib.Upgrade,
+ Name = attrib.Name,
+ Cost = attrib.Cost,
+ Description = attrib.Description,
+ Dependencies = attrib.Dependencies,
+ Category = attrib.Category
+ });
+
+ }
+ }
+
+ foreach (var mth in type.GetFields())
+ {
+ attrib = mth.GetCustomAttributes(false).FirstOrDefault(x => x is ShiftoriumUpgradeAttribute) as ShiftoriumUpgradeAttribute;
+ if (attrib != null)
+ {
+ if (upgDb.FirstOrDefault(x => x.ID == attrib.Upgrade) != null)
+ throw new ShiftoriumConflictException(attrib.Upgrade);
+ upgDb.Add(new ShiftoriumUpgrade
+ {
+ Id = attrib.Upgrade,
+ Name = attrib.Name,
+ Cost = attrib.Cost,
+ Description = attrib.Description,
+ Dependencies = attrib.Dependencies,
+ Category = attrib.Category
+ });
+
+ }
+ }
+
+ foreach (var mth in type.GetProperties())
+ {
+ attrib = mth.GetCustomAttributes(false).FirstOrDefault(x => x is ShiftoriumUpgradeAttribute) as ShiftoriumUpgradeAttribute;
+ if (attrib != null)
+ {
+ if (upgDb.FirstOrDefault(x => x.ID == attrib.Upgrade) != null)
+ throw new ShiftoriumConflictException(attrib.Upgrade);
+ upgDb.Add(new ShiftoriumUpgrade
+ {
+ Id = attrib.Upgrade,
+ Name = attrib.Name,
+ Cost = attrib.Cost,
+ Description = attrib.Description,
+ Dependencies = attrib.Dependencies,
+ Category = attrib.Category
+ });
+
+ }
+ }
+
+ }
+ }
+ catch { }
+ }
+ }
+
+
+
+ foreach (var item in upgDb)
+ {
+ if (upgDb.Where(x => x.ID == item.ID).Count() > 1)
+ throw new ShiftoriumConflictException(item.Id);
+ }
+ }
+
+
+ /// <summary>
+ /// Gets or sets whether the Shiftorium has been initiated.
+ /// </summary>
public static bool IsInitiated { get; private set; }
+
+ /// <summary>
+ /// Initiates the Shiftorium.
+ /// </summary>
public static void Init()
{
if (IsInitiated == false)
{
IsInitiated = true;
//Let the crash handler deal with this one...
- var dict = GetDefaults();
+ CreateUpgradeDatabase();
+ var dict = upgDb;
foreach (var itm in dict)
{
if (!SaveSystem.CurrentSave.Upgrades.ContainsKey(itm.ID))
@@ -188,9 +360,14 @@ namespace ShiftOS.Engine
}
- public static long GetCPValue(string id)
+ /// <summary>
+ /// Get the codepoint value for an upgrade.
+ /// </summary>
+ /// <param name="id">The upgrade ID to search</param>
+ /// <returns>The codepoint value.</returns>
+ public static ulong GetCPValue(string id)
{
- foreach(var upg in GetDefaults())
+ foreach (var upg in GetDefaults())
{
if (upg.ID == id)
return upg.Cost;
@@ -198,10 +375,14 @@ namespace ShiftOS.Engine
return 0;
}
+ /// <summary>
+ /// Gets all available upgrades.
+ /// </summary>
+ /// <returns></returns>
public static ShiftoriumUpgrade[] GetAvailable()
{
List<ShiftoriumUpgrade> available = new List<ShiftoriumUpgrade>();
- foreach(var defaultupg in GetDefaults())
+ foreach (var defaultupg in GetDefaults())
{
if (!UpgradeInstalled(defaultupg.ID) && DependenciesInstalled(defaultupg))
available.Add(defaultupg);
@@ -209,6 +390,11 @@ namespace ShiftOS.Engine
return available.ToArray();
}
+ /// <summary>
+ /// Determines whether all dependencies of a given upgrade have been installed.
+ /// </summary>
+ /// <param name="upg">The upgrade to scan</param>
+ /// <returns>Boolean representing the result of this function.</returns>
public static bool DependenciesInstalled(ShiftoriumUpgrade upg)
{
if (string.IsNullOrEmpty(upg.Dependencies))
@@ -218,23 +404,33 @@ namespace ShiftOS.Engine
else if (upg.Dependencies.Contains(";"))
{
string[] dependencies = upg.Dependencies.Split(';');
- foreach(var dependency in dependencies)
+ foreach (var dependency in dependencies)
{
if (!UpgradeInstalled(dependency))
return false;
}
return true;
- }
+ }
else
{
return UpgradeInstalled(upg.Dependencies);
}
}
+ /// <summary>
+ /// Fired when an upgrade is installed.
+ /// </summary>
public static event EmptyEventHandler Installed;
+ /// <summary>
+ /// Determines if an upgrade is installed.
+ /// </summary>
+ /// <param name="id">The upgrade ID to scan.</param>
+ /// <returns>Whether the upgrade is installed.</returns>
public static bool UpgradeInstalled(string id)
{
+ if (string.IsNullOrWhiteSpace(id))
+ return true;
if (SaveSystem.CurrentSave != null)
{
if (!IsInitiated)
@@ -250,7 +446,7 @@ namespace ShiftOS.Engine
if (id.Contains(';'))
{
- foreach(var u in id.Split(';'))
+ foreach (var u in id.Split(';'))
{
if (UpgradeInstalled(u) == false)
return false;
@@ -259,10 +455,10 @@ namespace ShiftOS.Engine
}
bool upgInstalled = false;
- if(SaveSystem.CurrentSave.Upgrades.ContainsKey(id))
+ if (SaveSystem.CurrentSave.Upgrades.ContainsKey(id))
upgInstalled = SaveSystem.CurrentSave.Upgrades[id];
- if(upgInstalled == false)
+ if (upgInstalled == false)
return SaveSystem.CurrentSave.StoriesExperienced.Contains(id);
return true;
}
@@ -286,125 +482,22 @@ namespace ShiftOS.Engine
_provider = p;
}
- //Bless the newer NEWER engine.
+ /// <summary>
+ /// Gets every upgrade inside the frontend and all mods.
+ /// </summary>
+ /// <returns>Every single found Shiftorium upgrade.</returns>
public static List<ShiftoriumUpgrade> GetDefaults()
{
- List<ShiftoriumUpgrade> list = new List<ShiftoriumUpgrade>();
- //Now we probe for ShiftoriumUpgradeAttributes for mods.
- foreach(var file in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
- {
- if(file.EndsWith(".exe") || file.EndsWith(".dll"))
- {
- try
- {
- var asm = Assembly.LoadFile(file);
- foreach (var type in asm.GetTypes())
- {
- if (type.GetInterfaces().Contains(typeof(IShiftoriumProvider)))
- {
- if(type.GetCustomAttributes().FirstOrDefault(x=> x is ShiftoriumProviderAttribute) != null)
- {
- var _p = Activator.CreateInstance(type, null) as IShiftoriumProvider;
- list.AddRange(_p.GetDefaults());
- }
- }
-
-
- ShiftoriumUpgradeAttribute attrib = type.GetCustomAttributes(false).FirstOrDefault(x => x is ShiftoriumUpgradeAttribute) as ShiftoriumUpgradeAttribute;
- if (attrib != null)
- {
- if (list.FirstOrDefault(x => x.ID == attrib.Upgrade) != null)
- throw new ShiftoriumConflictException(attrib.Upgrade);
- list.Add(new ShiftoriumUpgrade
- {
- Id = attrib.Upgrade,
- Name = attrib.Name,
- Cost = attrib.Cost,
- Description = attrib.Description,
- Dependencies = attrib.Dependencies,
- Category = attrib.Category
- });
- }
-
- foreach (var mth in type.GetMethods())
- {
- attrib = mth.GetCustomAttributes(false).FirstOrDefault(x => x is ShiftoriumUpgradeAttribute) as ShiftoriumUpgradeAttribute;
- if (attrib != null)
- {
- if (list.FirstOrDefault(x => x.ID == attrib.Upgrade) != null)
- throw new ShiftoriumConflictException(attrib.Upgrade);
- list.Add(new ShiftoriumUpgrade
- {
- Id = attrib.Upgrade,
- Name = attrib.Name,
- Cost = attrib.Cost,
- Description = attrib.Description,
- Dependencies = attrib.Dependencies,
- Category = attrib.Category
- });
-
- }
- }
-
- foreach (var mth in type.GetFields())
- {
- attrib = mth.GetCustomAttributes(false).FirstOrDefault(x => x is ShiftoriumUpgradeAttribute) as ShiftoriumUpgradeAttribute;
- if (attrib != null)
- {
- if (list.FirstOrDefault(x => x.ID == attrib.Upgrade) != null)
- throw new ShiftoriumConflictException(attrib.Upgrade);
- list.Add(new ShiftoriumUpgrade
- {
- Id = attrib.Upgrade,
- Name = attrib.Name,
- Cost = attrib.Cost,
- Description = attrib.Description,
- Dependencies = attrib.Dependencies,
- Category = attrib.Category
- });
-
- }
- }
-
- foreach (var mth in type.GetProperties())
- {
- attrib = mth.GetCustomAttributes(false).FirstOrDefault(x => x is ShiftoriumUpgradeAttribute) as ShiftoriumUpgradeAttribute;
- if (attrib != null)
- {
- if (list.FirstOrDefault(x => x.ID == attrib.Upgrade) != null)
- throw new ShiftoriumConflictException(attrib.Upgrade);
- list.Add(new ShiftoriumUpgrade
- {
- Id = attrib.Upgrade,
- Name = attrib.Name,
- Cost = attrib.Cost,
- Description = attrib.Description,
- Dependencies = attrib.Dependencies,
- Category = attrib.Category
- });
-
- }
- }
-
- }
- }
- catch { }
- }
- }
-
-
-
- foreach(var item in list)
- {
- if (list.Where(x => x.ID == item.ID).Count() > 1)
- throw new ShiftoriumConflictException(item.Id);
- }
- return list;
+ return upgDb;
}
}
public interface IShiftoriumProvider
{
+ /// <summary>
+ /// Retrieves all frontend upgrades.
+ /// </summary>
+ /// <returns></returns>
List<ShiftoriumUpgrade> GetDefaults();
}
@@ -427,7 +520,7 @@ namespace ShiftOS.Engine
{
public string Name { get; set; }
public string Description { get; set; }
- public long Cost { get; set; }
+ public ulong Cost { get; set; }
public string ID { get { return (this.Id != null ? this.Id : (Name.ToLower().Replace(" ", "_"))); } }
public string Id { get; set; }
public string Category { get; set; }
@@ -443,7 +536,7 @@ namespace ShiftOS.Engine
public class ShiftoriumUpgradeAttribute : RequiresUpgradeAttribute
{
- public ShiftoriumUpgradeAttribute(string name, long cost, string desc, string dependencies, string category) : base(name.ToLower().Replace(" ", "_"))
+ public ShiftoriumUpgradeAttribute(string name, ulong cost, string desc, string dependencies, string category) : base(name.ToLower().Replace(" ", "_"))
{
Name = name;
Description = desc;
@@ -454,7 +547,7 @@ namespace ShiftOS.Engine
public string Name { get; private set; }
public string Description { get; private set; }
- public long Cost { get; private set; }
+ public ulong Cost { get; private set; }
public string Dependencies { get; private set; }
public string Category { get; private set; }
}
diff --git a/ShiftOS_TheReturn/Skinning.cs b/ShiftOS_TheReturn/Skinning.cs
index 4cc9bbd..d5114c5 100644
--- a/ShiftOS_TheReturn/Skinning.cs
+++ b/ShiftOS_TheReturn/Skinning.cs
@@ -37,35 +37,71 @@ using System.Reflection;
using ShiftOS.Engine.Scripting;
namespace ShiftOS.Engine
{
-
+ /// <summary>
+ /// Skinning API for Lua.
+ /// </summary>
[Exposed("skinning")]
public class SkinFunctions
{
+ /// <summary>
+ /// Reload the current skin.
+ /// </summary>
public void loadSkin()
{
SkinEngine.LoadSkin();
}
+ /// <summary>
+ /// Get the current skin info.
+ /// </summary>
+ /// <returns>A proxy object containing all skin variables.</returns>
public dynamic getSkin()
{
return SkinEngine.LoadedSkin;
}
+ /// <summary>
+ /// Set the current skin to the specified <see cref="Skin"/> class.
+ /// </summary>
+ /// <param name="skn">The <see cref="Skin"/> class to load.</param>
public void setSkin(Skin skn)
{
Utils.WriteAllText(Paths.GetPath("skin.json"), JsonConvert.SerializeObject(skn));
SkinEngine.LoadSkin();
}
+ /// <summary>
+ /// Retrieves an image from the skin file.
+ /// </summary>
+ /// <param name="id">The skin image ID</param>
+ /// <returns>The loaded image, null (nil in Lua) if none is found.</returns>
public dynamic getImage(string id)
{
return SkinEngine.GetImage(id);
}
}
-
+ /// <summary>
+ /// Skin engine management class.
+ /// </summary>
public static class SkinEngine
{
+ private static ISkinPostProcessor processor = null;
+
+ /// <summary>
+ /// Load a new skin postprocessor into the engine.
+ /// </summary>
+ /// <param name="_processor">The postprocessor to load.</param>
+ public static void SetPostProcessor(ISkinPostProcessor _processor)
+ {
+ processor = _processor;
+ }
+
+ /// <summary>
+ /// Retrieve the user-specified image layout of a skin image.
+ /// </summary>
+ /// <param name="img">The skin image ID.</param>
+ /// <returns>The <see cref="ImageLayout"/> for the image.</returns>
public static ImageLayout GetImageLayout(string img)
{
if (LoadedSkin.SkinImageLayouts.ContainsKey(img))
@@ -79,6 +115,11 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Retrieves an image from the skin after postprocessing it.
+ /// </summary>
+ /// <param name="img">The image ID to search.</param>
+ /// <returns>The post-processed image, or null if none was found.</returns>
public static System.Drawing.Image GetImage(string img)
{
var type = typeof(Skin);
@@ -93,6 +134,8 @@ namespace ShiftOS.Engine
if (iattr.Name == img)
{
byte[] image = (byte[])field.GetValue(LoadedSkin);
+ if (processor != null)
+ image = processor.ProcessImage(image);
return ImageFromBinary(image);
}
}
@@ -102,11 +145,20 @@ namespace ShiftOS.Engine
return null;
}
+ /// <summary>
+ /// Set the engine's current icon prober.
+ /// </summary>
+ /// <param name="prober">The icon prober to use.</param>
public static void SetIconProber(IIconProber prober)
{
_iconProber = prober;
}
+ /// <summary>
+ /// Load a <see cref="Image"/> from a <see cref="byte"/> array.
+ /// </summary>
+ /// <param name="image">The array to convert</param>
+ /// <returns>The resulting image.</returns>
public static Image ImageFromBinary(byte[] image)
{
if (image == null)
@@ -117,6 +169,9 @@ namespace ShiftOS.Engine
private static Skin loadedSkin = new Skin();
+ /// <summary>
+ /// Gets the currently loaded skin.
+ /// </summary>
public static Skin LoadedSkin
{
get
@@ -129,6 +184,9 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Initiates the skin engine.
+ /// </summary>
public static void Init()
{
Application.ApplicationExit += (o, a) =>
@@ -151,8 +209,14 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Occurs when the skin is loaded.
+ /// </summary>
public static event EmptyEventHandler SkinLoaded;
+ /// <summary>
+ /// Reload the current skin.
+ /// </summary>
public static void LoadSkin()
{
LoadedSkin = JsonConvert.DeserializeObject<Skin>(Utils.ReadAllText(Paths.GetPath("skin.json")));
@@ -161,6 +225,9 @@ namespace ShiftOS.Engine
Desktop.PopulateAppLauncher();
}
+ /// <summary>
+ /// Save the skin loaded in memory to the filesystem.
+ /// </summary>
public static void SaveSkin()
{
Utils.WriteAllText(Paths.GetPath("skin.json"), JsonConvert.SerializeObject(LoadedSkin, Formatting.Indented));
@@ -168,6 +235,11 @@ namespace ShiftOS.Engine
private static IIconProber _iconProber = null;
+ /// <summary>
+ /// Retrieves the default icon for a given icon ID.
+ /// </summary>
+ /// <param name="id">The icon ID to search.</param>
+ /// <returns>The resulting icon image.</returns>
public static Image GetDefaultIcon(string id)
{
if (_iconProber == null)
@@ -204,13 +276,26 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Retrieves the user-defined icon for a specified icon ID.
+ /// </summary>
+ /// <param name="id">The icon ID to search.</param>
+ /// <returns>The resulting icon image.</returns>
public static Image GetIcon(string id)
{
if (!LoadedSkin.AppIcons.ContainsKey(id))
LoadedSkin.AppIcons.Add(id, null);
if (LoadedSkin.AppIcons[id] == null)
- return GetDefaultIcon(id);
+ {
+ var img = GetDefaultIcon(id);
+ using (var mstr = new MemoryStream())
+ {
+ img.Save(mstr, System.Drawing.Imaging.ImageFormat.Png);
+ LoadedSkin.AppIcons[id] = mstr.ToArray();
+ }
+ return img;
+ }
else
{
using (var sr = new MemoryStream(LoadedSkin.AppIcons[id]))
@@ -222,11 +307,23 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Interface for probing app icons.
+ /// </summary>
public interface IIconProber
{
+ /// <summary>
+ /// Retrieve the icon image from a <see cref="DefaultIconAttribute"/>.
+ /// </summary>
+ /// <param name="attr">The attribute data</param>
+ /// <returns>The resulting image.</returns>
Image GetIcon(DefaultIconAttribute attr);
}
+ /// <summary>
+ /// Sets the default icon ID for a <see cref="IShiftOSWindow"/>.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple =false)]
public class DefaultIconAttribute : Attribute
{
public DefaultIconAttribute(string id)
@@ -237,21 +334,24 @@ namespace ShiftOS.Engine
public string ID { get; private set; }
}
+ /// <summary>
+ /// The data stored in any .skn file.
+ /// </summary>
public class Skin
{
//borrowing from the discourse theme for the default skin
- private static readonly Color DefaultBackground = Color.FromArgb(0, 0x44, 0x00);
+ private static readonly Color DefaultBackground = Color.FromArgb(0x11, 0x11, 0x11);
private static readonly Color DefaultForeground = Color.FromArgb(0xDD, 0xDD, 0xDD);
private static readonly Color Accent1 = Color.FromArgb(0x66, 0x66, 0x66);
- private static readonly Color Accent2 = Color.FromArgb(0x80, 0, 0);
- private static readonly Color DesktopBG = Color.FromArgb(0x22, 0x22, 0x22);
+ private static readonly Color Accent2 = Color.FromArgb(0x0, 0x80, 0);
+ private static readonly Color DesktopBG = Color.FromArgb(0x00, 0x00, 0x00);
private static readonly Font SysFont = new Font("Tahoma", 9F);
private static readonly Font SysFont2 = new Font("Tahoma", 10F, FontStyle.Bold);
- private static readonly Font Header1 = new Font("Helvetica", 20F, FontStyle.Bold);
- private static readonly Font Header2 = new Font("Helvetica", 17.5F, FontStyle.Bold);
- private static readonly Font Header3 = new Font("Tahoma", 15F, FontStyle.Bold);
+ private static readonly Font Header1 = new Font("Courier New", 20F, FontStyle.Bold);
+ private static readonly Font Header2 = new Font("Courier New", 17.5F, FontStyle.Bold);
+ private static readonly Font Header3 = new Font("Courier New", 15F, FontStyle.Bold);
- private static readonly Color TitleBG = Color.FromArgb(0x11, 0x11, 0x11);
+ private static readonly Color TitleBG = Color.FromArgb(0x11, 0x55, 0x11);
private static readonly Color TitleFG = Color.FromArgb(0xaa, 0xaa, 0xaa);
//Todo: When making Shifter GUI we need to label all these with proper Shifter attributes to get 'em displaying in the right places.
@@ -267,6 +367,151 @@ namespace ShiftOS.Engine
[ShifterHidden]
public Dictionary<string, byte[]> AppIcons = new Dictionary<string, byte[]>();
+ [ShifterMeta("System")]
+ [ShifterCategory("Progress Bar")]
+ [RequiresUpgrade("shift_progress_bar;skinning")]
+ [Image("progressbarbg")]
+ [ShifterName("Progress Bar Background Image")]
+ [ShifterDescription("Set an image for the background of a progress bar.")]
+ public byte[] ProgressBarBG = null;
+
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Progress Bar")]
+ [RequiresUpgrade("shift_progress_bar;skinning")]
+ [Image("progress")]
+ [ShifterName("Progress Image")]
+ [ShifterDescription("Set the image for the progress inside a progress bar.")]
+ public byte[] Progress = null;
+
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Progress Bar")]
+ [RequiresUpgrade("shift_progress_bar")]
+ [ShifterName("Progress bar foreground color")]
+ [ShifterDescription("Set the color of the progress indicator.")]
+ public Color ProgressColor = Accent1;
+
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Progress Bar")]
+ [RequiresUpgrade("shift_progress_bar")]
+ [ShifterName("Progress bar background color")]
+ [ShifterDescription("The background color of the progress bar.")]
+ public Color ProgressBarBackgroundColor = Color.Black;
+
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Progress Bar")]
+ [RequiresUpgrade("shift_progress_bar")]
+ [ShifterName("Progress bar block size")]
+ [ShifterDescription("If the progress bar style is set to Blocks, this determines how wide each block should be.")]
+ public int ProgressBarBlockSize = 15;
+
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Progress Bar")]
+ [RequiresUpgrade("shift_progress_bar")]
+ [ShifterDescription("Set the style of a progress bar.\r\nMarquee: The progress bar will render a box that moves from the left to the right in a loop.\r\nContinuous: Progress is shown by a single, continuous box.\r\nBlocks: Just like Continuous, but the box is split into even smaller boxes of a set width.")]
+ [ShifterName("Progress bar style")]
+ public ProgressBarStyle ProgressBarStyle = ProgressBarStyle.Continuous;
+
+
+
+
+
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Buttons")]
+ [RequiresUpgrade("shift_buttons")]
+ [ShifterName("Button background color")]
+ [ShifterDescription("Set the background color for each button's Idle state.")]
+ public Color ButtonBackgroundColor = Skin.DefaultBackground;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Buttons")]
+ [RequiresUpgrade("shift_buttons;skinning")]
+ [Image("buttonhover")]
+ [ShifterName("Button hover image")]
+ [ShifterDescription("Set the image that's displayed when the mouse hovers over a button.")]
+ public byte[] ButtonHoverImage = null;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Buttons")]
+ [RequiresUpgrade("skinning;shift_buttons")]
+ [Image("buttonpressed")]
+ [ShifterName("Button pressed image")]
+ [ShifterDescription("Select an image to show when the user presses a button.")]
+ public byte[] ButtonPressedImage = null;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Buttons")]
+ [RequiresUpgrade("shift_buttons")]
+ [ShifterName("Button hover color")]
+ [ShifterDescription("Choose the color that displays on a button when the mouse hovers over it.")]
+ public Color ButtonHoverColor = Skin.Accent1;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Buttons")]
+ [RequiresUpgrade("shift_buttons")]
+ [ShifterName("Button pressed color")]
+ [ShifterDescription("Select the background color for the button when the mouse clicks it.")]
+ public Color ButtonPressedColor = Skin.Accent2;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Buttons")]
+ [RequiresUpgrade("shift_buttons")]
+ [ShifterName("Button foreground color")]
+ [ShifterDescription("Select the text and border color for each button.")]
+ public Color ButtonForegroundColor = Skin.DefaultForeground;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Buttons")]
+ [RequiresUpgrade("shift_buttons")]
+ [ShifterName("Button border width")]
+ [ShifterDescription("Set the width, in pixels, of the button's border.")]
+ public int ButtonBorderWidth = 2;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Buttons")]
+ [RequiresUpgrade("shift_buttons")]
+ [ShifterName("Button font")]
+ [ShifterDescription("Select the font for the button's text.")]
+ public Font ButtonTextFont = Skin.SysFont;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Buttons")]
+ [RequiresUpgrade("shift_buttons;skinning")]
+ [Image("buttonidle")]
+ [ShifterName("Button background color")]
+ [ShifterDescription("Select an image to show as the button's Idle state.")]
+ public byte[] ButtonBG = null;
+
+
+ [Image("panelclockbg")]
+ [ShifterMeta("Desktop")]
+ [ShifterCategory("Panel Clock")]
+ [ShifterName("Panel Clock Background Image")]
+ [ShifterDescription("Set the background image of the panel clock.")]
+ [RequiresUpgrade("skinning;shift_panel_clock")]
+ public byte[] PanelClockBG = null;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Login Screen")]
+ [RequiresUpgrade("gui_based_login_screen")]
+ [ShifterName("Login Screen Background Color")]
+ [ShifterDescription("Change the background color of the login screen.")]
+ public Color LoginScreenColor = Skin.DesktopBG;
+
+ [ShifterMeta("System")]
+ [ShifterCategory("Login Screen")]
+ [RequiresUpgrade("skinning;gui_based_login_screen")]
+ [ShifterName("Login Screen Background Image")]
+ [ShifterDescription("Set an image as your login screen!")]
+ [Image("login")]
+ public byte[] LoginScreenBG = null;
+
+
[RequiresUpgrade("shift_screensaver")]
[ShifterMeta("System")]
[ShifterCategory("Screen saver")]
@@ -405,7 +650,7 @@ namespace ShiftOS.Engine
[ShifterName("Close Button Color")]
[RequiresUpgrade("shift_title_buttons")]
[ShifterDescription("The close button color")]
- public Color CloseButtonColor = Accent2;
+ public Color CloseButtonColor = Color.FromArgb(0x80,0,0);
[ShifterMeta("Windows")]
[ShifterCategory("Title Buttons")]
@@ -1218,6 +1463,9 @@ namespace ShiftOS.Engine
public Font AdvALItemFont = SysFont2;
}
+ /// <summary>
+ /// Marks a skin spec field as hidden from the Shifter.
+ /// </summary>
public class ShifterHiddenAttribute : Attribute
{
@@ -1307,6 +1555,16 @@ namespace ShiftOS.Engine
public string Category { get; set; }
}
+ public interface ISkinPostProcessor
+ {
+ /// <summary>
+ /// Perform algorithmic operations at the bit level on a ShiftOS skin image.
+ /// </summary>
+ /// <param name="original">The image, as loaded by the engine, as a 32-bit ARGB byte array.</param>
+ /// <returns>The processed image.</returns>
+ byte[] ProcessImage(byte[] original);
+ }
+
public class ShifterMetaAttribute : Attribute
{
diff --git a/ShiftOS_TheReturn/Story.cs b/ShiftOS_TheReturn/Story.cs
index 8c726ed..f473f89 100644
--- a/ShiftOS_TheReturn/Story.cs
+++ b/ShiftOS_TheReturn/Story.cs
@@ -35,8 +35,95 @@ using Newtonsoft.Json;
namespace ShiftOS.Engine
{
- public class Story
+ public class StoryContext
{
+ public string Id { get; set; }
+ public MethodInfo Method { get; set; }
+ public bool AutoComplete = false;
+
+ public StoryContext()
+ {
+ AutoComplete = true;
+ }
+
+ public void MarkComplete()
+ {
+ SaveSystem.CurrentSave.StoriesExperienced.Add(Id);
+ OnComplete?.Invoke();
+ }
+
+ public event Action OnComplete;
+ }
+
+ public class Objective
+ {
+ private Func<bool> _completeFunc = null;
+
+ public string Name { get; set; }
+ public string Description { get; set; }
+
+ public bool IsComplete
+ {
+ get
+ {
+ return (bool)_completeFunc?.Invoke();
+ }
+ }
+
+ public Objective(string name, string desc, Func<bool> completeFunc, Action onComplete)
+ {
+ _completeFunc = completeFunc;
+ Name = name;
+ Description = desc;
+ this.onComplete = onComplete;
+ }
+
+ private Action onComplete = null;
+
+ public void Complete()
+ {
+ onComplete?.Invoke();
+ }
+ }
+
+ /// <summary>
+ /// Storyline management class.
+ /// </summary>
+ public static class Story
+ {
+ public static StoryContext Context { get; private set; }
+ public static event Action<string> StoryComplete;
+ public static List<Objective> CurrentObjectives { get; private set; }
+
+ public static void PushObjective(string name, string desc, Func<bool> completeFunc, Action onComplete)
+ {
+ if (CurrentObjectives == null)
+ CurrentObjectives = new List<Objective>();
+
+ var currentObjective = new Objective(name, desc, completeFunc, onComplete);
+ CurrentObjectives.Add(currentObjective);
+ var t = new Thread(() =>
+ {
+ var obj = currentObjective;
+ while (!obj.IsComplete)
+ {
+ Thread.Sleep(5000);
+ }
+ CurrentObjectives.Remove(obj);
+ obj.Complete();
+ });
+ t.IsBackground = true;
+ t.Start();
+
+ Console.WriteLine("NEW OBJECTIVE:");
+ Console.WriteLine("A new objective has been added to your system. Run sos.status to find out what you need to do.");
+ }
+
+
+ /// <summary>
+ /// Starts the storyline with the specified Storyline ID.
+ /// </summary>
+ /// <param name="stid">The storyline ID to start.</param>
public static void Start(string stid)
{
foreach (var exec in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
@@ -59,8 +146,26 @@ namespace ShiftOS.Engine
var story = attrib as StoryAttribute;
if(story.StoryID == stid)
{
- mth.Invoke(null, null);
- SaveSystem.CurrentSave.StoriesExperienced.Add(stid);
+ new Thread(() =>
+ {
+ Context = new Engine.StoryContext
+ {
+ Id = stid,
+ Method = mth,
+ AutoComplete = true,
+ };
+ SaveSystem.CurrentSave.PickupPoint = Context.Id;
+ Context.OnComplete += () =>
+ {
+ StoryComplete?.Invoke(stid);
+ SaveSystem.CurrentSave.PickupPoint = null;
+ };
+ mth.Invoke(null, null);
+ if (Context.AutoComplete)
+ {
+ Context.MarkComplete();
+ }
+ }).Start();
return;
}
}
@@ -78,231 +183,12 @@ namespace ShiftOS.Engine
#endif
}
-
+ [Obsolete("Please use Story.Start() in tandem with [StoryAttribute].")]
public static void RunFromInternalResource(string resource_id)
{
- var t = typeof(Properties.Resources);
-
- foreach(var prop in t.GetProperties(System.Reflection.BindingFlags.NonPublic | BindingFlags.Static))
- {
- if(prop.Name == resource_id)
- {
- if(prop.PropertyType == typeof(string))
- {
- WriteStory(prop.GetValue(null) as string);
-
- return;
- }
- }
- }
- throw new ArgumentException("Couldn't find resource ID inside the engine: " + resource_id);
- }
-
-
- public string Character { get; set; }
- public List<string> Lines { get; set; }
-
- public static void Start()
- {
- Console.WriteLine();
- if(SaveSystem.CurrentSave.StoryPosition == 5)
- {
- StartDevXLies();
- }
- }
-
- public static void StartDevXLies()
- {
- int chatProgress = 0;
- //bool LoopStuck = false;
- string textToWrite = "";
- const int TYPE_SPEED_MS = 45;
- bool done = false;
- bool write = true;
-
- while (done == false) {
- write = true;
- switch (chatProgress)
- {
- case 0:
- textToWrite = "User joined: @" + SaveSystem.CurrentSave.Username;
- break;
- case 1:
- textToWrite = $"Hello, {SaveSystem.CurrentSave.Username}.";
- break;
- case 2: //If C:\ShiftOS doesn't exist the player won't notice this is here.
- if (Directory.Exists(Paths.GetPath("classic")))
- {
- textToWrite = "I see you've participated in my previous ShiftOS experiment. Welcome back, Shifter. I assume you know lots about ShiftOS, but there are some updates I have to tell you.";
- }
- else
- {
- write = false;
- }
- break;
- case 3: //DevX hates ShiftOS-Next secretly.
- if (Directory.Exists(Paths.GetPath("classic") + "-Next"))
- {
- textToWrite = "Hmmmm.... looking at my sentience records, I see you've participated in ShiftOS-Next. This is gonna be difficult.";
- }
- else
- {
- write = false;
- }
- break;
- case 4:
- textToWrite = "There's a lot that has changed within ShiftOS.";
- break;
- case 5:
- textToWrite = "First off, I want to tell you a bit about myself in case you don't already know.";
- break;
- case 6:
- textToWrite = "My name is DevX. I am the architect of ShiftOS. I have chosen you to take part in helping me out with it.";
- break;
- case 7:
- textToWrite = "You see, in my past attempts it has all been about an evolving operating system and seeing how the users work with it...";
- break;
- case 8:
- textToWrite = "Almost one hundred percent of the time, people have found out it was an experiment and they could simply return to their regular system with a specific upgrade.";
- break;
- case 9:
- textToWrite = "But now, I want to try something different - something unique.";
- break;
- case 10:
- textToWrite = "ShiftOS is the same as it has been in my previous attempts, but now, your goal is to gain as much wealth and power as possible.";
- break;
- case 11:
- textToWrite = "Right now you are inside my segregation LAN. Only you and me exist within this domain. You are free from other users unless I create them.";
- break;
- case 12:
- textToWrite = "Since you have proved your sentience, I have a task for you outside the segregation LAN.";
- break;
- case 13:
- textToWrite = "But first... you need to be taught a few things.";
- break;
- case 14:
- textToWrite = "First off, when I bring you into my multi-user domain, you'll first want to establish as much wealth as possible.";
- break;
- case 15:
- textToWrite = "Wealth comes in the form of Codepoints - a currency used among users of the multi-user domain.";
- break;
- case 16:
- textToWrite = @"You can get Codepoints by doing the following:
-
- - Stealing them from other users
- - Extracting them from inactive/unverified sentiences
- - Using specific scripts/programs within ShiftOS
- - Creating paid scripts/applications within ShiftOS";
- break;
- case 17:
- textToWrite = "You can use Codepoints to buy upgrades using the 'shiftorium.buy' command, or you can use them to pay other users, or scripts.";
- break;
- case 18:
- textToWrite = "Within the multi-user domain you are free to do whatever you want. Larcany, theft, deceiving, lies, and distribution of malware is permitted under my watch.";
- break;
- case 19:
- textToWrite = "Do whatever you have to to get Codepoints.";
- break;
- case 20:
- textToWrite = "Then use them to make yourself stronger by buying upgrades at the shiftorium.";
- break;
- case 21:
- textToWrite = "If you want to get a bit devious within the multi-user domain, look around for scripts that will expose user account information.";
- break;
- case 22:
- textToWrite = "Or just spread a virus around the mud.";
- break;
- case 23:
- textToWrite = "Or you can be the 'good' guy and stop these attacks and gain the trust of other users.";
- break;
- case 24:
- textToWrite = "It's up to you. Just, don't mess with my system. You won't want me coming to you after that. I'm watching.";
- break;
- case 25:
- textToWrite = "User left chat: @" + SaveSystem.CurrentSave.Username;
- done = true;
- SaveSystem.CurrentSave.StoryPosition++;
- TerminalBackend.InvokeCommand("sos.save");
- break;
-
- }
-
- if (write == true)
- {
- Console.WriteLine();
- Console.Write("DevX: ");
- foreach(char c in textToWrite)
- {
- Console.Beep(750, TYPE_SPEED_MS);
- if (c == '\n')
- {
-
- }
- else if (c == '\r')
- {
- Console.WriteLine();
- }
- else
- {
- Console.Write(c);
- }
- }
- Thread.Sleep(1000);
- }
- chatProgress += 1;
- }
}
- public static void WriteStory(string json)
- {
- var thread = new Thread(new ThreadStart(() =>
- {
- var story = JsonConvert.DeserializeObject<Story>(json);
-
- const int TYPESPEED = 45;
-
- foreach (var line in story.Lines)
- {
- var localized = Localization.Parse(line);
-
-
- if (line.StartsWith("cmd:"))
- {
- string[] cmdsplit = line.Replace("cmd:", "").Split(' ');
- switch (cmdsplit[0])
- {
- case "givecp":
- SaveSystem.TransferCodepointsFrom(story.Character, Convert.ToInt32(cmdsplit[1]));
- break;
- }
- }
- else
- {
- Console.Write(story.Character + ": ");
-
- foreach (var c in localized)
- {
- Console.Beep(1024, TYPESPEED);
- if (c == '\r')
- {
-
- }
- else if (c == '\n')
- Console.WriteLine();
- else
- Console.Write(c);
- }
-
- Console.WriteLine();
- Thread.Sleep(1000);
- }
- }
- Console.Write($"{SaveSystem.CurrentSave.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ");
- }));
- thread.IsBackground = true;
- thread.Start();
- }
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
@@ -322,6 +208,9 @@ namespace ShiftOS.Engine
StoryID = id;
}
+ /// <summary>
+ /// Gets the storyline ID stored in this attribute.
+ /// </summary>
public string StoryID { get; private set; }
}
diff --git a/ShiftOS_TheReturn/TerminalBackend.cs b/ShiftOS_TheReturn/TerminalBackend.cs
index 9c57aa8..09ef3d6 100644
--- a/ShiftOS_TheReturn/TerminalBackend.cs
+++ b/ShiftOS_TheReturn/TerminalBackend.cs
@@ -24,6 +24,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
@@ -34,12 +35,26 @@ using static ShiftOS.Engine.SaveSystem;
namespace ShiftOS.Engine
{
+ /// <summary>
+ /// Backend for the ShiftOS terminal.
+ /// </summary>
public static class TerminalBackend
{
+ /// <summary>
+ /// Occurs when a command is processed.
+ /// </summary>
public static event Action<string, string> CommandProcessed;
+ /// <summary>
+ /// Gets or sets whether the current command is elevated.
+ /// </summary>
public static bool Elevated { get; set; }
+ /// <summary>
+ /// Parses command-line arguments using the ShiftOS syntax and stores them in a <see cref="Dictionary{string, string}"/>, removing the parsed text from the original string.
+ /// </summary>
+ /// <param name="text">The text to parse.</param>
+ /// <returns><see cref="Dictionary{string, string}"/> containing the parsed arguments.</returns>
public static Dictionary<string, string> GetArgs(ref string text)
{
bool shouldParse = false;
@@ -64,8 +79,23 @@ namespace ShiftOS.Engine
return JsonConvert.DeserializeObject<Dictionary<string, string>>(args);
}
+ /// <summary>
+ /// String representing the last command entered by the user.
+ /// </summary>
public static string LastCommand = "";
+ /// <summary>
+ /// Gets the output of the last command.
+ /// </summary>
+ public static string LastCommandBuffer { get; private set; }
+
+ /// <summary>
+ /// Invokes a ShiftOS terminal command.
+ /// </summary>
+ /// <param name="ns">The command's namespace.</param>
+ /// <param name="command">The command name.</param>
+ /// <param name="arguments">The command arguments.</param>
+ /// <param name="isRemote">Whether the command should be sent through Remote Terminal Session (RTS).</param>
public static void InvokeCommand(string ns, string command, Dictionary<string, string> arguments, bool isRemote = false)
{
try
@@ -78,13 +108,7 @@ namespace ShiftOS.Engine
if (!commandWasClient && !string.IsNullOrWhiteSpace(ns))
{
- PrefixEnabled = false;
-
- ServerManager.SendMessage("script", $@"{{
- user: ""{ns}"",
- script: ""{command}"",
- args: ""{GetSentArgs(arguments)}""
-}}");
+ Console.WriteLine("Error: Command not found.");
}
CommandProcessed?.Invoke(ns + "." + command, JsonConvert.SerializeObject(arguments));
@@ -97,6 +121,11 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Transforms a <see cref="Dictionary{String, String}"/> of arguments to a <see cref="Dictionary{String, Object}"/>.
+ /// </summary>
+ /// <param name="argss">The original argument dictionary to convert.</param>
+ /// <returns>The converted dictionary.</returns>
public static string GetSentArgs(Dictionary<string, string> argss)
{
Dictionary<string, object> args = new Dictionary<string, object>();
@@ -107,26 +136,239 @@ namespace ShiftOS.Engine
return JsonConvert.SerializeObject(args);
}
- public static void InvokeCommand(string text, bool isRemote = false)
+ public class TerminalCommand
{
- try
+ public override int GetHashCode()
+ {
+ int hash = 0;
+ foreach (char c in ToString())
+ {
+ hash += (int)c;
+ }
+ return hash;
+ }
+
+ public Namespace NamespaceInfo { get; set; }
+ public Command CommandInfo { get; set; }
+
+ public List<string> RequiredArguments { get; set; }
+ public string Dependencies { get; set; }
+
+ public MethodInfo CommandHandler;
+
+ public Type CommandType;
+
+ public override string ToString()
{
- if (string.IsNullOrWhiteSpace(text))
+ StringBuilder sb = new StringBuilder();
+ sb.Append(this.NamespaceInfo.name);
+ sb.Append(".");
+ sb.Append(this.CommandInfo.name);
+ if (this.RequiredArguments.Count > 0)
+ {
+ sb.Append("{");
+ foreach (var arg in RequiredArguments)
+ {
+ sb.Append(arg);
+ sb.Append(":");
+ if (RequiredArguments.IndexOf(arg) < RequiredArguments.Count - 1)
+ sb.Append(',');
+ }
+ sb.Append("}");
+ }
+ sb.Append("|");
+ sb.Append(CommandHandler.Name + "()");
+ return sb.ToString();
+ }
+
+ public bool RequiresElevation { get; set; }
+
+ public void Invoke(Dictionary<string, object> args)
+ {
+ List<string> errors = new List<string>();
+ bool requiresAuth = false;
+ if (!KernelWatchdog.IsSafe(this))
+ {
+ if (SaveSystem.CurrentUser.Permissions == Objects.UserPermissions.Admin)
+ requiresAuth = true;
+ else
+ errors.Add("You can't run this command - you do not have permission.");
+ }
+ if (errors.Count > 0)
+ {
+ foreach (var error in errors)
+ {
+ Console.WriteLine("Command error: " + error);
+ }
return;
+ }
+ if (requiresAuth)
+ {
+ Infobox.PromptText("Enter your password.", "This command requires you to have elevated permissions. Please enter your password to confirm this action.", (pass) =>
+ {
+ if (pass == SaveSystem.CurrentUser.Password)
+ {
+ var uname = SaveSystem.CurrentUser.Username;
+ SaveSystem.CurrentUser = SaveSystem.CurrentSave.Users.FirstOrDefault(x => x.Username == "root");
+ try
+ {
+ var h = CommandHandler;
+ h.Invoke(null, new[] { args });
+ }
+ catch
+ {
+ var h = CommandHandler;
+ h.Invoke(null, null);
+ }
+ SaveSystem.CurrentUser = SaveSystem.CurrentSave.Users.FirstOrDefault(x => x.Username == uname);
+ }
+ else
+ {
+ Infobox.Show("Access denied.", "Incorrect password provided. The command will not run.");
+ }
+ }, true);
+ }
+
+ try
+ {
+ CommandHandler.Invoke(null, new[] { args });
+ }
+ catch
+ {
+ CommandHandler.Invoke(null, null);
+ }
+ }
+ }
+
+ public class MemoryTextWriter : System.IO.TextWriter
+ {
+ public override Encoding Encoding
+ {
+ get
+ {
+ return Encoding.Unicode;
+ }
+ }
+
+ private StringBuilder sb = null;
+
+ public MemoryTextWriter()
+ {
+ sb = new StringBuilder();
+ }
+
+ public override string ToString()
+ {
+ return sb.ToString();
+ }
+
+ public override void Write(char value)
+ {
+ sb.Append(value);
+ }
+
+ public override void WriteLine()
+ {
+ sb.AppendLine();
+ }
+
+ public override void Write(string value)
+ {
+ sb.Append(value);
+ }
+
+ public override void Close()
+ {
+ sb.Clear();
+ sb = null;
+ base.Close();
+ }
+
+ public override void WriteLine(string value)
+ {
+ sb.AppendLine(value);
+ }
+ }
+
+ public static List<TerminalCommand> Commands { get; private set; }
+
+ public static void PopulateTerminalCommands()
+ {
+ Commands = new List<TerminalCommand>();
+ foreach(var exec in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
+ {
+ if(exec.ToLower().EndsWith(".exe") || exec.ToLower().EndsWith(".dll"))
+ {
+ try
+ {
+ var asm = Assembly.LoadFile(exec);
+ foreach(var type in asm.GetTypes())
+ {
+ var ns = type.GetCustomAttributes(false).FirstOrDefault(x => x is Namespace) as Namespace;
+ if(ns != null)
+ {
+ foreach(var mth in type.GetMethods(BindingFlags.Public | BindingFlags.Static))
+ {
+ var cmd = mth.GetCustomAttributes(false).FirstOrDefault(x => x is Command);
+ if(cmd != null)
+ {
+ var tc = new TerminalCommand();
+ tc.RequiresElevation = !(type.GetCustomAttributes(false).FirstOrDefault(x => x is KernelModeAttribute) == null);
+ tc.NamespaceInfo = ns;
+
+ tc.CommandInfo = cmd as Command;
+ tc.RequiresElevation = tc.RequiresElevation || !(mth.GetCustomAttributes(false).FirstOrDefault(x => x is KernelModeAttribute) == null);
+ tc.RequiredArguments = new List<string>();
+ foreach (var arg in mth.GetCustomAttributes(false).Where(x=>x is RequiresArgument))
+ {
+ var rarg = arg as RequiresArgument;
+ tc.RequiredArguments.Add(rarg.argument);
+ }
+ var rupg = mth.GetCustomAttributes(false).FirstOrDefault(x => x is RequiresUpgradeAttribute) as RequiresUpgradeAttribute;
+ if (rupg != null)
+ tc.Dependencies = rupg.Upgrade;
+ else
+ tc.Dependencies = "";
+ tc.CommandType = type;
+ tc.CommandHandler = mth;
+ if (!Commands.Contains(tc))
+ Commands.Add(tc);
+ }
+ }
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ Console.WriteLine("[termdb] Error: " + e.ToString());
+ }
+ }
+ }
+ Console.WriteLine("[termdb] " + Commands.Count + " commands found.");
+ }
+
+ /// <summary>
+ /// Invokes a ShiftOS terminal command.
+ /// </summary>
+ /// <param name="text">The full command text in regular ShiftOS syntax</param>
+ /// <param name="isRemote">Whether the command should be sent through Remote Terminal Session (RTS).</param>
+ public static void InvokeCommand(string text, bool isRemote = false)
+ {
+ if (string.IsNullOrWhiteSpace(text))
+ return;
+ var tw = new MemoryTextWriter();
+ Console.SetOut(tw);
+ try
+ {
var args = GetArgs(ref text);
bool commandWasClient = RunClient(text, args, isRemote);
if (!commandWasClient)
{
- PrefixEnabled = false;
-
- ServerManager.SendMessage("script", $@"{{
- user: ""{text.Split('.')[0]}"",
- script: ""{text.Split('.')[1]}"",
- args: ""{GetSentArgs(args)}""
-}}");
+ Console.WriteLine("Error: Command not found.");
+
}
CommandProcessed?.Invoke(text, GetSentArgs(args));
}
@@ -136,21 +378,48 @@ namespace ShiftOS.Engine
PrefixEnabled = true;
}
+ string buffer = tw.ToString();
+ LastCommandBuffer = buffer;
+ Console.SetOut(new TerminalTextWriter());
+ if(!isRemote)
+ Console.Write(buffer);
+
}
+ /// <summary>
+ /// Gets or sets whether the user prefix is printed after a command completes.
+ /// </summary>
public static bool PrefixEnabled { get; set; }
+ /// <summary>
+ /// Gets or sets whether the user is in a story plot, and thus, the terminal input should be disabled.
+ /// </summary>
public static bool InStory { get; set; }
+ /// <summary>
+ /// Another latest command string.
+ /// </summary>
public static string latestCommmand = "";
+ /// <summary>
+ /// Occurs when the engine requests a Terminal to be open.
+ /// </summary>
public static event EmptyEventHandler TerminalRequested;
+ /// <summary>
+ /// Opens a Terminal.
+ /// </summary>
internal static void OpenTerminal()
{
TerminalRequested?.Invoke();
}
+ /// <summary>
+ /// Determines if the specified command method can be ran in RTS
+ /// </summary>
+ /// <param name="mth">The method to scan</param>
+ /// <param name="isRemote">Is the user in an RTS session?</param>
+ /// <returns>Whether the command can be run.</returns>
public static bool CanRunRemotely(MethodInfo mth, bool isRemote)
{
if (!isRemote)
@@ -165,12 +434,26 @@ namespace ShiftOS.Engine
return true;
}
+ /// <summary>
+ /// Runs a command on the client-side.
+ /// </summary>
+ /// <param name="ns">The command's namespace.</param>
+ /// <param name="cmd">The command name.</param>
+ /// <param name="args">The command's arguments.</param>
+ /// <param name="isRemote">Whether the command should be ran through RTS.</param>
+ /// <returns>Whether the command ran successfully.</returns>
public static bool RunClient(string ns, string cmd, Dictionary<string, string> args, bool isRemote = false)
{
return RunClient(ns + "." + cmd, args, isRemote);
}
-
+ /// <summary>
+ /// Runs a command on the client.
+ /// </summary>
+ /// <param name="text">The command text.</param>
+ /// <param name="argss">The command arguments.</param>
+ /// <param name="isRemote">Whether the command should be ran through RTS.</param>
+ /// <returns>Whether the command ran successfully.</returns>
public static bool RunClient(string text, Dictionary<string, string> argss, bool isRemote = false)
{
Dictionary<string, object> args = new Dictionary<string, object>();
@@ -181,291 +464,93 @@ namespace ShiftOS.Engine
return RunClient(text, args, isRemote);
}
+ /// <summary>
+ /// Runs a command on the client.
+ /// </summary>
+ /// <param name="text">The command text.</param>
+ /// <param name="args">The command arguments.</param>
+ /// <param name="isRemote">Whether the command should be run in RTS.</param>
+ /// <returns>Whether the command ran successfully.</returns>
public static bool RunClient(string text, Dictionary<string, object> args, bool isRemote = false)
{
latestCommmand = text;
//Console.WriteLine(text + " " + "{" + string.Join(",", args.Select(kv => kv.Key + "=" + kv.Value).ToArray()) + "}" + " " + isRemote);
- foreach (var asmExec in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
+
+ string[] split = text.Split('.');
+ var cmd = Commands.FirstOrDefault(x => x.NamespaceInfo.name == split[0] && x.CommandInfo.name == split[1]);
+ if (cmd == null)
+ return false;
+ if (!Shiftorium.UpgradeInstalled(cmd.Dependencies))
+ return false;
+ bool res = false;
+ foreach (var arg in cmd.RequiredArguments)
{
- try
+ if (!args.ContainsKey(arg))
{
- var asm = Assembly.LoadFile(asmExec);
-
- var types = asm.GetTypes();
- foreach (var type in types)
- {
- if (Shiftorium.UpgradeAttributesUnlocked(type))
- {
- foreach (var a in type.GetCustomAttributes(false))
- {
- if (a is Namespace)
- {
- var ns = a as Namespace;
- if (text.Split('.')[0] == ns.name)
- {
- if (KernelWatchdog.IsSafe(type))
- {
- if (KernelWatchdog.CanRunOffline(type))
- {
- foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Static))
- {
- if (Shiftorium.UpgradeAttributesUnlocked(method))
- {
- if (CanRunRemotely(method, isRemote))
- {
- foreach (var ma in method.GetCustomAttributes(false))
- {
- if (ma is Command)
- {
- var cmd = ma as Command;
- if (text.Split('.')[1] == cmd.name)
- {
- if (KernelWatchdog.IsSafe(method))
- {
- if (KernelWatchdog.CanRunOffline(method))
- {
- var attr = method.GetCustomAttribute<CommandObsolete>();
-
- if (attr != null)
- {
- string newcommand = attr.newcommand;
- if (attr.warn)
- {
- Console.WriteLine(Localization.Parse((newcommand == "" ? "{ERROR}" : "{WARN}") + attr.reason, new Dictionary<string, string>() {
- {"%newcommand", newcommand}
- }));
- }
- if (newcommand != "")
- {
- // redo the entire process running newcommand
-
- return RunClient(newcommand, args);
- }
- }
-
- var requiresArgs = method.GetCustomAttributes<RequiresArgument>();
- bool error = false;
- bool providedusage = false;
-
- foreach (RequiresArgument argument in requiresArgs)
- {
- if (!args.ContainsKey(argument.argument))
- {
-
- if (!providedusage)
- {
- string usageparse = "{COMMAND_" + ns.name.ToUpper() + "_" + cmd.name.ToUpper() + "_USAGE}";
- if (usageparse == Localization.Parse(usageparse))
- usageparse = "";
- else
- usageparse = Shiftorium.UpgradeInstalled("help_usage") ? Localization.Parse("{ERROR}{USAGE}" + usageparse, new Dictionary<string, string>() {
- {"%ns", ns.name},
- {"%cmd", cmd.name}
- }) : "";
-
- Console.WriteLine(usageparse);
-
- providedusage = true;
- }
- if (Shiftorium.UpgradeInstalled("help_usage"))
- {
- Console.WriteLine(Localization.Parse("{ERROR_ARGUMENT_REQUIRED}", new Dictionary<string, string>() {
- {"%argument", argument.argument}
- }));
- }
- else
- {
- Console.WriteLine(Localization.Parse("{ERROR_ARGUMENT_REQUIRED_NO_USAGE}"));
- }
-
- error = true;
- }
- }
-
- if (error)
- {
- throw new Exception("{ERROR_COMMAND_WRONG}");
- }
-
- try
- {
- return (bool)method.Invoke(null, new[] { args });
- }
- catch (TargetInvocationException e)
- {
- Console.WriteLine(Localization.Parse("{ERROR_EXCEPTION_THROWN_IN_METHOD}"));
- Console.WriteLine(e.InnerException.Message);
- Console.WriteLine(e.InnerException.StackTrace);
- return true;
- }
- catch
- {
- return (bool)method.Invoke(null, new object[] { });
- }
- }
- else
- {
- Console.Write("<");
- ConsoleEx.Bold = true;
- ConsoleEx.ForegroundColor = ConsoleColor.DarkRed;
- Console.Write("session_mgr");
- ConsoleEx.ForegroundColor = SkinEngine.LoadedSkin.TerminalForeColorCC;
- ConsoleEx.Bold = false;
- Console.Write(">");
- ConsoleEx.Italic = true;
- ConsoleEx.ForegroundColor = ConsoleColor.DarkYellow;
- Console.WriteLine(" You cannot run this command while disconnected from the multi-user domain..");
- return true;
-
- }
- }
- else
- {
- if (SaveSystem.CurrentUser.Permissions == Objects.UserPermissions.Admin)
- {
- Infobox.PromptText("Elevate to root mode", "This command cannot be run as a regular user. To run this command, please enter your password to elevate to root mode temporarily.", (pass) =>
- {
- if (pass == SaveSystem.CurrentUser.Password)
- {
- KernelWatchdog.EnterKernelMode();
- RunClient(text, args, isRemote);
- KernelWatchdog.LeaveKernelMode();
- }
- else
- {
- Infobox.Show("Access denied.", "You did not type in the correct password.");
- }
- }, true);
- return true;
- }
- Console.Write("<");
- ConsoleEx.Bold = true;
- ConsoleEx.ForegroundColor = ConsoleColor.DarkRed;
- Console.Write("watchdog");
- ConsoleEx.ForegroundColor = SkinEngine.LoadedSkin.TerminalForeColorCC;
- ConsoleEx.Bold = false;
- Console.Write(">");
- ConsoleEx.Italic = true;
- ConsoleEx.ForegroundColor = ConsoleColor.DarkYellow;
- Console.WriteLine(" You cannot run this command. You do not have permission. Incident reported.");
- KernelWatchdog.Log("potential_sys_breach", "user attempted to run kernel mode command " + text + " - watchdog has prevented this, good sir.");
- return true;
- }
- }
- }
-
-
- }
- }
- }
- else
- {
- Console.WriteLine(text + " cannot be ran in a remote session");
- return true;
- }
- }
-
- }
-
-
- else
- {
- Console.Write("<");
- ConsoleEx.Bold = true;
- ConsoleEx.ForegroundColor = ConsoleColor.DarkRed;
- Console.Write("session_mgr");
- ConsoleEx.ForegroundColor = SkinEngine.LoadedSkin.TerminalForeColorCC;
- ConsoleEx.Bold = false;
- Console.Write(">");
- ConsoleEx.Italic = true;
- ConsoleEx.ForegroundColor = ConsoleColor.DarkYellow;
- Console.WriteLine(" You cannot run this command while disconnected from the multi-user domain..");
- return true;
-
- }
-
- }
- else
- {
- if (SaveSystem.CurrentUser.Permissions == Objects.UserPermissions.Admin)
- {
- Infobox.PromptText("Elevate to root mode", "This command cannot be run as a regular user. To run this command, please enter your password to elevate to root mode temporarily.", (pass) =>
- {
- if (pass == SaveSystem.CurrentUser.Password)
- {
- KernelWatchdog.EnterKernelMode();
- RunClient(text, args, isRemote);
- KernelWatchdog.LeaveKernelMode();
- }
- else
- {
- Infobox.Show("Access denied.", "You did not type in the correct password.");
- }
- }, true);
- return true;
- }
- Console.Write("<");
- ConsoleEx.Bold = true;
- ConsoleEx.ForegroundColor = ConsoleColor.DarkRed;
- Console.Write("watchdog");
- ConsoleEx.ForegroundColor = SkinEngine.LoadedSkin.TerminalForeColorCC;
- ConsoleEx.Bold = false;
- Console.Write(">");
- ConsoleEx.Italic = true;
- ConsoleEx.ForegroundColor = ConsoleColor.DarkYellow;
- Console.WriteLine(" You cannot run this command. You do not have permission. Incident reported.");
- KernelWatchdog.Log("potential_sys_breach", "user attempted to run kernel mode command " + text + " - watchdog has prevented this, good sir.");
- return true;
- }
- }
- }
- }
- }
- }
+ res = true;
+ Console.WriteLine("You are missing an argument with the key \"" + arg + "\".");
}
- catch { }
}
- return false;
+ if (res == true)
+ return true;
+ try
+ {
+ cmd.Invoke(args);
+ }
+ catch(Exception ex)
+ {
+ Console.WriteLine("Command error: " + ex.Message);
+ }
+
+ return true;
}
+
+ /// <summary>
+ /// Prints the user prompt to the terminal.
+ /// </summary>
public static void PrintPrompt()
{
+ Console.WriteLine();
if (SaveSystem.CurrentSave != null && CurrentUser != null)
{
- ConsoleEx.BackgroundColor = SkinEngine.LoadedSkin.TerminalBackColorCC;
- ConsoleEx.Italic = false;
- ConsoleEx.Underline = false;
-
- ConsoleEx.ForegroundColor = ConsoleColor.Magenta;
- ConsoleEx.Bold = true;
-
- Console.Write(SaveSystem.CurrentUser.Username);
- ConsoleEx.Bold = false;
- ConsoleEx.ForegroundColor = ConsoleColor.Gray;
- Console.Write("@");
- ConsoleEx.Italic = true;
- ConsoleEx.Bold = true;
- ConsoleEx.ForegroundColor = ConsoleColor.Yellow;
- Console.Write(SaveSystem.CurrentSave.SystemName);
- ConsoleEx.Italic = false;
- ConsoleEx.Bold = false;
- ConsoleEx.ForegroundColor = ConsoleColor.Gray;
- Console.Write(":~");
- Console.ForegroundColor = ConsoleColor.White;
- ConsoleEx.Italic = true;
- if (KernelWatchdog.InKernelMode == true)
- Console.Write("#");
- else
- Console.Write("$");
- ConsoleEx.Italic = false;
- ConsoleEx.Bold = false;
- ConsoleEx.ForegroundColor = SkinEngine.LoadedSkin.TerminalForeColorCC;
- Console.Write(" ");
+ ConsoleEx.BackgroundColor = SkinEngine.LoadedSkin.TerminalBackColorCC;
+ ConsoleEx.Italic = false;
+ ConsoleEx.Underline = false;
+
+ ConsoleEx.ForegroundColor = ConsoleColor.Magenta;
+ ConsoleEx.Bold = true;
+
+ Console.Write(SaveSystem.CurrentUser.Username);
+ ConsoleEx.Bold = false;
+ ConsoleEx.ForegroundColor = ConsoleColor.Gray;
+ Console.Write("@");
+ ConsoleEx.Italic = true;
+ ConsoleEx.Bold = true;
+ ConsoleEx.ForegroundColor = ConsoleColor.Yellow;
+ Console.Write(SaveSystem.CurrentSave.SystemName);
+ ConsoleEx.Italic = false;
+ ConsoleEx.Bold = false;
+ ConsoleEx.ForegroundColor = ConsoleColor.Gray;
+ Console.Write(":~");
+ Console.ForegroundColor = ConsoleColor.White;
+ ConsoleEx.Italic = true;
+ if (KernelWatchdog.InKernelMode == true)
+ Console.Write("#");
+ else
+ Console.Write("$");
+ ConsoleEx.Italic = false;
+ ConsoleEx.Bold = false;
+ ConsoleEx.ForegroundColor = SkinEngine.LoadedSkin.TerminalForeColorCC;
+ Console.Write(" ");
+ ConsoleEx.Flush();
}
}
-
+ /// <summary>
+ /// Static constructor for <see cref="TerminalBackend"/>.
+ /// </summary>
static TerminalBackend()
{
ServerMessageReceived onMessageReceived = (msg) =>
@@ -477,7 +562,7 @@ namespace ShiftOS.Engine
if (TerminalBackend.PrefixEnabled)
{
- text3 = text4.Remove(0, $"{SaveSystem.CurrentSave.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ".Length);
+ text3 = text4.Remove(0, $"{SaveSystem.CurrentUser.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ".Length);
}
IsForwardingConsoleWrites = true;
if (TerminalBackend.InStory == false)
@@ -486,7 +571,7 @@ namespace ShiftOS.Engine
}
if (TerminalBackend.PrefixEnabled)
{
- Console.Write($"{SaveSystem.CurrentSave.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ");
+ Console.Write($"{SaveSystem.CurrentUser.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ");
}
IsForwardingConsoleWrites = false;
}
@@ -501,7 +586,7 @@ namespace ShiftOS.Engine
string pass = a["password"] as string;
string sys = a["sysname"] as string;
string guid = msg.GUID;
- if (SaveSystem.CurrentSave.Username == uName && SaveSystem.CurrentSave.Password == pass && CurrentSave.SystemName == sys)
+ if (SaveSystem.CurrentUser.Username == uName && SaveSystem.CurrentSave.Password == pass && CurrentSave.SystemName == sys)
{
ForwardGUID = guid;
ServerManager.SendMessage("trm_handshake_accept", $@"{{
@@ -511,7 +596,7 @@ namespace ShiftOS.Engine
IsForwardingConsoleWrites = true;
InvokeCommand("sos.status");
- Console.Write($"{SaveSystem.CurrentSave.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ");
+ Console.Write($"{SaveSystem.CurrentUser.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ");
IsForwardingConsoleWrites = false;
}
}
@@ -520,11 +605,25 @@ namespace ShiftOS.Engine
ServerManager.MessageReceived += onMessageReceived;
}
+ /// <summary>
+ /// Gets whether the terminal backend is forwarding console write requests through RTS to a remote client.
+ /// </summary>
public static bool IsForwardingConsoleWrites { get; internal set; }
+
+ /// <summary>
+ /// Gets the RTS forward GUID.
+ /// </summary>
public static string ForwardGUID { get; internal set; }
+ /// <summary>
+ /// Occurs when the user inputs text in a Terminal.
+ /// </summary>
public static event TextSentEventHandler TextSent;
+ /// <summary>
+ /// Fakes the user inputting text to a Terminal.
+ /// </summary>
+ /// <param name="text">The text to input.</param>
public static void SendText(string text)
{
TextSent?.Invoke(text);
diff --git a/ShiftOS_TheReturn/TerminalTextWriter.cs b/ShiftOS_TheReturn/TerminalTextWriter.cs
index 55e27cf..63e88eb 100644
--- a/ShiftOS_TheReturn/TerminalTextWriter.cs
+++ b/ShiftOS_TheReturn/TerminalTextWriter.cs
@@ -32,12 +32,28 @@ using System.Windows.Forms;
namespace ShiftOS.Engine
{
+ /// <summary>
+ /// Backend class for forwarding <see cref="System.Console"/> to the ShiftOS terminal.
+ /// </summary>
public class TerminalTextWriter : TextWriter
{
- [System.Runtime.InteropServices.DllImport("user32.dll")]
- public static extern bool LockWindowUpdate(IntPtr hWndLock);
+ public TerminalTextWriter()
+ {
+ ConsoleEx.OnFlush = () =>
+ {
+ System.Diagnostics.Debug.WriteLine("[terminal] " + buffer);
+ Desktop.InvokeOnWorkerThread(() =>
+ {
+ UnderlyingControl?.Write(buffer);
+ buffer = "";
+ });
+ };
+ }
+ /// <summary>
+ /// Gets the encoding format for this <see cref="TextWriter"/>. God bless the Unicode Consortiem.
+ /// </summary>
public override Encoding Encoding
{
get
@@ -46,6 +62,9 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Gets the underlying <see cref="ITerminalWidget"/> that this <see cref="TerminalTextWriter"/> is forwarding to.
+ /// </summary>
public ITerminalWidget UnderlyingControl
{
get
@@ -54,6 +73,9 @@ namespace ShiftOS.Engine
}
}
+ /// <summary>
+ /// Moves the caret to the last character in the textbox.
+ /// </summary>
public void select()
{
Desktop.InvokeOnWorkerThread(new Action(() =>
@@ -63,6 +85,10 @@ namespace ShiftOS.Engine
}));
}
+ /// <summary>
+ /// Write a character to the Terminal.
+ /// </summary>
+ /// <param name="value">The character to write.</param>
public override void Write(char value)
{
if (TerminalBackend.IsForwardingConsoleWrites)
@@ -74,14 +100,24 @@ namespace ShiftOS.Engine
}
else
{
- Desktop.InvokeOnWorkerThread(new Action(() =>
- {
- UnderlyingControl?.Write(value.ToString());
- select();
- }));
+ buffer += value;
+ }
+ }
+
+ private string buffer = "";
+
+ public string Buffer
+ {
+ get
+ {
+ return buffer;
}
}
+ /// <summary>
+ /// Write text to the Terminal, followed by a newline.
+ /// </summary>
+ /// <param name="value">The text to write.</param>
public override void WriteLine(string value)
{
if (TerminalBackend.IsForwardingConsoleWrites)
@@ -94,18 +130,20 @@ namespace ShiftOS.Engine
else
{
- Desktop.InvokeOnWorkerThread(new Action(() =>
- {
- UnderlyingControl?.WriteLine(value);
- select();
- }));
+ buffer += value + Environment.NewLine;
+ ConsoleEx.Flush();
}
}
+ [Obsolete("Stub.")]
public void SetLastText()
{
}
+ /// <summary>
+ /// Write text to the Terminal.
+ /// </summary>
+ /// <param name="value">The text to write.</param>
public override void Write(string value)
{
if (TerminalBackend.IsForwardingConsoleWrites)
@@ -120,8 +158,7 @@ namespace ShiftOS.Engine
Desktop.InvokeOnWorkerThread(new Action(() =>
{
- UnderlyingControl?.Write(value.ToString());
- select();
+ buffer += value;
}));
}
}
diff --git a/ShiftOS_TheReturn/TutorialManager.cs b/ShiftOS_TheReturn/TutorialManager.cs
index ea78cd8..13df153 100644
--- a/ShiftOS_TheReturn/TutorialManager.cs
+++ b/ShiftOS_TheReturn/TutorialManager.cs
@@ -30,10 +30,18 @@ using System.Threading.Tasks;
namespace ShiftOS.Engine
{
+ [Obsolete("This isn't used... I don't think...")]
public static class TutorialManager
{
+ /// <summary>
+ /// The tutorial frontend.
+ /// </summary>
private static ITutorial _tut = null;
+ /// <summary>
+ /// Registers a tutorial frontend to the backend.
+ /// </summary>
+ /// <param name="tut"></param>
public static void RegisterTutorial(ITutorial tut)
{
IsInTutorial = false;
diff --git a/ShiftOS_TheReturn/UniteClient.cs b/ShiftOS_TheReturn/UniteClient.cs
deleted file mode 100644
index 1136b5c..0000000
--- a/ShiftOS_TheReturn/UniteClient.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-using Newtonsoft.Json;
-
-namespace ShiftOS.Unite
-{
- public class UniteClient
- {
- public string Token { get; private set; }
- public string BaseURL { get; private set; }
-
- public string GetDisplayNameId(string id)
- {
- return MakeCall("/API/GetDisplayName/" + id);
- }
-
- public PongHighscoreModel GetPongHighscores()
- {
- return JsonConvert.DeserializeObject<PongHighscoreModel>(MakeCall("/API/GetPongHighscores"));
- }
-
- public UniteClient(string baseurl, string usertoken)
- {
- BaseURL = baseurl;
- Token = usertoken;
- }
-
- internal string MakeCall(string url)
- {
- var webrequest = WebRequest.Create(BaseURL + url);
- webrequest.Headers.Add("Authentication: Token " + Token);
- using (var response = webrequest.GetResponse())
- {
- using (var stream = response.GetResponseStream())
- {
- using (var reader = new System.IO.StreamReader(stream))
- {
- return reader.ReadToEnd();
- }
- }
- }
- }
-
- public int GetPongCP()
- {
- return Convert.ToInt32(MakeCall("/API/GetPongCP"));
- }
-
- public int GetPongLevel()
- {
- return Convert.ToInt32(MakeCall("/API/GetPongLevel"));
- }
-
- public void SetPongLevel(int value)
- {
- MakeCall("/API/SetPongLevel/" + value.ToString());
- }
-
- public void SetPongCP(int value)
- {
- MakeCall("/API/SetPongCP/" + value.ToString());
- }
-
- public string GetEmail()
- {
- return MakeCall("/API/GetEmail");
- }
-
- public string GetSysName()
- {
- return MakeCall("/API/GetSysName");
- }
-
- public void SetSysName(string value)
- {
- MakeCall("/API/SetSysName/" + value);
- }
-
- public string GetDisplayName()
- {
- return MakeCall("/API/GetDisplayName");
- }
-
- public void SetDisplayName(string value)
- {
- MakeCall("/API/SetDisplayName/" + value.ToString());
- }
-
- public string GetFullName()
- {
- return MakeCall("/API/GetFullName");
- }
-
- public void SetFullName(string value)
- {
- MakeCall("/API/SetFullName/" + value.ToString());
- }
-
-
- public long GetCodepoints()
- {
- return Convert.ToInt64(MakeCall("/API/GetCodepoints"));
- }
-
- public void SetCodepoints(long value)
- {
- MakeCall("/API/SetCodepoints/" + value.ToString());
- }
- }
-
- public class PongHighscoreModel
- {
- public int Pages { get; set; }
- public PongHighscore[] Highscores { get; set; }
- }
-
- public class PongHighscore
- {
- public string UserId { get; set; }
- public int Level { get; set; }
- public long CodepointsCashout { get; set; }
- }
-}
diff --git a/ShiftOS_TheReturn/UniteTestCommands.cs b/ShiftOS_TheReturn/UniteTestCommands.cs
deleted file mode 100644
index 7a83e44..0000000
--- a/ShiftOS_TheReturn/UniteTestCommands.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ShiftOS.Engine
-{
- [Namespace("unite")]
- public static class UniteTestCommands
- {
- [Command("setdisplayname")]
- [RequiresArgument("name")]
- public static bool SetDisplayName(Dictionary<string, object> args)
- {
- string dname = args["name"].ToString();
- var unite = new ShiftOS.Unite.UniteClient("http://getshiftos.ml", SaveSystem.CurrentSave.UniteAuthToken);
- unite.SetDisplayName(dname);
- return true;
- }
-
- [Command("login")]
- [RequiresArgument("username")]
- [RequiresArgument("password")]
- public static bool LoginTest(Dictionary<string, object> args)
- {
- string u = args["username"].ToString();
- string p = args["password"].ToString();
- var webrequest = HttpWebRequest.Create("http://getshiftos.ml/Auth/Login?appname=ShiftOS&appdesc=ShiftOS+client&version=1_0_beta_2_4");
- string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{u}:{p}"));
- webrequest.Headers.Add("Authentication: Basic " + base64);
- var response = webrequest.GetResponse();
- var str = response.GetResponseStream();
- var reader = new System.IO.StreamReader(str);
- string result = reader.ReadToEnd();
- Console.WriteLine("Server returned: " + result);
- reader.Close();
- str.Close();
- str.Dispose();
- response.Dispose();
-
- return true;
- }
-
- [Command("linklogin")]
- [RequiresArgument("username")]
- [RequiresArgument("password")]
- public static bool LinkLogin(Dictionary<string, object> args)
- {
- string u = args["username"].ToString();
- string p = args["password"].ToString();
- var webrequest = HttpWebRequest.Create("http://getshiftos.ml/Auth/Login?appname=ShiftOS&appdesc=ShiftOS+client&version=1_0_beta_2_4");
- string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{u}:{p}"));
- webrequest.Headers.Add("Authentication: Basic " + base64);
- var response = webrequest.GetResponse();
- var str = response.GetResponseStream();
- var reader = new System.IO.StreamReader(str);
- string result = reader.ReadToEnd();
- //If we get this far, the token is OURS. :D
- SaveSystem.CurrentSave.UniteAuthToken = result;
- Console.WriteLine("Unite says \"Access Granted!\"");
- SaveSystem.SaveGame();
- reader.Close();
- str.Close();
- str.Dispose();
- response.Dispose();
-
- return true;
- }
-
-
- }
-}
diff --git a/ShiftOS_TheReturn/UserManagementCommands.cs b/ShiftOS_TheReturn/UserManagementCommands.cs
index 1c3c0ed..a64c99c 100644
--- a/ShiftOS_TheReturn/UserManagementCommands.cs
+++ b/ShiftOS_TheReturn/UserManagementCommands.cs
@@ -7,11 +7,19 @@ using ShiftOS.Objects;
namespace ShiftOS.Engine
{
+ /// <summary>
+ /// Administrative user management terminal commands.
+ /// </summary>
[Namespace("admin")]
[KernelMode]
[RequiresUpgrade("mud_fundamentals")]
public static class AdminUserManagementCommands
{
+ /// <summary>
+ /// Add a user to the system.
+ /// </summary>
+ /// <param name="args">Command arguments.</param>
+ /// <returns>Command result.</returns>
[Command("add", description = "Add a user to the system.", usage ="name:")]
[RequiresArgument("name")]
public static bool AddUser(Dictionary<string, object> args)
@@ -35,6 +43,12 @@ namespace ShiftOS.Engine
return true;
}
+ /// <summary>
+ /// Remove a user from the system.
+ /// </summary>
+ /// <param name="args">Command arguments.</param>
+ /// <returns>Command result.</returns>
+
[Command("remove", description = "Remove a user from the system.", usage = "name:")]
[RequiresArgument("name")]
public static bool RemoveUser(Dictionary<string, object> args)
@@ -47,12 +61,25 @@ namespace ShiftOS.Engine
}
var user = SaveSystem.CurrentSave.Users.FirstOrDefault(x => x.Username == name);
+ if(user.Username != SaveSystem.CurrentUser.Username)
+ {
+ Console.WriteLine("Error: Cannot remove yourself.");
+ return true;
+ }
SaveSystem.CurrentSave.Users.Remove(user);
Console.WriteLine($"Removing user \"{name}\" from system...");
SaveSystem.SaveGame();
return true;
}
+
+
+ /// <summary>
+ /// Set access control level for a user.
+ /// </summary>
+ /// <param name="args">Command arguments.</param>
+ /// <returns>Command result.</returns>
+
[Command("set_acl")]
[RequiresArgument("user")]
[RequiresArgument("val")]
@@ -116,14 +143,76 @@ namespace ShiftOS.Engine
return true;
}
+ /// <summary>
+ /// List all users in the system.
+ /// </summary>
+ /// <param name="args">Command arguments.</param>
+ /// <returns>Command result.</returns>
+
+ [Command("users", description = "Get a list of all users on the system.")]
+ public static bool GetUsers()
+ {
+ foreach (var u in SaveSystem.CurrentSave.Users)
+ {
+ if (u.Username == SaveSystem.CurrentUser.Username)
+ {
+ ConsoleEx.ForegroundColor = ConsoleColor.Magenta;
+ ConsoleEx.Bold = true;
+ }
+ else
+ {
+ ConsoleEx.ForegroundColor = ConsoleColor.Gray;
+ ConsoleEx.Bold = false;
+ }
+ Console.WriteLine(u.Username);
+ }
+ return true;
+ }
}
+ /// <summary>
+ /// Non-administrative user management terminal commands.
+ /// </summary>
[Namespace("user")]
[RequiresUpgrade("mud_fundamentals")]
public static class UserManagementCommands
{
+ /// <summary>
+ /// Log in as another user.
+ /// </summary>
+ /// <param name="args">Command arguments.</param>
+ /// <returns>Command result.</returns>
+ [Command("login", description = "Log in as another user.")]
+ [RequiresArgument("user")]
+ [RequiresArgument("pass")]
+ public static bool Login(Dictionary<string, object> args)
+ {
+ string user = args["user"].ToString();
+ string pass = args["pass"].ToString();
+
+ var usr = SaveSystem.CurrentSave.Users.FirstOrDefault(x => x.Username == user);
+ if(usr==null)
+ {
+ Console.WriteLine("Error: No such user.");
+ return true;
+ }
+ if (usr.Password != pass)
+ {
+ Console.WriteLine("Access denied.");
+ return true;
+ }
+
+ SaveSystem.CurrentUser = usr;
+ Console.WriteLine("Access granted.");
+ return true;
+ }
+ /// <summary>
+ /// Set the password for the current user.
+ /// </summary>
+ /// <param name="args">Command arguments.</param>
+ /// <returns>Command result.</returns>
[Command("setpass", description ="Allows you to set your password to a new value.", usage ="old:,new:")]
[RequiresArgument("old")]
[RequiresArgument("new")]
diff --git a/ShiftOS_TheReturn/VirusEngine.cs b/ShiftOS_TheReturn/VirusEngine.cs
deleted file mode 100644
index 650db92..0000000
--- a/ShiftOS_TheReturn/VirusEngine.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.
- */
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Newtonsoft.Json;
-using static ShiftOS.Objects.ShiftFS.Utils;
-
-
-namespace ShiftOS.Engine
-{
- public static class VirusEngine
- {
- public static void InfectFile(string file, string virusid)
- {
- var infected = new List<string>();
- var hData = GetHeaderText(file);
-
- if (hData == "")
- {
- infected.Add(virusid);
- }
- else
- {
- infected = JsonConvert.DeserializeObject<List<string>>(hData);
- if (!infected.Contains(virusid))
- infected.Add(virusid);
- }
-
- SetHeaderText(file, JsonConvert.SerializeObject(infected));
- }
-
- public static void DisinfectFile(string file, int threatlevel)
- {
- var infected = new List<string>();
- var hData = GetHeaderText(file);
-
- if (hData != "")
- {
- infected = JsonConvert.DeserializeObject<List<string>>(hData);
- for (int i = 0; i < infected.Count; i++)
- {
- string[] splitID = infected[i].Split('.');
- int th = Convert.ToInt32(splitID[splitID.Length - 1]);
- if (th <= threatlevel)
- {
- infected.RemoveAt(i);
- }
- }
- }
-
- SetHeaderText(file, JsonConvert.SerializeObject(infected));
- }
-
- internal static string[] FindAllVirusesInFile(string file)
- {
- string hdata = GetHeaderText(file);
- return (hdata != "") ? new string[0] : JsonConvert.DeserializeObject<string[]>(hdata);
- }
-
- }
-
- public abstract class Virus
- {
- /// <summary>
- /// Inject the virus into system memory by running it.
- /// </summary>
- public abstract void Activate();
-
- /// <summary>
- /// Terminate the virus.
- /// </summary>
- public abstract void Deactivate();
-
- public abstract int ThreatLevel { get; }
-
- public abstract string Signature { get; }
-
- public abstract string Type { get; }
- }
-}