diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml
index bed8492..d828f3c 100644
--- a/.github/workflows/on-release.yml
+++ b/.github/workflows/on-release.yml
@@ -1,7 +1,7 @@
name: Publish NuGet and upload release
env:
MOD_ID: 3482
- LATEST_GAME_VERSION: 0.2.0.0
+ KSP2_ID: 22407
on:
release:
@@ -35,7 +35,7 @@ jobs:
echo "artifact_name=PatchManager-$version.zip" >> $GITHUB_ENV
echo "zip=$(ls -1 dist/PatchManager-*.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
- echo "changelog=$(wget -qO- https://api.github.com/repos/$GITHUB_REPOSITORY/releases | jq '.[0].body' | tr -d \" | sed 's/@/%40/g')" >> $GITHUB_ENV
+ echo "changelog=$(wget -qO- https://api.github.com/repos/$GITHUB_REPOSITORY/releases | jq '.[0].body' | tr -d \" | jq -Rr @uri)" >> $GITHUB_ENV
- name: Check if version exists
id: check-version
@@ -79,10 +79,14 @@ jobs:
else
echo "Login to space dock successful"
fi
-
+
+ - name: Query latest game version
+ run: |
+ echo "LATEST_GAME_VERSION=$(curl 'https://spacedock.info/api/${{ env.KSP2_ID }}/versions' | jq '.[0].friendly_version' | tr -d \")" >> $GITHUB_ENV
+
- name: Update mod on spacedock
run: |
- result=$(curl -b ./cookies -F "version=${{ env.version }}" -F "changelog=${{ env.changelog }}" -F "game-version=${{ env.LATEST_GAME_VERSION}}" -F "notify-followers=yes" -F "zipball=@${{ env.zip }}" "https://spacedock.info/api/mod/${{ env.MOD_ID }}/update")
+ result=$(curl -b ./cookies -F "version=${{ env.version }}" -F "changelog=${{ env.changelog }}" -F "game-version=${{ env.LATEST_GAME_VERSION }}" -F "notify-followers=yes" -F "zipball=@${{ env.zip }}" "https://spacedock.info/api/mod/${{ env.MOD_ID }}/update")
errored=$(echo $result | jq .error)
if [ "$errored" == "true" ]; then
echo "Upload to space dock errored: $(echo $result | jq .reason)"
diff --git a/plugin_template/swinfo.json b/plugin_template/swinfo.json
index ad9ba60..563a2e1 100644
--- a/plugin_template/swinfo.json
+++ b/plugin_template/swinfo.json
@@ -5,7 +5,7 @@
"name": "Patch Manager",
"description": "A mod for generic patching needs similar to KSP 1's Module Manager.",
"source": "https://github.com/KSP2Community/PatchManager",
- "version": "0.8.0",
+ "version": "0.9.0",
"version_check": "https://raw.githubusercontent.com/KSP2Community/PatchManager/main/plugin_template/swinfo.json",
"ksp2_version": {
"min": "0.2.0",
diff --git a/src/PatchManager.Science/Modifiables/DiscoverablesModifiable.cs b/src/PatchManager.Science/Modifiables/DiscoverablesModifiable.cs
new file mode 100644
index 0000000..dba6efd
--- /dev/null
+++ b/src/PatchManager.Science/Modifiables/DiscoverablesModifiable.cs
@@ -0,0 +1,32 @@
+using PatchManager.SassyPatching;
+using PatchManager.SassyPatching.Modifiables;
+using PatchManager.Science.Selectables;
+
+namespace PatchManager.Science.Modifiables;
+///
+/// Modifiable for . This is used to modify the discoverables object.
+///
+public class DiscoverablesModifiable : JTokenModifiable
+{
+ private DiscoverablesSelectable _discoverablesSelectable;
+
+ ///
+ /// Creates a new for the given .
+ ///
+ /// The selectable to modify.
+ public DiscoverablesModifiable(DiscoverablesSelectable selectable) : base(selectable.DiscoverablesObject, selectable.SetModified)
+ {
+ _discoverablesSelectable = selectable;
+ }
+
+ ///
+ public override void Set(DataValue dataValue)
+ {
+ if (dataValue.IsDeletion)
+ {
+ _discoverablesSelectable.SetDeleted();
+ return;
+ }
+ base.Set(dataValue);
+ }
+}
\ No newline at end of file
diff --git a/src/PatchManager.Science/Modifiables/RegionsModifiable.cs b/src/PatchManager.Science/Modifiables/RegionsModifiable.cs
new file mode 100644
index 0000000..6a45bd6
--- /dev/null
+++ b/src/PatchManager.Science/Modifiables/RegionsModifiable.cs
@@ -0,0 +1,33 @@
+using PatchManager.SassyPatching;
+using PatchManager.SassyPatching.Modifiables;
+using PatchManager.Science.Selectables;
+
+namespace PatchManager.Science.Modifiables;
+
+///
+/// Modifiable for . This is used to modify the discoverables object.
+///
+public class RegionsModifiable : JTokenModifiable
+{
+ private RegionsSelectable _regionsSelectable;
+
+ ///
+ /// Creates a new for the given .
+ ///
+ /// The selectable to modify.
+ public RegionsModifiable(RegionsSelectable selectable) : base(selectable.RegionsObject, selectable.SetModified)
+ {
+ _regionsSelectable = selectable;
+ }
+
+ ///
+ public override void Set(DataValue dataValue)
+ {
+ if (dataValue.IsDeletion)
+ {
+ _regionsSelectable.SetDeleted();
+ return;
+ }
+ base.Set(dataValue);
+ }
+}
\ No newline at end of file
diff --git a/src/PatchManager.Science/Rulesets/DiscoverablesRuleset.cs b/src/PatchManager.Science/Rulesets/DiscoverablesRuleset.cs
new file mode 100644
index 0000000..cbb5dd2
--- /dev/null
+++ b/src/PatchManager.Science/Rulesets/DiscoverablesRuleset.cs
@@ -0,0 +1,38 @@
+using KSP.Game.Science;
+using Newtonsoft.Json.Linq;
+using PatchManager.SassyPatching;
+using PatchManager.SassyPatching.Attributes;
+using PatchManager.SassyPatching.Interfaces;
+using PatchManager.SassyPatching.NewAssets;
+using PatchManager.Science.Selectables;
+
+namespace PatchManager.Science.Rulesets;
+
+///
+/// A ruleset for modifying discoverable positions in the game
+///
+[PatcherRuleset("discoverables","science_region_discoverables")]
+public class DiscoverablesRuleset : IPatcherRuleSet
+{
+ ///
+ public bool Matches(string label) => label == "science_region_discoverables";
+
+ ///
+ public ISelectable ConvertToSelectable(string type, string name, string jsonData) =>
+ new DiscoverablesSelectable(JObject.Parse(jsonData));
+
+ ///
+ public INewAsset CreateNew(List dataValues)
+ {
+ var bodyName = dataValues[0].String;
+ var bakedDiscoverables = new CelestialBodyBakedDiscoverables
+ {
+ BodyName = bodyName,
+ Discoverables = [],
+ Version = dataValues.Count > 1 ? dataValues[1].String : "0.1"
+ };
+ return new NewGenericAsset("science_region_discoverables",
+ $"{bodyName.ToLowerInvariant()}_science_regions_discoverables",
+ new DiscoverablesSelectable(JObject.FromObject(bakedDiscoverables)));
+ }
+}
\ No newline at end of file
diff --git a/src/PatchManager.Science/Rulesets/RegionsRuleset.cs b/src/PatchManager.Science/Rulesets/RegionsRuleset.cs
new file mode 100644
index 0000000..833bbed
--- /dev/null
+++ b/src/PatchManager.Science/Rulesets/RegionsRuleset.cs
@@ -0,0 +1,38 @@
+using KSP.Game.Science;
+using Newtonsoft.Json.Linq;
+using PatchManager.SassyPatching;
+using PatchManager.SassyPatching.Attributes;
+using PatchManager.SassyPatching.Interfaces;
+using PatchManager.SassyPatching.NewAssets;
+using PatchManager.Science.Selectables;
+
+namespace PatchManager.Science.Rulesets;
+///
+/// Ruleset for science regions
+///
+[PatcherRuleset("regions","science_region")]
+public class RegionsRuleset : IPatcherRuleSet
+{
+ ///
+ public bool Matches(string label) => label == "science_region";
+
+ ///
+ public ISelectable ConvertToSelectable(string type, string name, string jsonData) =>
+ new RegionsSelectable(JObject.Parse(jsonData));
+
+ ///
+ public INewAsset CreateNew(List dataValues)
+ {
+ var bodyName = dataValues[0].String;
+ var bakedDiscoverables = new CelestialBodyScienceRegionsData
+ {
+ BodyName = bodyName,
+ SituationData = new CBSituationData(),
+ Regions = [],
+ Version = dataValues.Count > 1 ? dataValues[1].String : "0.1"
+ };
+ return new NewGenericAsset("science_region",
+ $"{bodyName.ToLowerInvariant()}_science_regions",
+ new RegionsSelectable(JObject.FromObject(bakedDiscoverables)));
+ }
+}
\ No newline at end of file
diff --git a/src/PatchManager.Science/Selectables/DiscoverablesSelectable.cs b/src/PatchManager.Science/Selectables/DiscoverablesSelectable.cs
new file mode 100644
index 0000000..d285aca
--- /dev/null
+++ b/src/PatchManager.Science/Selectables/DiscoverablesSelectable.cs
@@ -0,0 +1,125 @@
+using KSP.Game.Science;
+using Newtonsoft.Json.Linq;
+using PatchManager.SassyPatching;
+using PatchManager.SassyPatching.Interfaces;
+using PatchManager.SassyPatching.Selectables;
+using PatchManager.Science.Modifiables;
+
+namespace PatchManager.Science.Selectables;
+
+///
+/// A selectable that represents discoverables
+///
+public sealed class DiscoverablesSelectable : BaseSelectable
+{
+#pragma warning disable CS0414 // Field is assigned but its value is never used
+ private bool _modified;
+#pragma warning restore CS0414 // Field is assigned but its value is never used
+ private bool _deleted;
+
+ ///
+ /// Marks this part selectable as having been modified any level down
+ ///
+ public void SetModified()
+ {
+ _modified = true;
+ }
+
+ ///
+ /// Marks this part as goneso
+ ///
+ public void SetDeleted()
+ {
+ SetModified();
+ _deleted = true;
+ }
+
+
+ ///
+ /// The main object that represents this discoverable object
+ ///
+ public JObject DiscoverablesObject;
+ private JArray _discoverablesArray;
+
+ ///
+ /// Create a new discoverables selectable from a JObject
+ ///
+ /// Discoverable
+ public DiscoverablesSelectable(JObject discoverablesObject)
+ {
+ DiscoverablesObject = discoverablesObject;
+ ElementType = "discoverables";
+ Name = discoverablesObject["BodyName"].Value();
+ Children = [];
+ Classes =
+ ["BodyName"];
+ _discoverablesArray = (JArray)discoverablesObject["Discoverables"];
+ foreach (var jToken in _discoverablesArray)
+ {
+ var discoverable = (JObject)jToken;
+ var name = discoverable["ScienceRegionId"]!.Value();
+ Classes.Add(name);
+ Children.Add(new JTokenSelectable(SetModified, discoverable,
+ disc => ((JObject)disc)["ScienceRegionId"]!.Value(), "discoverable"));
+ }
+ }
+
+ ///
+ public override List Children { get; }
+
+ ///
+ public override string Name { get; }
+
+ ///
+ public override List Classes { get; }
+
+ ///
+ public override bool MatchesClass(string @class, out DataValue classValue)
+ {
+ foreach (var jToken in _discoverablesArray)
+ {
+ var discoverable = (JObject)jToken;
+ var name = discoverable["ScienceRegionId"]!.Value();
+ if (name != @class) continue;
+ classValue = DataValue.FromJToken(discoverable);
+ return true;
+ }
+ classValue = DataValue.Null;
+ return false;
+ }
+
+ ///
+ public override bool IsSameAs(ISelectable other) => other is DiscoverablesSelectable discoverablesSelectable &&
+ discoverablesSelectable.DiscoverablesObject ==
+ DiscoverablesObject;
+
+ ///
+ public override IModifiable OpenModification() => new DiscoverablesModifiable(this);
+
+ ///
+ public override ISelectable AddElement(string elementType)
+ {
+ var position = new CelestialBodyDiscoverablePosition
+ {
+ ScienceRegionId = elementType,
+ Position = new Vector3d(),
+ Radius = 0.0
+ };
+ var jObject = JObject.FromObject(position);
+ _discoverablesArray.Add(jObject);
+ var selectable = new JTokenSelectable(SetModified, jObject,
+ disc => ((JObject)disc)["ScienceRegionId"]!.Value(), "discoverable");
+ Classes.Add(elementType);
+ Children.Add(selectable);
+ return selectable;
+ }
+
+ ///
+ public override string Serialize() => _deleted ? "" : DiscoverablesObject.ToString();
+
+ ///
+ public override DataValue GetValue() => DataValue.FromJToken(DiscoverablesObject);
+
+ ///
+ public override string ElementType { get; }
+}
\ No newline at end of file
diff --git a/src/PatchManager.Science/Selectables/ExperimentSelectable.cs b/src/PatchManager.Science/Selectables/ExperimentSelectable.cs
index faecf83..7d75a35 100644
--- a/src/PatchManager.Science/Selectables/ExperimentSelectable.cs
+++ b/src/PatchManager.Science/Selectables/ExperimentSelectable.cs
@@ -52,8 +52,8 @@ public ExperimentSelectable(JObject scienceData)
ElementType = "scienceExperiment";
ScienceObject = scienceData;
DataObject = (JObject)scienceData["data"]!;
- Classes = new List();
- Children = new List();
+ Classes = [];
+ Children = [];
foreach (var subToken in DataObject)
{
Classes.Add(subToken.Key);
@@ -81,7 +81,6 @@ public override bool MatchesClass(string @class, out DataValue classValue)
classValue = DataValue.FromJToken(DataObject[@class]);
return true;
-
}
///
diff --git a/src/PatchManager.Science/Selectables/RegionsSelectable.cs b/src/PatchManager.Science/Selectables/RegionsSelectable.cs
new file mode 100644
index 0000000..94ca94f
--- /dev/null
+++ b/src/PatchManager.Science/Selectables/RegionsSelectable.cs
@@ -0,0 +1,124 @@
+using KSP.Game.Science;
+using Newtonsoft.Json.Linq;
+using PatchManager.SassyPatching;
+using PatchManager.SassyPatching.Interfaces;
+using PatchManager.SassyPatching.Selectables;
+using PatchManager.Science.Modifiables;
+
+namespace PatchManager.Science.Selectables;
+
+///
+/// This is the selectable for science regions
+///
+public sealed class RegionsSelectable : BaseSelectable
+{
+ #pragma warning disable CS0414 // Field is assigned but its value is never used
+ private bool _modified;
+#pragma warning restore CS0414 // Field is assigned but its value is never used
+ private bool _deleted;
+
+ ///
+ /// Marks this part selectable as having been modified any level down
+ ///
+ public void SetModified()
+ {
+ _modified = true;
+ }
+
+ ///
+ /// Marks this part as goneso
+ ///
+ public void SetDeleted()
+ {
+ SetModified();
+ _deleted = true;
+ }
+
+
+ ///
+ /// The main object that represents this discoverable object
+ ///
+ public JObject RegionsObject;
+ private JArray _regionsArray;
+
+ ///
+ /// Create a new regions selectable from a JObject
+ ///
+ /// Region
+ public RegionsSelectable(JObject regionsObject)
+ {
+ RegionsObject = regionsObject;
+ ElementType = "regions";
+ Name = regionsObject["BodyName"].Value();
+ Children = [new JTokenSelectable(SetModified, regionsObject["SituationData"], "SituationData","SituationData")];
+ Classes = ["BodyName", "SituationData"];
+ _regionsArray = (JArray)regionsObject["Regions"];
+ foreach (var jToken in _regionsArray)
+ {
+ var discoverable = (JObject)jToken;
+ var name = discoverable["Id"]!.Value();
+ Classes.Add(name);
+ Children.Add(new JTokenSelectable(SetModified, discoverable,
+ disc => ((JObject)disc)["Id"]!.Value(), "region"));
+ }
+ }
+
+ ///
+ public override List Children { get; }
+
+ ///
+ public override string Name { get; }
+
+ ///
+ public override List Classes { get; }
+
+ ///
+ public override bool MatchesClass(string @class, out DataValue classValue)
+ {
+ foreach (var jToken in _regionsArray)
+ {
+ var discoverable = (JObject)jToken;
+ var name = discoverable["Id"]!.Value();
+ if (name != @class) continue;
+ classValue = DataValue.FromJToken(discoverable);
+ return true;
+ }
+ classValue = DataValue.Null;
+ return false;
+ }
+
+ ///
+ public override bool IsSameAs(ISelectable other) => other is RegionsSelectable regionsSelectable &&
+ regionsSelectable.RegionsObject ==
+ RegionsObject;
+
+ ///
+ public override IModifiable OpenModification() => new RegionsModifiable(this);
+
+ ///
+ public override ISelectable AddElement(string elementType)
+ {
+ var position = new CelestialBodyDiscoverablePosition
+ {
+ ScienceRegionId = elementType,
+ Position = new Vector3d(),
+ Radius = 0.0
+ };
+ var jObject = JObject.FromObject(position);
+ _regionsArray.Add(jObject);
+ var selectable = new JTokenSelectable(SetModified, jObject,
+ disc => ((JObject)disc)["ScienceRegionID"]!.Value(), "discoverable");
+ Classes.Add(elementType);
+ Children.Add(selectable);
+ return selectable;
+ }
+
+ ///
+ public override string Serialize() => _deleted ? "" : RegionsObject.ToString();
+
+ ///
+ public override DataValue GetValue() => DataValue.FromJToken(RegionsObject);
+
+ ///
+ public override string ElementType { get; }
+}
\ No newline at end of file