Skip to content

Commit

Permalink
Update 0.9, multifaction (rwmt#399)
Browse files Browse the repository at this point in the history
- Protocol 34
- Multifaction: new hosting option, faction creation screen, set faction context in more places, refactor code related to factions
- Remove id blocks
- Track getting unique ids in desync traces
- Log stack traces in Sync command write log
- Use my UI layout helper (Layouter.cs) from Prepatcher
- Only set faction context when necessary (should slightly improve performance)
- Move Native and DeferredStackTracingImpl to Common
- Reorganize project dependencies (they previously doubled as artifact output control)
- Move conversion to singleplayer into its own file
- Split player cursor and location ping code
- Remove HotSwappableAttribute

- Fix applying the mod list with "Fix and restart"
- Fix issues with desync tracing and latest Harmony
- Fix desyncs related to autosaving and battle log
- Fix exception when not including all arguments in SyncMethod exposeParameters
- Fix clicking on files in save list sometimes not working
  • Loading branch information
Zetrith authored Oct 18, 2023
1 parent a4efdf7 commit 768cfcd
Show file tree
Hide file tree
Showing 140 changed files with 3,206 additions and 1,819 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,6 @@ __pycache__/
/Multiplayer
Multiplayer*.zip

!Source/Client/Debug/
!Source/Client/Debug/

/Source/mpdb
57 changes: 10 additions & 47 deletions Source/Client/AsyncTime/AsyncTimeComp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Multiplayer.API;
using Verse;
using Multiplayer.Client.Comp;
using Multiplayer.Client.Factions;
using Multiplayer.Client.Patches;
using Multiplayer.Client.Saving;
using Multiplayer.Client.Util;
Expand Down Expand Up @@ -67,7 +68,7 @@ public void SetDesiredTimeSpeed(TimeSpeed speed)

public float TimeToTickThrough { get; set; }

public Queue<ScheduledCommand> Cmds { get => cmds; }
public Queue<ScheduledCommand> Cmds => cmds;

public int TickableId => map.uniqueID;

Expand Down Expand Up @@ -148,10 +149,7 @@ public void TickMapTrading()
if (session.playerNegotiator.Map != map) continue;

if (session.ShouldCancel())
{
Multiplayer.WorldComp.RemoveTradeSession(session);
continue;
}
}
}

Expand Down Expand Up @@ -183,9 +181,6 @@ public void PreContext()
Current.Game.storyteller = storyteller;
Current.Game.storyWatcher = storyWatcher;

//UniqueIdsPatch.CurrentBlock = map.MpComp().mapIdBlock;
UniqueIdsPatch.CurrentBlock = Multiplayer.GlobalIdBlock;

Rand.PushState();
Rand.StateCompressed = randState;

Expand All @@ -195,8 +190,6 @@ public void PreContext()

public void PostContext()
{
UniqueIdsPatch.CurrentBlock = null;

Current.Game.storyteller = prevStoryteller;
Current.Game.storyWatcher = prevStoryWatcher;

Expand Down Expand Up @@ -276,11 +269,6 @@ public void ExecuteCmd(ScheduledCommand cmd)
MpDebugTools.HandleCmd(data);
}

if (cmdType == CommandType.CreateMapFactionData)
{
HandleMapFactionData(cmd, data);
}

if (cmdType == CommandType.MapTimeSpeed && Multiplayer.GameComp.asyncTime)
{
TimeSpeed speed = (TimeSpeed)data.ReadByte();
Expand All @@ -289,19 +277,9 @@ public void ExecuteCmd(ScheduledCommand cmd)
MpLog.Debug("Set map time speed " + speed);
}

if (cmdType == CommandType.MapIdBlock)
{
IdBlock block = IdBlock.Deserialize(data);

if (map != null)
{
//map.MpComp().mapIdBlock = block;
}
}

if (cmdType == CommandType.Designator)
{
HandleDesignator(cmd, data);
HandleDesignator(data);
}

UpdateManagers();
Expand Down Expand Up @@ -357,28 +335,11 @@ private static void TrySetCurrentMap(Map map)
}
}

private void HandleMapFactionData(ScheduledCommand cmd, ByteReader data)
{
int factionId = data.ReadInt32();

Faction faction = Find.FactionManager.GetById(factionId);
MultiplayerMapComp comp = map.MpComp();

if (!comp.factionData.ContainsKey(factionId))
{
BeforeMapGeneration.InitNewMapFactionData(map, faction);
MpLog.Log($"New map faction data for {faction.GetUniqueLoadID()}");
}
}

private void HandleDesignator(ScheduledCommand command, ByteReader data)
private void HandleDesignator(ByteReader data)
{
var mode = SyncSerialization.ReadSync<DesignatorMode>(data);
var designator = SyncSerialization.ReadSync<Designator>(data);

Container<Area>? prevArea = null;

bool SetState(Designator designator, ByteReader data)
bool SetState(Designator designator)
{
if (designator is Designator_AreaAllowed)
{
Expand Down Expand Up @@ -415,9 +376,12 @@ void RestoreState()
DesignatorInstall_SetThingToInstall.thingToInstall = null;
}

var mode = SyncSerialization.ReadSync<DesignatorMode>(data);
var designator = SyncSerialization.ReadSync<Designator>(data);

try
{
if (!SetState(designator, data)) return;
if (!SetState(designator)) return;

if (mode == DesignatorMode.SingleCell)
{
Expand Down Expand Up @@ -454,9 +418,8 @@ private void CacheNothingHappening()
nothingHappeningCached = true;
var list = map.mapPawns.SpawnedPawnsInFaction(Faction.OfPlayer);

for (int j = 0; j < list.Count; j++)
foreach (var pawn in list)
{
Pawn pawn = list[j];
if (pawn.HostFaction == null && pawn.RaceProps.Humanlike && pawn.Awake())
nothingHappeningCached = false;
}
Expand Down
61 changes: 17 additions & 44 deletions Source/Client/AsyncTime/AsyncWorldTimeComp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using HarmonyLib;
using Multiplayer.Client.Comp;
using Multiplayer.Client.Desyncs;
using Multiplayer.Client.Patches;
using Multiplayer.Client.Factions;
using Multiplayer.Client.Saving;
using Multiplayer.Client.Util;
using Multiplayer.Common;
Expand Down Expand Up @@ -45,10 +45,12 @@ public float TickRateMultiplier(TimeSpeed speed)
};
}

// Run at the speed of the fastest map
public TimeSpeed DesiredTimeSpeed => Find.Maps.Select(m => m.AsyncTime())
// Run at the speed of the fastest map or at chosen speed if there are no maps
public TimeSpeed DesiredTimeSpeed => !Find.Maps.Any() ?
timeSpeedInt :
Find.Maps.Select(m => m.AsyncTime())
.Where(a => a.ActualRateMultiplier(a.DesiredTimeSpeed) != 0f)
.Max(a => a?.DesiredTimeSpeed) ?? timeSpeedInt;
.Max(a => a?.DesiredTimeSpeed) ?? TimeSpeed.Paused;

public void SetDesiredTimeSpeed(TimeSpeed speed)
{
Expand Down Expand Up @@ -137,16 +139,20 @@ public void Tick()
public void PreContext()
{
Find.TickManager.CurTimeSpeed = DesiredTimeSpeed;
UniqueIdsPatch.CurrentBlock = Multiplayer.GlobalIdBlock;
Rand.PushState();
Rand.StateCompressed = randState;

if (Multiplayer.GameComp.multifaction)
FactionExtensions.PushFaction(null, Multiplayer.WorldComp.spectatorFaction);
}

public void PostContext()
{
if (Multiplayer.GameComp.multifaction)
FactionExtensions.PopFaction();

randState = Rand.StateCompressed;
Rand.PopState();
UniqueIdsPatch.CurrentBlock = null;
}

public void ExecuteCmd(ScheduledCommand cmd)
Expand All @@ -159,7 +165,7 @@ public void ExecuteCmd(ScheduledCommand cmd)
TickPatch.currentExecutingCmdIssuedBySelf = cmd.issuedBySelf && !TickPatch.Simulating;

PreContext();
Extensions.PushFaction(null, cmd.GetFaction());
FactionExtensions.PushFaction(null, cmd.GetFaction());

bool prevDevMode = Prefs.data.devMode;
var prevGodMode = DebugSettings.godMode;
Expand Down Expand Up @@ -195,14 +201,9 @@ public void ExecuteCmd(ScheduledCommand cmd)
SetTimeEverywhere(TimeSpeed.Paused);
}

if (cmdType == CommandType.SetupFaction)
{
HandleSetupFaction(cmd, data);
}

if (cmdType == CommandType.CreateJoinPoint)
{
LongEventHandler.QueueLongEvent(CreateJoinPoint, "MpCreatingJoinPoint", false, null);
LongEventHandler.QueueLongEvent(CreateJoinPointAndSendIfHost, "MpCreatingJoinPoint", false, null);
}

if (cmdType == CommandType.InitPlayerData)
Expand All @@ -224,7 +225,7 @@ public void ExecuteCmd(ScheduledCommand cmd)
MpLog.Debug($"rand calls {DeferredStackTracing.randCalls - randCalls1}");
MpLog.Debug("rand state " + Rand.StateCompressed);

Extensions.PopFaction();
FactionExtensions.PopFaction();
PostContext();
TickPatch.currentExecutingCmdIssuedBySelf = false;
executingCmdWorld = false;
Expand All @@ -236,9 +237,9 @@ public void ExecuteCmd(ScheduledCommand cmd)
}
}

private static void CreateJoinPoint()
private static void CreateJoinPointAndSendIfHost()
{
Multiplayer.session.dataSnapshot = SaveLoad.CreateGameDataSnapshot(SaveLoad.SaveAndReload());
Multiplayer.session.dataSnapshot = SaveLoad.CreateGameDataSnapshot(SaveLoad.SaveAndReload(), Multiplayer.GameComp.multifaction);

if (!TickPatch.Simulating && !Multiplayer.IsReplay &&
(Multiplayer.LocalServer != null || Multiplayer.arbiterInstance))
Expand Down Expand Up @@ -288,34 +289,6 @@ private void HandleTimeVote(ScheduledCommand cmd, ByteReader data)
tickable.SetDesiredTimeSpeed(Multiplayer.GameComp.GetLowestTimeVote(tickableId));
}

private void HandleSetupFaction(ScheduledCommand command, ByteReader data)
{
int factionId = data.ReadInt32();
Faction faction = Find.FactionManager.GetById(factionId);

if (faction == null)
{
faction = new Faction
{
loadID = factionId,
def = FactionDefOf.PlayerColony,
Name = "Multiplayer faction",
};

Find.FactionManager.Add(faction);

foreach (Faction current in Find.FactionManager.AllFactionsListForReading)
{
if (current == faction) continue;
current.TryMakeInitialRelationsWith(faction);
}

Multiplayer.WorldComp.factionData[factionId] = FactionWorldData.New(factionId);

MpLog.Log($"New faction {faction.GetUniqueLoadID()}");
}
}

public void FinalizeInit()
{
Multiplayer.game.SetThingMakerSeed((int)(randState >> 32));
Expand Down
3 changes: 1 addition & 2 deletions Source/Client/AsyncTime/StorytellerPatches.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using HarmonyLib;
Expand Down
19 changes: 6 additions & 13 deletions Source/Client/Comp/Game/MultiplayerGameComp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,31 @@ namespace Multiplayer.Client.Comp
public class MultiplayerGameComp : IExposable, IHasSemiPersistentData
{
public bool asyncTime;
public bool multifaction;
public bool debugMode;
public bool logDesyncTraces;
public PauseOnLetter pauseOnLetter;
public TimeControl timeControl;
public Dictionary<int, PlayerData> playerData = new(); // player id to player data

public IdBlock globalIdBlock = new(int.MaxValue / 2, 1_000_000_000);
public string idBlockBase64;

public bool IsLowestWins => timeControl == TimeControl.LowestWins;

public PlayerData LocalPlayerDataOrNull => playerData.GetValueOrDefault(Multiplayer.session.playerId);

public MultiplayerGameComp(Game game)
{
}

public void ExposeData()
{
Scribe_Values.Look(ref asyncTime, "asyncTime", true, true);
Scribe_Values.Look(ref multifaction, "multifaction", false, true);
Scribe_Values.Look(ref debugMode, "debugMode");
Scribe_Values.Look(ref logDesyncTraces, "logDesyncTraces");
Scribe_Values.Look(ref pauseOnLetter, "pauseOnLetter");
Scribe_Values.Look(ref timeControl, "timeControl");

Scribe_Custom.LookIdBlock(ref globalIdBlock, "globalIdBlock");

if (globalIdBlock == null)
{
// todo globalIdBlock was previously in WorldComp, this is a quick hack to make old saves compatible
Log.Warning("Global id block was null, fixing...");
globalIdBlock = new IdBlock(int.MaxValue / 2, 1_000_000_000);
}
// Store for back-compat conversion in GameExposeComponentsPatch
if (Scribe.mode == LoadSaveMode.LoadingVars)
Scribe_Values.Look(ref idBlockBase64, "globalIdBlock");
}

public void WriteSemiPersistent(ByteWriter writer)
Expand Down
2 changes: 1 addition & 1 deletion Source/Client/Comp/Map/ExposeActor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void ExposeData()
// This depends on the fact that the implementation of HashSet RimWorld currently uses
// "preserves" insertion order (as long as elements are only added and not removed
// [which is the case for Scribe managers])
public static void Register(Action action)
public static void OnPostInit(Action action)
{
if (Scribe.mode == LoadSaveMode.LoadingVars)
Scribe.loader.initer.RegisterForPostLoadInit(new ExposeActor(action));
Expand Down
5 changes: 3 additions & 2 deletions Source/Client/Comp/Map/FactionMapData.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Multiplayer.Client.Factions;
using RimWorld;
using Verse;

Expand Down Expand Up @@ -46,14 +47,14 @@ private FactionMapData(int factionId, Map map) : this(map)

public void ExposeData()
{
ExposeActor.Register(() => map.PushFaction(factionId));
ExposeActor.OnPostInit(() => map.PushFaction(factionId));

Scribe_Values.Look(ref factionId, "factionId");
Scribe_Deep.Look(ref designationManager, "designationManager", map);
Scribe_Deep.Look(ref areaManager, "areaManager", map);
Scribe_Deep.Look(ref zoneManager, "zoneManager", map);

ExposeActor.Register(() => map.PopFaction());
ExposeActor.OnPostInit(() => map.PopFaction());
}

public static FactionMapData New(int factionId, Map map)
Expand Down
Loading

0 comments on commit 768cfcd

Please sign in to comment.