diff --git a/.github/workflows/build_spacewarp.yml b/.github/workflows/build_spacewarp.yml index 78309260..a69ea86a 100644 --- a/.github/workflows/build_spacewarp.yml +++ b/.github/workflows/build_spacewarp.yml @@ -19,6 +19,15 @@ jobs: run: | sudo curl -o /usr/local/bin/nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe + - name: Running automated tests + run: | + dotnet test "SpaceWarp.sln" + test_exit_code=$? + if [ $test_exit_code -ne 0 ]; then + echo "Tests failed. Cancelling the build." + exit $test_exit_code + fi + - name: Build the solution run: dotnet build "SpaceWarp.sln" -c Release diff --git a/.github/workflows/release_nuget.yml b/.github/workflows/release_nuget.yml index a88f85ab..c16fb1f4 100644 --- a/.github/workflows/release_nuget.yml +++ b/.github/workflows/release_nuget.yml @@ -1,4 +1,7 @@ name: Publish NuGet Package +env: + MOD_ID: 3277 + KSP2_ID: 22407 on: release: @@ -7,7 +10,7 @@ on: jobs: publish: runs-on: ubuntu-latest - + permissions: write-all steps: - name: Check out repository uses: actions/checkout@v3 @@ -32,6 +35,7 @@ jobs: echo "artifact_name=spacewarp-release-$version.zip" >> $GITHUB_ENV echo "zip=$(ls -1 dist/SpaceWarp-*.zip | head -n 1)" >> $GITHUB_ENV echo "upload_url=$(wget -qO- https://api.github.com/repos/$GITHUB_REPOSITORY/releases | jq '.[0].upload_url' | tr -d \")" >> $GITHUB_ENV + wget -qO- https://api.github.com/repos/$GITHUB_REPOSITORY/releases | jq -r '.[0].body' > ./changelog.md - name: Check if version exists id: check-version @@ -41,7 +45,6 @@ jobs: exists=$(echo "$response" | jq -r --arg id "SpaceWarp" --arg version "$version" '.data[] | select(.id == $id) | .versions[] | select(.version == $version) | .version') if [ "$exists" == "$version" ]; then echo "Version $version already exists in the NuGet repository" - exit 1 else echo "Version $version does not exist in the NuGet repository" echo "should_publish=true" >> $GITHUB_ENV @@ -62,4 +65,17 @@ jobs: asset_path: ${{ env.zip }} asset_name: ${{ env.artifact_name }} asset_content_type: application/zip + + - name: Add Mask + run: echo "::add-mask::${{ secrets.SPACEDOCK_PASSWORD }}" + - name: Update spacedock + uses: KSP2Community/spacedock-upload@v1.0.0 + with: + username: ${{ secrets.SPACEDOCK_USER }} + password: ${{ secrets.SPACEDOCK_PASSWORD }} + game_id: 22407 + mod_id: 3277 + version: ${{ env.version }} + zipball: ${{ env.zip }} + changelog: ./changelog.md diff --git a/.gitignore b/.gitignore index bfba49bc..8e3106ce 100644 --- a/.gitignore +++ b/.gitignore @@ -70,7 +70,6 @@ StyleCopReport.xml *_p.c *_h.h *.ilk -*.meta *.obj *.iobj *.pch diff --git a/Directory.Build.props b/Directory.Build.props index 0fe657a8..e72d34f6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -21,6 +21,9 @@ $(SolutionDir)build/obj/modules/$(Configuration) $(SolutionDir)build/bin/patcher/$(Configuration) $(SolutionDir)build/obj/patcher/$(Configuration) + $(SolutionDir)build/bin/restarter/$(Configuration) + $(SolutionDir)build/obj/restarter/$(Configuration) + $(SolutionDir)dist/$(Configuration)/BepInEx/plugins/SpaceWarp/restarter $(ModulesBinPath)/$(MSBuildProjectName) $(ModulesObjPath)/$(MSBuildProjectName) $(MSBuildProjectName) @@ -56,9 +59,9 @@ @(Swinfo -> '%(description)') git @(Swinfo -> '%(source)') - $(ModId) - $(Product) - $(Version) + $(ModId) + $(Product) + $(Version) - + \ No newline at end of file diff --git a/SpaceWarp.sln b/SpaceWarp.sln index c19f2bbb..69f805b4 100644 --- a/SpaceWarp.sln +++ b/SpaceWarp.sln @@ -8,16 +8,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarp.Game", "src/Space EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarp.Messaging", "src/SpaceWarp.Messaging/SpaceWarp.Messaging.csproj", "{66BA4E01-8521-42EB-9D7D-8EB653757177}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarpRestarter", "src\SpaceWarpRestarter\SpaceWarpRestarter.csproj", "{4B509D31-4C02-4D6E-8508-8417F0745776}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarp.Sound", "src/SpaceWarp.Sound/SpaceWarp.Sound.csproj", "{BA439A24-7EA3-4E79-A44C-1FA303B9331C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarp.UI", "src/SpaceWarp.UI/SpaceWarp.UI.csproj", "{CB131B63-51E6-4ED7-A47C-28B1EB65B8D7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarp.VersionChecking", "src/SpaceWarp.VersionChecking/SpaceWarp.VersionChecking.csproj", "{6B76C415-5BC2-4AB0-8862-760D9DC8F485}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarpPatcher", "src/SpaceWarpPatcher/SpaceWarpPatcher.csproj", "{2EF642D0-F66D-461C-A5B0-953E39307B76}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarp.Preload", "src\SpaceWarp.Preload\SpaceWarp.Preload.csproj", "{2EF642D0-F66D-461C-A5B0-953E39307B76}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarpTest", "src/SpaceWarpTest/SpaceWarpTest.csproj", "{8DB42693-9177-40B9-AC6A-B6D7A4823FAD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceWarp.Patches", "src\SpaceWarp.Patches\SpaceWarp.Patches.csproj", "{88F73A97-3D47-4ED3-8381-177EED4451AC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -98,6 +102,22 @@ Global {8DB42693-9177-40B9-AC6A-B6D7A4823FAD}.Deploy|Any CPU.Build.0 = Deploy|Any CPU {8DB42693-9177-40B9-AC6A-B6D7A4823FAD}.DeployAndRun|Any CPU.ActiveCfg = DeployAndRun|Any CPU {8DB42693-9177-40B9-AC6A-B6D7A4823FAD}.DeployAndRun|Any CPU.Build.0 = DeployAndRun|Any CPU + {4B509D31-4C02-4D6E-8508-8417F0745776}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B509D31-4C02-4D6E-8508-8417F0745776}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B509D31-4C02-4D6E-8508-8417F0745776}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B509D31-4C02-4D6E-8508-8417F0745776}.Release|Any CPU.Build.0 = Release|Any CPU + {4B509D31-4C02-4D6E-8508-8417F0745776}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {4B509D31-4C02-4D6E-8508-8417F0745776}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {4B509D31-4C02-4D6E-8508-8417F0745776}.DeployAndRun|Any CPU.ActiveCfg = DeployAndRun|Any CPU + {4B509D31-4C02-4D6E-8508-8417F0745776}.DeployAndRun|Any CPU.Build.0 = DeployAndRun|Any CPU + {88F73A97-3D47-4ED3-8381-177EED4451AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88F73A97-3D47-4ED3-8381-177EED4451AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88F73A97-3D47-4ED3-8381-177EED4451AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88F73A97-3D47-4ED3-8381-177EED4451AC}.Release|Any CPU.Build.0 = Release|Any CPU + {88F73A97-3D47-4ED3-8381-177EED4451AC}.Deploy|Any CPU.ActiveCfg = Deploy|Any CPU + {88F73A97-3D47-4ED3-8381-177EED4451AC}.Deploy|Any CPU.Build.0 = Deploy|Any CPU + {88F73A97-3D47-4ED3-8381-177EED4451AC}.DeployAndRun|Any CPU.ActiveCfg = DeployAndRun|Any CPU + {88F73A97-3D47-4ED3-8381-177EED4451AC}.DeployAndRun|Any CPU.Build.0 = DeployAndRun|Any CPU EndGlobalSection EndGlobal diff --git a/plugin_template/BepInEx/plugins/ConfigurationManager/ConfigurationManager.dll b/plugin_template/BepInEx/plugins/ConfigurationManager/ConfigurationManager.dll deleted file mode 100644 index ef1e7073..00000000 Binary files a/plugin_template/BepInEx/plugins/ConfigurationManager/ConfigurationManager.dll and /dev/null differ diff --git a/plugin_template/BepInEx/plugins/ConfigurationManager/ConfigurationManager.xml b/plugin_template/BepInEx/plugins/ConfigurationManager/ConfigurationManager.xml deleted file mode 100644 index fb742bb1..00000000 --- a/plugin_template/BepInEx/plugins/ConfigurationManager/ConfigurationManager.xml +++ /dev/null @@ -1,197 +0,0 @@ - - - - ConfigurationManager - - - - - Get entries for all core BepInEx settings - - - - - Get entries for all settings of a plugin - - - - - An easy way to let user configure how a plugin behaves without the need to make your own GUI. The user can change any of the settings you expose, even keyboard shortcuts. - https://github.com/ManlyMarco/BepInEx.ConfigurationManager - - - - - GUID of this plugin - - - - - Version constant - - - - - Event fired every time the manager window is shown or hidden. - - - - - Disable the hotkey check used by config manager. If enabled you have to set to show the manager. - - - - - - - - Is the config manager main window displayed on screen - - - - - Register a custom setting drawer for a given type. The action is ran in OnGui in a single setting slot. - Do not use any Begin / End layout methods, and avoid raising height from standard. - - - - - Rebuild the setting list. Use to update the config manager window if config settings were removed or added while it was open. - - - - - String currently entered into the search box - - - - - Class representing all data about a setting collected by ConfigurationManager. - - - - - List of values this setting can take - - - - - Range of the values this setting can take - - - - - Should the setting be shown as a percentage (only applies to value range settings) - - - - - Custom setting draw action - - - - - Show this setting in the settings screen at all? If false, don't show. - - - - - Category the setting is under. Null to be directly under the plugin. - - - - - If set, a "Default" button will be shown next to the setting to allow resetting to default. - - - - - Force the "Reset" button to not be displayed, even if a valid DefaultValue is available. - - - - - Force the setting name to not be displayed. Should only be used with a to get more space. - Can be used together with to gain even more space. - - - - - Optional description shown when hovering over the setting - - - - - Name of the setting - - - - - Plugin this setting belongs to - - - - - Only allow showing of the value. False whenever possible by default. - - - - - Type of the variable - - - - - Instance of the plugin that owns this setting - - - - - Is this setting advanced - - - - - Order of the setting on the settings list relative to other settings in a category. 0 by default, lower is higher on the list. - - - - - Get the value of this setting - - - - - Set the value of this setting - - - - - Implementation of - - - - - Custom converter from setting type to string for the textbox - - - - - Custom converter from string to setting type for the textbox - - - - - Arguments representing a change in value - - - - - - - - Newly assigned value - - - - diff --git a/plugin_template/BepInEx/plugins/ConfigurationManager/LICENSE b/plugin_template/BepInEx/plugins/ConfigurationManager/LICENSE deleted file mode 100644 index afdc2c38..00000000 --- a/plugin_template/BepInEx/plugins/ConfigurationManager/LICENSE +++ /dev/null @@ -1,167 +0,0 @@ -BepInEx.ConfigurationManager is licensed under the LGPL v3 license. The full text of the license is included below. - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/plugin_template/BepInEx/plugins/ConfigurationManager/README b/plugin_template/BepInEx/plugins/ConfigurationManager/README deleted file mode 100644 index 019b6aef..00000000 --- a/plugin_template/BepInEx/plugins/ConfigurationManager/README +++ /dev/null @@ -1,2 +0,0 @@ -This contains binaries for BepInEx.ConfigurationManager, which is under the LGPL V3 license, copy of which is provided here. -The source for these binaries can be found at https://github.com/BepInEx/BepInEx.ConfigurationManager \ No newline at end of file diff --git a/plugin_template/BepInEx/plugins/SpaceWarp/assets/bundles/modlist.bundle b/plugin_template/BepInEx/plugins/SpaceWarp/assets/bundles/modlist.bundle index 54924792..259eb014 100644 Binary files a/plugin_template/BepInEx/plugins/SpaceWarp/assets/bundles/modlist.bundle and b/plugin_template/BepInEx/plugins/SpaceWarp/assets/bundles/modlist.bundle differ diff --git a/plugin_template/BepInEx/plugins/SpaceWarp/assets/bundles/swconsole.bundle b/plugin_template/BepInEx/plugins/SpaceWarp/assets/bundles/swconsole.bundle index cbce5b40..9ff413a1 100644 Binary files a/plugin_template/BepInEx/plugins/SpaceWarp/assets/bundles/swconsole.bundle and b/plugin_template/BepInEx/plugins/SpaceWarp/assets/bundles/swconsole.bundle differ diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/Microsoft.CodeAnalysis.CSharp.dll b/plugin_template/BepInEx/plugins/SpaceWarp/lib/Microsoft.CodeAnalysis.CSharp.dll similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/Microsoft.CodeAnalysis.CSharp.dll rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/Microsoft.CodeAnalysis.CSharp.dll diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/Microsoft.CodeAnalysis.CSharp.xml b/plugin_template/BepInEx/plugins/SpaceWarp/lib/Microsoft.CodeAnalysis.CSharp.xml similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/Microsoft.CodeAnalysis.CSharp.xml rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/Microsoft.CodeAnalysis.CSharp.xml diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/Microsoft.CodeAnalysis.dll b/plugin_template/BepInEx/plugins/SpaceWarp/lib/Microsoft.CodeAnalysis.dll similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/Microsoft.CodeAnalysis.dll rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/Microsoft.CodeAnalysis.dll diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/Microsoft.CodeAnalysis.xml b/plugin_template/BepInEx/plugins/SpaceWarp/lib/Microsoft.CodeAnalysis.xml similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/Microsoft.CodeAnalysis.xml rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/Microsoft.CodeAnalysis.xml diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Collections.Immutable.dll b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Collections.Immutable.dll similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Collections.Immutable.dll rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Collections.Immutable.dll diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Collections.Immutable.xml b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Collections.Immutable.xml similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Collections.Immutable.xml rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Collections.Immutable.xml diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Memory.dll b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Memory.dll similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Memory.dll rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Memory.dll diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Memory.xml b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Memory.xml similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Memory.xml rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Memory.xml diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Numerics.Vectors.dll b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Numerics.Vectors.dll similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Numerics.Vectors.dll rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Numerics.Vectors.dll diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Numerics.Vectors.xml b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Numerics.Vectors.xml similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Numerics.Vectors.xml rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Numerics.Vectors.xml diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Reflection.Metadata.dll b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Reflection.Metadata.dll similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Reflection.Metadata.dll rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Reflection.Metadata.dll diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Reflection.Metadata.xml b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Reflection.Metadata.xml similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Reflection.Metadata.xml rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Reflection.Metadata.xml diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Runtime.CompilerServices.Unsafe.dll b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Runtime.CompilerServices.Unsafe.dll similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Runtime.CompilerServices.Unsafe.dll rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Runtime.CompilerServices.Unsafe.dll diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Runtime.CompilerServices.Unsafe.xml b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Runtime.CompilerServices.Unsafe.xml similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Runtime.CompilerServices.Unsafe.xml rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Runtime.CompilerServices.Unsafe.xml diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Threading.Tasks.Extensions.dll b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Threading.Tasks.Extensions.dll similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Threading.Tasks.Extensions.dll rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Threading.Tasks.Extensions.dll diff --git a/plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Threading.Tasks.Extensions.xml b/plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Threading.Tasks.Extensions.xml similarity index 100% rename from plugin_template/BepInEx/patchers/SpaceWarp/lib/System.Threading.Tasks.Extensions.xml rename to plugin_template/BepInEx/plugins/SpaceWarp/lib/System.Threading.Tasks.Extensions.xml diff --git a/plugin_template/BepInEx/plugins/SpaceWarp/localizations/space_warp_localizations.csv b/plugin_template/BepInEx/plugins/SpaceWarp/localizations/space_warp_localizations.csv index 92936cf9..e335e0d1 100644 --- a/plugin_template/BepInEx/plugins/SpaceWarp/localizations/space_warp_localizations.csv +++ b/plugin_template/BepInEx/plugins/SpaceWarp/localizations/space_warp_localizations.csv @@ -1,46 +1,48 @@ -Key,Type,Description,English,Portuguese BR -SpaceWarp/ModList/EnableAll,Text,,Enable All,Ativar todos -SpaceWarp/ModList/DisableAll,Text,,Disable All,Desativar todos -SpaceWarp/ModList/RevertChanges,Text,,Revert Changes,Reverter alterações -SpaceWarp/ModList/multipleChangesDetected,Text,,"{0} changes detected, please restart to apply them","{0} alterações detetadas, porfavor reinicie o jogo" -SpaceWarp/ModList/singleChangeDetected,Text,,"1 change detected, please restart to apply it","1 alteração detectada, reinicie para aplicá-la" -SpaceWarp/ModList/Header,Text,,spacewarp.modlist,spacewarp.modlist -SpaceWarp/ModList/EnabledMods,Text,,Enabled Mods,Mods ativos -SpaceWarp/ModList/ErroredMods,Text,,Errored Mods,Mods com erros -SpaceWarp/ModList/DisabledMods,Text,,Disabled Mods,Mods desativados -SpaceWarp/ModList/Version,Text,,Version,Versão -SpaceWarp/ModList/Author,Text,,Author,Autor -SpaceWarp/ModList/Source,Text,,Source,Fonte -SpaceWarp/ModList/Description,Text,,Description,Descrição -SpaceWarp/ModList/KSP2Version,Text,,KSP2 Version,Versão do jogo -SpaceWarp/ModList/Dependencies,Text,,Dependencies,Dependências -SpaceWarp/ModList/outdated,Text,,outdated,desatualizado -SpaceWarp/ModList/unsupported,Text,,unsupported,não suportado -SpaceWarp/ModList/disabled,Text,,disabled,desativado -SpaceWarp/ModList/OpenConfigurationManager,Text,,Open Configuration Manager,Abrir gestor de configurações -SpaceWarp/ModList/OpenModsFolder,Text,,Open Mods Folder,Abrir pasta de mods -SpaceWarp/ModList/mismatched,Text,,Mismatched,Não corresponde com o swinfo -SpaceWarp/ModList/baddirectory,Text,,Bad Directory,Problemas no diretorio -SpaceWarp/ModList/missingswinfo,Text,,Missing SW Info,Não possui um swinfo -SpaceWarp/ModList/MissingDependency,Text,,Dependency is missing,Esta dependência não está presente -SpaceWarp/ModList/ErroredDependency,Text,,Dependency had an error while loading,Esta dependência teve um erro durante o loading -SpaceWarp/ModList/DisabledDependency,Text,,Dependency is disabled,Esta dependência esta desativada -SpaceWarp/ModList/UnspecifiedDependency,Text,,Dependency was not specified in SW info,Esta dependência não está presente no swinfo -SpaceWarp/ModList/UnsupportedDependency,Text,,Dependency is of an unsupported version,Esta dependência é de uma versão nao suportada -SpaceWarp/ModList/Conflicts,Text,,Conflicts,Incompatibilidades -SpaceWarp/ModList/Details,Text,,Details,Detalhes -SpaceWarp/Mods,Text,,Mods,Mods -SpaceWarp/Mods/Outdated,Text,,Mods ⚠,Mods ⚠ -SpaceWarp/Mods/Errored,Text,,Mods ⚠,Mods ⚠ -SpaceWarp,Text,,Space Warp,Space Warp -SpaceWarp/VersionChecking,Text,,Allow Space Warp to check versions for mods over the network?,Deixar SpaceWarp verificar a versão dos mods na internet? -SpaceWarp/Yes,Text,,Yes,Sim -SpaceWarp/No,Text,,No,Não -SpaceWarp/Console/Header,Text,,SPACE WARP - Console, SPACE WARP - Consola -SpaceWarp/Console/Clear,Text,,Clear,Limpar -SpaceWarp/Console/AutoScroll,Text,,Auto Scroll,Scroll automatico -SpaceWarp/Console/On,Text,,On,On -SpaceWarp/Console/Off,Text,,Off,Off -SpaceWarp/AvcDialog/Title,Text,,spacewarp.avc,spacewarp.avc -SpaceWarp/AvcDialog/MainText,Text,,Allow SpaceWarp to automatically check for mod updates online?,Allow SpaceWarp to automatically check for mod updates online? -SpaceWarp/AvcDialog/MinorText,Text,,*You can change this later in the settings menu.,*You can change this later in the settings menu. \ No newline at end of file +Key,Type,Description,English,Portuguese BR,French +SpaceWarp/ModList/EnableAll,Text,,Enable All,Ativar todos,Activer tous +SpaceWarp/ModList/DisableAll,Text,,Disable All,Desativar todos,Désactiver tous +SpaceWarp/ModList/RevertChanges,Text,,Revert Changes,Reverter alterações,Rétablir les changements +SpaceWarp/ModList/ApplyChanges,Text,,Apply and restart,Aplicar e reiniciar,Appliquer et redémarrer +SpaceWarp/ModList/multipleChangesDetected,Text,,"{0} changes detected, please restart to apply them","{0} alterações detetadas, porfavor reinicie o jogo","{0} changements détectés, veuillez redémarrer pour les appliquer" +SpaceWarp/ModList/singleChangeDetected,Text,,"1 change detected, please restart to apply it","1 alteração detectada, reinicie para aplicá-la","1 changement détecté, veuillez redémarrer pour l'appliquer" +SpaceWarp/ModList/Header,Text,,spacewarp.modlist,spacewarp.modlist,spacewarp.modlist +SpaceWarp/ModList/CoreMods,Text,,Core Mods,Mods do jogo,Mods du jeu +SpaceWarp/ModList/EnabledMods,Text,,Enabled Mods,Mods ativos,Mods activés +SpaceWarp/ModList/ErroredMods,Text,,Errored Mods,Mods com erros,Mods avec des erreurs +SpaceWarp/ModList/DisabledMods,Text,,Disabled Mods,Mods desativados,Mods désactivés +SpaceWarp/ModList/Version,Text,,Version,Versão,Version +SpaceWarp/ModList/Author,Text,,Author,Autor,Auteur +SpaceWarp/ModList/Source,Text,,Source,Fonte,Source +SpaceWarp/ModList/Description,Text,,Description,Descrição,Description +SpaceWarp/ModList/KSP2Version,Text,,KSP2 Version,Versão do jogo,Version de KSP2 +SpaceWarp/ModList/Dependencies,Text,,Dependencies,Dependências,Dépendances +SpaceWarp/ModList/outdated,Text,,(outdated),(desatualizado),(obsolète) +SpaceWarp/ModList/unsupported,Text,,(unsupported),(não suportado),(non pris en charge) +SpaceWarp/ModList/disabled,Text,,(disabled),(desativado),(désactivé) +SpaceWarp/ModList/mismatched,Text,,(mismatched),(não corresponde com o swinfo),(non concordant) +SpaceWarp/ModList/baddirectory,Text,,(bad directory),(problemas no diretorio),(mauvais dossier) +SpaceWarp/ModList/missingswinfo,Text,,(missing SW Info),(não possui um swinfo),(SW Info manquant) +SpaceWarp/ModList/OpenModSettings,Text,,Mod Settings,Configurações dos mods,Paramètres des mods +SpaceWarp/ModList/OpenModsFolder,Text,,Open Mods Folder,Abrir pasta de mods,Ouvrir le dossier des mods +SpaceWarp/ModList/MissingDependency,Text,,Dependency is missing,Esta dependência não está presente,Cette dépendance est manquante +SpaceWarp/ModList/ErroredDependency,Text,,Dependency had an error while loading,Esta dependência teve um erro durante o loading,Une erreur s'est produite lors du chargement de cette dépendance +SpaceWarp/ModList/DisabledDependency,Text,,Dependency is disabled,Esta dependência esta desativada,Cette dépendance est manquante +SpaceWarp/ModList/UnspecifiedDependency,Text,,Dependency was not specified in SW info,Esta dependência não está presente no swinfo,Cette dépendance n'a pas été spécifiée dans SW Info +SpaceWarp/ModList/UnsupportedDependency,Text,,Dependency is of an unsupported version,Esta dependência é de uma versão nao suportada,Cette dépendance est d'une version non supportée +SpaceWarp/ModList/Conflicts,Text,,Conflicts,Incompatibilidades,Conflits +SpaceWarp/ModList/Details,Text,,Details,Detalhes,Détails +SpaceWarp/Mods,Text,,Mods,Mods,Mods +SpaceWarp/Mods/Outdated,Text,,Mods ⚠,Mods ⚠,Mods ⚠ +SpaceWarp/Mods/Errored,Text,,Mods ⚠,Mods ⚠,Mods ⚠ +SpaceWarp,Text,,Space Warp,Space Warp,Space Warp +SpaceWarp/VersionChecking,Text,,Allow Space Warp to check versions for mods over the network?,Deixar SpaceWarp verificar a versão dos mods na internet?,Autoriser Space Warp à vérifier les versions des mods sur le réseau ? +SpaceWarp/Yes,Text,,Yes,Sim,Oui +SpaceWarp/No,Text,,No,Não,Non +SpaceWarp/Console/Header,Text,,SPACE WARP - Console,SPACE WARP - Consola,SPACE WARP - Console +SpaceWarp/Console/Clear,Text,,Clear,Limpar,Effacer +SpaceWarp/Console/AutoScroll,Text,,Auto Scroll,Scroll automatico,Défilement automatique +SpaceWarp/Console/On,Text,,On,On,On +SpaceWarp/Console/Off,Text,,Off,Off,Off +SpaceWarp/AvcDialog/Title,Text,,spacewarp.avc,spacewarp.avc,spacewarp.avc +SpaceWarp/AvcDialog/MainText,Text,,Allow SpaceWarp to automatically check for mod updates online?,Permitir que o SpaceWarp verifique automaticamente se há atualizações de mods online?,Autoriser SpaceWarp à vérifier automatiquement les mises à jour de mods en ligne ? +SpaceWarp/AvcDialog/MinorText,Text,,*You can change this later in the settings menu.,*Pode alterá-lo mais tarde no menu de definições.,*Vous pouvez modifier plus tard dans le menu des réglages. \ No newline at end of file diff --git a/plugin_template/BepInEx/plugins/SpaceWarp/swinfo.json b/plugin_template/BepInEx/plugins/SpaceWarp/swinfo.json index 67c244b5..6f560484 100644 --- a/plugin_template/BepInEx/plugins/SpaceWarp/swinfo.json +++ b/plugin_template/BepInEx/plugins/SpaceWarp/swinfo.json @@ -1,11 +1,11 @@ { - "spec": "2.0", + "spec": "2.1", "mod_id": "com.github.x606.spacewarp", "author": "Space Warp Team", "name": "Space Warp", "description": "Space Warp is an API for KSP 2 mod developers.", "source": "https://github.com/SpaceWarpDev/SpaceWarp", - "version": "1.7.0", + "version": "1.8.0", "version_check": "https://raw.githubusercontent.com/SpaceWarpDev/SpaceWarp/main/plugin_template/BepInEx/plugins/SpaceWarp/swinfo.json", "ksp2_version": { "min": "0.2.0", @@ -18,13 +18,9 @@ "min": "2.4.0", "max": "*" } - }, - { - "id": "com.bepis.bepinex.configurationmanager", - "version": { - "min": "*", - "max": "*" - } } + ], + "patchers": [ + "SpaceWarpPatcher.dll" ] } diff --git a/plugin_template/doorstop_config.ini b/plugin_template/doorstop_config.ini index a68f30f1..42991f24 100644 --- a/plugin_template/doorstop_config.ini +++ b/plugin_template/doorstop_config.ini @@ -7,7 +7,7 @@ targetAssembly=BepInEx\core\BepInEx.Preloader.dll redirectOutputLog=false # If enabled, DOORSTOP_DISABLE env var value is ignored # USE THIS ONLY WHEN ASKED TO OR YOU KNOW WHAT THIS MEANS -ignoreDisableSwitch=false +ignoreDisableSwitch=true # Overrides default Mono DLL search path # Sometimes it is needed to instruct Mono to seek its assemblies from a different path # (e.g. mscorlib is stripped in original game) diff --git a/src/SpaceWarp.Core/API/Assets/AssetManager.cs b/src/SpaceWarp.Core/API/Assets/AssetManager.cs index d1d956b2..fc578cb7 100644 --- a/src/SpaceWarp.Core/API/Assets/AssetManager.cs +++ b/src/SpaceWarp.Core/API/Assets/AssetManager.cs @@ -1,13 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using JetBrains.Annotations; +using JetBrains.Annotations; +using SpaceWarp.API.Logging; using SpaceWarp.API.Lua; using UnityEngine; using Logger = BepInEx.Logging.Logger; namespace SpaceWarp.API.Assets; +/// +/// Manages all mod assets loaded by SpaceWarp +/// [SpaceWarpLuaAPI("Assets")] [PublicAPI] public static class AssetManager @@ -17,7 +18,7 @@ public static class AssetManager internal static async Task RegisterAssetBundle(string modId, string assetBundleName, AssetBundle assetBundle) { assetBundleName = assetBundleName.Replace(".bundle", ""); - var logger = Logger.CreateLogSource($"{modId}/{assetBundleName}"); + var logger = BaseLogger.CreateDefault($"{modId}/{assetBundleName}"); var names = assetBundle.GetAllAssetNames(); diff --git a/src/SpaceWarp.Core/API/Configuration/BepInExConfigEntry.cs b/src/SpaceWarp.Core/API/Configuration/BepInExConfigEntry.cs index 1901d908..d49ab909 100644 --- a/src/SpaceWarp.Core/API/Configuration/BepInExConfigEntry.cs +++ b/src/SpaceWarp.Core/API/Configuration/BepInExConfigEntry.cs @@ -1,20 +1,38 @@ -using System; -using BepInEx.Configuration; +using BepInEx.Configuration; using JetBrains.Annotations; namespace SpaceWarp.API.Configuration; +/// +/// A wrapper around a BepInEx to make it compatible with the +/// interface. +/// [PublicAPI] public class BepInExConfigEntry : IConfigEntry { + /// + /// The underlying that this class wraps. + /// public readonly ConfigEntryBase EntryBase; - public event Action Callbacks; + + /// + /// The callbacks that are invoked when the value of this entry changes. + /// + public event Action Callbacks; + + /// + /// Creates a new from the given and optional + /// . + /// + /// The to wrap. + /// The to use. public BepInExConfigEntry(ConfigEntryBase entryBase, IValueConstraint constraint = null) { EntryBase = entryBase; Constraint = constraint; } + /// public object Value { get => EntryBase.BoxedValue; @@ -25,8 +43,10 @@ public object Value } } + /// public Type ValueType => EntryBase.SettingType; + /// public T Get() where T : class { if (!typeof(T).IsAssignableFrom(ValueType)) @@ -37,6 +57,7 @@ public T Get() where T : class return Value as T; } + /// public void Set(T value) { if (!ValueType.IsAssignableFrom(typeof(T))) @@ -48,12 +69,16 @@ public void Set(T value) { if (!Constraint.IsConstrained(value)) return; } - Callbacks?.Invoke(EntryBase.BoxedValue, value); EntryBase.BoxedValue = Convert.ChangeType(value, ValueType); } + /// public string Description => EntryBase.Description.Description; + + /// public IValueConstraint Constraint { get; } + + /// public void RegisterCallback(Action valueChangedCallback) { Callbacks += valueChangedCallback; diff --git a/src/SpaceWarp.Core/API/Configuration/BepInExConfigFile.cs b/src/SpaceWarp.Core/API/Configuration/BepInExConfigFile.cs index a1a5c60f..f519af3c 100644 --- a/src/SpaceWarp.Core/API/Configuration/BepInExConfigFile.cs +++ b/src/SpaceWarp.Core/API/Configuration/BepInExConfigFile.cs @@ -1,40 +1,74 @@ -using System.Collections.Generic; -using BepInEx.Configuration; +using BepInEx.Configuration; using JetBrains.Annotations; namespace SpaceWarp.API.Configuration; +/// +/// A wrapper around BepInEx's to make it implement . +/// [PublicAPI] public class BepInExConfigFile : IConfigFile { - + /// + /// The underlying instance. + /// public readonly ConfigFile AdaptedConfigFile; + /// + /// Creates a new instance. + /// + /// The instance to wrap. public BepInExConfigFile(ConfigFile adaptedConfigFile) { AdaptedConfigFile = adaptedConfigFile; } + /// public void Save() { AdaptedConfigFile.Save(); } - public IConfigEntry this[string section, string key] => new BepInExConfigEntry(AdaptedConfigFile[section, key]); + private Dictionary<(string section, string key), IConfigEntry> _storedEntries = new(); + + /// + public IConfigEntry this[string section, string key] => _storedEntries.TryGetValue((section, key), out var result) + ? result + : _storedEntries[(section, key)] = new BepInExConfigEntry(AdaptedConfigFile[section, key], + IValueConstraint.FromAcceptableValueBase(AdaptedConfigFile[section, key].Description.AcceptableValues)); + /// public IConfigEntry Bind(string section, string key, T defaultValue = default, string description = "") { return new BepInExConfigEntry(AdaptedConfigFile.Bind(section, key, defaultValue, description)); } - public IConfigEntry Bind(string section, string key, T defaultValue, string description, IValueConstraint valueConstraint) + /// + /// Binds a new config entry to the given section and key with the given default value and description. + /// + /// Section to bind the entry to. + /// Key to bind the entry to. + /// Default value of the entry. + /// Description of the entry. + /// Value constraint of the entry. + /// Type of the entry. + /// The newly bound config entry. + public IConfigEntry Bind( + string section, + string key, + T defaultValue, + string description, + IValueConstraint valueConstraint + ) { - return new BepInExConfigEntry(AdaptedConfigFile.Bind(new ConfigDefinition(section, key), defaultValue, - new ConfigDescription(description, valueConstraint.ToAcceptableValueBase()))); + return _storedEntries[(section, key)] = new BepInExConfigEntry(AdaptedConfigFile.Bind(new ConfigDefinition(section, key), defaultValue, + new ConfigDescription(description, valueConstraint.ToAcceptableValueBase())),valueConstraint); } + /// public IReadOnlyList Sections => AdaptedConfigFile.Keys.Select(x => x.Section).Distinct().ToList(); + /// public IReadOnlyList this[string section] => AdaptedConfigFile.Keys.Where(x => x.Section == section) .Select(x => x.Key).ToList(); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Configuration/ConfigValue.cs b/src/SpaceWarp.Core/API/Configuration/ConfigValue.cs index b4a54278..670b1977 100644 --- a/src/SpaceWarp.Core/API/Configuration/ConfigValue.cs +++ b/src/SpaceWarp.Core/API/Configuration/ConfigValue.cs @@ -1,13 +1,26 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; namespace SpaceWarp.API.Configuration; +/// +/// A wrapper around that provides type safety. +/// +/// The type of the value. [PublicAPI] public class ConfigValue { + /// + /// The underlying . + /// public IConfigEntry Entry; + /// + /// Creates a new from an . + /// + /// The entry to wrap. + /// + /// If the type of does not match . + /// public ConfigValue(IConfigEntry entry) { Entry = entry; @@ -17,15 +30,19 @@ public ConfigValue(IConfigEntry entry) } } + /// + /// The value of the entry. + /// public T Value { get => (T)Entry.Value; - set - { - Entry.Value = value; - } + set => Entry.Value = value; } + /// + /// Registers a callback that will be invoked when the value changes. + /// + /// The callback to invoke. public void RegisterCallback(Action callback) { // Callbacks += callback; diff --git a/src/SpaceWarp.Core/API/Configuration/EmptyConfigFile.cs b/src/SpaceWarp.Core/API/Configuration/EmptyConfigFile.cs index 503d8914..85cd3bbb 100644 --- a/src/SpaceWarp.Core/API/Configuration/EmptyConfigFile.cs +++ b/src/SpaceWarp.Core/API/Configuration/EmptyConfigFile.cs @@ -1,28 +1,52 @@ -using System.Collections.Generic; -using JetBrains.Annotations; +using JetBrains.Annotations; namespace SpaceWarp.API.Configuration; +/// +/// An empty config file that does not save anything. +/// [PublicAPI] public class EmptyConfigFile : IConfigFile { + /// public void Save() { } + /// public IConfigEntry this[string section, string key] => throw new KeyNotFoundException($"{section}/{key}"); + /// public IConfigEntry Bind(string section, string key, T defaultValue = default, string description = "") { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } - public IConfigEntry Bind(string section, string key, T defaultValue, string description, IValueConstraint valueConstraint) + /// + /// Binds a config entry to a section and key. + /// + /// Section to bind to. + /// Key to bind to. + /// Default value to use if no value is found. + /// Description of the config entry. + /// Constraint to use for the value. + /// Type of the value. + /// The config entry. + /// Always thrown. + public IConfigEntry Bind( + string section, + string key, + T defaultValue, + string description, + IValueConstraint valueConstraint + ) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } + /// public IReadOnlyList Sections => new List(); + /// public IReadOnlyList this[string section] => throw new KeyNotFoundException($"{section}"); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Configuration/IConfigEntry.cs b/src/SpaceWarp.Core/API/Configuration/IConfigEntry.cs index f5f062a9..0506edea 100644 --- a/src/SpaceWarp.Core/API/Configuration/IConfigEntry.cs +++ b/src/SpaceWarp.Core/API/Configuration/IConfigEntry.cs @@ -1,23 +1,52 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; namespace SpaceWarp.API.Configuration; +/// +/// Represents a config entry +/// [PublicAPI] public interface IConfigEntry { + /// + /// The value of the config entry + /// public object Value { get; set; } + + /// + /// The type of the value of the config entry + /// public Type ValueType { get; } + + /// + /// Gets the value of the config entry as a specific type + /// + /// The type to cast to + /// The value as the specified type public T Get() where T : class; + + /// + /// Sets the value of the config entry + /// + /// The value to set + /// The type of the value public void Set(T value); + /// + /// The description of the config entry + /// public string Description { get; } + /// + /// The value constraint of the config entry + /// public IValueConstraint Constraint { get; } - + /// - /// Called when setting the value on a config file + /// Registers a callback to be called when setting the value on a config file /// - /// An action that takes te old value and the new value and calls a callback + /// + /// An action that takes the old value and the new value and calls a callback + /// public void RegisterCallback(Action valueChangedCallback); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Configuration/IConfigFile.cs b/src/SpaceWarp.Core/API/Configuration/IConfigFile.cs index 87aedf23..2b271e5d 100644 --- a/src/SpaceWarp.Core/API/Configuration/IConfigFile.cs +++ b/src/SpaceWarp.Core/API/Configuration/IConfigFile.cs @@ -1,18 +1,44 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; +using JetBrains.Annotations; namespace SpaceWarp.API.Configuration; +/// +/// Represents a configuration file. +/// [PublicAPI] public interface IConfigFile { + /// + /// Saves the configuration file. + /// public void Save(); + /// + /// Gets the with the specified section and key. + /// + /// Section of the entry. + /// Key of the entry. public IConfigEntry this[string section, string key] { get; } + /// + /// Binds a new to the specified section and key. + /// + /// Section of the entry. + /// Key of the entry. + /// Default value of the entry. + /// Description of the entry. + /// Type of the entry. + /// The bound . public IConfigEntry Bind(string section, string key, T defaultValue = default, string description = ""); - + + /// + /// A list of all sections in the configuration file. + /// public IReadOnlyList Sections { get; } + + /// + /// A list of all keys in the specified section. + /// + /// public IReadOnlyList this[string section] { get; } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Configuration/IValueConstraint.cs b/src/SpaceWarp.Core/API/Configuration/IValueConstraint.cs index 4256ceba..b6f78822 100644 --- a/src/SpaceWarp.Core/API/Configuration/IValueConstraint.cs +++ b/src/SpaceWarp.Core/API/Configuration/IValueConstraint.cs @@ -1,9 +1,56 @@ -using BepInEx.Configuration; +using System.Reflection; +using BepInEx.Configuration; namespace SpaceWarp.API.Configuration; +/// +/// A constraint that can be applied to a to limit the values it can take. +/// public interface IValueConstraint { + /// + /// Checks if the given object is constrained by this constraint. + /// + /// Object to check. + /// True if the object is constrained, false otherwise. public bool IsConstrained(object o); + + /// + /// Converts this constraint to an . + /// + /// An representing this constraint. public AcceptableValueBase ToAcceptableValueBase(); + + /// + /// Converts an acceptable value base into an IValueConstraint + /// + /// The acceptable value base + /// The IValueConstraint + public static IValueConstraint FromAcceptableValueBase(AcceptableValueBase acceptableValueBase) + { + if (acceptableValueBase is null) return null; + if (acceptableValueBase.GetType().GetGenericTypeDefinition() == typeof(AcceptableValueList<>)) + { + var type = acceptableValueBase.GetType().GetGenericArguments()[0]; + var valuesMethod = acceptableValueBase.GetType() + .GetProperty("AcceptableValues", BindingFlags.Instance | BindingFlags.Public) + ?.GetMethod; + var values = valuesMethod?.Invoke(acceptableValueBase,[]); + return (IValueConstraint)Activator.CreateInstance(typeof(ListConstraint<>).MakeGenericType(type), [values]); + } + + if (acceptableValueBase.GetType().GetGenericTypeDefinition() == typeof(AcceptableValueRange<>)) + { + var type = acceptableValueBase.GetType().GetGenericArguments()[0]; + var minMethod = acceptableValueBase.GetType() + .GetProperty("MinValue", BindingFlags.Instance | BindingFlags.Public)?.GetMethod; + var maxMethod = acceptableValueBase.GetType() + .GetProperty("MaxValue", BindingFlags.Instance | BindingFlags.Public)?.GetMethod; + var min = minMethod?.Invoke(acceptableValueBase, []); + var max = maxMethod?.Invoke(acceptableValueBase, []); + return (IValueConstraint)Activator.CreateInstance(typeof(RangeConstraint<>).MakeGenericType(type),[min,max]); + } + + return null; + } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Configuration/JsonConfigEntry.cs b/src/SpaceWarp.Core/API/Configuration/JsonConfigEntry.cs index 977f910c..e43b17ab 100644 --- a/src/SpaceWarp.Core/API/Configuration/JsonConfigEntry.cs +++ b/src/SpaceWarp.Core/API/Configuration/JsonConfigEntry.cs @@ -1,17 +1,36 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; namespace SpaceWarp.API.Configuration; +/// +/// A config entry that is stored in a JSON file. +/// [PublicAPI] public class JsonConfigEntry : IConfigEntry { private readonly JsonConfigFile _configFile; private object _value; - public event Action Callbacks; - - public JsonConfigEntry(JsonConfigFile configFile, Type type, string description, object value, IValueConstraint constraint = null) + /// + /// The callbacks that are invoked when the value of this entry changes. + /// + public event Action Callbacks; + + /// + /// Creates a new config entry. + /// + /// Config file that this entry belongs to. + /// Type of the value. + /// Description of the value. + /// Value of the entry. + /// Constraint of the value. + public JsonConfigEntry( + JsonConfigFile configFile, + Type type, + string description, + object value, + IValueConstraint constraint = null + ) { _configFile = configFile; _value = value; @@ -20,7 +39,7 @@ public JsonConfigEntry(JsonConfigFile configFile, Type type, string description, ValueType = type; } - + /// public object Value { get => _value; @@ -32,7 +51,10 @@ public object Value } } + /// public Type ValueType { get; } + + /// public T Get() where T : class { if (!typeof(T).IsAssignableFrom(ValueType)) @@ -43,6 +65,7 @@ public T Get() where T : class return Value as T; } + /// public void Set(T value) { if (!ValueType.IsAssignableFrom(typeof(T))) @@ -56,8 +79,13 @@ public void Set(T value) Value = Convert.ChangeType(value, ValueType); } + /// public string Description { get; } + + /// public IValueConstraint Constraint { get; } + + /// public void RegisterCallback(Action valueChangedCallback) { Callbacks += valueChangedCallback; diff --git a/src/SpaceWarp.Core/API/Configuration/JsonConfigFile.cs b/src/SpaceWarp.Core/API/Configuration/JsonConfigFile.cs index aafbfc8b..90d38866 100644 --- a/src/SpaceWarp.Core/API/Configuration/JsonConfigFile.cs +++ b/src/SpaceWarp.Core/API/Configuration/JsonConfigFile.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; +using System.Text; using JetBrains.Annotations; using KSP.IO; using Newtonsoft.Json; @@ -11,6 +8,9 @@ namespace SpaceWarp.API.Configuration; +/// +/// A config file that uses JSON to store its data. +/// [PublicAPI] public class JsonConfigFile : IConfigFile { @@ -19,6 +19,10 @@ public class JsonConfigFile : IConfigFile internal Dictionary> CurrentEntries = new(); private readonly string _file; + /// + /// Creates a new JSON config file object. + /// + /// The file path to use. public JsonConfigFile(string file) { // Use .cfg as this is going to have comments and that will be an issue @@ -38,6 +42,7 @@ public JsonConfigFile(string file) _file = file; } + /// public void Save() { if (!CurrentEntries.Any(value => value.Value.Count > 0)) return; @@ -72,6 +77,9 @@ private static bool DumpSection(bool hadPreviousSection, StringBuilder result, K private static List _defaultConverters; + /// + /// The default converters to use when serializing/deserializing JSON. + /// public static List DefaultConverters { get @@ -86,7 +94,11 @@ public static List DefaultConverters } } - private static bool DumpEntry(StringBuilder result, bool hadPreviousKey, KeyValuePair entry) + private static bool DumpEntry( + StringBuilder result, + bool hadPreviousKey, + KeyValuePair entry + ) { if (hadPreviousKey) { @@ -128,8 +140,10 @@ private static bool DumpEntry(StringBuilder result, bool hadPreviousKey, KeyValu return true; } + /// public IConfigEntry this[string section, string key] => CurrentEntries[section][key]; + /// public IConfigEntry Bind(string section, string key, T defaultValue = default, string description = "") { // So now we have to check if its already bound, and/or if the previous config object has it @@ -173,7 +187,9 @@ public IConfigEntry Bind(string section, string key, T defaultValue = default return previousSection[key]; } + /// public IReadOnlyList Sections => CurrentEntries.Keys.ToList(); + /// public IReadOnlyList this[string section] => CurrentEntries[section].Keys.ToList(); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Configuration/ListConstraint.cs b/src/SpaceWarp.Core/API/Configuration/ListConstraint.cs index b9610ee4..af5dd4b8 100644 --- a/src/SpaceWarp.Core/API/Configuration/ListConstraint.cs +++ b/src/SpaceWarp.Core/API/Configuration/ListConstraint.cs @@ -1,32 +1,48 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Text; using BepInEx.Configuration; using JetBrains.Annotations; namespace SpaceWarp.API.Configuration; +/// +/// A constraint that checks if the value is in a list of acceptable values. +/// +/// The type of the value. public class ListConstraint : ValueConstraint where T : IEquatable { - [PublicAPI] - public List AcceptableValues; - + /// + /// The list of acceptable values. + /// + [PublicAPI] public List AcceptableValues; + + /// + /// Creates a new list constraint. + /// + /// The list of acceptable values. public ListConstraint(IEnumerable acceptableValues) { AcceptableValues = acceptableValues.ToList(); } + /// + /// Creates a new list constraint. + /// + /// The array of acceptable values. public ListConstraint(params T[] acceptableValues) { AcceptableValues = acceptableValues.ToList(); } + /// public override bool IsValid(T o) => AcceptableValues.Any(x => x.Equals(o)); + + /// public override AcceptableValueBase ToAcceptableValueBase() { return new AcceptableValueList(AcceptableValues.ToArray()); } + /// public override string ToString() { StringBuilder sb = new(); diff --git a/src/SpaceWarp.Core/API/Configuration/RangeConstraint.cs b/src/SpaceWarp.Core/API/Configuration/RangeConstraint.cs index 00fbc08d..18e0a4c5 100644 --- a/src/SpaceWarp.Core/API/Configuration/RangeConstraint.cs +++ b/src/SpaceWarp.Core/API/Configuration/RangeConstraint.cs @@ -1,28 +1,45 @@ -using System; -using BepInEx.Configuration; +using BepInEx.Configuration; using JetBrains.Annotations; namespace SpaceWarp.API.Configuration; +/// +/// A constraint that checks if a value is within a range. +/// +/// The type of the value. public class RangeConstraint : ValueConstraint where T : IComparable, IComparable { - [PublicAPI] - public T Minimum; - [PublicAPI] - public T Maximum; + /// + /// The minimum value. + /// + [PublicAPI] public T Minimum; + /// + /// The maximum value. + /// + [PublicAPI] public T Maximum; + + /// + /// Creates a new range constraint. + /// + /// The minimum value. + /// The maximum value. public RangeConstraint(T minimum, T maximum) { Minimum = minimum; Maximum = maximum; } + /// public override bool IsValid(T o) => Minimum.CompareTo(o) <= 0 && Maximum.CompareTo(o) >= 0; + + /// public override AcceptableValueBase ToAcceptableValueBase() { return new AcceptableValueRange(Minimum, Maximum); } + /// public override string ToString() { return $"{Minimum} - {Maximum}"; diff --git a/src/SpaceWarp.Core/API/Configuration/ValueConstraint.cs b/src/SpaceWarp.Core/API/Configuration/ValueConstraint.cs index ddabf763..4ba8da0e 100644 --- a/src/SpaceWarp.Core/API/Configuration/ValueConstraint.cs +++ b/src/SpaceWarp.Core/API/Configuration/ValueConstraint.cs @@ -2,18 +2,35 @@ namespace SpaceWarp.API.Configuration; +/// +/// Base class for value constraints. +/// +/// Type of the value. public abstract class ValueConstraint : IValueConstraint { + /// + /// Returns true if the given value is valid for this constraint. + /// + /// Value to check. + /// True if the value is valid, false otherwise. public abstract bool IsValid(T o); + + /// + /// Returns true if the given value is valid for this constraint. + /// + /// Value to check. + /// True if the value is valid, false otherwise. public bool IsValid(object o) { return IsValid((T)o); } + /// public bool IsConstrained(object o) { return IsValid((T)o); } + /// public abstract AcceptableValueBase ToAcceptableValueBase(); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Loading/Loading.cs b/src/SpaceWarp.Core/API/Loading/Loading.cs index e9a0a82d..d85b3b08 100644 --- a/src/SpaceWarp.Core/API/Loading/Loading.cs +++ b/src/SpaceWarp.Core/API/Loading/Loading.cs @@ -1,15 +1,17 @@ -using System; -using System.Collections.Generic; -using System.IO; -using JetBrains.Annotations; +using JetBrains.Annotations; using KSP.Game.Flow; using SpaceWarp.API.Assets; using SpaceWarp.API.Mods; using SpaceWarp.InternalUtilities; using SpaceWarp.Patching.LoadingActions; +#pragma warning disable CS0618 // Type or member is obsolete + namespace SpaceWarp.API.Loading; +/// +/// API for mods to register their actions for the loading of assets. +/// [PublicAPI] public static class Loading { @@ -20,7 +22,7 @@ public static class Loading internal static List> GeneralLoadingActions = new(); /// - /// Registers an asset loading function for space warp, will load assets from the subfolder. Should be added either on Awake() or Start(). + /// Registers an asset loading function for SpaceWarp, will load assets from the subfolder. Should be added either on Awake() or Start(). /// /// The subfolder under "assets" that this loader matches /// The name to be displayed for this loader, it gets displayed like the following "Mod Name: [name]" @@ -98,7 +100,7 @@ private static Action CreateAssetLoadingActionWithExtension } catch (Exception e) { - plugin.ModLogger.LogError(e.ToString()); + plugin.SWLogger.LogError(e.ToString()); } } } @@ -127,7 +129,7 @@ private static Action CreateAssetLoadingActionWithExt if (plugin.Plugin != null) plugin.Plugin.SWLogger.LogError(e.ToString()); else - SpaceWarpPlugin.Logger.LogError(plugin.SWInfo.Name + ": " + e); + SpaceWarpPlugin.Instance.SWLogger.LogError(plugin.SWInfo.Name + ": " + e); } } } @@ -195,7 +197,7 @@ private static Action CreateAssetLoadingActionWithoutExtens } catch (Exception e) { - plugin.ModLogger.LogError(e.ToString()); + plugin.SWLogger.LogError(e.ToString()); } } }; @@ -221,7 +223,7 @@ private static Action CreateAssetLoadingActionWithout if (plugin.Plugin != null) plugin.Plugin.SWLogger.LogError(e.ToString()); else - SpaceWarpPlugin.Logger.LogError(plugin.SWInfo.Name + ": " + e); + SpaceWarpPlugin.Instance.SWLogger.LogError(plugin.SWInfo.Name + ": " + e); } } }; diff --git a/src/SpaceWarp.Core/API/Loading/SaveLoad.cs b/src/SpaceWarp.Core/API/Loading/SaveLoad.cs index cd617ef5..8808ff96 100644 --- a/src/SpaceWarp.Core/API/Loading/SaveLoad.cs +++ b/src/SpaceWarp.Core/API/Loading/SaveLoad.cs @@ -1,17 +1,19 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; using KSP.Game.Flow; -using SpaceWarp.Patching; +using SpaceWarp.Patching.Flow; namespace SpaceWarp.API.Loading; +/// +/// An API to register flow actions to be run during loading and saving. +/// [PublicAPI] public static class SaveLoad { /// /// Construct and add a FlowAction to the Game's load sequence. /// - /// FlowActionType must have a public constructor that takes either no arguments, + /// TFlowActionType must have a public constructor that takes either no arguments, /// or a single GameManager. /// /// The action will be run after the first FlowAction with a name equal to referenceAction. @@ -34,12 +36,12 @@ public static class SaveLoad /// /// /// - /// The type of FlowAction to insert - /// The name of the action to insert a FlowActionType after. Use null to insert it at the start. - /// Thrown if FlowActionType does not have a valid Constructor - public static void AddFlowActionToGameLoadAfter(string referenceAction) where FlowActionType : FlowAction + /// The type of FlowAction to insert + /// The name of the action to insert a TFlowActionType after. Use null to insert it at the start. + /// Thrown if TFlowActionType does not have a valid Constructor + public static void AddFlowActionToGameLoadAfter(string referenceAction) where TFlowActionType : FlowAction { - SequentialFlowLoadersPatcher.AddConstructor(referenceAction, typeof(FlowActionType), SequentialFlowLoadersPatcher.FlowMethodStartgame); + SequentialFlowLoadersPatcher.AddConstructor(referenceAction, typeof(TFlowActionType), SequentialFlowLoadersPatcher.FlowMethodStartgame); } /// @@ -66,17 +68,17 @@ public static void AddFlowActionToGameLoadAfter(string reference /// /// /// The FlowAction to insert - /// The name of the action to insert a FlowActionType after. Use null to insert it at the start. + /// The name of the action to insert a TFlowActionType after. Use null to insert it at the start. public static void AddFlowActionToGameLoadAfter(FlowAction flowAction, string referenceAction) { SequentialFlowLoadersPatcher.AddFlowAction(referenceAction, flowAction, SequentialFlowLoadersPatcher.FlowMethodStartgame); } /// - /// Add a FlowAction to the save file loading sequence. A new FlowActionType is constructed every load. + /// Add a FlowAction to the save file loading sequence. A new TFlowActionType is constructed every load. /// /// - /// FlowActionType must have a public constructor that at most one of each of the following types: + /// TFlowActionType must have a public constructor that at most one of each of the following types: /// /// SaveLoadManager /// LoadOrSaveCampaignTicket @@ -145,12 +147,12 @@ public static void AddFlowActionToGameLoadAfter(FlowAction flowAction, string re /// /// /// - /// The type of FlowAction to insert - /// The name of the action to insert a FlowActionType after. Use null to insert it at the start. - /// Thrown if FlowActionType does not have a valid Constructor - public static void AddFlowActionToCampaignLoadAfter(string referenceAction) where FlowActionType : FlowAction + /// The type of FlowAction to insert + /// The name of the action to insert a TFlowActionType after. Use null to insert it at the start. + /// Thrown if TFlowActionType does not have a valid Constructor + public static void AddFlowActionToCampaignLoadAfter(string referenceAction) where TFlowActionType : FlowAction { - SequentialFlowLoadersPatcher.AddConstructor(referenceAction, typeof(FlowActionType), SequentialFlowLoadersPatcher.FlowMethodPrivateloadcommon); + SequentialFlowLoadersPatcher.AddConstructor(referenceAction, typeof(TFlowActionType), SequentialFlowLoadersPatcher.FlowMethodPrivateloadcommon); } /// @@ -225,10 +227,10 @@ public static void AddFlowActionToCampaignLoadAfter(FlowAction flowAction, strin } /// - /// Add a FlowAction to the save file writing sequence. A new FlowActionType is constructed every load. + /// Add a FlowAction to the save file writing sequence. A new TFlowActionType is constructed every load. /// /// - /// FlowActionType must have a public constructor that at most one of each of the following types: + /// TFlowActionType must have a public constructor that at most one of each of the following types: /// /// SaveLoadManager /// LoadOrSaveCampaignTicket @@ -258,12 +260,12 @@ public static void AddFlowActionToCampaignLoadAfter(FlowAction flowAction, strin /// /// /// - /// The type of FlowAction to insert - /// The name of the action to insert a FlowActionType after. Use null to insert it at the start. - /// Thrown if FlowActionType does not have a valid Constructor - public static void AddFlowActionToCampaignSaveAfter(string referenceAction) where FlowActionType : FlowAction + /// The type of FlowAction to insert + /// The name of the action to insert a TFlowActionType after. Use null to insert it at the start. + /// Thrown if TFlowActionType does not have a valid Constructor + public static void AddFlowActionToCampaignSaveAfter(string referenceAction) where TFlowActionType : FlowAction { - SequentialFlowLoadersPatcher.AddConstructor(referenceAction, typeof(FlowActionType), SequentialFlowLoadersPatcher.FlowMethodPrivatesavecommon); + SequentialFlowLoadersPatcher.AddConstructor(referenceAction, typeof(TFlowActionType), SequentialFlowLoadersPatcher.FlowMethodPrivatesavecommon); } /// diff --git a/src/SpaceWarp.Core/API/Logging/BaseLogger.cs b/src/SpaceWarp.Core/API/Logging/BaseLogger.cs index 7835d5b4..1600c4c6 100644 --- a/src/SpaceWarp.Core/API/Logging/BaseLogger.cs +++ b/src/SpaceWarp.Core/API/Logging/BaseLogger.cs @@ -1,24 +1,39 @@ -using JetBrains.Annotations; +using BepInEx.Logging; +using JetBrains.Annotations; namespace SpaceWarp.API.Logging; +/// +/// Base class for loggers. +/// [PublicAPI] public abstract class BaseLogger : ILogger { + /// public abstract void Log(LogLevel level, object x); - public void LogNone(object x) => Log(LogLevel.None, x); + /// public void LogFatal(object x) => Log(LogLevel.Fatal, x); + /// public void LogError(object x) => Log(LogLevel.Error, x); + /// public void LogWarning(object x) => Log(LogLevel.Warning, x); + /// public void LogMessage(object x) => Log(LogLevel.Message, x); + /// public void LogInfo(object x) => Log(LogLevel.Info, x); + /// public void LogDebug(object x) => Log(LogLevel.Debug, x); - public void LogAll(object x) => Log(LogLevel.All, x); + /// + /// Creates a logger of default type with the specified name. + /// + /// The name of the logger. + /// The created logger. + public static BaseLogger CreateDefault(string name) => new BepInExLogger(new ManualLogSource(name)); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Logging/BepInExLogger.cs b/src/SpaceWarp.Core/API/Logging/BepInExLogger.cs index 662f73a3..07897907 100644 --- a/src/SpaceWarp.Core/API/Logging/BepInExLogger.cs +++ b/src/SpaceWarp.Core/API/Logging/BepInExLogger.cs @@ -3,20 +3,33 @@ namespace SpaceWarp.API.Logging; +/// +/// A logger that uses BepInEx's logging system. +/// [PublicAPI] public class BepInExLogger : BaseLogger { private ManualLogSource _log; + /// + /// Creates a new instance of . + /// + /// The to use. public BepInExLogger(ManualLogSource log) { _log = log; } + /// public override void Log(LogLevel level, object x) { _log.Log((BepInEx.Logging.LogLevel)level, x); } + /// + /// Implicitly converts a to a . + /// + /// The to convert. + /// The converted . public static implicit operator BepInExLogger(ManualLogSource log) => new(log); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Logging/ILogger.cs b/src/SpaceWarp.Core/API/Logging/ILogger.cs index a77e76e3..f84cfa9f 100644 --- a/src/SpaceWarp.Core/API/Logging/ILogger.cs +++ b/src/SpaceWarp.Core/API/Logging/ILogger.cs @@ -2,17 +2,52 @@ namespace SpaceWarp.API.Logging; +/// +/// Interface for loggers. +/// [PublicAPI] public interface ILogger { + /// + /// Logs the given object with the given log level. + /// + /// Log level. + /// Object to log. public void Log(LogLevel level, object x); - public void LogNone(object x); + /// + /// Logs the given object with the log level . + /// + /// Object to log. public void LogFatal(object x); + + /// + /// Logs the given object with the log level . + /// + /// Object to log. public void LogError(object x); + + /// + /// Logs the given object with the log level . + /// + /// Object to log. public void LogWarning(object x); + + /// + /// Logs the given object with the log level . + /// + /// Object to log. public void LogMessage(object x); + + /// + /// Logs the given object with the log level . + /// + /// Object to log. public void LogInfo(object x); + + /// + /// Logs the given object with the log level . + /// + /// Object to log. public void LogDebug(object x); - public void LogAll(object x); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Logging/LogLevel.cs b/src/SpaceWarp.Core/API/Logging/LogLevel.cs index 2ef7977f..2c26fdd5 100644 --- a/src/SpaceWarp.Core/API/Logging/LogLevel.cs +++ b/src/SpaceWarp.Core/API/Logging/LogLevel.cs @@ -2,15 +2,42 @@ namespace SpaceWarp.API.Logging; +/// +/// The log level. +/// [PublicAPI] public enum LogLevel { + /// + /// No logging. + /// None = 0, + /// + /// Fatal errors. + /// Fatal = 1, + /// + /// Errors. + /// Error = 2, + /// + /// Warnings. + /// Warning = 4, + /// + /// Messages. + /// Message = 8, + /// + /// Information. + /// Info = 16, + /// + /// Debug information. + /// Debug = 32, + /// + /// All logging. + /// All = Debug | Info | Message | Warning | Error | Fatal } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Logging/UnityLogSource.cs b/src/SpaceWarp.Core/API/Logging/UnityLogSource.cs index 654cb060..8abbb90c 100644 --- a/src/SpaceWarp.Core/API/Logging/UnityLogSource.cs +++ b/src/SpaceWarp.Core/API/Logging/UnityLogSource.cs @@ -3,16 +3,27 @@ namespace SpaceWarp.API.Logging; +/// +/// A logger that logs to Unity's built-in logging system. +/// [PublicAPI] public class UnityLogSource : BaseLogger { + /// + /// The name of the logger. + /// public string Name; + /// + /// Creates a new with the given name. + /// + /// The name of the logger. public UnityLogSource(string name) { Name = name; } + /// public override void Log(LogLevel level, object x) { switch (level) diff --git a/src/SpaceWarp.Core/API/Lua/LuaMod.cs b/src/SpaceWarp.Core/API/Lua/LuaMod.cs index 14960196..9d5054fe 100644 --- a/src/SpaceWarp.Core/API/Lua/LuaMod.cs +++ b/src/SpaceWarp.Core/API/Lua/LuaMod.cs @@ -1,15 +1,20 @@ -using System; -using BepInEx.Logging; -using JetBrains.Annotations; +using JetBrains.Annotations; using KSP.Game; using MoonSharp.Interpreter; +using SpaceWarp.API.Logging; namespace SpaceWarp.API.Lua; +/// +/// A Lua mod, this is the base class for all mods that are written in Lua. +/// [MoonSharpUserData] [PublicAPI] public class LuaMod : KerbalMonoBehaviour { + /// + /// The table that contains the mod's functions. + /// public Table ModTable; // TODO: Add more than just this to the behaviour but for now @@ -33,9 +38,15 @@ public class LuaMod : KerbalMonoBehaviour private Closure _reset; #endregion - public ManualLogSource Logger; + /// + /// The logger for this mod. + /// + public ILogger Logger; - // First a pass through to the wrapped table + /// + /// A pass through to the wrapped table + /// + /// The index of the name. public DynValue this[DynValue idx] { get => ModTable.Get(idx); @@ -55,17 +66,17 @@ private void TryCallMethod(Closure closure, params object[] args) } #region Message Handlers - private void TryRegister(string name, out Closure method) + private void TryRegister(string methodName, out Closure method) { - if (ModTable.Get(name) != null && ModTable.Get(name).Type == DataType.Function) + if (ModTable.Get(methodName) != null && ModTable.Get(methodName).Type == DataType.Function) { - method = ModTable.Get(name).Function; + method = ModTable.Get(methodName).Function; return; } method = null; } - public void Awake() + private void Awake() { if (ModTable.Get("Awake") != null && ModTable.Get("Awake").Type == DataType.Function) { @@ -92,7 +103,7 @@ public void Awake() } // Start - public void Start() + private void Start() { if (_start != null) { @@ -102,7 +113,7 @@ public void Start() // Update Functions - public void Update() + private void Update() { if (_update != null) { @@ -110,7 +121,7 @@ public void Update() } } - public void FixedUpdate() + private void FixedUpdate() { if (_fixedUpdate != null) { @@ -118,7 +129,7 @@ public void FixedUpdate() } } - public void LateUpdate() + private void LateUpdate() { if (_lateUpdate != null) { @@ -128,7 +139,7 @@ public void LateUpdate() // Enable/Disable - public void OnEnable() + private void OnEnable() { if (_onEnable != null) { @@ -136,7 +147,7 @@ public void OnEnable() } } - public void OnDisable() + private void OnDisable() { if (_onDisable != null) { @@ -146,7 +157,7 @@ public void OnDisable() // Destruction - public void OnDestroy() + private void OnDestroy() { if (_onDestroy != null) { @@ -155,7 +166,7 @@ public void OnDestroy() } // Reset - public void Reset() + private void Reset() { if (_reset != null) { diff --git a/src/SpaceWarp.Core/API/Lua/SpaceWarpInterop.cs b/src/SpaceWarp.Core/API/Lua/SpaceWarpInterop.cs index 96b762aa..6ae7663b 100644 --- a/src/SpaceWarp.Core/API/Lua/SpaceWarpInterop.cs +++ b/src/SpaceWarp.Core/API/Lua/SpaceWarpInterop.cs @@ -1,16 +1,26 @@ using BepInEx.Bootstrap; using JetBrains.Annotations; using MoonSharp.Interpreter; +using SpaceWarp.API.Logging; using SpaceWarp.InternalUtilities; using UnityEngine; using Logger = BepInEx.Logging.Logger; namespace SpaceWarp.API.Lua; +/// +/// SpaceWarp interop class for Lua API. +/// [SpaceWarpLuaAPI("SpaceWarp")] [PublicAPI] public static class SpaceWarpInterop { + /// + /// Registers a Lua mod. + /// + /// Name of the mod. + /// Table containing the mod's functions. + /// The created instance. public static LuaMod RegisterMod(string name, Table modTable) { var go = new GameObject(name); @@ -18,7 +28,7 @@ public static LuaMod RegisterMod(string name, Table modTable) go.transform.SetParent(Chainloader.ManagerObject.transform); go.SetActive(false); var mod = go.AddComponent(); - mod.Logger = Logger.CreateLogSource(name); + mod.Logger = new BepInExLogger(Logger.CreateLogSource(name)); mod.ModTable = modTable; go.SetActive(true); return mod; diff --git a/src/SpaceWarp.Core/API/Lua/SpaceWarpLuaAPIAttribute.cs b/src/SpaceWarp.Core/API/Lua/SpaceWarpLuaAPIAttribute.cs index 91fc288f..7c346fa3 100644 --- a/src/SpaceWarp.Core/API/Lua/SpaceWarpLuaAPIAttribute.cs +++ b/src/SpaceWarp.Core/API/Lua/SpaceWarpLuaAPIAttribute.cs @@ -1,13 +1,23 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; namespace SpaceWarp.API.Lua; +/// +/// Marks a class as a Lua API class, allowing it to be used in Lua. +/// [AttributeUsage(AttributeTargets.Class)] [MeansImplicitUse] public class SpaceWarpLuaAPIAttribute : Attribute { + /// + /// The name of the class in Lua. + /// public string LuaName; + + /// + /// Marks a class as a Lua API class, allowing it to be used in Lua. + /// + /// public SpaceWarpLuaAPIAttribute(string luaName) { LuaName = luaName; diff --git a/src/SpaceWarp.Core/API/Lua/UI/LuaUITK.cs b/src/SpaceWarp.Core/API/Lua/UI/LuaUITK.cs index 34ae01f6..c8df04ae 100644 --- a/src/SpaceWarp.Core/API/Lua/UI/LuaUITK.cs +++ b/src/SpaceWarp.Core/API/Lua/UI/LuaUITK.cs @@ -1,50 +1,96 @@ using JetBrains.Annotations; using MoonSharp.Interpreter; using SpaceWarp.API.Assets; +using UitkForKsp2.API; using UnityEngine.UIElements; namespace SpaceWarp.API.Lua.UI; +/// +/// Lua API for UITK +/// [SpaceWarpLuaAPI("UI")] [PublicAPI] +// ReSharper disable once InconsistentNaming public static class LuaUITK { #region Creation + /// + /// Creates a new window from a UXML file. + /// + /// Mod to create the window for + /// ID of the window + /// Path to the UXML file + /// Created window public static UIDocument Window(LuaMod mod, string id, string documentPath) { return Window(mod, id, AssetManager.GetAsset(documentPath)); } + /// + /// Creates a new window from a VisualTreeAsset. + /// + /// Mod to create the window for + /// ID of the window + /// VisualTreeAsset to create the window from + /// Created window public static UIDocument Window(LuaMod mod, string id, VisualTreeAsset uxml) { - var parent = mod.transform; - return UitkForKsp2.API.Window.CreateFromUxml(uxml, id, parent, true); + var windowOptions = WindowOptions.Default; + windowOptions.Parent = mod.transform; + windowOptions.WindowId = id; + return UitkForKsp2.API.Window.Create(windowOptions, uxml); } + /// + /// Creates a new window with an empty root element. + /// + /// Mod to create the window for + /// ID of the window + /// Created window public static UIDocument Window(LuaMod mod, string id) { - var parent = mod.transform; - return UitkForKsp2.API.Window.Create(out _, id, parent, true); + var windowOptions = WindowOptions.Default; + windowOptions.Parent = mod.transform; + windowOptions.WindowId = id; + return UitkForKsp2.API.Window.Create(windowOptions); } #region Element Creation + /// + /// Creates a new VisualElement. + /// + /// Created VisualElement public static VisualElement VisualElement() { return new VisualElement(); } + /// + /// Creates a new ScrollView. + /// + /// Created ScrollView public static ScrollView ScrollView() { return new ScrollView(); } + /// + /// Creates a new ListView. + /// + /// Created ListView public static ListView ListView() { return new ListView(); } + /// + /// Creates a new Toggle. + /// + /// Text of the Toggle + /// Created Toggle public static Toggle Toggle(string text = "") { return new Toggle @@ -53,6 +99,11 @@ public static Toggle Toggle(string text = "") }; } + /// + /// Creates a new Label. + /// + /// Text of the Label + /// Created Label public static Label Label(string text = "") { return new Label @@ -61,6 +112,11 @@ public static Label Label(string text = "") }; } + /// + /// Creates a new Button. + /// + /// Text of the Button + /// Created Button public static Button Button(string text = "") { return new Button @@ -69,11 +125,20 @@ public static Button Button(string text = "") }; } + /// + /// Creates a new Scroller. + /// + /// Created Scroller public static Scroller Scroller() { return new Scroller(); } + /// + /// Creates a new TextField. + /// + /// Text of the TextField + /// Created TextField public static TextField TextField(string text = "") { return new TextField @@ -82,11 +147,22 @@ public static TextField TextField(string text = "") }; } + /// + /// Creates a new Foldout. + /// + /// Created Foldout public static Foldout Foldout() { return new Foldout(); } + /// + /// Creates a new Slider. + /// + /// Value of the Slider + /// Minimum value of the Slider + /// Maximum value of the Slider + /// Created Slider public static Slider Slider(float value = 0.0f, float minValue = 0.0f, float maxValue = 1.0f) { return new Slider @@ -97,6 +173,13 @@ public static Slider Slider(float value = 0.0f, float minValue = 0.0f, float max }; } + /// + /// Creates a new SliderInt. + /// + /// Value of the SliderInt + /// Minimum value of the SliderInt + /// Maximum value of the SliderInt + /// public static SliderInt SliderInt(int value = 0, int minValue = 0, int maxValue = 100) { return new SliderInt @@ -107,8 +190,20 @@ public static SliderInt SliderInt(int value = 0, int minValue = 0, int maxValue }; } - public static MinMaxSlider MinMaxSlider(float minValue = 0.0f, float maxValue = 1.0f, float minLimit = 0.0f, - float maxLimit = 1.0f) + /// + /// Creates a new MinMaxSlider. + /// + /// Minimum value of the MinMaxSlider + /// Maximum value of the MinMaxSlider + /// Minimum limit of the MinMaxSlider + /// Maximum limit of the MinMaxSlider + /// + public static MinMaxSlider MinMaxSlider( + float minValue = 0.0f, + float maxValue = 1.0f, + float minLimit = 0.0f, + float maxLimit = 1.0f + ) { return new MinMaxSlider { @@ -125,6 +220,12 @@ public static MinMaxSlider MinMaxSlider(float minValue = 0.0f, float maxValue = #region Callbacks + /// + /// Adds a callback to a button from Lua + /// + /// Button to add the callback to + /// Callback to add + /// Self parameter for the callback public static void AddCallback(Button button, Closure callback, [CanBeNull] DynValue self = null) { if (self != null) @@ -138,13 +239,13 @@ public static void AddCallback(Button button, Closure callback, [CanBeNull] DynV } /// - /// Registers a value changed callback from lua - /// The lua functions parameters should be like function(self?,previous,new) + /// Registers a value changed callback from Lua + /// The Lua functions parameters should be like function(self?,previous,new) /// - /// - /// - /// - /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Type of the value public static void RegisterValueChangedCallback( INotifyValueChanged element, Closure callback, @@ -170,19 +271,30 @@ private static void RegisterGenericCallback( { if (self != null) { - element.RegisterCallback(evt => callback.Call(self, evt), - trickleDown ? TrickleDown.TrickleDown : TrickleDown.NoTrickleDown); + element.RegisterCallback( + evt => callback.Call(self, evt), + trickleDown ? TrickleDown.TrickleDown : TrickleDown.NoTrickleDown + ); } else { - element.RegisterCallback(evt => callback.Call(evt), - trickleDown ? TrickleDown.TrickleDown : TrickleDown.NoTrickleDown); + element.RegisterCallback( + evt => callback.Call(evt), + trickleDown ? TrickleDown.TrickleDown : TrickleDown.NoTrickleDown + ); } } #region Capture Events + /// + /// Registers a mouse capture callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseCaptureCallback( VisualElement element, Closure callback, @@ -190,6 +302,13 @@ public static void RegisterMouseCaptureCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a mouse capture out callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseCaptureOutCallback( VisualElement element, Closure callback, @@ -197,6 +316,13 @@ public static void RegisterMouseCaptureOutCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a pointer capture callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterPointerCaptureCallback( VisualElement element, Closure callback, @@ -204,6 +330,13 @@ public static void RegisterPointerCaptureCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a pointer capture out callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterPointerCaptureOutCallback( VisualElement element, Closure callback, @@ -215,6 +348,13 @@ public static void RegisterPointerCaptureOutCallback( #region Change Events + /// + /// Registers a boolean value change event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterChangeBoolCallback( VisualElement element, Closure callback, @@ -222,6 +362,13 @@ public static void RegisterChangeBoolCallback( bool trickleDown = false ) => RegisterGenericCallback>(element, callback, self, trickleDown); + /// + /// Registers an integer value change event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterChangeIntCallback( VisualElement element, Closure callback, @@ -229,6 +376,13 @@ public static void RegisterChangeIntCallback( bool trickleDown = false ) => RegisterGenericCallback>(element, callback, self, trickleDown); + /// + /// Registers a float value change event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterChangeFloatCallback( VisualElement element, Closure callback, @@ -236,6 +390,13 @@ public static void RegisterChangeFloatCallback( bool trickleDown = false ) => RegisterGenericCallback>(element, callback, self, trickleDown); + /// + /// Registers a string value change event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterChangeStringCallback( VisualElement element, Closure callback, @@ -247,6 +408,13 @@ public static void RegisterChangeStringCallback( #region Click Events + /// + /// Registers a click event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterClickCallback( VisualElement element, Closure callback, @@ -258,6 +426,13 @@ public static void RegisterClickCallback( #region Focus Events + /// + /// Registers a focus out event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterFocusOutCallback( VisualElement element, Closure callback, @@ -265,6 +440,13 @@ public static void RegisterFocusOutCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a focus in event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterFocusInCallback( VisualElement element, Closure callback, @@ -272,6 +454,13 @@ public static void RegisterFocusInCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a blur event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterBlurCallback( VisualElement element, Closure callback, @@ -279,6 +468,13 @@ public static void RegisterBlurCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a focus event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterFocusCallback( VisualElement element, Closure callback, @@ -290,6 +486,13 @@ public static void RegisterFocusCallback( #region Input Events + /// + /// Registers an input event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterInputCallback( VisualElement element, Closure callback, @@ -301,6 +504,13 @@ public static void RegisterInputCallback( #region Layout Events + /// + /// Registers a geometry changed event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterGeometryChangedCallback( VisualElement element, Closure callback, @@ -312,6 +522,13 @@ public static void RegisterGeometryChangedCallback( #region Mouse Events + /// + /// Registers a mouse down event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseDownCallback( VisualElement element, Closure callback, @@ -319,6 +536,14 @@ public static void RegisterMouseDownCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + + /// + /// Registers a mouse up event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseUpCallback( VisualElement element, Closure callback, @@ -326,6 +551,13 @@ public static void RegisterMouseUpCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a mouse move event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseMoveCallback( VisualElement element, Closure callback, @@ -333,6 +565,13 @@ public static void RegisterMouseMoveCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a mouse wheel event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterWheelCallback( VisualElement element, Closure callback, @@ -340,6 +579,13 @@ public static void RegisterWheelCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a mouse enter window event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseEnterWindowCallback( VisualElement element, Closure callback, @@ -347,6 +593,13 @@ public static void RegisterMouseEnterWindowCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a mouse leave window event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseLeaveWindowCallback( VisualElement element, Closure callback, @@ -354,6 +607,13 @@ public static void RegisterMouseLeaveWindowCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a mouse enter event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseEnterCallback( VisualElement element, Closure callback, @@ -361,6 +621,13 @@ public static void RegisterMouseEnterCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a mouse leave event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseLeaveCallback( VisualElement element, Closure callback, @@ -368,6 +635,13 @@ public static void RegisterMouseLeaveCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a mouse over event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseOverCallback( VisualElement element, Closure callback, @@ -375,6 +649,13 @@ public static void RegisterMouseOverCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a mouse out event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterMouseOutCallback( VisualElement element, Closure callback, @@ -386,6 +667,13 @@ public static void RegisterMouseOutCallback( #region Pointer Events + /// + /// Registers a pointer down event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterPointerDownCallback( VisualElement element, Closure callback, @@ -393,6 +681,13 @@ public static void RegisterPointerDownCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a pointer up event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterPointerUpCallback( VisualElement element, Closure callback, @@ -400,6 +695,13 @@ public static void RegisterPointerUpCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a pointer move event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterPointerMoveCallback( VisualElement element, Closure callback, @@ -407,6 +709,13 @@ public static void RegisterPointerMoveCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a pointer enter event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterPointerEnterCallback( VisualElement element, Closure callback, @@ -414,6 +723,13 @@ public static void RegisterPointerEnterCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a pointer leave event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterPointerLeaveCallback( VisualElement element, Closure callback, @@ -421,6 +737,13 @@ public static void RegisterPointerLeaveCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a pointer over event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterPointerOverCallback( VisualElement element, Closure callback, @@ -428,6 +751,13 @@ public static void RegisterPointerOverCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a pointer out event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterPointerOutCallback( VisualElement element, Closure callback, @@ -439,6 +769,13 @@ public static void RegisterPointerOutCallback( #region Panel Events + /// + /// Registers an attach to panel event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterAttachToPanelCallback( VisualElement element, Closure callback, @@ -446,6 +783,13 @@ public static void RegisterAttachToPanelCallback( bool trickleDown = false ) => RegisterGenericCallback(element, callback, self, trickleDown); + /// + /// Registers a detach from panel event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterDetachFromPanelCallback( VisualElement element, Closure callback, @@ -457,6 +801,13 @@ public static void RegisterDetachFromPanelCallback( #region Tooltip Events + /// + /// Registers a tooltip event callback from Lua + /// + /// Element to register the callback for + /// Callback to register + /// Self parameter for the callback + /// Whether the event should trickle down public static void RegisterTooltipCallback( VisualElement element, Closure callback, diff --git a/src/SpaceWarp.Core/API/Mods/BaseKspLoaderSpaceWarpMod.cs b/src/SpaceWarp.Core/API/Mods/BaseKspLoaderSpaceWarpMod.cs index 0127632e..0cf5ecc2 100644 --- a/src/SpaceWarp.Core/API/Mods/BaseKspLoaderSpaceWarpMod.cs +++ b/src/SpaceWarp.Core/API/Mods/BaseKspLoaderSpaceWarpMod.cs @@ -5,31 +5,33 @@ namespace SpaceWarp.API.Mods; +/// +/// Base class for mods that are loaded by the KSP2 internal loader +/// [PublicAPI] public abstract class BaseKspLoaderSpaceWarpMod : Mod, ISpaceWarpMod { + /// public virtual void OnPreInitialized() { - } + /// public virtual void OnInitialized() { } + /// public virtual void OnPostInitialized() { } - /// - /// Gets set automatically, before awake is called - /// + /// public ILogger SWLogger { get; set; } - public IConfigFile SWConfiguration { - get; - internal set; - } + /// + public IConfigFile SWConfiguration { get; internal set; } + /// public SpaceWarpPluginDescriptor SWMetadata { get; set; } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Mods/BaseSpaceWarpPlugin.cs b/src/SpaceWarp.Core/API/Mods/BaseSpaceWarpPlugin.cs index 2f7551f8..6c22d6d4 100644 --- a/src/SpaceWarp.Core/API/Mods/BaseSpaceWarpPlugin.cs +++ b/src/SpaceWarp.Core/API/Mods/BaseSpaceWarpPlugin.cs @@ -1,5 +1,4 @@ using BepInEx; -using BepInEx.Logging; using JetBrains.Annotations; using KSP.Game; using KSP.Messages; @@ -11,61 +10,83 @@ namespace SpaceWarp.API.Mods; /// -/// Represents a KSP2 Mod, you should inherit from this and do your manager processing. +/// Represents a SpaceWarp mod based on BepInEx. /// [PublicAPI] public abstract class BaseSpaceWarpPlugin : BaseUnityPlugin, ISpaceWarpMod { - #region KspBehaviour things + #region KerbalMonoBehaviour properties + /// + /// The current game instance, this is null if the game is not yet initialized or shutting down. + /// protected static GameInstance Game => GameManager.Instance == null ? null : GameManager.Instance.Game; + /// + /// The message center for the current game instance. + /// protected MessageCenter Messages => Game.Messages; - // ReSharper disable Unity.NoNullPropagation - // fine because its null checked by Game properly + /// + /// The current game instance, this is null if the game is not yet initialized or shutting down. + /// + // ReSharper disable Unity.NoNullPropagation - fine because it's null checked by Game properly + // ReSharper disable once InconsistentNaming protected ContextualFxSystem CFXSystem => Game?.GraphicsManager?.ContextualFxSystem; + /// + /// Whether the game is shutting down. + /// protected bool IsGameShuttingDown => Game == null; #endregion + private BepInExLogger _logger; + private BepInExConfigFile _configFile; + + /// + /// The mod info for this mod. + /// + [Obsolete("This will be removed in 2.0.0. Use SWMetadata instead.")] public ModInfo SpaceWarpMetadata { get; internal set; } - internal ManualLogSource ModLogger => Logger; - public string PluginFolderPath { get; internal set; } - public string IdBySpec => GetGuidBySpec(Info, SpaceWarpMetadata); + /// + /// The path to the folder containing the plugin. + /// + [Obsolete("This will be removed in 2.0.0. Use SWMetadata.Folder instead.")] + public string PluginFolderPath { get; internal set; } /// - /// 1st stage initialization - /// This is called before any of the game is actually loaded, it is called as early as possible in the games bootstrap - /// process. + /// The correct ID of the mod based on its spec version. /// + [Obsolete("This will be removed in 2.0.0. Use SWMetadata.Guid instead.")] + public string IdBySpec => GetGuidBySpec(Info, SpaceWarpMetadata); + + /// + public ILogger SWLogger => _logger ??= new BepInExLogger(Logger); + + /// + public IConfigFile SWConfiguration => _configFile ??= new BepInExConfigFile(Config); + + /// + public SpaceWarpPluginDescriptor SWMetadata { get; set; } + + /// public virtual void OnPreInitialized() { } - /// - /// 2nd stage initialization - /// This is called after the game is loaded, and after your mods assets are loaded. - /// + /// public virtual void OnInitialized() { } - /// - /// 3rd stage initialization - /// This is called after all mods have done first stage initialization - /// + /// public virtual void OnPostInitialized() { } - private BepInExLogger _logger; - public ILogger SWLogger => _logger ??= new BepInExLogger(Logger); - private BepInExConfigFile _configFile; - public IConfigFile SWConfiguration => _configFile ??= new BepInExConfigFile(Config); - public SpaceWarpPluginDescriptor SWMetadata { get; set; } + [Obsolete("To be removed in 2.0.0.")] internal static string GetGuidBySpec(PluginInfo pluginInfo, ModInfo modInfo) { return modInfo.Spec >= SpecVersion.V1_2 diff --git a/src/SpaceWarp.Core/API/Mods/GlobalModDefines.cs b/src/SpaceWarp.Core/API/Mods/GlobalModDefines.cs index 4c36ad8e..fc1a8aa5 100644 --- a/src/SpaceWarp.Core/API/Mods/GlobalModDefines.cs +++ b/src/SpaceWarp.Core/API/Mods/GlobalModDefines.cs @@ -1,11 +1,19 @@ -using System.IO; -using JetBrains.Annotations; +using JetBrains.Annotations; namespace SpaceWarp.API.Mods; +/// +/// Global definitions for all SpaceWarp mods. +/// [PublicAPI] public static class GlobalModDefines { + /// + /// Relative path to the folder containing the mod's asset bundles. + /// public static readonly string AssetBundlesFolder = Path.Combine("assets", "bundles"); + /// + /// Relative path to the folder containing the mod's images. + /// public static readonly string ImageAssetsFolder = Path.Combine("assets", "images"); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Mods/ISpaceWarpMod.cs b/src/SpaceWarp.Core/API/Mods/ISpaceWarpMod.cs index c2f9d446..73351897 100644 --- a/src/SpaceWarp.Core/API/Mods/ISpaceWarpMod.cs +++ b/src/SpaceWarp.Core/API/Mods/ISpaceWarpMod.cs @@ -4,18 +4,43 @@ namespace SpaceWarp.API.Mods; +/// +/// Interface for all SpaceWarp mods +/// [PublicAPI] public interface ISpaceWarpMod { + /// + /// 1st stage initialization. + /// This is called before any of the game is actually loaded, it is called as early as possible in the game's + /// bootstrap process. + /// public void OnPreInitialized(); + /// + /// 2nd stage initialization. + /// This is called after the game is loaded, and after your mods assets are loaded. + /// public void OnInitialized(); + /// + /// 3rd stage initialization. + /// This is called after all mods have done 2nd stage initialization. + /// public void OnPostInitialized(); + /// + /// Gets the logger for this mod + /// public ILogger SWLogger { get; } + /// + /// Gets the configuration file for this mod + /// public IConfigFile SWConfiguration { get; } + /// + /// Gets the metadata for this mod + /// public SpaceWarpPluginDescriptor SWMetadata { get; set; } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Mods/JSON/Converters/SpecVersionConverter.cs b/src/SpaceWarp.Core/API/Mods/JSON/Converters/SpecVersionConverter.cs index 0b742864..ac658668 100644 --- a/src/SpaceWarp.Core/API/Mods/JSON/Converters/SpecVersionConverter.cs +++ b/src/SpaceWarp.Core/API/Mods/JSON/Converters/SpecVersionConverter.cs @@ -1,5 +1,4 @@ -using System; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpaceWarp.API.Mods.JSON.Converters; diff --git a/src/SpaceWarp.Core/API/Mods/JSON/DependencyInfo.cs b/src/SpaceWarp.Core/API/Mods/JSON/DependencyInfo.cs index f862fcd1..dd4e5954 100644 --- a/src/SpaceWarp.Core/API/Mods/JSON/DependencyInfo.cs +++ b/src/SpaceWarp.Core/API/Mods/JSON/DependencyInfo.cs @@ -11,7 +11,13 @@ namespace SpaceWarp.API.Mods.JSON; [PublicAPI] public sealed class DependencyInfo { + /// + /// The ID of the dependency. + /// [JsonProperty("id")] public string ID { get; internal set; } + /// + /// The version of the dependency. + /// [JsonProperty("version")] public SupportedVersionsInfo Version { get; internal set; } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Mods/JSON/ModInfo.cs b/src/SpaceWarp.Core/API/Mods/JSON/ModInfo.cs index 9a971929..6be09bda 100644 --- a/src/SpaceWarp.Core/API/Mods/JSON/ModInfo.cs +++ b/src/SpaceWarp.Core/API/Mods/JSON/ModInfo.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; +using JetBrains.Annotations; using Newtonsoft.Json; namespace SpaceWarp.API.Mods.JSON; @@ -12,10 +10,19 @@ namespace SpaceWarp.API.Mods.JSON; [PublicAPI] public sealed class ModInfo { - [JsonProperty("spec", Required = Required.DisallowNull)] public SpecVersion Spec { get; internal set; } = new(); + /// + /// The spec version of the mod info file. + /// + [JsonProperty("spec", Required = Required.DisallowNull)] + public SpecVersion Spec { get; internal set; } = new(); - [JsonProperty("mod_id", Required = Required.DisallowNull)] private string _modID = ""; + [JsonProperty("mod_id", Required = Required.DisallowNull)] + private string _modID = ""; + /// + /// The mod ID of the mod. + /// + /// Thrown when the spec version is 1.2. public string ModID { get @@ -24,31 +31,57 @@ public string ModID { throw new DeprecatedSwinfoPropertyException(nameof(ModID), SpecVersion.V1_2); } + return _modID; } internal set => _modID = value; } - [JsonProperty("name")] private string _name; + + /// + /// The name of the mod. + /// public string Name { get => _name ?? _modID; internal set => _name = value; } + /// + /// The author of the mod. + /// [JsonProperty("author", Required = Required.DisallowNull)] public string Author { get; internal set; } = ""; - [JsonProperty("description", Required = Required.DisallowNull)] public string Description { get; internal set; } = ""; + /// + /// The description of the mod. + /// + [JsonProperty("description", Required = Required.DisallowNull)] + public string Description { get; internal set; } = ""; - [JsonProperty("source", Required = Required.DisallowNull)] public string Source { get; internal set; } = ""; + /// + /// The URL of the source code of the mod. + /// + [JsonProperty("source", Required = Required.DisallowNull)] + public string Source { get; internal set; } = ""; - [JsonProperty("version", Required = Required.Always)] public string Version { get; internal set; } + /// + /// The version of the mod. + /// + [JsonProperty("version", Required = Required.Always)] + public string Version { get; internal set; } - [JsonProperty("dependencies", Required = Required.DisallowNull)] public List Dependencies { get; internal set; } = new(); + /// + /// The dependencies of the mod. + /// + [JsonProperty("dependencies", Required = Required.DisallowNull)] + public List Dependencies { get; internal set; } = new(); + /// + /// The KSP2 versions supported by the mod. + /// [JsonProperty("ksp2_version", Required = Required.DisallowNull)] public SupportedVersionsInfo SupportedKsp2Versions { get; internal set; } = new() { @@ -56,14 +89,29 @@ public string Name Max = "*" }; + /// + /// The URL for the version checking of the mod. + /// [JsonProperty("version_check")] [CanBeNull] public string VersionCheck { get; internal set; } + /// + /// The type of version checking of the mod. + /// [JsonProperty("version_check_type")] [Obsolete("Only swinfo.json version checking will be allowed in 2.0.0.")] public VersionCheckType VersionCheckType { get; internal set; } = VersionCheckType.SwInfo; + /// + /// The conflicts of the mod. + /// [JsonProperty("conflicts", Required = Required.DisallowNull)] public List Conflicts { get; internal set; } = new(); + + /// + /// The filenames of patcher assemblies of the mod. + /// + [JsonProperty("patchers", Required = Required.DisallowNull)] + public List Patchers { get; internal set; } = new(); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Mods/JSON/SpecVersion.cs b/src/SpaceWarp.Core/API/Mods/JSON/SpecVersion.cs index aa4c00dc..1c322806 100644 --- a/src/SpaceWarp.Core/API/Mods/JSON/SpecVersion.cs +++ b/src/SpaceWarp.Core/API/Mods/JSON/SpecVersion.cs @@ -1,5 +1,4 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; using Newtonsoft.Json; using SpaceWarp.API.Mods.JSON.Converters; @@ -15,7 +14,14 @@ public sealed record SpecVersion private const int DefaultMajor = 1; private const int DefaultMinor = 0; + /// + /// Major version number. + /// public int Major { get; } = DefaultMajor; + + /// + /// Minor version number. + /// public int Minor { get; } = DefaultMinor; // ReSharper disable InconsistentNaming @@ -39,11 +45,18 @@ public sealed record SpecVersion public static SpecVersion V1_3 { get; } = new(1, 3); /// - /// Specification version 2.0 (SpaceWarp 1.5.x and 2.0.x) - removes support for version checking from .csproj files, - /// + /// Specification version 2.0 (SpaceWarp 1.5 - 1.7.x) - removes support for version checking from .csproj files, + /// adds support for specifying mod conflicts. Switched to semantic versioning. /// public static SpecVersion V2_0 { get; } = new(2, 0); + /// + /// Specification version 2.1 (SpaceWarp 1.8.x) - requires that mods specify their preload patchers in the + /// swinfo.json file. + /// + public static SpecVersion V2_1 { get; } = new(2, 1); + + // ReSharper restore InconsistentNaming /// @@ -79,14 +92,44 @@ public SpecVersion(string version = null) Minor = minor; } + /// + /// Returns the string representation of the version in the format "major.minor". + /// + /// public override string ToString() => $"{Major}.{Minor}"; + /// + /// Returns true if the first version is less than the second version. + /// + /// First version + /// Second version + /// True if the first version is less than the second version public static bool operator <(SpecVersion a, SpecVersion b) => Compare(a, b) < 0; + + /// + /// Returns true if the first version is greater than the second version. + /// + /// First version + /// Second version + /// True if the first version is greater than the second version public static bool operator >(SpecVersion a, SpecVersion b) => Compare(a, b) > 0; + + /// + /// Returns true if the first version is less than or equal to the second version. + /// + /// First version + /// Second version + /// True if the first version is less than or equal to the second version public static bool operator <=(SpecVersion a, SpecVersion b) => Compare(a, b) <= 0; + + /// + /// Returns true if the first version is greater than or equal to the second version. + /// + /// First version + /// Second version + /// True if the first version is greater than or equal to the second version public static bool operator >=(SpecVersion a, SpecVersion b) => Compare(a, b) >= 0; - private static int Compare(SpecVersion a, SpecVersion b) { if (a.Major != b.Major) @@ -104,6 +147,10 @@ private static int Compare(SpecVersion a, SpecVersion b) [PublicAPI] public sealed class InvalidSpecVersionException : Exception { + /// + /// Creates a new InvalidSpecVersionException. + /// + /// Invalid version string public InvalidSpecVersionException(string version) : base($"Invalid spec version: {version}. The correct format is \"major.minor\".") { @@ -116,8 +163,15 @@ public InvalidSpecVersionException(string version) : [PublicAPI] public sealed class DeprecatedSwinfoPropertyException : Exception { + /// + /// Creates a new DeprecatedSwinfoPropertyException. + /// + /// Deprecated property name + /// Specification version in which the property was deprecated public DeprecatedSwinfoPropertyException(string property, SpecVersion deprecationVersion) : - base($"The swinfo.json property \"{property}\" is deprecated in the spec version {deprecationVersion} and will be removed completely in the future.") + base( + $"The swinfo.json property \"{property}\" is deprecated in the spec version {deprecationVersion} and will be removed completely in the future." + ) { } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Mods/JSON/SupportedVersionsInfo.cs b/src/SpaceWarp.Core/API/Mods/JSON/SupportedVersionsInfo.cs index fb4e3118..faca5784 100644 --- a/src/SpaceWarp.Core/API/Mods/JSON/SupportedVersionsInfo.cs +++ b/src/SpaceWarp.Core/API/Mods/JSON/SupportedVersionsInfo.cs @@ -11,18 +11,40 @@ namespace SpaceWarp.API.Mods.JSON; [PublicAPI] public sealed class SupportedVersionsInfo { + /// + /// The default minimum version. + /// public const string DefaultMin = "0.0.0"; + + /// + /// The default maximum version. + /// public const string DefaultMax = "*"; + /// + /// The minimum supported version of KSP2. + /// [JsonProperty("min")] public string Min { get; internal set; } = DefaultMin; + /// + /// The maximum supported version of KSP2. + /// [JsonProperty("max")] public string Max { get; internal set; } = DefaultMax; + /// + /// Checks if the given version is supported by this mod. + /// + /// The version to check. + /// public bool IsSupported(string toCheck) { return VersionUtility.IsSupported(toCheck, Min, Max); } + /// + /// Returns a string representation of the version range. + /// + /// The string representation of the version range. public override string ToString() { return $"{Min} - {Max}"; diff --git a/src/SpaceWarp.Core/API/Mods/JSON/VersionCheckType.cs b/src/SpaceWarp.Core/API/Mods/JSON/VersionCheckType.cs index bfa1b6db..521287f4 100644 --- a/src/SpaceWarp.Core/API/Mods/JSON/VersionCheckType.cs +++ b/src/SpaceWarp.Core/API/Mods/JSON/VersionCheckType.cs @@ -1,18 +1,26 @@ -using System; -using System.Runtime.Serialization; +using System.Runtime.Serialization; using JetBrains.Annotations; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace SpaceWarp.API.Mods.JSON; +/// +/// The type of version checking to use. +/// [JsonConverter(typeof(StringEnumConverter))] [Obsolete("Only swinfo.json version checking will be allowed in 2.0.0.")] [PublicAPI] public enum VersionCheckType { + /// + /// Use the swinfo.json file to check for updates. + /// [EnumMember(Value = "swinfo")] SwInfo, + /// + /// Use the .csproj file to check for updates. + /// [EnumMember(Value = "csproj")] Csproj } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Mods/PluginList.cs b/src/SpaceWarp.Core/API/Mods/PluginList.cs index 73c7f22d..c8d2e84a 100644 --- a/src/SpaceWarp.Core/API/Mods/PluginList.cs +++ b/src/SpaceWarp.Core/API/Mods/PluginList.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; -using BepInEx; +using BepInEx; using BepInEx.Bootstrap; using JetBrains.Annotations; using SpaceWarp.API.Mods.JSON; using SpaceWarp.API.Versions; -using SpaceWarpPatcher; -using UnityEngine.InputSystem; -using UnityEngine.InputSystem.Switch.LowLevel; +using SpaceWarp.Preload.API; // Disable obsolete warning for Chainloader.Plugins #pragma warning disable CS0618 @@ -26,7 +22,7 @@ public static class PluginList /// Set if the plugin list is different in any way since last run (version differences, new mods, mods removed, /// mods disabled, description differences, any different in any swinfo file and the disabled mod list). /// - public static bool ModListChangedSinceLastRun => ChainloaderPatch.ModListChangedSinceLastRun; + public static bool ModListChangedSinceLastRun => ModList.ChangedSinceLastRun; /// /// Contains information about all currently loaded plugins. The key is the BepInEx GUID of the plugin. @@ -36,8 +32,8 @@ public static class PluginList /// /// Contains information about all currently disabled plugins. The key is the BepInEx GUID of the plugin. /// - public static Dictionary DisabledPluginInfos { get; } = ChainloaderPatch - .DisabledPluginGuids.Zip(ChainloaderPatch.DisabledPlugins, (guid, info) => new { guid, info }) + public static Dictionary DisabledPluginInfos { get; } = ModList.DisabledPluginGuids + .Zip(ModList.DisabledPlugins, (guid, info) => new { guid, info }) .ToDictionary(item => item.guid, item => item.info); /// @@ -75,12 +71,9 @@ public static int CompareVersion(string guid, Version version) /// of the plugin or null if not found public static ModInfo TryGetSwinfo(string guid) { - var swModInfo = AllEnabledAndActivePlugins - .FirstOrDefault(item => item.Guid == guid); - - if (swModInfo != null) + if (TryGetDescriptor(guid) is { SWInfo: var swInfo }) { - return swModInfo.SWInfo; + return swInfo; } var disabledModInfo = AllDisabledPlugins @@ -99,8 +92,7 @@ public static ModInfo TryGetSwinfo(string guid) /// of the plugin or null if not found public static SpaceWarpPluginDescriptor TryGetDescriptor(string guid) { - return AllEnabledAndActivePlugins - .FirstOrDefault(item => item.Guid == guid); + return AllEnabledAndActivePlugins.FirstOrDefault(item => item.Guid == guid); } /// @@ -123,41 +115,53 @@ public static T TryGetPlugin(string guid) where T : BaseUnityPlugin => #region Registering Plugins - private static List _allEnabledAndActivePlugins = new(); + private static List _allEnabledAndActivePlugins = []; + private static List _allDisabledPlugins = []; + private static List _allErroredPlugins = []; /// - /// All plugins that are enabled, and active (not errored) + /// All plugins that are enabled and active (not errored) /// public static IReadOnlyList AllEnabledAndActivePlugins => _allEnabledAndActivePlugins; - private static List _allDisabledPlugins = new(); - /// /// All disabled plugins /// public static IReadOnlyList AllDisabledPlugins => _allDisabledPlugins; - private static List _allErroredPlugins = new(); + /// + /// All errored plugins + /// public static IReadOnlyList AllErroredPlugins => _allErroredPlugins; + /// + /// All plugins, including disabled and errored + /// public static IEnumerable AllPlugins => _allEnabledAndActivePlugins - .Concat(_allDisabledPlugins).Concat(_allErroredPlugins.Select(x => x.Plugin)); + .Concat(_allDisabledPlugins) + .Concat(_allErroredPlugins.Select(x => x.Plugin)); - public static void RegisterPlugin(SpaceWarpPluginDescriptor plugin) + internal static void RegisterPlugin(SpaceWarpPluginDescriptor plugin) { if (AllPlugins.Any(x => x.Guid == plugin.Guid)) { - SpaceWarpPlugin.Logger.LogError($"Attempting to register a mod with a duplicate GUID: {plugin.Guid}"); + SpaceWarpPlugin.Instance.SWLogger.LogError($"Attempting to register a mod with a duplicate GUID: {plugin.Guid}"); } - SpaceWarpPlugin.Logger.LogInfo($"Registered plugin: {plugin.Guid}"); + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Registered plugin: {plugin.Guid}"); _allEnabledAndActivePlugins.Add(plugin); } - public static void Disable(string guid) + internal static void Disable(string guid) { - var descriptor = _allEnabledAndActivePlugins.FirstOrDefault(x => - string.Equals(x.Guid, guid, StringComparison.InvariantCultureIgnoreCase)); + var descriptor = _allEnabledAndActivePlugins.FirstOrDefault( + x => string.Equals( + x.Guid, + guid, + StringComparison.InvariantCultureIgnoreCase + ) + ); + if (descriptor != null) { _allEnabledAndActivePlugins.Remove(descriptor); @@ -165,9 +169,8 @@ public static void Disable(string guid) } } - public static SpaceWarpErrorDescription GetErrorDescriptor(SpaceWarpPluginDescriptor plugin) + internal static SpaceWarpErrorDescription GetErrorDescriptor(SpaceWarpPluginDescriptor plugin) { - if (_allErroredPlugins.Any(x => x.Plugin == plugin)) { return _allErroredPlugins.First(x => x.Plugin == plugin); @@ -183,31 +186,31 @@ public static SpaceWarpErrorDescription GetErrorDescriptor(SpaceWarpPluginDescri return newError; } - public static void NoteMissingSwinfoError(SpaceWarpPluginDescriptor plugin) + internal static void NoteMissingSwinfoError(SpaceWarpPluginDescriptor plugin) { var errorDescriptor = GetErrorDescriptor(plugin); errorDescriptor.MissingSwinfo = true; } - public static void NoteBadDirectoryError(SpaceWarpPluginDescriptor plugin) + internal static void NoteBadDirectoryError(SpaceWarpPluginDescriptor plugin) { var errorDescriptor = GetErrorDescriptor(plugin); errorDescriptor.BadDirectory = true; } - public static void NoteBadIDError(SpaceWarpPluginDescriptor plugin) + internal static void NoteBadIDError(SpaceWarpPluginDescriptor plugin) { var errorDescriptor = GetErrorDescriptor(plugin); errorDescriptor.BadID = true; } - public static void NoteMismatchedVersionError(SpaceWarpPluginDescriptor plugin) + internal static void NoteMismatchedVersionError(SpaceWarpPluginDescriptor plugin) { var errorDescriptor = GetErrorDescriptor(plugin); errorDescriptor.MismatchedVersion = true; } - public static void NoteUnspecifiedDependencyError(SpaceWarpPluginDescriptor plugin, string dependency) + internal static void NoteUnspecifiedDependencyError(SpaceWarpPluginDescriptor plugin, string dependency) { var errorDescriptor = GetErrorDescriptor(plugin); errorDescriptor.UnspecifiedDependencies.Add(dependency); @@ -216,7 +219,7 @@ public static void NoteUnspecifiedDependencyError(SpaceWarpPluginDescriptor plug private static SemanticVersion PadVersion(string version) { var length = version.Split('.').Length; - for (var i = 0; i < 3-length; i++) + for (var i = 0; i < 3 - length; i++) { version += ".0"; } @@ -231,7 +234,7 @@ private static bool IsSupportedSemver(string version, string min, string max) var maxVersion = PadVersion(max.Replace("*", $"{int.MaxValue}")); return basicVersion >= minVersion && basicVersion <= maxVersion; } - + private static bool DependencyResolved( SpaceWarpPluginDescriptor descriptor, List resolvedPlugins @@ -239,10 +242,12 @@ List resolvedPlugins { if (descriptor.SWInfo.Spec < SpecVersion.V1_3) return true; return !(from dependency in descriptor.SWInfo.Dependencies - let info = resolvedPlugins.FirstOrDefault(x => string.Equals( - x.Guid, - dependency.ID, - StringComparison.InvariantCultureIgnoreCase) + let info = resolvedPlugins.FirstOrDefault( + x => string.Equals( + x.Guid, + dependency.ID, + StringComparison.InvariantCultureIgnoreCase + ) ) where info == null || !IsSupportedSemver( info.SWInfo.Version, @@ -271,10 +276,13 @@ private static void GetLoadOrder() for (var i = _allEnabledAndActivePlugins.Count - 1; i >= 0; i--) { var info = _allEnabledAndActivePlugins[i]; - SpaceWarpPlugin.Logger.LogError($"Missing dependency for mod: {info.Name}, this mod will not be loaded"); + SpaceWarpPlugin.Instance.SWLogger.LogError($"Missing dependency for mod: {info.Name}, this mod will not be loaded"); var error = GetErrorDescriptor(info); - error.MissingDependencies = info.SWInfo.Dependencies.Select(x => x.ID).Where(x => - !newOrder.Any(y => string.Equals(x, y.Guid, StringComparison.InvariantCultureIgnoreCase))).ToList(); + error.MissingDependencies = info.SWInfo + .Dependencies + .Select(x => x.ID) + .Where(x => !newOrder.Any(y => string.Equals(x, y.Guid, StringComparison.InvariantCultureIgnoreCase))) + .ToList(); } _allEnabledAndActivePlugins = newOrder; @@ -282,8 +290,9 @@ private static void GetLoadOrder() private static void GetDependencyErrors() { - foreach (var erroredPlugin in _allErroredPlugins.Where(erroredPlugin => - erroredPlugin.MissingDependencies.Count != 0)) + foreach (var erroredPlugin in _allErroredPlugins.Where( + erroredPlugin => erroredPlugin.MissingDependencies.Count != 0 + )) { for (var i = erroredPlugin.MissingDependencies.Count - 1; i >= 0; i--) { @@ -312,19 +321,30 @@ private static void GetDependencyErrors() private static void CheckCompatibility() { - var incompatibilities = _allEnabledAndActivePlugins.Select(x => (Key: x.Guid, Value: new HashSet())) + var incompatibilities = _allEnabledAndActivePlugins + .Select(x => (Key: x.Guid, Value: new HashSet())) .ToDictionary(x => x.Key, x => x.Value); - var versionLookup = _allEnabledAndActivePlugins.Select(x => (Key: x.Guid, Value: x.SWInfo.Version)) + var versionLookup = _allEnabledAndActivePlugins + .Select(x => (Key: x.Guid, Value: x.SWInfo.Version)) .ToDictionary(x => x.Key, x => x.Value); - var pluginDictionary = _allEnabledAndActivePlugins.ToDictionary(x => x.Guid, x => x); + var pluginDictionary = _allEnabledAndActivePlugins + .ToDictionary(x => x.Guid, x => x); foreach (var mod in _allEnabledAndActivePlugins) { var swinfo = mod.SWInfo; - if (swinfo.Spec < SpecVersion.V2_0) continue; + if (swinfo.Spec < SpecVersion.V2_0) + { + continue; + } + foreach (var conflict in swinfo.Conflicts) { if (!versionLookup.TryGetValue(conflict.ID, out var conflictingVersion) || - !IsSupportedSemver(conflictingVersion, conflict.Version.Min, conflict.Version.Max)) continue; + !IsSupportedSemver(conflictingVersion, conflict.Version.Min, conflict.Version.Max)) + { + continue; + } + incompatibilities[mod.Guid].Add(conflict.ID); incompatibilities[conflict.ID].Add(mod.Guid); } @@ -332,7 +352,11 @@ private static void CheckCompatibility() foreach (var incompatibility in incompatibilities) { - if (incompatibility.Value.Count <= 0) continue; + if (incompatibility.Value.Count <= 0) + { + continue; + } + var descriptor = GetErrorDescriptor(pluginDictionary[incompatibility.Key]); descriptor.Incompatibilities.AddRange(incompatibility.Value); } diff --git a/src/SpaceWarp.Core/API/Mods/SpaceWarpErrorDescription.cs b/src/SpaceWarp.Core/API/Mods/SpaceWarpErrorDescription.cs index 22456c09..5670ff80 100644 --- a/src/SpaceWarp.Core/API/Mods/SpaceWarpErrorDescription.cs +++ b/src/SpaceWarp.Core/API/Mods/SpaceWarpErrorDescription.cs @@ -1,27 +1,74 @@ -using System.Collections.Generic; -using BepInEx; +using BepInEx; using JetBrains.Annotations; -using SpaceWarp.Patching; -using UnityEngine; +using SpaceWarp.Patching.Flow; namespace SpaceWarp.API.Mods; +/// +/// This class is used to describe the errors that occur when loading a plugin +/// [PublicAPI] public class SpaceWarpErrorDescription { + /// + /// The plugin that errored + /// public SpaceWarpPluginDescriptor Plugin; + + /// + /// Whether the plugin is missing a swinfo file + /// public bool MissingSwinfo; + + /// + /// Whether the plugin is in the wrong directory + /// public bool BadDirectory; + + /// + /// Whether the plugin has a bad ID + /// public bool BadID; + + /// + /// Whether there's a version mismatch between the swinfo and the plugin + /// public bool MismatchedVersion; + /// + /// List of dependencies that are disabled + /// public List DisabledDependencies = new(); + + /// + /// List of dependencies that errored + /// public List ErroredDependencies = new(); + + /// + /// List of dependencies that are missing + /// public List MissingDependencies = new(); + + /// + /// List of dependencies that are unsupported + /// public List UnsupportedDependencies = new(); + + /// + /// List of dependencies that are unspecified + /// public List UnspecifiedDependencies = new(); + + /// + /// List of incompatibilities + /// public List Incompatibilities = new(); + /// + /// Creates a new error description for a plugin + /// + /// The plugin that errored public SpaceWarpErrorDescription(SpaceWarpPluginDescriptor plugin) { Plugin = plugin; @@ -43,5 +90,4 @@ public SpaceWarpErrorDescription(SpaceWarpPluginDescriptor plugin) } plugin.Plugin = null; } - } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Mods/SpaceWarpPluginDescriptor.cs b/src/SpaceWarp.Core/API/Mods/SpaceWarpPluginDescriptor.cs index fdf7edfb..31e6b2e9 100644 --- a/src/SpaceWarp.Core/API/Mods/SpaceWarpPluginDescriptor.cs +++ b/src/SpaceWarp.Core/API/Mods/SpaceWarpPluginDescriptor.cs @@ -1,13 +1,25 @@ -using System.IO; -using JetBrains.Annotations; +using JetBrains.Annotations; using SpaceWarp.API.Configuration; using SpaceWarp.API.Mods.JSON; namespace SpaceWarp.API.Mods; +/// +/// A descriptor for a SpaceWarp plugin. +/// [PublicAPI] public class SpaceWarpPluginDescriptor { + /// + /// Creates a new plugin descriptor. + /// + /// The plugin instance. + /// The plugin's GUID. + /// The plugin's name. + /// The plugin's swinfo. + /// The plugin's folder. + /// Whether or not to do loading actions. + /// The plugin's config file. public SpaceWarpPluginDescriptor( [CanBeNull] ISpaceWarpMod plugin, string guid, @@ -27,19 +39,53 @@ public SpaceWarpPluginDescriptor( ConfigFile = configFile; } + /// + /// The plugin instance. + /// [CanBeNull] public ISpaceWarpMod Plugin; + + /// + /// The plugin's GUID. + /// public readonly string Guid; + + /// + /// The plugin's name. + /// public readonly string Name; + + /// + /// The plugin's swinfo. + /// public readonly ModInfo SWInfo; + + /// + /// The plugin's folder. + /// public readonly DirectoryInfo Folder; + + /// + /// Whether or not to do loading actions. + /// public bool DoLoadingActions; + + /// + /// The plugin's config file. + /// [CanBeNull] public IConfigFile ConfigFile; - // Set by the version checking system + /// + /// Whether or not the plugin is outdated. Set by the version checking system. + /// public bool Outdated; - public bool Unsupported = false; + /// + /// Whether or not the plugin is unsupported. + /// + public bool Unsupported; - // Used to check for mods that have not been pre-initialized + /// + /// Whether or not the plugin has been pre-initialized yet. + /// public bool LatePreInitialize; } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Parts/Colors.cs b/src/SpaceWarp.Core/API/Parts/Colors.cs index 752bb847..6ef376ae 100644 --- a/src/SpaceWarp.Core/API/Parts/Colors.cs +++ b/src/SpaceWarp.Core/API/Parts/Colors.cs @@ -1,51 +1,52 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; +using JetBrains.Annotations; using SpaceWarp.API.Lua; -using SpaceWarp.Patching; +using SpaceWarp.Patching.Parts; using UnityEngine; namespace SpaceWarp.API.Parts; +/// +/// API for allowing modded parts to be colored. +/// [SpaceWarpLuaAPI("Colors")] [PublicAPI] public static class Colors { /// - /// Key is ModGUID. - /// Value is list of strings containing the partNames. - /// Only parts in this list will be modified. + /// Key is ModGUID. + /// Value is list of strings containing the partNames. + /// Only parts in this list will be modified. /// - [Obsolete("Use the shader \"KSP2/Parts/Paintable\" or \"Parts Replace\" instead")] + [Obsolete("Use the shader \"KSP2/Parts/Paintable\" or \"Parts Replace\" instead. Will be removed in 2.0.0.")] public static Dictionary DeclaredParts => new(); /// - /// Adds to internal parts list under - /// allowing them to have the patch applied. + /// Adds to internal parts list under + /// allowing them to have the patch applied. /// /// guid of the mod that owns the parts. /// - /// Collection of partNames. Names that end in XS, S, M, L or XL will be counted as the same - /// part, - /// Example: partNameS, partNameM, partNameL, partNameXL are all treated as partName + /// Collection of partNames. Names that end in XS, S, M, L or XL will be counted as the same + /// part, + /// Example: partNameS, partNameM, partNameL, partNameXL are all treated as partName /// - [Obsolete("Use the shader \"KSP2/Parts/Paintable\" or \"Parts Replace\" instead")] + [Obsolete("Use the shader \"KSP2/Parts/Paintable\" or \"Parts Replace\" instead. Will be removed in 2.0.0.")] public static void DeclareParts(string modGuid, params string[] partNameList) { ColorsPatch.DeclareParts(modGuid, partNameList); } /// - /// Adds to internal parts list under - /// allowing them to have the patch applied. + /// Adds to internal parts list under + /// allowing them to have the patch applied. /// /// guid of the mod that owns the parts. /// - /// Collection of partNames. Names that end in XS, S, M, L or XL will be counted as the same - /// part. - /// Example: partNameS, partNameM, partNameL, partNameXL are all treated as partName + /// Collection of partNames. Names that end in XS, S, M, L or XL will be counted as the same + /// part. + /// Example: partNameS, partNameM, partNameL, partNameXL are all treated as partName /// - [Obsolete("Use the shader \"KSP2/Parts/Paintable\" or \"Parts Replace\" instead")] + [Obsolete("Use the shader \"KSP2/Parts/Paintable\" or \"Parts Replace\" instead. Will be removed in 2.0.0.")] public static void DeclareParts(string modGuid, IEnumerable partNameList) { ColorsPatch.DeclareParts(modGuid, partNameList); @@ -54,7 +55,7 @@ public static void DeclareParts(string modGuid, IEnumerable partNameList /// Retrieves all the texture list from your part. Textures not set will be null. /// /// Name of the part as described in the .json. - /// - [Obsolete("Use the shader \"KSP2/Parts/Paintable\" or \"Parts Replace\" instead")] + /// Array of textures. + [Obsolete("Use the shader \"KSP2/Parts/Paintable\" or \"Parts Replace\" instead. Will be removed in 2.0.0.")] public static Texture[] GetTextures(string partName) => Array.Empty(); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Parts/PartComponentModuleOverride.cs b/src/SpaceWarp.Core/API/Parts/PartComponentModuleOverride.cs index 5cfb02d6..e32bbaf2 100644 --- a/src/SpaceWarp.Core/API/Parts/PartComponentModuleOverride.cs +++ b/src/SpaceWarp.Core/API/Parts/PartComponentModuleOverride.cs @@ -1,14 +1,14 @@ using JetBrains.Annotations; using KSP.Sim.impl; -using SpaceWarp.API.Logging; namespace SpaceWarp.API.Parts; +/// +/// This class allows you to register your custom PartComponentModule for background resource processing. +/// [PublicAPI] public static class PartComponentModuleOverride { - private static readonly ILogger _LOGGER = new UnityLogSource("SpaceWarp.PartComponentModuleOverride"); - internal static List RegisteredPartComponentOverrides = new(); /// @@ -22,11 +22,14 @@ public static void RegisterModuleForBackgroundResourceProcessing() where T : // Check if this Module is already registered if (RegisteredPartComponentOverrides.Contains(typeof(T))) { - throw new ArgumentException($"Module '{moduleName}' is already registered. Skipping.", nameof(T)); + throw new ArgumentException( + $"Background resource processing for module '{moduleName}' is already registered. Skipping.", + nameof(T) + ); } RegisteredPartComponentOverrides.Add(typeof(T)); - _LOGGER.LogInfo($"Registered '{moduleName}' for background resources processing."); + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Registered '{moduleName}' for background resources processing."); } /// @@ -35,9 +38,12 @@ public static void RegisterModuleForBackgroundResourceProcessing() where T : /// Your Custom Module class that inherits from PartComponentModule public static void UnRegisterModuleForBackgroundResourceProcessing() where T : PartComponentModule { - if (!RegisteredPartComponentOverrides.Contains(typeof(T))) return; + if (!RegisteredPartComponentOverrides.Contains(typeof(T))) + { + return; + } RegisteredPartComponentOverrides.Remove(typeof(T)); - _LOGGER.LogInfo($"Unregistered '{typeof(T).Name}' from background resources processing."); + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Unregistered '{typeof(T).Name}' from background resources processing."); } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/SaveGameManager/ModSaves.cs b/src/SpaceWarp.Core/API/SaveGameManager/ModSaves.cs index 792d0ee1..baae6cbc 100644 --- a/src/SpaceWarp.Core/API/SaveGameManager/ModSaves.cs +++ b/src/SpaceWarp.Core/API/SaveGameManager/ModSaves.cs @@ -1,28 +1,43 @@ using JetBrains.Annotations; using SpaceWarp.Backend.SaveGameManager; -using System; -using System.Collections.Generic; -using SpaceWarp.API.Logging; namespace SpaceWarp.API.SaveGameManager; +/// +/// This class allows you to register your mod data for the game's save file system . +/// [PublicAPI] public static class ModSaves { - private static readonly ILogger Logger = new UnityLogSource("SpaceWarp.ModSaves"); - internal static List InternalPluginSaveData = new(); /// /// Registers your mod data for saving and loading events. /// /// Any object - /// Your mod GUID. Or, technically, any kind of string can be passed here, but what is mandatory is that it's unique compared to what other mods will use. - /// Function that will execute when a SAVE event is triggered. Defaults to null or no callback. - /// Function that will execute when a LOAD event is triggered. Defaults to null or no callback. - /// Your object that will be saved to a save file during a save event and that will be updated when a load event pulls new data. Ensure that a new instance of this object is NOT created after registration. - /// T saveData object you passed as a parameter, or a default instance of object T if you didn't pass anything - public static T RegisterSaveLoadGameData(string modGuid, Action onSave = null, Action onLoad = null, T saveData = default) + /// + /// Your mod GUID. Or, technically, any kind of string can be passed here, but what is mandatory is that it's unique + /// compared to what other mods will use. + /// + /// + /// Function that will execute when a SAVE event is triggered. Defaults to null or no callback. + /// + /// + /// Function that will execute when a LOAD event is triggered. Defaults to null or no callback. + /// + /// + /// Your object that will be saved to a save file during a save event and that will be updated when a load event + /// pulls new data. Ensure that a new instance of this object is NOT created after registration. + /// + /// + /// T saveData object you passed as a parameter, or a default instance of object T if you didn't pass anything + /// + public static T RegisterSaveLoadGameData( + string modGuid, + Action onSave = null, + Action onLoad = null, + T saveData = default + ) where T : class { // Check if this GUID is already registered if (InternalPluginSaveData.Find(p => p.ModGuid == modGuid) != null) @@ -32,10 +47,18 @@ public static T RegisterSaveLoadGameData(string modGuid, Action onSave = n saveData ??= Activator.CreateInstance(); - InternalPluginSaveData.Add(new PluginSaveData { ModGuid = modGuid, SaveEventCallback = SaveCallbackAdapter, LoadEventCallback = LoadCallbackAdapter, SaveData = saveData }); - Logger.LogInfo($"Registered '{modGuid}' for save/load events."); + InternalPluginSaveData.Add(new PluginSaveData + { + ModGuid = modGuid, + SaveEventCallback = SaveCallbackAdapter, + LoadEventCallback = LoadCallbackAdapter, + SaveData = saveData + }); + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Registered '{modGuid}' for save/load events."); return saveData; + // Create adapter functions to convert Action to CallbackFunctionDelegate + void LoadCallbackAdapter(object dataToBeLoaded) { if (onLoad != null && dataToBeLoaded is T data) @@ -44,7 +67,6 @@ void LoadCallbackAdapter(object dataToBeLoaded) } } - // Create adapter functions to convert Action to CallbackFunctionDelegate void SaveCallbackAdapter(object dataToBeSaved) { if (onSave != null && dataToBeSaved is T data) @@ -55,7 +77,8 @@ void SaveCallbackAdapter(object dataToBeSaved) } /// - /// Unregister your previously registered mod data for saving and loading. Use this if you no longer need your data to be saved and loaded. + /// Unregister your previously registered mod data for saving and loading. Use this if you no longer need your data + /// to be saved and loaded. /// /// Your mod GUID you used when registering. public static void UnRegisterSaveLoadGameData(string modGuid) @@ -63,21 +86,39 @@ public static void UnRegisterSaveLoadGameData(string modGuid) var toRemove = InternalPluginSaveData.Find(p => p.ModGuid == modGuid); if (toRemove == null) return; InternalPluginSaveData.Remove(toRemove); - Logger.LogInfo($"Unregistered '{modGuid}' for save/load events."); + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Unregistered '{modGuid}' for save/load events."); } /// /// Unregisters then again registers your mod data for saving and loading events /// - /// Any object - /// Your mod GUID. Or, technically, any kind of string can be passed here, but what is mandatory is that it's unique compared to what other mods will use. - /// Function that will execute when a SAVE event is triggered. Defaults to null or no callback. - /// Function that will execute when a LOAD event is triggered. Defaults to null or no callback. - /// Your object that will be saved to a save file during a save event and that will be updated when a load event pulls new data. Ensure that a new instance of this object is NOT created after registration. - /// T saveData object you passed as a parameter, or a default instance of object T if you didn't pass anything - public static T ReregisterSaveLoadGameData(string modGuid, Action onSave = null, Action onLoad = null, T saveData = default(T)) + /// The type of your save data + /// + /// Your mod GUID. Or, technically, any kind of string can be passed here, but what is mandatory is that it's unique + /// compared to what other mods will use. + /// + /// + /// Function that will execute when a SAVE event is triggered. Defaults to null or no callback. + /// + /// + /// Function that will execute when a LOAD event is triggered. Defaults to null or no callback. + /// + /// + /// Your object that will be saved to a save file during a save event and that will be + /// updated when a load event pulls new data. Ensure that a new instance of this object is NOT created after + /// registration. + /// + /// + /// T saveData object you passed as a parameter, or a default instance of object T if you didn't pass anything + /// + public static T ReregisterSaveLoadGameData( + string modGuid, + Action onSave = null, + Action onLoad = null, + T saveData = default + ) where T : class { UnRegisterSaveLoadGameData(modGuid); return RegisterSaveLoadGameData(modGuid, onSave, onLoad, saveData); } -} +} \ No newline at end of file diff --git a/src/SpaceWarp.Core/API/Versions/SemanticVersion.cs b/src/SpaceWarp.Core/API/Versions/SemanticVersion.cs index ea45be74..bb51a7e9 100644 --- a/src/SpaceWarp.Core/API/Versions/SemanticVersion.cs +++ b/src/SpaceWarp.Core/API/Versions/SemanticVersion.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; + // Disable warnings for missing Equals and GetHashCode implementations #pragma warning disable CS0660, CS0661 diff --git a/src/SpaceWarp.Core/API/Versions/VersionUtility.cs b/src/SpaceWarp.Core/API/Versions/VersionUtility.cs index b6f9b2a3..dfe0e777 100644 --- a/src/SpaceWarp.Core/API/Versions/VersionUtility.cs +++ b/src/SpaceWarp.Core/API/Versions/VersionUtility.cs @@ -1,9 +1,11 @@ -using System; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using JetBrains.Annotations; namespace SpaceWarp.API.Versions; +/// +/// Utility class for comparing semantic versions +/// [PublicAPI] public static class VersionUtility { @@ -29,6 +31,13 @@ public static bool IsOlderThan(string version1, string version2) return CompareSemanticVersionStrings(version1, version2) < 0; } + /// + /// Checks if a semantic version is supported by a range of versions + /// + /// The version to check + /// The minimum version + /// The maximum version + /// public static bool IsSupported(string version, string min, string max) { return !IsOlderThan(version, min) && !IsNewerThan(version, max); @@ -120,7 +129,7 @@ private static int ComparePrereleaseSemanticVersions(string version1, string ver alphaVersionNumber1 = int.Parse(number.Value); alphaVersionName1 = name.Value; } - + if (_prereleaseVersion.IsMatch(alphaVersion2)) { var match = _prereleaseVersion.Match(alphaVersion2); @@ -131,20 +140,21 @@ private static int ComparePrereleaseSemanticVersions(string version1, string ver } var comparison = string.CompareOrdinal(alphaVersionName1, alphaVersionName2); - if (comparison == 0) + if (comparison != 0) { - if (alphaVersionNumber1 > alphaVersionNumber2) - { - return 1; - } else if (alphaVersionNumber1 == alphaVersionNumber2) - { - return 0; - } - else - { - return -1; - } + return comparison; } - return comparison; + + if (alphaVersionNumber1 > alphaVersionNumber2) + { + return 1; + } + + if (alphaVersionNumber1 == alphaVersionNumber2) + { + return 0; + } + + return -1; } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/Backend/Modding/BepInExModAdapter.cs b/src/SpaceWarp.Core/Backend/Modding/BepInExModAdapter.cs index 84f61bda..44117635 100644 --- a/src/SpaceWarp.Core/Backend/Modding/BepInExModAdapter.cs +++ b/src/SpaceWarp.Core/Backend/Modding/BepInExModAdapter.cs @@ -5,14 +5,16 @@ namespace SpaceWarp.Backend.Modding; -public class BepInExModAdapter : ISpaceWarpMod +internal class BepInExModAdapter : ISpaceWarpMod { public readonly BaseUnityPlugin Plugin; + /// public void OnPreInitialized() { } + /// public void OnInitialized() { } diff --git a/src/SpaceWarp.Core/Backend/Modding/Ksp2ModInfo.cs b/src/SpaceWarp.Core/Backend/Modding/Ksp2ModInfo.cs index d8615dd9..25610c2d 100644 --- a/src/SpaceWarp.Core/Backend/Modding/Ksp2ModInfo.cs +++ b/src/SpaceWarp.Core/Backend/Modding/Ksp2ModInfo.cs @@ -1,43 +1,48 @@ -using System; -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace SpaceWarp.Backend.Modding; +/// +/// Represents the KSP2 mod info file used by the internal loader. +/// public class Ksp2ModInfo { + /// + /// The API version of the mod. + /// [JsonConverter(typeof(VersionConverter))] [JsonProperty] public Version APIVersion { get; private set; } - // Token: 0x17001C93 RID: 7315 - // (get) Token: 0x06008070 RID: 32880 RVA: 0x001EE0B9 File Offset: 0x001EC2B9 - // (set) Token: 0x06008071 RID: 32881 RVA: 0x001EE0C1 File Offset: 0x001EC2C1 + /// + /// The version of the mod. + /// [JsonConverter(typeof(VersionConverter))] [JsonProperty] public Version ModVersion { get; private set; } - // Token: 0x17001C94 RID: 7316 - // (get) Token: 0x06008072 RID: 32882 RVA: 0x001EE0CA File Offset: 0x001EC2CA - // (set) Token: 0x06008073 RID: 32883 RVA: 0x001EE0D2 File Offset: 0x001EC2D2 + /// + /// The name of the mod. + /// [JsonProperty] public string ModName { get; private set; } - // Token: 0x17001C95 RID: 7317 - // (get) Token: 0x06008074 RID: 32884 RVA: 0x001EE0DB File Offset: 0x001EC2DB - // (set) Token: 0x06008075 RID: 32885 RVA: 0x001EE0E3 File Offset: 0x001EC2E3 + /// + /// The author of the mod. + /// [JsonProperty] public string ModAuthor { get; private set; } - // Token: 0x17001C96 RID: 7318 - // (get) Token: 0x06008076 RID: 32886 RVA: 0x001EE0EC File Offset: 0x001EC2EC - // (set) Token: 0x06008077 RID: 32887 RVA: 0x001EE0F4 File Offset: 0x001EC2F4 + /// + /// The description of the mod. + /// [JsonProperty] public string ModDescription { get; private set; } - // Token: 0x17001C97 RID: 7319 - // (get) Token: 0x06008078 RID: 32888 RVA: 0x001EE0FD File Offset: 0x001EC2FD - // (set) Token: 0x06008079 RID: 32889 RVA: 0x001EE105 File Offset: 0x001EC305 + /// + /// The addressables catalog file of the mod. + /// [JsonProperty] public string Catalog { get; private set; } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/Backend/Modding/PluginRegister.cs b/src/SpaceWarp.Core/Backend/Modding/PluginRegister.cs index 88d24c1c..1bde7b06 100644 --- a/src/SpaceWarp.Core/Backend/Modding/PluginRegister.cs +++ b/src/SpaceWarp.Core/Backend/Modding/PluginRegister.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; -using BepInEx; +using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using Newtonsoft.Json; @@ -11,7 +7,7 @@ using SpaceWarp.API.Mods; using SpaceWarp.API.Mods.JSON; using SpaceWarp.API.Versions; -using SpaceWarpPatcher; +using SpaceWarp.Preload.API; namespace SpaceWarp.Backend.Modding; @@ -27,7 +23,7 @@ public static void RegisterAllMods() DisableMods(); } - private static ILogger Logger = (BepInExLogger)SpaceWarpPlugin.Logger; + private static readonly ILogger Logger = SpaceWarpPlugin.Instance.SWLogger; private static ModInfo BepInExToSWInfo(PluginInfo plugin) { @@ -55,7 +51,6 @@ private static ModInfo BepInExToSWInfo(PluginInfo plugin) Max = "*" }, VersionCheck = null, - VersionCheckType = VersionCheckType.SwInfo, Conflicts = plugin.Incompatibilities.Select(x => new DependencyInfo { ID = x.IncompatibilityGUID, @@ -74,7 +69,9 @@ private static bool AssertFolderPath(BaseSpaceWarpPlugin plugin, string folderPa if (Path.GetFileName(folderPath) != "plugins") return true; Logger.LogError( - $"Found Space Warp mod {plugin.Info.Metadata.Name} in the BepInEx/plugins directory. This mod will not be initialized."); + $"Found Space Warp mod {plugin.Info.Metadata.Name} in the BepInEx/plugins directory. This mod will " + + $"not be initialized." + ); var descriptor = new SpaceWarpPluginDescriptor( plugin, @@ -86,25 +83,38 @@ private static bool AssertFolderPath(BaseSpaceWarpPlugin plugin, string folderPa new BepInExConfigFile(plugin.Config) ); PluginList.NoteBadDirectoryError(descriptor); + return false; } private static bool AssertModInfoExistence(BaseSpaceWarpPlugin plugin, string modInfoPath, string folderPath) { - if (File.Exists(modInfoPath)) return true; + if (File.Exists(modInfoPath)) + { + return true; + } Logger.LogError( - $"Found Space Warp plugin {plugin.Info.Metadata.Name} without a swinfo.json next to it. This mod will not be initialized."); + $"Found Space Warp plugin {plugin.Info.Metadata.Name} without a swinfo.json in its folder. This mod " + + $"will not be initialized." + ); + PluginList.NoteMissingSwinfoError(new SpaceWarpPluginDescriptor(plugin, plugin.Info.Metadata.GUID, plugin.Info.Metadata.Name, BepInExToSWInfo(plugin.Info), - new DirectoryInfo(folderPath))); + new DirectoryInfo(folderPath)) + ); + return false; } - private static bool TryReadModInfo(BaseUnityPlugin plugin, - string modInfoPath, string folderPath, out ModInfo metadata) + private static bool TryReadModInfo( + BaseUnityPlugin plugin, + string modInfoPath, + string folderPath, + out ModInfo metadata + ) { try { @@ -131,22 +141,19 @@ private static bool TryReadModInfo(BaseUnityPlugin plugin, private static bool AssertSpecificationCompliance( SpaceWarpPluginDescriptor descriptor, BaseUnityPlugin plugin, - ModInfo metadata, - string folderPath + ModInfo metadata ) => metadata.Spec < SpecVersion.V1_3 || AssertSpecVersion13Compliance( descriptor, plugin, - metadata, - folderPath + metadata ); private static bool AssertSpecVersion13Compliance( SpaceWarpPluginDescriptor descriptor, BaseUnityPlugin plugin, - ModInfo metadata, - string folderPath - ) => AssertMatchingModID(descriptor, plugin, metadata, folderPath) && - AssertMatchingVersions(descriptor, plugin, metadata, folderPath) && + ModInfo metadata + ) => AssertMatchingModID(descriptor, plugin, metadata) && + AssertMatchingVersions(descriptor, plugin, metadata) && AssertAllDependenciesAreSpecified(descriptor, plugin, metadata); private static bool AssertAllDependenciesAreSpecified( @@ -165,12 +172,19 @@ private static bool AssertDependencyIsSpecified( ModInfo metadata ) { - if (metadata.Dependencies.Any( - x => string.Equals(x.ID, dep.DependencyGUID, StringComparison.InvariantCultureIgnoreCase)) - ) return true; + if (metadata.Dependencies.Any(x => string.Equals( + x.ID, + dep.DependencyGUID, + StringComparison.InvariantCultureIgnoreCase + ))) + { + return true; + } Logger.LogError( - $"Found Space Warp Plugin {plugin.Info.Metadata.Name} that has an unspecified swinfo dependency found in its BepInDependencies: {dep.DependencyGUID}"); + $"Found Space Warp Plugin {plugin.Info.Metadata.Name} that has an unspecified swinfo dependency found " + + $"in its BepInDependencies: {dep.DependencyGUID}" + ); PluginList.NoteUnspecifiedDependencyError(descriptor, dep.DependencyGUID); metadata.Dependencies.Add(new DependencyInfo { @@ -187,21 +201,22 @@ ModInfo metadata private static string ClearPrerelease(string version) { var semver = new SemanticVersion(version); - return - $"{semver.Major}.{semver.Minor}.{semver.Patch}{(semver.VersionNumbers.Count > 3 ? $".{semver.VersionNumbers[3]}" : "")}"; + return $"{semver.Major}.{semver.Minor}.{semver.Patch}" + + $"{(semver.VersionNumbers.Count > 3 ? $".{semver.VersionNumbers[3]}" : "")}"; } private static bool AssertMatchingVersions( SpaceWarpPluginDescriptor descriptor, BaseUnityPlugin plugin, - ModInfo metadata, - string folderPath + ModInfo metadata ) { if (new Version(ClearPrerelease(metadata.Version)) == plugin.Info.Metadata.Version) return true; Logger.LogError( - $"Found Space Warp plugin {plugin.Info.Metadata.Name} that's swinfo version ({metadata.Version}) does not match the plugin version ({plugin.Info.Metadata.Version}), this mod will not be initialized"); + $"Found Space Warp plugin {plugin.Info.Metadata.Name} that's swinfo version ({metadata.Version}) does " + + $"not match the plugin version ({plugin.Info.Metadata.Version}), this mod will not be initialized" + ); PluginList.NoteMismatchedVersionError(descriptor); return false; } @@ -209,15 +224,16 @@ string folderPath private static bool AssertMatchingModID( SpaceWarpPluginDescriptor descriptor, BaseUnityPlugin plugin, - ModInfo metadata, - string folderPath + ModInfo metadata ) { var modID = metadata.ModID; if (modID == plugin.Info.Metadata.GUID) return true; Logger.LogError( - $"Found Space Warp plugin {plugin.Info.Metadata.Name} that has an swinfo.json w/ spec version >= 1.3 that's ModID is not the same as the plugins GUID, This mod will not be initialized."); + $"Found SpaceWarp plugin {plugin.Info.Metadata.Name} that has a swinfo.json file with spec version >=" + + $" 1.3 whose ModID is not the same as the plugin's GUID. This mod will not be initialized." + ); PluginList.NoteBadIDError(descriptor); return false; } @@ -225,16 +241,34 @@ string folderPath private static void RegisterSingleSpaceWarpPlugin(BaseSpaceWarpPlugin plugin) { var folderPath = Path.GetDirectoryName(plugin.Info.Location); + +#pragma warning disable CS0618 // Type or member is obsolete + // TODO: Remove this in 2.0 plugin.PluginFolderPath = folderPath; - if (!AssertFolderPath(plugin, folderPath)) return; +#pragma warning restore CS0618 // Type or member is obsolete + + if (!AssertFolderPath(plugin, folderPath)) + { + return; + } var modInfoPath = Path.Combine(folderPath!, "swinfo.json"); - if (!AssertModInfoExistence(plugin, modInfoPath, folderPath)) return; + if (!AssertModInfoExistence(plugin, modInfoPath, folderPath)) + { + return; + } - if (!TryReadModInfo(plugin, modInfoPath, folderPath, out var metadata)) return; + if (!TryReadModInfo(plugin, modInfoPath, folderPath, out var metadata)) + { + return; + } +#pragma warning disable CS0618 // Type or member is obsolete + // TODO: Remove this in 2.0 plugin.SpaceWarpMetadata = metadata; +#pragma warning restore CS0618 // Type or member is obsolete + var directoryInfo = new FileInfo(modInfoPath).Directory; var descriptor = new SpaceWarpPluginDescriptor( plugin, @@ -246,7 +280,10 @@ private static void RegisterSingleSpaceWarpPlugin(BaseSpaceWarpPlugin plugin) new BepInExConfigFile(plugin.Config) ); descriptor.Plugin!.SWMetadata = descriptor; - if (!AssertSpecificationCompliance(descriptor, plugin, metadata, folderPath)) return; + if (!AssertSpecificationCompliance(descriptor, plugin, metadata)) + { + return; + } PluginList.RegisterPlugin(descriptor); } @@ -263,7 +300,11 @@ private static void RegisterSingleBepInExPlugin(BaseUnityPlugin plugin) var directoryInfo = new DirectoryInfo(Path.GetDirectoryName(plugin.Info.Location)!); if (File.Exists(modInfoPath)) { - if (!TryReadModInfo(plugin, modInfoPath, folderPath, out var metadata)) return; + if (!TryReadModInfo(plugin, modInfoPath, folderPath, out var metadata)) + { + return; + } + var descriptor = new SpaceWarpPluginDescriptor( new BepInExModAdapter(plugin), metadata.Spec != SpecVersion.V1_2 ? metadata.ModID : plugin.Info.Metadata.GUID, @@ -274,8 +315,11 @@ private static void RegisterSingleBepInExPlugin(BaseUnityPlugin plugin) new BepInExConfigFile(plugin.Config) ); descriptor.Plugin!.SWMetadata = descriptor; - if (!AssertSpecificationCompliance(descriptor, plugin, metadata, folderPath)) + if (!AssertSpecificationCompliance(descriptor, plugin, metadata)) + { return; + } + PluginList.RegisterPlugin(descriptor); } else @@ -297,6 +341,7 @@ private static SpaceWarpPluginDescriptor GetBepInExDescriptor(BaseUnityPlugin pl new BepInExConfigFile(plugin.Config) ); pluginAdapter.SWMetadata = descriptor; + return descriptor; } @@ -346,7 +391,9 @@ private static void RegisterAllCodelessMods() if (swinfoData.Spec < SpecVersion.V1_3) { Logger.LogWarning( - $"Found swinfo information for: {swinfoData.Name}, but its spec is less than v1.3, if this describes a \"codeless\" mod, it will be ignored"); + $"Found swinfo information for: {swinfoData.Name}, but its spec is less than 1.3, if this " + + $"describes a \"codeless\" mod, it will be ignored" + ); continue; } @@ -364,7 +411,10 @@ private static void RegisterAllCodelessMods() if (PluginList.AllPlugins.Any( x => string.Equals(x.Guid, swinfoData.ModID, StringComparison.InvariantCultureIgnoreCase) - )) continue; + )) + { + continue; + } // Now we can just add it to our plugin list PluginList.RegisterPlugin(descriptor); @@ -394,8 +444,7 @@ private static ModInfo KspToSwinfo(Ksp2ModInfo mod) Min = "*", Max = "*" }, - VersionCheck = null, - VersionCheckType = VersionCheckType.SwInfo + VersionCheck = null }; return newInfo; } @@ -416,7 +465,10 @@ private static void RegisterSingleKspMod(DirectoryInfo folder) ); metadata = KspToSwinfo(modinfo); } - else return; + else + { + return; + } // This descriptor *will* be modified later var descriptor = new SpaceWarpPluginDescriptor( @@ -436,9 +488,14 @@ private static void RegisterSingleKspMod(DirectoryInfo folder) private static void RegisterAllKspMods() { var pluginPath = new DirectoryInfo(Path.Combine(Paths.GameRootPath, "GameData", "Mods")); - if (!pluginPath.Exists) return; + if (!pluginPath.Exists) + { + return; + } + Logger.LogInfo($"KSP Loaded mods path: {pluginPath.FullName}"); - // Lets quickly register every KSP loader loaded mod into the load order before anything, with late pre-initialize + // Let's quickly register every mod loaded with the internal loader into the load order before anything else, + // with late pre-initialize foreach (var plugin in pluginPath.EnumerateDirectories()) { Logger.LogInfo($"Attempting to register KSP loaded mod at {pluginPath.FullName}"); @@ -465,7 +522,10 @@ private static void RegisterAllErroredMods() (x.Plugin is BaseUnityPlugin baseUnityPlugin && string.Equals( baseUnityPlugin.Info.Metadata.GUID, info.Metadata.GUID, StringComparison.InvariantCultureIgnoreCase)) - )) continue; + )) + { + continue; + } var descriptor = new SpaceWarpPluginDescriptor( null, @@ -484,7 +544,7 @@ private static void RegisterAllErroredMods() private static void GetDisabledPlugins() { - foreach (var plugin in ChainloaderPatch.DisabledPlugins) + foreach (var plugin in ModList.DisabledPlugins) { GetSingleDisabledPlugin(plugin); } @@ -526,7 +586,7 @@ private static void GetSingleDisabledPlugin(PluginInfo plugin) private static void DisableMods() { - foreach (var mod in ChainloaderPatch.DisabledPluginGuids) + foreach (var mod in ModList.DisabledPluginGuids) { PluginList.Disable(mod); } diff --git a/src/SpaceWarp.Core/Backend/SaveGameManager/PluginSaveData.cs b/src/SpaceWarp.Core/Backend/SaveGameManager/PluginSaveData.cs index 768e5bf3..42796b31 100644 --- a/src/SpaceWarp.Core/Backend/SaveGameManager/PluginSaveData.cs +++ b/src/SpaceWarp.Core/Backend/SaveGameManager/PluginSaveData.cs @@ -1,13 +1,24 @@ -using System; +namespace SpaceWarp.Backend.SaveGameManager; -namespace SpaceWarp.Backend.SaveGameManager; - -internal delegate void SaveGameCallbackFunctionDelegate(object data); +/// +/// The delegate type that will be called when a save or load event is triggered. +/// +public delegate void SaveGameCallbackFunctionDelegate(object data); +/// +/// This class is used to store your mod data for saving and loading. +/// [Serializable] public class PluginSaveData { + /// + /// The GUID of your mod + /// public string ModGuid { get; set; } + + /// + /// The data that will be saved + /// public object SaveData { get; set; } [NonSerialized] diff --git a/src/SpaceWarp.Core/Backend/SaveGameManager/SpaceWarpSerializedSavedGame.cs b/src/SpaceWarp.Core/Backend/SaveGameManager/SpaceWarpSerializedSavedGame.cs index a777997c..5315f775 100644 --- a/src/SpaceWarp.Core/Backend/SaveGameManager/SpaceWarpSerializedSavedGame.cs +++ b/src/SpaceWarp.Core/Backend/SaveGameManager/SpaceWarpSerializedSavedGame.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using UnityEngine.Serialization; - -namespace SpaceWarp.Backend.SaveGameManager; +namespace SpaceWarp.Backend.SaveGameManager; /// /// Extension of game's save/load data class @@ -10,5 +6,9 @@ namespace SpaceWarp.Backend.SaveGameManager; [Serializable] public class SpaceWarpSerializedSavedGame : KSP.Sim.SerializedSavedGame { + /// + /// List of serialized plugin save data + /// + // ReSharper disable once InconsistentNaming public List serializedPluginSaveData = new(); } diff --git a/src/SpaceWarp.Core/InternalUtilities/AssetHelpers.cs b/src/SpaceWarp.Core/InternalUtilities/AssetHelpers.cs index 5eeeaac3..1565e81c 100644 --- a/src/SpaceWarp.Core/InternalUtilities/AssetHelpers.cs +++ b/src/SpaceWarp.Core/InternalUtilities/AssetHelpers.cs @@ -1,4 +1,3 @@ -using System.IO; using I2.Loc; using KSP.Game; using UnityEngine.AddressableAssets; @@ -22,44 +21,42 @@ public static void LoadAddressable(string catalog) SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Loaded addressables catalog {catalog}"); var locator = operation.Result; SpaceWarpPlugin.Instance.SWLogger.LogInfo($"{catalog} ----- {locator.LocatorId}"); - GameManager.Instance.Assets.RegisterResourceLocator(locator); + // GameManager.Instance.Assets.RegisterResourceLocator(locator); } } internal static void LoadLocalizationFromFolder(string folder) { SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Attempting to load localizations from {folder}"); - LanguageSourceData languageSourceData = null; if (!Directory.Exists(folder)) { SpaceWarpPlugin.Instance.SWLogger.LogInfo($"{folder} does not exist, not loading localizations."); return; } + int loadedCount = 0; + var info = new DirectoryInfo(folder); - foreach (var csvFile in info.GetFiles("*.csv")) + foreach (var csvFile in info.GetFiles("*.csv", SearchOption.AllDirectories)) { - languageSourceData ??= new LanguageSourceData(); + var csvSource = new LanguageSourceData(); var csvData = File.ReadAllText(csvFile.FullName).Replace("\r\n", "\n"); - languageSourceData.Import_CSV("", csvData, eSpreadsheetUpdateMode.AddNewTerms); + csvSource.Import_CSV("", csvData, eSpreadsheetUpdateMode.AddNewTerms); + loadedCount++; + LocalizationHelpers.AddSource(csvSource); } - foreach (var i2CsvFile in info.GetFiles("*.i2csv")) + foreach (var i2CsvFile in info.GetFiles("*.i2csv", SearchOption.AllDirectories)) { - languageSourceData ??= new LanguageSourceData(); + var i2CsvSource = new LanguageSourceData(); var i2CsvData = File.ReadAllText(i2CsvFile.FullName).Replace("\r\n", "\n"); - languageSourceData.Import_I2CSV("", i2CsvData, eSpreadsheetUpdateMode.AddNewTerms); + i2CsvSource.Import_I2CSV("", i2CsvData, eSpreadsheetUpdateMode.AddNewTerms); + loadedCount++; + LocalizationHelpers.AddSource(i2CsvSource); } - if (languageSourceData != null) - { - languageSourceData.OnMissingTranslation = LanguageSourceData.MissingTranslationAction.Fallback; - SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Loaded localizations from {folder}"); - LocalizationManager.AddSource(languageSourceData); - } - else - { - SpaceWarpPlugin.Instance.SWLogger.LogInfo($"No localizations found in {folder}"); - } + SpaceWarpPlugin.Instance.SWLogger.LogInfo( + loadedCount > 0 ? $"Loaded localizations from {folder}" : $"No localizations found in {folder}" + ); } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/InternalUtilities/InternalExtensions.cs b/src/SpaceWarp.Core/InternalUtilities/InternalExtensions.cs index 55accc73..e6aeb81d 100644 --- a/src/SpaceWarp.Core/InternalUtilities/InternalExtensions.cs +++ b/src/SpaceWarp.Core/InternalUtilities/InternalExtensions.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System; using UnityEngine; using System.Collections; diff --git a/src/SpaceWarp.Core/InternalUtilities/LocalizationHelpers.cs b/src/SpaceWarp.Core/InternalUtilities/LocalizationHelpers.cs new file mode 100644 index 00000000..db51997b --- /dev/null +++ b/src/SpaceWarp.Core/InternalUtilities/LocalizationHelpers.cs @@ -0,0 +1,29 @@ +using I2.Loc; + +namespace SpaceWarp.InternalUtilities; + +internal static class LocalizationHelpers +{ + public static void AddSource(LanguageSourceData source) + { + if (LocalizationManager.Sources.Contains(source)) + { + return; + } + + source.OnMissingTranslation = LanguageSourceData.MissingTranslationAction.Fallback; + + LocalizationManager.Sources.Insert(0, source); + foreach (var language in source.mLanguages) + { + language.SetLoaded(true); + } + + if (source.mDictionary.Count != 0) + { + return; + } + + source.UpdateDictionary(true); + } +} \ No newline at end of file diff --git a/src/SpaceWarp.Core/InternalUtilities/PathHelpers.cs b/src/SpaceWarp.Core/InternalUtilities/PathHelpers.cs index 49eb5e80..1f69801d 100644 --- a/src/SpaceWarp.Core/InternalUtilities/PathHelpers.cs +++ b/src/SpaceWarp.Core/InternalUtilities/PathHelpers.cs @@ -1,7 +1,4 @@ -using System; -using System.IO; - -namespace SpaceWarp.InternalUtilities; +namespace SpaceWarp.InternalUtilities; internal static class PathHelpers { diff --git a/src/SpaceWarp.Core/Modules/ModuleManager.cs b/src/SpaceWarp.Core/Modules/ModuleManager.cs index 29876ccd..c980f3ba 100644 --- a/src/SpaceWarp.Core/Modules/ModuleManager.cs +++ b/src/SpaceWarp.Core/Modules/ModuleManager.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; +using System.Reflection; using HarmonyLib; using SpaceWarp.API.Configuration; using SpaceWarp.API.Logging; @@ -9,11 +6,20 @@ namespace SpaceWarp.Modules; +/// +/// Manager of SpaceWarp modules. +/// public static class ModuleManager { internal static List AllSpaceWarpModules = new(); private static readonly ILogger ModuleManagerLogSource = new UnityLogSource("SpaceWarp.ModuleManager"); + /// + /// Gets a SpaceWarp module instance by name. + /// + /// Name of the module. + /// The module instance. + /// True if the module was found, false otherwise. public static bool TryGetModule(string name, out SpaceWarpModule module) { module = AllSpaceWarpModules.FirstOrDefault(x => x.Name == name); @@ -43,7 +49,7 @@ internal static void LoadAllModules() AllSpaceWarpModules.Add(mod); } - Harmony.CreateAndPatchAll(assembly); + // Harmony.CreateAndPatchAll(assembly); } catch (Exception e) { diff --git a/src/SpaceWarp.Core/Modules/SpaceWarpModule.cs b/src/SpaceWarp.Core/Modules/SpaceWarpModule.cs index d2f89bd0..9e72094f 100644 --- a/src/SpaceWarp.Core/Modules/SpaceWarpModule.cs +++ b/src/SpaceWarp.Core/Modules/SpaceWarpModule.cs @@ -1,23 +1,50 @@ -using System.Collections.Generic; -using SpaceWarp.API.Configuration; +using SpaceWarp.API.Configuration; using SpaceWarp.API.Logging; namespace SpaceWarp.Modules; +/// +/// Base class for SpaceWarp modules. +/// public abstract class SpaceWarpModule { + /// + /// The logger for the module. + /// public ILogger ModuleLogger; + + /// + /// The configuration file for the module. + /// public IConfigFile ModuleConfiguration; + /// + /// The name of the module. + /// public abstract string Name { get; } - public abstract void LoadModule(); - - public abstract void PreInitializeModule(); - - public abstract void InitializeModule(); - - public abstract void PostInitializeModule(); - + /// + /// Loads the module. Called in plugin's Awake method. + /// + public virtual void LoadModule() {} + + /// + /// 1st stage of module initialization. Called in plugin's OnPreInitialized method. + /// + public virtual void PreInitializeModule() {} + + /// + /// 2nd stage of module initialization. Called in plugin's OnInitialized method. + /// + public virtual void InitializeModule() {} + + /// + /// 3rd stage of module initialization. Called in plugin's OnPostInitialized method. + /// + public virtual void PostInitializeModule() {} + + /// + /// Names of modules that this module depends on. + /// public virtual List Prerequisites => new(); } \ No newline at end of file diff --git a/src/SpaceWarp.Core/Patching/CodeGenerationUtilities.cs b/src/SpaceWarp.Core/Patching/CodeGenerationUtilities.cs index 60fcee96..b67bc18e 100644 --- a/src/SpaceWarp.Core/Patching/CodeGenerationUtilities.cs +++ b/src/SpaceWarp.Core/Patching/CodeGenerationUtilities.cs @@ -6,7 +6,7 @@ namespace SpaceWarp.Patching; internal static class CodeGenerationUtilities { /// - /// Creates a CodeInstruction that pushed an integer to the stack. + /// Creates a CodeInstruction that pushed an integer to the stack. /// /// The integer to push /// An new CodeInstruction to push i diff --git a/src/SpaceWarp.Core/Patching/BootstrapPatch.cs b/src/SpaceWarp.Core/Patching/Flow/BootstrapPatch.cs similarity index 94% rename from src/SpaceWarp.Core/Patching/BootstrapPatch.cs rename to src/SpaceWarp.Core/Patching/Flow/BootstrapPatch.cs index 29a080fa..b10b1c23 100644 --- a/src/SpaceWarp.Core/Patching/BootstrapPatch.cs +++ b/src/SpaceWarp.Core/Patching/Flow/BootstrapPatch.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using HarmonyLib; using KSP.Game; using KSP.Game.Flow; @@ -8,7 +7,7 @@ using SpaceWarp.Backend.Modding; using SpaceWarp.Patching.LoadingActions; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.Flow; [HarmonyPatch] internal static class BootstrapPatch @@ -24,8 +23,8 @@ private static void GetAllMods() PluginList.ResolveDependenciesAndLoadOrder(); } - [HarmonyILManipulator] [HarmonyPatch(typeof(GameManager), nameof(GameManager.StartBootstrap))] + [HarmonyILManipulator] private static void PatchInitializationsIL(ILContext ilContext, ILLabel endLabel) { ILCursor ilCursor = new(ilContext); @@ -109,9 +108,9 @@ private static IList GetAllPlugins() IList allPlugins; if (ForceSpaceWarpLoadDueToError) { - var l = new List { ErroredSWPluginDescriptor }; - l.AddRange(PluginList.AllEnabledAndActivePlugins); - allPlugins = l; + var list = new List { ErroredSWPluginDescriptor }; + list.AddRange(PluginList.AllEnabledAndActivePlugins); + allPlugins = list; } else { @@ -131,7 +130,9 @@ private static void InjectBeforeGameLoadMethods() foreach (var plugin in PluginList.AllEnabledAndActivePlugins) { if (plugin.Plugin != null && !plugin.LatePreInitialize) + { GameManager.Instance.LoadingFlow.AddAction(new PreInitializeModAction(plugin)); + } } } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/Patching/SequentialFlowLoadersPatcher.cs b/src/SpaceWarp.Core/Patching/Flow/SequentialFlowLoadersPatcher.cs similarity index 71% rename from src/SpaceWarp.Core/Patching/SequentialFlowLoadersPatcher.cs rename to src/SpaceWarp.Core/Patching/Flow/SequentialFlowLoadersPatcher.cs index e84a7067..1fdfb79f 100644 --- a/src/SpaceWarp.Core/Patching/SequentialFlowLoadersPatcher.cs +++ b/src/SpaceWarp.Core/Patching/Flow/SequentialFlowLoadersPatcher.cs @@ -1,13 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Reflection; +using System.Reflection; using System.Reflection.Emit; -using BepInEx.Logging; using HarmonyLib; using KSP.Game; using KSP.Game.Flow; +using SpaceWarp.API.Logging; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.Flow; [HarmonyPatch] internal static class SequentialFlowLoadersPatcher @@ -16,28 +14,29 @@ internal static class SequentialFlowLoadersPatcher internal const int FlowMethodPrivateloadcommon = 1; internal const int FlowMethodPrivatesavecommon = 2; - private static SequentialFlowAdditions[] _sequentialFlowAdditions = + private static readonly SequentialFlowAdditions[] SequentialFlowAdditionMethods = { - new(typeof(GameManager).GetMethod("StartGame")), // Must be index FLOW_METHOD_STARTGAME - new(AccessTools.Method( - "KSP.Game.SaveLoadManager:PrivateLoadCommon")), // Must be index FLOW_METHOD_PRIVATELOADCOMMON - new(AccessTools.Method( - "KSP.Game.SaveLoadManager:PrivateSaveCommon")), // Must be index FLOW_METHOD_PRIVATESAVECOMMON + // Must be index FlowMethodStartgame + new(typeof(GameManager).GetMethod("StartGame")), + // Must be index FlowMethodPrivateloadcommon + new(AccessTools.Method("KSP.Game.SaveLoadManager:PrivateLoadCommon")), + // Must be index FlowMethodPrivatesavecommon + new(AccessTools.Method("KSP.Game.SaveLoadManager:PrivateSaveCommon")) }; internal static void AddConstructor(string after, Type flowAction, int methodIndex) { - _sequentialFlowAdditions[methodIndex].AddConstructor(after, flowAction); + SequentialFlowAdditionMethods[methodIndex].AddConstructor(after, flowAction); } internal static void AddFlowAction(string after, FlowAction flowAction, int methodIndex) { - _sequentialFlowAdditions[methodIndex].AddAction(after, flowAction); + SequentialFlowAdditionMethods[methodIndex].AddAction(after, flowAction); } public static SequentialFlow Apply(SequentialFlow flow, object[] methodArguments, int methodIndex) { - _sequentialFlowAdditions[methodIndex].ApplyTo(flow, methodArguments); + SequentialFlowAdditionMethods[methodIndex].ApplyTo(flow, methodArguments); return flow; } @@ -57,8 +56,9 @@ int methodIndex // Get list of relevant arguments to pass to FlowAction constructors. // `parameterCount` has a `+ 1` because `GetParameters()` doesn't include the instance parameter (this). - var parameters = _sequentialFlowAdditions[methodIndex].method.GetParameters() - .Where(parameter => !parameter.ParameterType.IsValueType).ToArray(); + var parameters = SequentialFlowAdditionMethods[methodIndex].Method.GetParameters() + .Where(parameter => !parameter.ParameterType.IsValueType) + .ToArray(); var parameterCount = parameters.Length + 1; // Creation of argument `methodArguments` to `Apply()`: @@ -99,19 +99,18 @@ int methodIndex } } - [HarmonyPatch(typeof(GameManager))] - [HarmonyPatch("StartGame")] + [HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))] [HarmonyPrefix] + // ReSharper disable once InconsistentNaming public static void PrefixGameManagerStartGame(GameManager __instance) { - _sequentialFlowAdditions[FlowMethodStartgame].ApplyTo( + SequentialFlowAdditionMethods[FlowMethodStartgame].ApplyTo( __instance.LoadingFlow, new object[] { __instance } ); } - [HarmonyPatch(typeof(SaveLoadManager))] - [HarmonyPatch("PrivateLoadCommon")] + [HarmonyPatch(typeof(SaveLoadManager), nameof(SaveLoadManager.PrivateLoadCommon))] [HarmonyTranspiler] public static IEnumerable TranspileSaveLoadManagerPrivateLoadCommon( IEnumerable instructions) @@ -119,8 +118,7 @@ public static IEnumerable TranspileSaveLoadManagerPrivateLoadCo return TranspileSequentialFlowBuilderMethod(instructions, FlowMethodPrivateloadcommon); } - [HarmonyPatch(typeof(SaveLoadManager))] - [HarmonyPatch("PrivateSaveCommon")] + [HarmonyPatch(typeof(SaveLoadManager), nameof(SaveLoadManager.PrivateSaveCommon))] [HarmonyTranspiler] public static IEnumerable TranspileSaveLoadManagerPrivateSaveCommon( IEnumerable instructions) @@ -130,29 +128,35 @@ public static IEnumerable TranspileSaveLoadManagerPrivateSaveCo private class SequentialFlowAdditions { - private readonly HashSet availableTypes; - private readonly List> insertAfter = new(); - internal readonly MethodInfo method; + private readonly HashSet _availableTypes; + private readonly List> _insertAfter = new(); + + internal readonly MethodInfo Method; internal SequentialFlowAdditions(MethodInfo method) { - availableTypes = - new HashSet(method.GetParameters().Select(parameter => parameter.ParameterType) - .Where(type => !type.IsValueType)) { method.DeclaringType }; - this.method = method; + _availableTypes = + [ + ..method.GetParameters() + .Select(parameter => parameter.ParameterType) + .Where(type => !type.IsValueType), + method.DeclaringType + ]; + Method = method; } internal void AddConstructor(string after, Type flowAction) { // Determine the correct constructor to use. var constructor = flowAction.GetConstructors() - .OrderByDescending(constructor => constructor.GetParameters().Length).Where(constructor => + .OrderByDescending(constructor => constructor.GetParameters().Length) + .Where(constructor => { HashSet seen = new(); foreach (var parameter in constructor.GetParameters()) { - if (!availableTypes.Contains(parameter.ParameterType)) + if (!_availableTypes.Contains(parameter.ParameterType)) return false; if (!seen.Add(parameter.GetType())) @@ -160,15 +164,18 @@ internal void AddConstructor(string after, Type flowAction) } return true; - }).FirstOrDefault() ?? throw new InvalidOperationException( - $"Flow action type {flowAction.Name} does not have a public constructor that has parameters compatible with {method.DeclaringType.Name}.{method.Name}"); + }) + .FirstOrDefault() ?? throw new InvalidOperationException( + $"Flow action type {flowAction.Name} does not have a public constructor that has " + + $"parameters compatible with {Method.DeclaringType!.Name}.{Method.Name}" + ); - insertAfter.Add(new KeyValuePair(after, constructor)); + _insertAfter.Add(new KeyValuePair(after, constructor)); } internal void AddAction(string after, FlowAction action) { - insertAfter.Add(new KeyValuePair(after, action)); + _insertAfter.Add(new KeyValuePair(after, action)); } private static FlowAction Construct(ConstructorInfo constructor, object[] methodArguments) @@ -201,11 +208,11 @@ private void AddActionsAfter(string name, List actions, bool[] added if (added[i]) continue; - if (insertAfter[i].Key != name) continue; + if (_insertAfter[i].Key != name) continue; added[i] = true; - var action = insertAfter[i].Value switch + var action = _insertAfter[i].Value switch { ConstructorInfo constructor => Construct(constructor, methodArguments), FlowAction flowAction => flowAction, @@ -216,7 +223,7 @@ private void AddActionsAfter(string name, List actions, bool[] added // There could be actions set to run after the newly inserted action, // so this needs to be called again. - AddActionsAfter(action.Name, actions, added, methodArguments); + AddActionsAfter(action!.Name, actions, added, methodArguments); } } @@ -242,7 +249,7 @@ internal void ApplyTo(SequentialFlow flow, object[] methodArguments) // Has each action been added already? // Used to prevent duplicates, and warn about unused actions. - var added = new bool[insertAfter.Count()]; + var added = new bool[_insertAfter.Count()]; // `null` is sued to signify the start of the action list. AddActionsAfter(null, actions, added, methodArguments); @@ -261,20 +268,27 @@ internal void ApplyTo(SequentialFlow flow, object[] methodArguments) // Warn about any actions that were not used. for (int i = 0; i < added.Length; i++) { - if (added[i]) continue; + if (added[i]) + { + continue; + } - if (insertAfter[i].Value is ConstructorInfo constructor) + if (_insertAfter[i].Value is ConstructorInfo constructor) { var actionType = constructor.DeclaringType; - var logger = Logger.CreateLogSource($"{actionType.Assembly.GetName().Name}/{actionType.Name}"); + var logger = BaseLogger.CreateDefault($"{actionType!.Assembly.GetName().Name}/{actionType.Name}"); logger.LogWarning( - $"Flow action {actionType.Name} was set to be inserted after \"{insertAfter[i].Key}\" in {method.Name}, however that action does not exist in that flow"); + $"Flow action {actionType.Name} was set to be inserted after \"{_insertAfter[i].Key}\" " + + $"in {Method.Name}, however that action does not exist in that flow" + ); } - else if (insertAfter[i].Value is FlowAction action) + else if (_insertAfter[i].Value is FlowAction action) { - var logger = Logger.CreateLogSource("SequentialFlow"); + var logger = BaseLogger.CreateDefault("SequentialFlow"); logger.LogWarning( - $"Flow action \"{action.Name}\" was set to be inserted after \"{insertAfter[i].Key}\" in {method.Name}, however that action does not exist in that flow"); + $"Flow action \"{action.Name}\" was set to be inserted after \"{_insertAfter[i].Key}\" " + + $"in {Method.Name}, however that action does not exist in that flow" + ); } } } diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/AddressableAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/AddressableAction.cs index cfb2dbce..6f1b6cfc 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/AddressableAction.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/AddressableAction.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; +using JetBrains.Annotations; using KSP.Game; using KSP.Game.Flow; using UnityEngine; @@ -8,17 +6,29 @@ namespace SpaceWarp.Patching.LoadingActions; +// TODO: Move this to SpaceWarp.API.Loading in 2.0.0 + +/// +/// A loading action that loads addressable assets by label. +/// +/// The type of assets to load. [Obsolete("This will be moved to SpaceWarp.API.Loading in 2.0.0")] [PublicAPI] public class AddressableAction : FlowAction where T : UnityObject { - private string Label; - private Action Action; + private string _label; + private Action _action; + /// + /// Creates a new addressable loading action. + /// + /// Name of the action. + /// Label of the asset to load. + /// Action to perform on the loaded asset. public AddressableAction(string name, string label, Action action) : base(name) { - Label = label; - Action = action; + _label = label; + _action = action; } private bool DoesLabelExist(object label) @@ -27,18 +37,23 @@ private bool DoesLabelExist(object label) || Addressables.ResourceLocators.Any(locator => locator.Keys.Contains(label)); } + /// + /// Performs the loading action. + /// + /// Callback to call when the action is resolved. + /// Callback to call when the action is rejected. public override void DoAction(Action resolve, Action reject) { - if (!DoesLabelExist(Label)) + if (!DoesLabelExist(_label)) { - Debug.Log($"[Space Warp] Skipping loading addressables for {Label} which does not exist."); + Debug.Log($"[Space Warp] Skipping loading addressables for {_label} which does not exist."); resolve(); return; } try { - GameManager.Instance.Assets.LoadByLabel(Label,Action,delegate(IList assetLocations) + GameManager.Instance.Assets.LoadByLabel(_label,_action,delegate(IList assetLocations) { if (assetLocations != null) { diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/DescriptorLoadingAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/DescriptorLoadingAction.cs index b1ab21d0..53ffb54d 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/DescriptorLoadingAction.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/DescriptorLoadingAction.cs @@ -1,10 +1,14 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; using KSP.Game.Flow; using SpaceWarp.API.Mods; namespace SpaceWarp.Patching.LoadingActions; +// TODO: Move this to SpaceWarp.API.Loading in 2.0.0 + +/// +/// A general loading action for a mod descriptor. +/// [Obsolete("This will be moved to SpaceWarp.API.Loading in 2.0.0")] [PublicAPI] public class DescriptorLoadingAction : FlowAction @@ -12,6 +16,12 @@ public class DescriptorLoadingAction : FlowAction private readonly Action _action; private readonly SpaceWarpPluginDescriptor _plugin; + /// + /// Creates a new descriptor loading action. + /// + /// Name of the loading action. + /// Callback to perform the loading action. + /// The plugin descriptor to create the action for. public DescriptorLoadingAction( string actionName, Action action, @@ -22,21 +32,32 @@ SpaceWarpPluginDescriptor plugin _plugin = plugin; } + /// + /// Performs the loading action. + /// + /// Callback to call when the action is resolved. + /// Callback to call when the action is rejected. public override void DoAction(Action resolve, Action reject) { try { if (_plugin.DoLoadingActions) + { _action(_plugin); + } resolve(); } catch (Exception e) { if (_plugin.Plugin != null) + { _plugin.Plugin.SWLogger.LogError(e.ToString()); + } else - SpaceWarpPlugin.Logger.LogError(_plugin.SWInfo.Name + ": " + e); + { + SpaceWarpPlugin.Instance.SWLogger.LogError(_plugin.SWInfo.Name + ": " + e); + } reject(null); } diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/FunctionalLoadingActions.cs b/src/SpaceWarp.Core/Patching/LoadingActions/FunctionalLoadingActions.cs index 59e68969..4e9cec47 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/FunctionalLoadingActions.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/FunctionalLoadingActions.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using UnityEngine; +using UnityEngine; namespace SpaceWarp.Patching.LoadingActions; @@ -15,8 +12,7 @@ string filename var assetBundle = AssetBundle.LoadFromFile(filename); if (assetBundle == null) { - throw new Exception( - $"Failed to load AssetBundle {internalPath} ({filename})"); + throw new Exception($"Failed to load AssetBundle {internalPath} ({filename})"); } internalPath = internalPath.Replace(".bundle", ""); diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/InitializeModAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/InitializeModAction.cs index 04ad68eb..8c49c2d2 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/InitializeModAction.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/InitializeModAction.cs @@ -1,4 +1,3 @@ -using System; using KSP.Game.Flow; using SpaceWarp.API.Mods; @@ -8,8 +7,7 @@ internal sealed class InitializeModAction : FlowAction { private readonly SpaceWarpPluginDescriptor _plugin; - public InitializeModAction(SpaceWarpPluginDescriptor plugin) : base( - $"Initialization for plugin {plugin.Name}") + public InitializeModAction(SpaceWarpPluginDescriptor plugin) : base($"Initialization for plugin {plugin.Name}") { _plugin = plugin; } @@ -19,7 +17,10 @@ public override void DoAction(Action resolve, Action reject) try { if (_plugin.DoLoadingActions) + { _plugin.Plugin.OnInitialized(); + } + resolve(); } catch (Exception e) diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/LoadAddressablesAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/LoadAddressablesAction.cs index 3e7376b3..956e9f71 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/LoadAddressablesAction.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/LoadAddressablesAction.cs @@ -1,7 +1,5 @@ -using System; -using System.IO; -using BepInEx.Logging; -using KSP.Game.Flow; +using KSP.Game.Flow; +using SpaceWarp.API.Logging; using SpaceWarp.API.Mods; using SpaceWarp.InternalUtilities; @@ -9,7 +7,7 @@ namespace SpaceWarp.Patching.LoadingActions; internal sealed class LoadAddressablesAction : FlowAction { - private static readonly ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("Addressables Loader"); + private static readonly ILogger Logger = BaseLogger.CreateDefault("Addressables Loader"); private readonly SpaceWarpPluginDescriptor _plugin; public LoadAddressablesAction(SpaceWarpPluginDescriptor plugin) : base( @@ -40,9 +38,14 @@ public override void DoAction(Action resolve, Action reject) catch (Exception e) { if (_plugin.Plugin != null) + { _plugin.Plugin.SWLogger.LogError(e.ToString()); + } else - SpaceWarpPlugin.Logger.LogError(_plugin.SWInfo.Name + ": " + e); + { + SpaceWarpPlugin.Instance.SWLogger.LogError(_plugin.SWInfo.Name + ": " + e); + } + reject(null); } } diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/LoadLocalizationAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/LoadLocalizationAction.cs index 69646912..9ba4aac1 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/LoadLocalizationAction.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/LoadLocalizationAction.cs @@ -1,6 +1,4 @@ -using System; -using System.IO; -using KSP.Game.Flow; +using KSP.Game.Flow; using SpaceWarp.API.Mods; using SpaceWarp.InternalUtilities; @@ -27,9 +25,14 @@ public override void DoAction(Action resolve, Action reject) catch (Exception e) { if (_plugin.Plugin != null) + { _plugin.Plugin.SWLogger.LogError(e.ToString()); + } else - SpaceWarpPlugin.Logger.LogError(_plugin.SWInfo.Name + ": " + e); + { + SpaceWarpPlugin.Instance.SWLogger.LogError(_plugin.SWInfo.Name + ": " + e); + } + reject(null); } } diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/LoadLuaAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/LoadLuaAction.cs index 0403bc07..5128baac 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/LoadLuaAction.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/LoadLuaAction.cs @@ -1,6 +1,4 @@ -using System; -using System.IO; -using KSP.Game.Flow; +using KSP.Game.Flow; using SpaceWarp.API.Mods; namespace SpaceWarp.Patching.LoadingActions; @@ -32,9 +30,13 @@ public override void DoAction(Action resolve, Action reject) catch (Exception e) { if (_plugin.Plugin != null) + { _plugin.Plugin.SWLogger.LogError(e.ToString()); + } else - SpaceWarpPlugin.Logger.LogError(_plugin.SWInfo.Name + ": " + e); + { + SpaceWarpPlugin.Instance.SWLogger.LogError(_plugin.SWInfo.Name + ": " + e); + } } } @@ -43,9 +45,14 @@ public override void DoAction(Action resolve, Action reject) catch (Exception e) { if (_plugin.Plugin != null) + { _plugin.Plugin.SWLogger.LogError(e.ToString()); + } else - SpaceWarpPlugin.Logger.LogError(_plugin.SWInfo.Name + ": " + e); + { + SpaceWarpPlugin.Instance.SWLogger.LogError(_plugin.SWInfo.Name + ": " + e); + } + reject(null); } } diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/LoadingAddressablesLocalizationsAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/LoadingAddressablesLocalizationsAction.cs deleted file mode 100644 index dc0e075b..00000000 --- a/src/SpaceWarp.Core/Patching/LoadingActions/LoadingAddressablesLocalizationsAction.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using I2.Loc; -using KSP.Game; -using KSP.Game.Flow; -using UnityEngine; -using UnityEngine.AddressableAssets; - -namespace SpaceWarp.Patching.LoadingActions; - -internal sealed class LoadAddressablesLocalizationsAction : FlowAction -{ - public LoadAddressablesLocalizationsAction() : base("Loading localizations from Addressables") - { - } - - public override void DoAction(Action resolve, Action reject) - { - try - { - GameManager.Instance.Assets.LoadByLabel( - "language_source", - OnLanguageSourceAssetLoaded, - delegate(IList languageAssetLocations) - { - if (languageAssetLocations != null) - { - Addressables.Release(languageAssetLocations); - } - - resolve(); - } - ); - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - reject(null); - } - } - - private static void OnLanguageSourceAssetLoaded(LanguageSourceAsset asset) - { - if (!asset || LocalizationManager.Sources.Contains(asset.mSource)) - { - return; - } - - asset.mSource.owner = asset; - LocalizationManager.AddSource(asset.mSource); - } -} \ No newline at end of file diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/ModLoadingAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/ModLoadingAction.cs index e595db71..f54c7c69 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/ModLoadingAction.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/ModLoadingAction.cs @@ -1,38 +1,52 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; using KSP.Game.Flow; using SpaceWarp.API.Mods; namespace SpaceWarp.Patching.LoadingActions; +// TODO: Move this to SpaceWarp.API.Loading in 2.0.0 + +/// +/// A general loading action for a SpaceWarp mod plugin. +/// [Obsolete("This will be moved to SpaceWarp.API.Loading in 2.0.0")] [PublicAPI] public class ModLoadingAction : FlowAction { - private Action Action; - private BaseSpaceWarpPlugin Plugin; - + private Action _action; + private BaseSpaceWarpPlugin _plugin; + /// + /// Creates a new mod plugin loading action. + /// + /// Name of the loading action. + /// Callback to perform the loading action. + /// The mod plugin to create the action for. public ModLoadingAction( string actionName, Action action, BaseSpaceWarpPlugin plugin ) : base($"{plugin.SpaceWarpMetadata.Name}:{actionName}") { - Action = action; - Plugin = plugin; + _action = action; + _plugin = plugin; } + /// + /// Performs the loading action. + /// + /// Callback to call when the action is resolved. + /// Callback to call when the action is rejected. public override void DoAction(Action resolve, Action reject) { try { - Action(Plugin); + _action(_plugin); resolve(); } catch (Exception e) { - Plugin.ModLogger.LogError(e.ToString()); + _plugin.SWLogger.LogError(e.ToString()); reject(null); } } diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/PostInitializeModAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/PostInitializeModAction.cs index e8c5894d..80831b50 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/PostInitializeModAction.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/PostInitializeModAction.cs @@ -1,5 +1,4 @@ -using System; -using KSP.Game.Flow; +using KSP.Game.Flow; using SpaceWarp.API.Mods; namespace SpaceWarp.Patching.LoadingActions; @@ -19,7 +18,10 @@ public override void DoAction(Action resolve, Action reject) try { if (_plugin.DoLoadingActions) - _plugin.Plugin.OnPostInitialized(); + { + _plugin.Plugin!.OnPostInitialized(); + } + resolve(); } catch (Exception e) diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/PreInitializeModAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/PreInitializeModAction.cs index a8aac19c..8dea48e8 100644 --- a/src/SpaceWarp.Core/Patching/LoadingActions/PreInitializeModAction.cs +++ b/src/SpaceWarp.Core/Patching/LoadingActions/PreInitializeModAction.cs @@ -1,4 +1,3 @@ -using System; using KSP.Game.Flow; using SpaceWarp.API.Mods; @@ -16,18 +15,19 @@ public PreInitializeModAction(SpaceWarpPluginDescriptor plugin) public override void DoAction(Action resolve, Action reject) { - SpaceWarpPlugin.Logger.LogInfo($"Pre-initializing: {_plugin.Name}?"); + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Pre-initializing: {_plugin.Name}?"); try { if (_plugin.DoLoadingActions) { - SpaceWarpPlugin.Logger.LogInfo($"YES! {_plugin.Plugin}"); + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"YES! {_plugin.Plugin}"); _plugin.Plugin.OnPreInitialized(); } else { - SpaceWarpPlugin.Logger.LogInfo("NO!!"); + SpaceWarpPlugin.Instance.SWLogger.LogInfo("NO!!"); } + resolve(); } catch (Exception e) diff --git a/src/SpaceWarp.Core/Patching/LoadingActions/ResolvingPatchOrderAction.cs b/src/SpaceWarp.Core/Patching/LoadingActions/ResolvingPatchOrderAction.cs deleted file mode 100644 index 76926cd3..00000000 --- a/src/SpaceWarp.Core/Patching/LoadingActions/ResolvingPatchOrderAction.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using KSP.Game.Flow; - -namespace SpaceWarp.Patching.LoadingActions; - -internal class ResolvingPatchOrderAction : FlowAction -{ - public ResolvingPatchOrderAction(string name) : base(name) - { - } - - public override void DoAction(Action resolve, Action reject) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/src/SpaceWarp.Core/Patching/Localization/LocalizationPatch.cs b/src/SpaceWarp.Core/Patching/Localization/LocalizationPatch.cs new file mode 100644 index 00000000..37330d9e --- /dev/null +++ b/src/SpaceWarp.Core/Patching/Localization/LocalizationPatch.cs @@ -0,0 +1,250 @@ +using HarmonyLib; +using I2.Loc; +using UnityEngine; + +namespace SpaceWarp.Patching.Localization; + +/// +/// Patches the localization system to properly find fallback translations. +/// +[HarmonyPatch] +internal static class LocalizationPatch +{ + [HarmonyPatch( + typeof(LocalizationManager), + nameof(LocalizationManager.TryGetTranslation), + [ + typeof(string), typeof(string), typeof(bool), typeof(int), typeof(bool), typeof(bool), + typeof(GameObject), typeof(string), typeof(bool), typeof(string) + ], + [ + ArgumentType.Normal, ArgumentType.Out, ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Normal, + ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Normal + ] + )] + [HarmonyPrefix] + // ReSharper disable InconsistentNaming + private static bool LocalizationManagerTryGetTranslationPrefix( + ref bool __result, + string Term, + out string Translation, + bool FixForRTL = true, + int maxLineLengthForRTL = 0, + bool ignoreRTLnumbers = true, + bool applyParameters = false, + GameObject localParametersRoot = null, + string overrideLanguage = null, + bool allowLocalizedParameters = true, + string overrideSpecialization = null + ) + { + // ReSharper restore InconsistentNaming + __result = TryGetTranslation( + Term, + out Translation, + FixForRTL, + maxLineLengthForRTL, + ignoreRTLnumbers, + applyParameters, + localParametersRoot, + overrideLanguage, + allowLocalizedParameters, + overrideSpecialization + ); + + return false; + } + + private static bool TryGetTranslation( + string term, + out string translation, + bool fixForRtl, + int maxLineLengthForRtl, + bool ignoreRtlNumbers, + bool applyParameters, + GameObject localParametersRoot, + string overrideLanguage, + bool allowLocalizedParameters, + string overrideSpecialization + ) + { + translation = null; + if (string.IsNullOrEmpty(term)) + { + return false; + } + + if (LocalizationManager.DebugLocalizationIsOn) + { + translation = term; + return true; + } + + LocalizationManager.InitializeIfNeeded(); + + foreach (var source in LocalizationManager.Sources) + { + if (!TryGetTranslationFromSource( + source, + term, + out translation, + overrideLanguage, + overrideSpecialization + )) + { + continue; + } + + if (applyParameters) + { + LocalizationManager.ApplyLocalizationParams( + ref translation, + localParametersRoot, + allowLocalizedParameters + ); + } + + if (LocalizationManager.IsRight2Left & fixForRtl) + { + translation = LocalizationManager.ApplyRTLfix(translation, maxLineLengthForRtl, ignoreRtlNumbers); + } + + return true; + } + + return TryGetFallback( + term, + ref translation, + fixForRtl, + maxLineLengthForRtl, + ignoreRtlNumbers, + applyParameters, + localParametersRoot, + allowLocalizedParameters, + overrideSpecialization + ); + } + + private static bool TryGetTranslationFromSource( + LanguageSourceData source, + string term, + out string translation, + string overrideLanguage = null, + string overrideSpecialization = null, + bool skipDisabled = false, + bool allowCategoryMistmatch = false + ) + { + var languageIndex = source.GetLanguageIndex( + overrideLanguage ?? LocalizationManager.CurrentLanguage, + SkipDisabled: false + ); + + if (languageIndex >= 0 && (!skipDisabled || source.mLanguages[languageIndex].IsEnabled())) + { + var termData = source.GetTermData(term, allowCategoryMistmatch); + if (termData != null) + { + translation = termData.GetTranslation(languageIndex, overrideSpecialization, true); + if (translation == "---") + { + translation = string.Empty; + return true; + } + + if (!string.IsNullOrEmpty(translation)) + { + return true; + } + } + } + + translation = null; + return false; + } + + private static bool TryGetFallback( + string term, + ref string translation, + bool fixForRtl, + int maxLineLengthForRtl, + bool ignoreRtlNumbers, + bool applyParameters, + GameObject localParametersRoot, + bool allowLocalizedParameters, + string overrideSpecialization + ) + { + if (!string.IsNullOrEmpty(translation) && !translation.Equals(term)) + { + return true; + } + + foreach (var source in LocalizationManager.Sources) + { + switch (source.OnMissingTranslation) + { + case LanguageSourceData.MissingTranslationAction.ShowWarning: + translation = ""; + return true; + case LanguageSourceData.MissingTranslationAction.Empty: + translation = string.Empty; + return true; + case LanguageSourceData.MissingTranslationAction.ShowTerm: + translation = term; + return true; + } + + if (!TryGetFallbackFromSource(source, term, out var fallback, overrideSpecialization)) + { + continue; + } + + if (applyParameters) + { + LocalizationManager.ApplyLocalizationParams( + ref fallback, + localParametersRoot, + allowLocalizedParameters + ); + } + + if (LocalizationManager.IsRight2Left & fixForRtl) + { + fallback = LocalizationManager.ApplyRTLfix(fallback, maxLineLengthForRtl, ignoreRtlNumbers); + } + + translation = fallback; + return true; + } + + return false; + } + + private static bool TryGetFallbackFromSource( + LanguageSourceData source, + string term, + out string translation, + string overrideSpecialization + ) + { + translation = null; + + for (var index = 0; index < source.mLanguages.Count; ++index) + { + var termData = source.GetTermData(term); + if (termData == null) + { + continue; + } + + translation = termData.GetTranslation(index, overrideSpecialization, true); + if (!string.IsNullOrEmpty(translation)) + { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/SpaceWarp.Core/Patching/ModLoaderPatch.cs b/src/SpaceWarp.Core/Patching/Mods/ModLoaderPatch.cs similarity index 58% rename from src/SpaceWarp.Core/Patching/ModLoaderPatch.cs rename to src/SpaceWarp.Core/Patching/Mods/ModLoaderPatch.cs index 98d10a64..b7462921 100644 --- a/src/SpaceWarp.Core/Patching/ModLoaderPatch.cs +++ b/src/SpaceWarp.Core/Patching/Mods/ModLoaderPatch.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; +using System.Reflection; using HarmonyLib; using KSP.Modding; using Newtonsoft.Json; @@ -11,16 +8,16 @@ using SpaceWarp.API.Mods.JSON; using SpaceWarp.Backend.Modding; using SpaceWarp.InternalUtilities; -using SpaceWarpPatcher; +using SpaceWarp.Preload.API; using UnityEngine; using File = System.IO.File; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.Mods; [HarmonyPatch(typeof(KSP2Mod))] -public static class ModLoaderPatch +internal static class ModLoaderPatch { - private static ModInfo KSPToSwinfo(KSP2Mod mod) + private static ModInfo KspToSwinfo(KSP2Mod mod) { var newInfo = new ModInfo { @@ -37,36 +34,40 @@ private static ModInfo KSPToSwinfo(KSP2Mod mod) Min = "*", Max = "*" }, - VersionCheck = null, - VersionCheckType = VersionCheckType.SwInfo + VersionCheck = null }; return newInfo; } - [HarmonyPrefix] + [HarmonyPatch(nameof(KSP2Mod.Load))] + [HarmonyPrefix] + // ReSharper disable InconsistentNaming private static bool LoadPre(KSP2Mod __instance, ref bool __result, out bool __state) { - SpaceWarpPlugin.Logger.LogInfo($"KSP2Mod.Load (Pre): {__instance.ModName}"); + // ReSharper restore InconsistentNaming + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"KSP2Mod.Load (Pre): {__instance.ModName}"); var path = __instance.ModRootPath; var info = File.Exists(Path.Combine(path, "swinfo.json")) ? JsonConvert.DeserializeObject(File.ReadAllText(path)) - : KSPToSwinfo(__instance); - var disabled = ChainloaderPatch.DisabledPluginGuids.Contains(info.ModID); + : KspToSwinfo(__instance); + var disabled = ModList.DisabledPluginGuids.Contains(info.ModID); __state = disabled; return !disabled; } - [HarmonyPostfix] [HarmonyPatch(nameof(KSP2Mod.Load))] + [HarmonyPostfix] + // ReSharper disable InconsistentNaming private static void LoadPost(KSP2Mod __instance, ref bool __result, ref bool __state) { - SpaceWarpPlugin.Logger.LogInfo($"KSP2Mod.Load (Post): {__instance.ModName}"); + // ReSharper restore InconsistentNaming + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"KSP2Mod.Load (Post): {__instance.ModName}"); if (__state) return; var path = __instance.ModRootPath; var info = File.Exists(Path.Combine(path, "swinfo.json")) ? JsonConvert.DeserializeObject(File.ReadAllText(path)) - : KSPToSwinfo(__instance); + : KspToSwinfo(__instance); var descriptor = PluginList.AllPlugins.FirstOrDefault(x => string.Equals(x.Guid, info.ModID, StringComparison.InvariantCultureIgnoreCase)); @@ -77,14 +78,17 @@ private static void LoadPost(KSP2Mod __instance, ref bool __result, ref bool __s if (__instance.EntryPoint != null) { if (LoadCodeBasedMod(__instance, ref __result, go, ref descriptor.Plugin, ref addAdapter, - ref descriptor.ConfigFile, ref descriptor.DoLoadingActions)) return; + ref descriptor.ConfigFile, ref descriptor.DoLoadingActions)) + { + return; + } } else { __instance.modType = KSP2ModType.ContentOnly; } - SpaceWarpPlugin.Logger.LogInfo($"KSP2Mod.Load (Loaded stuff): {__instance.ModName}"); + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"KSP2Mod.Load (Loaded stuff): {__instance.ModName}"); if (addAdapter) { @@ -100,8 +104,8 @@ private static void LoadPost(KSP2Mod __instance, ref bool __result, ref bool __s } private static bool LoadCodeBasedMod( - KSP2Mod __instance, - ref bool __result, + KSP2Mod instance, + ref bool result, GameObject go, ref ISpaceWarpMod swMod, ref bool addAdapter, @@ -110,46 +114,59 @@ ref bool isSWMod ) { // Lets take a simple guess at what needs to be done. - if (File.Exists(Path.Combine(__instance.ModRootPath, __instance.EntryPoint))) + if (File.Exists(Path.Combine(instance.ModRootPath, instance.EntryPoint))) { - if (__instance.EntryPoint.EndsWith(".dll")) + if (instance.EntryPoint.EndsWith(".dll")) { - if (LoadModWithDLLEntryPoint(__instance, ref __result, go, ref swMod, ref addAdapter, ref configFile, - ref isSWMod)) return true; + if (LoadModWithDLLEntryPoint( + instance, + ref result, + go, + ref swMod, + ref addAdapter, + ref configFile, + ref isSWMod + )) + { + return true; + } } - else if (__instance.EntryPoint.EndsWith(".lua")) + else if (instance.EntryPoint.EndsWith(".lua")) { - if (LoadModWithLuaEntryPoint(__instance, ref __result)) return true; + if (LoadModWithLuaEntryPoint(instance, ref result)) + { + return true; + } } } else { - __instance.modType = KSP2ModType.Error; - __result = false; + instance.modType = KSP2ModType.Error; + result = false; return true; } return false; } - private static bool LoadModWithLuaEntryPoint(KSP2Mod __instance, ref bool __result) + private static bool LoadModWithLuaEntryPoint(KSP2Mod instance, ref bool result) { try { - __instance.modCore = new KSP2LuaModCore( - __instance.APIVersion, - __instance.ModName, - __instance.EntryPoint, - __instance.ModRootPath + instance.modCore = new KSP2LuaModCore( + instance.APIVersion, + instance.ModName, + instance.EntryPoint, + instance.ModRootPath ); - __instance.modType = KSP2ModType.Lua; - __instance.currentState = KSP2ModState.Active; + instance.modType = KSP2ModType.Lua; + instance.currentState = KSP2ModState.Active; } catch (Exception e) { - SpaceWarpPlugin.Logger.LogError(e); - __instance.modType = KSP2ModType.Error; - __result = false; + SpaceWarpPlugin.Instance.SWLogger.LogError(e); + instance.modType = KSP2ModType.Error; + result = false; return true; } @@ -157,8 +174,8 @@ private static bool LoadModWithLuaEntryPoint(KSP2Mod __instance, ref bool __resu } private static bool LoadModWithDLLEntryPoint( - KSP2Mod __instance, - ref bool __result, + KSP2Mod instance, + ref bool result, GameObject go, ref ISpaceWarpMod swMod, ref bool addAdapter, @@ -168,32 +185,39 @@ ref bool isSWMod { try { - var asm = Assembly.LoadFile(Path.Combine(__instance.ModRootPath, __instance.EntryPoint)); - __instance.modType = KSP2ModType.CSharp; + var asm = Assembly.LoadFile(Path.Combine(instance.ModRootPath, instance.EntryPoint)); + instance.modType = KSP2ModType.CSharp; foreach (var type in asm.GetTypes()) { - if (!typeof(Mod).IsAssignableFrom(type) || type.IsAbstract) continue; + if (!typeof(Mod).IsAssignableFrom(type) || type.IsAbstract) + { + continue; + } + var comp = go.AddComponent(type); - if (comp is not BaseKspLoaderSpaceWarpMod baseKspLoaderSpaceWarpMod) continue; + if (comp is not BaseKspLoaderSpaceWarpMod baseKspLoaderSpaceWarpMod) + { + continue; + } - SpaceWarpPlugin.Logger.LogInfo($"Loading mod: {comp}"); + SpaceWarpPlugin.Instance.SWLogger.LogInfo($"Loading mod: {comp}"); isSWMod = true; - baseKspLoaderSpaceWarpMod.SWLogger = new UnityLogSource(__instance.ModName); + baseKspLoaderSpaceWarpMod.SWLogger = new UnityLogSource(instance.ModName); // baseKspLoaderSpaceWarpMod.modFolder = __instance.ModRootPath; configFile = baseKspLoaderSpaceWarpMod.SWConfiguration = new JsonConfigFile( - Path.Combine(__instance.ModRootPath, "config.cfg") + Path.Combine(instance.ModRootPath, "config.cfg") ); swMod = baseKspLoaderSpaceWarpMod; addAdapter = false; } - __instance.currentState = KSP2ModState.Active; + instance.currentState = KSP2ModState.Active; } catch (Exception e) { - SpaceWarpPlugin.Logger.LogError(e); - __instance.modType = KSP2ModType.Error; - __result = false; + SpaceWarpPlugin.Instance.SWLogger.LogError(e); + instance.modType = KSP2ModType.Error; + result = false; return true; } diff --git a/src/SpaceWarp.Core/Patching/PartOwnerComponentConstructor.cs b/src/SpaceWarp.Core/Patching/PartOwnerComponentConstructor.cs deleted file mode 100644 index f9c7da1f..00000000 --- a/src/SpaceWarp.Core/Patching/PartOwnerComponentConstructor.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Reflection; -using HarmonyLib; -using JetBrains.Annotations; -using KSP.Sim.impl; -using SpaceWarp.API.Parts; - -namespace SpaceWarp.Patching; - - -[HarmonyPatch(typeof(PartOwnerComponent))] -public static class PartOwnerComponentConstructor -{ - private static FieldInfo AddedField = - typeof(PartOwnerComponent).GetField("HasRegisteredPartComponentsForFixedUpdate"); - - [HarmonyPatch(MethodType.Constructor)] - public static void SetFalse(PartOwnerComponent __instance) - { - - AddedField.SetValue(__instance, false); - } - - [HarmonyPatch(nameof(PartOwnerComponent.Add)), HarmonyPrefix, UsedImplicitly] - public static void CheckForModule(PartOwnerComponent __instance, PartComponent part) - { - var currentValue = (Boolean)AddedField.GetValue(__instance); - if (currentValue) return; - var hasModule = PartComponentModuleOverride.RegisteredPartComponentOverrides.Any(type => part.TryGetModule(type, out _)); - - AddedField.SetValue(__instance, hasModule); - } -} \ No newline at end of file diff --git a/src/SpaceWarp.Core/Patching/ColorsPatch.cs b/src/SpaceWarp.Core/Patching/Parts/ColorsPatch.cs similarity index 94% rename from src/SpaceWarp.Core/Patching/ColorsPatch.cs rename to src/SpaceWarp.Core/Patching/Parts/ColorsPatch.cs index c2d8b52e..77db677a 100644 --- a/src/SpaceWarp.Core/Patching/ColorsPatch.cs +++ b/src/SpaceWarp.Core/Patching/Parts/ColorsPatch.cs @@ -1,16 +1,15 @@ -using System.Collections.Generic; -using System.Reflection; -using BepInEx.Logging; -using Castle.Core.Internal; +using System.Reflection; using HarmonyLib; using KSP.Game; using KSP.Modules; using KSP.OAB; using KSP.Sim.impl; using SpaceWarp.API.Assets; +using SpaceWarp.API.Logging; using UnityEngine; +using ILogger = SpaceWarp.API.Logging.ILogger; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.Parts; /// /// This patch is meant to give modders a way to use the new colors system on KSP2. @@ -22,9 +21,9 @@ namespace SpaceWarp.Patching; [HarmonyPatch] internal class ColorsPatch { + #region Colors patch + private const string Ksp2OpaquePath = "KSP2/Scenery/Standard (Opaque)"; - private const string Ksp2TransparentPath = "KSP2/Scenery/Standard (Transparent)"; - private const string UnityStandard = "Standard"; [HarmonyPatch(typeof(ObjectAssemblyPartTracker), nameof(ObjectAssemblyPartTracker.OnPartPrefabLoaded))] public static void Prefix(IObjectAssemblyAvailablePart obj, ref GameObject prefab) @@ -32,7 +31,11 @@ public static void Prefix(IObjectAssemblyAvailablePart obj, ref GameObject prefa foreach (var renderer in prefab.GetComponentsInChildren()) { var shaderName = renderer.material.shader.name; - if (shaderName is not ("Parts Replace" or "KSP2/Parts/Paintable")) continue; + if (shaderName is not ("Parts Replace" or "KSP2/Parts/Paintable")) + { + continue; + } + Material material; var mat = new Material(Shader.Find(Ksp2OpaquePath)) { @@ -50,7 +53,11 @@ public static void UpdateColorsInFlight(GameObject instance) foreach (var renderer in instance.GetComponentsInChildren()) { var shaderName = renderer.material.shader.name; - if (shaderName is not ("Parts Replace" or "KSP2/Parts/Paintable")) continue; + if (shaderName is not ("Parts Replace" or "KSP2/Parts/Paintable")) + { + continue; + } + Material material; var mat = new Material(Shader.Find(Ksp2OpaquePath)) { @@ -61,7 +68,17 @@ public static void UpdateColorsInFlight(GameObject instance) } } - //Everything below this point will be removed in the next patch + #endregion + + // TODO: Remove everything below this comment in 2.0. + + #region To be removed + + // ReSharper disable all + + private const string Ksp2TransparentPath = "KSP2/Scenery/Standard (Transparent)"; + private const string UnityStandard = "Standard"; + private const int Diffuse = 0; private const int Metallic = 1; private const int Bump = 2; @@ -100,9 +117,8 @@ public static void UpdateColorsInFlight(GameObject instance) private static Shader _ksp2Opaque; private static Shader _ksp2Transparent; private static Shader _unityStandard; - internal static ManualLogSource Logger; + internal static ILogger Logger = BaseLogger.CreateDefault(DisplayName); - ///TODO: Implement false behaviour public static Dictionary DeclaredParts { get; } = new(); [HarmonyPrepare] @@ -128,9 +144,7 @@ private static bool Init(MethodBase original) _ksp2Transparent = Shader.Find(Ksp2TransparentPath); _unityStandard = Shader.Find(UnityStandard); - Logger = BepInEx.Logging.Logger.CreateLogSource(DisplayName); - - return true; // TODO: add config to enable/disable this patch, if disabled return false. + return true; } /// @@ -314,7 +328,7 @@ private static string TrimPartName(string partName) nameof(GameManager.OnLoadingFinished))] internal static void Prefix() { - LoadDeclaredParts(); // TODO: Move this to a more apropriate call, like the one loading parts or something like that. + LoadDeclaredParts(); } [HarmonyPatch(typeof(Module_Color), @@ -322,7 +336,7 @@ internal static void Prefix() internal static void Postfix(Module_Color __instance) { var partName = __instance.OABPart is not null ? __instance.OABPart.PartName : __instance.part.Name; - if (partName.IsNullOrEmpty()) return; + if (string.IsNullOrEmpty(partName)) return; var trimmedPartName = TrimPartName(partName); if (DeclaredParts.Count <= 0 || !_allParts.Contains(trimmedPartName)) return; @@ -365,4 +379,6 @@ private static void LogError(object data) { Logger.LogError($"{data}"); } + + #endregion } \ No newline at end of file diff --git a/src/SpaceWarp.Core/Patching/Parts/PartOwnerComponentConstructor.cs b/src/SpaceWarp.Core/Patching/Parts/PartOwnerComponentConstructor.cs new file mode 100644 index 00000000..4eea15cc --- /dev/null +++ b/src/SpaceWarp.Core/Patching/Parts/PartOwnerComponentConstructor.cs @@ -0,0 +1,38 @@ +using System.Reflection; +using HarmonyLib; +using KSP.Sim.impl; +using SpaceWarp.API.Parts; + +namespace SpaceWarp.Patching.Parts; + +[HarmonyPatch(typeof(PartOwnerComponent))] +internal static class PartOwnerComponentConstructor +{ + private static readonly FieldInfo AddedField = + typeof(PartOwnerComponent).GetField("HasRegisteredPartComponentsForFixedUpdate"); + + [HarmonyPatch(MethodType.Constructor)] + // ReSharper disable once InconsistentNaming + private static void SetFalse(PartOwnerComponent __instance) + { + AddedField.SetValue(__instance, false); + } + + [HarmonyPatch(nameof(PartOwnerComponent.Add))] + [HarmonyPrefix] + // ReSharper disable once InconsistentNaming + private static void CheckForModule(PartOwnerComponent __instance, PartComponent part) + { + var currentValue = (bool)AddedField.GetValue(__instance); + if (currentValue) + { + return; + } + + var hasModule = PartComponentModuleOverride.RegisteredPartComponentOverrides.Any( + type => part.TryGetModule(type, out _) + ); + + AddedField.SetValue(__instance, hasModule); + } +} \ No newline at end of file diff --git a/src/SpaceWarp.Core/Patching/SaveGameManager/SaveGamePatches.cs b/src/SpaceWarp.Core/Patching/SaveGameManager/SaveGamePatches.cs index 5dad1816..a77deaec 100644 --- a/src/SpaceWarp.Core/Patching/SaveGameManager/SaveGamePatches.cs +++ b/src/SpaceWarp.Core/Patching/SaveGameManager/SaveGamePatches.cs @@ -1,28 +1,31 @@ using HarmonyLib; using KSP.Game.Load; using KSP.IO; -using SpaceWarp.API.Logging; using SpaceWarp.API.SaveGameManager; using SpaceWarp.Backend.SaveGameManager; using SpaceWarp.InternalUtilities; -using System; namespace SpaceWarp.Patching.SaveGameManager; [HarmonyPatch] internal class SaveLoadPatches { - private static readonly ILogger _logger = new UnityLogSource("SpaceWarp.SaveLoadPatches"); + #region Saving - /// SAVING /// - - [HarmonyPatch(typeof(SerializeGameDataFlowAction), MethodType.Constructor), HarmonyPostfix] - [HarmonyPatch(new Type[] { typeof(string), typeof(LoadGameData) })] - private static void InjectPluginSaveGameData(string filename, LoadGameData data, SerializeGameDataFlowAction __instance) + [HarmonyPatch(typeof(SerializeGameDataFlowAction), MethodType.Constructor, [typeof(string), typeof(LoadGameData)])] + [HarmonyPostfix] + private static void InjectPluginSaveGameData( + string filename, + LoadGameData data, + // ReSharper disable once InconsistentNaming + SerializeGameDataFlowAction __instance + ) { // Skip plugin data injection if there are no mods that have registered for save/load actions if (ModSaves.InternalPluginSaveData.Count == 0) + { return; + } // Take the game's LoadGameData, extend it with our own class and copy plugin save data to it SpaceWarpSerializedSavedGame modSaveData = new(); @@ -37,21 +40,30 @@ private static void InjectPluginSaveGameData(string filename, LoadGameData data, } } - /// LOADING /// + #endregion + + #region Loading - [HarmonyPatch(typeof(DeserializeContentsFlowAction), "DoAction"), HarmonyPrefix] - private static bool DeserializeLoadedPluginData(Action resolve, Action reject, DeserializeContentsFlowAction __instance) + [HarmonyPatch(typeof(DeserializeContentsFlowAction), "DoAction")] + [HarmonyPrefix] + private static bool DeserializeLoadedPluginData( + Action resolve, + Action reject, + // ReSharper disable once InconsistentNaming + DeserializeContentsFlowAction __instance + ) { // Skip plugin deserialization if there are no mods that have registered for save/load actions if (ModSaves.InternalPluginSaveData.Count == 0) + { return true; + } __instance._game.UI.SetLoadingBarText(__instance.Description); try { // Deserialize save data to our own class that extends game's SerializedSavedGame - SpaceWarpSerializedSavedGame serializedSavedGame = new(); - IOProvider.FromJsonFile(__instance._filename, out serializedSavedGame); + IOProvider.FromJsonFile(__instance._filename, out var serializedSavedGame); __instance._data.SavedGame = serializedSavedGame; __instance._data.DataLength = IOProvider.GetFileSize(__instance._filename); @@ -62,18 +74,27 @@ private static bool DeserializeLoadedPluginData(Action resolve, Action r foreach (var loadedData in serializedSavedGame.serializedPluginSaveData) { // Match registered plugin GUID with the GUID found in the save file - var existingData = ModSaves.InternalPluginSaveData.Find(p => p.ModGuid == loadedData.ModGuid); + var existingData = ModSaves.InternalPluginSaveData.Find( + p => p.ModGuid == loadedData.ModGuid + ); if (existingData == null) { - _logger.LogWarning($"Saved data for plugin '{loadedData.ModGuid}' found during a load event, however that plugin isn't registered for save/load events. Skipping load for this plugin."); + SpaceWarpPlugin.Instance.SWLogger.LogWarning( + $"Saved data for plugin '{loadedData.ModGuid}' found during a load event, however " + + $"that plugin isn't registered for save/load events. Skipping load for this plugin." + ); continue; } - // Perform a callback if plugin specified a callback function. This is done before plugin data is actually updated. + // Perform a callback if plugin specified a callback function. This is done before plugin data is + // actually updated. existingData.LoadEventCallback(loadedData.SaveData); // Copy loaded data to the SaveData object plugin registered - InternalExtensions.CopyFieldAndPropertyDataFromSourceToTargetObject(loadedData.SaveData, existingData.SaveData); + InternalExtensions.CopyFieldAndPropertyDataFromSourceToTargetObject( + loadedData.SaveData, + existingData.SaveData + ); } } } @@ -82,8 +103,11 @@ private static bool DeserializeLoadedPluginData(Action resolve, Action r UnityEngine.Debug.LogException(ex); reject(ex.Message); } + resolve(); return false; } -} + + #endregion +} \ No newline at end of file diff --git a/src/SpaceWarp.Core/Patching/SettingsManagerPatcher.cs b/src/SpaceWarp.Core/Patching/Settings/SettingsManagerPatcher.cs similarity index 50% rename from src/SpaceWarp.Core/Patching/SettingsManagerPatcher.cs rename to src/SpaceWarp.Core/Patching/Settings/SettingsManagerPatcher.cs index 93864fe9..3196c04e 100644 --- a/src/SpaceWarp.Core/Patching/SettingsManagerPatcher.cs +++ b/src/SpaceWarp.Core/Patching/Settings/SettingsManagerPatcher.cs @@ -1,16 +1,14 @@ -using System.Collections.Generic; -using HarmonyLib; +using HarmonyLib; using KSP.UI; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.Settings; [HarmonyPatch] internal static class SettingsManagerPatcher { - internal static List AllExtrasSettingsMenus = new(); - + internal static readonly List AllExtrasSettingsMenus = new(); + + [HarmonyPatch(typeof(SettingsMenuManager), nameof(SettingsMenuManager.ResetAllSettings))] [HarmonyPostfix] - [HarmonyPatch(typeof(SettingsMenuManager))] - [HarmonyPatch(nameof(SettingsMenuManager.ResetAllSettings))] internal static void ResetModsMenu() { foreach (var menu in AllExtrasSettingsMenus.Where(menu => menu != null)) diff --git a/src/SpaceWarp.Core/Patching/FixGetTypes.cs b/src/SpaceWarp.Core/Patching/System/FixGetTypes.cs similarity index 76% rename from src/SpaceWarp.Core/Patching/FixGetTypes.cs rename to src/SpaceWarp.Core/Patching/System/FixGetTypes.cs index 19ddcf90..b592666c 100644 --- a/src/SpaceWarp.Core/Patching/FixGetTypes.cs +++ b/src/SpaceWarp.Core/Patching/System/FixGetTypes.cs @@ -1,27 +1,29 @@ -using System; using System.Reflection; -using BepInEx.Logging; using HarmonyLib; +using SpaceWarp.API.Logging; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.System; [HarmonyPatch] internal static class FixGetTypes { - [HarmonyFinalizer] [HarmonyPatch(typeof(Assembly), nameof(Assembly.GetTypes), new Type[0])] [HarmonyPatch(typeof(Assembly), nameof(Assembly.GetExportedTypes))] + [HarmonyFinalizer] + // ReSharper disable InconsistentNaming private static Exception GetTypesFix(Exception __exception, Assembly __instance, ref Type[] __result) { + // ReSharper restore InconsistentNaming if (__exception is not ReflectionTypeLoadException reflectionTypeLoadException) { return __exception; } - var logger = new ManualLogSource("FixGetTypes"); + var logger = BaseLogger.CreateDefault("FixGetTypes"); logger.LogWarning( - $"Types failed to load from assembly {__instance.FullName} due to the reasons below, continuing anyway."); + $"Types failed to load from assembly {__instance.FullName} due to the reasons below, continuing anyway." + ); logger.LogWarning($"Exception: {__exception}"); foreach (var exception in reflectionTypeLoadException.LoaderExceptions) @@ -31,6 +33,5 @@ private static Exception GetTypesFix(Exception __exception, Assembly __instance, __result = reflectionTypeLoadException.Types.Where(type => type != null).ToArray(); return null; - } } \ No newline at end of file diff --git a/src/SpaceWarp.Core/AssemblyInfo.cs b/src/SpaceWarp.Core/Properties/AssemblyInfo.cs similarity index 100% rename from src/SpaceWarp.Core/AssemblyInfo.cs rename to src/SpaceWarp.Core/Properties/AssemblyInfo.cs diff --git a/src/SpaceWarp.Core/SpaceWarp.Core.csproj b/src/SpaceWarp.Core/SpaceWarp.Core.csproj index b3662049..9819d2a0 100644 --- a/src/SpaceWarp.Core/SpaceWarp.Core.csproj +++ b/src/SpaceWarp.Core/SpaceWarp.Core.csproj @@ -21,6 +21,9 @@ - + + false + all + diff --git a/src/SpaceWarp.Core/SpaceWarpPlugin.cs b/src/SpaceWarp.Core/SpaceWarpPlugin.cs index 87186335..db943ad6 100644 --- a/src/SpaceWarp.Core/SpaceWarpPlugin.cs +++ b/src/SpaceWarp.Core/SpaceWarpPlugin.cs @@ -1,7 +1,5 @@ global using UnityObject = UnityEngine.Object; global using System.Linq; -using System; -using System.IO; using System.Reflection; using BepInEx; using BepInEx.Logging; @@ -21,28 +19,47 @@ namespace SpaceWarp; -[BepInDependency("com.bepis.bepinex.configurationmanager", "17.1")] +/// +/// The main SpaceWarp plugin class. +/// [BepInDependency(UitkForKsp2Plugin.ModGuid, UitkForKsp2Plugin.ModVer)] [BepInIncompatibility("com.shadow.quantum")] [BepInPlugin(ModGuid, ModName, ModVer)] public sealed class SpaceWarpPlugin : BaseSpaceWarpPlugin { + /// + /// SpaceWarp plugin instance. + /// public static SpaceWarpPlugin Instance; - [PublicAPI] public const string ModGuid = "com.github.x606.spacewarp"; - [PublicAPI] public const string ModName = "Space Warp"; - [PublicAPI] public const string ModVer = MyPluginInfo.PLUGIN_VERSION; // TODO: Don't hard code this, but I don't know much msbuild stuff so @munix wil have to do that, - // and @munix is really lazy to do it right now but he definitely will at some point :P - + /// + /// The GUID of the SpaceWarp plugin. + /// + [PublicAPI] public const string ModGuid = MyPluginInfo.PLUGIN_GUID; + + /// + /// The name of the SpaceWarp plugin. + /// + [PublicAPI] public const string ModName = MyPluginInfo.PLUGIN_NAME; + + /// + /// The version of the SpaceWarp plugin. + /// + [PublicAPI] public const string ModVer = MyPluginInfo.PLUGIN_VERSION; + internal ScriptEnvironment GlobalLuaState; internal new static ManualLogSource Logger; + /// + /// Initializes a new instance of the class. + /// public SpaceWarpPlugin() { // Load the type forwarders Assembly.LoadFile( - $"{new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName}\\SpaceWarp.dll"); + $"{new FileInfo(Assembly.GetExecutingAssembly().Location).Directory!.FullName}\\SpaceWarp.dll" + ); Logger = base.Logger; Instance = this; } @@ -55,9 +72,10 @@ private static void OnLanguageSourceAssetLoaded(LanguageSourceAsset asset) } asset.mSource.owner = asset; - LocalizationManager.AddSource(asset.mSource); + LocalizationHelpers.AddSource(asset.mSource); } - public void Awake() + + private void Awake() { BepInEx.Bootstrap.Chainloader.ManagerObject.Persist(); // IOProvider.Init(); @@ -65,9 +83,22 @@ public void Awake() Harmony.CreateAndPatchAll(typeof(SpaceWarpPlugin).Assembly, ModGuid); ModuleManager.LoadAllModules(); - Loading.AddAssetLoadingAction("bundles", "loading asset bundles", FunctionalLoadingActions.AssetBundleLoadingAction, "bundle"); - Loading.AddAssetLoadingAction("images", "loading images", FunctionalLoadingActions.ImageLoadingAction); - Loading.AddAddressablesLoadingAction("localization","language_source",OnLanguageSourceAssetLoaded); + Loading.AddAssetLoadingAction( + "bundles", + "loading asset bundles", + FunctionalLoadingActions.AssetBundleLoadingAction, + "bundle" + ); + Loading.AddAssetLoadingAction( + "images", + "loading images", + FunctionalLoadingActions.ImageLoadingAction + ); + Loading.AddAddressablesLoadingAction( + "localization", + "language_source", + OnLanguageSourceAssetLoaded + ); } private void SetupLuaState() @@ -96,18 +127,27 @@ private void SetupLuaState() } } + private void UpdateLanguagesDropdown() + { + Game.SettingsMenuManager._generalSettings.InitializeLanguageDropdown(); + } + + /// public override void OnPreInitialized() { // Persist all game objects so I don't need to stomp on config ModuleManager.PreInitializeAllModules(); } + /// public override void OnInitialized() { ModuleManager.InitializeAllModules(); SetupLuaState(); + UpdateLanguagesDropdown(); } + /// public override void OnPostInitialized() { ModuleManager.PostInitializeAllModules(); diff --git a/src/SpaceWarp.Game/API/Game/Extensions/PartProviderExtensions.cs b/src/SpaceWarp.Game/API/Game/Extensions/PartProviderExtensions.cs index d77af419..353a7643 100644 --- a/src/SpaceWarp.Game/API/Game/Extensions/PartProviderExtensions.cs +++ b/src/SpaceWarp.Game/API/Game/Extensions/PartProviderExtensions.cs @@ -1,14 +1,21 @@ -using System.Collections.Generic; -using System.Linq; -using JetBrains.Annotations; +using JetBrains.Annotations; using KSP.Game; using KSP.Sim.Definitions; namespace SpaceWarp.API.Game.Extensions; +/// +/// Extensions for . +/// [PublicAPI] public static class PartProviderExtensions { + /// + /// Gets all parts with a module of type . + /// + /// The part provider. + /// The module type. + /// All parts with a module of type . public static IEnumerable WithModule(this PartProvider provider) where T : ModuleData { return provider._partData.Values.Where(part => part.modules.OfType().Any()); diff --git a/src/SpaceWarp.Game/API/Game/Extensions/VesselVehicleExtensions.cs b/src/SpaceWarp.Game/API/Game/Extensions/VesselVehicleExtensions.cs index e8b4df65..b7553b2c 100644 --- a/src/SpaceWarp.Game/API/Game/Extensions/VesselVehicleExtensions.cs +++ b/src/SpaceWarp.Game/API/Game/Extensions/VesselVehicleExtensions.cs @@ -5,9 +5,17 @@ namespace SpaceWarp.API.Game.Extensions; +/// +/// Extensions for . +/// [PublicAPI] public static class VesselVehicleExtensions { + /// + /// Sets the throttle of the vessel. + /// + /// The vessel. + /// The throttle value. public static void SetMainThrottle(this VesselVehicle vehicle, float throttle) { var incremental = new FlightCtrlStateIncremental @@ -17,6 +25,11 @@ public static void SetMainThrottle(this VesselVehicle vehicle, float throttle) vehicle.AtomicSet(incremental); } + /// + /// Sets the roll of the vessel. + /// + /// The vessel. + /// The roll value. public static void SetRoll(this VesselVehicle vehicle, float roll) { var incremental = new FlightCtrlStateIncremental @@ -26,6 +39,11 @@ public static void SetRoll(this VesselVehicle vehicle, float roll) vehicle.AtomicSet(incremental); } + /// + /// Sets the yaw of the vessel. + /// + /// The vessel. + /// The yaw value. public static void SetYaw(this VesselVehicle vehicle, float yaw) { var incremental = new FlightCtrlStateIncremental @@ -35,6 +53,11 @@ public static void SetYaw(this VesselVehicle vehicle, float yaw) vehicle.AtomicSet(incremental); } + /// + /// Sets the pitch of the vessel. + /// + /// The vessel. + /// The pitch value. public static void SetPitch(this VesselVehicle vehicle, float pitch) { var incremental = new FlightCtrlStateIncremental @@ -44,6 +67,13 @@ public static void SetPitch(this VesselVehicle vehicle, float pitch) vehicle.AtomicSet(incremental); } + /// + /// Sets the roll, yaw and pitch of the vessel. + /// + /// The vessel. + /// The roll value. + /// The yaw value. + /// The pitch value. public static void SetRollYawPitch(this VesselVehicle vehicle, float roll, float yaw, float pitch) { var incremental = new FlightCtrlStateIncremental @@ -55,6 +85,11 @@ public static void SetRollYawPitch(this VesselVehicle vehicle, float roll, float vehicle.AtomicSet(incremental); } + /// + /// Sets the roll trim of the vessel. + /// + /// The vessel. + /// The roll trim value. public static void SetRollTrim(this VesselVehicle vehicle, float rollTrim) { var incremental = new FlightCtrlStateIncremental @@ -64,6 +99,11 @@ public static void SetRollTrim(this VesselVehicle vehicle, float rollTrim) vehicle.AtomicSet(incremental); } + /// + /// Sets the yaw trim of the vessel. + /// + /// The vessel. + /// The yaw trim value. public static void SetYawTrim(this VesselVehicle vehicle, float yawTrim) { var incremental = new FlightCtrlStateIncremental @@ -73,6 +113,11 @@ public static void SetYawTrim(this VesselVehicle vehicle, float yawTrim) vehicle.AtomicSet(incremental); } + /// + /// Sets the pitch trim of the vessel. + /// + /// The vessel. + /// The pitch trim value. public static void SetPitchTrim(this VesselVehicle vehicle, float pitchTrim) { var incremental = new FlightCtrlStateIncremental @@ -83,6 +128,13 @@ public static void SetPitchTrim(this VesselVehicle vehicle, float pitchTrim) } + /// + /// Sets the roll, yaw and pitch trim of the vessel. + /// + /// The vessel. + /// The roll trim value. + /// The yaw trim value. + /// The pitch trim value. public static void SetRollYawPitchTrim(this VesselVehicle vehicle, float rollTrim, float yawTrim, float pitchTrim) { var incremental = new FlightCtrlStateIncremental @@ -94,6 +146,11 @@ public static void SetRollYawPitchTrim(this VesselVehicle vehicle, float rollTri vehicle.AtomicSet(incremental); } + /// + /// Sets the input roll of the vessel. + /// + /// The vessel. + /// The input roll value. public static void SetInputRoll(this VesselVehicle vehicle, float roll) { var incremental = new FlightCtrlStateIncremental @@ -103,6 +160,11 @@ public static void SetInputRoll(this VesselVehicle vehicle, float roll) vehicle.AtomicSet(incremental); } + /// + /// Sets the input yaw of the vessel. + /// + /// The vessel. + /// The input yaw value. public static void SetInputYaw(this VesselVehicle vehicle, float yaw) { var incremental = new FlightCtrlStateIncremental @@ -112,6 +174,11 @@ public static void SetInputYaw(this VesselVehicle vehicle, float yaw) vehicle.AtomicSet(incremental); } + /// + /// Sets the input pitch of the vessel. + /// + /// The vessel. + /// The input pitch value. public static void SetInputPitch(this VesselVehicle vehicle, float pitch) { var incremental = new FlightCtrlStateIncremental @@ -121,6 +188,13 @@ public static void SetInputPitch(this VesselVehicle vehicle, float pitch) vehicle.AtomicSet(incremental); } + /// + /// Sets the input roll, yaw and pitch of the vessel. + /// + /// The vessel. + /// The input roll value. + /// The input yaw value. + /// The input pitch value. public static void SetInputRollYawPitch(this VesselVehicle vehicle, float roll, float yaw, float pitch) { var incremental = new FlightCtrlStateIncremental @@ -132,6 +206,12 @@ public static void SetInputRollYawPitch(this VesselVehicle vehicle, float roll, vehicle.AtomicSet(incremental); } + /// + /// Sets the wheel steer and wheel steer trim of the vessel. + /// + /// The vessel. + /// The wheel steer value. + /// The wheel steer trim value. public static void SetWheelSteer(this VesselVehicle vehicle, float wheelSteer, float? wheelSteerTrim = null) { var incremental = new FlightCtrlStateIncremental @@ -142,6 +222,12 @@ public static void SetWheelSteer(this VesselVehicle vehicle, float wheelSteer, f vehicle.AtomicSet(incremental); } + /// + /// Sets the wheel throttle and wheel throttle trim of the vessel. + /// + /// The vessel. + /// The wheel throttle value. + /// The wheel throttle trim value. public static void SetWheelThrottle(this VesselVehicle vehicle, float wheelThrottle, float? wheelThrottleTrim = null) { @@ -153,6 +239,13 @@ public static void SetWheelThrottle(this VesselVehicle vehicle, float wheelThrot vehicle.AtomicSet(incremental); } + /// + /// Sets the X, Y and Z values of the vessel. + /// + /// The vessel. + /// The X orientation value. + /// The Y orientation value. + /// The Z orientation value. public static void SetXYZ(this VesselVehicle vehicle, float? x = null, float? y = null, float? z = null) { var incremental = new FlightCtrlStateIncremental @@ -164,6 +257,11 @@ public static void SetXYZ(this VesselVehicle vehicle, float? x = null, float? y vehicle.AtomicSet(incremental); } + /// + /// Sets the X, Y and Z values of the vessel. + /// + /// The vessel. + /// The X, Y and Z vector. public static void SetXYZ(this VesselVehicle vehicle, Vector3 xyz) { var incremental = new FlightCtrlStateIncremental @@ -175,6 +273,11 @@ public static void SetXYZ(this VesselVehicle vehicle, Vector3 xyz) vehicle.AtomicSet(incremental); } + /// + /// Sets the kill rotation value of the vessel. + /// + /// + /// public static void SetKillRot(this VesselVehicle vehicle, bool killRot) { var incremental = new FlightCtrlStateIncremental @@ -184,6 +287,11 @@ public static void SetKillRot(this VesselVehicle vehicle, bool killRot) vehicle.AtomicSet(incremental); } + /// + /// Sets the gear state of the vessel. + /// + /// The vessel. + /// Whether the gear is up. public static void SetGearState(this VesselVehicle vehicle, bool up) { var incremental = new FlightCtrlStateIncremental @@ -194,7 +302,11 @@ public static void SetGearState(this VesselVehicle vehicle, bool up) vehicle.AtomicSet(incremental); } - + /// + /// Sets the headlight state of the vessel. + /// + /// The vessel. + /// Whether the headlight is on. public static void SetHeadlight(this VesselVehicle vehicle, bool on) { var incremental = new FlightCtrlStateIncremental @@ -204,7 +316,11 @@ public static void SetHeadlight(this VesselVehicle vehicle, bool on) vehicle.AtomicSet(incremental); } - + /// + /// Sets the brake state of the vessel. + /// + /// The vessel. + /// Whether the brakes are on. public static void SetBrake(this VesselVehicle vehicle, bool on) { var incremental = new FlightCtrlStateIncremental @@ -214,6 +330,11 @@ public static void SetBrake(this VesselVehicle vehicle, bool on) vehicle.AtomicSet(incremental); } + /// + /// Sets the staging state of the vessel. + /// + /// The vessel. + /// Whether to stage. public static void SetStage(this VesselVehicle vehicle, bool stage) { var incremental = new FlightCtrlStateIncremental diff --git a/src/SpaceWarp.Game/API/Game/Messages/StateChanges.cs b/src/SpaceWarp.Game/API/Game/Messages/StateChanges.cs index c0f5768f..91693698 100644 --- a/src/SpaceWarp.Game/API/Game/Messages/StateChanges.cs +++ b/src/SpaceWarp.Game/API/Game/Messages/StateChanges.cs @@ -1,5 +1,4 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; using KSP.Game; using KSP.Messages; @@ -23,50 +22,208 @@ public static class StateChanges #region Entering States + /// + /// Invoked when the game state is changed to + /// public static event Action InvalidStateEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action WarmUpLoadingStateEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action MainMenuStateEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action KerbalSpaceCenterStateEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action VehicleAssemblyBuilderEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action BaseAssemblyEditorEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action FlightViewEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action ColonyViewEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action Map3DViewEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action PhotoModeEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action MetricsModeEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action PlanetViewerEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action LoadingEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action TrainingCenterEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action MissionControlEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action TrackingStationEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action ResearchAndDevelopmentEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action LaunchpadEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action RunwayEntered; + + /// + /// Invoked when the game state is changed to + /// public static event Action FlagEntered; #endregion #region Leaving States + /// + /// Invoked when the game state is changed from + /// public static event Action InvalidStateLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action WarmUpLoadingStateLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action MainMenuStateLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action KerbalSpaceCenterStateLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action VehicleAssemblyBuilderLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action BaseAssemblyEditorLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action FlightViewLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action ColonyViewLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action PhotoModeLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action Map3DViewLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action MetricsModeLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action PlanetViewerLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action LoadingLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action TrainingCenterLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action MissionControlLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action TrackingStationLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action ResearchAndDevelopmentLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action LaunchpadLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action RunwayLeft; + + /// + /// Invoked when the game state is changed from + /// public static event Action FlagLeft; #endregion diff --git a/src/SpaceWarp.Game/API/Game/Messages/StateLoadings.cs b/src/SpaceWarp.Game/API/Game/Messages/StateLoadings.cs index 94df110c..df232a49 100644 --- a/src/SpaceWarp.Game/API/Game/Messages/StateLoadings.cs +++ b/src/SpaceWarp.Game/API/Game/Messages/StateLoadings.cs @@ -1,24 +1,49 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; using KSP.Messages; namespace SpaceWarp.API.Game.Messages; +/// +/// Messages related to the loading of game states. +/// [PublicAPI] public class StateLoadings { + /// + /// Invoked when the training center is loaded. + /// public static event Action TrainingCenterLoaded; + /// + /// Invoked when the tracking station is loaded. + /// public static event Action TrackingStationLoaded; + /// + /// Invoked when the tracking station is unloaded. + /// public static event Action TrackingStationUnloaded; + + /// + /// Handler for the evenr. + /// + /// The associated message. public static void TrainingCenterLoadedHandler(MessageCenterMessage message) { TrainingCenterLoaded?.Invoke(message as TrainingCenterLoadedMessage); } + + /// + /// Handler for the event. + /// + /// The associated message. public static void TrackingStationLoadedHandler(MessageCenterMessage message) { TrackingStationLoaded?.Invoke(message as TrackingStationLoadedMessage); } + /// + /// Handler for the event. + /// + /// The associated message. public static void TrackingStationUnloadedHandler(MessageCenterMessage message) { TrackingStationUnloaded?.Invoke(message as TrackingStationUnloadedMessage); diff --git a/src/SpaceWarp.Game/API/Game/Vehicle.cs b/src/SpaceWarp.Game/API/Game/Vehicle.cs index 68902970..9372bdf5 100644 --- a/src/SpaceWarp.Game/API/Game/Vehicle.cs +++ b/src/SpaceWarp.Game/API/Game/Vehicle.cs @@ -5,10 +5,20 @@ namespace SpaceWarp.API.Game; +/// +/// Vehicle related API. +/// [SpaceWarpLuaAPI("Vehicle")] [PublicAPI] public static class Vehicle { + /// + /// Gets the active vessel. + /// public static VesselVehicle ActiveVesselVehicle => GameManager.Instance.Game.ViewController._activeVesselVehicle; + + /// + /// Gets the active vessel component. + /// public static VesselComponent ActiveSimVessel => GameManager.Instance.Game.ViewController.GetActiveSimVessel(); } \ No newline at end of file diff --git a/src/SpaceWarp.Game/Modules/Game.cs b/src/SpaceWarp.Game/Modules/Game.cs index 461156ff..c9db2432 100644 --- a/src/SpaceWarp.Game/Modules/Game.cs +++ b/src/SpaceWarp.Game/Modules/Game.cs @@ -5,19 +5,16 @@ namespace SpaceWarp.Modules; +/// +/// The module for game-related APIs. +/// [UsedImplicitly] public class Game : SpaceWarpModule { + /// public override string Name => "SpaceWarp.Game"; - public override void LoadModule() - { - } - - public override void PreInitializeModule() - { - } - + /// public override void InitializeModule() { var game = GameManager.Instance.Game; @@ -28,8 +25,4 @@ public override void InitializeModule() game.Messages.Subscribe(typeof(TrackingStationUnloadedMessage), StateLoadings.TrackingStationUnloadedHandler, false, true); game.Messages.Subscribe(typeof(TrainingCenterLoadedMessage), StateLoadings.TrainingCenterLoadedHandler, false, true); } - - public override void PostInitializeModule() - { - } } \ No newline at end of file diff --git a/src/SpaceWarp.Messaging/API/Messaging/MessageBus.cs b/src/SpaceWarp.Messaging/API/Messaging/MessageBus.cs index dc220ba3..36590251 100644 --- a/src/SpaceWarp.Messaging/API/Messaging/MessageBus.cs +++ b/src/SpaceWarp.Messaging/API/Messaging/MessageBus.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; -using UnityEngine; +using JetBrains.Annotations; namespace SpaceWarp.API.Messaging; +/// +/// MessageBus that can be used to publish messages with no arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -12,21 +12,42 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) + { throw new ArgumentNullException(); + } _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) + { if (_handlers[i] == handler) + { _handlers.RemoveAt(i); + } + } } + /// + /// Publishes a message to all subscribers. + /// + /// + /// Publishes a message to all subscribers. + /// public void Publish() { for (var i = _handlers.Count; i-- > 0;) @@ -43,6 +64,9 @@ public void Publish() } } +/// +/// MessageBus that can be used to publish messages with 1 argument to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -50,21 +74,39 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) + { throw new ArgumentNullException(); + } _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) + { if (_handlers[i] == handler) + { _handlers.RemoveAt(i); + } + } } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0) { for (var i = _handlers.Count; i-- > 0;) @@ -81,6 +123,9 @@ public void Publish(T1 arg0) } } +/// +/// MessageBus that can be used to publish messages with 2 argument to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -88,6 +133,11 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -96,6 +146,10 @@ public void Subscribe(Action handler) _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (int i = _handlers.Count; i-- > 0;) @@ -103,6 +157,9 @@ public void Unsubscribe(Action handler) _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1) { for (var i = _handlers.Count; i-- > 0;) @@ -119,6 +176,9 @@ public void Publish(T1 arg0, T2 arg1) } } +/// +/// MessageBus that can be used to publish messages with 3 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -126,6 +186,11 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -134,6 +199,10 @@ public void Subscribe(Action handler) _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -141,6 +210,9 @@ public void Unsubscribe(Action handler) _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2) { for (var i = _handlers.Count; i-- > 0;) @@ -157,6 +229,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2) } } +/// +/// MessageBus that can be used to publish messages with 4 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -164,6 +239,11 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -172,6 +252,10 @@ public void Subscribe(Action handler) _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -179,6 +263,9 @@ public void Unsubscribe(Action handler) _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3) { for (var i = _handlers.Count; i-- > 0;) @@ -195,6 +282,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3) } } +/// +/// MessageBus that can be used to publish messages with 5 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -202,6 +292,11 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -210,6 +305,10 @@ public void Subscribe(Action handler) _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -217,6 +316,9 @@ public void Unsubscribe(Action handler) _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) { for (var i = _handlers.Count; i-- > 0;) @@ -233,6 +335,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) } } +/// +/// MessageBus that can be used to publish messages with 6 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -240,6 +345,11 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -248,6 +358,10 @@ public void Subscribe(Action handler) _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -255,6 +369,9 @@ public void Unsubscribe(Action handler) _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) { for (var i = _handlers.Count; i-- > 0;) @@ -271,6 +388,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) } } +/// +/// MessageBus that can be used to publish messages with 7 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -278,6 +398,11 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -286,6 +411,10 @@ public void Subscribe(Action handler) _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -293,6 +422,9 @@ public void Unsubscribe(Action handler) _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) { for (var i = _handlers.Count; i-- > 0;) @@ -309,6 +441,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg } } +/// +/// MessageBus that can be used to publish messages with 8 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -316,6 +451,11 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -324,6 +464,10 @@ public void Subscribe(Action handler) _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -331,6 +475,9 @@ public void Unsubscribe(Action handler) _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) { for (var i = _handlers.Count; i-- > 0;) @@ -347,6 +494,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg } } +/// +/// MessageBus that can be used to publish messages with 9 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -354,6 +504,11 @@ public class MessageBus : MessageBusBase internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -362,6 +517,10 @@ public void Subscribe(Action handler) _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -369,6 +528,9 @@ public void Unsubscribe(Action handler) _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) { for (var i = _handlers.Count; i-- > 0;) @@ -385,6 +547,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg } } +/// +/// MessageBus that can be used to publish messages with 10 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -392,6 +557,11 @@ public class MessageBus : MessageBusBas internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -400,6 +570,10 @@ public void Subscribe(Action handler) _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -407,6 +581,9 @@ public void Unsubscribe(Action handler) _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) { for (var i = _handlers.Count; i-- > 0;) @@ -423,6 +600,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg } } +/// +/// MessageBus that can be used to publish messages with 11 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -430,6 +610,11 @@ public class MessageBus : MessageB internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -438,6 +623,10 @@ public void Subscribe(Action handl _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -445,6 +634,9 @@ public void Unsubscribe(Action han _handlers.RemoveAt(i); } + /// + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) { @@ -462,6 +654,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg } } +/// +/// MessageBus that can be used to publish messages with 12 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -469,6 +664,11 @@ public class MessageBus : Mes internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -477,6 +677,10 @@ public void Subscribe(Action _handlers.Add(handler); } + /// + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -484,6 +688,9 @@ public void Unsubscribe(Action + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10, T12 arg11) { @@ -501,6 +708,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg } } +/// +/// MessageBus that can be used to publish messages with 13 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -508,6 +718,11 @@ public class MessageBus internal override IReadOnlyList Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -516,6 +731,10 @@ public void Subscribe(Action + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -523,6 +742,9 @@ public void Unsubscribe(Action + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10, T12 arg11, T13 arg12) { @@ -540,6 +762,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg } } +/// +/// MessageBus that can be used to publish messages with 14 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -547,6 +772,11 @@ public class MessageBus Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -555,6 +785,10 @@ public void Subscribe(Action + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -562,6 +796,9 @@ public void Unsubscribe(Action + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10, T12 arg11, T13 arg12, T14 arg13) { @@ -580,6 +817,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg } } +/// +/// MessageBus that can be used to publish messages with 15 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -587,6 +827,11 @@ public class MessageBus Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -595,6 +840,10 @@ public void Subscribe(Action + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -602,6 +851,9 @@ public void Unsubscribe(Action + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10, T12 arg11, T13 arg12, T14 arg13, T15 arg14) { @@ -620,6 +872,9 @@ public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg } } +/// +/// MessageBus that can be used to publish messages with 16 arguments to subscribers. +/// [PublicAPI] public class MessageBus : MessageBusBase { @@ -629,6 +884,11 @@ public class MessageBus Handlers => _handlers; internal override void RemoveHandlerAt(int index) => _handlers.RemoveAt(index); + /// + /// Subscribes a handler to the MessageBus. + /// + /// The handler to subscribe. + /// Thrown when the handler is null. public void Subscribe(Action handler) { if (handler == null) @@ -637,6 +897,10 @@ public void Subscribe(Action + /// Unsubscribes a handler from the MessageBus. + /// + /// The handler to unsubscribe. public void Unsubscribe(Action handler) { for (var i = _handlers.Count; i-- > 0;) @@ -644,6 +908,9 @@ public void Unsubscribe(Action + /// Publishes a message to all subscribers. + /// public void Publish(T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10, T12 arg11, T13 arg12, T14 arg13, T15 arg14, T16 arg15) { diff --git a/src/SpaceWarp.Messaging/API/Messaging/MessageBusBase.cs b/src/SpaceWarp.Messaging/API/Messaging/MessageBusBase.cs index f8ae2782..7fd7547e 100644 --- a/src/SpaceWarp.Messaging/API/Messaging/MessageBusBase.cs +++ b/src/SpaceWarp.Messaging/API/Messaging/MessageBusBase.cs @@ -1,12 +1,16 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; +using JetBrains.Annotations; namespace SpaceWarp.API.Messaging; +/// +/// A base class for MessageBus instances. +/// [PublicAPI] public abstract class MessageBusBase { + /// + /// The name of the MessageBus. + /// public string Name { get; internal set; } internal abstract IReadOnlyList Handlers { get; } internal abstract void RemoveHandlerAt(int index); diff --git a/src/SpaceWarp.Messaging/API/Messaging/MessageBusManager.cs b/src/SpaceWarp.Messaging/API/Messaging/MessageBusManager.cs index 8b256e92..9c716a09 100644 --- a/src/SpaceWarp.Messaging/API/Messaging/MessageBusManager.cs +++ b/src/SpaceWarp.Messaging/API/Messaging/MessageBusManager.cs @@ -1,81 +1,119 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; -using UnityEngine; +using JetBrains.Annotations; namespace SpaceWarp.API.Messaging; +/// +/// A static class that manages the creation and retrieval of MessageBus instances. +/// [PublicAPI] public static class MessageBusManager { - private static Dictionary _messagesBusesByName = new Dictionary(); + private static Dictionary _messagesBusesByName = new(); - public static T Add(string name) where T : MessageBusBase, new() - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentException("Null or empty MessageBus name"); + /// + /// Creates a new MessageBus instance with the given name. + /// + /// The name of the MessageBus to create. + /// The type of the MessageBus to create. + /// The created MessageBus instance. + /// Thrown when the given name is null or empty. + /// Thrown when a MessageBus with the given name already exists. + public static T Add(string name) where T : MessageBusBase, new() + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentException("Null or empty MessageBus name"); + } - if (_messagesBusesByName.ContainsKey(name)) - throw new Exception($"MessageBus '{name}' exists already"); + if (_messagesBusesByName.ContainsKey(name)) + { + throw new Exception($"MessageBus '{name}' exists already"); + } - var messageBus = new T - { - Name = name - }; - _messagesBusesByName.Add(name, messageBus); + var messageBus = new T + { + Name = name + }; + _messagesBusesByName.Add(name, messageBus); - Modules.Messaging.Instance.ModuleLogger.LogDebug($"MessageBus '{name}' created"); - return messageBus; - } + Modules.Messaging.Instance.ModuleLogger.LogDebug($"MessageBus '{name}' created"); + return messageBus; + } - public static bool Exists(string messageBusName) => _messagesBusesByName.ContainsKey(messageBusName); + /// + /// Does a MessageBus with the given name exist? + /// + /// The name of the MessageBus to check. + /// True if a MessageBus with the given name exists, false otherwise. + public static bool Exists(string messageBusName) => _messagesBusesByName.ContainsKey(messageBusName); - public static bool TryGet(string messageBusName, out T messageBus) where T : MessageBusBase, new() - { - if (string.IsNullOrEmpty(messageBusName)) - throw new ArgumentException("Null or empty MessageBus name"); + /// + /// Gets a MessageBus instance with the given name. + /// + /// + /// + /// + /// + /// + /// + public static bool TryGet(string messageBusName, out T messageBus) where T : MessageBusBase, new() + { + if (string.IsNullOrEmpty(messageBusName)) + { + throw new ArgumentException("Null or empty MessageBus name"); + } - if (!_messagesBusesByName.TryGetValue(messageBusName, out MessageBusBase messageBusBase)) - { - messageBus = null; - return false; - } + if (!_messagesBusesByName.TryGetValue(messageBusName, out MessageBusBase messageBusBase)) + { + messageBus = null; + return false; + } - if (messageBusBase is not T @base) - throw new Exception( - $"Message bus '{messageBusBase.Name}' is of type '{messageBusBase.GetType()}' but the requested type was '{typeof(T)}'"); - messageBus = @base; - return true; + if (messageBusBase is not T @base) + { + throw new Exception( + $"Message bus '{messageBusBase.Name}' is of type '{messageBusBase.GetType()}' but the " + + $"requested type was '{typeof(T)}'" + ); + } - } + messageBus = @base; + return true; + } - // Call this (potentially a bit heavy) method on some occasions, for example when a loading screen happens - internal static void CheckForMemoryLeaks() - { - var memoryLeaks = 0; + // Call this (potentially a bit heavy) method on some occasions, for example when a loading screen happens + internal static void CheckForMemoryLeaks() + { + var memoryLeaks = 0; - foreach (var messageBus in _messagesBusesByName.Values) - { - var handlers = messageBus.Handlers; + foreach (var messageBus in _messagesBusesByName.Values) + { + var handlers = messageBus.Handlers; - for (var i = handlers.Count; i-- > 0;) - { - var target = handlers[i].Target; - switch (target) - { - // bypass UnityEngine.Object null equality overload - case null: - continue; - case UnityEngine.Object uObj when uObj == null: - Modules.Messaging.Instance.ModuleLogger.LogDebug($"Memory leak detected : a destroyed instance of the '{target.GetType().Assembly.GetName().Name}:{target.GetType().Name}' class is holding a '{messageBus.Name}' MessageBus handler"); - messageBus.RemoveHandlerAt(i); - memoryLeaks++; - break; - } - } - } + for (var i = handlers.Count; i-- > 0;) + { + var target = handlers[i].Target; + switch (target) + { + // bypass UnityEngine.Object null equality overload + case null: + continue; + case UnityEngine.Object uObj when uObj == null: + Modules.Messaging.Instance.ModuleLogger.LogDebug( + $"Memory leak detected : a destroyed instance of the " + + $"'{target.GetType().Assembly.GetName().Name}:{target.GetType().Name}' class is holding " + + $"a '{messageBus.Name}' MessageBus handler" + ); + messageBus.RemoveHandlerAt(i); + memoryLeaks++; + break; + } + } + } - if (memoryLeaks > 0) - Modules.Messaging.Instance.ModuleLogger.LogDebug($"{memoryLeaks} detected!"); - } + if (memoryLeaks > 0) + { + Modules.Messaging.Instance.ModuleLogger.LogDebug($"{memoryLeaks} detected!"); + } + } } \ No newline at end of file diff --git a/src/SpaceWarp.Messaging/Modules/Messaging.cs b/src/SpaceWarp.Messaging/Modules/Messaging.cs index 861ca156..003f396d 100644 --- a/src/SpaceWarp.Messaging/Modules/Messaging.cs +++ b/src/SpaceWarp.Messaging/Modules/Messaging.cs @@ -2,25 +2,20 @@ namespace SpaceWarp.Modules; +/// +/// The messaging module. +/// [PublicAPI] public class Messaging : SpaceWarpModule { + /// public override string Name => "SpaceWarp.Messaging"; + internal static Messaging Instance; + + /// public override void LoadModule() { Instance = this; } - - public override void PreInitializeModule() - { - } - - public override void InitializeModule() - { - } - - public override void PostInitializeModule() - { - } } \ No newline at end of file diff --git a/src/SpaceWarpPatcher/SwinfoTransformer.cs b/src/SpaceWarp.Patches/Backend/ModInfoGenerator.cs similarity index 74% rename from src/SpaceWarpPatcher/SwinfoTransformer.cs rename to src/SpaceWarp.Patches/Backend/ModInfoGenerator.cs index 2df4b07d..c93ac99c 100644 --- a/src/SpaceWarpPatcher/SwinfoTransformer.cs +++ b/src/SpaceWarp.Patches/Backend/ModInfoGenerator.cs @@ -1,16 +1,53 @@ -using System.IO; -using System.Linq; -using System.Security.Cryptography; +using System.Security.Cryptography; using System.Text; -using BepInEx; using Newtonsoft.Json.Linq; +using SpaceWarp.Preload.API; -namespace SpaceWarpPatcher; +namespace SpaceWarp.Patches.Backend; -internal static class SwinfoTransformer +internal static class ModInfoGenerator { - - internal static JObject TransformSwinfo(JObject swinfo, string hash, DirectoryInfo directoryInfo) + public static void TransformSwinfosToModInfos() + { + var dir = new DirectoryInfo(Path.Combine(CommonPaths.GameRootPath, "GameData", "Mods")); + if (!dir.Exists) + { + return; + } + + var allSwinfos = dir.EnumerateFiles("swinfo.json", SearchOption.AllDirectories); + foreach (var swinfo in allSwinfos) + { + var directory = swinfo.Directory!; + var target = Path.Combine(directory.FullName, "modinfo.json"); + var swinfoText = File.ReadAllText(swinfo.FullName); + var swinfoData = JObject.Parse(swinfoText); + var hash = GetHashString(swinfoText); + var toCompareHash = ""; + + if (File.Exists(target)) + { + var targetModInfo = JObject.Parse(File.ReadAllText(target)); + if (targetModInfo.ContainsKey("Hash")) + { + toCompareHash = (string)(targetModInfo.GetValue("Hash") as JValue)?.Value; + } + else + { + toCompareHash = hash; + } + } + + if (hash == toCompareHash) + { + continue; + } + + File.WriteAllText(target,TransformSwinfoToModInfo(swinfoData,hash, directory).ToString()); + } + } + + private static JObject TransformSwinfoToModInfo(JObject swinfo, string hash, DirectoryInfo directoryInfo) { var addressables = Path.Combine(directoryInfo.FullName, "addressables"); string catalog = null; @@ -23,16 +60,18 @@ internal static JObject TransformSwinfo(JObject swinfo, string hash, DirectoryIn } } - string entryPoint = swinfo.TryGetValue("EntryPoint", out var value) ? value.Value() : null; + var entryPoint = swinfo.TryGetValue("EntryPoint", out var value) ? value.Value() : null; if (entryPoint != null) { - var dll = directoryInfo.EnumerateFiles("*.dll", SearchOption.TopDirectoryOnly).FirstOrDefault(); + var dll = directoryInfo.EnumerateFiles("*.dll", SearchOption.TopDirectoryOnly) + .FirstOrDefault(); + if (dll != null) { entryPoint = dll.FullName; } } - JObject target = new JObject(); + var target = new JObject(); if (catalog == null) { if (entryPoint == null) @@ -82,51 +121,21 @@ internal static JObject TransformSwinfo(JObject swinfo, string hash, DirectoryIn return target; } - + private static byte[] GetHash(string inputString) { - using (HashAlgorithm algorithm = SHA256.Create()) - return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString)); + using HashAlgorithm algorithm = SHA256.Create(); + return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString)); } private static string GetHashString(string inputString) { - StringBuilder sb = new StringBuilder(); - foreach (byte b in GetHash(inputString)) + var sb = new StringBuilder(); + foreach (var b in GetHash(inputString)) + { sb.Append(b.ToString("X2")); + } return sb.ToString(); } - - internal static void TransformModSwinfos() - { - var dir = new DirectoryInfo(Path.Combine(Paths.GameRootPath, "GameData", "Mods")); - if (!dir.Exists) return; - var allSwinfos = - dir.EnumerateFiles("swinfo.json", - SearchOption.AllDirectories); - foreach (var swinfo in allSwinfos) - { - var directory = swinfo.Directory!; - var target = Path.Combine(directory.FullName, "modinfo.json"); - var swinfoText = File.ReadAllText(swinfo.FullName); - var swinfoData = JObject.Parse(swinfoText); - var hash = GetHashString(swinfoText); - var toCompareHash = ""; - if (File.Exists(target)) - { - var targetModInfo = JObject.Parse(File.ReadAllText(target)); - if (targetModInfo.ContainsKey("Hash")) - { - toCompareHash = (string)(targetModInfo.GetValue("Hash") as JValue)?.Value; - } - else - { - toCompareHash = hash; - } - } - if (hash == toCompareHash) continue; - File.WriteAllText(target,TransformSwinfo(swinfoData,hash, directory).ToString()); - } - } } \ No newline at end of file diff --git a/src/SpaceWarp.Patches/Backend/PathsGenerator.cs b/src/SpaceWarp.Patches/Backend/PathsGenerator.cs new file mode 100644 index 00000000..0536efd4 --- /dev/null +++ b/src/SpaceWarp.Patches/Backend/PathsGenerator.cs @@ -0,0 +1,144 @@ +using System.Reflection; +using System.Text.RegularExpressions; +using BepInEx; +using BepInEx.Logging; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Newtonsoft.Json.Linq; +using SpaceWarp.Preload.API; + +namespace SpaceWarp.Patches.Backend; + +internal static class PathsGenerator +{ + private static readonly Regex InvalidCharacterRegex = new("[^a-zA-Z0-9_]"); + private static readonly Regex InvalidStartRegex = new("^[0-9].*$"); + + private static (string name, string path) GetNameAndPath(FileInfo jsonFile) + { + var path = '"' + jsonFile.Directory!.FullName.Replace("\"", "\\\"").Replace("\\", "\\\\") + '"'; + var obj = JObject.Parse(File.ReadAllText(jsonFile.FullName)); + var id = obj["mod_id"]!.Value(); + var replaced = InvalidCharacterRegex.Replace(id, "_"); + if (InvalidStartRegex.IsMatch(replaced)) + { + replaced = $"_{replaced}"; + } + + return (replaced, path); + } + + private static bool IsDisabled(FileInfo jsonFile, string[] allDisabled) + { + var obj = JObject.Parse(File.ReadAllText(jsonFile.FullName)); + + if (!obj.ContainsKey("spec")) + { + return false; + } + + if (obj["spec"]!.Value() is "1.2" or "1.0") + { + return false; + } + + return !allDisabled.Contains(obj["mod_id"]!.Value()); + } + + internal static void GenerateSpaceWarpPathsDLL(bool changed, ManualLogSource trueLogger) + { + var cacheLocation = Path.Combine(CommonPaths.BepInExRootPath, "AssemblyCache"); + + try + { + var addressablePaths = Path.Combine(cacheLocation, "SpaceWarpPaths.dll"); + if (changed || !File.Exists(addressablePaths)) + { + // Preload newtonsoft.json + try + { + Assembly.LoadFile(Path.Combine(CommonPaths.ManagedPath, "Newtonsoft.Json.dll")); + } + catch (Exception e) + { + trueLogger.LogError(e); + } + + var code = GetSpaceWarpPathsCode(); + trueLogger.LogInfo($"Compiling:\n{code}"); + var tree = CSharpSyntaxTree.ParseText(code); + var references = AppDomain.CurrentDomain.GetAssemblies() + .Where(x => !x.IsDynamic && x.Location.Length > 0) + .Select(x => MetadataReference.CreateFromFile(x.Location)) + .ToList(); + var compilation = CSharpCompilation.Create( + "SpaceWarpPaths.dll", + [tree], + references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + var result = compilation.Emit(addressablePaths); + + foreach (var diagnostic in result.Diagnostics) + { + if (diagnostic.WarningLevel == 0) + { + trueLogger.LogError($"{diagnostic.Location}: {diagnostic}"); + } + else + { + trueLogger.LogInfo($"{diagnostic.Location}: {diagnostic}"); + } + } + + if (!result.Success) + { + try + { + File.Delete(addressablePaths); + } + catch + { + //Ignored + } + } + } + + Assembly.LoadFile(addressablePaths); + } + catch (Exception e) + { + trueLogger.LogError(e); + //ignored + } + } + + private static string GetSpaceWarpPathsCode() + { + var disabledPluginsFilepath = Path.Combine(CommonPaths.BepInExRootPath, "disabled_plugins.cfg"); + var allDisabled = File.ReadAllText(disabledPluginsFilepath) + .Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + var allSwinfoPaths = new DirectoryInfo(Path.Combine(CommonPaths.BepInExRootPath, "plugins")) + .EnumerateFiles("swinfo.json", SearchOption.AllDirectories) + .Where(x => IsDisabled(x, allDisabled)); + + var gameDataMods = new DirectoryInfo(Path.Combine(CommonPaths.GameRootPath, "GameData", "Mods")); + if (gameDataMods.Exists) + { + allSwinfoPaths = allSwinfoPaths.Concat( + new DirectoryInfo(Path.Combine(CommonPaths.GameRootPath, "GameData", "Mods")) + .EnumerateFiles("swinfo.json", SearchOption.AllDirectories) + ); + } + + var allSwinfos = allSwinfoPaths.Select(GetNameAndPath); + + var code = allSwinfos.Aggregate( + "public static class SpaceWarpPaths {\n", + (current, swinfo) => $"{current}public static string {swinfo.name} = {swinfo.path};\n" + ); + code += "}"; + + return code; + } +} \ No newline at end of file diff --git a/src/SpaceWarp.Patches/Backend/RoslynCompiler.cs b/src/SpaceWarp.Patches/Backend/RoslynCompiler.cs new file mode 100644 index 00000000..99c32512 --- /dev/null +++ b/src/SpaceWarp.Patches/Backend/RoslynCompiler.cs @@ -0,0 +1,211 @@ +using System.Reflection; +using System.Text; +using BepInEx; +using BepInEx.Logging; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using SpaceWarp.Preload.API; + +namespace SpaceWarp.Patches.Backend; + +internal static class RoslynCompiler +{ + private static IEnumerable AllSourceFiles(DirectoryInfo directoryInfo) => directoryInfo + .EnumerateFiles("*.cs", SearchOption.AllDirectories) + .Select(fileInfo => fileInfo.FullName) + .ToArray(); + + /// + /// Compiles all Roslyn mods. + /// + /// The logger to use. + /// Whether the mod list changed since the last run. + public static bool CompileMods(ManualLogSource trueLogger) + { + try + { + List toLoad = + [ + "System.Collections.Immutable", + "System.Memory", + "System.Reflection.Metadata", + "System.Threading.Tasks.Extensions", + "Microsoft.CodeAnalysis", + "Microsoft.CodeAnalysis.CSharp", + "System.Runtime.CompilerServices.Unsafe", + "System.Numerics.Vectors" + ]; + + var loc = new DirectoryInfo(Assembly.GetExecutingAssembly().Location).Parent!.Parent!.FullName; + foreach (var file in toLoad) + { + trueLogger.LogInfo($"Loading: {file}"); + Assembly.LoadFile(Path.Combine(loc, "lib", $"{file}.dll")); + } + + var cacheLocation = Path.Combine(CommonPaths.BepInExRootPath, "AssemblyCache"); + var modListHash = Path.Combine(CommonPaths.BepInExRootPath, "ModListHash.txt"); + var disabledPluginsFilepath = Path.Combine(CommonPaths.BepInExRootPath, "disabled_plugins.cfg"); + + var allPluginsSwinfo = string.Join("", new DirectoryInfo(Path.Combine(CommonPaths.BepInExRootPath, "plugins")) + .EnumerateFiles("swinfo.json", SearchOption.AllDirectories) + .Select(x => File.ReadAllText(x.FullName))); + allPluginsSwinfo += File.ReadAllText(disabledPluginsFilepath); + + string hash; + using (var md5 = System.Security.Cryptography.MD5.Create()) + { + var inputBytes = Encoding.ASCII.GetBytes(allPluginsSwinfo); + var hashBytes = md5.ComputeHash(inputBytes); + var sb = new StringBuilder(); + foreach (var b in hashBytes) + { + sb.Append(b.ToString("X2")); + } + + hash = sb.ToString(); + } + + if (!File.Exists(modListHash)) + { + File.WriteAllText(modListHash, hash); + ModList.ChangedSinceLastRun = true; + } + else + { + var storedHash = File.ReadAllText(modListHash); + if (storedHash != hash) + { + File.WriteAllText(modListHash, hash); + ModList.ChangedSinceLastRun = true; + } + else + { + ModList.ChangedSinceLastRun = false; + } + } + + if (ModList.ChangedSinceLastRun) + { + if (Directory.Exists(cacheLocation)) + { + Directory.Delete(cacheLocation, true); + } + } + + if (!Directory.Exists(cacheLocation)) + { + Directory.CreateDirectory(cacheLocation); + } + + trueLogger.LogInfo("Loaded assemblies"); + // So now we can compile roslyn based mods by first importing every precompiled DLL + var pluginsFilePath = new DirectoryInfo(Path.Combine(CommonPaths.BepInExRootPath, "plugins")); + // So now we do a loop and generate a reference table to every plugin name that does not start with "roslyn-" + // And we keep track of every folder that contains a src folder + + var references = AppDomain.CurrentDomain.GetAssemblies() + .Where(x => !x.IsDynamic && x.Location.Length > 0) + .Select(x => MetadataReference.CreateFromFile(x.Location)) + .ToList(); + + foreach (var file in pluginsFilePath.EnumerateFiles("*.dll", SearchOption.AllDirectories)) + { + if (file.Name.StartsWith("roslyn-")) + { + File.Delete(file.FullName); + } + else + { + references.Add(MetadataReference.CreateFromFile(file.FullName)); + } + } + + foreach (var directory in pluginsFilePath.EnumerateDirectories("src", SearchOption.AllDirectories)) + { + var parent = directory.Parent; + if (parent == null || !File.Exists(Path.Combine(parent.FullName, "swinfo.json"))) + { + continue; + } + + var id = parent.Name; + + var logger = Logger.CreateLogSource($"{parent.Name} compilation"); + var allSource = AllSourceFiles(directory); + var latestWriteTime = DateTime.FromBinary(0); + + var resultFileName = $"roslyn-{id}"; + var cached = Path.Combine(cacheLocation, resultFileName); + var cachedDLL = $"{cached}.dll"; + + var combined = Path.Combine(parent.FullName, resultFileName); + var dll = $"{combined}.dll"; + + if (File.Exists(cachedDLL)) + { + if (File.GetLastWriteTime(cachedDLL) < latestWriteTime) + { + File.Delete(cachedDLL); + } + else + { + File.Copy(cachedDLL, dll); + continue; + } + } + + var trees = allSource.Select(x => (filename: x, text: File.ReadAllText(x))) + .Select(code => CSharpSyntaxTree.ParseText( + code.text, + CSharpParseOptions.Default, + code.filename, Encoding.UTF8 + )) + .ToList(); + var compilation = CSharpCompilation.Create( + $"{resultFileName}.dll", + trees, + references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + var result = compilation.Emit(cachedDLL); + foreach (var diagnostic in result.Diagnostics) + { + if (diagnostic.WarningLevel == 0) + { + logger.LogError(diagnostic.Location + ": " + diagnostic); + } + else + { + logger.LogInfo(diagnostic.Location + ": " + diagnostic); + } + } + + if (!result.Success) + { + try + { + File.Delete(cachedDLL); + } + catch + { + //Ignored + } + + continue; + } + + File.Copy(cachedDLL, dll); + references.Add(MetadataReference.CreateFromFile(dll)); + } + } + catch (Exception e) + { + trueLogger.LogError(e); + trueLogger.LogInfo(e.StackTrace); + return true; + } + + return ModList.ChangedSinceLastRun; + } +} \ No newline at end of file diff --git a/src/SpaceWarp.Patches/ChainloaderPatch.cs b/src/SpaceWarp.Patches/ChainloaderPatch.cs new file mode 100644 index 00000000..62dfbff1 --- /dev/null +++ b/src/SpaceWarp.Patches/ChainloaderPatch.cs @@ -0,0 +1,77 @@ +using BepInEx; +using BepInEx.Bootstrap; +using BepInEx.Logging; +using HarmonyLib; +using Mono.Cecil.Cil; +using MonoMod.Cil; +using SpaceWarp.Patches.Backend; +using SpaceWarp.Preload; +using SpaceWarp.Preload.API; + +namespace SpaceWarp.Patches; + +/// +/// Patches BepInEx's Chainloader.Start method to disable plugins, generate the mod paths DLL, compile Roslyn mods +/// and transform swinfo files to modinfo files. +/// +[HarmonyPatch] +internal static class ChainloaderPatch +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(Chainloader), nameof(Chainloader.Start))] + private static void PreStartActions() + { + var trueLogger = Logger.CreateLogSource("Roslyn Compiler"); + + // Compile Roslyn mods + var changed = RoslynCompiler.CompileMods(trueLogger); + + // Generate the mod paths DLL + PathsGenerator.GenerateSpaceWarpPathsDLL(changed, trueLogger); + + try + { + // Transform swinfo files in the internal mod loader folder to modinfo files + ModInfoGenerator.TransformSwinfosToModInfos(); + } + catch (Exception e) + { + trueLogger.LogError(e.ToString()); + } + } + + private static bool CheckIfModIsDisabled(PluginInfo plugin, HashSet deniedSet) + { + if (Array.IndexOf(ModList.DisabledPluginGuids, plugin.Metadata.GUID) == -1) + { + return true; + } + + deniedSet.Add(plugin.Metadata.GUID); + ModList.DisabledPlugins.Add(plugin); + Entrypoint.LogSource.LogInfo($"{plugin.Metadata.GUID} was disabled, skipping loading..."); + return false; + + } + [HarmonyILManipulator] + [HarmonyPatch(typeof(Chainloader), nameof(Chainloader.Start))] + private static void DisablePluginsIL(ILContext il) + { + ILCursor c = new(il); + + ILLabel continueLabel = default; + c.GotoNext( + MoveType.After, + // this is from a continue, we use this to start the next iteration: + x => x.MatchBrfalse(out continueLabel), + x => x.MatchLdcI4(0), // false + x => x.MatchStloc(24) // someBool = false + ); + + c.Emit(OpCodes.Ldloc, 23); // current PluginInfo + c.Emit(OpCodes.Ldloc, 5); // set of denied plugins so far + // false means skip to this plugin, true means continue loading it + c.EmitDelegate(CheckIfModIsDisabled); + c.Emit(OpCodes.Brfalse, continueLabel); + } +} \ No newline at end of file diff --git a/src/SpaceWarpPatcher/AssemblyCSharpPatcher.cs b/src/SpaceWarp.Patches/ResourceFlowPatch.cs similarity index 60% rename from src/SpaceWarpPatcher/AssemblyCSharpPatcher.cs rename to src/SpaceWarp.Patches/ResourceFlowPatch.cs index 91318da2..c8c29214 100644 --- a/src/SpaceWarpPatcher/AssemblyCSharpPatcher.cs +++ b/src/SpaceWarp.Patches/ResourceFlowPatch.cs @@ -1,67 +1,63 @@ -using BepInEx; -using BepInEx.Logging; -using JetBrains.Annotations; +using JetBrains.Annotations; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using MonoMod.Cil; using MonoMod.Utils; +using SpaceWarp.Preload.API; -namespace SpaceWarpPatcher; - +namespace SpaceWarp.Patches; +/// +/// Patches the game so that parts can register their own resource flow requests. +/// [UsedImplicitly] -public class AssemblyCSharpPatcher +internal class ResourceFlowPatch : BasePatcher { + /// + /// The target DLLs to patch + /// [UsedImplicitly] - public static IEnumerable TargetDLLs => new[] { "Assembly-CSharp.dll"}; - + public override IEnumerable DLLsToPatch => ["Assembly-CSharp.dll"]; + /// + /// Patches the target DLL + /// + /// The assembly definition to patch [UsedImplicitly] - public static void Patch(ref AssemblyDefinition assemblyDefinition) + public override void ApplyPatch(ref AssemblyDefinition assemblyDefinition) { - // AssemblyDefinition coreAssembly = null; - // var dir = new DirectoryInfo(Paths.PluginPath); - // foreach (var file in dir.EnumerateFiles("SpaceWarp.Core.dll", SearchOption.AllDirectories)) - // { - // coreAssembly = AssemblyDefinition.ReadAssembly(file.FullName); - // } - // - // if (coreAssembly == null) - // { - // throw new Exception("Could not find SpaceWarp Core"); - // } - var firstTargetType = assemblyDefinition.MainModule.Types.First(t => t.Name == "PartOwnerComponent"); var boolType = firstTargetType.Fields - .Select(x => x.FieldType).First(x => x.MetadataType == MetadataType.Boolean)!; - firstTargetType.Fields.Add(new FieldDefinition("HasRegisteredPartComponentsForFixedUpdate",FieldAttributes.Public,boolType)); + .Select(x => x.FieldType) + .First(x => x.MetadataType == MetadataType.Boolean)!; + firstTargetType.Fields.Add( + new FieldDefinition("HasRegisteredPartComponentsForFixedUpdate", FieldAttributes.Public, boolType) + ); var field = firstTargetType.Fields.First(x => x.Name == "HasRegisteredPartComponentsForFixedUpdate"); - // Now later we harmony patch the initializer for partownercomponent - + // Now later we harmony patch the initializer for PartOwnerComponent + var targetMethod = firstTargetType.Methods.First(method => method.Name == "OnFixedUpdate"); - var methodCallA = assemblyDefinition.MainModule.Types.First(t => t.Name == "ResourceFlowRequestManager").Methods + var methodCallA = assemblyDefinition.MainModule.Types + .First(t => t.Name == "ResourceFlowRequestManager") + .Methods .First(m => m.Name == "UpdateFlowRequests"); var methodCallB = firstTargetType.Properties - .First(definition => definition.Name == "ResourceFlowRequestManager").GetMethod; - // var context = new ILContext(targetMethod); - // var cursor = new ILCursor(context); - // var elseEndLabel = cursor.DefineLabel(); - // var elseBeginLabel = cursor.DefineLabel(); - // cursor.GotoNext(MoveType.Before) - // cursor.GotoNext(MoveType.After, instruction => instruction.MatchCallOrCallvirt(methodCallA)); - var insts = targetMethod.Body.Instructions; - Collection newInstructions = new Collection(); + .First(definition => definition.Name == "ResourceFlowRequestManager") + .GetMethod; + + var instructions = targetMethod.Body.Instructions; + var newInstructions = new Collection(); var nextIsTarget = false; Instruction done = null; Instruction @else = null; - foreach (var currentInstruction in insts) + foreach (var currentInstruction in instructions) { if (nextIsTarget) { done = currentInstruction; nextIsTarget = false; - } + } newInstructions.Add(currentInstruction); if (!currentInstruction.MatchCallOrCallvirt(methodCallA)) continue; nextIsTarget = true; @@ -69,9 +65,9 @@ public static void Patch(ref AssemblyDefinition assemblyDefinition) newInstructions.Add(Instruction.Create(OpCodes.Ldarg_0)); @else = newInstructions.Last(); newInstructions.Add(Instruction.Create(OpCodes.Ldfld,field)); - newInstructions.Add(Instruction.Create(OpCodes.Ldarg_3)); + newInstructions.Add(Instruction.Create(OpCodes.Ldarg_3)); newInstructions.Add(Instruction.Create(OpCodes.Ldarg_0)); - newInstructions.Add(Instruction.Create(OpCodes.Call, methodCallB)); + newInstructions.Add(Instruction.Create(OpCodes.Call, methodCallB)); newInstructions.Add(Instruction.Create(OpCodes.Ldarg_1)); newInstructions.Add(Instruction.Create(OpCodes.Ldarg_2)); newInstructions.Add(Instruction.Create(OpCodes.Callvirt, methodCallA)); @@ -97,20 +93,19 @@ public static void Patch(ref AssemblyDefinition assemblyDefinition) { newInstructions[i] = Instruction.Create(OpCodes.Bne_Un_S, @else); } - + if (currentInstruction.OpCode == OpCodes.Nop) { newInstructions[i] = Instruction.Create(OpCodes.Br_S, done); } - + if (currentInstruction.OpCode == OpCodes.Ldarg_3) { newInstructions[i] = Instruction.Create(OpCodes.Brfalse_S, done); } } - - - insts.Clear(); - insts.AddRange(newInstructions); + + instructions.Clear(); + instructions.AddRange(newInstructions); } } \ No newline at end of file diff --git a/src/SpaceWarp.Patches/SpaceWarp.Patches.csproj b/src/SpaceWarp.Patches/SpaceWarp.Patches.csproj new file mode 100644 index 00000000..e5191e9c --- /dev/null +++ b/src/SpaceWarp.Patches/SpaceWarp.Patches.csproj @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/SpaceWarp.Patches/UnityCoreModulePatch.cs b/src/SpaceWarp.Patches/UnityCoreModulePatch.cs new file mode 100644 index 00000000..84250134 --- /dev/null +++ b/src/SpaceWarp.Patches/UnityCoreModulePatch.cs @@ -0,0 +1,43 @@ +using HarmonyLib; +using JetBrains.Annotations; +using Mono.Cecil; +using Mono.Cecil.Cil; +using MonoMod.Cil; +using SpaceWarp.Preload.API; + +namespace SpaceWarp.Patches; + +[UsedImplicitly] +internal class UnityCoreModulePatch : BasePatcher +{ + public override IEnumerable DLLsToPatch { get; } = ["UnityEngine.CoreModule.dll"]; + public override void ApplyPatch(ref AssemblyDefinition assembly) + { + // is this necessary? I (Windows10CE) didn't think so until i had to do it! + var targetType = assembly.MainModule.GetType("UnityEngine.Application"); + var targetMethod = targetType.Methods.Single(x => x.Name == ".cctor"); + + using var thisAsm = AssemblyDefinition.ReadAssembly(typeof(UnityCoreModulePatch).Assembly.Location); + var delayer = thisAsm.MainModule.GetType("SpaceWarp.Patches.Delayer"); + var patchMethod = delayer.Methods.Single(m => m.Name == "PatchChainloaderStart"); + + var il = new ILContext(targetMethod); + var c = new ILCursor(il); + c.GotoNext( + MoveType.Before, + x => x.MatchCall("BepInEx.Bootstrap.Chainloader", "Start") + ); + + c.Emit(OpCodes.Call, il.Module.ImportReference(patchMethod)); + } +} + +internal static class Delayer +{ + [UsedImplicitly] + private static void PatchChainloaderStart() + { + ModList.Initialize(); + Harmony.CreateAndPatchAll(typeof(ChainloaderPatch)); + } +} \ No newline at end of file diff --git a/src/SpaceWarp.Preload/API/BasePatcher.cs b/src/SpaceWarp.Preload/API/BasePatcher.cs new file mode 100644 index 00000000..ae45daff --- /dev/null +++ b/src/SpaceWarp.Preload/API/BasePatcher.cs @@ -0,0 +1,24 @@ +using BepInEx.Logging; +using JetBrains.Annotations; +using Mono.Cecil; + +namespace SpaceWarp.Preload.API; + +/// +/// Base class of a SpaceWarp wrapper for BepInEx preload patchers. Runs conditionally based on whether the mod is +/// enabled. +/// +[PublicAPI] +public abstract class BasePatcher : IPatcher +{ + /// + /// Logger for the patcher. + /// + protected internal ManualLogSource Logger; + + /// + public abstract IEnumerable DLLsToPatch { get; } + + /// + public abstract void ApplyPatch(ref AssemblyDefinition assembly); +} \ No newline at end of file diff --git a/src/SpaceWarp.Preload/API/CommonPaths.cs b/src/SpaceWarp.Preload/API/CommonPaths.cs new file mode 100644 index 00000000..5981f870 --- /dev/null +++ b/src/SpaceWarp.Preload/API/CommonPaths.cs @@ -0,0 +1,46 @@ +using JetBrains.Annotations; + +namespace SpaceWarp.Preload.API; + +/// +/// Contains paths to various directories. +/// +[PublicAPI] +public static class CommonPaths +{ + /// + /// Path to the game's root directory. + /// + public static string GameRootPath { get; } = Path.GetDirectoryName( + Environment.GetEnvironmentVariable("DOORSTOP_PROCESS_PATH") + ); + + /// + /// Path to the game's Managed directory. + /// + public static string ManagedPath { get; } = Path.Combine( + GameRootPath, + $"{Path.GetFileNameWithoutExtension(Environment.GetEnvironmentVariable("DOORSTOP_PROCESS_PATH"))}_Data", + "Managed" + ); + + /// + /// Path to the BepInEx root directory. + /// + public static string BepInExRootPath { get; } = Path.Combine(GameRootPath, "BepInEx"); + + /// + /// Path to the BepInEx plugins directory. + /// + public static string BepInExPluginsPath { get; } = Path.Combine(BepInExRootPath, "plugins"); + + /// + /// Path to the internal mod loader Mods directory. + /// + public static string InternalModLoaderPath { get; } = Path.Combine(GameRootPath, "GameData", "Mods"); + + /// + /// Path to the file containing the list of disabled plugins. + /// + public static string DisabledPluginsFilepath { get; } = Path.Combine(BepInExRootPath, "disabled_plugins.cfg"); +} \ No newline at end of file diff --git a/src/SpaceWarp.Preload/API/IPatcher.cs b/src/SpaceWarp.Preload/API/IPatcher.cs new file mode 100644 index 00000000..24c7059a --- /dev/null +++ b/src/SpaceWarp.Preload/API/IPatcher.cs @@ -0,0 +1,22 @@ +using JetBrains.Annotations; +using Mono.Cecil; + +namespace SpaceWarp.Preload.API; + +/// +/// SpaceWarp wrapper for BepInEx preload patchers. Runs conditionally based on whether the mod is enabled. +/// +[PublicAPI] +public interface IPatcher +{ + /// + /// The target DLLs to patch. + /// + public IEnumerable DLLsToPatch { get; } + + /// + /// Patch the target assembly. + /// + /// The target assembly. + public void ApplyPatch(ref AssemblyDefinition assembly); +} \ No newline at end of file diff --git a/src/SpaceWarp.Preload/API/ModList.cs b/src/SpaceWarp.Preload/API/ModList.cs new file mode 100644 index 00000000..a5e6f35e --- /dev/null +++ b/src/SpaceWarp.Preload/API/ModList.cs @@ -0,0 +1,37 @@ +using BepInEx; + +namespace SpaceWarp.Preload.API; + +/// +/// Contains methods related to the mod list. +/// +internal static class ModList +{ + /// + /// The list of all disabled plugin GUIDs. + /// + internal static string[] DisabledPluginGuids { get; private set; } + + /// + /// The list of all disabled plugins. + /// + internal static List DisabledPlugins { get; } = []; + + /// + /// Whether the mod list changed since the last run. + /// + public static bool ChangedSinceLastRun { get; internal set; } + + internal static void Initialize() + { + if (!File.Exists(CommonPaths.DisabledPluginsFilepath)) + { + File.Create(CommonPaths.DisabledPluginsFilepath).Dispose(); + Entrypoint.LogSource.LogWarning( + $"Disabled plugins file did not exist, created empty file at: {CommonPaths.DisabledPluginsFilepath}" + ); + } + + DisabledPluginGuids = File.ReadAllLines(CommonPaths.DisabledPluginsFilepath); + } +} \ No newline at end of file diff --git a/src/SpaceWarpPatcher/Directory.Build.props b/src/SpaceWarp.Preload/Directory.Build.props similarity index 100% rename from src/SpaceWarpPatcher/Directory.Build.props rename to src/SpaceWarp.Preload/Directory.Build.props diff --git a/src/SpaceWarp.Preload/Entrypoint.cs b/src/SpaceWarp.Preload/Entrypoint.cs new file mode 100644 index 00000000..c5c1efae --- /dev/null +++ b/src/SpaceWarp.Preload/Entrypoint.cs @@ -0,0 +1,142 @@ +using System.Reflection; +using BepInEx.Logging; +using JetBrains.Annotations; +using Mono.Cecil; +using Newtonsoft.Json.Linq; +using SpaceWarp.Preload.API; + +namespace SpaceWarp.Preload; + +/// +/// Patcher for the UnityEngine.CoreModule assembly. +/// +[UsedImplicitly] +public static class Entrypoint +{ + internal static ManualLogSource LogSource; + + private static readonly List Patchers = []; + + /// + /// The target DLLs to patch. + /// + [UsedImplicitly] + public static IEnumerable TargetDLLs + { + get + { + LogSource = Logger.CreateLogSource("SpaceWarp.Preload"); + AddEnabledPatchers(); + return Patchers.SelectMany(patcher => patcher.DLLsToPatch).ToList(); + } + } + + /// + /// Patch the target assembly. + /// + /// The target assembly. + [UsedImplicitly] + public static void Patch(ref AssemblyDefinition asm) + { + var assemblyPath = Path.GetFileName(asm.MainModule.FileName); + + foreach (var patcher in Patchers.Where(patcher => patcher.DLLsToPatch.Contains(assemblyPath))) + { + LogSource.LogInfo($"Patching {assemblyPath} with {patcher.GetType().Name}"); + patcher.ApplyPatch(ref asm); + } + } + + private static void AddEnabledPatchers() + { + var disabledPluginGuids = GetDisabledPluginGuids(); + + var swinfoPaths = Directory + .EnumerateFiles( + CommonPaths.BepInExPluginsPath, + "swinfo.json", + SearchOption.AllDirectories + ) + .ToList(); + if (Directory.Exists(CommonPaths.InternalModLoaderPath)) + { + swinfoPaths.AddRange( + Directory.EnumerateFiles( + CommonPaths.InternalModLoaderPath, + "swinfo.json", + SearchOption.AllDirectories + ) + ); + } + + foreach (var swinfoPath in swinfoPaths) + { + try + { + var guid = GetGuidFromSwinfo(swinfoPath); + if (disabledPluginGuids.Contains(guid)) + { + continue; + } + + // Check all DLLs in the mod folder for classes extending BasePatcher using Mono.Cecil + // If any are found, add them to the list of patchers to enable + var modFolder = Path.GetDirectoryName(swinfoPath)!; + var dlls = Directory.EnumerateFiles( + modFolder, + "*.dll", + SearchOption.AllDirectories + ); + + foreach (var dll in dlls) + { + AddPatchersFromDLL(dll); + } + + } + catch (Exception ex) + { + LogSource.LogError($"An error occurred while processing {swinfoPath}:\n{ex}"); + } + } + } + + private static void AddPatchersFromDLL(string dllPath) + { + using var asm = AssemblyDefinition.ReadAssembly(dllPath); + var patcherTypes = asm.MainModule.Types.Where( + type => !type.IsAbstract && type.BaseType?.FullName == "SpaceWarp.Preload.API.BasePatcher" + ); + + foreach (var patcherType in patcherTypes) + { + LogSource.LogInfo($"Found patcher: {patcherType.Name}"); + var loadedAsm = Assembly.LoadFile(dllPath); + var patcher = (BasePatcher)Activator.CreateInstance(loadedAsm.GetType(patcherType.FullName)); + patcher.Logger = Logger.CreateLogSource(patcherType.Name); + Patchers.Add(patcher); + } + } + + private static string[] GetDisabledPluginGuids() + { + var disabledPluginsPath = CommonPaths.DisabledPluginsFilepath; + + return File.Exists(disabledPluginsPath) + ? File.ReadAllLines(disabledPluginsPath) + : []; + } + + private static string GetGuidFromSwinfo(string swinfoPath) + { + var swinfo = JObject.Parse(File.ReadAllText(swinfoPath)); + + var guid = swinfo["mod_id"]?.Value(); + if (guid == null) + { + throw new Exception($"{swinfoPath} does not contain a mod_id."); + } + + return guid; + } +} \ No newline at end of file diff --git a/src/SpaceWarp.Preload/Properties/AssemblyInfo.cs b/src/SpaceWarp.Preload/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..2103ebc1 --- /dev/null +++ b/src/SpaceWarp.Preload/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("SpaceWarp.Core")] +[assembly: InternalsVisibleTo("SpaceWarp.Patches")] +[assembly: InternalsVisibleTo("SpaceWarp.UI")] \ No newline at end of file diff --git a/src/SpaceWarpPatcher/SpaceWarpPatcher.csproj b/src/SpaceWarp.Preload/SpaceWarp.Preload.csproj similarity index 94% rename from src/SpaceWarpPatcher/SpaceWarpPatcher.csproj rename to src/SpaceWarp.Preload/SpaceWarp.Preload.csproj index c304ba38..f7720300 100644 --- a/src/SpaceWarpPatcher/SpaceWarpPatcher.csproj +++ b/src/SpaceWarp.Preload/SpaceWarp.Preload.csproj @@ -4,7 +4,7 @@ - + diff --git a/src/SpaceWarp.Sound/API/Sound/Soundbank.cs b/src/SpaceWarp.Sound/API/Sound/Soundbank.cs index 50a40657..c9e1d66e 100644 --- a/src/SpaceWarp.Sound/API/Sound/Soundbank.cs +++ b/src/SpaceWarp.Sound/API/Sound/Soundbank.cs @@ -1,12 +1,18 @@ -using System; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using JetBrains.Annotations; namespace SpaceWarp.API.Sound; +/// +/// Represents a Soundbank. +/// [PublicAPI] public class Soundbank { + /// + /// Creates a Soundbank object from bytes. + /// + /// The bytes of the Soundbank. public Soundbank(byte[] bankData) { BankData = bankData; @@ -43,6 +49,10 @@ public Soundbank(byte[] bankData) /// public uint WwiseID; + /// + /// Loads the Soundbank. + /// + /// The result of the operation. public AKRESULT Load() { // Pins BankData array in memory diff --git a/src/SpaceWarp.Sound/API/Sound/SoundbankManager.cs b/src/SpaceWarp.Sound/API/Sound/SoundbankManager.cs index 7e1466f0..7f1f92e1 100644 --- a/src/SpaceWarp.Sound/API/Sound/SoundbankManager.cs +++ b/src/SpaceWarp.Sound/API/Sound/SoundbankManager.cs @@ -1,11 +1,20 @@ using JetBrains.Annotations; -using System.Collections.Generic; namespace SpaceWarp.API.Sound; +/// +/// Manages Soundbanks. +/// [PublicAPI] public static class SoundbankManager { + /// + /// Loads a Soundbank from bytes. + /// + /// The internal path of the Soundbank. + /// The bytes of the Soundbank. + /// The loaded Soundbank. + /// Whether the Soundbank was loaded successfully. public static bool LoadSoundbank(string internalPath, byte[] bankData, out Soundbank soundbank) { var bank = new Soundbank(bankData); @@ -24,11 +33,22 @@ public static bool LoadSoundbank(string internalPath, byte[] bankData, out Sound return true; } + /// + /// Gets a Soundbank by its internal path. + /// + /// The internal path of the Soundbank. + /// The Soundbank. public static Soundbank GetSoundbank(string internalPath) { return LoadedSoundbanks[internalPath]; } + /// + /// Tries to get a Soundbank by its internal path. + /// + /// The internal path of the Soundbank. + /// The Soundbank. + /// Whether the Soundbank was found. public static bool TryGetSoundbank(string internalPath, out Soundbank soundbank) { return LoadedSoundbanks.TryGetValue(internalPath, out soundbank); diff --git a/src/SpaceWarp.Sound/Modules/Sound.cs b/src/SpaceWarp.Sound/Modules/Sound.cs index 1497d6a2..32f45622 100644 --- a/src/SpaceWarp.Sound/Modules/Sound.cs +++ b/src/SpaceWarp.Sound/Modules/Sound.cs @@ -1,39 +1,30 @@ -using System; -using System.Collections.Generic; -using System.IO; -using JetBrains.Annotations; +using JetBrains.Annotations; using SpaceWarp.API.Loading; using SpaceWarp.API.Sound; using UnityObject = UnityEngine.Object; namespace SpaceWarp.Modules; +/// +/// Module that handles sound. +/// [UsedImplicitly] public class Sound : SpaceWarpModule { + /// public override string Name => "SpaceWarp.Sound"; + internal static Sound Instance; private const string SoundbanksFolder = "soundbanks"; + /// public override void LoadModule() { Instance = this; Loading.AddAssetLoadingAction(SoundbanksFolder, "loading soundbanks", AssetSoundbankLoadingAction, "bnk"); } - public override void PreInitializeModule() - { - } - - public override void InitializeModule() - { - } - - public override void PostInitializeModule() - { - } - private static List<(string name, UnityObject asset)> AssetSoundbankLoadingAction( string internalPath, string filename diff --git a/src/SpaceWarp.UI/API/Lua/AppBarInterop.cs b/src/SpaceWarp.UI/API/Lua/AppBarInterop.cs index 6fe42aa6..fd9821eb 100644 --- a/src/SpaceWarp.UI/API/Lua/AppBarInterop.cs +++ b/src/SpaceWarp.UI/API/Lua/AppBarInterop.cs @@ -1,5 +1,4 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; using MoonSharp.Interpreter; using SpaceWarp.API.Assets; using SpaceWarp.API.UI.Appbar; @@ -8,15 +7,32 @@ namespace SpaceWarp.API.Lua; +/// +/// Lua API for the AppBar. +/// [SpaceWarpLuaAPI("AppBar")] [PublicAPI] public static class AppBarInterop { + /// + /// Gets a sprite from a texture path. + /// + /// Path to the texture. + /// Width of the sprite. + /// Height of the sprite. + /// The sprite. public static Sprite GetSprite(string texturePath, int width = 0, int height = 0) { return GetSprite(AssetManager.GetAsset(texturePath)); } + /// + /// Gets a sprite from a texture. + /// + /// The texture. + /// Width of the sprite. + /// Height of the sprite. + /// public static Sprite GetSprite(Texture2D texture, int width = 0, int height = 0) { if (width == 0) @@ -32,11 +48,21 @@ public static Sprite GetSprite(Texture2D texture, int width = 0, int height = 0) return Sprite.Create(texture, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f)); } + /// + /// Registers an app button. + /// + /// Whether the button should be registered in the OAB. + /// Whether the button should be registered in flight. + /// The text of the button. + /// The ID of the button. + /// The icon of the button. + /// The callback to be called when the button is toggled. + /// The self parameter for the callback. public static void RegisterAppButton( bool oab, bool inFlight, string name, - string ID, + string id, Sprite icon, Closure toggleCallback, [CanBeNull] DynValue self = null @@ -54,30 +80,51 @@ public static void RegisterAppButton( if (oab) { - Appbar.RegisterAppButton(name, ID, icon, callback); + Appbar.RegisterAppButton(name, id, icon, callback); } if (inFlight) { - Appbar.RegisterOABAppButton(name, ID, icon, callback); + Appbar.RegisterOABAppButton(name, id, icon, callback); } } + /// + /// Registers an app button. + /// + /// Whether the button should be registered in the OAB. + /// Whether the button should be registered in flight. + /// The text of the button. + /// The ID of the button. + /// The path to the texture of the button. + /// The callback to be called when the button is toggled. + /// The self parameter for the callback. public static void RegisterAppButton( bool oab, bool inFlight, string name, - string ID, + string id, string texturePath, Closure toggleCallback, [CanBeNull] DynValue self = null - ) => RegisterAppButton(oab, inFlight, name, ID, GetSprite(texturePath), toggleCallback, self); + ) => RegisterAppButton(oab, inFlight, name, id, GetSprite(texturePath), toggleCallback, self); + /// + /// Registers an app window. + /// + /// Whether the window should be registered in the OAB. + /// Whether the window should be registered in flight. + /// The text of the button that opens the window. + /// The ID of the button that opens the window. + /// The icon of the button that opens the window. + /// The window. + /// The callback to be called when the button is toggled. + /// The self parameter for the callback. public static void RegisterAppWindow( bool oab, bool inFlight, string name, - string ID, + string id, Sprite icon, VisualElement window, Closure toggleCallback, @@ -104,26 +151,42 @@ public static void RegisterAppWindow( if (oab) { - Appbar.RegisterAppButton(name, ID, icon, callback); + Appbar.RegisterAppButton(name, id, icon, callback); } if (inFlight) { - Appbar.RegisterOABAppButton(name, ID, icon, callback); + Appbar.RegisterOABAppButton(name, id, icon, callback); } } + /// + /// Registers an app window. + /// + /// Whether the window should be registered in the OAB. + /// Whether the window should be registered in flight. + /// The text of the button that opens the window. + /// The ID of the button that opens the window. + /// The path to the texture of the button that opens the window. + /// The window. + /// The callback to be called when the button is toggled. + /// The self parameter for the callback. public static void RegisterAppWindow( bool oab, bool inFlight, string name, - string ID, + string id, string texturePath, VisualElement window, Closure toggleCallback, [CanBeNull] DynValue self = null - ) => RegisterAppWindow(oab, inFlight, name, ID, GetSprite(texturePath), window, toggleCallback, self); + ) => RegisterAppWindow(oab, inFlight, name, id, GetSprite(texturePath), window, toggleCallback, self); + /// + /// Sets the indicator of an app button. + /// + /// The ID of the button. + /// Whether the indicator should be set. public static void SetAppButtonIndicator(string id, bool b) { Appbar.SetAppBarButtonIndicator(id, b); diff --git a/src/SpaceWarp.UI/API/UI/Appbar/Appbar.cs b/src/SpaceWarp.UI/API/UI/Appbar/Appbar.cs index af009f94..2bab0e54 100644 --- a/src/SpaceWarp.UI/API/UI/Appbar/Appbar.cs +++ b/src/SpaceWarp.UI/API/UI/Appbar/Appbar.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using BepInEx.Bootstrap; using JetBrains.Annotations; using KSP.UI.Binding; @@ -9,17 +7,20 @@ namespace SpaceWarp.API.UI.Appbar; +/// +/// Used to register buttons on the game's AppBar. +/// [PublicAPI] public static class Appbar { private static readonly List<(string text, Sprite icon, string ID, Action action)> ButtonsToBeLoaded = new(); - private static readonly List<(string text, Sprite icon, string ID, Action action)> OABButtonsToBeLoaded = new(); + private static readonly List<(string text, Sprite icon, string ID, Action action)> OabButtonsToBeLoaded = new(); - private static readonly List<(string text, Sprite icon, string ID, Action action)> KSCButtonsToBeLoaded = new(); + private static readonly List<(string text, Sprite icon, string ID, Action action)> KscButtonsToBeLoaded = new(); /// - /// Register an appbar menu for the game + /// Register an AppBar menu for the game. /// /// The text in the appbar menu /// The title of the menu @@ -27,6 +28,7 @@ public static class Appbar /// A Sprite for the icon in the appbar /// The type of the appbar menu, must extend AppbarMenu /// An instance of T which has been added to a GameObject +#pragma warning disable CS0618 // Type or member is obsolete public static T RegisterGameAppbarMenu(string text, string title, string id, Sprite icon) where T : AppbarMenu { var toolBarUIObject = new GameObject($"Toolbar: {id}"); @@ -37,11 +39,11 @@ public static T RegisterGameAppbarMenu(string text, string title, string id, toolBarUIObject.transform.SetParent(Chainloader.ManagerObject.transform); toolBarUIObject.SetActive(true); ButtonsToBeLoaded.Add((text, icon, id, menu.ToggleGUI)); - return menu as T; + return (T)menu; } /// - /// Register a appbar menu for the game + /// Register an AppBar menu for the game. /// /// The text in the appbar menu /// The title of the menu @@ -53,9 +55,10 @@ public static T RegisterGameAppbarMenu(string text, string title, string id, { return RegisterGameAppbarMenu(text, title, id, GetAppBarIconFromTexture(icon)); } +#pragma warning restore CS0618 // Type or member is obsolete /// - /// Register a button on the games AppBar + /// Register a button on the game's AppBar /// /// The text in the appbar menu /// A unique id for the appbar menu eg: "BTN-Example" @@ -67,7 +70,7 @@ public static void RegisterAppButton(string text, string id, Sprite icon, Action } /// - /// Register a button on the games AppBar + /// Register a button on the game's AppBar /// /// The text in the appbar menu /// A unique id for the appbar menu eg: "BTN-Example" @@ -85,9 +88,10 @@ public static void RegisterAppButton(string text, string id, Texture2D icon, Act /// A unique id for the appbar menu eg: "BTN-ExampleOAB" /// A Sprite for the icon in the appbar /// The function to be called when this button is clicked + // ReSharper disable once InconsistentNaming public static void RegisterOABAppButton(string text, string id, Sprite icon, Action func) { - OABButtonsToBeLoaded.Add((text, icon, id, func)); + OabButtonsToBeLoaded.Add((text, icon, id, func)); } /// @@ -97,6 +101,7 @@ public static void RegisterOABAppButton(string text, string id, Sprite icon, Act /// A unique id for the appbar menu eg: "BTN-ExampleOAB" /// A Texture2D for the icon in the appbar /// The function to be called when this button is clicked + // ReSharper disable once InconsistentNaming public static void RegisterOABAppButton(string text, string id, Texture2D icon, Action func) { RegisterOABAppButton(text, id, GetAppBarIconFromTexture(icon), func); @@ -109,9 +114,10 @@ public static void RegisterOABAppButton(string text, string id, Texture2D icon, /// A unique id for the appbar menu eg: "BTN-ExampleKSC" /// A Sprite for the icon in the appbar /// The function to be called when this button is clicked + // ReSharper disable once InconsistentNaming public static void RegisterKSCAppButton(string text, string id, Sprite icon, Action func) { - KSCButtonsToBeLoaded.Add((text, icon, id, func)); + KscButtonsToBeLoaded.Add((text, icon, id, func)); } /// @@ -121,6 +127,7 @@ public static void RegisterKSCAppButton(string text, string id, Sprite icon, Act /// A unique id for the appbar menu eg: "BTN-ExampleKSC" /// A Texture2D for the icon in the appbar /// The function to be called when this button is clicked + // ReSharper disable once InconsistentNaming public static void RegisterKSCAppButton(string text, string id, Texture2D icon, Action func) { RegisterKSCAppButton(text, id, GetAppBarIconFromTexture(icon), func); @@ -167,17 +174,19 @@ internal static void LoadAllButtons() } } + // ReSharper disable once InconsistentNaming internal static void LoadOABButtons() { - foreach (var button in OABButtonsToBeLoaded) + foreach (var button in OabButtonsToBeLoaded) { AppbarBackend.AddOABButton(button.text, button.icon, button.ID, button.action); } } + // ReSharper disable once InconsistentNaming internal static void LoadKSCButtons() { - foreach (var button in KSCButtonsToBeLoaded) + foreach (var button in KscButtonsToBeLoaded) { AppbarBackend.AddKSCButton(button.text, button.icon, button.ID, button.action); } diff --git a/src/SpaceWarp.UI/API/UI/Appbar/AppbarMenu.cs b/src/SpaceWarp.UI/API/UI/Appbar/AppbarMenu.cs index 2e130c1a..4efe2d76 100644 --- a/src/SpaceWarp.UI/API/UI/Appbar/AppbarMenu.cs +++ b/src/SpaceWarp.UI/API/UI/Appbar/AppbarMenu.cs @@ -1,4 +1,3 @@ -using System; using JetBrains.Annotations; using KSP.Game; using KSP.Sim.impl; @@ -7,25 +6,48 @@ namespace SpaceWarp.API.UI.Appbar; +/// +/// Used to create a menu on the game's AppBar. +/// [Obsolete("Spacewarps support for IMGUI will not be getting updates, please use UITK instead")] [PublicAPI] public abstract class AppbarMenu : KerbalBehavior { + /// + /// The title of the menu + /// + // ReSharper disable once InconsistentNaming [FormerlySerializedAs("Title")] public string title; + private GUIStyle _closeButtonStyle; private bool _drawing; private GUISkin _spaceWarpConsoleSkin; private Rect _windowRect; internal string ID; + /// + /// The width of the menu + /// protected abstract float Width { get; } + /// + /// The height of the menu + /// protected abstract float Height { get; } + /// + /// The X position of the menu + /// protected abstract float X { get; } + /// + /// The Y position of the menu + /// protected abstract float Y { get; } + /// + /// The skin to use for the menu + /// protected virtual GUISkin Skin { get @@ -39,12 +61,18 @@ protected virtual GUISkin Skin } } - public new void Awake() + /// + /// Called when the menu is created + /// + protected new void Awake() { _windowRect = new Rect(X, Y, 0, 0); } - public void OnGUI() + /// + /// Draws the GUI + /// + protected void OnGUI() { if (!_drawing || GameManager.Instance.Game.GlobalGameState.GetState() != GameState.FlightView) @@ -71,6 +99,9 @@ internal void ToggleGUI(bool drawing) Appbar.SetAppBarButtonIndicator(ID, drawing); } + /// + /// Toggles the menu + /// public void ToggleGUI() { _drawing = !_drawing; @@ -78,7 +109,6 @@ public void ToggleGUI() private void DoDrawing(int windowID) { - var closeButtonRect = new Rect(Width - 23, 6, 16, 16); if (GUI.Button(new Rect(_windowRect.width - 18, 2, 16, 16), "x", _closeButtonStyle)) { CloseWindow(); @@ -89,8 +119,15 @@ private void DoDrawing(int windowID) GUI.DragWindow(new Rect(0, 0, 10000, 10000)); } + /// + /// Contains the code to draw the menu + /// + /// The ID of the window public abstract void DrawWindow(int windowID); + /// + /// Closes the menu + /// public void CloseWindow() { ToggleGUI(false); diff --git a/src/SpaceWarp.UI/API/UI/MainMenu.cs b/src/SpaceWarp.UI/API/UI/MainMenu.cs index 5667fd4b..2e1e9458 100644 --- a/src/SpaceWarp.UI/API/UI/MainMenu.cs +++ b/src/SpaceWarp.UI/API/UI/MainMenu.cs @@ -1,9 +1,10 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; +using JetBrains.Annotations; namespace SpaceWarp.API.UI; +/// +/// Used to register buttons in the game's main menu. +/// [PublicAPI] public static class MainMenu { diff --git a/src/SpaceWarp.UI/API/UI/ModList.cs b/src/SpaceWarp.UI/API/UI/ModList.cs index 884652b1..c8e57d03 100644 --- a/src/SpaceWarp.UI/API/UI/ModList.cs +++ b/src/SpaceWarp.UI/API/UI/ModList.cs @@ -1,10 +1,11 @@ -using System; -using JetBrains.Annotations; -using SpaceWarp.UI.ModList; +using JetBrains.Annotations; using UnityEngine.UIElements; namespace SpaceWarp.API.UI; +/// +/// API for the mod list UI +/// [PublicAPI] public static class ModList { diff --git a/src/SpaceWarp.UI/API/UI/Settings/ModsPropertyDrawers.cs b/src/SpaceWarp.UI/API/UI/Settings/ModsPropertyDrawers.cs index e78c2796..7a1ed44f 100644 --- a/src/SpaceWarp.UI/API/UI/Settings/ModsPropertyDrawers.cs +++ b/src/SpaceWarp.UI/API/UI/Settings/ModsPropertyDrawers.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; +using System.ComponentModel; using System.Reflection; using BepInEx.Configuration; using I2.Loc; @@ -16,17 +13,39 @@ namespace SpaceWarp.API.UI.Settings; +/// +/// This class is used to register custom property drawers for the settings UI. +/// [PublicAPI] public static class ModsPropertyDrawers { private static readonly Dictionary> AllPropertyDrawers = new(); private static readonly Dictionary> AllAbstractedPropertyDrawers = new(); + /// + /// Registers a custom property drawer for a specific type. + /// + /// + /// A function that takes a and returns a that will be used + /// as the property drawer. + /// + /// The type to register the drawer for. public static void AddDrawer(Func drawerGenerator) => AllPropertyDrawers.Add(typeof(T), drawerGenerator); + /// + /// Registers a custom abstract property drawer for a specific type. + /// + /// + /// public static void AddAbstractedDrawer(Func drawerGenerator) => AllAbstractedPropertyDrawers.Add(typeof(T), drawerGenerator); + + /// + /// Gets a property drawer for a config entry. + /// + /// The config entry to get a drawer for. + /// A that will be used as the property drawer. public static GameObject Drawer(ConfigEntryBase entry) { if (entry.SettingType.IsEnum && !AllPropertyDrawers.ContainsKey(entry.SettingType)) @@ -45,6 +64,12 @@ public static GameObject Drawer(ConfigEntryBase entry) return AllPropertyDrawers.TryGetValue(entry.SettingType, out var func) ? func(entry) : null; } + /// + /// Gets a property drawer for a config entry with a name. + /// + /// The name of the config entry. + /// The config entry to get a drawer for. + /// public static GameObject Drawer(string name, IConfigEntry entry) { if (entry.ValueType.IsEnum && !AllAbstractedPropertyDrawers.ContainsKey(entry.ValueType)) @@ -78,7 +103,7 @@ private static Func GenerateEnumDrawerFor(Type t) { var memberInfos = t.GetMember(optionNames[i]); var enumValueInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == t); - var valueAttributes = enumValueInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); + var valueAttributes = enumValueInfo!.GetCustomAttributes(typeof(DescriptionAttribute), false); optionNames[i] = ((DescriptionAttribute)valueAttributes[0]).Description; } catch @@ -190,7 +215,7 @@ private static Func GenerateAbstractEnumDrawer { var memberInfos = t.GetMember(optionNames[i]); var enumValueInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == t); - var valueAttributes = enumValueInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); + var valueAttributes = enumValueInfo!.GetCustomAttributes(typeof(DescriptionAttribute), false); optionNames[i] = ((DescriptionAttribute)valueAttributes[0]).Description; } catch @@ -358,7 +383,7 @@ private static Func GenerateAbstractGenericDra t.GenericTypeArguments[0] == entrySettingType) { if (valueListMethod != null) - return (GameObject)valueListMethod.Invoke(null, new object[] { name, entry, entry.Constraint }); + return (GameObject)valueListMethod.Invoke(null, [name, entry, entry.Constraint]); } if (t?.GetGenericTypeDefinition() == typeof(RangeConstraint<>) && @@ -366,7 +391,7 @@ private static Func GenerateAbstractGenericDra { if (valueRangeMethod != null) { - return (GameObject)valueRangeMethod.Invoke(null, new object[] { name, entry, entry.Constraint }); + return (GameObject)valueRangeMethod.Invoke(null, [name, entry, entry.Constraint]); } } var inputFieldCopy = UnityObject.Instantiate(InputFieldPrefab); @@ -584,7 +609,7 @@ private static GameObject CreateFromAcceptableValueRange(ConfigEntry entry TypeCode.Decimal => x => (T)(object)Convert.ToDecimal(x), TypeCode.Double => x => (T)(object)Convert.ToDouble(x), TypeCode.Single => x => (T)(object)x, - _ => x => throw new NotImplementedException(typeof(T).ToString()) + _ => _ => throw new NotImplementedException(typeof(T).ToString()) }; slider.minValue = toFloat(acceptableValues.MinValue); slider.maxValue = toFloat(acceptableValues.MaxValue); @@ -626,7 +651,7 @@ private static GameObject CreateFromListConstraint(string key, IConfigEntry e ? (color.a < 1 ? ColorUtility.ToHtmlStringRGBA(color) : ColorUtility.ToHtmlStringRGB(color)) : option.ToString()))); } - + extended.value = constraint.AcceptableValues.IndexOf(value.Value); extended.onValueChanged.AddListener(idx => { value.Value = constraint.AcceptableValues[idx]; }); var sec = ddCopy.AddComponent(); @@ -671,7 +696,7 @@ private static GameObject CreateFromRangeConstraint(string key, IConfigEntry TypeCode.Decimal => x => (T)(object)Convert.ToDecimal(x), TypeCode.Double => x => (T)(object)Convert.ToDouble(x), TypeCode.Single => x => (T)(object)x, - _ => x => throw new NotImplementedException(typeof(T).ToString()) + _ => _ => throw new NotImplementedException(typeof(T).ToString()) }; slider.minValue = toFloat(constraint.Minimum); slider.maxValue = toFloat(constraint.Maximum); @@ -681,9 +706,8 @@ private static GameObject CreateFromRangeConstraint(string key, IConfigEntry // var trueValue = (acceptableValues.MaxValue-acceptableValues.MinValue) * (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value) // var trueValue = (toFloat(acceptableValues.MaxValue) - toFloat(acceptableValues.MinValue)) * value + // toFloat(acceptableValues.MinValue); - var trueValue = val; - value.Value = toT(trueValue) ?? value.Value; + value.Value = toT(val) ?? value.Value; if (entry.Value != null) text.text = entry.Value.ToString(); slider.SetWithoutCallback(toFloat(value.Value)); }); @@ -715,7 +739,7 @@ private static GameObject CreateStringConfig(ConfigEntryBase entryBase) textField.readOnly = false; textField.interactable = true; textField.text = entry.Value; - textField.onValueChanged.AddListener(str => { entry.Value = str; }); + textField.onValueChanged.AddListener(text => { entry.Value = text; }); var rectTransform = textFieldObject.transform.parent.gameObject.GetComponent(); rectTransform.anchorMin = new Vector2(0, 2.7f); rectTransform.anchorMax = new Vector2(0.19f, 2.25f); @@ -729,6 +753,10 @@ private static GameObject CreateStringConfig(ConfigEntryBase entryBase) private static GameObject CreateStringConfigAbstracted(string name, IConfigEntry entry) { + if (entry.Constraint is ListConstraint constraint) + { + return CreateFromListConstraint(name, entry, constraint); + } var inputFieldCopy = UnityObject.Instantiate(InputFieldPrefab); var lab = inputFieldCopy.GetChild("Label"); lab.GetComponent().SetTerm(name); diff --git a/src/SpaceWarp.UI/API/UI/Settings/SettingsMenu.cs b/src/SpaceWarp.UI/API/UI/Settings/SettingsMenu.cs new file mode 100644 index 00000000..936bd712 --- /dev/null +++ b/src/SpaceWarp.UI/API/UI/Settings/SettingsMenu.cs @@ -0,0 +1,26 @@ +using JetBrains.Annotations; +using SpaceWarp.API.Configuration; + +namespace SpaceWarp.UI.API.UI.Settings; + +/// +/// API for the mod settings menu +/// +[PublicAPI] +public static class SettingsMenu +{ + /// + /// Contains a list of all the registered config files + /// + public static Dictionary RegisteredConfigFiles = new(); + + /// + /// Register a manually created config file for the settings menu + /// + /// The section name for the config file + /// The file itself + public static void RegisterConfigFile(string section, IConfigFile file) + { + RegisteredConfigFiles[section] = file; + } +} \ No newline at end of file diff --git a/src/SpaceWarp.UI/API/UI/Skins.cs b/src/SpaceWarp.UI/API/UI/Skins.cs index b281628b..ff1d6630 100644 --- a/src/SpaceWarp.UI/API/UI/Skins.cs +++ b/src/SpaceWarp.UI/API/UI/Skins.cs @@ -1,10 +1,12 @@ -using System; -using JetBrains.Annotations; +using JetBrains.Annotations; using SpaceWarp.API.Assets; using UnityEngine; namespace SpaceWarp.API.UI; +/// +/// SpaceWarp's internal GUI skins +/// // This exposes the SpaceWarp internal skins [Obsolete("SpaceWarp's support for IMGUI will not be getting updates, please use UITK instead")] [PublicAPI] @@ -12,6 +14,9 @@ public static class Skins { private static GUISkin _skin; + /// + /// The default SpaceWarp skin + /// [Obsolete("SpaceWarp's support for IMGUI will not be getting updates, please use UITK instead")] public static GUISkin ConsoleSkin { diff --git a/src/SpaceWarp.UI/Backend/UI/Appbar/AppbarBackend.cs b/src/SpaceWarp.UI/Backend/UI/Appbar/AppbarBackend.cs index abdd99ca..11694735 100644 --- a/src/SpaceWarp.UI/Backend/UI/Appbar/AppbarBackend.cs +++ b/src/SpaceWarp.UI/Backend/UI/Appbar/AppbarBackend.cs @@ -1,12 +1,11 @@ // 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 System.Reflection; -using BepInEx.Logging; using HarmonyLib; using I2.Loc; +using JetBrains.Annotations; using KSP; using KSP.Api.CoreTypes; using KSP.Game; @@ -21,17 +20,20 @@ using UnityEngine.Events; using UnityEngine.UI; using static SpaceWarp.Backend.UI.Appbar.AppbarBackend; +using ILogger = SpaceWarp.API.Logging.ILogger; using UnityObject = UnityEngine.Object; namespace SpaceWarp.Backend.UI.Appbar; internal static class AppbarBackend { - private static readonly ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("ToolbarBackend"); + private static ILogger Logger => Modules.UI.Instance.ModuleLogger; + // ReSharper disable InconsistentNaming public static readonly UnityEvent AppBarOABSubscriber = new(); public static readonly UnityEvent AppBarInFlightSubscriber = new(); public static readonly UnityEvent AppBarKSCSubscriber = new(); + // ReSharper restore InconsistentNaming internal static void SubscriberSchedulePing(AppbarEvent type) { @@ -52,12 +54,14 @@ internal static void SubscriberSchedulePing(AppbarEvent type) gameObject.SetActive(true); } + // ReSharper disable InconsistentNaming internal enum AppbarEvent { Flight, OAB, KSC } + // ReSharper restore InconsistentNaming #region Flight App Bar @@ -129,6 +133,7 @@ public static void SetTrayState(bool state) private static GameObject _oabTray; + // ReSharper disable once InconsistentNaming private static GameObject OABTray { get @@ -144,6 +149,7 @@ private static GameObject OABTray private static Property _oabState; + // ReSharper disable once InconsistentNaming private static GameObject CreateOABTray() { Logger.LogInfo("Creating OAB app button tray..."); @@ -227,6 +233,7 @@ private static GameObject CreateOABTray() return oabTray; } + // ReSharper disable once InconsistentNaming public static void AddOABButton(string buttonText, Sprite buttonIcon, string buttonId, Action function) { Logger.LogInfo($"Adding OAB app bar button: {buttonId}."); @@ -280,6 +287,7 @@ public static void AddOABButton(string buttonText, Sprite buttonIcon, string but Logger.LogInfo($"Added OAB appbar button: {buttonId}"); } + // ReSharper disable once InconsistentNaming private static void SetOABTrayState(bool state) { if (_oabTray == null) @@ -296,6 +304,7 @@ private static void SetOABTrayState(bool state) private static GameObject _kscTray; + // ReSharper disable once InconsistentNaming private static GameObject KSCTray { get @@ -309,6 +318,7 @@ private static GameObject KSCTray } } + // ReSharper disable once InconsistentNaming private static GameObject CreateKSCTray() { Logger.LogInfo("Creating KSC app tray..."); @@ -367,6 +377,7 @@ private static GameObject CreateKSCTray() return kscAppTray; } + // ReSharper disable once InconsistentNaming public static void AddKSCButton(string buttonText, Sprite buttonIcon, string buttonId, Action function) { Logger.LogInfo($"Adding KSC appbar button: {buttonId}."); @@ -457,6 +468,7 @@ private IEnumerator Awaiter() [HarmonyPatch("Start")] internal class ToolbarBackendAppBarPatcher { + [UsedImplicitly] public static void Postfix() { SubscriberSchedulePing(AppbarEvent.Flight); @@ -465,8 +477,10 @@ public static void Postfix() [HarmonyPatch(typeof(OABSideBar))] [HarmonyPatch("Start")] +// ReSharper disable once InconsistentNaming internal class ToolbarBackendOABSideBarPatcher { + [UsedImplicitly] public static void Postfix() { SubscriberSchedulePing(AppbarEvent.OAB); @@ -475,8 +489,10 @@ public static void Postfix() [HarmonyPatch(typeof(KSCMenuManager))] [HarmonyPatch("Start")] +// ReSharper disable once InconsistentNaming internal class ToolbarBackendKSCPatcher { + [UsedImplicitly] public static void Postfix() { SubscriberSchedulePing(AppbarEvent.KSC); diff --git a/src/SpaceWarp.UI/Backend/UI/Loading/LoadingScreenManager.cs b/src/SpaceWarp.UI/Backend/UI/Loading/LoadingScreenManager.cs index f3178504..22c0118b 100644 --- a/src/SpaceWarp.UI/Backend/UI/Loading/LoadingScreenManager.cs +++ b/src/SpaceWarp.UI/Backend/UI/Loading/LoadingScreenManager.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.IO; -using KSP.Game; -using SpaceWarp.API.Mods; +using SpaceWarp.API.Mods; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets.ResourceLocators; diff --git a/src/SpaceWarp.UI/Backend/UI/Settings/CustomSettingsElementDescriptionController.cs b/src/SpaceWarp.UI/Backend/UI/Settings/CustomSettingsElementDescriptionController.cs index 347f74f8..25cddc8f 100644 --- a/src/SpaceWarp.UI/Backend/UI/Settings/CustomSettingsElementDescriptionController.cs +++ b/src/SpaceWarp.UI/Backend/UI/Settings/CustomSettingsElementDescriptionController.cs @@ -1,27 +1,52 @@ -using System.Collections.Generic; -using KSP.Game; +using KSP.Game; using UnityEngine.EventSystems; using DG.Tweening; namespace SpaceWarp.Backend.UI.Settings; +/// +/// This class is used to display a description for a custom setting element. +/// public class CustomSettingsElementDescriptionController : KerbalMonoBehaviour, IPointerEnterHandler, IPointerExitHandler { - + /// + /// The description to display when the element is hovered. + /// + // ReSharper disable once InconsistentNaming public string description; + + /// + /// Whether or not this element is an input setting element. + /// + // ReSharper disable once InconsistentNaming public bool isInputSettingElement; + /// + /// The tween animations to play when the element is hovered. + /// + // ReSharper disable once InconsistentNaming public List tweenAnimations = new(); + + /// + /// Called when the object is created. + /// public void Start() => tweenAnimations.AddRange(GetComponents()); + /// + /// Called when the pointer enters the object. + /// + /// public void OnPointerEnter(PointerEventData eventData) => OnHover(true); + /// + /// Called when the pointer exits the object. + /// + /// public void OnPointerExit(PointerEventData eventData) => OnHover(false); - private void OnHover(bool isHovered) { if (isHovered) @@ -40,6 +65,8 @@ private void HandleAnimation(string triggerType) { var all = tweenAnimations.FindAll(da => da.id.Equals(triggerType)); foreach (var animationComponent in all) + { animationComponent.tween.Restart(); + } } } diff --git a/src/SpaceWarp.UI/Modules/UI.cs b/src/SpaceWarp.UI/Modules/UI.cs index 9ec81c5e..eed59bc7 100644 --- a/src/SpaceWarp.UI/Modules/UI.cs +++ b/src/SpaceWarp.UI/Modules/UI.cs @@ -1,17 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using BepInEx.Bootstrap; +using HarmonyLib; using JetBrains.Annotations; -using KSP.Assets; -using KSP.Game; -using KSP.Game.Flow; using SpaceWarp.API.Assets; using SpaceWarp.API.Configuration; -using SpaceWarp.API.Loading; using SpaceWarp.API.UI.Appbar; using SpaceWarp.Backend.UI.Appbar; -using SpaceWarp.Backend.UI.Loading; using SpaceWarp.InternalUtilities; using SpaceWarp.UI.AvcDialog; using SpaceWarp.UI.Console; @@ -20,19 +12,21 @@ using UitkForKsp2.API; using UnityEngine; using UnityEngine.UIElements; -using ConfigManager = ConfigurationManager.ConfigurationManager; namespace SpaceWarp.Modules; +/// +/// The UI module for Space Warp. +/// [PublicAPI] public class UI : SpaceWarpModule { + /// public override string Name => "SpaceWarp.UI"; internal static UI Instance; - + internal ConfigValue ConfigAllColor; - internal ConfigValue ConfigCheckVersions; internal ConfigValue ConfigShowMainMenuWarningForOutdatedMods; internal ConfigValue ConfigShowMainMenuWarningForErroredMods; internal ConfigValue ConfigDebugColor; @@ -44,11 +38,10 @@ public class UI : SpaceWarpModule internal ConfigValue ConfigShowTimeStamps; internal ConfigValue ConfigTimeStampFormat; internal ConfigValue ConfigWarningColor; - internal ConfigManager ConfigurationManager; internal ModListController ModListController; internal SpaceWarpConsole SpaceWarpConsole; - + /// public override void LoadModule() { AppbarBackend.AppBarInFlightSubscriber.AddListener(Appbar.LoadAllButtons); @@ -82,12 +75,15 @@ public override void LoadModule() "Show Warning for Errored Mods", true, "Whether or not Space Warp should display a warning in main menu if there are errored mods")); BepInEx.Logging.Logger.Listeners.Add(new SpaceWarpConsoleLogListener(this)); + Harmony.CreateAndPatchAll(GetType().Assembly); } + /// public override void PreInitializeModule() { } + /// public override void InitializeModule() { ModuleLogger.LogInfo("Initializing UI"); @@ -101,7 +97,11 @@ public override void InitializeModule() var avcDialogUxml = AssetManager.GetAsset( $"{SpaceWarpPlugin.ModGuid}/avcdialog/ui/avcdialog/avcdialog.uxml"); - var avcDialog = Window.CreateFromUxml(avcDialogUxml, "Space Warp AVC Dialog", ui.transform, true); + + var windowOptions = WindowOptions.Default; + windowOptions.WindowId = "Space Warp AVC Dialog"; + windowOptions.Parent = ui.transform; + var avcDialog = Window.Create(windowOptions, avcDialogUxml); var avcDialogController = avcDialog.gameObject.AddComponent(); avcDialogController.Module = VersionChecking.Instance; @@ -110,6 +110,7 @@ public override void InitializeModule() InitializeUI(); } + /// public override void PostInitializeModule() { ModuleLogger.LogInfo("Post Initializing UI"); @@ -118,16 +119,11 @@ public override void PostInitializeModule() ModListController.AddMainMenuItem(); } - public override List Prerequisites => new() - { - "SpaceWarp.VersionChecking" - }; - + /// + public override List Prerequisites => ["SpaceWarp.VersionChecking"]; + private void InitializeUI() { - ConfigurationManager = (ConfigurationManager.ConfigurationManager)Chainloader - .PluginInfos[ConfigManager.GUID].Instance; - var ui = new GameObject("Space Warp UI"); ui.Persist(); ui.SetActive(true); @@ -135,18 +131,23 @@ private void InitializeUI() var modListUxml = AssetManager.GetAsset( $"{SpaceWarpPlugin.ModGuid}/modlist/ui/modlist/modlist.uxml" ); - var modList = Window.CreateFromUxml(modListUxml, "Space Warp Mod List", ui.transform, true); + var modListOptions = WindowOptions.Default; + modListOptions.WindowId = "Space Warp Mod List"; + modListOptions.Parent = ui.transform; + var modList = Window.Create(modListOptions, modListUxml); ModListController = modList.gameObject.AddComponent(); var swConsoleUxml = AssetManager.GetAsset( $"{SpaceWarpPlugin.ModGuid}/swconsole/ui/console/console.uxml" ); - - var swConsole = Window.CreateFromUxml(swConsoleUxml, "Space Warp Console", ui.transform, true); + var swConsoleOptions = WindowOptions.Default; + swConsoleOptions.WindowId = "Space Warp AVC Dialog"; + swConsoleOptions.Parent = ui.transform; + var swConsole = Window.Create(swConsoleOptions, swConsoleUxml); SpaceWarpConsole = swConsole.gameObject.AddComponent(); } - - + + private static void InitializeSettingsUI() { GameObject settingsController = new("Space Warp Settings Controller"); diff --git a/src/SpaceWarp.UI/Patching/ConfigurationPatch.cs b/src/SpaceWarp.UI/Patching/ConfigurationPatch.cs deleted file mode 100644 index b2e6a2a7..00000000 --- a/src/SpaceWarp.UI/Patching/ConfigurationPatch.cs +++ /dev/null @@ -1,19 +0,0 @@ -using BepInEx; -using BepInEx.Bootstrap; -using ConfigurationManager.Utilities; -using HarmonyLib; - -namespace SpaceWarp.Patching; - -[HarmonyPatch(typeof(Utils))] -[HarmonyPatch(nameof(Utils.FindPlugins))] -public class ConfigurationPatch -{ - private static void Postfix(ref BaseUnityPlugin[] __result) - { - //Disable because I know what I am doing. - #pragma warning disable CS0618 - __result = Chainloader.Plugins.ToArray(); - #pragma warning restore CS0618 - } -} \ No newline at end of file diff --git a/src/SpaceWarp.UI/Patching/CurtainPatch.cs b/src/SpaceWarp.UI/Patching/LoadingScreen/CurtainPatch.cs similarity index 72% rename from src/SpaceWarp.UI/Patching/CurtainPatch.cs rename to src/SpaceWarp.UI/Patching/LoadingScreen/CurtainPatch.cs index 853abefb..3ae52d60 100644 --- a/src/SpaceWarp.UI/Patching/CurtainPatch.cs +++ b/src/SpaceWarp.UI/Patching/LoadingScreen/CurtainPatch.cs @@ -1,23 +1,22 @@ -using System; -using HarmonyLib; -using KSP.Networking.MP.Utils; +using HarmonyLib; using SpaceWarp.Backend.UI.Loading; -using UnityEngine; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.LoadingScreen; [HarmonyPatch(typeof(Curtain))] internal static class CurtainPatch { internal static LoadingScreenManager LoadingScreenManager; - + [HarmonyPrefix] [HarmonyPatch(nameof(Curtain.Awake))] + // ReSharper disable once InconsistentNaming public static void LoadScreensEarly(Curtain __instance) { LoadingScreenManager = new LoadingScreenManager(); LoadingScreenManager.LoadScreens(__instance); - __instance._appStartLoadingScreenSpriteOptions.AddRange(LoadingScreenManager.LoadingScreens - .Values); + __instance._appStartLoadingScreenSpriteOptions.AddRange( + LoadingScreenManager.LoadingScreens.Values + ); } } \ No newline at end of file diff --git a/src/SpaceWarp.UI/Patching/LoadingFlowPatch.cs b/src/SpaceWarp.UI/Patching/LoadingScreen/LoadingFlowPatch.cs similarity index 81% rename from src/SpaceWarp.UI/Patching/LoadingFlowPatch.cs rename to src/SpaceWarp.UI/Patching/LoadingScreen/LoadingFlowPatch.cs index 15cbe4f0..95bd7815 100644 --- a/src/SpaceWarp.UI/Patching/LoadingFlowPatch.cs +++ b/src/SpaceWarp.UI/Patching/LoadingScreen/LoadingFlowPatch.cs @@ -1,27 +1,26 @@ -using System; -using HarmonyLib; +using HarmonyLib; using KSP.Game; using KSP.Game.Flow; using KSP.Startup; -using UnityEngine; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.LoadingScreen; [HarmonyPatch(typeof(SequentialFlow))] internal static class LoadingFlowPatch { - internal static long LoadingScreenTimer; + private static long _loadingScreenTimer; [HarmonyPostfix] [HarmonyPatch(nameof(SequentialFlow.NextFlowAction))] + // ReSharper disable once InconsistentNaming internal static void SelectRandomLoadingScreen(SequentialFlow __instance) { if (__instance.FlowState != FlowState.Finished) { var time = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(); - if (time - LoadingScreenTimer >= 7) + if (time - _loadingScreenTimer >= 7) { - LoadingScreenTimer = time; + _loadingScreenTimer = time; // Switch loading screen if (GameManager.Instance == null || GameManager.Instance.Game == null || GameManager.Instance.Game.UI == null) return; @@ -36,5 +35,4 @@ internal static void SelectRandomLoadingScreen(SequentialFlow __instance) } } } - } \ No newline at end of file diff --git a/src/SpaceWarp.UI/Patching/LoadingScreenDeserializationPatch.cs b/src/SpaceWarp.UI/Patching/LoadingScreen/LoadingScreenDeserializationPatch.cs similarity index 72% rename from src/SpaceWarp.UI/Patching/LoadingScreenDeserializationPatch.cs rename to src/SpaceWarp.UI/Patching/LoadingScreen/LoadingScreenDeserializationPatch.cs index 5a75d466..19e9a73f 100644 --- a/src/SpaceWarp.UI/Patching/LoadingScreenDeserializationPatch.cs +++ b/src/SpaceWarp.UI/Patching/LoadingScreen/LoadingScreenDeserializationPatch.cs @@ -1,16 +1,15 @@ -using System.Linq; -using HarmonyLib; +using HarmonyLib; using KSP.Game; using KSP.Game.StartupFlow; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.LoadingScreen; [HarmonyPatch(typeof(DeserializeLoadingScreens))] -public static class LoadingScreenDeserializationPatch +internal static class LoadingScreenDeserializationPatch { [HarmonyPatch(nameof(DeserializeLoadingScreens.DoAction))] [HarmonyPostfix] - public static void AddToAllFlows() + private static void AddToAllFlows() { var curtain = GameManager.Instance.Game.UI.Curtain; foreach (var flow in curtain.LoadingScreens.Values.Distinct()) diff --git a/src/SpaceWarp.UI/Patching/MainMenuPatcher.cs b/src/SpaceWarp.UI/Patching/MainMenu/MainMenuPatcher.cs similarity index 68% rename from src/SpaceWarp.UI/Patching/MainMenuPatcher.cs rename to src/SpaceWarp.UI/Patching/MainMenu/MainMenuPatcher.cs index 58261589..b35cf4e0 100644 --- a/src/SpaceWarp.UI/Patching/MainMenuPatcher.cs +++ b/src/SpaceWarp.UI/Patching/MainMenu/MainMenuPatcher.cs @@ -1,25 +1,26 @@ -using System; -using HarmonyLib; +using HarmonyLib; using I2.Loc; +using JetBrains.Annotations; using KSP.Api.CoreTypes; using KSP.Game.StartupFlow; -using SpaceWarp.API.UI; using TMPro; using UnityObject = UnityEngine.Object; -namespace SpaceWarp.Patching; +namespace SpaceWarp.Patching.MainMenu; -[HarmonyPatch(typeof(LandingHUD))] -[HarmonyPatch("Start")] +[HarmonyPatch(typeof(LandingHUD), nameof(LandingHUD.Start))] internal class MainMenuPatcher { internal static event Action MainMenuLoaded; + + [UsedImplicitly] + // ReSharper disable once InconsistentNaming public static void Postfix(LandingHUD __instance) { var menuItemsGroupTransform = __instance.transform.FindChildEx("MenuItemsGroup"); var singleplayerButtonTransform = menuItemsGroupTransform.FindChildEx("Singleplayer"); - foreach (var menuButtonToBeAdded in MainMenu.MenuButtonsToBeAdded) + foreach (var menuButtonToBeAdded in API.UI.MainMenu.MenuButtonsToBeAdded) { var newButton = UnityObject.Instantiate(singleplayerButtonTransform.gameObject, menuItemsGroupTransform, false); @@ -38,12 +39,18 @@ public static void Postfix(LandingHUD __instance) var tmp = newButton.GetComponentInChildren(); tmp.SetText(menuButtonToBeAdded.name); + + LocalizationManager.OnLocalizeEvent += () => tmp.SetText(menuButtonToBeAdded.name); } - foreach (var localizedMenuButtonToBeAddded in MainMenu.LocalizedMenuButtonsToBeAdded) - {var newButton = - UnityObject.Instantiate(singleplayerButtonTransform.gameObject, menuItemsGroupTransform, false); - newButton.name = localizedMenuButtonToBeAddded.term; + foreach (var localizedMenuButtonToBeAdded in API.UI.MainMenu.LocalizedMenuButtonsToBeAdded) + { + var newButton = UnityObject.Instantiate( + singleplayerButtonTransform.gameObject, + menuItemsGroupTransform, + false + ); + newButton.name = localizedMenuButtonToBeAdded.term; // Move the button to be above the Exit button. newButton.transform.SetSiblingIndex(newButton.transform.GetSiblingIndex() - 1); @@ -51,11 +58,12 @@ public static void Postfix(LandingHUD __instance) // Rebind the button's action to call the action var uiAction = newButton.GetComponent(); DelegateAction action = new(); - action.BindDelegate(() => localizedMenuButtonToBeAddded.onClicked.Invoke()); + action.BindDelegate(() => localizedMenuButtonToBeAdded.onClicked.Invoke()); uiAction.BindAction(action); var localize = newButton.GetComponentInChildren(); - localize.SetTerm(localizedMenuButtonToBeAddded.term); + localize.SetTerm(localizedMenuButtonToBeAdded.term); } + MainMenuLoaded?.Invoke(); } } \ No newline at end of file diff --git a/src/SpaceWarp.UI/SpaceWarp.UI.csproj b/src/SpaceWarp.UI/SpaceWarp.UI.csproj index ea456a29..5672b3ba 100644 --- a/src/SpaceWarp.UI/SpaceWarp.UI.csproj +++ b/src/SpaceWarp.UI/SpaceWarp.UI.csproj @@ -1,9 +1,6 @@ - - - @@ -13,6 +10,13 @@ - + + false + + + + + + diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/.gitignore b/src/SpaceWarp.UI/SpaceWarp.Unity/.gitignore new file mode 100644 index 00000000..51780299 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/.gitignore @@ -0,0 +1,77 @@ +# This .gitignore file should be placed at the root of your Unity project directory +# +# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore +# +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/[Ll]ogs/ +/[Uu]ser[Ss]ettings/ + +# MemoryCaptures can get excessive in size. +# They also could contain extremely sensitive data +/[Mm]emoryCaptures/ + +# Recordings can get excessive in size +/[Rr]ecordings/ + +# Uncomment this line if you wish to ignore the asset store tools plugin +# /[Aa]ssets/AssetStoreTools* + +# Autogenerated Jetbrains Rider plugin +/[Aa]ssets/Plugins/Editor/JetBrains* +.idea/ + +# Visual Studio cache directory +.vs/ + +# Gradle cache directory +.gradle/ + +# Autogenerated VS/MD/Consulo solution and project files +ExportedObj/ +.consulo/ +*.csproj +*.unityproj +*.sln +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb +*.mdb +*.opendb +*.VC.db + +# Unity3D generated meta files +*.pidb.meta +*.pdb.meta +*.mdb.meta + +# Unity3D generated file on crash reports +sysinfo.txt + +# Builds +*.apk +*.aab +*.unitypackage +*.app + +# Crashlytics generated file +crashlytics-build.properties + +# Packed Addressables +/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* + +# Packed asset bundles +/[Aa]ssets/[Aa]sset[Bb]undles/* +/[Aa]ssets/[Aa]sset[Bb]undles.meta + +# Temporary auto-generated Android Assets +/[Aa]ssets/[Ss]treamingAssets/aa.meta +/[Aa]ssets/[Ss]treamingAssets/aa/* \ No newline at end of file diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Editor.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Editor.meta new file mode 100644 index 00000000..d8d828cd --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fdab3574d4d142a4ebd82cb7caf295b3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Editor/CreateAssetBundles.cs b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Editor/CreateAssetBundles.cs new file mode 100644 index 00000000..2f601fe9 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Editor/CreateAssetBundles.cs @@ -0,0 +1,40 @@ +using UnityEditor; +using System.IO; + +public static class CreateAssetBundles +{ + private const string AssetBundleDirectory = "Assets/AssetBundles"; + + // Relative path from the Unity project directory to the target directory + private const string TargetDirectory = "../../../plugin_template/BepInEx/plugins/SpaceWarp/assets/bundles"; + + [MenuItem("Assets/Build AssetBundles")] + private static void BuildAllAssetBundles() + { + // Ensure the AssetBundle directory exists + if (!Directory.Exists(AssetBundleDirectory)) + { + Directory.CreateDirectory(AssetBundleDirectory); + } + + // Build the asset bundles + BuildPipeline.BuildAssetBundles( + AssetBundleDirectory, + BuildAssetBundleOptions.None, + BuildTarget.StandaloneWindows + ); + + if (!Directory.Exists(TargetDirectory)) + { + Directory.CreateDirectory(TargetDirectory); + } + + // Copy the newly built bundles to the target directory + var newBundles = Directory.GetFiles(AssetBundleDirectory, "*.bundle"); + foreach (var bundle in newBundles) + { + var destFile = Path.Combine(TargetDirectory, Path.GetFileName(bundle)); + File.Copy(bundle, destFile, overwrite: true); + } + } +} \ No newline at end of file diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Editor/CreateAssetBundles.cs.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Editor/CreateAssetBundles.cs.meta new file mode 100644 index 00000000..b4cd910a --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Editor/CreateAssetBundles.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d62c366594acc54cbb872f2fca7687d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Mock.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Mock.meta new file mode 100644 index 00000000..34e7f6ef --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Mock.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 05982c98f230e314aade81c9d61ba285 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Mock/SpaceWarpMock.dll b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Mock/SpaceWarpMock.dll new file mode 100644 index 00000000..7245f8e2 Binary files /dev/null and b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Mock/SpaceWarpMock.dll differ diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Mock/SpaceWarpMock.dll.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Mock/SpaceWarpMock.dll.meta new file mode 100644 index 00000000..d057e298 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Mock/SpaceWarpMock.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 74914552cc33f3441aadbf4c61d5f76c +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes.meta new file mode 100644 index 00000000..a6655650 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 60a7dc3412ff32d4696b4fbe815925d5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/AvcScene.unity b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/AvcScene.unity new file mode 100644 index 00000000..fbccf85c --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/AvcScene.unity @@ -0,0 +1,366 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &741411289 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 741411291} + - component: {fileID: 741411290} + m_Layer: 5 + m_Name: AvcDialog + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &741411290 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 741411289} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PanelSettings: {fileID: 11400000, guid: 3419f04c0d00a974f960d832d66f2220, type: 2} + m_ParentUI: {fileID: 0} + sourceAsset: {fileID: 9197481963319205126, guid: a676d09cc2b989046aff5404348b9cc7, type: 3} + m_SortingOrder: 0 +--- !u!4 &741411291 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 741411289} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1116985981 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1116985984} + - component: {fileID: 1116985983} + - component: {fileID: 1116985982} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1116985982 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1116985981} + m_Enabled: 1 +--- !u!20 &1116985983 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1116985981} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1116985984 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1116985981} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1362960111 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1362960113} + - component: {fileID: 1362960112} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1362960112 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1362960111} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1362960113 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1362960111} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1116985984} + - {fileID: 1362960113} + - {fileID: 741411291} diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/AvcScene.unity.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/AvcScene.unity.meta new file mode 100644 index 00000000..6eccbf59 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/AvcScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a88b633f90dd9da4687e9a2ace2c695a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ConsoleScene.unity b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ConsoleScene.unity new file mode 100644 index 00000000..12b39c91 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ConsoleScene.unity @@ -0,0 +1,366 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &166378521 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 166378523} + - component: {fileID: 166378522} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &166378522 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 166378521} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &166378523 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 166378521} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1165952230 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1165952233} + - component: {fileID: 1165952232} + - component: {fileID: 1165952231} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1165952231 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1165952230} + m_Enabled: 1 +--- !u!20 &1165952232 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1165952230} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1165952233 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1165952230} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1854748492 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1854748494} + - component: {fileID: 1854748493} + m_Layer: 5 + m_Name: Console + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1854748493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1854748492} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PanelSettings: {fileID: 11400000, guid: 3419f04c0d00a974f960d832d66f2220, type: 2} + m_ParentUI: {fileID: 0} + sourceAsset: {fileID: 9197481963319205126, guid: eb9ee84eaf84888418434887ed49f764, type: 3} + m_SortingOrder: 0 +--- !u!4 &1854748494 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1854748492} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1165952233} + - {fileID: 166378523} + - {fileID: 1854748494} diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ConsoleScene.unity.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ConsoleScene.unity.meta new file mode 100644 index 00000000..f2e5c654 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ConsoleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4da49840ecfeee943876d9ed3be915d2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ModListScene.unity b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ModListScene.unity new file mode 100644 index 00000000..f11cc1db --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ModListScene.unity @@ -0,0 +1,366 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &88255775 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88255777} + - component: {fileID: 88255776} + m_Layer: 5 + m_Name: ModList + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &88255776 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88255775} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PanelSettings: {fileID: 11400000, guid: 3419f04c0d00a974f960d832d66f2220, type: 2} + m_ParentUI: {fileID: 0} + sourceAsset: {fileID: 9197481963319205126, guid: 6d9ecd385d9b32a4d82256d59462965c, type: 3} + m_SortingOrder: 0 +--- !u!4 &88255777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88255775} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &850075947 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 850075950} + - component: {fileID: 850075949} + - component: {fileID: 850075948} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &850075948 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 850075947} + m_Enabled: 1 +--- !u!20 &850075949 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 850075947} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &850075950 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 850075947} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1102734171 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1102734173} + - component: {fileID: 1102734172} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1102734172 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1102734171} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1102734173 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1102734171} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 850075950} + - {fileID: 1102734173} + - {fileID: 88255777} diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ModListScene.unity.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ModListScene.unity.meta new file mode 100644 index 00000000..e78c90d1 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/Scenes/ModListScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7f2a8f6e87d652c4b9206595a4bad90b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit.meta new file mode 100644 index 00000000..b56e18bd --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0adad9becc7eb084da3094dc7ca82462 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/PanelSettings.asset b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/PanelSettings.asset new file mode 100644 index 00000000..d35e804d --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/PanelSettings.asset @@ -0,0 +1,38 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 19101, guid: 0000000000000000e000000000000000, type: 0} + m_Name: PanelSettings + m_EditorClassIdentifier: + themeUss: {fileID: -4733365628477956816, guid: 14cbf56c01e1f0746b270b3af9b9e7ec, type: 3} + m_TargetTexture: {fileID: 0} + m_ScaleMode: 1 + m_ReferenceSpritePixelsPerUnit: 100 + m_Scale: 1 + m_ReferenceDpi: 96 + m_FallbackDpi: 96 + m_ReferenceResolution: {x: 1200, y: 800} + m_ScreenMatchMode: 0 + m_Match: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 + m_ClearDepthStencil: 1 + m_ClearColor: 0 + m_ColorClearValue: {r: 0, g: 0, b: 0, a: 0} + m_DynamicAtlasSettings: + m_MinAtlasSize: 64 + m_MaxAtlasSize: 4096 + m_MaxSubTextureSize: 64 + m_ActiveFilters: -1 + m_AtlasBlitShader: {fileID: 9101, guid: 0000000000000000f000000000000000, type: 0} + m_RuntimeShader: {fileID: 9100, guid: 0000000000000000f000000000000000, type: 0} + m_RuntimeWorldShader: {fileID: 9102, guid: 0000000000000000f000000000000000, type: 0} + textSettings: {fileID: 0} diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/PanelSettings.asset.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/PanelSettings.asset.meta new file mode 100644 index 00000000..aba2385d --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/PanelSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e297ff1cf8f3ac54085c4676d843e615 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/UnityThemes.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/UnityThemes.meta new file mode 100644 index 00000000..e4eed5d8 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/UnityThemes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea60f11cbde092c43b6134f096e7f942 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss.meta new file mode 100644 index 00000000..5f845d3d --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 14cbf56c01e1f0746b270b3af9b9e7ec +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12388, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI.meta new file mode 100644 index 00000000..1844e598 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 506cef04d17dc6c4fbfc299ec7a15907 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog.meta new file mode 100644 index 00000000..0296a731 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 215cb8e7440ca1a4ba3cafc65e59acd7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog/AvcDialog.uss b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog/AvcDialog.uss new file mode 100644 index 00000000..bb01af91 --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog/AvcDialog.uss @@ -0,0 +1,49 @@ +@import url('../SpaceWarpUI.uss'); + +#avc-dialog { + height: 160px; + width: 600px; +} + +#avc-text-container { + padding: 2px; + -unity-text-align: upper-center; + background-color: rgb(30, 33, 42); + border-width: 1px; + border-radius: 6px; + border-color: rgb(30, 33, 42); + margin-bottom: 4px; + flex-grow: 1; + flex-shrink: 0; + align-items: stretch; +} + +#avc-text-main { + white-space: normal; + font-size: 12px; + -unity-text-align: upper-left; +} + +#avc-text-minor { + -unity-text-align: upper-right; + font-size: 10px; + -unity-font-style: italic; + white-space: normal; + color: rgb(172, 179, 191); +} + +#avc-buttons-container { + flex-direction: row; +} + +#yes-button { + width: 50%; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +#no-button { + width: 50%; + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog/AvcDialog.uss.meta b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog/AvcDialog.uss.meta new file mode 100644 index 00000000..1865524c --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog/AvcDialog.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 66edc366439f08f429958672e34c03f8 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: avcdialog.bundle + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog/AvcDialog.uxml b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog/AvcDialog.uxml new file mode 100644 index 00000000..9526d19b --- /dev/null +++ b/src/SpaceWarp.UI/SpaceWarp.Unity/Assets/UI/AvcDialog/AvcDialog.uxml @@ -0,0 +1,16 @@ + +