ID:2338788
 
Resolved
The internal value used to store the last src for animate() is cleared after a batch of procs is finished, and also during del() for objs, mobs, areas, and images. Previously this reference could cause a movable atom to stick around much longer than intended.
BYOND Version:512.1404
Operating System:Windows 10 Home 64-bit
Web Browser:Chrome 63.0.3239.132
Applies to:Dream Daemon
Status: Resolved (512.1412)

This issue has been resolved.
Descriptive Problem Summary:
When animating a mob, it messes with garbage collection. Instead of getting rid of the mob once there's nothing referencing it, it waits until another animated mob is scheduled to be dealt with before finally being collected; however, the second animated mob isn't collected until yet another animated mob is scheduled take it's place in limbo. The cycle then continues.


Numbered Steps to Reproduce Problem:
1a) Download this test environment or use the Code Snippet below.
1b) Click NewMob() if you'd like to see garbage collection working properly.
2) Click NewAnimatedMob() to see that "Del() Mob #X" doesn't get called.
3a) Click NewAnimatedMob() to see that the previous "Del() Mob #X" gets called in place of the current "Del() Mob #X".
3b) Monitor which mobs are currently in the world via Mobs Alive statpanel.

Code Snippet (if applicable) to Reproduce Problem:
/*
These are simple defaults for your project.
*/


world
fps = 25 // 25 frames per second
icon_size = 32 // 32x32 icon size by default

view = 6 // show up to 6 tiles outward from center (13x13 view)

maxx = 13
maxy = 13
maxz = 1


// Make objects move 8 pixels per tick when walking

atom
icon = 'icons.dmi'

movable
icon_state = "m"
step_size = 8

turf
icon_state = "t"

var/total_mobs = 0

mob
New(loc)
..(loc)
name = "Mob #[++total_mobs]"
world << "New() [src]"

Del()
world << "Del() [src]"
..()

Stat()
statpanel("Mobs Alive")
for(var/mob/m)
stat(m.name)

verb
NewMob()
var/mob/m = new(locate(rand(1, world.maxx), rand(1, world.maxy), 1))
sleep(10)
m.loc = null

NewAnimatedMob()
var/x = 8
var/matrix/m = matrix()
var/mob/M = new(locate(rand(1, world.maxx), rand(1, world.maxy), 1))
while(--x)
m.Turn(45)
animate(M, transform = m, time = 1)
sleep(1)
animate(transform = null)
M.loc = null


Expected Results:
Garbage collection to work properly on animated mobs.

Actual Results:
Garbage collection on animated mobs is delayed, and only called when another animated mob can take it's place in limbo.

Does the problem occur:
Every time? Or how often? Yes.
In other games? So far, yes.
In other user accounts? Yes.
On other computers? Yes.

When does the problem NOT occur?
Problem doesn't occur when I don't use animate().

Did the problem NOT occur in any earlier versions? If so, what was the last version that worked? (Visit http://www.byond.com/download/build to download old versions for testing.)
Not sure, I'll look into older versions post-bug report.

Workarounds:
Manually call del on mobs that use animate().
I finally had some downtime this morning to circle back to this. I did some more digging, and this issue happens with animated objs as well, not just animated mobs. I tried getting it to reproduce with turfs, but animated turfs are collected properly.

With that said, I've tracked this issue back to build 512.1386. I've also tried the most recent build, build 512.1406, and the issue is still present. The stable build, build 511.1385, displays the expected results which is fortunate news.

Here is a link to the updated test case. It mostly includes animated objs, animated turfs, and clear debug messages as you'll see below.

After clicking NewAnimatedMob 3 times and NewAnimatedObj 2 times, the following are the actual results:
// NewAnimatedMob first click
Mob #2 New() has been called.
Expecting Mob #2 Del() to be called.

// NewAnimatedMob second click
Mob #3 New() has been called.
Mob #2 Del() has been called.
Expecting Mob #3 Del() to be called.

// NewAnimatedMob third click
Mob #4 New() has been called.
Mob #3 Del() has been called.
Expecting Mob #4 Del() to be called.

// NewAnimatedObj first click
Obj #1 New() has been called.
Mob #4 Del() has been called.
Expecting Obj #1 Del() to be called.

// NewAnimatedObj second click
Obj #2 New() has been called.
Obj #1 Del() has been called.
Expecting Obj #2 Del() to be called.


Here are the expected results ( and actual results as of stable build 511.1385 ):
// NewAnimatedMob first click
Mob #2 New() has been called.
Expecting Mob #2 Del() to be called.
Mob #2 Del() has been called.

// NewAnimatedMob second click
Mob #3 New() has been called.
Expecting Mob #3 Del() to be called.
Mob #3 Del() has been called.

// NewAnimatedMob third click
Mob #4 New() has been called.
Expecting Mob #4 Del() to be called.
Mob #4 Del() has been called.

// NewAnimatedObj first click
Obj #1 New() has been called.
Expecting Obj #1 Del() to be called.
Obj #1 Del() has been called.

// NewAnimatedObj second click
Obj #2 New() has been called.
Expecting Obj #2 Del() to be called.
Obj #2 Del() has been called.
Encountered this as well. Spent quite a while troubleshooting before I noticed this issue here.
Lummox JR resolved issue with message:
The internal value used to store the last src for animate() is cleared after a batch of procs is finished, and also during del() for objs, mobs, areas, and images. Previously this reference could cause a movable atom to stick around much longer than intended.