Skip to content

feat: Adds new decay system and SkipSerialization#2311

Merged
kamronbatman merged 11 commits intomainfrom
kbatman/skip_serialization
Jan 8, 2026
Merged

feat: Adds new decay system and SkipSerialization#2311
kamronbatman merged 11 commits intomainfrom
kbatman/skip_serialization

Conversation

@kamronbatman
Copy link
Contributor

@kamronbatman kamronbatman commented Jan 8, 2026

Summary

  • Replaces scan-based decay checking during world saves with an event-driven timer wheel scheduler
  • Removes virtual property checks from serialization hot path, achieving 6-8x faster world saves

Changes

DecayScheduler (new):

  • Timer wheel with 12 HashSet buckets (5-min intervals) + PriorityQueue for active processing
  • O(1) register/unregister vs O(n) scan of all items
  • Auto start/stop when items exist/empty
  • Configurable tick interval with jitter to prevent system synchronization

Item.cs:

  • Added ScheduledDecayTime computed property
  • Added UpdateDecayRegistration() called from SetLastMoved(), property setters, AddItem()/RemoveItem()
  • Hooks in Visible, Movable, Spawner setters and Delete()

World.cs:

  • Removed _decayQueue, EnqueueForDecay(), ProcessDecay()
  • ItemPersistence.Serialize() now tight loop without virtual calls

Performance

Metric Before After Improvement
Items (230K) 245K ticks 34K ticks 8x faster
Mobiles (43K) 56K ticks 6K ticks 9x faster
Total 302K ticks 40K ticks 7.5x faster

Configuration

decay.maxItemsPerTick = 250 # Items processed per tick
decay.tickInterval = 256ms # Base processing interval
decay.bucketInterval = 5min # Timer wheel bucket size
decay.jitterMaxMs = 25 # ±25ms tick jitter

Copilot AI review requested due to automatic review settings January 8, 2026 06:24
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request introduces a SkipSerialization property to the ISerializable interface to provide a cleaner mechanism for marking entities that should not be persisted. This replaces the previous pattern of using [AfterDeserialization(false)] methods that unconditionally call Delete().

  • Adds SkipSerialization property to ISerializable interface
  • Updates serialization logic to skip entities where SkipSerialization => true
  • Converts 16 classes from the old deletion-on-deserialization pattern to the new skip-serialization approach

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Projects/Server/Serialization/ISerializable.cs Adds SkipSerialization property to interface
Projects/Server/Serialization/GenericEntityPersistence.cs Updates serialization logic to skip entities and maintain accurate counts
Projects/Server/Items/Item.cs Adds default implementation returning false
Projects/Server/Mobiles/Mobile.cs Adds default implementation returning false
Projects/Server/Guild.cs Adds implementation returning false
Projects/Server/IEntity.cs Adds implementation returning true and removes deserialization deletion logic
Projects/Server/Items/VirtualCheck.cs Adds SkipSerialization, refactors properties to use serialization generator
Projects/UOContent/Spells/Spellweaving/Mobiles/NatureFury.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Spells/Seventh/GateTravel.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Multis/Houses/PreviewHouse.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Multis/Houses/BaseHouse.cs Replaces AfterDeserialization with SkipSerialization for TransferItem
Projects/UOContent/Mobiles/Monsters/Mammal/Melee/VorpalBunny.cs Replaces AfterDeserialization with SkipSerialization for BunnyHole
Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Mobiles/Monsters/AOS/Revenant.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Mobiles/AI/BaseAI/TransferItem.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Items/Weapons/Fists.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Items/Misc/MoonstoneGate.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Items/Misc/EffectItem.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Items/Misc/Acid.cs Replaces AfterDeserialization with SkipSerialization
Projects/UOContent/Items/Maps/TreasureMap.cs Replaces AfterDeserialization with SkipSerialization for TreasureChestDirt
Projects/UOContent/Engines/Spawners/Commands/ShowSpawnerBordersCommand.cs Replaces AfterDeserialization with SkipSerialization for SpawnerBorder
Projects/UOContent/Engines/Quests/Core/Items/HornOfRetreat.cs Replaces AfterDeserialization with SkipSerialization for HornOfRetreatMoongate
Projects/UOContent/Engines/Plants/MiscItems/GreenThorns.cs Replaces AfterDeserialization with SkipSerialization for GreenThornsSHTeleporter
Projects/UOContent/Engines/Ethics/Core/EthicsEntity.cs Adds SkipSerialization returning false
Projects/UOContent/Engines/ConPVP/Games/BombingRun.cs Adds SkipSerialization, makes FindOwner static, removes deserialization logic
Projects/UOContent/Accounting/Account.cs Adds SkipSerialization returning false
Projects/Server.Tests/Tests/Network/Packets/Outgoing/AccountPacketTests.cs Updates mock to implement SkipSerialization
Projects/Server.Tests/Tests/Maps/ClientEnumeratorTests.cs Updates mock to implement SkipSerialization
Comments suppressed due to low confidence (1)

Projects/UOContent/Engines/ConPVP/Games/BombingRun.cs:73

  • Since this class now has SkipSerialization => true, the Serialize and Deserialize methods should also be removed as they will never be called. These methods are redundant and will cause confusion.
        public override void Deserialize(IGenericReader reader)
        {
            base.Deserialize(reader);

            var version = reader.ReadInt();
        }

        public override void Serialize(IGenericWriter writer)
        {
            base.Serialize(writer);

            writer.Write(0); // version
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@modernuo modernuo deleted a comment from Copilot AI Jan 8, 2026
@kamronbatman kamronbatman changed the title feat: Adds SkipSerialization to ISerializable feat: Adds new decay system and SkipSerialization Jan 8, 2026
@kamronbatman kamronbatman merged commit ee2cd1d into main Jan 8, 2026
8 of 9 checks passed
@kamronbatman kamronbatman deleted the kbatman/skip_serialization branch January 8, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant