diff --git a/Builds/Managed/Assembly-CSharp.dll b/Builds/Managed/Assembly-CSharp.dll
new file mode 100644
index 0000000..52ccdd3
Binary files /dev/null and b/Builds/Managed/Assembly-CSharp.dll differ
diff --git a/Builds/preview-mod/TestMod1.dll b/Builds/preview-mod/TestMod1.dll
new file mode 100644
index 0000000..4d4ac59
Binary files /dev/null and b/Builds/preview-mod/TestMod1.dll differ
diff --git a/ModLoader/Attributes/MyModEntryPoint.cs b/ModLoader/Attributes/MyModEntryPoint.cs
new file mode 100644
index 0000000..9744e21
--- /dev/null
+++ b/ModLoader/Attributes/MyModEntryPoint.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SFSML.Attributes
+{
+ public class MyModEntryPoint : Attribute
+ {
+ }
+}
diff --git a/ModLoader/Exceptions/MyCoreException.cs b/ModLoader/Exceptions/MyCoreException.cs
new file mode 100644
index 0000000..cd3fe4d
--- /dev/null
+++ b/ModLoader/Exceptions/MyCoreException.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SFSML.Exceptions
+{
+ class MyCoreException : Exception
+ {
+ public MyCaller caller;
+ public readonly string file;
+ public readonly string msg;
+ public MyCoreException(string message, string myFile) : base("Whoops something went wrong!")
+ {
+ this.file = myFile;
+ this.msg = message;
+ }
+
+ public class MyCaller
+ {
+ public readonly string function;
+ public readonly string file;
+ public MyCaller(string functionName, string fileName)
+ {
+ this.function = functionName;
+ this.file = fileName;
+ }
+ public string construct()
+ {
+ return function + "()" + " [" + file + "]";
+ }
+ }
+ }
+}
diff --git a/ModLoader/HookSystem/HookExceptions/NotHookedException.cs b/ModLoader/HookSystem/HookExceptions/NotHookedException.cs
new file mode 100644
index 0000000..48235ab
--- /dev/null
+++ b/ModLoader/HookSystem/HookExceptions/NotHookedException.cs
@@ -0,0 +1,26 @@
+/*
+ * Created by SharpDevelop.
+ * User: JordivdMolen
+ * Date: 2/15/2018
+ * Time: 10:35 AM
+ *
+ * Using this file for commercial purposes can result
+ * in violating the license!
+ */
+using System;
+using SFSML.HookSystem;
+
+namespace SFSML.HookSystem.HookExceptions
+{
+ ///
+ /// Description of NotHookedException.
+ ///
+ public class NotHookedException : Exception
+ {
+ public MyInitialHook target;
+ public NotHookedException(MyInitialHook tgt) : base("This hook is not registered in a MyBaseHookable")
+ {
+ this.target = tgt;
+ }
+ }
+}
diff --git a/ModLoader/HookSystem/MainHooks/MyGameLoadedHook.cs b/ModLoader/HookSystem/MainHooks/MyGameLoadedHook.cs
new file mode 100644
index 0000000..6627d98
--- /dev/null
+++ b/ModLoader/HookSystem/MainHooks/MyGameLoadedHook.cs
@@ -0,0 +1,17 @@
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SFSML.HookSystem.MainHooks
+{
+ class MyGameLoadedHook : MyBaseHook
+ {
+ public ModLoader core;
+ public MyGameLoadedHook(ModLoader coreLoader, String test)
+ {
+ this.core = coreLoader;
+ }
+ }
+}
diff --git a/ModLoader/HookSystem/MyBaseHook.cs b/ModLoader/HookSystem/MyBaseHook.cs
new file mode 100644
index 0000000..6b440cc
--- /dev/null
+++ b/ModLoader/HookSystem/MyBaseHook.cs
@@ -0,0 +1,81 @@
+/*
+ * Created by SharpDevelop.
+ * User: JordivdMolen
+ * Date: 2/14/2018
+ * Time: 9:26 PM
+ *
+ * Using this file for commercial purposes can result
+ * in violating the license!
+ */
+using System;
+using System.Collections.Generic;
+using SFSML.HookSystem.HookExceptions;
+using System.Reflection;
+
+namespace SFSML.HookSystem
+{
+ ///
+ /// Event-like system, baseclass.
+ ///
+ public abstract class MyBaseHook : MyInitialHook
+ {
+ private MyBaseHookable infested = null;
+ protected Func onInvoke = null;
+ public MyBaseHook()
+ {
+ this.baseType = typeof(T);
+ }
+
+ ///
+ /// setOnInvoke AKA Register hook as hookListener
+ ///
+ /// This function will be ran when the hook is casted
+ /// This object should be the object you are registering the hook on.
+ public void setOnInvoke(Func hook, MyBaseHookable root)
+ {
+ if (this.onInvoke == null)
+ {
+ this.onInvoke = hook;
+ root.registerListener(this);
+ }
+ else
+ {
+ throw new Exception("OnInvoke is already set @ setOnInvoke");
+ }
+ }
+
+ public T invoke(T e)
+ {
+ if (!(e is MyBaseHook))
+ {
+ throw new Exception("event has to be an instace of MyBaseHook @ Invoke");
+ }
+ if (!this.isListener())
+ {
+ throw new Exception("This hook is not a listener! @ Invoke");
+ }
+ MyBaseHook hookT = ((object) e) as MyBaseHook;
+ T invokeResult = this.onInvoke(e);
+ return invokeResult;
+ }
+
+
+ public Dictionary getEventArgumets()
+ {
+ Dictionary args = new Dictionary();
+ foreach (FieldInfo fi in this.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
+ {
+ if (fi.DeclaringType == typeof(T))
+ {
+ args[fi.Name] = fi;
+ }
+ }
+ return args;
+ }
+
+ public bool isListener()
+ {
+ return this.onInvoke != null;
+ }
+ }
+}
diff --git a/ModLoader/HookSystem/MyBaseHookable.cs b/ModLoader/HookSystem/MyBaseHookable.cs
new file mode 100644
index 0000000..748ee84
--- /dev/null
+++ b/ModLoader/HookSystem/MyBaseHookable.cs
@@ -0,0 +1,70 @@
+/*
+ * Created by SharpDevelop.
+ * User: JordivdMolen
+ * Date: 2/14/2018
+ * Time: 9:39 PM
+ *
+ * Using this file for commercial purposes can result
+ * in violating the license!
+ */
+using SFSML.Exceptions;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace SFSML.HookSystem
+{
+ ///
+ /// Description of MyBaseHookable.
+ ///
+ public class MyBaseHookable
+ {
+ private List hooks = new List();
+ public MyBaseHookable()
+ {
+ }
+
+ public void registerListener(MyBaseHook e)
+ {
+ if (!e.isListener())
+ {
+ throw new MyCoreException("This hook is not a listener! @ RegisterListener","registerListener>()");
+ }
+ this.hooks.Add(e);
+ }
+ public void removeListener(MyInitialHook e)
+ {
+ this.hooks.Remove(e);
+ }
+ public T castHook(T e)
+ {
+ T usedCaller = (T) ((MyInitialHook)(object)e).Clone();
+ MyBaseHook convertedBase = (Object) e as MyBaseHook;
+ Dictionary initialFields = convertedBase.getEventArgumets();
+ foreach (MyInitialHook initHook in this.hooks)
+ {
+ T ih = (T) (object) initHook;
+ MyBaseHook convertedHook = (MyBaseHook) initHook;
+ T afterInvoke = convertedHook.invoke(usedCaller);
+ convertedHook = (object) afterInvoke as MyBaseHook;
+ Dictionary initHookFields = convertedHook.getEventArgumets();
+ if (convertedHook.isCanceled())
+ {
+ convertedBase.forceCanceled(true);
+ }
+ foreach (String fieldName in initialFields.Keys)
+ {
+ FieldInfo orginField = initialFields[fieldName];
+ FieldInfo newField = initHookFields[fieldName];
+ object orginValue = orginField.GetValue(e);
+ object newValue = newField.GetValue(afterInvoke);
+ if (orginValue != newValue)
+ {
+ orginField.SetValue(e, newValue);
+ }
+ }
+ }
+ return (T) (object) convertedBase;
+ }
+ }
+}
diff --git a/ModLoader/HookSystem/MyInitialHook.cs b/ModLoader/HookSystem/MyInitialHook.cs
new file mode 100644
index 0000000..5314a2d
--- /dev/null
+++ b/ModLoader/HookSystem/MyInitialHook.cs
@@ -0,0 +1,38 @@
+using SFSML.HookSystem;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SFSML.HookSystem
+{
+ public class MyInitialHook : ICloneable
+ {
+ private MyBaseHookable infested = null;
+ protected Type baseType;
+ protected bool cancel = false;
+ public MyInitialHook()
+ {
+ }
+
+ public Type getInitialType()
+ {
+ return this.baseType;
+ }
+
+ public bool isCanceled()
+ {
+ return this.cancel;
+ }
+
+ public void forceCanceled(bool state)
+ {
+ this.cancel = state;
+ }
+
+ public object Clone()
+ {
+ return this.MemberwiseClone();
+ }
+ }
+}
diff --git a/ModLoader/ModLoader.cs b/ModLoader/ModLoader.cs
new file mode 100644
index 0000000..d11771a
--- /dev/null
+++ b/ModLoader/ModLoader.cs
@@ -0,0 +1,164 @@
+/*
+ * Created by SharpDevelop.
+ * User: JordivdMolen
+ * Date: 2/14/2018
+ * Time: 10:06 PM
+ *
+ * Using this file for commercial purposes can result
+ * in violating the license!
+ */
+using System;
+using System.Diagnostics;
+using System.IO;
+using UnityEngine;
+using System.Reflection;
+using SFSML.HookSystem;
+using SFSML.HookSystem.MainHooks;
+using SFSML.Exceptions;
+using SFSML.Attributes;
+
+namespace SFSML
+{
+ ///
+ /// The coreclass of SFSML.
+ ///
+ [MyModEntryPoint]
+ public class ModLoader : MyBaseHookable
+ {
+ public static MyConsole mainConsole;
+
+ public int loadedMods = 0;
+ private Canvas overlayObject = null;
+ public MyConsole myConsole;
+
+ public ModLoader()
+ {
+ if (Application.platform == RuntimePlatform.WindowsPlayer)
+ this.myConsole = new MyConsole();
+ mainConsole = this.myConsole;
+
+ }
+
+ public void startLoadProcedure()
+ {
+ mainConsole.log("Initiating load procedure", "Core");
+ this.performDirCheck();
+
+ this.loadPriorityMods();
+ this.loadMods();
+ }
+
+ public void toggleOverlay()
+ {
+ overlayObject.enabled = !overlayObject.enabled;
+ }
+
+ public string getMyBaseDirectory()
+ {
+ return Application.dataPath + "/SFSML/";
+ }
+
+ public string getMyModDirectory()
+ {
+ return Application.dataPath + "/SFSML/Mods/";
+ }
+
+ public string getMyDataDirectory()
+ {
+ return Application.dataPath + "/SFSML/Data/";
+ }
+
+ private void performDirCheck()
+ {
+ if (!Directory.Exists(this.getMyBaseDirectory()))
+ {
+ Directory.CreateDirectory(this.getMyBaseDirectory());
+ mainConsole.log("Created SFSML directory.", "DirChecker");
+ }
+ if (!Directory.Exists(this.getMyModDirectory()))
+ {
+ Directory.CreateDirectory(this.getMyModDirectory());
+ Directory.CreateDirectory(this.getMyModDirectory()+ "priority/");
+ Directory.CreateDirectory(this.getMyModDirectory() + "normal/");
+ mainConsole.log("Created Mods directory.", "DirChecker");
+ }
+ if (!Directory.Exists(this.getMyDataDirectory()))
+ {
+ Directory.CreateDirectory(this.getMyDataDirectory());
+ mainConsole.log("Created Data directory.", "DirChecker");
+ }
+
+ }
+ private void loadPriorityMods()
+ {
+ try
+ {
+ string[] priorityMods = Directory.GetFiles(this.getMyModDirectory() + "priority/");
+ foreach (string mod in priorityMods)
+ {
+ if (Path.GetExtension(mod) != ".dll") continue;
+ this.loadModFromFile(mod);
+ }
+ }
+ catch (MyCoreException e)
+ {
+ e.caller = new MyCoreException.MyCaller("loadPriorityMods", "ModLoader.cs");
+ }
+ catch (Exception e)
+ {
+ mainConsole.logError(e);
+ }
+
+ }
+ private void loadMods()
+ {
+ try
+ {
+ string[] normalMods = Directory.GetFiles(this.getMyModDirectory() + "normal/");
+ foreach (string mod in normalMods)
+ {
+ this.loadModFromFile(mod);
+ }
+ }
+ catch (MyCoreException e)
+ {
+ e.caller = new MyCoreException.MyCaller("loadMods", "ModLoader.cs");
+ }
+ catch (Exception e)
+ {
+ mainConsole.logError(e);
+ }
+ }
+ private void loadModFromFile(String modFile)
+ {
+ try
+ {
+ if (Path.GetExtension(modFile) != ".dll") return;
+ string modFileName = Path.GetFileNameWithoutExtension(modFile);
+ mainConsole.log("Loading mod: " + modFileName,"SFSML");
+ Assembly modAssembly = Assembly.LoadFrom(modFile);
+ MyMod entryObject = null;
+ foreach (Type modType in modAssembly.GetTypes())
+ {
+ object[] attributeList = modType.GetCustomAttributes(typeof(MyModEntryPoint), true);
+ if (attributeList.Length == 1)
+ {
+ entryObject = Activator.CreateInstance(modType) as MyMod;
+ }
+ }
+ string dataPath = this.getMyDataDirectory() + modFileName;
+ entryObject.assignDataPath(dataPath);
+ entryObject.Load();
+ mainConsole.log("Loaded " + entryObject.myName+".\n"+entryObject.myDescription+"\nVersion "+entryObject.myVersion, entryObject.myName);
+ }
+ catch (MyCoreException e)
+ {
+ e.caller = new MyCoreException.MyCaller("loadModFromFile", "ModLoader.cs");
+ }
+ catch (Exception e)
+ {
+ mainConsole.logError(e);
+ }
+ }
+ }
+}
diff --git a/ModLoader/MyConfig.cs b/ModLoader/MyConfig.cs
new file mode 100644
index 0000000..e9e4718
--- /dev/null
+++ b/ModLoader/MyConfig.cs
@@ -0,0 +1,74 @@
+using SFSML.Exceptions;
+using SFSML.HookSystem;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+
+namespace SFSML
+{
+ public class MyConfig
+ {
+ Type t;
+ private object configuration = null;
+ public readonly string configurationPath;
+ public MyConfig(string path, Type baseType)
+ {
+ this.t = baseType;
+ this.configurationPath = path;
+ this.loadConfiguration(baseType);
+ }
+
+ public T getConfiguration()
+ {
+ return (T) this.configuration;
+ }
+ public void loadConfiguration(Type configType)
+ {
+ if (!File.Exists(this.configurationPath))
+ {
+ object obj = Activator.CreateInstance(configType);
+ if (!(obj is IMyConfig))
+ {
+ throw new MyCoreException("configType is not part of a IMyConfig!", "MyConfig.cs");
+ }
+ IMyConfig cfg = obj as IMyConfig;
+ cfg.SetupDefaults();
+ this.configuration = cfg;
+ ((IMyConfig)this.configuration).setParent(this);
+ this.save();
+ }
+ String json = File.ReadAllText(this.configurationPath);
+ this.configuration = JsonUtility.FromJson(json, configType);
+ ((IMyConfig)this.configuration).setParent(this);
+ }
+
+ public void save()
+ {
+ string json = JsonUtility.ToJson(this.configuration);
+ string path = this.configurationPath;
+ File.WriteAllText(path, json);
+ }
+ }
+
+ public abstract class IMyConfig
+ {
+ [NonSerialized]
+ private MyConfig parent = null;
+ abstract public void SetupDefaults();
+ public void save()
+ {
+ this.parent.save();
+ }
+ public void setParent(MyConfig par)
+ {
+ if (this.parent == null)
+ {
+ this.parent = par;
+ }
+ }
+ }
+
+}
diff --git a/ModLoader/MyConsole.cs b/ModLoader/MyConsole.cs
new file mode 100644
index 0000000..d7781c9
--- /dev/null
+++ b/ModLoader/MyConsole.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace SFSML
+{
+ public class MyConsole
+ {
+ [DllImport("kernel32.dll")]
+ static extern IntPtr GetConsoleWindow();
+
+ [DllImport("user32.dll")]
+ static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
+
+ [DllImport("Kernel32.dll")]
+ private static extern bool AllocConsole();
+
+ const int SW_HIDE = 0;
+ const int SW_SHOW = 5;
+
+ private bool visible = false;
+
+ public MyConsole()
+ {
+ AllocConsole();
+ this.hideConsole();
+ Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true });
+ this.visible = false;
+ }
+ public void hideConsole()
+ {
+ ShowWindow(GetConsoleWindow(), SW_HIDE);
+ this.visible = false;
+ }
+ public void showConsole()
+ {
+ ShowWindow(GetConsoleWindow(), SW_SHOW);
+ this.visible = true;
+ }
+ public void toggleConsole()
+ {
+ if (this.visible)
+ {
+ this.hideConsole();
+ } else
+ {
+ this.showConsole();
+ }
+ }
+ public void logError(Exception e)
+ {
+ StackTrace st = new StackTrace(e, true);
+ StackFrame sf = st.GetFrame(0);
+ int line = sf.GetFileLineNumber();
+ string file = sf.GetFileName();
+ Console.WriteLine("##[ERROR]##");
+ Console.WriteLine(e.Message);
+ Console.WriteLine(e.StackTrace);
+ Console.WriteLine(line + "@"+file);
+ Console.WriteLine("##[ERROR]##");
+ }
+ public void log(String msg, String tag)
+ {
+ Console.WriteLine("["+ tag + "]: " + msg);
+ }
+ public void log(String msg)
+ {
+ this.log(msg, "Unkwn");
+ }
+
+ }
+}
diff --git a/ModLoader/MyMod.cs b/ModLoader/MyMod.cs
new file mode 100644
index 0000000..b5e8488
--- /dev/null
+++ b/ModLoader/MyMod.cs
@@ -0,0 +1,61 @@
+using SFSML.HookSystem;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SFSML
+{
+ public abstract class MyMod : MyBaseHookable
+ {
+ public readonly String myName;
+ public readonly String myDescription;
+ public readonly String myVersion;
+ private string dataPath;
+ private string configPath;
+ private MyConfig configurationObject;
+ private Type cfgType = null;
+ public MyMod(String name, String description, string version)
+ {
+ this.myName = name;
+ this.myDescription = description;
+ this.myVersion = version;
+ ModLoader.mainConsole.log("No MyConfig type specefied.", "MyMod");
+ }
+ public MyMod(String name, String description, string version, Type configurationType)
+ {
+ this.myName = name;
+ this.myDescription = description;
+ this.myVersion = version;
+ this.cfgType = configurationType;
+ ModLoader.mainConsole.log("Instanciating MyConfig.", "MyMod");
+ }
+ protected abstract void onLoad();
+ protected abstract void onUnload();
+ public void Load()
+ {
+ this.onLoad();
+ }
+ public void Unload()
+ {
+ this.onUnload();
+ }
+ public void assignDataPath(string path)
+ {
+ if (this.dataPath == null)
+ {
+ this.dataPath = path;
+ if (cfgType != null)
+ this.configurationObject = new MyConfig(path + ".cfg",this.cfgType);
+ }
+ }
+ public string getDataPath()
+ {
+ return this.dataPath;
+ }
+ public MyConfig config()
+ {
+ return configurationObject;
+ }
+ }
+}