diff --git a/README.md b/README.md
index e443d279..9964aab9 100644
--- a/README.md
+++ b/README.md
@@ -11,10 +11,11 @@ Note: Use at your own risk, as this is an early version that is expected to unde
To compile this project, you will need to follow these steps:
-1. Copy everything in the `Kerbal Space Program 2\KSP2_x64_Data\Managed` folder into the `external_dlls/` folder.
-2. Run one of the build scripts (see below for more info) and copy the contents from the correct build output directory into the KSP2 root directory.
-3. Launch KSP2 and wait until the title screen appears. You should see a mods folder under the `SpaceWarp` folder.
-4. Drag any mods that follow the structure below into that mods folder.
+1. Install NuGet
+2. Copy everything in the `Kerbal Space Program 2\KSP2_x64_Data\Managed` folder into the `external_dlls/` folder.
+3. Run one of the build scripts (see below for more info) and copy the contents from the correct build output directory into the KSP2 root directory.
+4. Launch KSP2 and wait until the title screen appears. You should see a mods folder under the `SpaceWarp` folder.
+5. Drag any mods that follow the structure below into that mods folder.
Mods are currently implemented as monobehaviours with two fields: a `Logger` for logging and a `Manager` that points to Spacewarp. A mod template generator exists as a Python script.
diff --git a/SpaceWarp/API/Logging/ModLogger.cs b/SpaceWarp/API/Logging/ModLogger.cs
index 4d1157a0..42ba2486 100644
--- a/SpaceWarp/API/Logging/ModLogger.cs
+++ b/SpaceWarp/API/Logging/ModLogger.cs
@@ -31,7 +31,7 @@ private void InternalLog(LogLevel level, string message)
protected override void Log(LogLevel level, string message)
{
- if ((int)level >= StartupManager.SpaceWarpObject.SpaceWarpConfiguration.LogLevel)
+ if ((int)level >= SpaceWarpGlobalConfiguration.Instance.LogLevel)
{
InternalLog(level,message);
}
diff --git a/SpaceWarp/API/SpaceWarpGlobalConfiguration.cs b/SpaceWarp/API/SpaceWarpGlobalConfiguration.cs
index f8b24b80..40061e23 100644
--- a/SpaceWarp/API/SpaceWarpGlobalConfiguration.cs
+++ b/SpaceWarp/API/SpaceWarpGlobalConfiguration.cs
@@ -1,13 +1,63 @@
-using System.ComponentModel;
+using System;
+using System.ComponentModel;
+using System.IO;
using Newtonsoft.Json;
+using UnityEngine;
namespace SpaceWarp.API
{
[JsonObject(MemberSerialization.OptIn)]
public class SpaceWarpGlobalConfiguration
{
- [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
- [DefaultValue((int)Logging.LogLevel.Info)]
+ public static SpaceWarpGlobalConfiguration Instance;
+ private const string MODS_FOLDER_NAME = "Mods";
+ public static string SPACE_WARP_PATH = Directory.GetCurrentDirectory() + "/SpaceWarp/";
+ public static string MODS_FULL_PATH = SPACE_WARP_PATH + MODS_FOLDER_NAME;
+
+ private static string SPACEWARP_CONFIG_FULL_PATH = MODS_FULL_PATH + "/" + SPACE_WARP_CONFIG_FILE_NAME;
+ private const string SPACE_WARP_CONFIG_FILE_NAME = "space_warp_config.json";
+
+ ///
+ /// Loading Global Configuration and puting it into Instance.
+ ///
+ public static void Init()
+ {
+ if (!File.Exists(SPACEWARP_CONFIG_FULL_PATH))
+ {
+ Instance = new SpaceWarpGlobalConfiguration();
+ Instance.ApplyDefaultValues();
+ }
+ else
+ {
+ try
+ {
+ string json = File.ReadAllText(SPACEWARP_CONFIG_FULL_PATH);
+ Instance = JsonConvert.DeserializeObject(json);
+ }
+ catch (Exception exception)
+ {
+ //TODO: log this in a nicer way, for now I guess we can just construct a new logger
+ Debug.LogError($"Loading space warp config failed\nException: {exception}");
+
+ File.Delete(SPACEWARP_CONFIG_FULL_PATH);
+ Init();
+ return;
+ }
+ }
+
+ try
+ {
+ File.WriteAllLines(SPACEWARP_CONFIG_FULL_PATH, new[] { JsonConvert.SerializeObject(Instance) });
+ }
+ catch (Exception exception)
+ {
+ //TODO: log this in a nicer way, for now I guess we can just construct a new logger
+ Debug.LogError($"Saving the spacewarp config failed\nException: {exception}");
+ }
+ }
+
+ [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
+ [DefaultValue((int)Logging.LogLevel.Info)]
public int LogLevel { get; set; }
public void ApplyDefaultValues()
diff --git a/SpaceWarp/API/SpaceWarpManager.cs b/SpaceWarp/API/SpaceWarpManager.cs
index 1f02777a..cb628510 100644
--- a/SpaceWarp/API/SpaceWarpManager.cs
+++ b/SpaceWarp/API/SpaceWarpManager.cs
@@ -32,9 +32,6 @@ public class SpaceWarpManager : Manager
public static string SPACE_WARP_PATH = Directory.GetCurrentDirectory() + "/SpaceWarp/";
public static string MODS_FULL_PATH = SPACE_WARP_PATH + MODS_FOLDER_NAME;
- private const string SPACE_WARP_CONFIG_FILE_NAME = "space_warp_config.json";
- private static string SPACEWARP_CONFIG_FULL_PATH = MODS_FULL_PATH + "/" + SPACE_WARP_CONFIG_FILE_NAME;
-
public SpaceWarpGlobalConfiguration SpaceWarpConfiguration;
private readonly List _allModScripts = new List();
@@ -56,7 +53,6 @@ protected override void Start()
private void Initialize()
{
InitializeConfigManager();
- InitializeSpaceWarpConfig();
InitializeModLogger();
@@ -481,7 +477,7 @@ private void InitializeModConfig(Type config_type, string mod_id)
_modLogger.Error($"Loading mod config failed\nException: {exception}");
File.Delete(config_path);
- InitializeSpaceWarpConfig();
+ InitializeModConfig(config_type, mod_id);
return;
}
}
@@ -500,46 +496,6 @@ private void InitializeModConfig(Type config_type, string mod_id)
configurationManager.Add(mod_id,(config_type,modConfiguration,config_path));
}
}
-
- ///
- /// Tried to find the SpaceWarp config file in the game, if none is found one is created.
- ///
- ///
- private void InitializeSpaceWarpConfig()
- {
- if (!File.Exists(SPACEWARP_CONFIG_FULL_PATH))
- {
- SpaceWarpConfiguration = new SpaceWarpGlobalConfiguration();
- SpaceWarpConfiguration.ApplyDefaultValues();
- }
- else
- {
- try
- {
- string json = File.ReadAllText(SPACEWARP_CONFIG_FULL_PATH);
- SpaceWarpConfiguration = JsonConvert.DeserializeObject(json);
- }
- catch (Exception exception)
- {
- //TODO: log this in a nicer way, for now I guess we can just construct a new logger
- new ModLogger("Space Warp").Error($"Loading space warp config failed\nException: {exception}");
-
- File.Delete(SPACEWARP_CONFIG_FULL_PATH);
- InitializeSpaceWarpConfig();
- return;
- }
- }
-
- try
- {
- File.WriteAllLines(SPACEWARP_CONFIG_FULL_PATH, new[] { JsonConvert.SerializeObject(SpaceWarpConfiguration) });
- }
- catch(Exception exception)
- {
- //TODO: log this in a nicer way, for now I guess we can just construct a new logger
- new ModLogger("Space Warp").Error($"Saving the spacewarp config failed\nException: {exception}");
- }
- }
///
/// Initializes a mod object.
diff --git a/SpaceWarp/Compilation/ModCompiler.cs b/SpaceWarp/Compilation/ModCompiler.cs
index 0c7ead37..db5f1e26 100644
--- a/SpaceWarp/Compilation/ModCompiler.cs
+++ b/SpaceWarp/Compilation/ModCompiler.cs
@@ -107,8 +107,26 @@ private static Assembly CompileNewAssemblyAndCache(string modID, string modSrcPa
var compilation = CSharpCompilation.Create(modID + ".dll", trees, references,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true));
+
var result = compilation.Emit(CACHE_LOCATION + modID + ".dll");
- return Assembly.LoadFile(CACHE_LOCATION + modID + ".dll");
+ foreach (Diagnostic diagnostic in result.Diagnostics)
+ {
+ if (diagnostic.WarningLevel == 0)
+ {
+ _logger.Error(diagnostic.ToString());
+ }
+ else
+ {
+ _logger.Info(diagnostic.ToString());
+ }
+ }
+
+ _logger.Info(result.ToString());
+ if (!result.Success)
+ {
+ File.Delete(CACHE_LOCATION + modID + ".dll");
+ }
+ return !result.Success ? null : Assembly.LoadFile(CACHE_LOCATION + modID + ".dll");
}
}
}
\ No newline at end of file
diff --git a/SpaceWarp/Entrypoint.cs b/SpaceWarp/Entrypoint.cs
index d29f2213..08651d40 100644
--- a/SpaceWarp/Entrypoint.cs
+++ b/SpaceWarp/Entrypoint.cs
@@ -1,5 +1,6 @@
using HarmonyLib;
using KSP.Logging;
+using SpaceWarp.API;
using SpaceWarp.UI;
using System.Reflection;
using UnityEngine.SceneManagement;
@@ -22,6 +23,8 @@ public class SpaceWarpEntrypoint
///
public static void Start()
{
+ SpaceWarpGlobalConfiguration.Init();
+
SceneManager.sceneLoaded += OnSceneLoaded;
KspLogManager.AddLogCallback(SpaceWarpConsoleLogListener.LogCallback);
diff --git a/SpaceWarp/UI/ModConfigurationSection.cs b/SpaceWarp/UI/ModConfigurationSection.cs
index 4ed78ae8..10536300 100644
--- a/SpaceWarp/UI/ModConfigurationSection.cs
+++ b/SpaceWarp/UI/ModConfigurationSection.cs
@@ -8,7 +8,7 @@ public class ModConfigurationSection
{
public bool Open = false;
- public readonly List<(string name, FieldInfo info, object confAttribute)> Properties = new List<(string name, FieldInfo info, object confAttribute)>();
+ public readonly List<(string name, FieldInfo info, object confAttribute, string currentStringValue)> Properties = new List<(string name, FieldInfo info, object confAttribute, string currentStringValue)>();
public readonly List<(string path, ModConfigurationSection section)> SubSections = new List<(string path, ModConfigurationSection section)>();
private ModConfigurationSection TouchSubSection(string subsection)
@@ -25,7 +25,7 @@ private ModConfigurationSection TouchSubSection(string subsection)
return sub2;
}
- public void Insert(string[] path, (string name, FieldInfo info, object confAttribute) property)
+ public void Insert(string[] path, (string name, FieldInfo info, object confAttribute, string currentStringValue) property)
{
StringBuilder sb = new StringBuilder();
foreach (string t in path)
diff --git a/SpaceWarp/UI/ModConfigurationUI.cs b/SpaceWarp/UI/ModConfigurationUI.cs
index f0fa5630..1e570d05 100644
--- a/SpaceWarp/UI/ModConfigurationUI.cs
+++ b/SpaceWarp/UI/ModConfigurationUI.cs
@@ -5,6 +5,7 @@
using SpaceWarp.API.Configuration;
using SpaceWarp.API.Managers;
using UnityEngine;
+using UnityEngine.Serialization;
namespace SpaceWarp.UI
{
@@ -14,8 +15,7 @@ public class ModConfigurationUI : KerbalMonoBehaviour
public Type ConfigurationType;
public object ConfigurationObject;
- public string ModName;
- public string ModID;
+ [FormerlySerializedAs("ModID")] public string modID;
private int _windowWidth = 350;
private int _windowHeight = 700;
@@ -23,7 +23,7 @@ public class ModConfigurationUI : KerbalMonoBehaviour
private static GUIStyle _boxStyle;
- private readonly ModConfigurationSection _rootSection = new ModConfigurationSection();
+ private ModConfigurationSection _rootSection;
private void Awake()
{
@@ -33,6 +33,7 @@ private void Awake()
public void Start()
{
+ _rootSection = new ModConfigurationSection();
foreach (FieldInfo field in ConfigurationType.GetFields(BindingFlags.Instance | BindingFlags.Public))
{
object attribute;
@@ -48,17 +49,19 @@ public void Start()
ConfigFieldAttribute fieldAttribute = field.GetCustomAttribute();
- if (fieldAttribute != null)
+ if (fieldAttribute == null)
{
- attribute = fieldAttribute;
- attributeName = fieldAttribute.Name;
- _rootSection.Insert(section.Split(new []{'/'},StringSplitOptions.RemoveEmptyEntries), (attributeName, field, attribute));
+ // attribute = fieldAttribute;
+ // attributeName = fieldAttribute.Name;
+ // _rootSection.Insert(section.Split(new []{'/'},StringSplitOptions.RemoveEmptyEntries), (attributeName, field, attribute, field.GetValue(ConfigurationObject).ToString()));
+ continue;
}
-
attribute = fieldAttribute;
- attributeName = fieldAttribute?.Name;
+ attributeName = fieldAttribute.Name;
- _rootSection.Insert(section.Split(new []{'/'},StringSplitOptions.RemoveEmptyEntries), (attributeName, field, attribute));
+ var value = field.GetValue(ConfigurationObject);
+ _rootSection.Insert(section.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries),
+ (attributeName, field, attribute, value != null ? value.ToString() : ""));
}
_windowRect = new Rect((Screen.width * 0.15f), (Screen.height * 0.15f), 0, 0);
@@ -67,7 +70,7 @@ public void Start()
public void OnGUI()
{
int controlID = GUIUtility.GetControlID(FocusType.Passive);
- string header = $"{ModID} configuration";
+ string header = $"{modID} configuration";
GUILayoutOption width = GUILayout.Width((float)(_windowWidth * 0.5));
GUILayoutOption height = GUILayout.Height((float)(_windowHeight * 0.5));
@@ -75,34 +78,48 @@ public void OnGUI()
_windowRect = GUILayout.Window(controlID, _windowRect, FillWindow, header, width, height);
}
- private void EditorInputField(string fieldName, FieldInfo info)
+ private string EditorInputField(string fieldName, FieldInfo info, string current)
{
+ var result = "";
GUILayout.BeginHorizontal();
if (info.FieldType != typeof(bool))
{
GUILayout.Label(fieldName);
- string rawInputValue = GUILayout.TextField(info.GetValue(ConfigurationObject).ToString());
- object convertedInputValue = TypeDescriptor.GetConverter(info.FieldType).ConvertFromInvariantString(rawInputValue);
-
- info.SetValue(ConfigurationObject, convertedInputValue);
+ string rawInputValue = GUILayout.TextField(current);
+ result = rawInputValue;
+ try
+ {
+ object convertedInputValue = TypeDescriptor.GetConverter(info.FieldType)
+ .ConvertFromInvariantString(rawInputValue);
+ info.SetValue(ConfigurationObject, convertedInputValue);
+ }
+ catch
+ {
+ // ignored
+ }
}
else
{
bool toggleValue = GUILayout.Toggle((bool)info.GetValue(ConfigurationObject), fieldName);
-
+ result = toggleValue.ToString();
info.SetValue(ConfigurationObject, toggleValue);
}
GUILayout.EndHorizontal();
+ return result;
}
- private void EditorForField((string name, FieldInfo info, object confAttribute) field)
+ private string EditorForField((string name, FieldInfo info, object confAttribute, string currentStringValue) field)
{
if (field.confAttribute is ConfigFieldAttribute)
{
- EditorInputField(field.name, field.info);
+ return EditorInputField(field.name, field.info, field.currentStringValue);
+ }
+ else
+ {
+ return "";
}
}
@@ -118,9 +135,13 @@ private void SectionPropertyViewer(string sectionName, ModConfigurationSection s
return;
}
- foreach ((string name, FieldInfo info, object confAttribute) property in section.Properties)
+
+ for (int i = 0; i < section.Properties.Count; i++)
{
- EditorForField(property);
+ var prop = section.Properties[i];
+ var str = EditorForField(prop);
+ prop.currentStringValue = str;
+ section.Properties[i] = prop;
}
foreach ((string path, ModConfigurationSection section) sub in section.SubSections)
@@ -140,9 +161,12 @@ private void FillWindow(int windowID)
GUILayout.BeginVertical();
// These are the root properties
- foreach ((string name, FieldInfo info, object confAttribute) field in _rootSection.Properties)
+ for (int i = 0; i < _rootSection.Properties.Count; i++)
{
- EditorForField(field);
+ var prop = _rootSection.Properties[i];
+ var str = EditorForField(prop);
+ prop.currentStringValue = str;
+ _rootSection.Properties[i] = prop;
}
foreach ((string path, ModConfigurationSection section) section in _rootSection.SubSections)
@@ -155,7 +179,7 @@ private void FillWindow(int windowID)
//Run saving code from the configuration manager
if (ManagerLocator.TryGet(out ConfigurationManager configurationManager))
{
- configurationManager.UpdateConfiguration(ModID);
+ configurationManager.UpdateConfiguration(modID);
}
Destroy(this);
}
diff --git a/SpaceWarp/UI/ModListUI.cs b/SpaceWarp/UI/ModListUI.cs
index 5257c582..a9dae230 100644
--- a/SpaceWarp/UI/ModListUI.cs
+++ b/SpaceWarp/UI/ModListUI.cs
@@ -137,7 +137,7 @@ private void CreateModConfigurationUI()
configUI.ConfigurationType = config.configType;
configUI.ConfigurationObject = config.configObject;
- configUI.name = _selectedModInfo.name;
+ configUI.modID = _selectedMod;
go.SetActive(true);
}
diff --git a/SpaceWarp/UI/SpaceWarpConsole.cs b/SpaceWarp/UI/SpaceWarpConsole.cs
index 0461ea17..e2f8d61d 100644
--- a/SpaceWarp/UI/SpaceWarpConsole.cs
+++ b/SpaceWarp/UI/SpaceWarpConsole.cs
@@ -41,7 +41,6 @@ public void Start()
private void Awake()
{
- KspLogManager.AddLogCallback(LogCallback);
_windowWidth = (int)(Screen.width * 0.5f);
_windowHeight = (int)(Screen.height * 0.5f);
@@ -65,30 +64,7 @@ private void OnGUI()
_windowRect = GUILayout.Window(controlID, _windowRect, DrawConsole, header, width, height);
}
-
- private void LogCallback(string condition, string stackTrace, LogType type)
- {
- switch (type)
- {
- case LogType.Error:
- _debugMessages.Add($"[ERR] {condition}");
- break;
- case LogType.Assert:
- _debugMessages.Add($"[AST] {condition}");
- break;
- case LogType.Warning:
- _debugMessages.Add($"[WRN] {condition}");
- break;
- case LogType.Log:
- _debugMessages.Add($"[LOG] {condition}");
- break;
- case LogType.Exception:
- _debugMessages.Add($"[EXC] {condition}");
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(type), type, null);
- }
- }
+
private void Update()
{
if (Input.GetKey(KeyCode.LeftAlt) && Input.GetKeyDown(KeyCode.C))
@@ -102,8 +78,8 @@ private void DrawConsole(int windowID)
_boxStyle = GUI.skin.GetStyle("Box");
GUILayout.BeginVertical();
_scrollPosition = GUILayout.BeginScrollView(_scrollPosition, false, true);
-
- foreach (string debugMessage in _debugMessages)
+
+ foreach (string debugMessage in SpaceWarpConsoleLogListener.DebugMessages)
{
GUILayout.Label(debugMessage);
}
diff --git a/builder.py b/builder.py
index ed457429..674f5989 100644
--- a/builder.py
+++ b/builder.py
@@ -25,12 +25,46 @@ def clean():
if os.path.exists(os.path.join(SPACEWARP_DIR, "obj")):
shutil.rmtree(os.path.join(SPACEWARP_DIR, "obj"))
+def do_nuget_source():
+ sources_output = subprocess.run(["nuget", "sources", "list"], capture_output=True)
+
+ if not "bepinex" in str(sources_output.stdout, "utf-8").lower():
+ print("=> Adding BepInEx source to Nuget config...")
+
+ nuget_src_out = subprocess.run(["nuget", "sources", "add", "-Name", "BepInEx", "-Source", "https://nuget.bepinex.dev/v3/index.json"], capture_output=True)
+
+ print(" |=>| STDOUT")
+
+ for line in str(nuget_src_out.stdout, "utf-8").splitlines():
+ print(f" {line}")
+
+ print(" |=>| STDERR")
+
+ for line in str(nuget_src_out.stderr, "utf-8").splitlines():
+ print(f" {line}")
+
+ print("=> Restoring project dependencies...")
+
+ nuget_out = subprocess.run(["nuget", "restore"], capture_output=True)
+
+ print(" |=>| STDOUT")
+
+ for line in str(nuget_out.stdout, "utf-8").splitlines():
+ print(f" {line}")
+
+ print(" |=>| STDERR")
+
+ for line in str(nuget_out.stderr, "utf-8").splitlines():
+ print(f" {line}")
+
def build(release = False, doorstop = False):
build_type = "Doorstop" if doorstop else "BepInEx"
dotnet_args = ["dotnet", "build", os.path.join(SPACEWARP_DIR, "SpaceWarp.csproj"), "-c", "Release" if release else "Debug"]
build_output_dir = os.path.join(SPACEWARP_DIR, "bin", "Release" if release else "Debug")
output_dir = os.path.join(BUILD_DIR, build_type, "BepInEx", "plugins", "SpaceWarp")
+ do_nuget_source()
+
if doorstop:
dotnet_args.append("-p:DefineConstants=\"DOORSTOP_BUILD\"")
output_dir = os.path.join(BUILD_DIR, build_type, "SpaceWarp", "core")