Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Source/Client/Factions/FactionRepeater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static bool Template<T>(IDictionary<int, T> factionIdToData, Action<T> da
{
if (Multiplayer.Client == null || ignore) return true;

var spectatorId = Multiplayer.WorldComp.spectatorFaction.loadID;
var spectatorId = Multiplayer.WorldComp.spectatorFaction?.loadID;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can null spectatorFaction ever happen? Seems to be forcefully installed even when there is none during MultiplayerWorldComp.ExposeData, it's not tested for null anywhere else either.

Copy link
Copy Markdown
Contributor Author

@Sakura-TA Sakura-TA Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Met one time with VAE...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I remember correctly, read it at MapComponent.FinalizeInit can cause issue, I was using new API patching this
https://github.com/Vanilla-Expanded/VanillaAspirationsExpanded/blob/abb0c64efc7861cc04a0f1909eeaa5a4f589aed0/1.5/Source/VAspirE/World%20and%20Map%20Components/WorldComponent_PawnList.cs#L22

Likely when MapComponent.FinalizeInit and WorldComponent.FinalizeInit is calling?

ignore = true;
foreach (var (id, data) in factionIdToData)
{
Expand Down
22 changes: 22 additions & 0 deletions Source/Client/MultiplayerAPIBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Multiplayer.API;
using Multiplayer.Client;
using Verse;
using Multiplayer.Client.Factions;
using Multiplayer.Client.Patches;
using RimWorld;

Expand Down Expand Up @@ -199,5 +200,26 @@ public void SetThingFilterContext(ThingFilterContext context)
{
ThingFilterMarkers.DrawnThingFilter = context;
}

public bool IsMultifaction => Client.Multiplayer.GameComp.multifaction;

public Faction SpectatorFaction => Client.Multiplayer.WorldComp.spectatorFaction;

public void PushFaction(Map map, Faction faction) => FactionExtensions.PushFaction(map, faction);

public void PopFaction(Map map = null) => FactionExtensions.PopFaction(map);

public void RepeatForWorldFactions(Action action)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to share a readonly faction list?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean like we implement a IFacionData to expose factionDatas and ask modders to iter through it themselves?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm struggling with this idea exposing factionData, cuz push/popfaction is serving situations that we set faction data of distinct faction and RepeatFaction serves the iterator through all player-factions so I think all the usages are covered?
Still not a big problem if modders using it wisely though.

{
bool ignore = false;
FactionRepeater.Template(Client.Multiplayer.game?.worldComp.factionData, _ => action(), null, ref ignore);
}

public void RepeatForMapFactions(Map map, Action action)
{
if (map == null) throw new ArgumentNullException(nameof(map));
bool ignore = false;
FactionRepeater.Template(map.MpComp()?.factionData, _ => action(), map, ref ignore);
}
}
}
Loading