diff --git a/CommunityFixes.sln.DotSettings b/CommunityFixes.sln.DotSettings new file mode 100644 index 0000000..7de9879 --- /dev/null +++ b/CommunityFixes.sln.DotSettings @@ -0,0 +1,4 @@ + + KSP + VAB + STFU \ No newline at end of file diff --git a/README.md b/README.md index 137d72f..9731845 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ This project aims to bring together community bug fixes for Kerbal Space Program 2 in one centralized place. ## Compatibility -- Tested with Kerbal Space Program 2 v0.2.1.0.30833 -- Requires **[SpaceWarp 1.9.0+](https://github.com/SpaceWarpDev/SpaceWarp/releases/)** -- Requires **[Patch Manager 0.9.3+](https://github.com/KSP2Community/PatchManager/releases/)** +- Tested with Kerbal Space Program 2 v0.2.2.0.32913 +- Requires **[SpaceWarp 1.9.5+](https://github.com/SpaceWarpDev/SpaceWarp/releases/)** +- Requires **[Patch Manager 0.11.1+](https://github.com/KSP2Community/PatchManager/releases/)** ## Implemented fixes - **KSP 2 Save Fix** by [jayouimet](https://github.com/jayouimet) - Replaces the Control Owner Part to the first available Command module or to the Root part if not found when it is set to null. -- **Vessel Landed State Fix** by [munix](https://github.com/jan-bures) - Checks if the vessel's state is Landed when not actually near the ground and resets it. Should fix [this persistent bug](https://forum.kerbalspaceprogram.com/topic/220260-incorrect-landed-state-causing-lack-of-trajectory-lines/). +- **Vessel Landed State Fix** by [munix](https://github.com/jan-bures) - Checks if the vessel's state is Landed when not actually near the ground and resets it. - **Suppress Transmissions Falsely Urgent Fix** by [schlosrat](https://github.com/schlosrat) - Suppresses unhelpful map view log messages. - **VAB Redo Tooltip Fix** by [coldrifting](https://github.com/coldrifting) - Fixes the VAB Redo button tooltip not being at the same height as the button. - **Revert After Recovery Fix** by [munix](https://github.com/jan-bures) - Fixes the Revert buttons being enabled after recovering a vessel. @@ -16,6 +16,7 @@ This project aims to bring together community bug fixes for Kerbal Space Program - **Resource Manager UI Fix** by [munix](https://github.com/jan-bures) - Fixes the Resource Manager bug where moving a tank from the right pane back to the left pane caused it to duplicate. - **Decoupled Craft Name Fix** by [munix](https://github.com/jan-bures) - Decoupled and docked/undocked vessels get names based on the original vessels instead of "Default Name" and "(Combined)". - **Time Warp Thrust Fix** by [SunSerega](https://github.com/SunSerega) - Fixes the bug where thrust under time warp was sometimes not working despite draining fuel. +- **Save/Load DateTime Fix** by [bizzehdee](https://github.com/bizzehdee) - Displays dates and times of save files in the correct locale format. ## Planned fixes To see what fixes are planned to be implemented, you can visit the [Issues page](https://github.com/KSP2Community/CommunityFixes/issues) on the project's GitHub. @@ -28,8 +29,9 @@ To see what fixes are planned to be implemented, you can visit the [Issues page] ### Manual 1. Download and extract [UITK for KSP 2](https://github.com/UitkForKsp2/UitkForKsp2/releases) into your game folder (this is a dependency of SpaceWarp). 2. Download and extract [SpaceWarp](https://github.com/SpaceWarpDev/SpaceWarp/releases) into your game folder. -3. Download and extract [Patch Manager](https://github.com/KSP2Community/PatchManager/releases) into your game folder. -4. Download and extract this mod into the game folder. If done correctly, you should have the following folder structure: `/BepInEx/plugins/CommunityFixes`. +3. Download and extract [Premonition](https://github.com/cheese3660/Premonition/releases) into your game folder (this is a dependency of Patch Manager). +4. Download and extract [Patch Manager](https://github.com/KSP2Community/PatchManager/releases) into your game folder. +5. Download and extract this mod into the game folder. If done correctly, you should have the following folder structure: `/BepInEx/plugins/CommunityFixes`. ## Configuration If you want to toggle any of the included fixes off, you can do so in game: `Main menu` -> `Settings` -> `Mods` -> `Community Fixes`. The changes will apply after restarting the game. diff --git a/plugin_template/swinfo.json b/plugin_template/swinfo.json index 0dea4f8..ffbee84 100644 --- a/plugin_template/swinfo.json +++ b/plugin_template/swinfo.json @@ -5,24 +5,24 @@ "name": "Community Fixes", "description": "Community project that aims to bring together bug fixes for KSP 2.", "source": "https://github.com/KSP2Community/CommunityFixes", - "version": "0.13.0", + "version": "0.14.0", "version_check": "https://raw.githubusercontent.com/KSP2Community/CommunityFixes/main/plugin_template/swinfo.json", "ksp2_version": { - "min": "0.2.1", + "min": "0.2.2", "max": "*" }, "dependencies": [ { "id": "com.github.x606.spacewarp", "version": { - "min": "1.9.0", + "min": "1.9.5", "max": "*" } }, { "id": "PatchManager", "version": { - "min": "0.9.3", + "min": "0.11.1", "max": "*" } } diff --git a/src/CommunityFixes/CommunityFixes.csproj b/src/CommunityFixes/CommunityFixes.csproj index 0dbc84d..fbf4dde 100644 --- a/src/CommunityFixes/CommunityFixes.csproj +++ b/src/CommunityFixes/CommunityFixes.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/src/CommunityFixes/Fix/DecoupledCraftNameFix/DecoupledCraftNameFix.cs b/src/CommunityFixes/Fix/DecoupledCraftNameFix/DecoupledCraftNameFix.cs index 6328e7d..23af1d9 100644 --- a/src/CommunityFixes/Fix/DecoupledCraftNameFix/DecoupledCraftNameFix.cs +++ b/src/CommunityFixes/Fix/DecoupledCraftNameFix/DecoupledCraftNameFix.cs @@ -29,8 +29,8 @@ private void HandleDecoupleMessage(DecoupleMessage decoupleMessage) private void HandleUndockMessage(VesselUndockedMessage undockMessage) { - VesselComponent vessel1 = undockMessage.VesselOne?.Model; - VesselComponent vessel2 = undockMessage.VesselTwo?.Model; + VesselComponent vessel1 = undockMessage.VesselOne == null ? null : undockMessage.VesselOne.Model; + VesselComponent vessel2 = undockMessage.VesselTwo == null ? null : undockMessage.VesselTwo.Model; HandleSeparationEvent(vessel1, vessel2); } diff --git a/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFix.cs b/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFix.cs index 421f954..756170b 100644 --- a/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFix.cs +++ b/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFix.cs @@ -12,6 +12,6 @@ public KSP2SaveFix() public override void OnInitialized() { - HarmonyInstance.PatchAll(typeof(KSP2SaveFix_GetState)); + HarmonyInstance.PatchAll(typeof(KSP2SaveFixPatch)); } } \ No newline at end of file diff --git a/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFixPatch.cs b/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFixPatch.cs new file mode 100644 index 0000000..f362b3d --- /dev/null +++ b/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFixPatch.cs @@ -0,0 +1,55 @@ +using HarmonyLib; +using JetBrains.Annotations; +using KSP.Sim.impl; + +namespace CommunityFixes.Fix.KSP2SaveFix; + +[HarmonyPatch(typeof(VesselComponent), nameof(VesselComponent.GetState))] +public class KSP2SaveFixPatch +{ + /// Called before VesselComponent.GetState + /// This is the part that crashes during serialization + /// + /// Last 3 functions in the call stack after a save: + /// [EXC 20:35:06.678] NullReferenceException: Object reference not set to an instance of an object + /// KSP.Sim.impl.VesselComponent.GetState() + /// KSP.Game.Serialization.SerializationUtility.VesselToSerializable(KSP.Sim.impl.SimulationObjectModel vessel, + /// System.Boolean isAutosave) + /// KSP.Game.Load.CollectFlightDataFlowAction.CollectVesselComponents(System.Byte playerID) + /// + /// Occurs because the controlOwner hasn't been correctly set after decoupling / undocking + /// After saving in a file or in memory and loading afterwards (this can also be triggered after reverting to VAB), + /// the faulty controlOwner is set to null + /// Once controlOwner is set to null, it crashes during the GetState() call + /// + /// Ideal fix would be to fix the decoupling / docking, I will look into it later if needed but this is a decent + /// workaround until the patch comes out + [UsedImplicitly] + // ReSharper disable once InconsistentNaming + public static void Prefix(VesselComponent __instance) + { + // Check if control owner is already set + if (__instance.GetControlOwner() is not null) + { + return; + } + + KSP2SaveFix.Instance.Logger.LogInfo($"Control 0wner not found for {__instance.GlobalId}"); + // Gather command modules + var partModules = __instance.SimulationObject.PartOwner.GetPartModules(); + // Set ownership to the first command module + if (partModules.Count > 0) + { + KSP2SaveFix.Instance.Logger.LogInfo($"Set control to {partModules[0].Part.GlobalId}"); + __instance.SetControlOwner(partModules[0].Part); + } + // Otherwise try to set it to the root part, whatever it is + else if (__instance.SimulationObject.PartOwner != null) + { + KSP2SaveFix.Instance.Logger.LogInfo( + $"Set control to {__instance.SimulationObject.PartOwner.RootPart.GlobalId}" + ); + __instance.SetControlOwner(__instance.SimulationObject.PartOwner.RootPart); + } + } +} \ No newline at end of file diff --git a/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFix_GetState.cs b/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFix_GetState.cs deleted file mode 100644 index bd8fd14..0000000 --- a/src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFix_GetState.cs +++ /dev/null @@ -1,49 +0,0 @@ -using HarmonyLib; -using KSP.Sim.impl; - -namespace CommunityFixes.Fix.KSP2SaveFix; - -[HarmonyPatch(typeof(VesselComponent), nameof(VesselComponent.GetState))] -public class KSP2SaveFix_GetState -{ - // Called before VesselComponent.GetState - // This is the part that crashes during serialization - - // Last 3 functions in the call stack after a save: - // [EXC 20:35:06.678] NullReferenceException: Object reference not set to an instance of an object - // KSP.Sim.impl.VesselComponent.GetState() (at<8c5bdf369a8c45f68951f69eb825ef73>:0) - // KSP.Game.Serialization.SerializationUtility.VesselToSerializable(KSP.Sim.impl.SimulationObjectModel vessel, System.Boolean isAutosave) (at<8c5bdf369a8c45f68951f69eb825ef73>:0) - // KSP.Game.Load.CollectFlightDataFlowAction.CollectVesselComponents(System.Byte playerID) (at<8c5bdf369a8c45f68951f69eb825ef73>:0) - - // Occurs because the controlOwner hasn't been correctly set after decoupling / undocking - // After saving in a file or in memory and loading afterwards (this can also be triggered after reverting to VAB), the faulty controlOwner is set to null - // Once controlOwner is set to null, it crashes during the GetState() call - - // Ideal fix would be to fix the decoupling / docking, I will look into it later if needed but this is a decent workaround until the patch comes out - public static void Prefix(VesselComponent __instance) - { - // Get control owner for the vessel - PartComponent controlOwner = __instance.GetControlOwner(); - if (controlOwner is null) - { - KSP2SaveFix.Instance.Logger.LogInfo("Control 0wner not found for " + __instance.GlobalId); - // Gather command modules - List partModules = __instance.SimulationObject.PartOwner.GetPartModules(); - // Set ownership to the first command module - if (partModules.Count > 0) - { - KSP2SaveFix.Instance.Logger.LogInfo("Set control to " + partModules[0].Part.GlobalId); - __instance.SetControlOwner(partModules[0].Part); - } - else - { - // Otherwise try to set it to the root part, whatever it is - if (__instance.SimulationObject.PartOwner != null) - { - KSP2SaveFix.Instance.Logger.LogInfo("Set control to " + __instance.SimulationObject.PartOwner.RootPart.GlobalId); - __instance.SetControlOwner(__instance.SimulationObject.PartOwner.RootPart); - } - } - } - } -} \ No newline at end of file diff --git a/src/CommunityFixes/Fix/STFUFix/STFUPatches.cs b/src/CommunityFixes/Fix/STFUFix/STFUPatches.cs index 450fb17..4b70899 100644 --- a/src/CommunityFixes/Fix/STFUFix/STFUPatches.cs +++ b/src/CommunityFixes/Fix/STFUFix/STFUPatches.cs @@ -1,8 +1,7 @@ using HarmonyLib; -using KSP.Game; -using KSP.Logging; using KSP.Map; using KSP.Sim.impl; +using SpaceWarp.API.Game; namespace CommunityFixes.Fix.STFUFix; @@ -10,30 +9,9 @@ internal class STFUPatches { [HarmonyPatch(typeof(Map3DTrajectoryEvents), nameof(Map3DTrajectoryEvents.UpdateViewForOrbiter))] [HarmonyPrefix] + // ReSharper disable once InconsistentNaming public static bool BetterUpdateViewForOrbiter(Map3DTrajectoryEvents __instance, OrbiterComponent orbiter) { - if (orbiter == null) - GlobalLog.Warn("GenerateEventsForVessel() called with vessel.Orbiter == null! Events will not be updated"); - else if (orbiter.PatchedConicSolver == null) - { - var activeVessel = GameManager.Instance?.Game?.ViewController?.GetActiveVehicle(true)?.GetSimVessel(true); - var currentTarget = activeVessel?.TargetObject; - if (!currentTarget.IsCelestialBody) - GlobalLog.Warn( - "GenerateEventsForVessel() called with vessel.Orbiter.patchedConicSolver == null. Events will not be updated"); - } - else if (__instance._mapCamera?.UnityCamera == null) - { - GlobalLog.Warn("GenerateEventsForVessel() called with a null map camera. Events will not be updated"); - } - else - { - IGGuid globalId = orbiter.SimulationObject.GlobalId; - __instance.UpdateViewForCurrentTrajectory(orbiter, globalId); - __instance.UpdateViewForManeuverTrajectory(orbiter, globalId); - __instance.UpdateViewForTargeter(orbiter.OrbitTargeter, orbiter, globalId); - } - - return false; + return orbiter.PatchedConicSolver != null || Vehicle.ActiveSimVessel?.TargetObject?.IsCelestialBody is not true; } } \ No newline at end of file diff --git a/src/CommunityFixes/Fix/SaveLoadDateTimeFix/SaveLoadDateTimeFix.cs b/src/CommunityFixes/Fix/SaveLoadDateTimeFix/SaveLoadDateTimeFix.cs new file mode 100644 index 0000000..eb5145a --- /dev/null +++ b/src/CommunityFixes/Fix/SaveLoadDateTimeFix/SaveLoadDateTimeFix.cs @@ -0,0 +1,10 @@ +namespace CommunityFixes.Fix.SaveLoadDateTimeFix; + +[Fix("Save/Load Date/Time Fix")] +public class SaveLoadDateTimeFix : BaseFix +{ + public override void OnInitialized() + { + HarmonyInstance.PatchAll(typeof(SaveLoadDateTimeFix_Patch)); + } +} diff --git a/src/CommunityFixes/Fix/SaveLoadDateTimeFix/SaveLoadDateTimeFix_Patch.cs b/src/CommunityFixes/Fix/SaveLoadDateTimeFix/SaveLoadDateTimeFix_Patch.cs new file mode 100644 index 0000000..ecfaa11 --- /dev/null +++ b/src/CommunityFixes/Fix/SaveLoadDateTimeFix/SaveLoadDateTimeFix_Patch.cs @@ -0,0 +1,36 @@ +using HarmonyLib; +using KSP.Game; +using UnityEngine.UI; + +namespace CommunityFixes.Fix.SaveLoadDateTimeFix; + +internal class SaveLoadDateTimeFix_Patch +{ + [HarmonyPatch(typeof(SaveLoadDialogFileEntry), nameof(SaveLoadDialogFileEntry.Initialize), new Type[] { typeof(ExtendedSaveFileInfo), typeof(bool), typeof(bool) })] + [HarmonyPrefix] + public static void SaveLoadDialogFileEntry_Initialize(SaveLoadDialogFileEntry __instance, ExtendedSaveFileInfo fileInfo, bool loading, bool isLastPlayed) + { + Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture; + } + + [HarmonyPatch(typeof(SaveLoadDialog), nameof(SaveLoadDialog.UpdateLoadMenuGameInformation), new Type[] { typeof(ExtendedSaveFileInfo), typeof(Image) })] + [HarmonyPrefix] + public static void SaveLoadDialog_UpdateLoadMenuGameInformation(SaveLoadDialog __instance, ExtendedSaveFileInfo fileInfo, Image thumnailScreenshot) + { + Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture; + } + + [HarmonyPatch(typeof(CampaignLoadMenu), nameof(CampaignLoadMenu.UpdateLoadMenuGameInformation), new Type[] { typeof(ExtendedSaveFileInfo), typeof(Image) })] + [HarmonyPrefix] + public static void CampaignLoadMenu_UpdateLoadMenuGameInformation(CampaignLoadMenu __instance, ExtendedSaveFileInfo fileInfo, Image thumnailScreenshot) + { + Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture; + } + + [HarmonyPatch(typeof(CampaignTileEntry), nameof(CampaignTileEntry.Initialize), new Type[] { typeof(ExtendedSaveFileInfo), typeof(CampaignLoadMenu), typeof(CampaignMenu) })] + [HarmonyPrefix] + public static void CampaignTileEntry_UpdateLoadMenuGameInformation(CampaignTileEntry __instance, ExtendedSaveFileInfo fileInfo, CampaignLoadMenu loadMenu, CampaignMenu campaignMenu) + { + Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture; + } +} \ No newline at end of file diff --git a/src/CommunityFixes/Fix/VABRedoTooltipFIx/VABRedoTooltipFix.cs b/src/CommunityFixes/Fix/VABRedoTooltipFIx/VABRedoTooltipFix.cs index ee70122..849998d 100644 --- a/src/CommunityFixes/Fix/VABRedoTooltipFIx/VABRedoTooltipFix.cs +++ b/src/CommunityFixes/Fix/VABRedoTooltipFIx/VABRedoTooltipFix.cs @@ -5,23 +5,23 @@ namespace CommunityFixes.Fix.VABRedoTooltipFIx; [Fix("VAB Redo tooltip offset fix")] -public class VABRedoTooltipFix: BaseFix +public class VABRedoTooltipFix : BaseFix { - private readonly Action _fixCallback = _ => FixVABRedoTooltip(); - public override void OnInitialized() { - Messages.Subscribe(_fixCallback); + Messages.Subscribe(_ => FixVABRedoTooltip()); } // This fix patches the VAB Redo button tooltip appearing above and to the right // of the button, instead of on the same line. It does this by copying the undo button texture // and flipping it. Since the actual texture is protected, we need to use the GPU to render the image in // a flipped position, and then save that to a new sprite that we replace the redo image with. - public static void FixVABRedoTooltip() + private static void FixVABRedoTooltip() { - const string undoButton = "/OAB(Clone)/HUDSpawner/HUD/widget_ToolBar/GRP-Undo-Redo/KSP2ButtonText_ToolsBar-Undo"; - const string redoButton = "/OAB(Clone)/HUDSpawner/HUD/widget_ToolBar/GRP-Undo-Redo/KSP2ButtonText_ToolsBar-Redo"; + const string undoButton = + "/OAB(Clone)/HUDSpawner/HUD/widget_ToolBar/GRP-Undo-Redo/KSP2ButtonText_ToolsBar-Undo"; + const string redoButton = + "/OAB(Clone)/HUDSpawner/HUD/widget_ToolBar/GRP-Undo-Redo/KSP2ButtonText_ToolsBar-Redo"; var undoGameObject = GameObject.Find(undoButton); if (undoGameObject == null) @@ -32,37 +32,38 @@ public static void FixVABRedoTooltip() var undoImage = undoGameObject.GetComponent(); var oldSprite = undoImage.sprite; var tex = oldSprite.texture; - + // Original texture is readonly, so we have to render it through Graphics.Blit - RenderTexture renderTex = RenderTexture.GetTemporary( + var renderTex = RenderTexture.GetTemporary( tex.width, tex.height, 0, RenderTextureFormat.Default, - RenderTextureReadWrite.Linear); - + RenderTextureReadWrite.Linear + ); + // Flip X Axis var scale = new Vector2(-1, 1); var offset = new Vector2(1, 0); - + Graphics.Blit(tex, renderTex, scale, offset); - RenderTexture previous = RenderTexture.active; + var previous = RenderTexture.active; RenderTexture.active = renderTex; - Texture2D readableText = new Texture2D(tex.width, tex.height); + var readableText = new Texture2D(tex.width, tex.height); readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0); readableText.Apply(); RenderTexture.active = previous; RenderTexture.ReleaseTemporary(renderTex); - + // Make sure Unity doesn't anti-alias the pixel graphics readableText.filterMode = FilterMode.Point; - + var newSprite = Sprite.Create( readableText, oldSprite.rect, oldSprite.pivot ); - + var redoGameObject = GameObject.Find(redoButton); if (redoGameObject == null) { @@ -71,7 +72,7 @@ public static void FixVABRedoTooltip() // Undo the negative y axis scaling to fix the tooltip bug redoGameObject.transform.localScale = new Vector3(1, 1, 1); - + // Replace the texture with our custom flipped one to prevent an upside down image var redoGameObjectImage = redoGameObject.GetComponent(); redoGameObjectImage.sprite = newSprite;