Skip to content

Commit

Permalink
Letters and location pings are now per faction
Browse files Browse the repository at this point in the history
Global storytellers are now per faction
Use Harmony finalizers where it makes sense
Fix assigning ideo roles in multifaction
Fix attacking non-player bases in multifaction
Fix bill pawn restrictions sometimes getting removed
Fix host's zones and areas sometimes disappearing
Fix potential desync sources caused by things running in the interface: creation of situational thoughts, pawn capacity level caching and stat caching
Remove ResearchSpeed and situation thought proxy
  • Loading branch information
Zetrith committed Nov 13, 2023
1 parent 20068a8 commit 3ec9c4c
Show file tree
Hide file tree
Showing 41 changed files with 861 additions and 462 deletions.
2 changes: 1 addition & 1 deletion About/About.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<author>RimWorld Multiplayer Team</author>
<url>https://github.com/rwmt/Multiplayer</url>
<description>&lt;color=red&gt;&lt;b&gt;Important: &lt;/b&gt; This mod should be placed right below Core and expansions in the mod list to work properly!
Requires >= Rimworld v1.4.3555&lt;/color&gt;\n
Requires Rimworld >= v1.4.3901&lt;/color&gt;\n
Multiplayer mod for RimWorld.

FAQ - https://hackmd.io/@rimworldmultiplayer/docs/
Expand Down
12 changes: 9 additions & 3 deletions Source/Client/AsyncTime/AsyncTimeComp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,12 @@ public void UpdateManagers()

public void PreContext()
{
map.PushFaction(map.ParentFaction); // bullets?
if (Multiplayer.GameComp.multifaction)
{
map.PushFaction(map.ParentFaction is { IsPlayer: true }
? map.ParentFaction
: Multiplayer.WorldComp.spectatorFaction);
}

prevTime = TimeSnapshot.GetAndSetFromMap(map);

Expand All @@ -198,7 +203,8 @@ public void PostContext()
randState = Rand.StateCompressed;
Rand.PopState();

map.PopFaction();
if (Multiplayer.GameComp.multifaction)
map.PopFaction();
}

public void ExposeData()
Expand Down Expand Up @@ -266,7 +272,7 @@ public void ExecuteCmd(ScheduledCommand cmd)

if (cmdType == CommandType.DebugTools)
{
MpDebugTools.HandleCmd(data);
DebugSync.HandleCmd(data);
}

if (cmdType == CommandType.MapTimeSpeed && Multiplayer.GameComp.asyncTime)
Expand Down
6 changes: 3 additions & 3 deletions Source/Client/AsyncTime/AsyncTimePatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static class MapUpdateMarker
public static bool updating;

static void Prefix() => updating = true;
static void Postfix() => updating = false;
static void Finalizer() => updating = false;
}

[HarmonyPatch]
Expand Down Expand Up @@ -64,7 +64,7 @@ static void Prefix(DateNotifier __instance, ref int? __state)
Find.TickManager.DebugSetTicksGame(map.AsyncTime().mapTicks);
}

static void Postfix(int? __state)
static void Finalizer(int? __state)
{
if (!__state.HasValue) return;
Find.TickManager.DebugSetTicksGame(__state.Value);
Expand Down Expand Up @@ -120,7 +120,7 @@ static class PreDrawCalcMarker
public static Pawn calculating;

static void Prefix(PawnTweener __instance) => calculating = __instance.pawn;
static void Postfix() => calculating = null;
static void Finalizer() => calculating = null;
}

[HarmonyPatch(typeof(TickManager), nameof(TickManager.TickRateMultiplier), MethodType.Getter)]
Expand Down
2 changes: 1 addition & 1 deletion Source/Client/AsyncTime/AsyncWorldTimeComp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public void ExecuteCmd(ScheduledCommand cmd)

if (cmdType == CommandType.DebugTools)
{
MpDebugTools.HandleCmd(data);
DebugSync.HandleCmd(data);
}

if (cmdType == CommandType.GlobalTimeSpeed)
Expand Down
2 changes: 1 addition & 1 deletion Source/Client/AsyncTime/MultiplayerAsyncQuest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ private static AsyncTimeComp TryGetQuestMap(Quest quest)
//Really terrible way to determine if any quest parts have a map which also has an async time
foreach (var part in quest.parts.Where(x => x != null && questPartsToCheck.Contains(x.GetType())))
{
if (part.GetType().GetField("mapParent")?.GetValue(part) is MapParent mapParent)
if (part.GetType().GetField("mapParent")?.GetValue(part) is MapParent { Map: not null } mapParent)
{
var mapAsyncTimeComp = mapParent.Map.IsPlayerHome ? mapParent.Map.AsyncTime() : null;
if (mapAsyncTimeComp != null) return mapAsyncTimeComp;
Expand Down
4 changes: 2 additions & 2 deletions Source/Client/AsyncTime/SetMapTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ static IEnumerable<MethodBase> TargetMethods()
}

[HarmonyPriority(MpPriority.MpFirst)]
static void Prefix(ref TimeSnapshot? __state)
internal static void Prefix(ref TimeSnapshot? __state)
{
if (Multiplayer.Client == null || WorldRendererUtility.WorldRenderedNow || Find.CurrentMap == null) return;
__state = TimeSnapshot.GetAndSetFromMap(Find.CurrentMap);
}

[HarmonyPriority(MpPriority.MpLast)]
static void Postfix(TimeSnapshot? __state) => __state?.Set();
internal static void Postfix(TimeSnapshot? __state) => __state?.Set();
}

[HarmonyPatch]
Expand Down
6 changes: 3 additions & 3 deletions Source/Client/AsyncTime/StorytellerPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static bool Prefix()
return Multiplayer.Client == null || Multiplayer.Ticking;
}

static void Postfix() => updating = false;
static void Finalizer() => updating = false;
}

[HarmonyPatch(typeof(Storyteller))]
Expand Down Expand Up @@ -92,7 +92,7 @@ static void Prefix(IIncidentTarget target, ref Map __state)
}
}

static void Postfix(Map __state)
static void Finalizer(Map __state)
{
if (__state != null)
{
Expand All @@ -115,7 +115,7 @@ static void Prefix(IncidentParms parms, ref Map __state)
}
}

static void Postfix(Map __state)
static void Finalizer(Map __state)
{
if (__state != null)
{
Expand Down
22 changes: 9 additions & 13 deletions Source/Client/Comp/Map/MultiplayerMapComp.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using HarmonyLib;
using Multiplayer.Client.Factions;
Expand All @@ -9,7 +8,6 @@
using Multiplayer.Common;
using RimWorld;
using RimWorld.Planet;
using UnityEngine;
using Verse;

namespace Multiplayer.Client
Expand Down Expand Up @@ -96,13 +94,6 @@ public void SetFaction(Faction faction)
map.listerMergeables = data.listerMergeables;
}

[Conditional("DEBUG")]
public void CheckInvariant()
{
if (factionData.TryGetValue(Faction.OfPlayer.loadID, out var data) && map.areaManager != data.areaManager)
Log.Error($"(Debug) Invariant broken for {Faction.OfPlayer}: {FactionContext.stack.ToStringSafeEnumerable()} {factionData.FirstOrDefault(d => d.Value.areaManager == map.areaManager)} {StackTraceUtility.ExtractStackTrace()}");
}

public CustomFactionMapData GetCurrentCustomFactionData()
{
return customFactionData[Faction.OfPlayer.loadID];
Expand Down Expand Up @@ -140,12 +131,12 @@ private void ExposeFactionData()
{
if (Scribe.mode == LoadSaveMode.Saving)
{
int currentFactionId = Faction.OfPlayer.loadID;
int currentFactionId =GetFactionId(map.zoneManager);
Scribe_Custom.LookValue(currentFactionId, "currentFactionId");

var data = new Dictionary<int, FactionMapData>(factionData);
data.Remove(currentFactionId);
Scribe_Custom.LookValueDeep(ref data, "factionMapData", map);
var savedFactionData = new Dictionary<int, FactionMapData>(factionData);
savedFactionData.Remove(currentFactionId);
Scribe_Custom.LookValueDeep(ref savedFactionData, "factionMapData", map);
}
else
{
Expand Down Expand Up @@ -189,6 +180,11 @@ public void ReadSemiPersistent(ByteReader reader)
ritualSession = session;
}
}

public int GetFactionId(ZoneManager zoneManager)
{
return factionData.First(kv => kv.Value.zoneManager == zoneManager).Key;
}
}

[HarmonyPatch(typeof(MapDrawer), nameof(MapDrawer.DrawMapMesh))]
Expand Down
28 changes: 21 additions & 7 deletions Source/Client/Comp/World/FactionWorldData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,40 @@ namespace Multiplayer.Client;
public class FactionWorldData : IExposable
{
public int factionId;
public bool online;

public ResearchManager researchManager;
public OutfitDatabase outfitDatabase;
public DrugPolicyDatabase drugPolicyDatabase;
public FoodRestrictionDatabase foodRestrictionDatabase;
public PlaySettings playSettings;

public ResearchSpeed researchSpeed;
public History history;
public Storyteller storyteller;
public StoryWatcher storyWatcher;

public FactionWorldData() { }

public void ExposeData()
{
Scribe_Values.Look(ref factionId, "factionId");
Scribe_Values.Look(ref online, "online");

Scribe_Deep.Look(ref researchManager, "researchManager");
Scribe_Deep.Look(ref drugPolicyDatabase, "drugPolicyDatabase");
Scribe_Deep.Look(ref outfitDatabase, "outfitDatabase");
Scribe_Deep.Look(ref foodRestrictionDatabase, "foodRestrictionDatabase");
Scribe_Deep.Look(ref playSettings, "playSettings");

Scribe_Deep.Look(ref researchSpeed, "researchSpeed");
Scribe_Deep.Look(ref history, "history");
Scribe_Deep.Look(ref storyteller, "storyteller");
Scribe_Deep.Look(ref storyWatcher, "storyWatcher");

if (Scribe.mode == LoadSaveMode.LoadingVars)
{
history ??= new History();
storyteller ??= new Storyteller(Find.Storyteller.def, Find.Storyteller.difficultyDef,
Find.Storyteller.difficulty);
storyWatcher ??= new StoryWatcher();
}
}

public void ReassignIds()
Expand All @@ -55,7 +65,10 @@ public static FactionWorldData New(int factionId)
outfitDatabase = new OutfitDatabase(),
foodRestrictionDatabase = new FoodRestrictionDatabase(),
playSettings = new PlaySettings(),
researchSpeed = new ResearchSpeed(),

history = new History(),
storyteller = new Storyteller(Find.Storyteller.def, Find.Storyteller.difficultyDef, Find.Storyteller.difficulty),
storyWatcher = new StoryWatcher()
};
}

Expand All @@ -64,15 +77,16 @@ public static FactionWorldData FromCurrent(int factionId)
return new FactionWorldData()
{
factionId = factionId == int.MinValue ? Faction.OfPlayer.loadID : factionId,
online = true,

researchManager = Find.ResearchManager,
drugPolicyDatabase = Current.Game.drugPolicyDatabase,
outfitDatabase = Current.Game.outfitDatabase,
foodRestrictionDatabase = Current.Game.foodRestrictionDatabase,
playSettings = Current.Game.playSettings,

researchSpeed = new ResearchSpeed(),
history = Find.History,
storyteller = Find.Storyteller,
storyWatcher = Find.StoryWatcher
};
}
}
17 changes: 12 additions & 5 deletions Source/Client/Comp/World/MultiplayerWorldComp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ private void ExposeFactionData()
{
if (Scribe.mode == LoadSaveMode.Saving)
{
int currentFactionId = Faction.OfPlayer.loadID;
int currentFactionId = GetFactionId(Find.ResearchManager);
Scribe_Custom.LookValue(currentFactionId, "currentFactionId");

var factionData = new Dictionary<int, FactionWorldData>(this.factionData);
factionData.Remove(currentFactionId);
var savedFactionData = new Dictionary<int, FactionWorldData>(factionData);
savedFactionData.Remove(currentFactionId);

Scribe_Collections.Look(ref factionData, "factionData", LookMode.Value, LookMode.Deep);
Scribe_Collections.Look(ref savedFactionData, "factionData", LookMode.Value, LookMode.Deep);
}
else
{
Expand Down Expand Up @@ -144,7 +144,9 @@ public void SetFaction(Faction faction)
game.foodRestrictionDatabase = data.foodRestrictionDatabase;
game.playSettings = data.playSettings;

SyncResearch.researchSpeed = data.researchSpeed;
game.history = data.history;
game.storyteller = data.storyteller;
game.storyWatcher = data.storyWatcher;
}

public void DirtyColonyTradeForMap(Map map)
Expand Down Expand Up @@ -179,6 +181,11 @@ public bool AnyTradeSessionsOnMap(Map map)
return false;
}

public int GetFactionId(ResearchManager researchManager)
{
return factionData.First(kv => kv.Value.researchManager == researchManager).Key;
}

public override string ToString()
{
return $"{nameof(MultiplayerWorldComp)}_{world}";
Expand Down
54 changes: 0 additions & 54 deletions Source/Client/ConstantTicker.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using HarmonyLib;
using Multiplayer.Client.Factions;
using Multiplayer.Common;
using RimWorld;
using Verse;
Expand All @@ -17,14 +15,6 @@ public static void Tick()

try
{
//TickResearch();

// Not really deterministic but here for possible future server-side game state verification
//Extensions.PushFaction(null, Multiplayer.RealPlayerFaction);
//TickSync();
//SyncResearch.ConstantTick();
//Extensions.PopFaction();

TickShipCountdown();
TickSyncCoordinator();
TickAutosave();
Expand Down Expand Up @@ -91,50 +81,6 @@ private static void TickShipCountdown()
ShipCountdown.CountdownEnded();
}
}

private static Func<BufferTarget, BufferData, bool> bufferPredicate = SyncFieldUtil.BufferedChangesPruner(() => TickPatch.Timer);

private static void TickSync()
{
foreach (SyncField f in Sync.bufferedFields)
{
if (!f.inGameLoop) continue;
SyncFieldUtil.bufferedChanges[f].RemoveAll(bufferPredicate);
}
}

private static Pawn dummyPawn = new()
{
relations = new Pawn_RelationsTracker(dummyPawn),
};

public static void TickResearch()
{
MultiplayerWorldComp comp = Multiplayer.WorldComp;
foreach (FactionWorldData factionData in comp.factionData.Values)
{
if (factionData.researchManager.currentProj == null)
continue;

FactionExtensions.PushFaction(null, factionData.factionId);

foreach (var kv in factionData.researchSpeed.data)
{
Pawn pawn = PawnsFinder.AllMaps_Spawned.FirstOrDefault(p => p.thingIDNumber == kv.Key);
if (pawn == null)
{
dummyPawn.factionInt = Faction.OfPlayer;
pawn = dummyPawn;
}

Find.ResearchManager.ResearchPerformed(kv.Value, pawn);

dummyPawn.factionInt = null;
}

FactionExtensions.PopFaction();
}
}
}

[HarmonyPatch(typeof(ShipCountdown), nameof(ShipCountdown.CancelCountdown))]
Expand Down
2 changes: 1 addition & 1 deletion Source/Client/Debug/DebugActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private static void SetFaction()
[DebugAction(MultiplayerCategory, actionType = DebugActionType.ToolMap, allowedGameStates = AllowedGameStates.PlayingOnMap)]
public static void SpawnShuttleAcceptColonists()
{
var shuttle = ThingMaker.MakeThing(ThingDefOf.Shuttle, null);
var shuttle = ThingMaker.MakeThing(ThingDefOf.Shuttle);
shuttle.TryGetComp<CompShuttle>().acceptColonists = true;
GenPlace.TryPlaceThing(shuttle, UI.MouseCell(), Find.CurrentMap, ThingPlaceMode.Near);
}
Expand Down
Loading

0 comments on commit 3ec9c4c

Please sign in to comment.