From 67d71dcedd65f20d5f0c133737370fd4866c446d Mon Sep 17 00:00:00 2001 From: David <87927264+Rexicon226@users.noreply.github.com> Date: Sat, 25 Feb 2023 19:26:09 -0800 Subject: [PATCH 1/5] Auto find the KSP2 folder, if possible. ^^^ + a couple fixes. --- ModTemplateGenerator.py | 76 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/ModTemplateGenerator.py b/ModTemplateGenerator.py index e4fc95fa..c70269c8 100644 --- a/ModTemplateGenerator.py +++ b/ModTemplateGenerator.py @@ -50,21 +50,77 @@ # !.gitignore import os +from os.path import expanduser + + +def find_ksp2_install_path(): + # Look for the game in Steam library folders + steam_path = os.path.join(os.getenv("ProgramFiles(x86)"), "Steam") + steam_library_folders_file = os.path.join(steam_path, "steamapps", "libraryfolders.vdf") + steam_install_folder = os.path.join(steam_path, "steamapps", "common", "Kerbal Space Program 2") + + if os.path.exists(steam_library_folders_file): + with open(steam_library_folders_file) as f: + for line in f: + if "BaseInstallFolder" in line: + steam_library_path = line.strip().split("\"")[3] + if os.path.exists(os.path.join(steam_library_path, "steamapps", "appmanifest_1406800.acf")): + steam_install_folder = os.path.join(steam_library_path, "steamapps", "common", "Kerbal Space Program 2") + break + + # Look for the game in default installation path + if not os.path.exists(steam_install_folder): + default_install_folder = os.path.join(os.getenv("ProgramFiles"), "Private Division", "Kerbal Space Program 2") + if os.path.exists(default_install_folder): + steam_install_folder = default_install_folder + + return steam_install_folder print("Space Warp Mod Setup Wizard") -project_name = input("What would you like to name the project: ") -mod_id = input("What is the ID of the mod: ") -mod_author = input("Who is the author of the mod: ") -mod_name = input("What is the name of the mod: ") + +while True: + project_name = input("What would you like to name the project: ") + if not project_name: + print("Project name cannot be empty, please try again.") + else: + break + +while True: + mod_id = input("What is the ID of the mod: ") + if not mod_id: + print("Mod ID cannot be empty, please try again.") + else: + break + +while True: + mod_author = input("Who is the author of the mod: ") + if not mod_author: + print("Mod author cannot be empty, please try again.") + else: + break + +while True: + mod_name = input("What is the name of the mod: ") + if not mod_name: + print("Mod name cannot be empty, please try again.") + else: + break + mod_description = input("What is a short description of the mod: ") mod_source = input("What is the source link of the mod: ") mod_version = input("What is the starting version of the mod: ") mod_ksp_min_version = input("What is the minimum version of KSP2 this mod will accept: ") mod_ksp_max_version = input("What is the maximum version of KSP2 this mod will accept: ") -# Now we copy all the game directories -space_warp_path = input("What is the path to spacewarp.dll: ") -managed_path = input("What is the path to the KSP managed dlls: ") +steam_install_folder = find_ksp2_install_path() + +if os.path.exists(steam_install_folder): + print(f"Kerbal Space Program 2 is installed at {steam_install_folder}") +else: + print("Could not find the installation path for Kerbal Space Program 2.\n Please enter the path to the KSP2 installation folder manually.: ") + +managed_path = os.path.join(steam_install_folder, "KSP2_x64_Data", "Managed") + os.mkdir(project_name) os.mkdir(f"{project_name}/{mod_id}") @@ -75,13 +131,15 @@ os.mkdir(f"{project_name}/{mod_id}/bin") os.mkdir(f"{project_name}/{mod_id}/config") namespace = mod_id.replace("_", " ").title().replace(" ", "") -os.mkdir(f"{project_name}/{mod_id}project_name") -os.mkdir(f"{project_name}/{mod_id}/namespace") +os.mkdir(f"{project_name}/{project_name}") +os.mkdir(f"{project_name}/{project_name}/{namespace}") os.mkdir(f"{project_name}/external_dlls") external_dlls = f"{project_name}/external_dlls" release_folder = f"{project_name}/{mod_id}" +space_warp_path = os.path.join(managed_path, "SpaceWarp.dll") + shutil.copy2(space_warp_path,external_dlls) for filename in os.listdir(managed_path): From 55c00ed5a6bd41296f4f0ca995dddedeb6c1b9c9 Mon Sep 17 00:00:00 2001 From: David <87927264+Rexicon226@users.noreply.github.com> Date: Sat, 25 Feb 2023 19:41:47 -0800 Subject: [PATCH 2/5] fixer the input thing --- ModTemplateGenerator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModTemplateGenerator.py b/ModTemplateGenerator.py index c70269c8..14b4d663 100644 --- a/ModTemplateGenerator.py +++ b/ModTemplateGenerator.py @@ -117,7 +117,7 @@ def find_ksp2_install_path(): if os.path.exists(steam_install_folder): print(f"Kerbal Space Program 2 is installed at {steam_install_folder}") else: - print("Could not find the installation path for Kerbal Space Program 2.\n Please enter the path to the KSP2 installation folder manually.: ") + managed_path = input("Could not find the installation path for Kerbal Space Program 2.\n Please enter the path to the KSP2 installation folder manually: ") managed_path = os.path.join(steam_install_folder, "KSP2_x64_Data", "Managed") From e36af609938bbda68fa18f5d7bf5921a0b0e566d Mon Sep 17 00:00:00 2001 From: David <87927264+Rexicon226@users.noreply.github.com> Date: Sat, 25 Feb 2023 19:54:59 -0800 Subject: [PATCH 3/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcb4a190..28d3c749 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Note: Use at your own risk, this is an early version which is expected to have a # Compiling In order to compile this project you need the code from kerbal space program 2, so before you can build anything, copy everything in ``Kerbal Space Program 2\KSP2_x64_Data\Managed`` into ``external_dlls/`` -Then compile the `spacewarp` project, then run the `injector` project. +Then compile the `spacewarp` project, then run the `ksp2_mod_loader_patcher` project. Then run KSP2, and wait until the title screen, there should then be a mods folder under the `KSP2_X64_data` folder From 08280e299c907b2348c375009396862956c32351 Mon Sep 17 00:00:00 2001 From: Lexi Date: Sat, 25 Feb 2023 22:58:48 -0500 Subject: [PATCH 4/5] Configuration Sectioning Baby! --- .../Configuration/ConfigSectionAttribute.cs | 14 +++ SpaceWarp/SpaceWarp.csproj | 1 + SpaceWarp/UI/ModConfigurationUI.cs | 106 ++++++++++++++++-- 3 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 SpaceWarp/API/Configuration/ConfigSectionAttribute.cs diff --git a/SpaceWarp/API/Configuration/ConfigSectionAttribute.cs b/SpaceWarp/API/Configuration/ConfigSectionAttribute.cs new file mode 100644 index 00000000..b651bba6 --- /dev/null +++ b/SpaceWarp/API/Configuration/ConfigSectionAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace SpaceWarp.API.Configuration +{ + public class ConfigSectionAttribute : Attribute + { + public string Path; + + public ConfigSectionAttribute(string path) + { + Path = path; + } + } +} \ No newline at end of file diff --git a/SpaceWarp/SpaceWarp.csproj b/SpaceWarp/SpaceWarp.csproj index 5805048d..c95c79a4 100644 --- a/SpaceWarp/SpaceWarp.csproj +++ b/SpaceWarp/SpaceWarp.csproj @@ -67,6 +67,7 @@ + diff --git a/SpaceWarp/UI/ModConfigurationUI.cs b/SpaceWarp/UI/ModConfigurationUI.cs index c5accb80..1ca2a1ca 100644 --- a/SpaceWarp/UI/ModConfigurationUI.cs +++ b/SpaceWarp/UI/ModConfigurationUI.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; using System.Reflection; +using System.Text; using KSP.Game; using SpaceWarp.API.Configuration; using SpaceWarp.API.Managers; @@ -21,11 +23,15 @@ public class ModConfigurationUI : KerbalMonoBehaviour private int windowWidth = 350; private int windowHeight = 700; private Rect windowRect; + + //Have the file structure + + // private List<(string name, FieldInfo info, object confAttribute)> fieldsToConfigure = + // new List<(string name, FieldInfo info, object confAttribute)>(); - - private List<(string name, FieldInfo info, object confAttribute)> fieldsToConfigure = - new List<(string name, FieldInfo info, object confAttribute)>(); - + private ModConfigurationSection _rootSection = new ModConfigurationSection(); + + void Awake() { windowWidth = (int)(Screen.width * 0.5f); @@ -38,13 +44,19 @@ public void Start() { object attribute = null; string attributeName = ""; + string section = ""; + var sectionAttribute = field.GetCustomAttribute(); + if (sectionAttribute != null) + { + section = sectionAttribute.Path; + } + var fieldAttribute = field.GetCustomAttribute(); if (fieldAttribute != null) { attribute = fieldAttribute; attributeName = fieldAttribute.Name; - fieldsToConfigure.Add((attributeName, field, attribute)); - + _rootSection.Insert(section.Split(new []{'/'},StringSplitOptions.RemoveEmptyEntries), (attributeName, field, attribute)); } } windowRect = new Rect((Screen.width * 0.15f), (Screen.height * 0.15f), @@ -63,7 +75,7 @@ public void OnGUI() } - public void EditorInputField(string fieldName, FieldInfo info, ConfigFieldAttribute fieldAttribute) + private void EditorInputField(string fieldName, FieldInfo info, ConfigFieldAttribute fieldAttribute) { GUILayout.BeginHorizontal(); if (info.FieldType != typeof(bool)) @@ -81,24 +93,53 @@ public void EditorInputField(string fieldName, FieldInfo info, ConfigFieldAttrib GUILayout.EndHorizontal(); } - public void EditorForField((string name, FieldInfo info, object confAttribute) field) + private void EditorForField((string name, FieldInfo info, object confAttribute) field) { if (field.confAttribute is ConfigFieldAttribute fieldAttribute) { EditorInputField(field.name,field.info,fieldAttribute); } } + + private void SectionPropertyViewer(string sectionName, ModConfigurationSection section, string parent) + { + if (GUILayout.Button(parent == "" ? sectionName : parent + "/" + sectionName)) + { + section.Open = !section.Open; + } + + if (!section.Open) return; + // Debug.Log($"[ModConfigurationSection] {sectionName} - {section}: {section.Properties.Count}"); + foreach (var property in section.Properties) + { + // Debug.Log($"[ModConfigurationUI] {property.name}, {property.info}, {property.confAttribute}"); + EditorForField(property); + } + + foreach (var sub in section.SubSections) + { + SectionPropertyViewer(sub.path, sub.section, parent == "" ? sectionName : parent + "/" + sectionName); + } + } + private static GUIStyle boxStyle; private void FillWindow(int windowID) { boxStyle = GUI.skin.GetStyle("Box"); GUILayout.BeginVertical(); - foreach (var field in fieldsToConfigure) + // These are the root properties + foreach (var field in _rootSection.Properties) { + // Debug.Log($"[ModConfigurationUI] {field.name}, {field.info}, {field.confAttribute}"); EditorForField(field); } + foreach (var section in _rootSection.SubSections) + { + SectionPropertyViewer(section.path, section.section, ""); + } + if (GUILayout.Button("Save and close")) { //Run saving code from the configuration manager @@ -112,4 +153,51 @@ private void FillWindow(int windowID) GUI.DragWindow(new Rect(0, 0, 10000, 500)); } } + + class ModConfigurationSection + { + public bool Open = false; + + public List<(string name, FieldInfo info, object confAttribute)> Properties = + new List<(string name, FieldInfo info, object confAttribute)>(); + public List<(string path, ModConfigurationSection section)> SubSections = + new List<(string path, ModConfigurationSection section)>(); + + private ModConfigurationSection TouchSubSection(string subsection) + { + var sub1 = SubSections.FirstOrDefault(sub => sub.path == subsection); + if (sub1 != default) return sub1.section; + var sub2 = new ModConfigurationSection(); + // Debug.Log($"[ModConfigurationSection] creating {subsection} - {sub2.GetHashCode()}"); + SubSections.Add((subsection,sub2)); + return sub2; + } + public void Insert(string[] path, (string name, FieldInfo info, object confAttribute) property) + { + var sb = new StringBuilder(); + foreach (var t in path) + { + sb.Append(t + "/"); + } + // Debug.Log($"[ModConfigurationSection] {path.Length}: {sb}"); + if (path.Length > 0) + { + var subPath = new List(); + for (var i = 1; i < path.Length; i++) + { + subPath.Add(path[i]); + } + + var recieved_sub = TouchSubSection(path[0]); + + // Debug.Log($"[ModConfigurationSection] received {path[0]} - {recieved_sub.GetHashCode()}"); + recieved_sub.Insert(subPath.ToArray(),property); + } + else + { + // Debug.Log($"[ModConfigurationSection] {property.name}, {property.info}, {property.confAttribute}"); + Properties.Add(property); + } + } + } } \ No newline at end of file From 0b29d80fb5eb554faeba1d2d84ba8bafd78da0a8 Mon Sep 17 00:00:00 2001 From: Lexi Date: Sat, 25 Feb 2023 23:04:39 -0500 Subject: [PATCH 5/5] Cleaned up template gen a bit more --- .gitignore | 1 + ModTemplateGenerator.py | 56 ++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index dfcfd56f..c95cf427 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ bld/ # Visual Studio 2015/2017 cache/options directory .vs/ +.idea/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ diff --git a/ModTemplateGenerator.py b/ModTemplateGenerator.py index 14b4d663..153fc4b6 100644 --- a/ModTemplateGenerator.py +++ b/ModTemplateGenerator.py @@ -78,15 +78,15 @@ def find_ksp2_install_path(): print("Space Warp Mod Setup Wizard") -while True: - project_name = input("What would you like to name the project: ") - if not project_name: - print("Project name cannot be empty, please try again.") - else: - break +# while True: +# project_name = input("What would you like to name the project: ") +# if not project_name: +# print("Project name cannot be empty, please try again.") +# else: +# break while True: - mod_id = input("What is the ID of the mod: ") + mod_id = input("What is the ID of the mod (This should be in snake_case): ") if not mod_id: print("Mod ID cannot be empty, please try again.") else: @@ -122,21 +122,21 @@ def find_ksp2_install_path(): managed_path = os.path.join(steam_install_folder, "KSP2_x64_Data", "Managed") -os.mkdir(project_name) -os.mkdir(f"{project_name}/{mod_id}") -os.mkdir(f"{project_name}/{mod_id}/assets") -os.mkdir(f"{project_name}/{mod_id}/assets/parts") -os.mkdir(f"{project_name}/{mod_id}/assets/models") -os.mkdir(f"{project_name}/{mod_id}/assets/resources") -os.mkdir(f"{project_name}/{mod_id}/bin") -os.mkdir(f"{project_name}/{mod_id}/config") -namespace = mod_id.replace("_", " ").title().replace(" ", "") -os.mkdir(f"{project_name}/{project_name}") -os.mkdir(f"{project_name}/{project_name}/{namespace}") -os.mkdir(f"{project_name}/external_dlls") +mod_id_title = mod_id.replace("_", " ").title().replace(" ", "") +os.mkdir(mod_id) +os.mkdir(f"{mod_id}/{mod_id}") +os.mkdir(f"{mod_id}/{mod_id}/assets") +os.mkdir(f"{mod_id}/{mod_id}/assets/parts") +os.mkdir(f"{mod_id}/{mod_id}/assets/models") +os.mkdir(f"{mod_id}/{mod_id}/assets/resources") +os.mkdir(f"{mod_id}/{mod_id}/bin") +os.mkdir(f"{mod_id}/{mod_id}/config") +os.mkdir(f"{mod_id}/{mod_id_title}") +os.mkdir(f"{mod_id}/{mod_id_title}/{mod_id_title}") +os.mkdir(f"{mod_id}/external_dlls") -external_dlls = f"{project_name}/external_dlls" -release_folder = f"{project_name}/{mod_id}" +external_dlls = f"{mod_id}/external_dlls" +release_folder = f"{mod_id}/{mod_id}" space_warp_path = os.path.join(managed_path, "SpaceWarp.dll") @@ -149,7 +149,7 @@ def find_ksp2_install_path(): with open(f"{external_dlls}/.gitignore","w") as external_gitignore: external_gitignore.write("*\n!.gitignore") -with open(f"{project_name}/.gitignore","w") as main_gitignore: +with open(f"{mod_id}/.gitignore","w") as main_gitignore: main_gitignore.writelines( [ "*.rsuser", @@ -198,13 +198,13 @@ def find_ksp2_install_path(): with open(f"{release_folder}/README.json","w") as readme: readme.write("# Default Readme") -code_folder = f"{project_name}/{project_name}/{namespace}" +code_folder = f"{mod_id}/{mod_id_title}/{mod_id_title}" -with open(f"{code_folder}/{namespace}Mod.cs","w") as default_code: - default_code.write("using SpaceWarp.API.Mods;\n\nnamespace " + namespace + "\n{\n [MainMod]\n public class " + namespace + "Mod : Mod\n {\n public override void OnInitialized()\n {\n Logger.Info(\"Mod is initialized\");\n }\n }\n}") +with open(f"{code_folder}/{mod_id_title}Mod.cs","w") as default_code: + default_code.write("using SpaceWarp.API.Mods;\n\nnamespace " + mod_id_title + "\n{\n [MainMod]\n public class " + mod_id_title + "Mod : Mod\n {\n public override void OnInitialized()\n {\n Logger.Info(\"Mod is initialized\");\n }\n }\n}") -with open(f"{code_folder}/{namespace}Config.cs","w") as default_config: - default_config.write("using SpaceWarp.API.Configuration;\nusing Newtonsoft.Json;\n\nnamespace " + namespace + "\n{\n [JsonObject(MemberSerialization.OptOut)]\n [ModConfig]\n public class " + namespace + "Config\n {\n [ConfigField(\"pi\")] [ConfigDefaultValue(3.14159)] public double pi;\n }\n}") +with open(f"{code_folder}/{mod_id_title}Config.cs","w") as default_config: + default_config.write("using SpaceWarp.API.Configuration;\nusing Newtonsoft.Json;\n\nnamespace " + mod_id_title + "\n{\n [JsonObject(MemberSerialization.OptOut)]\n [ModConfig]\n public class " + mod_id_title + "Config\n {\n [ConfigField(\"pi\")] [ConfigDefaultValue(3.14159)] public double pi;\n }\n}") def quickCreateProperty(root,name,text): @@ -214,7 +214,7 @@ def quickCreateProperty(root,name,text): return a -with open(f"{project_name}/{project_name}/{project_name}.csproj","w") as csproj: +with open(f"{mod_id}/{mod_id_title}/{mod_id_title}.csproj","w") as csproj: root = minidom.Document() xml = root.createElement('Project') xml.setAttribute('Sdk','Microsoft.NET.Sdk')