From c3f54f1b0a73ddb22c240063d70890a12e189b71 Mon Sep 17 00:00:00 2001 From: still222 <118853487+still222@users.noreply.github.com> Date: Wed, 22 Oct 2025 06:13:23 +0500 Subject: [PATCH 1/3] Create MultifactionEvents.cs --- Source/Client/Patches/MultifactionEvents.cs | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Source/Client/Patches/MultifactionEvents.cs diff --git a/Source/Client/Patches/MultifactionEvents.cs b/Source/Client/Patches/MultifactionEvents.cs new file mode 100644 index 00000000..fc19c85a --- /dev/null +++ b/Source/Client/Patches/MultifactionEvents.cs @@ -0,0 +1,73 @@ +using HarmonyLib; +using Multiplayer.API; +using RimWorld; +using RimWorld.Planet; +using Verse; + +namespace Multiplayer.Client; + +// Set of patches that forces events to play for a correct player on a correct map + +// First patch is for the "SettlementDefeatUtility.IsDefeated", in vanilla it's purpose +// is to fire events on non-settled enemy faction bases, that player had defeated. +// But it doesn account situation where "enemy base" is actually an other player base, +// who is friendly with you. Which (I assume) is the most common situation for MP. + +[HarmonyPatch(typeof(SettlementDefeatUtility), nameof(SettlementDefeatUtility.IsDefeated), typeof(Map), typeof(Faction))] +public static class Patch_SettlementDefeatUtility_IsDefeated +{ + static bool Prefix(Faction faction, ref bool __result) + { + // We run original if's not MP, or faction owning the map is not any player + if (!MP.IsInMultiplayer || !faction.IsPlayer) + return true; + + // We skip checking if "enemy" is defeated on any player base (beacuse other players could be friendly) + __result = false; + return false; + } +} + +// Second patch forbids from firing an event on an incorrect map. +// It's uses mostly vanilla logic for incorrect event by sending th "true" +// as an output for shutdowning events. I left the debug log line to see how many +// incorrect events are "lost", but game storyteller should understand correctly +// that these events were not fired, and will adapt by firing more (correct) events. + +[HarmonyPatch(typeof(IncidentWorker), nameof(IncidentWorker.TryExecute))] +public static class Patch_IncidentWorker_TryExecute_ForMultifactionTriggering +{ + static bool Prefix(IncidentParms parms, ref bool __result) + { + // We make some sanity checks and assume, that empty (without any colonists) + // factionless maps (such as dungeones) are impossible and instantly abandoned. + if (!MP.IsInMultiplayer || + parms.target is not Map map || + map.ParentFaction == Faction.OfPlayer || + map.mapPawns.AnyColonistSpawned) + { + //Log.Message($"[Multiplayer] Incident greenlit"); + return true; + } + + // Skip incidents if we couldn't do it + Log.Warning($"[Multiplayer] Incident shutdown on a {map}"); + __result = true; + return false; + } +} + +// This is (currently) purely debug patch. I used it to see for which faction +// event was supposed to fire (and thus for whitch faction evetn letter will arrive). +// I will leave its here just in case. It could be useful, as some event keep firing +// for the "Spectator" player, but I didn't notice any gameplay effects from that. + +//[HarmonyPatch(typeof(LetterStack), nameof(LetterStack.ReceiveLetter), typeof(Letter), typeof(string), typeof(int), typeof(bool))] +//static class LetterStackReceiveFactionDebug +//{ +// // todo the letter might get culled from the archive if it isn't in the stack and Sync depends on the archive +// static void Prefix() +// { +// Log.Message($"[StkMPPatch] Current Incident Faction: {Faction.OfPlayer}"); +// } +//} \ No newline at end of file From 3f769ce00d32663d97903374faf23c409a4f959e Mon Sep 17 00:00:00 2001 From: still222 <118853487+still222@users.noreply.github.com> Date: Wed, 22 Oct 2025 11:13:23 +0500 Subject: [PATCH 2/3] Update MultifactionEvents.cs Just tidying up comments. No changes in code. Fixing spelling errors etc. Hopefully a little more readable now. --- Source/Client/Patches/MultifactionEvents.cs | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/Client/Patches/MultifactionEvents.cs b/Source/Client/Patches/MultifactionEvents.cs index fc19c85a..742e850d 100644 --- a/Source/Client/Patches/MultifactionEvents.cs +++ b/Source/Client/Patches/MultifactionEvents.cs @@ -8,9 +8,9 @@ namespace Multiplayer.Client; // Set of patches that forces events to play for a correct player on a correct map -// First patch is for the "SettlementDefeatUtility.IsDefeated", in vanilla it's purpose -// is to fire events on non-settled enemy faction bases, that player had defeated. -// But it doesn account situation where "enemy base" is actually an other player base, +// First patch is for the "SettlementDefeatUtility.IsDefeated". In vanilla it's purpose +// is to fire events on a non-settled enemy faction bases that player had defeated. +// But it doesn't account for situations, where "enemy base" is actually an other player base, // who is friendly with you. Which (I assume) is the most common situation for MP. [HarmonyPatch(typeof(SettlementDefeatUtility), nameof(SettlementDefeatUtility.IsDefeated), typeof(Map), typeof(Faction))] @@ -22,15 +22,15 @@ static bool Prefix(Faction faction, ref bool __result) if (!MP.IsInMultiplayer || !faction.IsPlayer) return true; - // We skip checking if "enemy" is defeated on any player base (beacuse other players could be friendly) + // We skip checking if "enemy" is defeated on any player base (because other players most likely are friendly) __result = false; return false; } } // Second patch forbids from firing an event on an incorrect map. -// It's uses mostly vanilla logic for incorrect event by sending th "true" -// as an output for shutdowning events. I left the debug log line to see how many +// It's uses mostly vanilla logic for incorrect event by sending "true" +// as an output to shutdown an event. I left the debug log line to see how many // incorrect events are "lost", but game storyteller should understand correctly // that these events were not fired, and will adapt by firing more (correct) events. @@ -39,8 +39,8 @@ public static class Patch_IncidentWorker_TryExecute_ForMultifactionTriggering { static bool Prefix(IncidentParms parms, ref bool __result) { - // We make some sanity checks and assume, that empty (without any colonists) - // factionless maps (such as dungeones) are impossible and instantly abandoned. + // We make some sanity checks and assume, that empty (without any player colonists) + // factionless maps (such as dungeons) are impossible and instantly abandoned. if (!MP.IsInMultiplayer || parms.target is not Map map || map.ParentFaction == Faction.OfPlayer || @@ -50,16 +50,16 @@ parms.target is not Map map || return true; } - // Skip incidents if we couldn't do it + // Skip incidents if we fail previous check Log.Warning($"[Multiplayer] Incident shutdown on a {map}"); __result = true; return false; } } -// This is (currently) purely debug patch. I used it to see for which faction -// event was supposed to fire (and thus for whitch faction evetn letter will arrive). -// I will leave its here just in case. It could be useful, as some event keep firing +// This is (currently) purely a debug patch. I used it to see for which faction +// event was supposed to fire (and thus for which faction event notification will arrive). +// I will leave it here just in case. It could be useful, as some events keep firing // for the "Spectator" player, but I didn't notice any gameplay effects from that. //[HarmonyPatch(typeof(LetterStack), nameof(LetterStack.ReceiveLetter), typeof(Letter), typeof(string), typeof(int), typeof(bool))] @@ -70,4 +70,4 @@ parms.target is not Map map || // { // Log.Message($"[StkMPPatch] Current Incident Faction: {Faction.OfPlayer}"); // } -//} \ No newline at end of file +//} From 63b87c703770b34368ebb1d69a42584874a3a684 Mon Sep 17 00:00:00 2001 From: still222 <118853487+still222@users.noreply.github.com> Date: Sat, 25 Oct 2025 13:21:50 +0500 Subject: [PATCH 3/3] Update MultifactionEvents.cs Changing `!MP.IsInMultiplayer` to `Multiplayer.Client == null` --- Source/Client/Patches/MultifactionEvents.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/Client/Patches/MultifactionEvents.cs b/Source/Client/Patches/MultifactionEvents.cs index 742e850d..8d642515 100644 --- a/Source/Client/Patches/MultifactionEvents.cs +++ b/Source/Client/Patches/MultifactionEvents.cs @@ -1,5 +1,4 @@ using HarmonyLib; -using Multiplayer.API; using RimWorld; using RimWorld.Planet; using Verse; @@ -19,7 +18,7 @@ public static class Patch_SettlementDefeatUtility_IsDefeated static bool Prefix(Faction faction, ref bool __result) { // We run original if's not MP, or faction owning the map is not any player - if (!MP.IsInMultiplayer || !faction.IsPlayer) + if (Multiplayer.Client == null || !faction.IsPlayer) return true; // We skip checking if "enemy" is defeated on any player base (because other players most likely are friendly) @@ -41,7 +40,7 @@ static bool Prefix(IncidentParms parms, ref bool __result) { // We make some sanity checks and assume, that empty (without any player colonists) // factionless maps (such as dungeons) are impossible and instantly abandoned. - if (!MP.IsInMultiplayer || + if (Multiplayer.Client == null || parms.target is not Map map || map.ParentFaction == Faction.OfPlayer || map.mapPawns.AnyColonistSpawned)