Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[Help] state object not updating properly

1489628634

Edited 1489690478
PaprikaCC
Pro
API Scripter
The problem has been fixed with TheAaron and Scott's help. Heyo everyone. I'm most of the way through creating a script to duplicate all objects on a map to a second map, but I've been running into a weird problem that I have no idea how to resolve. Script in question here . I have an attribute in state at 'state.PageCopy.active', that the script uses to prevent users from potentially interrupting active processes. After the script is done creating new graphics, it should call the clearState() function, which resets state.PageCopy to a default state, so users can copy another page. My problem is that clearState() fires but doesn't actually update the state object. What happens instead is that all of the chat messages will fire, as well as all log() calls (even within the clearState function), but state.PageCopy.active stays true and the script continues to think that it's running. I've tried using _.defer and _.delay to let clearState() fire after everything is done, but I get a console error that says: TypeError: Cannot read property 'apply' of undefined TypeError: Cannot read property 'apply' of undefined at null._onTimeout (/home/node/d20-api-server/node_modules/underscore/underscore.js:768:18) at Timer.listOnTimeout (timers.js:92:15) preparePageCopy() is the main function that handles everything. If you want to see the script work, use !pagecopy or '!pagecopy source' on a page to designate it as the source, then !pagecopy again on a different page. A chat prompt will open before the script works. Everything works fine (minus some z-ordering) right until the very end where state.PageCopy is supposed to reset and state.PageCopy.active is set to false. I've also run into a weird issue where pages that have been edited by this script do not delete properly. If you copy page A to page B, page B will reappear after being deleted with nothing inside. You have to delete it twice for it to totally disappear.
1489632500

Edited 1489632562
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Took me a bit to get used to your code since you aren't using 'use strict' and can therefore technically leave off the ending commas/semicolons between variables and at the end of lines respectively. I think you defined defaultState as a constant to prevent it being overwritten when you update the state.PageCopy with other things, but I might suggest changing it to a var declaration and using _.clone() when you set state.PageCopy. You could also probably get rid of defaultState altogether and simply call clearState() whenever you have set state.PageCopy to defaultState elsewhere, and simply have state.PageCopy defined like this in clearState(): clearState = function(){ state.PageCopy = { active: false, secureStr: false, destinationPage: false, sourcePage: false, workQueue: [] }; }, I don't know constants that well, but I think you might be running into a problem where having a variable equal another variable just copies that variable (thinking it might work this way with constants as well), and so since constants can't be redefined, it just stays the same. All that said, I'm not sure you need to use the state for this. You aren't going to have a process spanning session starts, or at least I would hope not, so you can probably just use regular variable definitions for this. Hope that made sense, and hopefully it's also correct, Scott
1489634360

Edited 1489634441
The Aaron
Pro
API Scripter
Actually, it's not the const. const only applies to the variable, not the value. So: const bob={age:44}; bob can never be assigned another value, but bob.age=13; is perfectly fine because the value (object) can be manipulated freely.  The issue is that assignment is by reference, not by value. state.PageCopy and defaultState are not just identical, they are precisely the same object. When state.PageState.active is changed to true, defaultState.active is also true because state.PageState and defaultState are just aliases for the same object. Using _.clone() should clear that up.  Also, looks like you weren't passing a function to _.delay()/_.defer()
1489636668
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Ah, I had part of it then, thanks for clearing that up Aaron. You might have another view on this, but I think getting rid of default state altogether would be even better, and just define the Page copy object from scratch in clearState.
1489638577

Edited 1489643993
PaprikaCC
Pro
API Scripter
I'm just using the  Javascript Standard Style . I removed all references to defaultState and just replaced it with clearState... Just read TheAaron's response. I'll test that out. Also, I'm only using _.delay() to call the workQueue function in copyObjectsToDestination right now. I tried to call clearState with it as well (with a delay of 10ms), but I ran into the problem in my first post. EDIT: I updated the script and I'm still having the same problem. EDIT2: I found the problem. I'm reading the returned value from copyObjectsToDestination(), but it's undefined because only the last call will return anything. EDIT3: I don't know what's going on anymore. I managed to get clearState() to work? But not really? And the script is no longer copying over all graphic objects. This feels like madness. Edit4:  I don't know what's going on.
1489665386
The Aaron
Pro
API Scripter
You are passing the result of executing workQueue() to _.delay(), you need to just pass workQueue to it. _.delay(workQueue,20);
1489666801
The Aaron
Pro
API Scripter
In your current version from the link above (which varies from the screenshot) you are falling prey to procedural thinking in an asynchronous circumstance.  On line 282, copyObjectToDestination() will return pretty much immediately, returning undefined (except if there is nothing in workQueue, when it will return success immediately). With Asynchronous functions that you need to react to in some way, you have to prepare to do some action later.  The simplest way to do that is to pass a callback into the function chain.  For example, if line 282 looked like this: copyObjectsToDestination(clearState); and copyObjectsToDestination looked like this:   var copyObjectsToDestination = function ( callback ) {     var workQueue = () => {       if (state.PageCopy.workQueue.length) {         var part = state.PageCopy.workQueue.shift()         createObj(part.type, part.data)         _.defer(workQueue)       } else {         printToChat('gm', `Finished copying the ${getObj('page', state.PageCopy.sourcePage).get('name')} page.`)         callback();       }     }   } you can see that clearState would get called as soon as the queue is emptied. The more advanced way to handle that is with Promises, which are really just a standardized interface to callbacks on async functions and a bunch of syntactic sugar around dealing with many simultaneous Asynchronous calls and error handling. An even better and more advanced way of dealing with it is the new Async/Await keywords in Node7 (which we're getting soon in the API!)
1489668179
The Aaron
Pro
API Scripter
Opinion: About standards:   Anyone can write a standard, and pick the name for it.  Feross Aboukhadijeh named his "Standard JS".  I don't particularly care for his rules and it seems like  Airbnb's Javascript Style Guide is more popular in the wider Javascript Internet.  I don't actually like it either, but it's closer to my preferences.  And that's the nature of Style Standards .  Other languages have their own holy wars over style, but generally the language standard is rigid enough that it generally revolves around "tabs vs. spaces" and "does the open curly brace belong on the same line as the if".  Javascript suffers from the problem that it was written by someone who didn't fully consider the consequences of making optional the standard line ending from C/C++/Java ( ; ) which he was modeling his language on.  That gives it more room for argument over what is "right". To me, coming from a Computer Science background and heavily C++ influenced:   Lack of semicolons is an abomination. But it's a free internet, you can write it how you feel most comfortable. =D
1489684094
Lithl
Pro
Sheet Author
API Scripter
The Aaron said: To me, coming from a Computer Science background and heavily C++ influenced:   Lack of semicolons is an abomination. More importantly, relying on automatic semicolon insertion can cause unexpected errors for people not well-versed on the subject of when and where it happens. For example: function fn() { return { foo: 'bar', fizz: 'buzz', } } console.log(fn()) // output: undefined, not {foo:'bar',fizz:'buzz'} var i = 1 var j = 2 i ++ j console.log(i, j) // output: 1 3, not 2 2 var a = b + c (d + e).print() // depending on the value of c, this is either a parse error or a function call Mixing ASI and manual semicolons can cause some head-scratchers, too: var i = 1 i ++; // parse error Regex also causes issues: var a = 5 var g = { exec: (s) => parseInt(s) } var s = '16' var z = 10 var i = 5 /[a-z]/g.exec(s) // i === -0.0625, because /[a-z]/g is interpreted as two division operations instead of Regex There's also the logic of "the semicolons are being inserted by the computer, I'm smarter than the computer, I'll insert the semicolons myself". If you know the ASI rules extremely well, you can be safe relying on ASI. If you don't know the ASI rules well, you can get bugs and have no idea why they're occurring.
1489684676
PaprikaCC
Pro
API Scripter
This is immensely helpful for me. Thanks! And I'll probably stick to AirBnB's style from now on.
1489695891
The Aaron
Pro
API Scripter
Brian said: The Aaron said: To me, coming from a Computer Science background and heavily C++ influenced:   Lack of semicolons is an abomination. More importantly, relying on automatic semicolon insertion can cause unexpected errors for people not well-versed on the subject of when and where it happens.  I wholeheartedly agree. =D  Generally the style guides that suggest leaving out semicolons then have to prop it up further by saying "don't use ++ or -- because they are confusing!".  Of course, even Douglas Crockford is against them. =D (be we won't hold that against HIM!). PaprikaCC said: This is immensely helpful for me. Thanks! And I'll probably stick to AirBnB's style from now on. Great!  I do think AirBnB is a better style guide to follow (Thanks Kryx!), even though I don't completely agree with it.  If you're just starting out in your Javascript, I think it will help you more than the "Standard JS" (and it's quite arrogant of them to name themselves that!  I should start one called "Proper JS"!). Also, since I haven't mentioned it in about a year.. I highly recommend Javascript: The Good Parts by Douglas Crockford . =D
1489697141

Edited 1489697203
Lithl
Pro
Sheet Author
API Scripter
The Aaron said: Great!  I do think AirBnB is a better style guide to follow (Thanks Kryx!), even though I don't completely agree with it.  If you're just starting out in your Javascript, I think it will help you more than the "Standard JS" (and it's quite arrogant of them to name themselves that!  I should start one called "Proper JS"!). At my day job, I'm required to follow the  Google JavaScript Style Guide . Since, y'know... I work there. =) Fortunately for me, there's  an eslint configuration I can use.