diff --git a/source/ContractConfigurator/ContractConfigurator.csproj b/source/ContractConfigurator/ContractConfigurator.csproj
index bfe294de..30a2863d 100644
--- a/source/ContractConfigurator/ContractConfigurator.csproj
+++ b/source/ContractConfigurator/ContractConfigurator.csproj
@@ -139,6 +139,7 @@
+
diff --git a/source/ContractConfigurator/Harmony/Contract.cs b/source/ContractConfigurator/Harmony/Contract.cs
new file mode 100644
index 00000000..ff76efac
--- /dev/null
+++ b/source/ContractConfigurator/Harmony/Contract.cs
@@ -0,0 +1,33 @@
+using Contracts;
+using HarmonyLib;
+using System;
+using System.Collections;
+using System.Threading.Tasks;
+
+namespace ContractConfigurator.Harmony
+{
+ [HarmonyPatch(typeof(Contract))]
+ internal class PatchContract
+ {
+ ///
+ /// KSP's ContractSystem calls Contract.Generate() with State.Generated when filling the offered contracts.
+ /// ConfiguredContract.Generate() always returns false for these calls (contractType is unset on fresh instances) so each attempt is a wasted allocation.
+ /// Short-circuit here before Activator.CreateInstance is reached. The pre-loader uses State.Withdrawn, which is allowed through.
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HarmonyPrefix]
+ [HarmonyPatch("Generate", new Type[] { typeof(Type), typeof(Contract.ContractPrestige), typeof(int), typeof(Contract.State) })]
+ internal static bool Prefix_Generate(ref Contract __result, Type contractType, Contract.State state)
+ {
+ if (contractType == typeof(ConfiguredContract) && state == Contract.State.Generated)
+ {
+ __result = null;
+ return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/source/ContractConfigurator/Harmony/ContractSystem.cs b/source/ContractConfigurator/Harmony/ContractSystem.cs
index fe78fbfd..d62da850 100644
--- a/source/ContractConfigurator/Harmony/ContractSystem.cs
+++ b/source/ContractConfigurator/Harmony/ContractSystem.cs
@@ -41,6 +41,39 @@ internal static void PostfixAction(ConfigNode gameNode)
}
}
+ ///
+ /// Make KSP count pre-loaded CC contracts toward the offered-contract quota
+ ///
+ ///
+ ///
+ [HarmonyPostfix]
+ [HarmonyPatch("CountContracts")]
+ internal static void Postfix_CountContracts(ref int __result, Contract.ContractPrestige difficulty)
+ {
+ if (ContractPreLoader.Instance == null) return;
+ foreach (ConfiguredContract c in ContractPreLoader.Instance.PendingContracts())
+ {
+ if (c.Prestige == difficulty)
+ __result++;
+ }
+ }
+
+ ///
+ /// Skip weighted random selection when ConfiguredContract is the only registered contract type.
+ ///
+ [HarmonyPrefix]
+ [HarmonyPatch("WeightedContractChoice")]
+ internal static bool Prefix_WeightedContractChoice(ref Type __result)
+ {
+ if (ContractSystem.ContractTypes?.Count == 1 &&
+ ContractSystem.ContractTypes[0] == typeof(ConfiguredContract))
+ {
+ __result = typeof(ConfiguredContract);
+ return false;
+ }
+ return true;
+ }
+
private class PostfixEnumerator : IEnumerable
{
public IEnumerator enumerator;
diff --git a/source/ContractConfigurator/ScenarioModules/ContractPreLoader.cs b/source/ContractConfigurator/ScenarioModules/ContractPreLoader.cs
index ace1864a..116aae58 100644
--- a/source/ContractConfigurator/ScenarioModules/ContractPreLoader.cs
+++ b/source/ContractConfigurator/ScenarioModules/ContractPreLoader.cs
@@ -29,7 +29,7 @@ public class ContractPreLoader : ScenarioModule
private static System.Random rand = new System.Random();
private static int nextContractGroup = rand.Next();
- private List contracts = new List();
+ private readonly List contracts = new List();
private string lastKey = null;
private double lastGenerationFailure;
@@ -376,7 +376,7 @@ public override void OnSave(ConfigNode node)
{
try
{
- foreach (ConfiguredContract contract in contracts.Where(c => c.ContractState == Contract.State.Offered))
+ foreach (ConfiguredContract contract in contracts)
{
ConfigNode child = new ConfigNode("CONTRACT");
node.AddNode(child);
@@ -436,9 +436,15 @@ public override void OnLoad(ConfigNode node)
}
}
- public IEnumerable PendingContracts()
+ ///
+ /// Contracts that have been generated but not yet accepted. Not all of may be presented to the player.
+ /// Do not edit the returned collection directly.
+ ///
+ ///
+ public List PendingContracts()
{
- return contracts.Where(c => c.ContractState == Contract.State.Offered);
+ // contracts only ever holds State.Offered contracts
+ return contracts;
}
}
}