rwmt / Multiplayer

Zetrith's Multiplayer mod for RimWorld

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Timestamp fixer - potential issues and improvements

SokyranTheDragon opened this issue · comments

I've created this github issue to discuss the timestamp fixer. I've looked through it, how it works, and noticed a potential issue with default values, started wondering if we need to fix all the timestamps, and was thinking about potential changes to better handle compat patches with other mods.

First, an issue with some fields (including most of the ones currently handled by timestamp fixer) is that they have an uninitialized, "not set" value like -1, or -99999. However, currently the timestamp fixer doesn't consider this at all, which could end up messing with those fields, either "initializing" them or setting them to some other negative value which RimWorld may not handle properly - fixing this would require a slightly different implementation of the timestamp fixed (having the fixes be optional).

Second, do we need to fix all of the timestamps? Why not just reset some of them to their default, uninitialized values? Setting Pawn_MindState.canSleepTick to -99999 would just reset it, and the pawns should be able to safely handle it themselves. After all, this is what RimWorld does inside of Pawn.ExitMap(), where it calls Pawn_MindState.Reset. This is obviously not going to work for all fields, but for some there's not much benefit to actually keeping a proper value for.

Third, a minor thing with compat, and not fully needed (mostly a convenience feature). The timestamp fixer uses a dictionary, but doesn't allow to register implicit ones. This means that it'll require registering one timestamp fixer for each subtype. For example, this will be the case for MP Compat fixing Vanilla Expanded Framework abilities - the Ability type is abstract, and so each of its subtypes will have to be registered to properly handle it, each one with an identical getter.

Fourth - to avoid clutter in this message I'll post the list in a second one. It is a list of fields (that I could find) that store specific tick timestamp, and what will/may happen (some were tested, some based on analyzing code) when moving from a map with much higher current tick to a map with much lower one (unless we fix it). The issue will (usually) persist until the ticks catch up to their previous map. In some cases it's possible to manually fix those values. There were some fields that were countdowns, and those were excluded.

Fifth - the timestamp fixer doesn't seem to run when a drop pod or a royal shuttle land. However, it runs fine when they launch (changing the timestamps from map to world).

The list of all fields that store a tick timestamp with an additional comment from me is below. It's likely not all of those would need the fixer, and would likely need extra investigation to verify.

Pawn.lastSleepDisturbedTick - unless it was not set before, they won't get disturbed sleep. Can't be corrected without waiting.

Pawn_HealthTracker.lastReceivedNeuralSuperchargeTick - pawns won't automatically seek neural superchargers, and they won't have negative thoughts for not having it. Value set by neural supercharge hediff, so easy to correct and may not need interaction if the pawn had the pawn when arriving at a new map.

Pawn_MeleeVerbs.curMeleeVerbUpdateTick - reset inside of Notify_PawnDespawned, so likely should be safe to leave as-is.
Pawn_MeleeVerbs.lastTerrainBasedVerbUseTick - as opposed to melee verbs, it isn't reset. Will likely prevent pawns from using terrain based verbs (untested).

Pawn_MindState - current timestamp fixer fixes some of them, but there's more fields that aren't included in the current version. Are they not needed? Are they reset inside of Pawn.ExitMap?

Pawn_PathFollower.lastMovedTick, Pawn_PathFollower.foundPathWhichCollidesWithPawns, Pawn_PathFollower.foundPathWithDanger, Pawn_PathFollower.failedToFindCloseUnoccupiedCellTicks - unsure on what will happen, if anything.

Pawn_ApparelTracker.lastApparelWearoutTick - unless it wasn't set then it'll cause the clothing to not naturally deteriorate.

Pawn_SkillTracker.lastXpSinceMidnightResetTimestamp - it'll cause the pawn to not reset their earned XP at midnight, eventually causing all their skills to get slowed down experience gains.

Pawn_RoyaltyTracker.lastDecreeTicks - will prevent pawns to issue decrees (if they were able to issue them in the first place).
RoyalTitle.receivedTick - will cause pawns to ignore room requirements for titles acquired before changing maps.
FactionPermit.lastUsedTick - will change when a pawn can next use their free permit.

Pawn_IdeoTracker.joinTick - will stop pawns from wanting connection with Gauranlen trees, and likely similar checks in mods.

Pawn_TrainingTracker.countDecayFrom - will stop animal training from decaying.

Pawn_PsychicEntropyTracker.lastMeditationTick - will cause them to not lose psyfocus, at least until they meditate again (which would reset this value).

Pawn_RelationsTracker.romanceEnableTick - will disable the romance attempt interaction from social card (ITab_Pawn_Social) or right click float menu option due to being on cooldown. Can be reset by the "DEV: Reset try romance cooldown" gizmo.

Pawn_InteractionsTracker.lastInteractionTime - not fully sure on what will happen, but I'm assuming it'll prevent some/many social interactions for pawns due to having been interacted to too recently.

Pawn_PlayerSettings.joinTick - used in the same check as Pawn_IdeoTracker.joinTick, taking the biggest value of the 2. Is also used for sorting pawn list based join tick.

And to finish this off, pinging @Zetrith. Any thoughts on the 4 points I've brought up?

I assume the 1st point is going to be important. I'm not sure how you'd want to handle changes there.

The 4th point is something I plan to investigate deeper myself as well to check what is and isn't needed, so it'll just be as adding a few lines of code.

And for the points 2nd and 3rd points, I've just dropped them in here as something that was on my mind. Are those something that you believe we should touch upon, or just leave as-is? Overall, it won't have a significant difference if they are implemented or not.

Thanks a lot for making the issue. TimestampFixer is currently very much a prototype as you noticed.

  1. Default values will need per field handling so I think we'll just pass them when registering
  2. As fixing too often can't cause problems, I think it'll be better to just eagerly add fields after quickly skimming through code and according to some simple heuristic like "name ends in tick" without having to spend time thinking whether it's safe to reset them
  3. Handling subtyping would definitely be a convenient feature
  4. These are all good candidates for fixing I think
  5. One other issue that might come up is what to do when some field is not reachable from an IExposable object

Been thinking a bit more about this the past couple of days.

according to some simple heuristic like "name ends in tick"

One thing that will be important will be to double check if it's a timestamp, or a counter - there was at least 1I found while looking through the code.

One other issue that might come up is what to do when some field is not reachable from an IExposable object

I assume that in some situations we could do something along the lines of: Add((Pawn pawn) => ref SomeObject.Instance.GetForPawn(pawn).ticks). Obviously, that's not an ideal solution, and won't always be applicable (for example, I don't think we could do this with Dictionary<Pawn, int>).

Also, one final thought - FixPawn() -> FixThing()? Probably not really needed in vanilla RW, but could possibly be useful for mod compat.

Working on an unrelated mod I've noticed another field that would likely need a timestamp fix - FactionPermit.lastUsedTick. The list of permits is held by Pawn_RoyaltyTracker.factionPermits. Just writing it down to not forget about it in the future.

I was testing the timestamp fixer a bit today, and may have noticed another issue. The timestamp fixer seems to not work properly when using drop pods or the Royalty shuttle.

What seems to happen is that the timestamp fixer only runs once - when a pawn leaves the map, it changes the timestamps from previous map to world. However, when they arrive the timestamp fixer doesn't run at all.

I'll just add it to the list in the original message to keep track of.