AidanDaniel97

Developer plugins

Recommended Posts

Hey guys,

So I decided to make this list for finding plugins made by the developer community and the Overwolf team quickly and easily!

 

Developer Community plugins

 

Overwolf plugins    
  • Twitch chat plugin - allows you to access the Twitch chat of a specified channel - GitHub
  • Twitch polls plugin - allows you to make twitch polls on your channel - GitHub
  • Simple IO plugin - allows you to read files from disk - GitHub
 
 

Make your own plugins

 

 

 

If I have missed any plugins, made mistakes or you would like to suggest a change then please post on this telling me which one I missed, any mistakes or a suggestion you wish to make.
I will do my best to continue to update the thread but if any other mods feel the need to do so then please do :thanks:

Share this post


Link to post
Share on other sites

Just two notes, I think it's a better idea to link to the GitHub repositories instead of the forum posts (or possibly link both) and please write it as meh, not Meh.

Share this post


Link to post
Share on other sites

Awesome initiative. Thanks for doing this!

 

+ Cookies to everyone.

 

Edit - Oh yea, I'm pinning this as it's super important info and resources that everyone should know about. Hope to see this list grow  :laugh:

Thaaaaanks :)  Same I'm excited to see what else is developed! :)

Share this post


Link to post
Share on other sites

It is somewhat funny that plugin with "IO" in the name actually does only the "I"

Maybe someone in overwolf would extend it or change the name, when I clicked the link in dev page I was so exited and then I was very disapointed :)

Share this post


Link to post
Share on other sites

Hey Bob, glad to see you on here.

 

Are you talking about writing to a file? What exactly are you trying to do?

Yes I am, I'm not actually doing anything yet, I'm just looking how to do certain things while figuring out how the app development works here.

 

Ps, the dev forum is quite dead, the lack of exaples in dev page does not help and there are a lot spam bots in this forum

Share this post


Link to post
Share on other sites

The "O" part wasn't developed (actually, for no specific reason), but if it's a requested feature, we'll definitely look into adding it.

The documentation requires an overhaul, and alongside the developer platform is part of our plans for this year.

We're also planning to focus more on the developer community through events, new tools etc.

 

Finally, we keep battling with spam bots, to the best of our manpower :) Hopefully they'll give up soon

Share this post


Link to post
Share on other sites

I've actually handed in an extended IO plugin with my last app submission, that enabled me to save a canvas to a png file in the "My pictures" location.

I've not made the few changes to make it general purpose yet though, but if the actual practical need arises, feel free to poke me.

I'd put it up on github only once it's at least polished a little.

Share this post


Link to post
Share on other sites

Hi guys, you seem to be knowledgeable bunch, could you tell me how to achieve something like in polls plugin

 

chatPlugin.onChatStateChanged = function (e, error) {

}

I want to be able to call function from within a plugin to js when something will happen, the demo does not have such thing implemented and I dont quite know how to do this, I hacked my way around this by calling the function and returning only when there is a event but it is just plain awful :)

 

any tips?

Share this post


Link to post
Share on other sites

Like an event system?

I've hacked this in a new plugin in development based on the updated IO sample a couple of days ago.

It's been far from beautiful, but wasn't actually hard and got the job done.

 

It should pretty much come down to, using that PluginMethod stuff as is, and adjust some functions in the nsScriptableObject<Name>

 

There, we have the ::Invoke which puts the static ::Execute function in a seperate thread, calling the PluginMethods implementation and when done, does NPN_PluginThreadAsyncCall with the static ::ExecuteCallback below (which calls the trigger in PluginMethod).

So far so good.

Our functions of interest here are ExecuteMethod and ExecuteCallback.

If you compare this snippet:

void nsScriptableObjectWhatever::ExecuteMethod(PluginMethod* method) {
  if (shutting_down_) {
    return;
  }
 
  if (nullptr == method) {
    return;
  }
 
  while ((!shutting_down_) && nullptr != method) {
 method->Execute();
 
 if (!method->HasCallback()) {
delete method;
return;
 }
 
 NPN_PluginThreadAsyncCall(
npp_, 
nsScriptableObjectKeyCapture::ExecuteCallback, 
method);
  }
  if (nullptr != method)
 delete method;
}
 
//static
void nsScriptableObjectWhatever::ExecuteCallback(void* method) {
  if (nullptr == method) {
    return;
  }
 
  PluginMethod* plugin_method = reinterpret_cast<PluginMethod*>(method);
  plugin_method->TriggerCallback();
 
  // delete plugin_method;
}

with the original, it's easy to see what I've done there. Deleting stuff at different conditions and looping the execute. In the PluginMethods execute I got another loop waiting for a condition, and when that one returns -> callback -> reexecute.

 

Note that this reaaally is hacky in the bad shortcut kinda sense. Things like actually offering a stop functionality leading to the consideration of using a singleton for PluginMethod or providing an instance lookup like

PluginMethodKeyCapture* instance = instanceMap[id_in];
instance->callback_ = nullptr;

leading to a lazy cleanup, giving new variables to the thread (if needed) leading to Mutexes etc.etc. are all to be considered when one  wants to do it "properly" and not part of this snippet.

 

And neither completely done on my work in progress since I don't need it for that case, but as long as I'm the single user of it and know about the do's and don'ts you know ;)

With the first snippet you should reach an event system that simply runs through the life-time of the app and gets deleted properly when shut down.

That enough for your case?

 

Edith: P.S. Does not rely on the File sample in any way, it's probably less confusing to  do applying the principle to one of the other samples without the PluginMethod base class.

 

Maybe one of the devs wants to add a nicer template for this than that to the samples? I too consider publish / subsribe a rather nice pattern to have.

Share this post


Link to post
Share on other sites

Like an event system?

I've hacked this in a new plugin in development based on the updated IO sample a couple of days ago.

It's been far from beautiful, but wasn't actually hard and got the job done.

 

It should pretty much come down to, using that PluginMethod stuff as is, and adjust some functions in the nsScriptableObject<Name>

 

There, we have the ::Invoke which puts the static ::Execute function in a seperate thread, calling the PluginMethods implementation and when done, does NPN_PluginThreadAsyncCall with the static ::ExecuteCallback below (which calls the trigger in PluginMethod).

So far so good.

Our functions of interest here are ExecuteMethod and ExecuteCallback.

If you compare this snippet:

void nsScriptableObjectWhatever::ExecuteMethod(PluginMethod* method) {
  if (shutting_down_) {
    return;
  }
 
  if (nullptr == method) {
    return;
  }
 
  while ((!shutting_down_) && nullptr != method) {
 method->Execute();
 
 if (!method->HasCallback()) {
delete method;
return;
 }
 
 NPN_PluginThreadAsyncCall(
npp_, 
nsScriptableObjectKeyCapture::ExecuteCallback, 
method);
  }
  if (nullptr != method)
 delete method;
}
 
//static
void nsScriptableObjectWhatever::ExecuteCallback(void* method) {
  if (nullptr == method) {
    return;
  }
 
  PluginMethod* plugin_method = reinterpret_cast<PluginMethod*>(method);
  plugin_method->TriggerCallback();
 
  // delete plugin_method;
}

with the original, it's easy to see what I've done there. Deleting stuff at different conditions and looping the execute. In the PluginMethods execute I got another loop waiting for a condition, and when that one returns -> callback -> reexecute.

 

Note that this reaaally is hacky in the bad shortcut kinda sense. Things like actually offering a stop functionality leading to the consideration of using a singleton for PluginMethod or providing an instance lookup like

PluginMethodKeyCapture* instance = instanceMap[id_in];
instance->callback_ = nullptr;

leading to a lazy cleanup, giving new variables to the thread (if needed) leading to Mutexes etc.etc. are all to be considered when one  wants to do it "properly" and not part of this snippet.

 

And neither completely done on my work in progress since I don't need it for that case, but as long as I'm the single user of it and know about the do's and don'ts you know ;)

With the first snippet you should reach an event system that simply runs through the life-time of the app and gets deleted properly when shut down.

That enough for your case?

 

Edith: P.S. Does not rely on the File sample in any way, it's probably less confusing to  do applying the principle to one of the other samples without the PluginMethod base class.

 

Maybe one of the devs wants to add a nicer template for this than that to the samples? I too consider publish / subsribe a rather nice pattern to have.

So if I understand correctly after PostTask you call NPN_PluginThreadAsyncCall but I'm still under impression that the call you made from javascript is still blocking, I mean isn't it still waiting for the plugin().funcCall(onChange) to return (where onChange is a function)?

When it returns its done, onChange function will be called once and it will not be called every time somethings will trigger it from plugin?

 

I still fail to understand how to achieve the event part of this, isn't this exactly what overwolf example does:

plugin().callToTheFunction->plugin does stuff and returns->done

but how do you achieve the part when the javascript method is called every time something in plugin happens?

How to achieve this without calling the plugin().funcCall() over and over again.

Can I actually trigger a callback multiple times, whenever I want?

 

So right now I need to call check() in a loop to monitor for change:

 

function check() {

     plugin().funcCall(onChange);

}

 

function onChange() {

    /*returned from plugin*/

}

 

but I just want to call it once and the plugin will call onChange every time something in plugin will happen, isnt what they have in polls plugin?

Share this post


Link to post
Share on other sites

I haven't looked at the polls sample yet, but that js sure looks like it. However, since the plugin part ain't open source, I don't know how they implemented that (though sure as hell less hacky than I did, hehe).

 

It would be blocking if it'd be in the same thread, but the blockiness end with the Invoke function, where

return thread_->PostTask(
    std::bind(
    &nsScriptableObjectKeyCapture::ExecuteMethod, 
    this,
    plugin_method));

causes all of this stuff here happening in it's very own thread. That's the point control goes back to js.

 

Now. the static Execute method is the task of that thread, and calls the callback from time to time, as in everytime the PluginMethods execute returns (the method-execute line), it'll first check if there's still a callback and then do the NPN async callback with the static ExecuteCallback as parameter which calls the plugins TriggerCallback.

 

And then...calls method->execute(); again since we're still in that while loop above. Et repeat et repeat.

So yes, the syntax in js it looks like you know it, like plugin().somefunc(args,callbackfunc), but the callbackfunc won't be called once so that js would need to do that  again, no, it'll be called over and over, every time the PluginMethods Execute returns, which is where my actual condition check loop is that I want to trigger an event.

 

I suspect you assume the control would return to js with the triggering of the callback, since then it  would behave exactly as described. But it  does already with the return of Invoke, which happens quite immediately (see utils/thread, there's just adding to queue no waiting) not when the task is done, the whole rest runs independently while control is already back  in js in that own thread where the callback can be triggered as much and often as one wants per se.

 

To put it another way:

Even the unaltered version and those other samples using the thread helper are less:

plugin().callToTheFunction->plugin does stuff and returns->done

more:

plugin().callToTheFunction->plugin-addsStuffToDoToThreadQueue->returns; thread-does-stuff->callback->selfdestruct

The snippet simply changes that last part to thread-does-stuff->callback->repeat. Destruction only comes on shutdown or when the callback becomes a null pointer.

Share this post


Link to post
Share on other sites

I haven't looked at the polls sample yet, but that js sure looks like it. However, since the plugin part ain't open source, I don't know how they implemented that (though sure as hell less hacky than I did, hehe).

 

It would be blocking if it'd be in the same thread, but the blockiness end with the Invoke function, where

return thread_->PostTask(
    std::bind(
    &nsScriptableObjectKeyCapture::ExecuteMethod, 
    this,
    plugin_method));

causes all of this stuff here happening in it's very own thread. That's the point control goes back to js.

 

Now. the static Execute method is the task of that thread, and calls the callback from time to time, as in everytime the PluginMethods execute returns (the method-execute line), it'll first check if there's still a callback and then do the NPN async callback with the static ExecuteCallback as parameter which calls the plugins TriggerCallback.

 

And then...calls method->execute(); again since we're still in that while loop above. Et repeat et repeat.

So yes, the syntax in js it looks like you know it, like plugin().somefunc(args,callbackfunc), but the callbackfunc won't be called once so that js would need to do that  again, no, it'll be called over and over, every time the PluginMethods Execute returns, which is where my actual condition check loop is that I want to trigger an event.

 

I suspect you assume the control would return to js with the triggering of the callback, since then it  would behave exactly as described. But it  does already with the return of Invoke, which happens quite immediately (see utils/thread, there's just adding to queue no waiting) not when the task is done, the whole rest runs independently while control is already back  in js in that own thread where the callback can be triggered as much and often as one wants per se.

 

To put it another way:

Even the unaltered version and those other samples using the thread helper are less:

plugin().callToTheFunction->plugin does stuff and returns->done

more:

plugin().callToTheFunction->plugin-addsStuffToDoToThreadQueue->returns; thread-does-stuff->callback->selfdestruct

The snippet simply changes that last part to thread-does-stuff->callback->repeat. Destruction only comes on shutdown or when the callback becomes a null pointer.

Ok, thx for clarification - for some reason I ignored the part where method->Execute() is called in a loop :)

It looks like it is then exactly what I wanted, I will try it out.

Share this post


Link to post
Share on other sites

Overwolf RawInput Plugin - Monitors Raw Input

https://github.com/thorwe/overwolf-plugin-rawinput

 

Currently features only keystrokes (most of them anyways).

Mouse may be added on a per need basis, Gamepads rather unlikely as HTML5 provides that for common/current devices at least.

 

What's new about this NPAPI plugin wise, is that I implemented it as observer pattern.

Consider it beta.

Share this post


Link to post
Share on other sites

Overwolf RawInput Plugin - Monitors Raw Input

https://github.com/thorwe/overwolf-plugin-rawinput

 

Currently features only keystrokes (most of them anyways).

Mouse may be added on a per need basis, Gamepads rather unlikely as HTML5 provides that for common/current devices at least.

 

What's new about this NPAPI plugin wise, is that I implemented it as observer pattern.

Consider it beta.

 

Adding it to the list :) 

Share this post


Link to post
Share on other sites

I have a question.

 

Is there a way to get current working directory from the plugin, I mean the directory where plugin is located.

Right now cwd is shown as path to OverwolfBroswer.exe.

 

Maybe I missed some function from overwolf api?

Or someone already figured it out and would like to share?

 

[EDIT] Never mind I figured it out

 

EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#pragma warning(disable: 4047)
HINSTANCE hInstance = (HINSTANCE)&__ImageBase;
#pragma warning(default: 4047)

string GetCurrentPath()
{
    char r1[MAX_PATH]; 
    string ret = string(r1, GetModuleFileName(hInstance, r1, MAX_PATH));
    return ret.substr(0, ret.find_last_of( "\\/" ));
}
Edited by BobDev

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now