fix: drop the decay reset stamp when an item loses eligibility
A stamped item that was re-frozen, re-hidden, spawner-linked, or moved into a container programmatically kept its stamp - and the CompactInfo holding it - for as long as it stayed ineligible. UpdateDecayRegistration's ineligible branch now clears the stamp; every re-eligibility path re-anchors, so only the allocation was at stake. The guarded setter makes the hot-path cost a field read and two compares, with no allocation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8067a7d0aa
commit
046452d7c7
2 changed files with 69 additions and 0 deletions
|
|
@ -374,6 +374,69 @@ public class DecayRegistrationTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Losing decay eligibility makes the stamp meaningless; it must be dropped so the
|
||||||
|
// CompactInfo is not held for as long as the item stays ineligible.
|
||||||
|
[Fact]
|
||||||
|
public void ItemBecomingIneligible_DropsTheDecayResetStamp()
|
||||||
|
{
|
||||||
|
var start = Core._now;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var item = new Item(0x1234);
|
||||||
|
item.MoveToWorld(new Point3D(115, 100, 0), Map.Felucca);
|
||||||
|
|
||||||
|
item.Movable = false;
|
||||||
|
Core._now = start + TimeSpan.FromDays(30);
|
||||||
|
item.Movable = true;
|
||||||
|
|
||||||
|
Assert.NotEqual(default, item.DecayResetTime);
|
||||||
|
|
||||||
|
item.Movable = false;
|
||||||
|
|
||||||
|
Assert.Equal(default, item.DecayResetTime);
|
||||||
|
|
||||||
|
item.Delete();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Core._now = start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moving a stamped item into a container programmatically (no drop, no SetLastMoved)
|
||||||
|
// must also drop the stamp.
|
||||||
|
[Fact]
|
||||||
|
public void StampedItemAddedToContainer_DropsTheDecayResetStamp()
|
||||||
|
{
|
||||||
|
var start = Core._now;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pack = new Container(0xE75);
|
||||||
|
pack.MoveToWorld(new Point3D(116, 100, 0), Map.Felucca);
|
||||||
|
|
||||||
|
var item = new Item(0x1234);
|
||||||
|
item.MoveToWorld(new Point3D(117, 100, 0), Map.Felucca);
|
||||||
|
|
||||||
|
item.Movable = false;
|
||||||
|
Core._now = start + TimeSpan.FromDays(30);
|
||||||
|
item.Movable = true;
|
||||||
|
|
||||||
|
Assert.NotEqual(default, item.DecayResetTime);
|
||||||
|
|
||||||
|
pack.AddItem(item);
|
||||||
|
|
||||||
|
Assert.Equal(default, item.DecayResetTime);
|
||||||
|
|
||||||
|
pack.Delete();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Core._now = start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A raw Map assignment (e.g. a GM changing Map through props) is a move: it must enroll
|
// A raw Map assignment (e.g. a GM changing Map through props) is a move: it must enroll
|
||||||
// an untracked item for decay instead of leaving it to linger forever.
|
// an untracked item for decay instead of leaving it to linger forever.
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -2429,6 +2429,12 @@ public partial class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropert
|
||||||
{
|
{
|
||||||
DecayScheduler.Register(this);
|
DecayScheduler.Register(this);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No countdown to anchor while ineligible; drop the stamp so the CompactInfo
|
||||||
|
// can collapse. Re-eligibility always re-anchors.
|
||||||
|
DecayResetTime = default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetLastMoved()
|
public void SetLastMoved()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue