Skip to content

Commit

Permalink
Merge pull request #44 from KSP2Community/dev
Browse files Browse the repository at this point in the history
Added ResourceManagerUIFix and DecoupledCraftNameFix
  • Loading branch information
jan-bures authored Dec 30, 2023
2 parents 33c3158 + 3619062 commit 50ed7e5
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 83 deletions.
18 changes: 15 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,29 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Download NuGet
id: download-nuget
run: |
sudo curl -o /usr/local/bin/nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
- name: Install jq
uses: dcarbone/[email protected]

- name: Build the solution
run: |
version=$(jq -r '.version' plugin_template/swinfo.json)
echo "Version is $version"
dotnet build "CommunityFixes.sln" -c Release
echo "release_filename=CommunityFixes-$version.zip" >> $GITHUB_ENV
echo "zip=$(ls -1 dist/CommunityFixes-*.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
- name: Upload zip to release
uses: actions/upload-release-asset@v1.0.1
uses: shogo82148/actions-upload-release-asset@v1.7.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ env.upload_url }}
asset_path: ${{ env.zip }}
asset_name: ${{ env.artifact_name }}
asset_content_type: application/zip
asset_name: ${{ env.release_filename }}
asset_content_type: application/zip
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ This project aims to bring together community bug fixes for Kerbal Space Program
- **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 Fix** by [Cheese](https://github.com/cheese3660) - Fixes the incorrect completion conditions of the mission _Second Dibs: Gold Edition_.
- **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)".

## Planned fixes
To see what fixes are planned to be implemented, you can visit the [Issues page](https://github.com/Bit-Studios/CommunityFixes/issues) on the project's GitHub.
Expand Down
2 changes: 1 addition & 1 deletion plugin_template/swinfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"name": "Community Fixes",
"description": "Community project that aims to bring together bug fixes for KSP 2.",
"source": "https://github.com/KSP2Community/CommunityFixes",
"version": "0.10.0",
"version": "0.11.0",
"version_check": "https://raw.githubusercontent.com/KSP2Community/CommunityFixes/main/plugin_template/swinfo.json",
"ksp2_version": {
"min": "0.2.0",
Expand Down
30 changes: 0 additions & 30 deletions src/CommunityFixes/CommunityFixesConfig.cs

This file was deleted.

46 changes: 4 additions & 42 deletions src/CommunityFixes/CommunityFixesMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class CommunityFixesMod : BaseSpaceWarpPlugin
[PublicAPI] public const string ModVer = MyPluginInfo.PLUGIN_VERSION;

private static readonly Assembly Assembly = typeof(CommunityFixesMod).Assembly;
internal new static CommunityFixesConfig Config;
internal new static Configuration Config;

private readonly List<BaseFix> _fixes = new();

Expand All @@ -33,11 +33,11 @@ private void Awake()
return;
}

Config = new CommunityFixesConfig(base.Config);
Config = new Configuration(base.Config);

foreach (var type in types)
{
if (type.IsAbstract || !HasFixType(type))
if (type.IsAbstract || !type.IsSubclassOf(typeof(BaseFix)))
{
continue;
}
Expand Down Expand Up @@ -66,9 +66,7 @@ public override void OnInitialized()

private bool LoadFix(Type type)
{
var fixName = GetFixName(type);

if (!Config.LoadConfig(type, fixName))
if (!Config.IsFixEnabled(type))
{
return false;
}
Expand All @@ -84,40 +82,4 @@ private bool LoadFix(Type type)

return true;
}

private static string GetFixName(Type type)
{
var attributes = Attribute.GetCustomAttributes(type);
foreach (var attribute in attributes)
{
if (attribute is FixAttribute fix)
{
return fix.Name;
}
}

throw new Exception($"The attribute {typeof(FixAttribute).FullName} has to be declared on a fix class.");
}

private static bool HasFixType(Type type)
{
if (type == null)
{
return false;
}

// return all inherited types
var currentBaseType = type.BaseType;
while (currentBaseType != null)
{
if (currentBaseType == typeof(BaseFix))
{
return true;
}

currentBaseType = currentBaseType.BaseType;
}

return false;
}
}
55 changes: 55 additions & 0 deletions src/CommunityFixes/Configuration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using BepInEx.Configuration;
using CommunityFixes.Fix;

namespace CommunityFixes;

internal class Configuration
{
private const string TogglesSection = "Toggle fixes";

private readonly Dictionary<Type, ConfigEntry<bool>> _fixesEnabled = new();
private readonly ConfigFile _file;

/// <summary>
/// Creates a new config file object.
/// </summary>
/// <param name="file">The config file to use.</param>
public Configuration(ConfigFile file)
{
_file = file;
}

/// <summary>
/// Gets the toggle value for a fix class.
/// </summary>
/// <param name="type">Type of the fix class.</param>
/// <returns>The toggle value for the fix class.</returns>
public bool IsFixEnabled(Type type)
{
// If the toggle value for a fix class is already defined, we return it
if (_fixesEnabled.TryGetValue(type, out var isEnabled))
{
return isEnabled.Value;
}

// Otherwise create a new config entry for the fix class and return its default value (true)
var metadata = FixAttribute.GetForType(type);
var configEntry = _file.Bind(TogglesSection, type.Name, true, metadata.Name);
_fixesEnabled.Add(type, configEntry);
return configEntry.Value;
}

/// <summary>
/// Binds a config entry to a hack class.
/// </summary>
/// <param name="hackType">The hack class type.</param>
/// <param name="key">The config entry key.</param>
/// <param name="defaultValue">The config entry default value.</param>
/// <param name="description">The config entry description.</param>
/// <typeparam name="T">The config entry type.</typeparam>
/// <returns>The config entry.</returns>
public ConfigEntry<T> BindFixValue<T>(Type hackType, string key, T defaultValue, string description = null)
{
return _file.Bind($"{hackType.Name} settings", key, defaultValue, description);
}
}
45 changes: 39 additions & 6 deletions src/CommunityFixes/Fix/BaseFix.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,54 @@
using BepInEx.Logging;
using BepInEx.Configuration;
using HarmonyLib;
using KSP.Game;
using SpaceWarp.API.Logging;

namespace CommunityFixes.Fix;

/// <summary>
/// Base class for all fixes.
/// </summary>
public abstract class BaseFix : KerbalMonoBehaviour
{
public virtual void OnInitialized()
{
}
private Configuration Config { get; }

/// <summary>
/// The logger for the fix.
/// </summary>
internal ILogger Logger { get; }

/// <summary>
/// The harmony instance for the fix.
/// </summary>
protected Harmony HarmonyInstance { get; }
internal ManualLogSource Logger { get; }

/// <summary>
/// Creates a new fix.
/// </summary>
protected BaseFix()
{
Logger = BepInEx.Logging.Logger.CreateLogSource($"CF/{GetType().Name}");
Config = CommunityFixesMod.Config;
Logger = new BepInExLogger(BepInEx.Logging.Logger.CreateLogSource($"CF/{GetType().Name}"));
HarmonyInstance = new Harmony(GetType().FullName);
}

/// <summary>
/// Binds a config entry to a fix class.
/// </summary>
/// <param name="key">The config entry key.</param>
/// <param name="defaultValue">The config entry default value.</param>
/// <param name="description">The config entry description.</param>
/// <typeparam name="T">The config entry type.</typeparam>
/// <returns>The config entry.</returns>
private protected ConfigEntry<T> BindConfigValue<T>(string key, T defaultValue, string description = null)
{
return Config.BindFixValue(GetType(), key, defaultValue, description);
}

/// <summary>
/// Called when the fix is initialized.
/// </summary>
public virtual void OnInitialized()
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Text.RegularExpressions;
using HarmonyLib;
using KSP.Messages;
using KSP.Sim.impl;

namespace CommunityFixes.Fix.FairingEjectSidewaysFix;

[Fix("Decoupled craft name fix")]
public class DecoupledCraftNameFix : BaseFix
{
public override void OnInitialized()
{
Messages.Subscribe<DecoupleMessage>(msg => HandleDecoupleMessage((DecoupleMessage)msg));
Messages.Subscribe<VesselUndockedMessage>(msg => HandleUndockMessage((VesselUndockedMessage)msg));

HarmonyInstance.PatchAll(typeof(DecoupledCraftNameFix));
}

private void HandleDecoupleMessage(DecoupleMessage decoupleMessage)
{
var part1Guid = new IGGuid(Guid.Parse(decoupleMessage.PartGuid));
var part2Guid = decoupleMessage.OtherPartGuid;

var vessel1 = Game.UniverseModel.FindPartComponent(part1Guid)?.PartOwner?.SimulationObject?.Vessel;
var vessel2 = Game.UniverseModel.FindPartComponent(part2Guid)?.PartOwner?.SimulationObject?.Vessel;

HandleSeparationEvent(vessel1, vessel2);
}

private void HandleUndockMessage(VesselUndockedMessage undockMessage)
{
VesselComponent vessel1 = undockMessage.VesselOne?.Model;
VesselComponent vessel2 = undockMessage.VesselTwo?.Model;

HandleSeparationEvent(vessel1, vessel2);
}

private void HandleSeparationEvent(VesselComponent vessel1, VesselComponent vessel2)
{
Logger.LogDebug($"Separated: {vessel1?.Name}, {vessel2?.Name}");

if (vessel2 is not { Name: var newName } ||
!newName.StartsWith("Default Name") ||
string.IsNullOrEmpty(vessel1?.Name))
{
return;
}

var match = Regex.Match(vessel1!.Name, @"-(\d+)$");
newName = match.Success
? Regex.Replace(vessel1.Name, @"-\d+$", $"-{int.Parse(match.Groups[1].Value) + 1}")
: $"{vessel1.Name}-2";

Logger.LogDebug($"Renaming {vessel2.Name} to {newName}");

vessel2.SimulationObject.Name = newName;
}

[HarmonyPatch(typeof(SpaceSimulation), nameof(SpaceSimulation.CreateCombinedVesselSimObject))]
[HarmonyPrefix]
public static void CreateCombinedVesselSimObjectPrefix(
// ReSharper disable once InconsistentNaming
ref string __state,
VesselComponent masterVessel
)
{
__state = masterVessel.Name;
}

[HarmonyPatch(typeof(SpaceSimulation), nameof(SpaceSimulation.CreateCombinedVesselSimObject))]
[HarmonyPostfix]
public static void CreateCombinedVesselSimObjectPostfix(
// ReSharper disable once InconsistentNaming
string __state,
// ReSharper disable once InconsistentNaming
ref SimulationObjectModel __result
)
{
__result.Name = __state;
}
}
Loading

0 comments on commit 50ed7e5

Please sign in to comment.