Skip to content
Closed
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
62 changes: 59 additions & 3 deletions Source/Mods/CommonSense.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System;
using System;
using System.Reflection;
using HarmonyLib;
using Multiplayer.API;
using RimWorld;
using Verse;
using Verse.AI;

namespace Multiplayer.Compat
{
Expand All @@ -17,6 +20,9 @@ internal class CommonSense
private static GetChecker getCompUnlockerCheckerMethod;
private static Type rpgStyleInventoryTabType;

// Meditation economy sync support
private static AccessTools.FieldRef<bool> meditationEconomyField;

public CommonSense(ModContentPack mod)
{
var type = AccessTools.TypeByName("CommonSense.CompUnloadChecker");
Expand All @@ -32,6 +38,18 @@ public CommonSense(ModContentPack mod)
// Gizmo patch
MpCompat.RegisterLambdaMethod("CommonSense.DoCleanComp", "CompGetGizmosExtra", 1);

// Meditation economy: cancel the original postfix in MP and replace with
// a host-authoritative version that syncs the EndJobWith decision.
meditationEconomyField = AccessTools.StaticFieldRefAccess<bool>(
AccessTools.Field(AccessTools.TypeByName("CommonSense.Settings"), "meditation_economy"));
MpCompat.harmony.Patch(
AccessTools.Method("CommonSense.JobDriver_MeditationTick_CommonSensePatch:Postfix"),
prefix: new HarmonyMethod(typeof(CommonSense), nameof(CancelMeditationPostfixInMp)));
MpCompat.harmony.Patch(
AccessTools.Method(typeof(JobDriver_Meditate), "MeditationTick"),
postfix: new HarmonyMethod(typeof(CommonSense), nameof(HostAuthorativeMeditationCheck)));
MP.RegisterSyncMethod(typeof(CommonSense), nameof(SyncedEndMeditationJob));

// RPG Style Inventory patch sync (popup menu)
rpgStyleInventoryTabType = AccessTools.TypeByName("Sandy_Detailed_RPG_Inventory.Sandy_Detailed_RPG_GearTab");
// If the type doesn't exist (no RPG style inventory active), skip syncing and patching the relevant parts
Expand All @@ -51,6 +69,44 @@ public CommonSense(ModContentPack mod)
LongEventHandler.ExecuteWhenFinished(LatePatch);
}

// Cancel the original CommonSense meditation postfix in MP -
// replaced by HostAuthorativeMeditationCheck below.
private static bool CancelMeditationPostfixInMp() => !MP.IsInMultiplayer;

// Host-authoritative replacement for CommonSense's meditation economy.
// Mirrors the original logic but only evaluates on the host, then syncs
// the EndJobWith decision to all clients for deterministic execution.
private static void HostAuthorativeMeditationCheck(JobDriver_Meditate __instance)
{
if (!MP.IsInMultiplayer || !MP.IsHosting)
return;

if (!meditationEconomyField.Invoke() || __instance?.pawn == null)
return;

var pawn = __instance.pawn;
bool meditating = pawn.GetTimeAssignment() == TimeAssignmentDefOf.Meditate;

var entropy = pawn.psychicEntropy;
var joy = pawn.needs?.joy;
var joyKind = pawn.CurJob?.def?.joyKind;

if (!meditating
&& (joy == null || joy.CurLevel >= 0.98f || joyKind != null && joy.tolerances?.BoredOf(joyKind) == true)
&& (entropy == null || !entropy.NeedsPsyfocus || entropy.CurrentPsyfocus == 1f))
{
SyncedEndMeditationJob(pawn);
}
}

// Synced method: host tells all clients to end this pawn's meditation job.
// Executed on all clients at the same tick for deterministic state.
private static void SyncedEndMeditationJob(Pawn pawn)
{
if (pawn.jobs?.curDriver is JobDriver_Meditate driver)
driver.EndJobWith(JobCondition.InterruptForced);
}

private static void LatePatch()
{
// Watch unload bool changes
Expand Down Expand Up @@ -82,7 +138,7 @@ private static void CommonSensePatchPostfix(bool __state)
private static void RpgStyleCompatPrefix(ref object _____instance)
{
// Yes, it should have 5 `_` symbols. The field has 2 in name, and we need to add 3 to access it through harmony argument
// The __instance field used by the mod
// The __instance field used by the mod
if (MP.IsInMultiplayer)
_____instance ??= Activator.CreateInstance(rpgStyleInventoryTabType);
}
Expand All @@ -96,4 +152,4 @@ private static void SyncComp(SyncWorker sync, ref ThingComp thing)
thing = getCompUnlockerCheckerMethod(sync.Read<Thing>(), false, false);
}
}
}
}