ID:1830173
 
BYOND Version:507.1281
Operating System:Windows 10 Pro Technical Preview - Build 10049
Web Browser:
Applies to:Dream Seeker
Status: Deferred

This issue may be low priority or very difficult to fix, and has been put on the back burner for the time being.
Descriptive Problem Summary:Use sleep() inside Stat() to prevent calls from it until you want to call it.

Numbered Steps to Reproduce Problem:1.Make a new project.
2.Replace the code with the snippet below.

Code Snippet (if applicable) to Reproduce Problem:
mob
var
Gold=0
tmp
NeedsUpdated=1
verb
Update_Gold()
Gold+=1
NeedsUpdated=1
Stat()
while(!NeedsUpdated)
sleep(1)
statpanel("Test")
stat("Gold",Gold)
src<<"Updating statpanel to show the new gold amount of [Gold] gold."
NeedsUpdated=0


Expected Results:It's telling me it's updating the statpanel every time I click the Update_Gold() verb so when I click back over to the Test panel from clicking it under commands, it should be updated to reflect as much.

Actual Results:When I click back over to the Test panel from clicking it under commands, it's not updated.

Does the problem occur:
Every time? Or how often?Every Time
In other games?Yes
In other user accounts?Yes
On other computers?Yes

When does the problem NOT occur?Don't override Stat() like this.

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.)

Workarounds:Stop over-riding Stat() in this way.

EXTRA NOTES: If you make a macro for the verb and stay clicked into the Test panel, it will update properly, but it will never update if you are in another panel at the time.

It may never send the update to the client because the server likely knows what tab your in, now this is fine even, but under circumstances such as in the above code sleeping, it should send the last update gotten to the client when they switch back to the tab in question, if there's a pending update.

I am over-riding it to prevent a lengthy amount of code running using Stat() when it's not even updating anything, and it's all the same information.

I don't know if it already suppresses updates to the client or not when the Stat() code ends up generating all the same info for the statpanels and such or not, but if it does re-send even if it's identical to the last one sent to the client, this would save a small bit(although negligible amount) to networking as well.

Superbike32 wrote:
Descriptive Problem Summary:Use sleep() inside Stat() to prevent calls from it until you want to call it.

That doesn't sound like the problem summary. It sounds like what you're expecting will happen.

Stat() is never, ever intended to sleep--or be called directly, which is what sleep() ultimately ends up doing when it finishes. It's not something you can just put on the back burner, because new calls to it will come in. You'll just wind up with a lot of sleeping procs that will eventually try to complete. I'm calling this a non-bug.

If you want to avoid pointless updates like ones that use long calculations, just cache that info and only recalculate when your var says so.
Lummox JR resolved issue (Not a bug)
Actually Lummox you wont get a lot of sleeping calls at all.

New calls don't go to Stat() until it returns. Returns in this case is simply when it hits the end of the defined Stat() in my code.

I can confirm this by adding one verb that sets the value to 1, and the other sets it to 0.

I get messages at regular intervals, and if it had a bunch of sleeping Stat() procs you would expect a lot of spam output at once had you slept for a long time on multiple calls to Stat() which I never get when I hit the verb to make it not sleep anymore, it just continues the messages at normal intervals.

EDIT: The reference backs me up on this. http://www.byond.com/docs/ref/index.html#/client/proc/Stat

It reads:
If this procedure sleeps (or engages in some other waiting operation), it will not be called again until it finally returns. This allows you to effectively decrease the frequency of calls to the proc. You might want to do that if it is a fairly lengthy procedure, and frequent calls are slowing things down.

***So according to the reference since it's a lengthy process, it's essentially telling me to do what I just tried to do, I just made it sleep basically forever though until I want it to update again, where-as it's only insinuating that I use sleep to slow down calls to Stat()

Close enough though, this shouldn't be marked as "not a bug" in my opinion unless this is modified or the reference modified as to not insinuate that sleeping the Stat() proc is a viable option.
Lummox JR changed status to 'Open'
Hrm, you're right. All the time I've worked with Stat() I didn't realize sleeping was actually supposed to be supported per the reference. I'll look into it.
I know this is a pretty old bug report but the bug reported here is still reproducible so I figure it's fair game.

I believe I know what's going on here. client/Stat() gets called at least every 7ish ticks, depending on tick_lag settings, no matter what.

Behind the scenes, client.statpanel (among other things) is being set at the beginning of a client/Stat() call. This is set to whatever statpanel the client is currently looking at. Then the 7ish tick internal sleep begins. After this sleep, statobj.Stat() is called and set as the return value. Before client/Stat() actually returns though, a render update is applied to whatever panel is specified in client.statpanel.

So in this example code, when the Update_Gold() verb is clicked, it is clicked sometime within an already occurring client/Stat() call's sleep. At this point client.statpanel = "verbs" because the client is currently looking at a verb panel.

The client/Stat()'s sleep ends, and statobj.Stat() is called, which defaults to the client's mob. So mob/Stat() is called. This is where we get the message saying that the statpanel is being updated with the new gold amount and the NeedsUpdating flag is being reset to 0.

The problem is, all this was performed without any change to the client.statpanel var. So when mob/Stat() returns client.statpanel = "verbs", not "Test", and "verbs" gets a render update.

On the next call to client/Stat(), if we're looking at the "Test" panel now, client.statpanel = "Test". Then like before, the sleep happens and afterwards mob/Stat() gets called. But on the previous iteration we already flipped the flag putting mob/Stat() into an endless loop, it never returns so the render call is never made.

When we go back over to the verbs panel to try to force it to update by using the Update_Gold() verb, we're back to client.statpanel = "verbs". There's no way in this scenario for the "Test" statpanel to receive it's render update.

There's a work around to this whole thing. Right after NeedsUpdated = 0 in mob/Stat(), we can add client.statpanel = "Test" and the render will happen as originally intended.

To prevent this bug from being able to occur in the first place, Lummox could move the internal set of statpanel from the beginning of the client/Stat() call to the end, right before the render call.
Stat() is never, ever intended to sleep--or be called directly

This is wrong on both counts. Dan explicitly intended for the developer to be able to delay Stat() updates by sleeping the proc, as well as to be able to force updates from the server by calling Stat() directly.
In response to Ter13
Yeah, I was way off on that at the time.
This is going into suggestion territory but if you find the time to work on this bug it would be nice to also have full access to the three output columns of the statpanel. Right now it's super limited access to where you can really only utilize all three by feeding an atom into it, and then you only get the atom's icon and name.

Might as well go for broke and ask for full HTML support within the stat() procs as well while I'm already pushing things.
Info controls allow for limited HTML if you enable it, but because they're related to grids they aren't capable of advanced formatting like mixed styles (e.g, bold and not bold in the same cell).
Okay, I've taken a look into this, and the problem turns out to be a bit dicey, but there are workarounds.

Here's what's going on: Dream Daemon doesn't push stat updates to panels that aren't currently visible by DS, with the webclient being an exception. While Stat() is sleeping, no new Stat() calls are made. In the OP's example, NeedsUpdated is set while the statpanel is not visible, so the sleeping Stat() wakes up and finds that the player is currently looking at the verbs panel. Therefore no stats get changed. By the time the player switches back to the Test statpanel, NeedsUpdated has been cleared and it's sleeping again.

All in all I still see this as a bug because it'd be better if DS could detect the sleeping proc instance and discard it, and also it'd be ideal if it could prevent a proc call for a forced stat refresh from sleeping at all. But that's a lot to ask of the engine since it adds a lot of logic. For that reason I'm deferring this issue, but I present the following workarounds.

There are two ways to fix this issue on the code end. The first method suffices for simple statpanels:

    Stat()
while(!NeedsUpdated || !statpanel("Test"))
sleep(1)
stat("Gold",Gold)
src<<"Updating statpanel to show the new gold amount of [Gold] gold."
NeedsUpdated=0

Since statpanel("Test") will return false if DS isn't viewing that panel (the webclient returns true, but it doesn't have this problem), the logic that resets NeedsUpdated is never called.

A more complex statpanel would want to adopt logic like this:

    Stat()
while(!NeedsUpdated)
sleep(1)
if(statpanel("Test"))
stat("Gold",Gold)
src<<"Updating statpanel to show the new gold amount of [Gold] gold."
NeedsUpdated=0

Under each panel you fill, you'd want to start off with an if(statpanel(NAME)) and fill its stats in the if block; at the end of the if block, reset your update flag.

Also, in 512.1428 I've made a minor change to mark stats as dirty if the panel has been changed by DS, which should result in quicker statpanel updates when you switch panels.
Lummox JR changed status to 'Deferred'