diff --git a/.gitignore b/.gitignore index 66a104ce..a9263cf3 100644 --- a/.gitignore +++ b/.gitignore @@ -354,4 +354,4 @@ MigrationBackup/ build/ # Idea folder -.idea \ No newline at end of file +.idea diff --git a/Bundles/swconsoleui.bundle b/Bundles/swconsoleui.bundle index 70a34b4a..951a47f5 100644 Binary files a/Bundles/swconsoleui.bundle and b/Bundles/swconsoleui.bundle differ diff --git a/ExampleMod/Class1.cs b/ExampleMod/Class1.cs index 6ece2e52..3ffec4f6 100644 --- a/ExampleMod/Class1.cs +++ b/ExampleMod/Class1.cs @@ -1,15 +1,14 @@ -using SpaceWarp.API; +using SpaceWarp.API.Mods; -namespace ExampleMod +namespace ExampleMod; + +[MainMod] +public class ExampleModRunner : Mod { - [MainMod] - public class ExampleModRunner : Mod + public override void Initialize() { - public override void Initialize() - { - base.Initialize(); + base.Initialize(); - Logger.Info("Mod is initialized"); - } + Logger.Info("Mod is initialized"); } } \ No newline at end of file diff --git a/ExampleMod/ExampleMod.csproj b/ExampleMod/ExampleMod.csproj index 9376b5bb..d2d84dbe 100644 --- a/ExampleMod/ExampleMod.csproj +++ b/ExampleMod/ExampleMod.csproj @@ -1,62 +1,19 @@  - - + - Debug - AnyCPU - {F9A01E83-FA9A-4921-BF31-DB0770A8EA54} - Library - Properties - ExampleMod - ExampleMod - v4.7.2 - 512 + netstandard2.0 + 11 + true + false - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - ..\external_dlls\UnityEngine.CoreModule.dll - - - - - - - - {42fa2f7b-a595-44e8-8cd5-a9c30b80a667} - SpaceWarp - + + + + ..\external_dlls\Assembly-CSharp.dll + true + + - - diff --git a/ExampleMod/Properties/AssemblyInfo.cs b/ExampleMod/Properties/AssemblyInfo.cs deleted file mode 100644 index 66016cd4..00000000 --- a/ExampleMod/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ExampleMod")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ExampleMod")] -[assembly: AssemblyCopyright("Copyright © 2023")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("F9A01E83-FA9A-4921-BF31-DB0770A8EA54")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/README.md b/README.md index 9964aab9..b5996df7 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,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. 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. +2. Run `nuget restore` inside the top directory to install the packages. +3. Copy everything in the `Kerbal Space Program 2\KSP2_x64_Data\Managed` folder into the `external_dlls/` folder. +4. 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. +5. Launch KSP2 and wait until the title screen appears. You should see a mods folder under the `SpaceWarp` folder. +6. 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/ksp2_mod_loader_patcher.sln b/SpaceWarp.sln similarity index 69% rename from ksp2_mod_loader_patcher.sln rename to SpaceWarp.sln index 47b54344..d93f4e98 100644 --- a/ksp2_mod_loader_patcher.sln +++ b/SpaceWarp.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.4.33205.214 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarp", "SpaceWarp\SpaceWarp.csproj", "{42FA2F7B-A595-44E8-8CD5-A9C30B80A667}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleMod", "ExampleMod\ExampleMod.csproj", "{56255DE9-749D-447D-B1D8-1B634535A087}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {42FA2F7B-A595-44E8-8CD5-A9C30B80A667}.Debug|Any CPU.Build.0 = Debug|Any CPU {42FA2F7B-A595-44E8-8CD5-A9C30B80A667}.Release|Any CPU.ActiveCfg = Release|Any CPU {42FA2F7B-A595-44E8-8CD5-A9C30B80A667}.Release|Any CPU.Build.0 = Release|Any CPU + {56255DE9-749D-447D-B1D8-1B634535A087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56255DE9-749D-447D-B1D8-1B634535A087}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56255DE9-749D-447D-B1D8-1B634535A087}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56255DE9-749D-447D-B1D8-1B634535A087}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SpaceWarp/API/AssetBundles/ResourceManager.cs b/SpaceWarp/API/AssetBundles/ResourceManager.cs index 400dcf33..7f7251a6 100644 --- a/SpaceWarp/API/AssetBundles/ResourceManager.cs +++ b/SpaceWarp/API/AssetBundles/ResourceManager.cs @@ -3,124 +3,123 @@ using SpaceWarp.API.Logging; using UnityEngine; -namespace SpaceWarp.API.AssetBundles +namespace SpaceWarp.API.AssetBundles; + +public static class ResourceManager { - public static class ResourceManager - { - static readonly Dictionary AllAssets = new Dictionary(); + static readonly Dictionary AllAssets = new Dictionary(); - internal static void RegisterAssetBundle(string modId, string assetBundleName, AssetBundle assetBundle) - { - assetBundleName = assetBundleName.Replace(".bundle", ""); - ModLogger logger = new ModLogger($"{modId}/{assetBundleName}"); - // TODO: use async loading instead? + internal static void RegisterAssetBundle(string modId, string assetBundleName, AssetBundle assetBundle) + { + assetBundleName = assetBundleName.Replace(".bundle", ""); + ModLogger logger = new ModLogger($"{modId}/{assetBundleName}"); + // TODO: use async loading instead? - // Object[] bundleObjects = assetBundle.LoadAllAssets(); - string[] names = assetBundle.GetAllAssetNames(); + // Object[] bundleObjects = assetBundle.LoadAllAssets(); + string[] names = assetBundle.GetAllAssetNames(); - for (int i = 0; i < names.Length; i++) + for (int i = 0; i < names.Length; i++) + { + List assetNamePath = names[i].Split('/').ToList(); + if (assetNamePath[0].ToLower() == "assets") { - List assetNamePath = names[i].Split('/').ToList(); - if (assetNamePath[0].ToLower() == "assets") - { - assetNamePath.RemoveAt(0); - } + assetNamePath.RemoveAt(0); + } - string assetName = ""; - for (int j = 0; j < assetNamePath.Count; j++) + string assetName = ""; + for (int j = 0; j < assetNamePath.Count; j++) + { + assetName += assetNamePath[j]; + if (j != assetNamePath.Count - 1) { - assetName += assetNamePath[j]; - if (j != assetNamePath.Count - 1) - { - assetName += "/"; - } + assetName += "/"; } + } - string path = modId + "/" + assetBundleName + "/" + assetName; - path = path.ToLower(); - Object bundleObject = assetBundle.LoadAsset(names[i]); + string path = modId + "/" + assetBundleName + "/" + assetName; + path = path.ToLower(); + Object bundleObject = assetBundle.LoadAsset(names[i]); - logger.Info($"registering path \"{path}\""); + logger.Info($"registering path \"{path}\""); - AllAssets.Add(path, bundleObject); - } + AllAssets.Add(path, bundleObject); + } - // if (bundleObjects.Length != names.Length) - // { - // logger.Critical("bundle objects length and name lengths do not match"); - // logger.Info("going to dump objects and names"); - // logger.Info("Names"); - // for (int i = 0; i < names.Length; i++) - // { - // logger.Info($"{i} - {names[i]}"); - // } - // - // logger.Info("Objects"); - // for (int i = 0; i < bundleObjects.Length; i++) - // { - // logger.Info($"{i} - {bundleObjects[i]}"); - // } - // throw new System.Exception("bundle objects length and name lengths do not match"); - // } + // if (bundleObjects.Length != names.Length) + // { + // logger.Critical("bundle objects length and name lengths do not match"); + // logger.Info("going to dump objects and names"); + // logger.Info("Names"); + // for (int i = 0; i < names.Length; i++) + // { + // logger.Info($"{i} - {names[i]}"); + // } + // + // logger.Info("Objects"); + // for (int i = 0; i < bundleObjects.Length; i++) + // { + // logger.Info($"{i} - {bundleObjects[i]}"); + // } + // throw new System.Exception("bundle objects length and name lengths do not match"); + // } + } + + /// + /// Gets an asset from the specified asset path + /// + /// The type + /// an asset path, format: {mod_id}/{asset_bundle}/{asset_path} + /// + public static T GetAsset(string path) where T: UnityEngine.Object + { + path = path.ToLower(); + string[] subPaths = path.Split('/', '\\'); + if (subPaths.Length < 3) + { + throw new System.ArgumentException("Invalid path, asset paths must follow to following structure: {mod_id}/{asset_bundle}/{asset_path}"); } - /// - /// Gets an asset from the specified asset path - /// - /// The type - /// an asset path, format: {mod_id}/{asset_bundle}/{asset_path} - /// - public static T GetAsset(string path) where T: UnityEngine.Object + if (!AllAssets.TryGetValue(path, out Object value)) { - path = path.ToLower(); - string[] subPaths = path.Split('/', '\\'); - if (subPaths.Length < 3) - { - throw new System.ArgumentException("Invalid path, asset paths must follow to following structure: {mod_id}/{asset_bundle}/{asset_path}"); - } + throw new System.Exception($"Unable to find asset at path \"{path}\""); + } - if (!AllAssets.TryGetValue(path, out Object value)) - { - throw new System.Exception($"Unable to find asset at path \"{path}\""); - } + if (!(value is T tValue)) + { + throw new System.Exception($"The asset at path {path} isn't of type {typeof(T).Name} but of type {value.GetType().Name}"); + } - if (!(value is T tValue)) - { - throw new System.Exception($"The asset at path {path} isn't of type {typeof(T).Name} but of type {value.GetType().Name}"); - } + return tValue; + } - return tValue; + /// + /// Tries to get an asset from the specified asset path + /// + /// The type + /// an asset path, format: {mod_id}/{asset_bundle}/{asset_name} + /// the asset output + /// Whether or not the asset exists and is loaded + public static bool TryGetAsset(string path, out T asset) where T : Object + { + path = path.ToLower(); + asset = null; + string[] subPaths = path.Split('/', '\\'); + if (subPaths.Length < 3) + { + return false; } - - /// - /// Tries to get an asset from the specified asset path - /// - /// The type - /// an asset path, format: {mod_id}/{asset_bundle}/{asset_name} - /// the asset output - /// Whether or not the asset exists and is loaded - public static bool TryGetAsset(string path, out T asset) where T : Object + if (!AllAssets.TryGetValue(path, out Object value)) { - path = path.ToLower(); - asset = null; - string[] subPaths = path.Split('/', '\\'); - if (subPaths.Length < 3) - { - return false; - } - if (!AllAssets.TryGetValue(path, out Object value)) - { - return false; - } - if (!(value is T tValue)) - { - return false; - } + return false; + } + if (!(value is T tValue)) + { + return false; + } - asset = tValue; + asset = tValue; - return true; - } + return true; } -} +} \ No newline at end of file diff --git a/SpaceWarp/API/Configuration/ConfigDefaultValueAttribute.cs b/SpaceWarp/API/Configuration/ConfigDefaultValueAttribute.cs index 93bc9f9e..caa370f3 100644 --- a/SpaceWarp/API/Configuration/ConfigDefaultValueAttribute.cs +++ b/SpaceWarp/API/Configuration/ConfigDefaultValueAttribute.cs @@ -1,14 +1,13 @@ using System; -namespace SpaceWarp.API.Configuration +namespace SpaceWarp.API.Configuration; + +public class ConfigDefaultValueAttribute : Attribute { - public class ConfigDefaultValueAttribute : Attribute - { - public readonly object DefaultValue; + public readonly object DefaultValue; - public ConfigDefaultValueAttribute(object defaultValue) - { - DefaultValue = defaultValue; - } + public ConfigDefaultValueAttribute(object defaultValue) + { + DefaultValue = defaultValue; } } \ No newline at end of file diff --git a/SpaceWarp/API/Configuration/ConfigFieldAttribute.cs b/SpaceWarp/API/Configuration/ConfigFieldAttribute.cs index 37799a59..990e482c 100644 --- a/SpaceWarp/API/Configuration/ConfigFieldAttribute.cs +++ b/SpaceWarp/API/Configuration/ConfigFieldAttribute.cs @@ -1,14 +1,13 @@ using System; -namespace SpaceWarp.API.Configuration +namespace SpaceWarp.API.Configuration; + +public class ConfigFieldAttribute : Attribute { - public class ConfigFieldAttribute : Attribute - { - public readonly string Name; + public readonly string Name; - public ConfigFieldAttribute(string name) - { - Name = name; - } + public ConfigFieldAttribute(string name) + { + Name = name; } } \ No newline at end of file diff --git a/SpaceWarp/API/Configuration/ConfigSectionAttribute.cs b/SpaceWarp/API/Configuration/ConfigSectionAttribute.cs index 54cf4eb6..6bd882f9 100644 --- a/SpaceWarp/API/Configuration/ConfigSectionAttribute.cs +++ b/SpaceWarp/API/Configuration/ConfigSectionAttribute.cs @@ -1,14 +1,13 @@ using System; -namespace SpaceWarp.API.Configuration +namespace SpaceWarp.API.Configuration; + +public class ConfigSectionAttribute : Attribute { - public class ConfigSectionAttribute : Attribute - { - public readonly string Path; + public readonly string Path; - public ConfigSectionAttribute(string path) - { - Path = path; - } + public ConfigSectionAttribute(string path) + { + Path = path; } } \ No newline at end of file diff --git a/SpaceWarp/API/Configuration/ConfigurationManager.cs b/SpaceWarp/API/Configuration/ConfigurationManager.cs index 51730274..7bf73574 100644 --- a/SpaceWarp/API/Configuration/ConfigurationManager.cs +++ b/SpaceWarp/API/Configuration/ConfigurationManager.cs @@ -4,36 +4,35 @@ using SpaceWarp.API.Managers; using Newtonsoft.Json; -namespace SpaceWarp.API.Configuration +namespace SpaceWarp.API.Configuration; + +public class ConfigurationManager : Manager { - public class ConfigurationManager : Manager - { - private readonly Dictionary _modConfigurations = new Dictionary(); + private readonly Dictionary _modConfigurations = new Dictionary(); - public void Add(string id, (Type configType, object configObject, string path) configuration) + public void Add(string id, (Type configType, object configObject, string path) configuration) + { + if (_modConfigurations.ContainsKey(id)) { - if (_modConfigurations.ContainsKey(id)) - { - return; - } - - _modConfigurations[id] = configuration; + return; } - public bool TryGet(string id, out (Type configType, object configObject, string path) config) - { - return _modConfigurations.TryGetValue(id, out config); - } + _modConfigurations[id] = configuration; + } - public void UpdateConfiguration(string id) - { - if (!_modConfigurations.TryGetValue(id, out (Type, object, string) config)) - { - return; - } + public bool TryGet(string id, out (Type configType, object configObject, string path) config) + { + return _modConfigurations.TryGetValue(id, out config); + } - // Saves the new configuration - File.WriteAllText(config.Item3,JsonConvert.SerializeObject(config.Item2)); + public void UpdateConfiguration(string id) + { + if (!_modConfigurations.TryGetValue(id, out (Type, object, string) config)) + { + return; } + + // Saves the new configuration + File.WriteAllText(config.Item3,JsonConvert.SerializeObject(config.Item2)); } } \ No newline at end of file diff --git a/SpaceWarp/API/Configuration/ModConfigAttribute.cs b/SpaceWarp/API/Configuration/ModConfigAttribute.cs index 83faa52a..ffd1e156 100644 --- a/SpaceWarp/API/Configuration/ModConfigAttribute.cs +++ b/SpaceWarp/API/Configuration/ModConfigAttribute.cs @@ -1,9 +1,8 @@ using System; -namespace SpaceWarp.API.Configuration +namespace SpaceWarp.API.Configuration; + +public class ModConfigAttribute : Attribute { - public class ModConfigAttribute : Attribute - { - } } \ No newline at end of file diff --git a/SpaceWarp/API/Logging/BaseModLogger.cs b/SpaceWarp/API/Logging/BaseModLogger.cs index 16abad61..91570e65 100644 --- a/SpaceWarp/API/Logging/BaseModLogger.cs +++ b/SpaceWarp/API/Logging/BaseModLogger.cs @@ -1,17 +1,16 @@ -namespace SpaceWarp.API.Logging +namespace SpaceWarp.API.Logging; + +/// +/// Used to print logs on each mod. +/// +public abstract class BaseModLogger { - /// - /// Used to print logs on each mod. - /// - public abstract class BaseModLogger - { - protected abstract void Log(LogLevel level, string message); + protected abstract void Log(LogLevel level, string message); - public void Trace(string message) => Log(LogLevel.Trace, message); - public void Debug(string message) => Log(LogLevel.Debug, message); - public void Info(string message) => Log(LogLevel.Info, message); - public void Warn(string message) => Log(LogLevel.Warn, message); - public void Error(string message) => Log(LogLevel.Error, message); - public void Critical(string message) => Log(LogLevel.Critical, message); - } + public void Trace(string message) => Log(LogLevel.Trace, message); + public void Debug(string message) => Log(LogLevel.Debug, message); + public void Info(string message) => Log(LogLevel.Info, message); + public void Warn(string message) => Log(LogLevel.Warn, message); + public void Error(string message) => Log(LogLevel.Error, message); + public void Critical(string message) => Log(LogLevel.Critical, message); } \ No newline at end of file diff --git a/SpaceWarp/API/Logging/LogLevel.cs b/SpaceWarp/API/Logging/LogLevel.cs index f550a6be..ee8a7702 100644 --- a/SpaceWarp/API/Logging/LogLevel.cs +++ b/SpaceWarp/API/Logging/LogLevel.cs @@ -1,15 +1,14 @@ -namespace SpaceWarp.API.Logging +namespace SpaceWarp.API.Logging; + +/// +/// Log levels for the BaseModLogger class. +/// +public enum LogLevel { - /// - /// Log levels for the BaseModLogger class. - /// - public enum LogLevel - { - Trace = 0, - Debug = 1, - Info = 2, - Warn = 3, - Error = 4, - Critical = 5 - } + Trace = 0, + Debug = 1, + Info = 2, + Warn = 3, + Error = 4, + Critical = 5 } \ No newline at end of file diff --git a/SpaceWarp/API/Logging/ModLogger.cs b/SpaceWarp/API/Logging/ModLogger.cs index 42ba2486..07b8dff0 100644 --- a/SpaceWarp/API/Logging/ModLogger.cs +++ b/SpaceWarp/API/Logging/ModLogger.cs @@ -1,40 +1,42 @@ -using System.Text; +using System; +using System.Text; -namespace SpaceWarp.API.Logging +namespace SpaceWarp.API.Logging; + +/// +/// Unique logger for each mod, each mod has its own logger to accomodate different behaviours. +/// +public class ModLogger : BaseModLogger { + private readonly string _moduleName; + /// - /// Unique logger for each mod, each mod has its own logger to accomodate different behaviours. + /// Creates a ModLogger for a module /// - public class ModLogger : BaseModLogger + /// + public ModLogger(string moduleName) { - private readonly string _moduleName; - - /// - /// Creates a ModLogger for a module - /// - /// - public ModLogger(string moduleName) - { - _moduleName = moduleName; - } - - private void InternalLog(LogLevel level, string message) - { - StringBuilder sb = new StringBuilder(); + _moduleName = moduleName; + } + + private string BuildLogMessage(LogLevel level, string message) + { + StringBuilder sb = new StringBuilder(); - sb.Append($"[{_moduleName}] "); - sb.Append($"[{level}] "); - sb.Append(message); + sb.Append($"[{DateTime.Now:HH:mm:ss.fff}] "); + sb.Append($"[{_moduleName}] "); + sb.Append($"[{level}] "); + sb.Append(message); - UnityEngine.Debug.Log(sb.ToString()); - } + return sb.ToString(); + } - protected override void Log(LogLevel level, string message) + protected override void Log(LogLevel level, string message) + { + if ((int)level >= SpaceWarpGlobalConfiguration.Instance.LogLevel) { - if ((int)level >= SpaceWarpGlobalConfiguration.Instance.LogLevel) - { - InternalLog(level,message); - } + string logMessage = BuildLogMessage(level, message); + UnityEngine.Debug.Log(logMessage); } } } \ No newline at end of file diff --git a/SpaceWarp/API/Managers/Manager.cs b/SpaceWarp/API/Managers/Manager.cs index 8ae5526f..86f8a74d 100644 --- a/SpaceWarp/API/Managers/Manager.cs +++ b/SpaceWarp/API/Managers/Manager.cs @@ -1,21 +1,19 @@ -using System; -using KSP.Game; +using KSP.Game; -namespace SpaceWarp.API.Managers +namespace SpaceWarp.API.Managers; + +/// +/// Class to register itself on the ManagerLocator class for ease and performant access. +/// +public class Manager : KerbalMonoBehaviour { - /// - /// Class to register itself on the ManagerLocator class for ease and performant access. - /// - public class Manager : KerbalMonoBehaviour + protected virtual void Start() { - protected virtual void Start() - { - ManagerLocator.Add(this); - } + ManagerLocator.Add(this); + } - private void OnDestroy() - { - ManagerLocator.Remove(this); - } + private void OnDestroy() + { + ManagerLocator.Remove(this); } } \ No newline at end of file diff --git a/SpaceWarp/API/Managers/ManagerLocator.cs b/SpaceWarp/API/Managers/ManagerLocator.cs index 095be84c..1e1f71aa 100644 --- a/SpaceWarp/API/Managers/ManagerLocator.cs +++ b/SpaceWarp/API/Managers/ManagerLocator.cs @@ -2,47 +2,46 @@ using System.Collections.Generic; using UnityEngine; -namespace SpaceWarp.API.Managers +namespace SpaceWarp.API.Managers; + +public static class ManagerLocator { - public static class ManagerLocator - { - private static readonly Dictionary Managers = new Dictionary(); + private static readonly Dictionary Managers = new Dictionary(); - /// - /// Adds a manager object to the Managers dictionary. This should only run on Start(). - /// - /// The Mod component - public static void Add(MonoBehaviour manager) + /// + /// Adds a manager object to the Managers dictionary. This should only run on Start(). + /// + /// The Mod component + public static void Add(MonoBehaviour manager) + { + if (Managers.TryGetValue(manager.GetType(), out object _)) { - if (Managers.TryGetValue(manager.GetType(), out object _)) - { - return; - } - - Managers.Add(manager.GetType(), manager); + return; } - /// - /// Tries to get a manager from the Managers dictionary. - /// - /// The mod object found. - /// The type of Mod you want to find. - /// - public static bool TryGet(out T foundMod) where T : MonoBehaviour - { - bool hasMod = Managers.TryGetValue(typeof(T), out object mod); + Managers.Add(manager.GetType(), manager); + } - foundMod = mod as T; - return hasMod; - } + /// + /// Tries to get a manager from the Managers dictionary. + /// + /// The mod object found. + /// The type of Mod you want to find. + /// + public static bool TryGet(out T foundMod) where T : MonoBehaviour + { + bool hasMod = Managers.TryGetValue(typeof(T), out object mod); - /// - /// Removes a manager from the dictionary - /// - /// - public static void Remove(Manager manager) - { - Managers.Remove(manager.GetType()); - } + foundMod = mod as T; + return hasMod; + } + + /// + /// Removes a manager from the dictionary + /// + /// + public static void Remove(Manager manager) + { + Managers.Remove(manager.GetType()); } } \ No newline at end of file diff --git a/SpaceWarp/API/Mods/GlobalModDefines.cs b/SpaceWarp/API/Mods/GlobalModDefines.cs index 2f9c340e..0bbf52b1 100644 --- a/SpaceWarp/API/Mods/GlobalModDefines.cs +++ b/SpaceWarp/API/Mods/GlobalModDefines.cs @@ -1,9 +1,10 @@ -namespace SpaceWarp.API.Mods +using System.IO; + +namespace SpaceWarp.API.Mods; + +public static class GlobalModDefines { - public static class GlobalModDefines - { - public const string BINARIES_FOLDER = "/bin/"; + public const string BINARIES_FOLDER = "bin"; - public const string ASSET_BUNDLES_FOLDER = "/assets/bundles/"; - } + public static readonly string ASSET_BUNDLES_FOLDER = Path.Combine("assets","bundles"); } \ No newline at end of file diff --git a/SpaceWarp/API/Mods/JSON/DependencyInfo.cs b/SpaceWarp/API/Mods/JSON/DependencyInfo.cs index f6f36491..dbdac248 100644 --- a/SpaceWarp/API/Mods/JSON/DependencyInfo.cs +++ b/SpaceWarp/API/Mods/JSON/DependencyInfo.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace SpaceWarp.API.Mods.JSON +namespace SpaceWarp.API.Mods.JSON; + +/// +/// Represents the json property info. Properties have to use the same name as in the JSON file, that's why they break convention. +/// +[JsonObject(MemberSerialization.OptIn)] +public class DependencyInfo { - /// - /// Represents the json property info. Properties have to use the same name as in the JSON file, that's why they break convention. - /// - [JsonObject(MemberSerialization.OptIn)] - public class DependencyInfo - { - [JsonProperty("id")] - public string id { get; set; } + [JsonProperty("id")] + public string id { get; set; } - [JsonProperty("version")] - public SupportedVersionsInfo version { get; set; } - } + [JsonProperty("version")] + public SupportedVersionsInfo version { get; set; } } \ No newline at end of file diff --git a/SpaceWarp/API/Mods/JSON/ModInfo.cs b/SpaceWarp/API/Mods/JSON/ModInfo.cs index baaf5bc4..abe8964d 100644 --- a/SpaceWarp/API/Mods/JSON/ModInfo.cs +++ b/SpaceWarp/API/Mods/JSON/ModInfo.cs @@ -1,36 +1,35 @@ using Newtonsoft.Json; using System.Collections.Generic; -namespace SpaceWarp.API.Mods.JSON +namespace SpaceWarp.API.Mods.JSON; + +/// +/// Representation of the mod info JSON file. +/// +[JsonObject(MemberSerialization.OptIn)] +public class ModInfo { - /// - /// Representation of the mod info JSON file. - /// - [JsonObject(MemberSerialization.OptIn)] - public class ModInfo - { - [JsonProperty("mod_id")] - public string mod_id { get; set; } + [JsonProperty("mod_id")] + public string mod_id { get; set; } - [JsonProperty("name")] - public string name { get; set; } + [JsonProperty("name")] + public string name { get; set; } - [JsonProperty("author")] - public string author { get; set; } + [JsonProperty("author")] + public string author { get; set; } - [JsonProperty("description")] - public string description { get; set; } + [JsonProperty("description")] + public string description { get; set; } - [JsonProperty("source")] - public string source { get; set; } + [JsonProperty("source")] + public string source { get; set; } - [JsonProperty("version")] - public string version { get; set; } + [JsonProperty("version")] + public string version { get; set; } - [JsonProperty("dependencies")] - public List dependencies { get; set; } = new List(); + [JsonProperty("dependencies")] + public List dependencies { get; set; } = new List(); - [JsonProperty("ksp2_version")] - public SupportedVersionsInfo supported_ksp2_versions { get; set; } = new SupportedVersionsInfo(); - } + [JsonProperty("ksp2_version")] + public SupportedVersionsInfo supported_ksp2_versions { get; set; } = new SupportedVersionsInfo(); } \ No newline at end of file diff --git a/SpaceWarp/API/Mods/JSON/SupportedVersionsInfo.cs b/SpaceWarp/API/Mods/JSON/SupportedVersionsInfo.cs index 39ba2a8e..a483a898 100644 --- a/SpaceWarp/API/Mods/JSON/SupportedVersionsInfo.cs +++ b/SpaceWarp/API/Mods/JSON/SupportedVersionsInfo.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace SpaceWarp.API.Mods.JSON +namespace SpaceWarp.API.Mods.JSON; + +/// +/// Representation of the supported version info of a mod from a JSON file. +/// +[JsonObject(MemberSerialization.OptIn)] +public class SupportedVersionsInfo { - /// - /// Representation of the supported version info of a mod from a JSON file. - /// - [JsonObject(MemberSerialization.OptIn)] - public class SupportedVersionsInfo - { - [JsonProperty("min")] - public string min { get; set; } = "0.0.0"; + [JsonProperty("min")] + public string min { get; set; } = "0.0.0"; - [JsonProperty("max")] - public string max { get; set; } = "*"; - } + [JsonProperty("max")] + public string max { get; set; } = "*"; } \ No newline at end of file diff --git a/SpaceWarp/API/Mods/MainModAttribute.cs b/SpaceWarp/API/Mods/MainModAttribute.cs index 9e0a583a..e5838097 100644 --- a/SpaceWarp/API/Mods/MainModAttribute.cs +++ b/SpaceWarp/API/Mods/MainModAttribute.cs @@ -1,6 +1,5 @@ using System; -namespace SpaceWarp.API.Mods -{ - public class MainModAttribute : Attribute { } -} \ No newline at end of file +namespace SpaceWarp.API.Mods; + +public class MainModAttribute : Attribute { } \ No newline at end of file diff --git a/SpaceWarp/API/Mods/Mod.cs b/SpaceWarp/API/Mods/Mod.cs index 7edc9722..6528c730 100644 --- a/SpaceWarp/API/Mods/Mod.cs +++ b/SpaceWarp/API/Mods/Mod.cs @@ -1,44 +1,41 @@ -using System; -using KSP.Game; -using SpaceWarp.API.Configuration; +using KSP.Game; using SpaceWarp.API.Logging; using SpaceWarp.API.Mods.JSON; using UnityEngine; -namespace SpaceWarp.API.Mods +namespace SpaceWarp.API.Mods; + +/// +/// Represents a KSP2 Mod, you should inherit from this and do your manager processing. +/// +public abstract class Mod : KerbalMonoBehaviour { - /// - /// Represents a KSP2 Mod, you should inherit from this and do your manager processing. - /// - public abstract class Mod : KerbalMonoBehaviour - { - public BaseModLogger Logger; - public ModInfo Info; + public BaseModLogger Logger; + public ModInfo Info; - public virtual void Initialize() - { - } + public virtual void Initialize() + { + } - private void OnDestroy() - { - ModLocator.Remove(this); - } + private void OnDestroy() + { + ModLocator.Remove(this); + } - public virtual void OnInitialized() - { - // Empty - } + public virtual void OnInitialized() + { + // Empty + } - public void Setup(Transform transformParent, ModInfo info) - { - transform.SetParent(transformParent); + public void Setup(Transform transformParent, ModInfo info) + { + transform.SetParent(transformParent); - ModLogger newModLogger = new ModLogger(info.name); - Logger = newModLogger; + ModLogger newModLogger = new ModLogger(info.name); + Logger = newModLogger; - Info = info; - } + Info = info; } -} +} \ No newline at end of file diff --git a/SpaceWarp/API/Mods/ModLocator.cs b/SpaceWarp/API/Mods/ModLocator.cs index d4d1ed9d..e3116207 100644 --- a/SpaceWarp/API/Mods/ModLocator.cs +++ b/SpaceWarp/API/Mods/ModLocator.cs @@ -1,50 +1,49 @@ using System; using System.Collections.Generic; -namespace SpaceWarp.API.Mods +namespace SpaceWarp.API.Mods; + +/// +/// Useful performance-optimized locator for Mod objects. Should be used instead of any other way. +/// +public static class ModLocator { + private static readonly Dictionary Mods = new Dictionary(); + /// - /// Useful performance-optimized locator for Mod objects. Should be used instead of any other way. + /// Adds a mod object to the Mods dictionary. This should only run on Mod.Start(). /// - public static class ModLocator + /// The Mod component + public static void Add(Mod modObject) { - private static readonly Dictionary Mods = new Dictionary(); - - /// - /// Adds a mod object to the Mods dictionary. This should only run on Mod.Start(). - /// - /// The Mod component - public static void Add(Mod modObject) + if (Mods.TryGetValue(modObject.GetType(), out object _)) { - if (Mods.TryGetValue(modObject.GetType(), out object _)) - { - return; - } - - Mods.Add(modObject.GetType(), modObject); + return; } - /// - /// Tries to get a mod from the Mods dictionary. - /// - /// The mod object found. - /// The type of Mod you want to find. - /// - public static bool TryGet(out T foundMod) where T : Mod - { - bool hasMod = Mods.TryGetValue(typeof(T), out object mod); + Mods.Add(modObject.GetType(), modObject); + } - foundMod = mod as T; - return hasMod; - } + /// + /// Tries to get a mod from the Mods dictionary. + /// + /// The mod object found. + /// The type of Mod you want to find. + /// + public static bool TryGet(out T foundMod) where T : Mod + { + bool hasMod = Mods.TryGetValue(typeof(T), out object mod); - /// - /// Removes a manager from the dictionary - /// - /// - public static void Remove(Mod modObject) - { - Mods.Remove(modObject.GetType()); - } + foundMod = mod as T; + return hasMod; + } + + /// + /// Removes a manager from the dictionary + /// + /// + public static void Remove(Mod modObject) + { + Mods.Remove(modObject.GetType()); } } \ No newline at end of file diff --git a/SpaceWarp/API/SpaceWarpGlobalConfiguration.cs b/SpaceWarp/API/SpaceWarpGlobalConfiguration.cs index 40061e23..ba0e8269 100644 --- a/SpaceWarp/API/SpaceWarpGlobalConfiguration.cs +++ b/SpaceWarp/API/SpaceWarpGlobalConfiguration.cs @@ -4,65 +4,71 @@ using Newtonsoft.Json; using UnityEngine; -namespace SpaceWarp.API +namespace SpaceWarp.API; + +[JsonObject(MemberSerialization.OptIn)] +public class SpaceWarpGlobalConfiguration { - [JsonObject(MemberSerialization.OptIn)] - public class SpaceWarpGlobalConfiguration - { - 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; + public static SpaceWarpGlobalConfiguration Instance; - 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"; + private static string SPACEWARP_CONFIG_FULL_PATH = Path.Combine(SpaceWarpManager.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() + /// + /// 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 { - 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) }); + 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($"Saving the spacewarp config failed\nException: {exception}"); + Debug.LogError($"Loading space warp config failed\nException: {exception}"); + + File.Delete(SPACEWARP_CONFIG_FULL_PATH); + Init(); + return; } } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] - [DefaultValue((int)Logging.LogLevel.Info)] - public int LogLevel { get; set; } - - public void ApplyDefaultValues() + try { - LogLevel = (int)Logging.LogLevel.Info; + 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; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] + [DefaultValue((bool)false)] + public bool HarmonyLoggin { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] + [DefaultValue((int)Logging.LogLevel.Info)] + public int HarmonyLogLevel { get; set; } + + public void ApplyDefaultValues() + { + LogLevel = (int)Logging.LogLevel.Info; + HarmonyLoggin = false; + HarmonyLogLevel = (int)Logging.LogLevel.Info; } } \ No newline at end of file diff --git a/SpaceWarp/API/SpaceWarpManager.cs b/SpaceWarp/API/SpaceWarpManager.cs index cb628510..48b75ff9 100644 --- a/SpaceWarp/API/SpaceWarpManager.cs +++ b/SpaceWarp/API/SpaceWarpManager.cs @@ -1,11 +1,10 @@ using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using HarmonyLib; -using KSP; -using KSP.Game; using UnityEngine; using Newtonsoft.Json; using SpaceWarp.API.Configuration; @@ -14,558 +13,759 @@ using SpaceWarp.API.Managers; using SpaceWarp.API.Mods; using SpaceWarp.API.Mods.JSON; +using SpaceWarp.API.Toolbar; using SpaceWarp.API.Versions; using SpaceWarp.Compilation; using SpaceWarp.Patching; using SpaceWarp.UI; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.AddressableAssets.ResourceProviders; +using UnityEngine.ResourceManagement.AsyncOperations; -namespace SpaceWarp.API +namespace SpaceWarp.API; + +/// +/// Handles all the SpaceWarp initialization and mod processing. +/// +public class SpaceWarpManager : Manager { - /// - /// Handles all the SpaceWarp initialization and mod processing. - /// - public class SpaceWarpManager : Manager - { - private BaseModLogger _modLogger; + private BaseModLogger _modLogger; 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; + #if DOORSTOP_BUILD + public static string SPACE_WARP_PATH = Directory.GetParent(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)).FullName + "/"; + #else + public static string SPACE_WARP_PATH = Path.Combine(Directory.GetParent(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)).Parent.Parent.FullName,"SpaceWarp"); + #endif + public static string MODS_FULL_PATH = Path.Combine(SPACE_WARP_PATH,MODS_FOLDER_NAME); + + public SpaceWarpGlobalConfiguration SpaceWarpConfiguration; + + private readonly List _allModScripts = new List(); + internal readonly List<(string, ModInfo)> _modLoadOrder = new List<(string, ModInfo)>(); + public readonly List<(string,ModInfo)> LoadedMods = new List<(string,ModInfo)>(); + private static readonly List<(string, ModInfo)> AllEnabledModInfo = new List<(string, ModInfo)>(); + + public readonly List<(string,ModInfo)> IgnoredMods = new List<(string,ModInfo)>(); - public SpaceWarpGlobalConfiguration SpaceWarpConfiguration; + public ModListUI ModListUI { get; private set; } + protected override void Start() + { + + Debug.Log($"Space Warp Path {SPACE_WARP_PATH}"); + Debug.Log($"Mods Path {MODS_FULL_PATH}"); + + base.Start(); - private readonly List _allModScripts = new List(); - internal readonly List<(string, ModInfo)> _modLoadOrder = new List<(string, ModInfo)>(); - public readonly List<(string,ModInfo)> LoadedMods = new List<(string,ModInfo)>(); - private static readonly List<(string, ModInfo)> AllEnabledModInfo = new List<(string, ModInfo)>(); + Initialize(); + } - public ModListUI ModListUI { get; private set; } - protected override void Start() - { - base.Start(); + /// + /// Initializes the SpaceWarp manager. + /// + private void Initialize() + { + ToolbarBackend.AppBarInFlightSubscriber.AddListener(LoadAllButtons); + InitializeConfigManager(); + + InitializeModLogger(); - Initialize(); - } + LoadingScreenPatcher.AddModLoadingScreens(); + } - /// - /// Initializes the SpaceWarp manager. - /// - private void Initialize() - { - InitializeConfigManager(); - - InitializeModLogger(); + /// + ///Initializes the configuration manager + /// + public void InitializeConfigManager() + { + GameObject confManagerObject = new GameObject("Configuration Manager"); + Persist(confManagerObject); - LoadingScreenPatcher.AddModLoadingScreens(); - } + confManagerObject.AddComponent(); + confManagerObject.SetActive(true); + } + + /// + /// Initializes the SpaceWarp mod logger. + /// + private void InitializeModLogger() + { + _modLogger = new ModLogger("Space Warp"); + _modLogger.Info("Warping Spacetime"); + } - /// - ///Initializes the configuration manager - /// - public void InitializeConfigManager() - { - GameObject confManagerObject = new GameObject("Configuration Manager"); - DontDestroyOnLoad(confManagerObject); + /// + /// Read all the mods in the mods path + /// + internal void ReadMods() + { + _modLogger.Info("Reading mods"); - confManagerObject.AddComponent(); - confManagerObject.SetActive(true); + string[] modDirectories; + try + { + modDirectories = Directory.GetDirectories(MODS_FULL_PATH); } - - /// - /// Initializes the SpaceWarp mod logger. - /// - private void InitializeModLogger() + catch(Exception exception) { - _modLogger = new ModLogger("Space Warp"); - _modLogger.Info("Warping Spacetime"); + _modLogger.Critical($"Unable to open mod path: {MODS_FULL_PATH}\nException:{exception}"); + return; } - /// - /// Read all the mods in the mods path - /// - internal void ReadMods() + if (modDirectories.Length == 0) { - _modLogger.Info("Reading mods"); + _modLogger.Warn("No mods were found! No panic though."); + } - string[] modDirectories; - try - { - modDirectories = Directory.GetDirectories(MODS_FULL_PATH); - } - catch(Exception exception) - { - _modLogger.Critical($"Unable to open mod path: {MODS_FULL_PATH}\nException:{exception}"); - return; - } + foreach (string modFolderuntrimmedU in modDirectories) + { + string modFolder = modFolderuntrimmedU.TrimEnd('/', '\\'); - if (modDirectories.Length == 0) + string modName = Path.GetFileName(modFolder); + if (!File.Exists(Path.Combine(modFolder,"modinfo.json"))) { - _modLogger.Warn("No mods were found! No panic though."); + _modLogger.Warn($"Found mod {modName} without modinfo.json"); + continue; } - foreach (string modFolderuntrimmedU in modDirectories) + if (File.Exists(Path.Combine(modFolder,".ignore"))) { - string modFolder = modFolderuntrimmedU.TrimEnd('/', '\\'); - - string modName = Path.GetFileName(modFolder); - if (!File.Exists(modFolder + "\\modinfo.json")) - { - _modLogger.Warn($"Found mod {modName} without modinfo.json"); - continue; - } - - if (File.Exists(modFolder + "\\.ignore")) - { - _modLogger.Info($"Skipping mod {modName} due to .ignore file"); - continue; - } - _modLogger.Info($"Found mod: {modName}, adding to enable mods"); - - ModInfo info = JsonConvert.DeserializeObject(File.ReadAllText(modFolder + "\\modinfo.json")); - string fileName = Path.GetFileName(modFolder); - AllEnabledModInfo.Add((fileName,info)); + _modLogger.Info($"Skipping mod {modName} due to .ignore file"); + ModInfo ignore_info = JsonConvert.DeserializeObject(File.ReadAllText(modFolder + "\\modinfo.json")); + string ignore_fileName = Path.GetFileName(modFolder); + IgnoredMods.Add((ignore_fileName,ignore_info)); + continue; } + _modLogger.Info($"Found mod: {modName}, adding to enable mods"); - ResolveLoadOrder(); + ModInfo info = JsonConvert.DeserializeObject(File.ReadAllText(modFolder + "\\modinfo.json")); + string fileName = Path.GetFileName(modFolder); + AllEnabledModInfo.Add((fileName,info)); } - /// - /// Checks if all dependencies are resolved. - /// - /// - /// - private bool AreDependenciesResolved(ModInfo mod) + ResolveLoadOrder(); + } + + /// + /// Checks if all dependencies are resolved. + /// + /// + /// + private bool AreDependenciesResolved(ModInfo mod) + { + foreach (DependencyInfo dependency in mod.dependencies) { - foreach (DependencyInfo dependency in mod.dependencies) - { - _modLogger.Info($"{mod.name} dependency - {dependency.id} {dependency.version.min}-{dependency.version.max}"); + _modLogger.Info($"{mod.name} dependency - {dependency.id} {dependency.version.min}-{dependency.version.max}"); - string dependencyID = dependency.id; - SupportedVersionsInfo dependencyVersion = dependency.version; + string dependencyID = dependency.id; + SupportedVersionsInfo dependencyVersion = dependency.version; - bool found = false; - foreach ((string, ModInfo) loadedMod in _modLoadOrder) + bool found = false; + foreach ((string, ModInfo) loadedMod in _modLoadOrder) + { + if (loadedMod.Item2.mod_id != dependencyID) { - if (loadedMod.Item2.mod_id != dependencyID) - { - continue; - } + continue; + } - string depLoadedVersion = loadedMod.Item2.version; + string depLoadedVersion = loadedMod.Item2.version; - if (!VersionUtility.IsVersionAbove(depLoadedVersion, dependencyVersion.min)) - return false; - if (!VersionUtility.IsVersionBellow(depLoadedVersion, dependencyVersion.max)) - return false; + if (!VersionUtility.IsVersionAbove(depLoadedVersion, dependencyVersion.min)) + return false; + if (!VersionUtility.IsVersionBellow(depLoadedVersion, dependencyVersion.max)) + return false; - found = true; - } - - if (!found) return false; + found = true; } - return true; + if (!found) return false; } - /// - /// Resolves mod order - /// - private void ResolveLoadOrder() + return true; + } + + /// + /// Resolves mod order + /// + private void ResolveLoadOrder() + { + //TODO: Make this way more optimized! + _modLogger.Info("Resolving Load Order"); + bool changed = true; + while (changed) { - //TODO: Make this way more optimized! - _modLogger.Info("Resolving Load Order"); - bool changed = true; - while (changed) + changed = false; + List toRemove = new List(); + for (int i = 0; i < AllEnabledModInfo.Count; i++) { - changed = false; - List toRemove = new List(); - for (int i = 0; i < AllEnabledModInfo.Count; i++) + _modLogger.Info("Attempting to resolve dependencies for " + AllEnabledModInfo[i].Item1); + if (AreDependenciesResolved(AllEnabledModInfo[i].Item2)) { - _modLogger.Info("Attempting to resolve dependencies for " + AllEnabledModInfo[i].Item1); - if (AreDependenciesResolved(AllEnabledModInfo[i].Item2)) - { - _modLoadOrder.Add(AllEnabledModInfo[i]); - toRemove.Add(i); - changed = true; - } - } - - for (int i = toRemove.Count - 1; i >= 0; i--) - { - AllEnabledModInfo.RemoveAt(toRemove[i]); + _modLoadOrder.Add(AllEnabledModInfo[i]); + toRemove.Add(i); + changed = true; } } - if (AllEnabledModInfo.Count > 0) + for (int i = toRemove.Count - 1; i >= 0; i--) { - foreach ((string modName, ModInfo info) in AllEnabledModInfo) - { - _modLogger.Warn($"Skipping loading of {modName} as not all dependencies could be met"); - } + AllEnabledModInfo.RemoveAt(toRemove[i]); } - LoadingScreenPatcher.AddAllModLoadingSteps(); } - internal void InitializeAssets() + if (AllEnabledModInfo.Count > 0) { - _modLogger.Info("Initializing mod assets"); - - foreach ((string modName, ModInfo info) in _modLoadOrder) + foreach ((string modName, ModInfo info) in AllEnabledModInfo) { - LoadSingleModAssets(modName, info); + _modLogger.Warn($"Skipping loading of {modName} as not all dependencies could be met"); } + } + LoadingScreenPatcher.AddAllModLoadingSteps(); + } + + internal void InitializeAssets() + { + _modLogger.Info("Initializing mod assets"); + foreach ((string modName, ModInfo info) in _modLoadOrder) + { + LoadSingleModAssets(modName, info); } + } - internal void LoadSpaceWarpAssets() + + internal void LoadSpaceWarpAssets() + { + string bundlesPath = Path.Combine(SPACE_WARP_PATH, GlobalModDefines.ASSET_BUNDLES_FOLDER); + + if (Directory.Exists(bundlesPath)) { - string bundlesPath = Directory.GetCurrentDirectory() + "/SpaceWarp" + GlobalModDefines.ASSET_BUNDLES_FOLDER; - if (Directory.Exists(bundlesPath)) + foreach (string file in Directory.GetFiles(bundlesPath)) { - foreach (string file in Directory.GetFiles(bundlesPath)) - { - _modLogger.Info($"Found space warp asset file {file}"); - string assetBundleName = Path.GetFileNameWithoutExtension(file); - if (Path.GetExtension(file) != ".bundle") continue; + _modLogger.Info($"Found space warp asset file {file}"); + string assetBundleName = Path.GetFileNameWithoutExtension(file); + if (Path.GetExtension(file) != ".bundle") continue; - AssetBundle assetBundle = AssetBundle.LoadFromFile(file); + AssetBundle assetBundle = AssetBundle.LoadFromFile(file); - if (assetBundle == null) - { - _modLogger.Error($"Failed to load AssetBundle space_warp/{assetBundleName}"); - continue; - } - ResourceManager.RegisterAssetBundle("space_warp", assetBundleName, assetBundle); - _modLogger.Info($"Loaded AssetBundle space_warp/{assetBundleName}"); + if (assetBundle == null) + { + _modLogger.Error($"Failed to load AssetBundle space_warp/{assetBundleName}"); + continue; } + ResourceManager.RegisterAssetBundle("space_warp", assetBundleName, assetBundle); + _modLogger.Info($"Loaded AssetBundle space_warp/{assetBundleName}"); } } + } - /// - /// Loads a single mods assets - /// - /// the name/id of the mod - /// the mod info structure that describes the mod - internal void LoadSingleModAssets(string modName, ModInfo info) - { - string modFolder = MODS_FULL_PATH + "/" + modName; - - // Now we load all asset bundles under the asset/bundles folder of the mod - string bundlesPath = modFolder + GlobalModDefines.ASSET_BUNDLES_FOLDER; - if (Directory.Exists(bundlesPath)) + /// + /// Loads a single mods assets + /// + /// the name/id of the mod + /// the mod info structure that describes the mod + internal void LoadSingleModAssets(string modName, ModInfo info) + { + string modFolder = Path.Combine(MODS_FULL_PATH, modName); + + // Now we load all asset bundles under the asset/bundles folder of the mod + string bundlesPath = modFolder + GlobalModDefines.ASSET_BUNDLES_FOLDER; + if (Directory.Exists(bundlesPath)) + { + foreach (string file in Directory.GetFiles(bundlesPath)) { - foreach (string file in Directory.GetFiles(bundlesPath)) - { - string assetBundleName = Path.GetFileNameWithoutExtension(file); - if (Path.GetExtension(file) != ".bundle") continue; + string assetBundleName = Path.GetFileNameWithoutExtension(file); + if (Path.GetExtension(file) != ".bundle") continue; - AssetBundle assetBundle = AssetBundle.LoadFromFile(file); + AssetBundle assetBundle = AssetBundle.LoadFromFile(file); - if (assetBundle == null) - { - _modLogger.Error($"Failed to load AssetBundle {info.mod_id}/{assetBundleName}"); - continue; - } - ResourceManager.RegisterAssetBundle(info.mod_id, assetBundleName, assetBundle); - _modLogger.Info($"Loaded AssetBundle {info.mod_id}/{assetBundleName}"); + if (assetBundle == null) + { + _modLogger.Error($"Failed to load AssetBundle {info.mod_id}/{assetBundleName}"); + continue; } + ResourceManager.RegisterAssetBundle(info.mod_id, assetBundleName, assetBundle); + _modLogger.Info($"Loaded AssetBundle {info.mod_id}/{assetBundleName}"); } - else - { - _modLogger.Info($"Did not load assets for {modName} as no assets folder existed!"); - } - - // TODO: load part specific json stuff } - - /// - /// Runs the mod initialization procedures. - /// - internal void InitializeMods() + else { - _modLogger.Info("Initializing mods"); + _modLogger.Info($"Did not load assets for {modName} as no assets folder existed!"); + } + + // TODO: load part specific json stuff + } + + /// + /// Runs the mod initialization procedures. + /// + internal void InitializeMods() + { + _modLogger.Info("Initializing mods"); - foreach ((string modName, ModInfo info) in _modLoadOrder) + foreach ((string modName, ModInfo info) in _modLoadOrder) + { + InitializeSingleMod(modName, info); + } + } + + /// + /// Initializes a single mod + /// + /// the name/id of the mod + /// the mod info structure that describes the mod + internal void InitializeSingleMod(string modName, ModInfo info) + { + string modFolder = Path.Combine(MODS_FULL_PATH, modName); + + _modLogger.Info($"Found mod: {modName}, attempting to load mod"); + + // Now we load all assemblies under the code folder of the mod + string codePath = Path.Combine(modFolder, GlobalModDefines.BINARIES_FOLDER); + + if (Directory.Exists(codePath)) + { + if (!TryLoadMod(codePath, modName, info, out Type mainModType)) { - InitializeSingleMod(modName, info); + // error logging is done inside TryLoadMod + return; } - } - /// - /// Initializes a single mod - /// - /// the name/id of the mod - /// the mod info structure that describes the mod - internal void InitializeSingleMod(string modName, ModInfo info) + InitializeModObject(modName, info, mainModType); + } + else { - string modFolder = MODS_FULL_PATH + "/" + modName; + _modLogger.Error($"Directory not found: {codePath}"); + } + } - _modLogger.Info($"Found mod: {modName}, attempting to load mod"); + /// + /// Tries to load a mod at a path + /// + /// The full path to this mod binaries. + /// The mod name + /// The Mod type found + /// If the mod was successfully found. + private bool TryLoadMod(string codePath, string modName, ModInfo modInfo, out Type mainModType) + { + string[] files; + try + { + files = Directory.GetFiles(codePath); + } + catch + { + _modLogger.Error($"Could not load mod: {modName}, unable to read directory"); + mainModType = null; + return false; + } - // Now we load all assemblies under the code folder of the mod - string codePath = modFolder + GlobalModDefines.BINARIES_FOLDER; + List modAssemblies = new List(); + foreach (string file in files) + { + // we only want to load dll files, ignore everything else + if (!file.EndsWith(".dll")) + { + _modLogger.Warn($"Non-dll file found in \"{codePath}\" \"{file}\", Ignoring"); + continue; + } - if (Directory.Exists(codePath)) + Assembly asm; + try { - if (!TryLoadMod(codePath, modName, info, out Type mainModType)) - { - // error logging is done inside TryLoadMod - return; - } + asm = Assembly.LoadFrom(file); + } + catch(Exception exeption) + { + _modLogger.Error($"Could not load mod: {modName}, Failed to load assembly {file}\nException: {exeption}"); + mainModType = null; - InitializeModObject(modName, info, mainModType); + return false; } - else + + modAssemblies.Add(asm); + } + + + string modFolder = Path.Combine(MODS_FULL_PATH,modName); + string srcPath = Path.Combine(modFolder, "src"); + if (Directory.Exists(srcPath) && Directory.GetFiles(srcPath, "*",SearchOption.AllDirectories).Length > 0) + { + var result = ModCompiler.CompileMod(modInfo.mod_id, srcPath); + if (result != null) { - _modLogger.Error($"Directory not found: {codePath}"); + modAssemblies.Add(result); } } - /// - /// Tries to load a mod at a path - /// - /// The full path to this mod binaries. - /// The mod name - /// The Mod type found - /// If the mod was successfully found. - private bool TryLoadMod(string codePath, string modName, ModInfo modInfo, out Type mainModType) + mainModType = null; + foreach (Assembly asm in modAssemblies) { - string[] files; + Type[] types; try { - files = Directory.GetFiles(codePath); - } + types = asm.GetTypes(); + } catch { - _modLogger.Error($"Could not load mod: {modName}, unable to read directory"); + _modLogger.Error($"Could not load mod: {modName}, Unable to get types out of assembly {asm.FullName}"); + mainModType = null; - return false; + return false; } - List modAssemblies = new List(); - foreach (string file in files) - { - // we only want to load dll files, ignore everything else - if (!file.EndsWith(".dll")) - { - _modLogger.Warn($"Non-dll file found in \"{codePath}\" \"{file}\", Ignoring"); - continue; - } - Assembly asm; - try - { - asm = Assembly.LoadFrom(file); - } - catch(Exception exeption) - { - _modLogger.Error($"Could not load mod: {modName}, Failed to load assembly {file}\nException: {exeption}"); - mainModType = null; + mainModType = types.FirstOrDefault(type => type.GetCustomAttribute() != null); + if (mainModType != null) break; + } - return false; - } + if (mainModType == null) + { + _modLogger.Error($"Could not load mod: {modName}, no type with [MainMod] exists"); + return false; + } - modAssemblies.Add(asm); - } - - string modFolder = MODS_FULL_PATH + "/" + modName; - string srcPath = modFolder + "/src/"; - if (Directory.Exists(srcPath) && Directory.GetFiles(srcPath, "*",SearchOption.AllDirectories).Length > 0) - { - var result = ModCompiler.CompileMod(modInfo.mod_id, srcPath); - if (result != null) - { - modAssemblies.Add(result); - } - } + // We want to load the configuration for the mod as well + Type configurationModType = null; + foreach (Assembly asm in modAssemblies) + { + configurationModType = asm.GetTypes() + .FirstOrDefault(type => type.GetCustomAttribute () != null); + if (configurationModType != null) break; + } + + if (configurationModType != null) + { + InitializeModConfig(configurationModType, modName); + } + + if (!typeof(Mod).IsAssignableFrom(mainModType)) + { + _modLogger.Error($"Could not load mod: {modName}, the found class ({mainModType.FullName}) with [MainMod] doesn't inherit from {nameof(Mod)}"); mainModType = null; - foreach (Assembly asm in modAssemblies) - { - Type[] types; - try - { - types = asm.GetTypes(); - } - catch - { - _modLogger.Error($"Could not load mod: {modName}, Unable to get types out of assembly {asm.FullName}"); + return false; + } - mainModType = null; - return false; - } + // Harmony patch everything in the current mod! + Harmony harmony = new Harmony($"com.mod.{modInfo.author}.{modInfo.mod_id}"); + foreach (Assembly asm in modAssemblies) + { + harmony.PatchAll(asm); + } + return true; - mainModType = types.FirstOrDefault(type => type.GetCustomAttribute() != null); - if (mainModType != null) break; - } + } - if (mainModType == null) + /// + /// Tries to find a specific mods config file, if none is found, one is created + /// + private void InitializeModConfig(Type config_type, string mod_id) + { + object modConfiguration = null; + var config_path = Path.Combine(MODS_FULL_PATH, mod_id, "config","config.json"); + if (!File.Exists(config_path)) + { + modConfiguration = Activator.CreateInstance(config_type); + foreach (var fieldInfo in config_type.GetFields(BindingFlags.Instance | BindingFlags.Public)) { - _modLogger.Error($"Could not load mod: {modName}, no type with [MainMod] exists"); - return false; + var def = fieldInfo.GetCustomAttribute(); + if (def != null) + { + fieldInfo.SetValue(modConfiguration, def.DefaultValue); + } } - - - // We want to load the configuration for the mod as well - Type configurationModType = null; - foreach (Assembly asm in modAssemblies) + } + else + { + try { - configurationModType = asm.GetTypes() - .FirstOrDefault(type => type.GetCustomAttribute () != null); - if (configurationModType != null) break; + string json = File.ReadAllText(config_path); + modConfiguration = JsonConvert.DeserializeObject(json,config_type); + } - - if (configurationModType != null) + catch (Exception exception) { - InitializeModConfig(configurationModType, modName); + _modLogger.Error($"Loading mod config failed\nException: {exception}"); + + File.Delete(config_path); + InitializeModConfig(config_type, mod_id); + return; } + } - if (!typeof(Mod).IsAssignableFrom(mainModType)) - { - _modLogger.Error($"Could not load mod: {modName}, the found class ({mainModType.FullName}) with [MainMod] doesn't inherit from {nameof(Mod)}"); + try + { + File.WriteAllLines(config_path, new[] { JsonConvert.SerializeObject(modConfiguration) }); + } + catch (Exception exception) + { + _modLogger.Error($"Saving mod config failed\nException: {exception}"); + } - mainModType = null; - return false; - } + if (ManagerLocator.TryGet(out ConfigurationManager configurationManager)) + { + configurationManager.Add(mod_id,(config_type,modConfiguration,config_path)); + } + } - // Harmony patch everything in the current mod! - Harmony harmony = new Harmony($"com.mod.{modInfo.author}.{modInfo.mod_id}"); - foreach (Assembly asm in modAssemblies) - { - harmony.PatchAll(asm); - } + /// + /// Initializes a mod object. + /// + /// The mod name to initialize. + /// The mod type to initialize. + /// The new mod logger to spawn + private void InitializeModObject(string modName, ModInfo info, Type mainModType) + { + GameObject modObject = new GameObject($"Mod: {modName}"); + Mod modComponent = (Mod)modObject.AddComponent(mainModType); + + _allModScripts.Add(modComponent); + + modComponent.Setup(transform.parent, info); + modObject.SetActive(true); - return true; + _modLogger.Info($"Loaded: {modName}"); + // we probably dont want to completely stop loading mods if 1 mod throws an exception on Initialize + try + { + ModLocator.Add(modComponent); + Persist(modObject); + modComponent.Initialize(); } - - /// - /// Tries to find a specific mods config file, if none is found, one is created - /// - private void InitializeModConfig(Type config_type, string mod_id) + catch(Exception exception) { - object modConfiguration = null; - var config_path = MODS_FULL_PATH + "\\" + mod_id + "\\config\\config.json"; - if (!File.Exists(config_path)) - { - modConfiguration = Activator.CreateInstance(config_type); - foreach (var fieldInfo in config_type.GetFields(BindingFlags.Instance | BindingFlags.Public)) - { - var def = fieldInfo.GetCustomAttribute(); - if (def != null) - { - fieldInfo.SetValue(modConfiguration, def.DefaultValue); - } - } - } - else - { - try - { - string json = File.ReadAllText(config_path); - modConfiguration = JsonConvert.DeserializeObject(json,config_type); - - } - catch (Exception exception) - { - _modLogger.Error($"Loading mod config failed\nException: {exception}"); + _modLogger.Critical($"Exception in {modName} Initialize(): {exception}"); + } - File.Delete(config_path); - InitializeModConfig(config_type, mod_id); - return; - } - } + LoadedMods.Add((modName, info)); + } + /// + /// Calls the OnInitialized method on each initialized mod. + /// + internal void InvokePostInitializeModsAfterAllModsLoaded() + { + foreach (Mod mod in _allModScripts) + { try { - File.WriteAllLines(config_path, new[] { JsonConvert.SerializeObject(modConfiguration) }); + mod.OnInitialized(); } - catch (Exception exception) + catch(Exception exception) { - _modLogger.Error($"Saving mod config failed\nException: {exception}"); + _modLogger.Critical($"Exception in {mod.name} AfterInitialization(): {exception}"); } + } + InitModUI(); + } + /// + /// Initializes the UI for the mod list and configuration menu + /// + private void InitModUI() + { + GameObject modUIObject = new GameObject("Space Warp Mod UI"); + Persist(modUIObject); - if (ManagerLocator.TryGet(out ConfigurationManager configurationManager)) - { - configurationManager.Add(mod_id,(config_type,modConfiguration,config_path)); - } + modUIObject.transform.SetParent(transform.parent); + ModListUI = modUIObject.AddComponent(); + + modUIObject.SetActive(true); + + GameObject consoleUIObject = new GameObject("Space Warp Console"); + Persist(consoleUIObject); + consoleUIObject.transform.SetParent(transform.parent); + SpaceWarpConsole con = consoleUIObject.AddComponent(); + consoleUIObject.SetActive(true); + } + + private static List<(string text, Sprite icon, string ID, Action action)> _buttonsToBeLoaded = + new List<(string text, Sprite icon, string ID, Action action)>(); + + public T RegisterGameToolbarMenu(string text, string title, string id, Sprite icon) where T : ToolbarMenu + { + GameObject toolBarUIObject = new GameObject($"Toolbar: {id}"); + Persist(toolBarUIObject); + ToolbarMenu menu = toolBarUIObject.AddComponent(); + menu.Title = title; + toolBarUIObject.transform.SetParent(transform.parent); + toolBarUIObject.SetActive(true); + _buttonsToBeLoaded.Add((text,icon,id,menu.ToggleGUI)); + return menu as T; + } + + public static void RegisterAppButton(string text, string id, Sprite icon, Action func) => + _buttonsToBeLoaded.Add((text ,icon, id, func)); + + /// + /// Allows an object to persist through KSP 2s destruction + /// + /// Object that should be persisted + public static void Persist(GameObject toPersist) + { + DontDestroyOnLoad(toPersist); + toPersist.tag = "Game Manager"; + } + + private static GUISkin _skin = null; + + public static GUISkin Skin + { + get + { + if (_skin == null) + ResourceManager.TryGetAsset("space_warp/swconsoleui/swconsoleUI/spacewarpConsole.guiskin", out + (_skin)); + return _skin; + } + } + + private void LoadAllButtons() + { + foreach (var button in _buttonsToBeLoaded) + { + ToolbarBackend.AddButton(button.text, button.icon, button.ID, button.action); } + } + + /// + /// Loads a png called 'icon.png' as a sprite from the same folder as the calling dll. + /// In our case this should be SpaceWarp\Mods\[mod]\bin\icon.png + /// + /// The size of the png. The appbar expects 24x24. + public static Sprite LoadIcon(int size = 24) + { + string folderPath = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location); + + return LoadIcon(Path.Combine(folderPath, "icon.png"), size); + } + + /// + /// Loads a png at the given path as a sprite. + /// + /// Path to the png. + /// The size of the png. The appbar expects 24x24. + public static Sprite LoadIcon(string path, int size = 24) + { + Texture2D tex = new Texture2D(size, size, TextureFormat.ARGB32, false); + tex.filterMode = FilterMode.Point; - /// - /// Initializes a mod object. - /// - /// The mod name to initialize. - /// The mod type to initialize. - /// The new mod logger to spawn - private void InitializeModObject(string modName, ModInfo info, Type mainModType) + if (File.Exists(path)) { - GameObject modObject = new GameObject($"Mod: {modName}"); - Mod modComponent = (Mod)modObject.AddComponent(mainModType); - - _allModScripts.Add(modComponent); - - modComponent.Setup(transform.parent, info); - modObject.SetActive(true); - - _modLogger.Info($"Loaded: {modName}"); - - // we probably dont want to completely stop loading mods if 1 mod throws an exception on Initialize - try - { - ModLocator.Add(modComponent); - DontDestroyOnLoad(modObject); - modComponent.Initialize(); - } - catch(Exception exception) - { - _modLogger.Critical($"Exception in {modName} Initialize(): {exception}"); - } + byte[] fileContent = File.ReadAllBytes(path); + ImageConversion.LoadImage(tex, fileContent); + } + + return Sprite.Create(tex, new Rect(0, 0, size, size), new Vector2(0.5f, 0.5f)); + } + + public void InitializeAddressablesFolder() + { + LoadSpaceWarpAddressables(); + } - LoadedMods.Add((modName, info)); + public IEnumerator LoadAddressable(string catalog) + { + _modLogger.Info($"Attempting to load {catalog}"); + AsyncOperationHandle operation = Addressables.LoadContentCatalogAsync(catalog, null); + yield return operation; + if (operation.Status == AsyncOperationStatus.Failed) + { + _modLogger.Error($"Failed to load addressables catalog {catalog}"); + } + else + { + _modLogger.Info($"Loaded addressables catalog {catalog}"); + var locator = operation.Result; + _modLogger.Info($"{catalog} ----- {locator.LocatorId}"); + Game.Assets.RegisterResourceLocator(locator); } + } - /// - /// Calls the OnInitialized method on each initialized mod. - /// - internal void InvokePostInitializeModsAfterAllModsLoaded() + public void LoadSpaceWarpAddressables() + { + string addressablesPath = Path.Combine(SPACE_WARP_PATH,"addressables"); + string catalogPath = Path.Combine(addressablesPath,"catalog.json"); + if (File.Exists(catalogPath)) { - foreach (Mod mod in _allModScripts) - { - try - { - mod.OnInitialized(); - } - catch(Exception exception) - { - _modLogger.Critical($"Exception in {mod.name} AfterInitialization(): {exception}"); - } - } - InitModUI(); + StartCoroutine(LoadAddressable(catalogPath)); + } + } + + public void LoadSingleModAddressables(string modID, ModInfo info) + { + string modFolder = Path.Combine(MODS_FULL_PATH, modID); + string addressablesPath = Path.Combine(modFolder,"addressables"); + _modLogger.Info($"Loading addressables for {modID}"); + string catalogPath = Path.Combine(addressablesPath, "catalog.json"); + if (File.Exists(catalogPath)) + { + _modLogger.Info($"Found addressables for {modID}"); + StartCoroutine(LoadAddressable(catalogPath)); } - /// - /// Initializes the UI for the mod list and configuration menu - /// - private void InitModUI() + else { - GameObject modUIObject = new GameObject("Space Warp Mod UI"); - DontDestroyOnLoad(modUIObject); + _modLogger.Info($"Did not find addressables for {modID}"); + } + } - modUIObject.transform.SetParent(transform.parent); - ModListUI = modUIObject.AddComponent(); + private void LoadLocalizationFromFolder(string folder) + { + _modLogger.Info($"Attempting to load localizations from {folder}"); + I2.Loc.LanguageSourceData languageSourceData = null; + if (!Directory.Exists(folder)) + { + _modLogger.Info($"{folder} does not exist, not loading localizations."); + return; + } + DirectoryInfo info = new DirectoryInfo(folder); + foreach (var csvFile in info.GetFiles("*.csv")) + { + languageSourceData ??= new I2.Loc.LanguageSourceData(); + var csvData = File.ReadAllText(csvFile.FullName); + languageSourceData.Import_CSV("", csvData, I2.Loc.eSpreadsheetUpdateMode.AddNewTerms); + } - modUIObject.SetActive(true); + foreach (var i2csvFile in info.GetFiles("*.i2csv")) + { + languageSourceData ??= new I2.Loc.LanguageSourceData(); + var i2csvData = File.ReadAllText(i2csvFile.FullName); + languageSourceData.Import_I2CSV("", i2csvData, I2.Loc.eSpreadsheetUpdateMode.AddNewTerms); + } - GameObject consoleUIObject = new GameObject("Space Warp Console"); - DontDestroyOnLoad(consoleUIObject); - consoleUIObject.transform.SetParent(transform.parent); - SpaceWarpConsole con = consoleUIObject.AddComponent(); - consoleUIObject.SetActive(true); + if (languageSourceData != null) + { + _modLogger.Info($"Loaded localizations from {folder}"); + I2.Loc.LocalizationManager.AddSource(languageSourceData); } + else + { + _modLogger.Info($"No localizations found in {folder}"); + } + } + public void LoadSpaceWarpLocalizations() + { + if (I2.Loc.LocalizationManager.Sources.Count == 0) + { + I2.Loc.LocalizationManager.UpdateSources(); + } + + string localizationsPath = Path.Combine(SPACE_WARP_PATH, "localizations"); + LoadLocalizationFromFolder(localizationsPath); + } + + public void LoadSingleModLocalization(string modID, ModInfo info) + { + string modFolder = Path.Combine(MODS_FULL_PATH, modID); + string localizationsPath = Path.Combine(modFolder, "localizations"); + LoadLocalizationFromFolder(localizationsPath); } } \ No newline at end of file diff --git a/SpaceWarp/API/Toolbar/ToolbarBackend.cs b/SpaceWarp/API/Toolbar/ToolbarBackend.cs new file mode 100644 index 00000000..b1636a93 --- /dev/null +++ b/SpaceWarp/API/Toolbar/ToolbarBackend.cs @@ -0,0 +1,105 @@ +// Attribution Notice To Lawrence/HatBat of https://github.com/Halbann/LazyOrbit +// This file is licensed under https://creativecommons.org/licenses/by-sa/4.0/ + +using System; +using System.Collections; +using HarmonyLib; +using I2.Loc; +using KSP.Api; +using KSP.Api.CoreTypes; +using KSP.Sim.impl; +using KSP.UI.Binding; +using KSP.UI.Flight; +using SpaceWarp.API.Logging; +using TMPro; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using Object = UnityEngine.Object; + +namespace SpaceWarp.API.Toolbar; + +public static class ToolbarBackend +{ + private static BaseModLogger _logger = new ModLogger("ToolbarBackend"); + public static GameObject AddButton(string buttonText, Sprite buttonIcon, string buttonId, Action function) + { + // Find the resource manager button and "others" group. + + // Say the magic words... + GameObject list = GameObject.Find("GameManager/Default Game Instance(Clone)/UI Manager(Clone)/Popup Canvas/Container/ButtonBar/BTN-App-Tray/appbar-others-group"); + GameObject resourceManger = list?.GetChild("BTN-Resource-Manager"); + + if (list == null || resourceManger == null) + { + _logger.Info("Couldn't find appbar."); + return null; + } + + // Clone the resource manager button. + GameObject appButton = Object.Instantiate(resourceManger, list.transform); + appButton.name = buttonId; + + // Change the text. + TextMeshProUGUI text = appButton.GetChild("Content").GetChild("TXT-title").GetComponent(); + text.text = buttonText; + + Localize localizer = text.gameObject.GetComponent(); + if (localizer) + Object.Destroy(localizer); + + // Change the icon. + GameObject icon = appButton.GetChild("Content").GetChild("GRP-icon"); + Image image = icon.GetChild("ICO-asset").GetComponent(); + image.sprite = buttonIcon; + + // Add our function call to the toggle. + ToggleExtended utoggle = appButton.GetComponent(); + utoggle.onValueChanged.AddListener(state => function(state)); + + // Set the initial state of the button. + UIValue_WriteBool_Toggle toggle = appButton.GetComponent(); + toggle.BindValue(new Property(false)); + + // Bind the action to close the tray after pressing the button. + IAction action = resourceManger.GetComponent().Action; + appButton.GetComponent().BindAction(action); + + _logger.Info($"Added appbar button: {buttonId}"); + + return appButton; + } + + public static UnityEvent AppBarInFlightSubscriber = new UnityEvent(); + + internal static void SubscriberSchedulePing() + { + GameObject gameObject = new GameObject(); + gameObject.AddComponent(); + gameObject.SetActive(true); + } +} + +class ToolbarBackendObject : KerbalBehavior +{ + public new void Start() + { + + StartCoroutine(awaiter()); + } + + private IEnumerator awaiter() + { + yield return new WaitForSeconds(1); + ToolbarBackend.AppBarInFlightSubscriber.Invoke(); + Destroy(this); + } +} + +//TODO: Much better way of doing this +[HarmonyPatch(typeof(UIFlightHud))] +[HarmonyPatch("Start")] +class ToolbarBackendAppBarPatcher +{ + public static void Postfix(UIFlightHud __instance) => ToolbarBackend.SubscriberSchedulePing(); +} \ No newline at end of file diff --git a/SpaceWarp/API/Toolbar/ToolbarMenu.cs b/SpaceWarp/API/Toolbar/ToolbarMenu.cs new file mode 100644 index 00000000..d880dd84 --- /dev/null +++ b/SpaceWarp/API/Toolbar/ToolbarMenu.cs @@ -0,0 +1,87 @@ +using System.IO; +using System.Reflection; +using KSP.Game; +using KSP.Sim.impl; +using SpaceWarp.API.AssetBundles; +using UnityEngine; + +namespace SpaceWarp.API.Toolbar; + +public abstract class ToolbarMenu : KerbalBehavior +{ + private GUISkin _spaceWarpConsoleSkin = null; + private bool _drawing = false; + + public abstract float Width + { + get; + } + + public abstract float Height + { + get; + } + + public abstract float X + { + get; + } + + public abstract float Y + { + get; + } + + public virtual GUISkin Skin + { + get + { + if (_spaceWarpConsoleSkin == null) + { + ResourceManager.TryGetAsset($"space_warp/swconsoleui/swconsoleUI/spacewarpConsole.guiskin", out _spaceWarpConsoleSkin); + } + + return _spaceWarpConsoleSkin; + } + } + + public string Title; + private Rect _windowRect; + + public new void Awake() + { + _windowRect = new Rect(X, Y, 0, 0); + } + + public void OnGUI() + { + if (!_drawing + || GameManager.Instance.Game.GlobalGameState.GetState() != GameState.FlightView) return; + GUI.skin = Skin; + + int controlID = GUIUtility.GetControlID(FocusType.Passive); + + GUILayoutOption width = GUILayout.Width(Width); + GUILayoutOption height = GUILayout.Height(Height); + + _windowRect = GUILayout.Window(controlID, _windowRect, DoDrawing, Title, width, height); + } + + internal void ToggleGUI(bool drawing) + { + _drawing = drawing; + } + + public void ToggleGUI() + { + _drawing = !_drawing; + } + + private void DoDrawing(int windowID) + { + DrawWindow(windowID); + GUI.DragWindow(new Rect(0, 0, 10000, 10000)); + } + + public abstract void DrawWindow(int windowID); +} \ No newline at end of file diff --git a/SpaceWarp/API/Versions/VersionUtility.cs b/SpaceWarp/API/Versions/VersionUtility.cs index 3ccf5f7b..defaff80 100644 --- a/SpaceWarp/API/Versions/VersionUtility.cs +++ b/SpaceWarp/API/Versions/VersionUtility.cs @@ -1,59 +1,56 @@ -using System; +namespace SpaceWarp.API.Versions; -namespace SpaceWarp.API.Versions +public static class VersionUtility { - public static class VersionUtility + public static bool IsVersionAbove(string version, string toCheck) { - public static bool IsVersionAbove(string version, string toCheck) + if (version == "") { - if (version == "") + return true; + } + + string[] semanticVersion = toCheck.Split('.'); + string[] requiredVersion = version.Split('.'); + + for (int i = 0; i < requiredVersion.Length; i++) + { + if (requiredVersion[i] == "*") { - return true; + continue; } - string[] semanticVersion = toCheck.Split('.'); - string[] requiredVersion = version.Split('.'); - - for (int i = 0; i < requiredVersion.Length; i++) + if (int.Parse(semanticVersion[i]) < int.Parse(requiredVersion[i])) { - if (requiredVersion[i] == "*") - { - continue; - } - - if (int.Parse(semanticVersion[i]) < int.Parse(requiredVersion[i])) - { - return false; - } + return false; } + } + + return true; + } + public static bool IsVersionBellow(string version, string toCheck) + { + if (version == "") + { return true; } - public static bool IsVersionBellow(string version, string toCheck) + string[] semanticVersion = toCheck.Split('.'); + string[] requiredVersion = version.Split('.'); + + for (int i = 0; i < requiredVersion.Length; i++) { - if (version == "") + if (requiredVersion[i] == "*") { - return true; + continue; } - string[] semanticVersion = toCheck.Split('.'); - string[] requiredVersion = version.Split('.'); - - for (int i = 0; i < requiredVersion.Length; i++) + if (int.Parse(semanticVersion[i]) > int.Parse(requiredVersion[i])) { - if (requiredVersion[i] == "*") - { - continue; - } - - if (int.Parse(semanticVersion[i]) > int.Parse(requiredVersion[i])) - { - return false; - } + return false; } - - return true; } + + return true; } } \ No newline at end of file diff --git a/SpaceWarp/Compilation/ModCompiler.cs b/SpaceWarp/Compilation/ModCompiler.cs index db5f1e26..6adeb741 100644 --- a/SpaceWarp/Compilation/ModCompiler.cs +++ b/SpaceWarp/Compilation/ModCompiler.cs @@ -8,125 +8,125 @@ using SpaceWarp.API.Logging; using UniLinq; -namespace SpaceWarp.Compilation +namespace SpaceWarp.Compilation; + +public static class ModCompiler { - public static class ModCompiler - { - public static string CACHE_LOCATION = SpaceWarpManager.SPACE_WARP_PATH + "mod_cache/"; + public static readonly string CACHE_LOCATION = Path.Combine(SpaceWarpManager.SPACE_WARP_PATH,"mod_cache"); - private static BaseModLogger _logger = new ModLogger("Roslyn Compilation"); - public static Assembly CompileMod(string modID, string modSrcPath) + private static BaseModLogger _logger = new ModLogger("Roslyn Compilation"); + public static Assembly CompileMod(string modID, string modSrcPath) + { + try { - try + if (!Directory.Exists(modSrcPath)) { - if (!Directory.Exists(modSrcPath)) - { - return null; - } - _logger.Info($"starting compilation of {modID}"); - - if (!CreateNewCompilation(modID, modSrcPath)) - { - _logger.Info($"found cached version of {modID}"); - return GetCachedCompilation(modID); - } - - _logger.Info($"no cached version for {modID}, generating assembly"); - - // Now work on adding dependencies to the tree - return CompileNewAssemblyAndCache(modID, modSrcPath); + return null; } - catch (Exception e) + _logger.Info($"starting compilation of {modID}"); + + if (!CreateNewCompilation(modID, modSrcPath)) { - _logger.Error($"error compiling scripts for {modID}\n{e}"); - return null; + _logger.Info($"found cached version of {modID}"); + return GetCachedCompilation(modID); } + + _logger.Info($"no cached version for {modID}, generating assembly"); + + // Now work on adding dependencies to the tree + return CompileNewAssemblyAndCache(modID, modSrcPath); } - - private static string[] AllSourceFiles(string modSrcPath) + catch (Exception e) { - DirectoryInfo d = new DirectoryInfo(modSrcPath); - string[] sourceFiles = d.EnumerateFiles("*.cs", SearchOption.AllDirectories).Select(a => a.FullName) - .ToArray(); - return sourceFiles; + _logger.Error($"error compiling scripts for {modID}\n{e}"); + return null; } + } + + private static string[] AllSourceFiles(string modSrcPath) + { + DirectoryInfo directoryInfo = new DirectoryInfo(modSrcPath); + string[] sourceFiles = directoryInfo.EnumerateFiles("*.cs", SearchOption.AllDirectories) + .Select(fileInfo => fileInfo.FullName) + .ToArray(); + return sourceFiles; + } - private static bool CreateNewCompilation(string modID, string modSrcPath) + private static bool CreateNewCompilation(string modID, string modSrcPath) + { + string[] allSourceFiles = AllSourceFiles(modSrcPath); + DateTime latestWriteTime = DateTime.FromBinary(0); + foreach (var sourceFile in allSourceFiles) { - var allSourceFiles = AllSourceFiles(modSrcPath); - DateTime latestWriteTime = DateTime.FromBinary(0); - foreach (var sourceFile in allSourceFiles) - { - if (File.GetLastWriteTime(sourceFile) > latestWriteTime) - { - latestWriteTime = File.GetLastWriteTime(sourceFile); - } - } - - if (!Directory.Exists(CACHE_LOCATION)) - { - Directory.CreateDirectory(CACHE_LOCATION); - return true; - } - - if (!File.Exists(CACHE_LOCATION + modID + ".dll")) + if (File.GetLastWriteTime(sourceFile) > latestWriteTime) { - return true; + latestWriteTime = File.GetLastWriteTime(sourceFile); } + } - if (File.GetLastWriteTime(CACHE_LOCATION + modID + ".dll") < latestWriteTime) - { - return true; - } - - return false; + if (!Directory.Exists(CACHE_LOCATION)) + { + Directory.CreateDirectory(CACHE_LOCATION); + return true; } - private static Assembly GetCachedCompilation(string modID) + if (!File.Exists(Path.Combine(CACHE_LOCATION,modID + ".dll"))) { - return Assembly.LoadFrom(CACHE_LOCATION + modID + ".dll"); + return true; } - private static Assembly CompileNewAssemblyAndCache(string modID, string modSrcPath) + if (File.GetLastWriteTime(Path.Combine(CACHE_LOCATION,modID + ".dll")) < latestWriteTime) { - var allSourceFiles = AllSourceFiles(modSrcPath); - List trees = new List(); - foreach (string file in allSourceFiles) - { - string code = File.ReadAllText(file); - SyntaxTree tree = CSharpSyntaxTree.ParseText(code); - trees.Add(tree); - } + return true; + } + + return false; + } - List references = new List(); - foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) - { - if (asm.IsDynamic) continue; - references.Add(MetadataReference.CreateFromFile(asm.Location)); - } + private static Assembly GetCachedCompilation(string modID) + { + return Assembly.LoadFrom(Path.Combine(CACHE_LOCATION,modID + ".dll")); + } + + private static Assembly CompileNewAssemblyAndCache(string modID, string modSrcPath) + { + string[] allSourceFiles = AllSourceFiles(modSrcPath); + List trees = Enumerable.ToList( + Enumerable.Select( + Enumerable.Select(allSourceFiles, File.ReadAllText), + code => CSharpSyntaxTree.ParseText(code) + ) + ); + + List references = Enumerable.ToList( + Enumerable.Cast( + from asm in AppDomain.CurrentDomain.GetAssemblies() + where !asm.IsDynamic + select MetadataReference.CreateFromFile(asm.Location) + ) + ); - var compilation = CSharpCompilation.Create(modID + ".dll", trees, references, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true)); + var compilation = CSharpCompilation.Create(modID + ".dll", trees, references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true)); - var result = compilation.Emit(CACHE_LOCATION + modID + ".dll"); - foreach (Diagnostic diagnostic in result.Diagnostics) + var result = compilation.Emit(Path.Combine(CACHE_LOCATION,modID + ".dll")); + foreach (Diagnostic diagnostic in result.Diagnostics) + { + if (diagnostic.WarningLevel == 0) { - if (diagnostic.WarningLevel == 0) - { - _logger.Error(diagnostic.ToString()); - } - else - { - _logger.Info(diagnostic.ToString()); - } + _logger.Error(diagnostic.ToString()); } - - _logger.Info(result.ToString()); - if (!result.Success) + else { - File.Delete(CACHE_LOCATION + modID + ".dll"); + _logger.Info(diagnostic.ToString()); } - return !result.Success ? null : Assembly.LoadFile(CACHE_LOCATION + modID + ".dll"); } + + _logger.Info(result.ToString()); + if (!result.Success) + { + File.Delete(Path.Combine(CACHE_LOCATION,modID + ".dll")); + } + return !result.Success ? null : Assembly.LoadFile(Path.Combine(CACHE_LOCATION,modID + ".dll")); } } \ No newline at end of file diff --git a/SpaceWarp/Entrypoint.cs b/SpaceWarp/Entrypoint.cs index 08651d40..15fed0cd 100644 --- a/SpaceWarp/Entrypoint.cs +++ b/SpaceWarp/Entrypoint.cs @@ -4,6 +4,7 @@ using SpaceWarp.UI; using System.Reflection; using UnityEngine.SceneManagement; +using HarmonyLogger = HarmonyLib.Tools.Logger; #if DOORSTOP_BUILD namespace Doorstop @@ -28,6 +29,11 @@ public static void Start() SceneManager.sceneLoaded += OnSceneLoaded; KspLogManager.AddLogCallback(SpaceWarpConsoleLogListener.LogCallback); + if (SpaceWarpGlobalConfiguration.Instance.HarmonyLoggin) + { + HarmonyLogger.ChannelFilter = HarmonyLogger.LogChannel.All; + HarmonyLogger.MessageReceived += SpaceWarpConsoleLogListener.HarmonyLogCallback; + } } /// diff --git a/SpaceWarp/Patching/LoadingActions/AfterModsLoadedAction.cs b/SpaceWarp/Patching/LoadingActions/AfterModsLoadedAction.cs index 3b3c1655..41a54d2d 100644 --- a/SpaceWarp/Patching/LoadingActions/AfterModsLoadedAction.cs +++ b/SpaceWarp/Patching/LoadingActions/AfterModsLoadedAction.cs @@ -3,28 +3,27 @@ using SpaceWarp.API; using SpaceWarp.API.Managers; -namespace SpaceWarp.Patching.LoadingActions +namespace SpaceWarp.Patching.LoadingActions; + +public class AfterModsLoadedAction : FlowAction { - public class AfterModsLoadedAction : FlowAction + public AfterModsLoadedAction(string name) : base(name) + { + // + } + + public override void DoAction(Action resolve, Action reject) { - public AfterModsLoadedAction(string name) : base(name) + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try { - // + spaceWarpManager.InvokePostInitializeModsAfterAllModsLoaded(); + resolve(); } - - protected override void DoAction(Action resolve, Action reject) + catch (Exception e) { - ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); - - try - { - spaceWarpManager.InvokePostInitializeModsAfterAllModsLoaded(); - resolve(); - } - catch (Exception e) - { - reject(e.ToString()); - } + reject(e.ToString()); } } } \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/LoadAddressablesAction.cs b/SpaceWarp/Patching/LoadingActions/LoadAddressablesAction.cs new file mode 100644 index 00000000..e3594a75 --- /dev/null +++ b/SpaceWarp/Patching/LoadingActions/LoadAddressablesAction.cs @@ -0,0 +1,34 @@ +using System; +using KSP.Game.Flow; +using SpaceWarp.API; +using SpaceWarp.API.Managers; +using SpaceWarp.API.Mods.JSON; + +namespace SpaceWarp.Patching.LoadingActions; + +public class LoadAddressablesAction : FlowAction +{ + private string _modID; + private ModInfo _info; + + public LoadAddressablesAction(string name, string modID, ModInfo info) : base(name) + { + _modID = modID; + _info = info; + } + + public override void DoAction(Action resolve, Action reject) + { + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try + { + spaceWarpManager.LoadSingleModAddressables(_modID,_info); + resolve(); + } + catch (Exception e) + { + reject(e.ToString()); + } + } +} \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/LoadAssetAction.cs b/SpaceWarp/Patching/LoadingActions/LoadAssetAction.cs index 0a626d4a..299bc1d0 100644 --- a/SpaceWarp/Patching/LoadingActions/LoadAssetAction.cs +++ b/SpaceWarp/Patching/LoadingActions/LoadAssetAction.cs @@ -1,35 +1,33 @@ using System; using KSP.Game.Flow; using SpaceWarp.API; -using SpaceWarp.API.Configuration; using SpaceWarp.API.Managers; using SpaceWarp.API.Mods.JSON; -namespace SpaceWarp.Patching.LoadingActions +namespace SpaceWarp.Patching.LoadingActions; + +public class LoadAssetAction : FlowAction { - public class LoadAssetAction : FlowAction + private readonly string _modID; + private readonly ModInfo _info; + public LoadAssetAction(string name, string modID, ModInfo info) : base(name) + { + _modID = modID; + _info = info; + } + + public override void DoAction(Action resolve, Action reject) { - private readonly string _modID; - private readonly ModInfo _info; - public LoadAssetAction(string name, string modID, ModInfo info) : base(name) + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try { - _modID = modID; - _info = info; + spaceWarpManager.LoadSingleModAssets(_modID,_info); + resolve(); } - - protected override void DoAction(Action resolve, Action reject) + catch (Exception e) { - ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); - - try - { - spaceWarpManager.LoadSingleModAssets(_modID,_info); - resolve(); - } - catch (Exception e) - { - reject(e.ToString()); - } + reject(e.ToString()); } } } \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/LoadAssetsAction.cs b/SpaceWarp/Patching/LoadingActions/LoadAssetsAction.cs index af9d4f7e..588bc932 100644 --- a/SpaceWarp/Patching/LoadingActions/LoadAssetsAction.cs +++ b/SpaceWarp/Patching/LoadingActions/LoadAssetsAction.cs @@ -3,28 +3,27 @@ using SpaceWarp.API; using SpaceWarp.API.Managers; -namespace SpaceWarp.Patching.LoadingActions +namespace SpaceWarp.Patching.LoadingActions; + +public class LoadAssetsAction : FlowAction { - public class LoadAssetsAction : FlowAction + public LoadAssetsAction(string name) : base(name) + { + // + } + + public override void DoAction(Action resolve, Action reject) { - public LoadAssetsAction(string name) : base(name) + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try { - // + spaceWarpManager.InitializeAssets(); + resolve(); } - - protected override void DoAction(Action resolve, Action reject) + catch (Exception e) { - ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); - - try - { - spaceWarpManager.InitializeAssets(); - resolve(); - } - catch (Exception e) - { - reject(e.ToString()); - } + reject(e.ToString()); } } } \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/LoadLocalizationAction.cs b/SpaceWarp/Patching/LoadingActions/LoadLocalizationAction.cs new file mode 100644 index 00000000..0b6131bb --- /dev/null +++ b/SpaceWarp/Patching/LoadingActions/LoadLocalizationAction.cs @@ -0,0 +1,34 @@ +using System; +using KSP.Game.Flow; +using SpaceWarp.API; +using SpaceWarp.API.Managers; +using SpaceWarp.API.Mods.JSON; + +namespace SpaceWarp.Patching.LoadingActions; + +public class LoadLocalizationAction : FlowAction +{ + private string _modID; + private ModInfo _info; + + public LoadLocalizationAction(string name, string modID, ModInfo info) : base(name) + { + _modID = modID; + _info = info; + } + + public override void DoAction(Action resolve, Action reject) + { + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try + { + spaceWarpManager.LoadSingleModLocalization(_modID,_info); + resolve(); + } + catch (Exception e) + { + reject(e.ToString()); + } + } +} \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/LoadModAction.cs b/SpaceWarp/Patching/LoadingActions/LoadModAction.cs index a6d8f509..500608c7 100644 --- a/SpaceWarp/Patching/LoadingActions/LoadModAction.cs +++ b/SpaceWarp/Patching/LoadingActions/LoadModAction.cs @@ -1,36 +1,34 @@ using System; using KSP.Game.Flow; using SpaceWarp.API; -using SpaceWarp.API.Configuration; using SpaceWarp.API.Managers; using SpaceWarp.API.Mods.JSON; -namespace SpaceWarp.Patching.LoadingActions +namespace SpaceWarp.Patching.LoadingActions; + +public class LoadModAction : FlowAction { - public class LoadModAction : FlowAction - { - private readonly string _modID; - private readonly ModInfo _info; + private readonly string _modID; + private readonly ModInfo _info; - public LoadModAction(string name, string modID, ModInfo info) : base(name) + public LoadModAction(string name, string modID, ModInfo info) : base(name) + { + _modID = modID; + _info = info; + } + + public override void DoAction(Action resolve, Action reject) + { + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try { - _modID = modID; - _info = info; + spaceWarpManager.InitializeSingleMod(_modID,_info); + resolve(); } - - protected override void DoAction(Action resolve, Action reject) + catch (Exception e) { - ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); - - try - { - spaceWarpManager.InitializeSingleMod(_modID,_info); - resolve(); - } - catch (Exception e) - { - reject(e.ToString()); - } + reject(e.ToString()); } } } \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/LoadModsAction.cs b/SpaceWarp/Patching/LoadingActions/LoadModsAction.cs index 3cb6048a..9c23442e 100644 --- a/SpaceWarp/Patching/LoadingActions/LoadModsAction.cs +++ b/SpaceWarp/Patching/LoadingActions/LoadModsAction.cs @@ -3,28 +3,27 @@ using SpaceWarp.API; using SpaceWarp.API.Managers; -namespace SpaceWarp.Patching.LoadingActions +namespace SpaceWarp.Patching.LoadingActions; + +public class LoadModsAction : FlowAction { - public class LoadModsAction : FlowAction + public LoadModsAction(string name) : base(name) + { + // + } + + public override void DoAction(Action resolve, Action reject) { - public LoadModsAction(string name) : base(name) + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try { - // + spaceWarpManager.InitializeMods(); + resolve(); } - - protected override void DoAction(Action resolve, Action reject) + catch (Exception e) { - ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); - - try - { - spaceWarpManager.InitializeMods(); - resolve(); - } - catch (Exception e) - { - reject(e.ToString()); - } + reject(e.ToString()); } } } \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/LoadSpaceWarpAddressablesAction.cs b/SpaceWarp/Patching/LoadingActions/LoadSpaceWarpAddressablesAction.cs new file mode 100644 index 00000000..c857ce8d --- /dev/null +++ b/SpaceWarp/Patching/LoadingActions/LoadSpaceWarpAddressablesAction.cs @@ -0,0 +1,28 @@ +using System; +using KSP.Game.Flow; +using SpaceWarp.API; +using SpaceWarp.API.Managers; + +namespace SpaceWarp.Patching.LoadingActions; + +public class LoadSpaceWarpAddressablesAction : FlowAction +{ + public LoadSpaceWarpAddressablesAction(string name) : base(name) + { + } + + public override void DoAction(Action resolve, Action reject) + { + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try + { + spaceWarpManager.InitializeAddressablesFolder(); + resolve(); + } + catch (Exception e) + { + reject(e.ToString()); + } + } +} \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/LoadSpaceWarpLocalizationsAction.cs b/SpaceWarp/Patching/LoadingActions/LoadSpaceWarpLocalizationsAction.cs new file mode 100644 index 00000000..8f347067 --- /dev/null +++ b/SpaceWarp/Patching/LoadingActions/LoadSpaceWarpLocalizationsAction.cs @@ -0,0 +1,28 @@ +using System; +using KSP.Game.Flow; +using SpaceWarp.API; +using SpaceWarp.API.Managers; + +namespace SpaceWarp.Patching.LoadingActions; + +public class LoadSpaceWarpLocalizationsAction : FlowAction +{ + public LoadSpaceWarpLocalizationsAction(string name) : base(name) + { + } + + public override void DoAction(Action resolve, Action reject) + { + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try + { + spaceWarpManager.LoadSpaceWarpLocalizations(); + resolve(); + } + catch (Exception e) + { + reject(e.ToString()); + } + } +} \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/ReadingModsAction.cs b/SpaceWarp/Patching/LoadingActions/ReadingModsAction.cs index b4dce741..ea3698c1 100644 --- a/SpaceWarp/Patching/LoadingActions/ReadingModsAction.cs +++ b/SpaceWarp/Patching/LoadingActions/ReadingModsAction.cs @@ -3,28 +3,27 @@ using SpaceWarp.API; using SpaceWarp.API.Managers; -namespace SpaceWarp.Patching.LoadingActions +namespace SpaceWarp.Patching.LoadingActions; + +public class ReadingModsAction : FlowAction { - public class ReadingModsAction : FlowAction + public ReadingModsAction(string name) : base(name) + { + // + } + + public override void DoAction(Action resolve, Action reject) { - public ReadingModsAction(string name) : base(name) + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try { - // + spaceWarpManager.ReadMods(); + resolve(); } - - protected override void DoAction(Action resolve, Action reject) + catch (Exception e) { - ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); - - try - { - spaceWarpManager.ReadMods(); - resolve(); - } - catch (Exception e) - { - reject(e.ToString()); - } + reject(e.ToString()); } } } \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingActions/SpaceWarpAssetInitializationAction.cs b/SpaceWarp/Patching/LoadingActions/SpaceWarpAssetInitializationAction.cs index add8b97f..e531f366 100644 --- a/SpaceWarp/Patching/LoadingActions/SpaceWarpAssetInitializationAction.cs +++ b/SpaceWarp/Patching/LoadingActions/SpaceWarpAssetInitializationAction.cs @@ -3,27 +3,26 @@ using SpaceWarp.API; using SpaceWarp.API.Managers; -namespace SpaceWarp.Patching.LoadingActions +namespace SpaceWarp.Patching.LoadingActions; + +public class SpaceWarpAssetInitializationAction : FlowAction { - public class SpaceWarpAssetInitializationAction : FlowAction + public SpaceWarpAssetInitializationAction(string name) : base(name) + { + } + + public override void DoAction(Action resolve, Action reject) { - public SpaceWarpAssetInitializationAction(string name) : base(name) + ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); + + try { + spaceWarpManager.LoadSpaceWarpAssets(); + resolve(); } - - protected override void DoAction(Action resolve, Action reject) + catch (Exception e) { - ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager); - - try - { - spaceWarpManager.LoadSpaceWarpAssets(); - resolve(); - } - catch (Exception e) - { - reject(e.ToString()); - } + reject(e.ToString()); } } } \ No newline at end of file diff --git a/SpaceWarp/Patching/LoadingScreenPatcher.cs b/SpaceWarp/Patching/LoadingScreenPatcher.cs index 7eba11d8..ad7ff4e4 100644 --- a/SpaceWarp/Patching/LoadingScreenPatcher.cs +++ b/SpaceWarp/Patching/LoadingScreenPatcher.cs @@ -1,38 +1,42 @@ -using HarmonyLib; -using KSP.Game; +using KSP.Game; using SpaceWarp.API; using SpaceWarp.API.Managers; using SpaceWarp.Patching.LoadingActions; -namespace SpaceWarp.Patching +namespace SpaceWarp.Patching; + +/// +/// Patches the loading screen to add the mod loading +/// +public class LoadingScreenPatcher { - /// - /// Patches the loading screen to add the mod loading - /// - public class LoadingScreenPatcher + public static void AddModLoadingScreens() { - public static void AddModLoadingScreens() - { - - GameManager gameManager = GameManager.Instance; - gameManager.LoadingFlow.AddAction(new ReadingModsAction("Resolving Space Warp Mod Load Order")); - gameManager.LoadingFlow.AddAction(new SpaceWarpAssetInitializationAction("Initializing Space Warp Provided Assets")); - } + GameManager gameManager = GameManager.Instance; + gameManager.LoadingFlow.AddAction(new ReadingModsAction("Resolving Space Warp Mod Load Order")); + gameManager.LoadingFlow.AddAction( + new LoadSpaceWarpAddressablesAction("Initializing Space Warp Provided Addressables")); + gameManager.LoadingFlow.AddAction( + new SpaceWarpAssetInitializationAction("Initializing Space Warp Provided Assets")); + gameManager.LoadingFlow.AddAction( + new LoadSpaceWarpLocalizationsAction("Initializing Space Warp Localizations")); + } - public static void AddAllModLoadingSteps() + public static void AddAllModLoadingSteps() + { + GameManager gameManager = GameManager.Instance; + if (!ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager)) return; //TODO: Log a message here + foreach (var mod in spaceWarpManager._modLoadOrder) { - - GameManager gameManager = GameManager.Instance; - if (!ManagerLocator.TryGet(out SpaceWarpManager spaceWarpManager)) return; //TODO: Log a message here - foreach (var mod in spaceWarpManager._modLoadOrder) - { - gameManager.LoadingFlow.AddAction(new LoadAssetAction($"Loading assets for {mod.Item1}",mod.Item1, mod.Item2)); - gameManager.LoadingFlow.AddAction(new LoadModAction($"Initializing {mod.Item1}",mod.Item1, mod.Item2)); - } - - gameManager.LoadingFlow.AddAction(new AfterModsLoadedAction("Space Warp Mod Post-Initialization")); - + gameManager.LoadingFlow.AddAction(new LoadAddressablesAction($"Loading addressables for {mod.Item1}", + mod.Item1, mod.Item2)); + gameManager.LoadingFlow.AddAction(new LoadAssetAction($"Loading assets for {mod.Item1}", mod.Item1, + mod.Item2)); + gameManager.LoadingFlow.AddAction(new LoadLocalizationAction($"Loading localizations for {mod.Item1}", mod.Item1, mod.Item2)); + gameManager.LoadingFlow.AddAction(new LoadModAction($"Initializing {mod.Item1}", mod.Item1, mod.Item2)); } + + gameManager.LoadingFlow.AddAction(new AfterModsLoadedAction("Space Warp Mod Post-Initialization")); } } \ No newline at end of file diff --git a/SpaceWarp/Patching/MainMenuPatcher.cs b/SpaceWarp/Patching/MainMenuPatcher.cs index a5194069..dd435a69 100644 --- a/SpaceWarp/Patching/MainMenuPatcher.cs +++ b/SpaceWarp/Patching/MainMenuPatcher.cs @@ -1,52 +1,49 @@ using HarmonyLib; using KSP.Api.CoreTypes; -using KSP.Game; using SpaceWarp.API; using SpaceWarp.API.Managers; using TMPro; using UnityEngine; -namespace SpaceWarp.Patching -{ +namespace SpaceWarp.Patching; - [HarmonyPatch(typeof(KSP.Game.StartupFlow.LandingHUD))] - [HarmonyPatch("Start")] - class MainMenuPatcher +[HarmonyPatch(typeof(KSP.Game.StartupFlow.LandingHUD))] +[HarmonyPatch("Start")] +class MainMenuPatcher +{ + public static void Postfix(KSP.Game.StartupFlow.LandingHUD __instance) { - public static void Postfix(KSP.Game.StartupFlow.LandingHUD __instance) - { - Transform menuItemsGroupTransform = __instance.transform.FindChildEx("MenuItemsGroup"); + Transform menuItemsGroupTransform = __instance.transform.FindChildEx("MenuItemsGroup"); - Transform singleplayerButtonTransform = menuItemsGroupTransform.FindChildEx("Singleplayer"); + Transform singleplayerButtonTransform = menuItemsGroupTransform.FindChildEx("Singleplayer"); - GameObject modsButton = Object.Instantiate(singleplayerButtonTransform.gameObject, menuItemsGroupTransform, false); - modsButton.name = "Mods"; + GameObject modsButton = Object.Instantiate(singleplayerButtonTransform.gameObject, menuItemsGroupTransform, false); + modsButton.name = "Mods"; - // Move the button to be above the Exit button. - modsButton.transform.SetSiblingIndex(modsButton.transform.GetSiblingIndex() - 1); + // Move the button to be above the Exit button. + modsButton.transform.SetSiblingIndex(modsButton.transform.GetSiblingIndex() - 1); - // Rebind the button's action to open the mod manager dialog. - UIAction_Void_Button uiAction = modsButton.GetComponent(); - DelegateAction action = new DelegateAction(); - action.BindDelegate(ModsOnClick); - uiAction.BindAction(action); + // Rebind the button's action to open the mod manager dialog. + UIAction_Void_Button uiAction = modsButton.GetComponent(); + DelegateAction action = new DelegateAction(); + action.BindDelegate(ModsOnClick); + uiAction.BindAction(action); - // Set the label to "Mods". - TextMeshProUGUI tmp = modsButton.GetComponentInChildren(); + // Set the label to "Mods". + TextMeshProUGUI tmp = modsButton.GetComponentInChildren(); - tmp.SetText("Mods"); + tmp.SetText("Mods"); - } + } - static void ModsOnClick() - { - bool found = ManagerLocator.TryGet(out SpaceWarpManager manager); + static void ModsOnClick() + { + bool found = ManagerLocator.TryGet(out SpaceWarpManager manager); - if (found) - { - manager.ModListUI.ToggleVisible(); - } + if (found) + { + manager.ModListUI.ToggleVisible(); } } -} +} \ No newline at end of file diff --git a/SpaceWarp/Patching/StartGamePatch.cs b/SpaceWarp/Patching/StartGamePatch.cs index 74ae560d..346526a6 100644 --- a/SpaceWarp/Patching/StartGamePatch.cs +++ b/SpaceWarp/Patching/StartGamePatch.cs @@ -1,15 +1,14 @@ using HarmonyLib; -namespace SpaceWarp.Patching +namespace SpaceWarp.Patching; + +[HarmonyPatch(typeof(KSP.Game.GameManager))] +[HarmonyPatch("StartGame")] +public class StartGamePatch { - [HarmonyPatch(typeof(KSP.Game.GameManager))] - [HarmonyPatch("StartGame")] - public class StartGamePatch + public static void Prefix() { - public static void Prefix() - { - StartupManager.OnGameStarted(); - } + StartupManager.OnGameStarted(); } } \ No newline at end of file diff --git a/SpaceWarp/Properties/AssemblyInfo.cs b/SpaceWarp/Properties/AssemblyInfo.cs deleted file mode 100644 index 37e2fce8..00000000 --- a/SpaceWarp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SpaceWarp")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SpaceWarp")] -[assembly: AssemblyCopyright("Copyright © 2023")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("42fa2f7b-a595-44e8-8cd5-a9c30b80a667")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SpaceWarp/SpaceWarp.csproj b/SpaceWarp/SpaceWarp.csproj index 5ce43164..88314d58 100644 --- a/SpaceWarp/SpaceWarp.csproj +++ b/SpaceWarp/SpaceWarp.csproj @@ -1,216 +1,41 @@  - - - - + - 0.2.0 - Debug - AnyCPU - {42FA2F7B-A595-44E8-8CD5-A9C30B80A667} - Library - Properties - SpaceWarp - SpaceWarp - v4.7.2 - 512 - true - - - - https://api.nuget.org/v3/index.json; - https://nuget.bepinex.dev/v3/index.json; - https://nuget.samboy.dev/v3/index.json - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 + 0.3.0 + latest + true + false + true + net472;netstandard2.0 - - ..\packages\HarmonyX.2.10.1\lib\net45\0Harmony.dll - - - False + ..\external_dlls\Assembly-CSharp.dll + true - - ..\packages\Microsoft.CodeAnalysis.Common.4.5.0\lib\netstandard2.0\Microsoft.CodeAnalysis.dll - - - ..\packages\Microsoft.CodeAnalysis.CSharp.4.5.0\lib\netstandard2.0\Microsoft.CodeAnalysis.CSharp.dll - - - ..\packages\BepInEx.BaseLib.5.4.20\lib\net35\BepInEx.dll - - - ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.dll - - - ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Mdb.dll - - - ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Pdb.dll - - - ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Rocks.dll - - - ..\packages\MonoMod.RuntimeDetour.22.3.23.4\lib\net452\MonoMod.RuntimeDetour.dll - - - ..\packages\MonoMod.Utils.22.3.23.4\lib\net452\MonoMod.Utils.dll - - - - False - ..\external_dlls\Newtonsoft.Json.dll - - - False - ..\external_dlls\Newtonsoft.Json.UnityConverters.dll - - - - ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll - - - ..\packages\System.Collections.Immutable.6.0.0\lib\net461\System.Collections.Immutable.dll - - - - ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll - - - - ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - - ..\packages\System.Reflection.Metadata.6.0.1\lib\net461\System.Reflection.Metadata.dll - - - ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll - - - ..\packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll - - - ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll - - - - - - - - - False + ..\external_dlls\Unity.TextMeshPro.dll - - False - ..\external_dlls\UnityEngine.dll - - - False - ..\external_dlls\UnityEngine.AssetBundleModule.dll - - - False - ..\external_dlls\UnityEngine.CoreModule.dll + + ..\external_dlls\UnityEngine.UI.dll - - False - ..\external_dlls\UnityEngine.IMGUIModule.dll + + ..\external_dlls\Unity.Addressables.dll - - False - ..\external_dlls\UnityEngine.InputLegacyModule.dll + + ..\external_dlls\Unity.ResourceManager.dll - - False - ..\external_dlls\UnityEngine.UI.dll + + ..\external_dlls\UnityEngine.ImageConversionModule.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. - - - - - - - diff --git a/SpaceWarp/StartupManager.cs b/SpaceWarp/StartupManager.cs index caf1eb33..d9bf68f4 100644 --- a/SpaceWarp/StartupManager.cs +++ b/SpaceWarp/StartupManager.cs @@ -2,59 +2,53 @@ using UnityEngine; using System.IO; using SpaceWarp.API; -using Object = UnityEngine.Object; -using SpaceWarp.Patching; -using KSP.Logging; -using SpaceWarp.UI; -using static UnityEngine.Application; -namespace SpaceWarp +namespace SpaceWarp; + +/// +/// Starts the SpaceWarm mod manager +/// +public static class StartupManager { + public static SpaceWarpManager SpaceWarpObject; + public static bool _hasInitialized = false; + /// - /// Starts the SpaceWarm mod manager + /// This will be called once the KSP2 game is loaded. /// - public static class StartupManager + /// + public static void OnGameStarted() { - public static SpaceWarpManager SpaceWarpObject; - public static bool _hasInitialized = false; - - /// - /// This will be called once the KSP2 game is loaded. - /// - /// - public static void OnGameStarted() + // since OnGameStarted could be called multiple times, we want to make sure we only do anything on first call. + if (_hasInitialized) { - // since OnGameStarted could be called multiple times, we want to make sure we only do anything on first call. - if (_hasInitialized) - { - return; - } + return; + } - CreateModDirectoryIfNotExists(); - CreateSpaceWarpManager(); + CreateModDirectoryIfNotExists(); + CreateSpaceWarpManager(); - Console.WriteLine("[Space Warp] Space Warp mod manager loaded!"); - _hasInitialized = true; - } + Console.WriteLine("[Space Warp] Space Warp mod manager loaded!"); + _hasInitialized = true; + } - /// - /// Creates the space warp manager object. - /// - private static void CreateSpaceWarpManager() - { - GameObject spaceWarp = new GameObject("Space Warp"); - Object.DontDestroyOnLoad(spaceWarp); - SpaceWarpObject = spaceWarp.AddComponent(); - spaceWarp.SetActive(true); - // SpaceWarpObject.Initialize(); - } + /// + /// Creates the space warp manager object. + /// + private static void CreateSpaceWarpManager() + { + GameObject spaceWarp = new GameObject("Space Warp"); + SpaceWarpManager.Persist(spaceWarp); + SpaceWarpObject = spaceWarp.AddComponent(); + spaceWarp.SetActive(true); + // SpaceWarpObject.Initialize(); + } - /// - /// Creates the mod folder if it doesn't exist. - /// - private static void CreateModDirectoryIfNotExists() - { - Directory.CreateDirectory(SpaceWarpManager.MODS_FULL_PATH); - } + /// + /// Creates the mod folder if it doesn't exist. + /// + private static void CreateModDirectoryIfNotExists() + { + Directory.CreateDirectory(SpaceWarpManager.MODS_FULL_PATH); } -} +} \ No newline at end of file diff --git a/SpaceWarp/UI/ModConfigurationSection.cs b/SpaceWarp/UI/ModConfigurationSection.cs index 10536300..eff00147 100644 --- a/SpaceWarp/UI/ModConfigurationSection.cs +++ b/SpaceWarp/UI/ModConfigurationSection.cs @@ -2,52 +2,51 @@ using System.Linq; using System.Reflection; using System.Text; -namespace SpaceWarp.UI +namespace SpaceWarp.UI; + +public class ModConfigurationSection { - public class ModConfigurationSection - { - public bool Open = false; + public bool Open = false; - 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)>(); + 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) - { - (string path, ModConfigurationSection section) sub1 = SubSections.FirstOrDefault(sub => sub.path == subsection); + private ModConfigurationSection TouchSubSection(string subsection) + { + (string path, ModConfigurationSection section) sub1 = SubSections.FirstOrDefault(sub => sub.path == subsection); - if (sub1 != default) - { - return sub1.section; - } + if (sub1 != default) + { + return sub1.section; + } - ModConfigurationSection sub2 = new ModConfigurationSection(); - SubSections.Add((subsection, sub2)); - return sub2; + ModConfigurationSection sub2 = new ModConfigurationSection(); + SubSections.Add((subsection, sub2)); + return sub2; + } + public void Insert(string[] path, (string name, FieldInfo info, object confAttribute, string currentStringValue) property) + { + StringBuilder sb = new StringBuilder(); + foreach (string t in path) + { + sb.Append(t + "/"); } - public void Insert(string[] path, (string name, FieldInfo info, object confAttribute, string currentStringValue) property) + if (path.Length > 0) { - StringBuilder sb = new StringBuilder(); - foreach (string t in path) + List subPath = new List(); + for (int i = 1; i < path.Length; i++) { - sb.Append(t + "/"); + subPath.Add(path[i]); } - if (path.Length > 0) - { - List subPath = new List(); - for (int i = 1; i < path.Length; i++) - { - subPath.Add(path[i]); - } - ModConfigurationSection receivedSub = TouchSubSection(path[0]); + ModConfigurationSection receivedSub = TouchSubSection(path[0]); - receivedSub.Insert(subPath.ToArray(),property); - } - else - { - Properties.Add(property); - } + receivedSub.Insert(subPath.ToArray(),property); + } + else + { + Properties.Add(property); } } } \ No newline at end of file diff --git a/SpaceWarp/UI/ModConfigurationUI.cs b/SpaceWarp/UI/ModConfigurationUI.cs index 1e570d05..e77de934 100644 --- a/SpaceWarp/UI/ModConfigurationUI.cs +++ b/SpaceWarp/UI/ModConfigurationUI.cs @@ -2,190 +2,215 @@ using System.ComponentModel; using System.Reflection; using KSP.Game; +using SpaceWarp.API; using SpaceWarp.API.Configuration; using SpaceWarp.API.Managers; using UnityEngine; using UnityEngine.Serialization; -namespace SpaceWarp.UI -{ - - public class ModConfigurationUI : KerbalMonoBehaviour - { - public Type ConfigurationType; - public object ConfigurationObject; +namespace SpaceWarp.UI; - [FormerlySerializedAs("ModID")] public string modID; +public class ModConfigurationUI : KerbalMonoBehaviour +{ + public Type ConfigurationType; + public object ConfigurationObject; - private int _windowWidth = 350; - private int _windowHeight = 700; - private Rect _windowRect; + [FormerlySerializedAs("ModID")] public string modID; - private static GUIStyle _boxStyle; + private int _windowWidth = 350; + private int _windowHeight = 700; + private Rect _windowRect; - private ModConfigurationSection _rootSection; + private static GUIStyle _boxStyle; - private void Awake() - { - _windowWidth = (int)(Screen.width * 0.5f); - _windowHeight = (int)(Screen.height * 0.5f); - } + private ModConfigurationSection _rootSection; + private GUIStyle _spaceWarpUISkinToggled; + private bool hasGUIStyles = false; + + private void Awake() + { + _windowWidth = (int)(Screen.width * 0.5f); + _windowHeight = (int)(Screen.height * 0.5f); + } - public void Start() + public void Start() + { + _rootSection = new ModConfigurationSection(); + foreach (FieldInfo field in ConfigurationType.GetFields(BindingFlags.Instance | BindingFlags.Public)) { - _rootSection = new ModConfigurationSection(); - foreach (FieldInfo field in ConfigurationType.GetFields(BindingFlags.Instance | BindingFlags.Public)) - { - object attribute; - string attributeName; - string section = ""; + object attribute; + string attributeName; + string section = ""; - ConfigSectionAttribute sectionAttribute = field.GetCustomAttribute(); + ConfigSectionAttribute sectionAttribute = field.GetCustomAttribute(); - if (sectionAttribute != null) - { - section = sectionAttribute.Path; - } + if (sectionAttribute != null) + { + section = sectionAttribute.Path; + } - ConfigFieldAttribute fieldAttribute = field.GetCustomAttribute(); + ConfigFieldAttribute fieldAttribute = field.GetCustomAttribute(); - if (fieldAttribute == null) - { - // 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; - - var value = field.GetValue(ConfigurationObject); - _rootSection.Insert(section.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries), - (attributeName, field, attribute, value != null ? value.ToString() : "")); + if (fieldAttribute == null) + { + // 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; - _windowRect = new Rect((Screen.width * 0.15f), (Screen.height * 0.15f), 0, 0); + var value = field.GetValue(ConfigurationObject); + _rootSection.Insert(section.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries), + (attributeName, field, attribute, value != null ? value.ToString() : "")); } - public void OnGUI() - { - int controlID = GUIUtility.GetControlID(FocusType.Passive); - string header = $"{modID} configuration"; - - GUILayoutOption width = GUILayout.Width((float)(_windowWidth * 0.5)); - GUILayoutOption height = GUILayout.Height((float)(_windowHeight * 0.5)); + _windowRect = new Rect((Screen.width * 0.15f), (Screen.height * 0.15f), 0, 0); + } - _windowRect = GUILayout.Window(controlID, _windowRect, FillWindow, header, width, height); + private void GetGUIStyles() + { + _spaceWarpUISkinToggled = new GUIStyle(SpaceWarpManager.Skin.button); + var oldNormal = _spaceWarpUISkinToggled.normal; + var oldHover = _spaceWarpUISkinToggled.hover; + var oldActive = _spaceWarpUISkinToggled.active; + var oldFocused = _spaceWarpUISkinToggled.focused; + _spaceWarpUISkinToggled.normal = _spaceWarpUISkinToggled.onNormal; + _spaceWarpUISkinToggled.hover = _spaceWarpUISkinToggled.onHover; + _spaceWarpUISkinToggled.active = _spaceWarpUISkinToggled.onActive; + _spaceWarpUISkinToggled.focused = _spaceWarpUISkinToggled.onFocused; + _spaceWarpUISkinToggled.onNormal = oldNormal; + _spaceWarpUISkinToggled.onHover = oldHover; + _spaceWarpUISkinToggled.onActive = oldActive; + _spaceWarpUISkinToggled.onFocused = oldFocused; + hasGUIStyles = true; + } + public void OnGUI() + { + GUI.skin = SpaceWarpManager.Skin; + if (!hasGUIStyles) + { + } + int controlID = GUIUtility.GetControlID(FocusType.Passive); + string header = $"{modID} configuration"; + + GUILayoutOption width = GUILayout.Width((float)(_windowWidth * 0.5)); + GUILayoutOption height = GUILayout.Height((float)(_windowHeight * 0.5)); - private string EditorInputField(string fieldName, FieldInfo info, string current) + _windowRect = GUILayout.Window(controlID, _windowRect, FillWindow, header, width, height); + } + + private string EditorInputField(string fieldName, FieldInfo info, string current) + { + var result = ""; + GUILayout.BeginHorizontal(); + + if (info.FieldType != typeof(bool)) { - var result = ""; - GUILayout.BeginHorizontal(); + GUILayout.Label(fieldName); - if (info.FieldType != typeof(bool)) + string rawInputValue = GUILayout.TextField(current); + result = rawInputValue; + try { - GUILayout.Label(fieldName); - - string rawInputValue = GUILayout.TextField(current); - result = rawInputValue; - try - { - object convertedInputValue = TypeDescriptor.GetConverter(info.FieldType) - .ConvertFromInvariantString(rawInputValue); - info.SetValue(ConfigurationObject, convertedInputValue); - } - catch - { - // ignored - } + object convertedInputValue = TypeDescriptor.GetConverter(info.FieldType) + .ConvertFromInvariantString(rawInputValue); + info.SetValue(ConfigurationObject, convertedInputValue); } - else + catch { - bool toggleValue = GUILayout.Toggle((bool)info.GetValue(ConfigurationObject), fieldName); - result = toggleValue.ToString(); - info.SetValue(ConfigurationObject, toggleValue); + // ignored } - - GUILayout.EndHorizontal(); - return result; } - - private string EditorForField((string name, FieldInfo info, object confAttribute, string currentStringValue) field) + else { - if (field.confAttribute is ConfigFieldAttribute) - { - return EditorInputField(field.name, field.info, field.currentStringValue); - } - else - { - return ""; - } + bool toggleValue = GUILayout.Toggle((bool)info.GetValue(ConfigurationObject), fieldName); + result = toggleValue.ToString(); + info.SetValue(ConfigurationObject, toggleValue); } - private void SectionPropertyViewer(string sectionName, ModConfigurationSection section, string parent) - { - if (GUILayout.Button(parent == "" ? sectionName : parent + "/" + sectionName)) - { - section.Open = !section.Open; - } + GUILayout.EndHorizontal(); + return result; + } - if (!section.Open) - { - return; - } + private string EditorForField((string name, FieldInfo info, object confAttribute, string currentStringValue) field) + { + if (field.confAttribute is ConfigFieldAttribute) + { + return EditorInputField(field.name, field.info, field.currentStringValue); + } + else + { + return ""; + } + } + private void SectionPropertyViewer(string sectionName, ModConfigurationSection section, string parent) + { + - for (int i = 0; i < section.Properties.Count; i++) - { - var prop = section.Properties[i]; - var str = EditorForField(prop); - prop.currentStringValue = str; - section.Properties[i] = prop; - } + if (GUILayout.Button((section.Open ? "V " : "> ") + (parent == "" ? sectionName : parent + "/" + sectionName))) + { + section.Open = !section.Open; + } - foreach ((string path, ModConfigurationSection section) sub in section.SubSections) - { - SectionPropertyViewer(sub.path, sub.section, parent == "" ? sectionName : parent + "/" + sectionName); - } + if (!section.Open) + { + return; } - public ModConfigurationUI(Rect windowRect) + + for (int i = 0; i < section.Properties.Count; i++) { - _windowRect = windowRect; + var prop = section.Properties[i]; + var str = EditorForField(prop); + prop.currentStringValue = str; + section.Properties[i] = prop; } - private void FillWindow(int windowID) + foreach ((string path, ModConfigurationSection section) sub in section.SubSections) { - _boxStyle = GUI.skin.GetStyle("Box"); - GUILayout.BeginVertical(); + SectionPropertyViewer(sub.path, sub.section, parent == "" ? sectionName : parent + "/" + sectionName); + } + } - // These are the root properties - for (int i = 0; i < _rootSection.Properties.Count; i++) - { - var prop = _rootSection.Properties[i]; - var str = EditorForField(prop); - prop.currentStringValue = str; - _rootSection.Properties[i] = prop; - } + public ModConfigurationUI(Rect windowRect) + { + _windowRect = windowRect; + } - foreach ((string path, ModConfigurationSection section) section in _rootSection.SubSections) - { - SectionPropertyViewer(section.path, section.section, ""); - } + private void FillWindow(int windowID) + { + _boxStyle = GUI.skin.GetStyle("Box"); + GUILayout.BeginVertical(); - if (GUILayout.Button("Save and close")) + // These are the root properties + for (int i = 0; i < _rootSection.Properties.Count; i++) + { + 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) + { + SectionPropertyViewer(section.path, section.section, ""); + } + + if (GUILayout.Button("Save and close")) + { + //Run saving code from the configuration manager + if (ManagerLocator.TryGet(out ConfigurationManager configurationManager)) { - //Run saving code from the configuration manager - if (ManagerLocator.TryGet(out ConfigurationManager configurationManager)) - { - configurationManager.UpdateConfiguration(modID); - } - Destroy(this); + configurationManager.UpdateConfiguration(modID); } - - GUILayout.EndVertical(); - GUI.DragWindow(new Rect(0, 0, 10000, 500)); + Destroy(this); } + + GUILayout.EndVertical(); + GUI.DragWindow(new Rect(0, 0, 10000, 500)); } } \ No newline at end of file diff --git a/SpaceWarp/UI/ModListUI.cs b/SpaceWarp/UI/ModListUI.cs index a9dae230..c0d876ee 100644 --- a/SpaceWarp/UI/ModListUI.cs +++ b/SpaceWarp/UI/ModListUI.cs @@ -1,150 +1,287 @@ using System; +using System.Collections.Generic; +using System.IO; using KSP.Game; using SpaceWarp.API; +using SpaceWarp.API.AssetBundles; using SpaceWarp.API.Configuration; using SpaceWarp.API.Managers; using SpaceWarp.API.Mods.JSON; using UnityEngine; -namespace SpaceWarp.UI +namespace SpaceWarp.UI; + +public class ModListUI : KerbalMonoBehaviour { - public class ModListUI : KerbalMonoBehaviour - { - private static bool _loaded; - private bool _drawUI; - private Rect _windowRect; + private static bool _loaded; + private bool _drawUI; + private Rect _windowRect; - private int _windowWidth = 350; - private int _windowHeight = 700; + private int _windowWidth = 350; + private int _windowHeight = 700; - private static GUIStyle _boxStyle; - private static Vector2 _scrollPositionMods; - private string _selectedMod; - private ModInfo _selectedModInfo; + private static GUIStyle _boxStyle; + private static Vector2 _scrollPositionMods; + private string _selectedMod; + private ModInfo _selectedModInfo; + private GUISkin _spaceWarpUISkin; + + private List<(string, bool)> _toggles = new List<(string, bool)>(); + private List<(string, bool)> _initialToggles = new List<(string, bool)>(); + private readonly Dictionary _wasToggledDict = new Dictionary(); - public void Start() + public void Start() + { + if (_loaded) { - if (_loaded) - { - Destroy(this); - } + Destroy(this); + } + + _loaded = true; + } + + private void Awake() + { + _windowWidth = (int)(Screen.width * 0.85f); + _windowHeight = (int)(Screen.height * 0.85f); + + _windowRect = new Rect(Screen.width * 0.15f, Screen.height * 0.15f, 0, 0); + ResourceManager.TryGetAsset($"space_warp/swconsoleui/swconsoleUI/spacewarpConsole.guiskin", out _spaceWarpUISkin); + } - _loaded = true; + private void OnGUI() + { + GUI.skin = _spaceWarpUISkin; + if (!_drawUI) + { + return; } - private void Awake() + int controlID = GUIUtility.GetControlID(FocusType.Passive); + const string header = "spacewarp.modlist"; + GUILayoutOption width = GUILayout.Width((float)(_windowWidth * 0.8)); + GUILayoutOption height = GUILayout.Height((float)(_windowHeight * 0.8)); + GUI.skin = _spaceWarpUISkin; + + _windowRect = GUILayout.Window(controlID, _windowRect, FillWindow, header, width, height); + } + + private void Update() + { + if (Input.GetKey(KeyCode.LeftAlt) && Input.GetKeyDown(KeyCode.M)) { - _windowWidth = (int)(Screen.width * 0.85f); - _windowHeight = (int)(Screen.height * 0.85f); + ToggleVisible(); + } + } - _windowRect = new Rect((Screen.width * 0.15f), (Screen.height * 0.15f), 0, 0); + private void FillWindow(int windowID) + { + if (_initialToggles.Count == 0) + { + _initialToggles = new List<(string, bool)>(_toggles); } + + _boxStyle = GUI.skin.GetStyle("Box"); + GUILayout.BeginHorizontal(); + GUILayout.BeginVertical(); - private void OnGUI() + _scrollPositionMods = GUILayout.BeginScrollView(_scrollPositionMods, false, true, + GUILayout.Height((float)(_windowHeight * 0.8)), GUILayout.Width(300)); + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("Disable All")) { - if (!_drawUI) + for (int i = 0; i < _toggles.Count; i++) { - return; + _toggles[i] = (_toggles[i].Item1, false); } - - int controlID = GUIUtility.GetControlID(FocusType.Passive); - const string header = "Space Warp Mod List"; - GUILayoutOption width = GUILayout.Width((float)(_windowWidth * 0.8)); - GUILayoutOption height = GUILayout.Height((float)(_windowHeight * 0.8)); - - _windowRect = GUILayout.Window(controlID, _windowRect, FillWindow, header, width, height); } - private void Update() + if (GUILayout.Button("Enable All")) { - if (Input.GetKey(KeyCode.LeftAlt) && Input.GetKeyDown(KeyCode.M)) + for (int i = 0; i < _toggles.Count; i++) { - ToggleVisible(); + _toggles[i] = (_toggles[i].Item1, true); } } + GUILayout.EndHorizontal(); + - private void FillWindow(int windowID) + GUILayout.BeginHorizontal(); + if (ManagerLocator.TryGet(out SpaceWarpManager managerRemove)) { - _boxStyle = GUI.skin.GetStyle("Box"); - GUILayout.BeginHorizontal(); - GUILayout.BeginVertical(); - - _scrollPositionMods = GUILayout.BeginScrollView(_scrollPositionMods, false, true, GUILayout.Height((float)(_windowHeight * 0.8)), GUILayout.Width(300)); - - if (ManagerLocator.TryGet(out SpaceWarpManager manager)) + if (GUILayout.Button("Revert Changes")) { - foreach ((string modID, ModInfo modInfo) in manager.LoadedMods) + // Replace _toggles list with backup copy + _toggles = new List<(string, bool)>(_initialToggles); + + // Delete all ignore files + foreach ((string modID, ModInfo modInfo) in managerRemove.LoadedMods) { - if (GUILayout.Button(modID)) + if (File.Exists($"SpaceWarp/Mods/{modID}/.ignore")) { - _selectedMod = modID; - _selectedModInfo = modInfo; + File.Delete($"SpaceWarp/Mods/{modID}/.ignore"); } } } + } + + GUILayout.EndHorizontal(); - GUILayout.EndScrollView(); - GUILayout.EndVertical(); - GUILayout.BeginVertical(); - - if (_selectedModInfo != null) - { - CreateModConfigurationUI(); - } - else + int numChanges = 0; + for (int i = 0; i < _toggles.Count; i++) + { + if (_toggles[i].Item2 != _initialToggles[i].Item2) { - GUILayout.Label("No mod selected"); + numChanges++; } - - GUILayout.EndVertical(); - GUILayout.EndHorizontal(); - GUI.DragWindow(new Rect(0, 0, 10000, 500)); } - - private void CreateModConfigurationUI() + + if (numChanges > 0) { - GUILayout.Label(_selectedModInfo.name); - GUILayout.Label($"Author: {_selectedModInfo.author}"); - GUILayout.Label($"Version: {_selectedModInfo.version}"); - GUILayout.Label($"Description: {_selectedModInfo.description}"); - GUILayout.Label($"KSP2 Version: {_selectedModInfo.supported_ksp2_versions.min} - {_selectedModInfo.supported_ksp2_versions.max}"); - GUILayout.Label($"Dependencies"); + GUILayout.Label($"{numChanges} changes detected, please restart"); + } - foreach (DependencyInfo dependency in _selectedModInfo.dependencies) + if (ManagerLocator.TryGet(out SpaceWarpManager manager)) + { + foreach ((string modID, ModInfo modInfo) in manager.LoadedMods) { - GUILayout.Label($"{dependency.id}: {dependency.version.min} - {dependency.version.max}"); - } + int toggleIndex = _toggles.FindIndex(t => t.Item1 == modID); + if (toggleIndex == -1) // Toggle not found, add a new one + { + _toggles.Add((modID, true)); + toggleIndex = _toggles.Count - 1; + } - if (!ManagerLocator.TryGet(out ConfigurationManager configManager)) - { - return; - } + bool isToggled = _toggles[toggleIndex].Item2; // current state of the toggle + bool wasToggled = _wasToggledDict.ContainsKey(modID) && _wasToggledDict[modID]; // previous state of the toggle (defaults to false if not found) - if (!configManager.TryGet(_selectedModInfo.mod_id, out (Type configType, object configObject, string path) config)) - { - return; + GUILayout.BeginHorizontal(); + _toggles[toggleIndex] = (modID, GUILayout.Toggle(isToggled, "")); + if (GUILayout.Button(modID)) + { + _selectedMod = modID; + _selectedModInfo = modInfo; + } + GUILayout.EndHorizontal(); + + // Edge detection + if (!isToggled && wasToggled) // falling edge + { + File.Create($"SpaceWarp/Mods/{modID}/.ignore").Close(); + } + else if (isToggled && !wasToggled) // rising edge + { + File.Delete($"SpaceWarp/Mods/{modID}/.ignore"); + } + + _wasToggledDict[modID] = isToggled; // update the previous state of the toggle } - if (!GUILayout.Button("Configure")) + + foreach ((string modID, ModInfo modInfo) in manager.IgnoredMods) { - return; + int toggleIndex = _toggles.FindIndex((t) => t.Item1 == modID); + if (toggleIndex == -1) // Toggle not found, add a new one + { + _toggles.Add((modID, false)); + toggleIndex = _toggles.Count - 1; + } + + bool isToggled = _toggles[toggleIndex].Item2; // current state of the toggle + bool wasToggled = !_wasToggledDict.ContainsKey(modID) || _wasToggledDict[modID]; + + GUILayout.BeginHorizontal(); + + // Add a space to vertically center the toggle button + GUILayoutOption[] alignMiddleOption = { GUILayout.Height(30)}; + + _toggles[toggleIndex] = (modID, GUILayout.Toggle(isToggled, "", alignMiddleOption)); + if (GUILayout.Button(modID)) + { + _selectedMod = modID; + _selectedModInfo = modInfo; + } + + GUILayout.EndHorizontal(); + // Edge detection + if (isToggled && !wasToggled) // falling edge + { + File.Delete($"SpaceWarp/Mods/{modID}/.ignore"); + } + else if (!isToggled && wasToggled) // rising edge + { + File.Create($"SpaceWarp/Mods/{modID}/.ignore").Close(); + } + + _wasToggledDict[modID] = isToggled; // update the previous state of the toggle } + } - GameObject go = new GameObject(_selectedModInfo.mod_id); - go.transform.SetParent(transform); + GUILayout.EndScrollView(); + GUILayout.EndVertical(); + GUILayout.BeginVertical(); - ModConfigurationUI configUI = go.AddComponent(); + if (_selectedModInfo != null) + { + CreateModConfigurationUI(); + } + else + { + GUILayout.Label("No mod selected"); + } - configUI.ConfigurationType = config.configType; - configUI.ConfigurationObject = config.configObject; - configUI.modID = _selectedMod; + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); - go.SetActive(true); + GUI.DragWindow(); + } + + private void CreateModConfigurationUI() + { + GUILayout.Label(_selectedModInfo.name); + GUILayout.Label($"Author: {_selectedModInfo.author}"); + GUILayout.Label($"Version: {_selectedModInfo.version}"); + GUILayout.Label($"Source: {_selectedModInfo.source}"); + GUILayout.Label($"Description: {_selectedModInfo.description}"); + GUILayout.Label($"KSP2 Version: {_selectedModInfo.supported_ksp2_versions.min} - {_selectedModInfo.supported_ksp2_versions.max}"); + GUILayout.Label($"Dependencies"); + + foreach (DependencyInfo dependency in _selectedModInfo.dependencies) + { + GUILayout.Label($"{dependency.id}: {dependency.version.min} - {dependency.version.max}"); + } + + if (!ManagerLocator.TryGet(out ConfigurationManager configManager)) + { + return; } - public void ToggleVisible() + if (!configManager.TryGet(_selectedModInfo.mod_id, out (Type configType, object configObject, string path) config)) { - _drawUI = !_drawUI; + return; } + + if (!GUILayout.Button("Configure")) + { + return; + } + + GameObject go = new GameObject(_selectedModInfo.mod_id); + go.transform.SetParent(transform); + + ModConfigurationUI configUI = go.AddComponent(); + + configUI.ConfigurationType = config.configType; + configUI.ConfigurationObject = config.configObject; + configUI.modID = _selectedMod; + + + go.SetActive(true); + } + + public void ToggleVisible() + { + _drawUI = !_drawUI; } } \ No newline at end of file diff --git a/SpaceWarp/UI/SpaceWarpConsole.cs b/SpaceWarp/UI/SpaceWarpConsole.cs index e2f8d61d..2b00a83a 100644 --- a/SpaceWarp/UI/SpaceWarpConsole.cs +++ b/SpaceWarp/UI/SpaceWarpConsole.cs @@ -1,110 +1,116 @@ -using System; -using System.Collections.Generic; -using KSP.Game; +using System.Collections.Generic; using KSP.Sim.impl; using UnityEngine; -using SpaceWarp.API.AssetBundles; -using KSP.Logging; -using static KSP.Map.impl.Targeting.Sample; -using static RTG.Object2ObjectSnap; -using UnityEngine.UI; -using BepInEx.Logging; - -namespace SpaceWarp.UI -{ - public class SpaceWarpConsole : KerbalBehavior - { - private static bool _loaded; +using SpaceWarp.API; - private bool _drawUI; - private Rect _windowRect; +namespace SpaceWarp.UI; - private int _windowWidth = 350; - private int _windowHeight = 700; +public class SpaceWarpConsole : KerbalBehavior +{ + private static bool _loaded; - private static GUIStyle _boxStyle; - private static Vector2 _scrollPosition; + private bool _drawUI; + private Rect _windowRect; + bool _autoScroll = true; - public GUISkin _spaceWarpUISkin; + private int _windowWidth = 350; + private int _windowHeight = 700; - private readonly List _debugMessages = new List(); + private static GUIStyle _boxStyle; + private static Vector2 _scrollPosition; + private static Vector2 _scrollView; - public void Start() - { - if (_loaded) - { - Destroy(this); - } + private readonly Queue _debugMessages = new(); - _loaded = true; - } - - private void Awake() + public new void Start() + { + if (_loaded) { + Destroy(this); + } - _windowWidth = (int)(Screen.width * 0.5f); - _windowHeight = (int)(Screen.height * 0.5f); - _windowRect = new Rect((Screen.width * 0.15f), (Screen.height * 0.15f),0, 0); + _loaded = true; + } - ResourceManager.TryGetAsset($"space_warp/swconsoleui/spacewarpConsole.guiskin", out _spaceWarpUISkin); - } + private new void Awake() + { - private void OnGUI() - { - GUI.skin = _spaceWarpUISkin; - if (!_drawUI) - { - return; - } + _windowWidth = (int)(Screen.width * 0.5f); + _windowHeight = (int)(Screen.height * 0.5f); - int controlID = GUIUtility.GetControlID(FocusType.Passive); - string header = $"spacewarp.console"; - GUILayoutOption width = GUILayout.Width((float)(_windowWidth * 0.8)); - GUILayoutOption height = GUILayout.Height((float)(_windowHeight * 0.8)); + _windowRect = new Rect((Screen.width * 0.15f), (Screen.height * 0.15f), 0, 0); + _scrollPosition = Vector2.zero; + + } - _windowRect = GUILayout.Window(controlID, _windowRect, DrawConsole, header, width, height); + private void OnGUI() + { + GUI.skin = SpaceWarpManager.Skin; + if (!_drawUI) + { + return; } + + int controlID = GUIUtility.GetControlID(FocusType.Passive); + string header = $"spacewarp.console"; + GUILayoutOption width = GUILayout.Width((float)(_windowWidth * 0.8)); + GUILayoutOption height = GUILayout.Height((float)(_windowHeight * 0.8)); - private void Update() + _windowRect = GUILayout.Window(controlID, _windowRect, DrawConsole, header, width, height); + } + + private void Update() + { + if (Input.GetKey(KeyCode.LeftAlt) && Input.GetKeyDown(KeyCode.C)) { - if (Input.GetKey(KeyCode.LeftAlt) && Input.GetKeyDown(KeyCode.C)) - { - _drawUI = !_drawUI; - } + _drawUI = !_drawUI; } + } - private void DrawConsole(int windowID) + private void DrawConsole(int windowID) + { + _boxStyle = GUI.skin.GetStyle("Box"); + GUILayout.BeginVertical(); + _scrollView = GUILayout.BeginScrollView(_scrollPosition, false, true); + + foreach (string message in SpaceWarpConsoleLogListener.DebugMessages) { - _boxStyle = GUI.skin.GetStyle("Box"); - GUILayout.BeginVertical(); - _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, false, true); - - foreach (string debugMessage in SpaceWarpConsoleLogListener.DebugMessages) + string new_message = "" + message + "\n"; + GUILayout.Label( new_message); + if(_autoScroll) { - GUILayout.Label(debugMessage); + _scrollView.Set(_scrollView.x, Mathf.Infinity ); + _scrollPosition = _scrollView; } - - GUILayout.EndScrollView(); - GUILayout.BeginHorizontal(); - - if (GUILayout.Button("Close")) + else { - _drawUI = false; + _scrollPosition = _scrollView; } + } + + GUILayout.EndScrollView(); + GUILayout.BeginHorizontal(); - if (GUILayout.Button("Clear")) - { - SpaceWarpConsoleLogListener.DebugMessages.Clear(); - } + if (GUILayout.Button("Close")) + { + _drawUI = false; + GUIUtility.ExitGUI(); + } - if (GUILayout.Button("Clear Control Locks")) - { - GameManager.Instance.Game.ViewController.inputLockManager.ClearControlLocks(); - } + if (GUILayout.Button("Clear")) + { + SpaceWarpConsoleLogListener.DebugMessages.Clear(); + } - GUILayout.EndHorizontal(); - GUILayout.EndVertical(); - GUI.DragWindow(new Rect(0, 0, 10000, 500)); + if (GUILayout.Button( _autoScroll ? "Auto Scroll: On" : "Auto Scroll: Off" )) + { + //Todo: Add proper close button to top corner and add input lock button back. + // GameManager.Instance.Game.ViewController.inputLockManager.ClearControlLocks(); + _autoScroll = !_autoScroll; } + + GUILayout.EndHorizontal(); + GUILayout.EndVertical(); + GUI.DragWindow(new Rect(0, 0, 10000, 500)); } } \ No newline at end of file diff --git a/SpaceWarp/UI/SpaceWarpConsoleLogListener.cs b/SpaceWarp/UI/SpaceWarpConsoleLogListener.cs index 1e788f2b..5c183881 100644 --- a/SpaceWarp/UI/SpaceWarpConsoleLogListener.cs +++ b/SpaceWarp/UI/SpaceWarpConsoleLogListener.cs @@ -1,34 +1,67 @@ +using SpaceWarp.API; using System; using System.Collections.Generic; using UnityEngine; -namespace SpaceWarp.UI +using HarmonyLogger = HarmonyLib.Tools.Logger; +namespace SpaceWarp.UI; + +public class SpaceWarpConsoleLogListener { - public class SpaceWarpConsoleLogListener - { - internal static readonly List DebugMessages = new List(); + internal static readonly List DebugMessages = new List(); + internal static SpaceWarpGlobalConfiguration config = SpaceWarpGlobalConfiguration.Instance; - public static void LogCallback(string condition, string stackTrace, LogType type) + public static void LogCallback(string condition, string stackTrace, LogType type) + { + switch (type) { - switch (type) - { case LogType.Error: - DebugMessages.Add($"[ERR] {condition}"); + if (config.LogLevel >= (int)LogType.Error) + DebugMessages.Add($"[ERR] {condition}"); break; case LogType.Assert: - DebugMessages.Add($"[AST] {condition}"); + if (config.LogLevel >= (int)LogType.Assert) + DebugMessages.Add($"[AST] {condition}"); break; case LogType.Warning: - DebugMessages.Add($"[WRN] {condition}"); + if (config.LogLevel >= (int)LogType.Warning) + DebugMessages.Add($"[WRN] {condition}"); break; case LogType.Log: - DebugMessages.Add($"[LOG] {condition}"); + if (config.LogLevel >= (int)LogType.Log) + DebugMessages.Add($"[LOG] {condition}"); break; case LogType.Exception: - DebugMessages.Add($"[EXC] {condition}"); + if (config.LogLevel >= (int)LogType.Exception) + DebugMessages.Add($"[EXC] {condition}"); break; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); - } + } + } + + public static void HarmonyLogCallback(object sender, HarmonyLogger.LogEventArgs e) + { + switch (e.LogChannel) + { + case HarmonyLogger.LogChannel.Info: + if (config.HarmonyLogLevel >= (int)LogType.Log) + DebugMessages.Add($"[HINF] {e.Message}"); + break; + case HarmonyLogger.LogChannel.Warn: + if (config.HarmonyLogLevel >= (int)LogType.Warning) + DebugMessages.Add($"[HWRN] {e.Message}"); + break; + case HarmonyLogger.LogChannel.Error: + if (config.HarmonyLogLevel >= (int)LogType.Error) + DebugMessages.Add($"[HERR] {e.Message}"); + break; + case HarmonyLogger.LogChannel.IL: + if (config.HarmonyLogLevel >= (int)LogType.Exception) + DebugMessages.Add($"[HIL] {e.Message}"); + break; + default: + DebugMessages.Add($"[HARM] {e.Message}"); + break; } } } \ No newline at end of file diff --git a/SpaceWarp/app.config b/SpaceWarp/app.config deleted file mode 100644 index aa563623..00000000 --- a/SpaceWarp/app.config +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SpaceWarp/packages.config b/SpaceWarp/packages.config deleted file mode 100644 index fa05771a..00000000 --- a/SpaceWarp/packages.config +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/builder.py b/builder.py index 674f5989..107bb526 100644 --- a/builder.py +++ b/builder.py @@ -25,46 +25,12 @@ 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") @@ -100,7 +66,6 @@ def shutil_copy(file): to_transfer = [ "0Harmony.dll", - "0Harmony.xml", "Mono.Cecil.dll", "Mono.Cecil.Mdb.dll", "Mono.Cecil.Pdb.dll",