Skip to content

Commit

Permalink
Merge pull request #40 from dmarcuse/experiment-biome-fix
Browse files Browse the repository at this point in the history
Update KSP dep to 0.2.0 and add fix for biome switch pausing experiments
  • Loading branch information
jan-bures authored Dec 26, 2023
2 parents 8ada7c3 + 51d8e5d commit 136bcaf
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 16 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This project aims to bring together community bug fixes for Kerbal Space Program
- **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.
- **Experiment Biome Pause Fix** by [dmarcuse](https://github.com/dmarcuse) - Fixes experiments that don't care about biome pausing when the biome changes.
- **Stock Mission Fixes** by [Cheese](https://github.com/cheese3660) - Fixes the incorrect completion conditions of the missions _Going Green_ and _Second Dibs: Gold Edition_.

## Planned fixes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using HarmonyLib;
using KSP.Game.Science;
using KSP.Sim.impl;
using KSP.Modules;
using System.Reflection;

namespace CommunityFixes.Fix.ExperimentBiomePauseFix;

[Fix("Fix experiments pausing when switching biome for scenarios where biome is irrelevant")]
public class ExperimentBiomePauseFix : BaseFix
{
public static ExperimentBiomePauseFix Instance;

// This fix makes assumptions about the game's code and reads/writes private state, which can end up in save files.
// In order to avoid accidentally breaking anything, we only apply the patch to known-broken versions of the game.
public static HashSet<string> KNOWN_BROKEN_VERSIONS = ["0.2.0.0.30291"];
public static string GameVersion = typeof(VersionID).GetField("VERSION_TEXT", BindingFlags.Static | BindingFlags.Public)
?.GetValue(null) as string;

public override void OnInitialized()
{
Instance = this;
if (KNOWN_BROKEN_VERSIONS.Contains(GameVersion))
{
HarmonyInstance.PatchAll(typeof(ExperimentBiomePauseFix));
}
else
{
Logger.LogError($"Not enabling experiment biome pause fix - game version {GameVersion} may not be broken");
}
}

// RefreshLocationsValidity has a bug where it unconditionally pauses experiments when switching biome, even if the
// experiment is still valid and doesn't care about the biome. To fix this, we prevent the function from being
// called if the part has running experiments, the experiments don't care about the biome, and the other parameters
// of the experiment are unchanged.
// To avoid breaking things when we skip RefreshLocationsValidity, we also update some private state that the method
// is responsible for when skipping it.
[HarmonyPatch(typeof(PartComponentModule_ScienceExperiment), "RefreshLocationsValidity")]
[HarmonyPrefix]
public static bool RefreshLocationsValidityPrefix(
ref VesselComponent ____vesselComponent,
ref ResearchLocation ____currentLocation,
ref Data_ScienceExperiment ___dataScienceExperiment
)
{
if (____vesselComponent?.mainBody == null || ____vesselComponent?.VesselScienceRegionSituation.ResearchLocation == null)
{
return true;
}

var newLocation = new ResearchLocation(
requiresRegion: true, // Placeholder, assigned per-experiment below
bodyName: ____vesselComponent.mainBody.bodyName,
scienceSituation: ____vesselComponent.VesselScienceRegionSituation.ResearchLocation.ScienceSituation,
scienceRegion: ____vesselComponent.VesselScienceRegionSituation.ResearchLocation.ScienceRegion
);

bool safeToSkip = true;
List<string> newRegions = [];
for (int i = 0; i < ___dataScienceExperiment.ExperimentStandings.Count; i++)
{
var standing = ___dataScienceExperiment.ExperimentStandings[i];
if (standing.CurrentExperimentState == ExperimentState.RUNNING &&
!standing.RegionRequired &&
standing.ExperimentLocation.BodyName == newLocation.BodyName &&
standing.ExperimentLocation.ScienceSituation == newLocation.ScienceSituation)
{
newLocation.RequiresRegion = standing.RegionRequired;
newRegions.Append(newLocation.ScienceRegion);
continue;
}
safeToSkip = false;
}

if (safeToSkip)
{
Instance.Logger.LogInfo("Skipping PartComponentModule_ScienceExperiment.RefreshLocationsValidity - experiment is still valid.");
____currentLocation = newLocation;
for (int i = 0; i < newRegions.Count; i++)
{
___dataScienceExperiment.ExperimentStandings[i].ExperimentLocation.SetScienceRegion(newRegions[i]);
}
}
return !safeToSkip;
}
}
7 changes: 5 additions & 2 deletions src/CommunityFixes/Fix/KSP2SaveFix/KSP2SaveFix.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
namespace CommunityFixes.Fix.KSP2SaveFix;
using System.Reflection;
using KSP.Game;

namespace CommunityFixes.Fix.KSP2SaveFix;

[Fix("KSP 2 Save Fix")]
public class KSP2SaveFix: BaseFix
public class KSP2SaveFix : BaseFix
{
public static KSP2SaveFix Instance;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public override void OnInitialized()
HarmonyInstance.PatchAll(typeof(RevertAfterRecoveryFix));
}

[HarmonyPatch(typeof(UIManager), nameof(UIManager.HandleButtonStates))]
[HarmonyPatch(typeof(UIManager), "HandleButtonStates")]
[HarmonyPostfix]
// ReSharper disable once InconsistentNaming
private static void HandleButtonStatesPatch(UIManager __instance)
{
__instance._escapeMenu.GetComponentInChildren<ESCMenuUIController>().UpdateRevertAvailability();
__instance.EscapeMenu.GetComponentInChildren<ESCMenuUIController>().UpdateRevertAvailability();
}
}
31 changes: 24 additions & 7 deletions src/CommunityFixes/Fix/STFUFix/STFUPatches.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using HarmonyLib;
using System.Reflection;
using HarmonyLib;
using KSP.Game;
using KSP.Logging;
using KSP.Map;
Expand All @@ -7,7 +8,26 @@
namespace CommunityFixes.Fix.STFUFix;
internal class STFUPatches
{
[HarmonyPatch(typeof(Map3DTrajectoryEvents), nameof(Map3DTrajectoryEvents.UpdateViewForOrbiter))]
private const BindingFlags FLAGS = BindingFlags.NonPublic | BindingFlags.Instance;
private static Type TYPE = typeof(Map3DTrajectoryEvents);
private static FieldInfo mapCameraField = TYPE.GetField("_mapCamera", FLAGS);
private static MethodInfo updateForCurrent = TYPE.GetMethod("UpdateViewForCurrentTrajectory", FLAGS);
private static MethodInfo updateForManeuver = TYPE.GetMethod("UpdateViewForManeuverTrajectory", FLAGS);
private static MethodInfo updateForTargeter = TYPE.GetMethod("UpdateViewForTargeter", FLAGS);

private static MapCamera GetCamera(Map3DTrajectoryEvents inst)
{
return mapCameraField.GetValue(inst) as MapCamera;
}

private static void UpdateViews(Map3DTrajectoryEvents inst, OrbiterComponent orbiter, IGGuid globalId)
{
updateForCurrent.Invoke(inst, [orbiter, globalId]);
updateForManeuver.Invoke(inst, [orbiter, globalId]);
updateForTargeter.Invoke(inst, [orbiter.OrbitTargeter, orbiter, globalId]);
}

[HarmonyPatch(typeof(Map3DTrajectoryEvents), "UpdateViewForOrbiter")]
[HarmonyPrefix]
public static bool BetterUpdateViewForOrbiter(Map3DTrajectoryEvents __instance, OrbiterComponent orbiter)
{
Expand All @@ -20,16 +40,13 @@ public static bool BetterUpdateViewForOrbiter(Map3DTrajectoryEvents __instance,
if (!currentTarget.IsCelestialBody)
GlobalLog.Warn("GenerateEventsForVessel() called with vessel.Orbiter.patchedConicSolver == null. Events will not be updated");
}
else if (__instance._mapCamera?.UnityCamera == null)
else if (GetCamera(__instance)?.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);
UpdateViews(__instance, orbiter, orbiter.SimulationObject.GlobalId);
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
using System.Reflection;
using KSP.Game;
using KSP.UI.Binding;
using UnityEngine;
using static KSP.UI.Binding.UIValue_ReadNumber_TextUnits;

namespace CommunityFixes.Fix.VelocityDisplayPrecisionFix;

[Fix("Velocity Display Precision Fix")]
public class VelocityDisplayPrecisionFix: BaseFix
public class VelocityDisplayPrecisionFix : BaseFix
{
private bool _fixed = false;


private FieldInfo unitEntryArrayField = typeof(UIValue_ReadNumber_TextUnits).GetField("unitEntryArray", BindingFlags.NonPublic | BindingFlags.Instance);

public void Update()
{
var gameState = Game?.GlobalGameState?.GetGameState();
if (gameState == null || gameState.GameState is GameState.MainMenu or GameState.WarmUpLoading or GameState.Loading)
_fixed = false;

if (_fixed) return;

var velocityValue = GameObject.Find("GameManager/Default Game Instance(Clone)/UI Manager(Clone)/" +
"Scaled Main Canvas/FlightHudRoot(Clone)/group_navball(Clone)/Container/" +
"GRP-VEL/Container/DataContainer/Items/Value");
if (velocityValue == null) return;
var entries = velocityValue.GetComponent<UIValue_ReadNumber_TextUnits>().unitEntryArray;
var entries = unitEntryArrayField.GetValue(velocityValue.GetComponent<UIValue_ReadNumber_TextUnits>()) as UnitEntry[];
for (int i = 0; i < entries.Length; ++i)
entries[i].dontTruncateValue = true;

Expand Down

0 comments on commit 136bcaf

Please sign in to comment.