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

[Help] Any way to call API event?

1401829885

Edited 1401830567
I've got several scripts that listen for turn order change. One of them, however, causes the turn order TO change, which does not fire a turn order change event (which means the other scripts do not do their stuff.) Is there a way to call the event manually? Alternately, is there a way to advance the turn tracker that does call the change event?
1401830945

Edited 1401831102
Lithl
Pro
Sheet Author
API Scripter
The API does not trigger API events, to avoid infinite loops (exception: sendChat can cause infinite loops). If you want your code to trigger other event-handling code, break out your callbacks into named functions, and call the functions yourself. Example: on('change:campaign:turnorder', turnOrderChanged); on('chat:message', function(msg) { ... // event handling code // Time to change the turn order! Campaign().set('turnorder', turnOrder); turnOrderChanged(Campaign(), { // id and type won't be changing _id: Campaign().id, _type: 'campaign', // if your change:campaign:turnorder function cares about what the turnorder changed *from* you need this turnorder: oldTurnOrder, // the other properties of the campaign won't have changed for a turnorder change event initiativepage: Campaign().get('initiativepage'), playerpageid: Campaign().get('playerpageid'), playerspecificpages: Campaign().get('playerspecificpages') }); }); function turnOrderChanged(campaign, oldCampaignState) { // campaign.get('turnorder') is different from oldCampaignState.turnorder! DO SOMETHING!!! // Of course, because the campaign is a singleton, you could use `Campaign()` instead of `campaign`. // If you don't care about the previous value of the turnorder, you don't even need oldCampaignState, // and you could call turnOrderChanged without any parameters at all. } It's generally considered a good idea to namespace your stuff, so that you don't have name collisions with other scripts. For that, you'd do something like this: var jeremy_w = jeremy_w || {}; on('change:campaign:turnorder', jeremy_w.turnOrderChanged); on('chat:message', function(msg) { ... jeremy_w.turnOrderChanged(...); }); jeremy_w.turnOrderChanged = function(...) { ... };
I was afraid I'd have to do it that way... I suppose there's no better way at the moment. However, I would like to suggest to the dev team, an API feature that allows us to call events (intentionally.) If there is already a way to cause infinite loops due to bad programming, would it really hurt to add something else in that must be used responsibly? It would go a long way for improving script compatibility.
Isn't using call function the same thing as calling another script, seeing as the function can be an entire script in its self?
The thing about having a way to call the events is that you can create a script that provides out of the box compatibility with other scripts. This means that people who don't have Javascript & Roll20 API experience can simply use the scripts instead of having to do significant reworking to make them compatible.
1401969933

Edited 1401970200
DXWarlock
Sheet Author
API Scripter
Wouldn't calling the event be the same thing as calling a function anyway, since like on('chat:message', function(msg) { is just a premade API function called on a chat message? I think the issue with calling a separate 'script' is that technically all your scripts load into one sandbox, so its not like each is a separate class file. You could paste all your scripts into one long single script window, and it wouldn't change anything. And functions are compatible with other scripts without a lot of work..its just adding the one line to call the function, vs one line to trigger an event like you said. Unless Im misunderstanding what you mean.
1401969942
Alex L.
Pro
Sheet Author
Jeremy W. said: The thing about having a way to call the events is that you can create a script that provides out of the box compatibility with other scripts. This means that people who don't have Javascript & Roll20 API experience can simply use the scripts instead of having to do significant reworking to make them compatible. What sort of script needs to be able to call events for another script to be compatible? The correct way of doing this is to have a script expose a way to call the functions you need, not creating fake events.
My solution to this was to put all my event functions in a... dictionary? I don't know what {} is called in js. The only on(<event>, function) things I create figure out what actual function will be interested in the event and pass it on accordingly. So on('chat:message', looks to see if it is an api msg, then splits the text and uses the first word (!something) to pull an entry out of my chatEvents and call it. If I want to simulate a message, I can simply look up the handler in chatEvents, construct a fake message and call it. When I add someone else's script to my sandbox, if I want access to their event handlers, I simply register their event handlers with my event dicts, thereby exposing them the same way all my others already are.
Alex L. said: Jeremy W. said: The thing about having a way to call the events is that you can create a script that provides out of the box compatibility with other scripts. This means that people who don't have Javascript & Roll20 API experience can simply use the scripts instead of having to do significant reworking to make them compatible. What sort of script needs to be able to call events for another script to be compatible? The correct way of doing this is to have a script expose a way to call the functions you need, not creating fake events. The problem here is that you have to rely on other developers to write their scripts in such a way that you can easily call exactly what you need. So far, all the scripts I'm wanting to get working together do no expose their functions in such a nice and easy to use way. They are all written in such a way that the parts of them I need to actually use is in the middle of some other function. This leads me to having to modify, sometimes significantly, their scripts to get them to be compatible with mine. Basically, you can't rely on community developers to be extremely proficient in JavaScript to the point where they know all the tenets of good design. When you have non-experts developing scripts for the community, being able to call fake events can be a godsend. I am quite use to this exact situation in a community full of amateur developers - Bukkit - and it ends up working quite well, even if it is not the "right" way to do it.
No major modifications required. The only spots they register event handlers are via calls to the on() function, replace that in the global namespace with one that registers the callback in a {}, you can then look that up yourself, create a fake event object, and call their callback. Something like this in your first script: _oldon=on;callbacks={}; on=function(evnt, handler){callbacks[evnt]=handler;_oldon(evnt,handler);} You can then find the other scripts' handlers in callbacks.
1402553641
Alex L.
Pro
Sheet Author
Jeremy W. said: Alex L. said: Jeremy W. said: The thing about having a way to call the events is that you can create a script that provides out of the box compatibility with other scripts. This means that people who don't have Javascript & Roll20 API experience can simply use the scripts instead of having to do significant reworking to make them compatible. What sort of script needs to be able to call events for another script to be compatible? The correct way of doing this is to have a script expose a way to call the functions you need, not creating fake events. The problem here is that you have to rely on other developers to write their scripts in such a way that you can easily call exactly what you need. So far, all the scripts I'm wanting to get working together do no expose their functions in such a nice and easy to use way. They are all written in such a way that the parts of them I need to actually use is in the middle of some other function. This leads me to having to modify, sometimes significantly, their scripts to get them to be compatible with mine. Basically, you can't rely on community developers to be extremely proficient in JavaScript to the point where they know all the tenets of good design. When you have non-experts developing scripts for the community, being able to call fake events can be a godsend. I am quite use to this exact situation in a community full of amateur developers - Bukkit - and it ends up working quite well, even if it is not the "right" way to do it. If you don't want to rely on other developers then just rewrite there code for yourself correctly, this is an open source community there is nothing stopping you. Firing fake events is never the answer it breaks down the chain of trust you no longer can be sure if something happened or if another api script is just interfering unexpectedly. Always remember the sins of others do not forgive your own, the raptor does not care that someone else also used goto he will still rip your face off.
I don't think it's really wrong to fire off events manually. I mean, if you just moved a token via the API, then firing off an onMove event is appropriate, assuming you are emulating a player moving a token. It keeps management simple, since any future scripts added will also just work without having to mess with them.
Logan P. said: I don't think it's really wrong to fire off events manually. I mean, if you just moved a token via the API, then firing off an onMove event is appropriate, assuming you are emulating a player moving a token. It keeps management simple, since any future scripts added will also just work without having to mess with them. Yay, someone gets it.
Jeremy W. said: Logan P. said: I don't think it's really wrong to fire off events manually. I mean, if you just moved a token via the API, then firing off an onMove event is appropriate, assuming you are emulating a player moving a token. It keeps management simple, since any future scripts added will also just work without having to mess with them. Yay, someone gets it. Heh, don't get me wrong, I think lots of people abuse event systems simply because they want to trigger a specific function in a different script (triggering onMove when you did not just move something), when they should instead simply trip the other function directly. Your case with the turn order is a prime example of when it is appropriate. The other thing I realised is that it better follows the don't-repeat-code rule. If you have several places which should trip onMove, and you add another callback for the onMove event into the middle of the list of callbacks, if you are manually tripping all the callbacks, you will need to go find every place where you move tokens and add another callback to the list. That kind of thing is exactly what the don't-repeat-code rule is trying to prevent. Anyway, I also realised I made a slight error in my description of the replacement on() function. You need it to set the callback in the dict to an array, so that additional registered callbacks can be added to the array, otherwise the second on('chat:message',handler) replaces the first, instead of being called after the first. If you like I can probably make a gist with a working example.