• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Question - Code Pass GML script to C++ extension?

hippyman

Member
I'm working on an OpenGL extension and there are a good amount of functions that take a callback function. Instead of having every callback function hard coded in the extension, I'd like to pass a GML script to the extension so the end user can have more control over what happens in each event.

I get the feeling this just isn't possible. If that's the case, are there any suggestions somebody might have to achieve the same effect? I know I can implement LUA into the extension but that would be pretty complicated and the whole reason for making this an extension instead of a separate engine is because I want to use GML.

Any thoughts/help would be greatly appreciated!


Also.. sorry if this is better fit to a different subforum. Feel free to move it wherever necessary.
 

rwkay

GameMaker Staff
GameMaker Dev.
you can get the asset index of the script (which is just a number) and pass that into the extension then use the GML function execute_script() to actually call it (if it is a GML extension then that is easy) if this is a C++ extension then it will have to use a GML helper to do the execute_script() i.e. on an onTick or step for the extension (you can have mixed C++ and GML functions in an extension)

Russell
 

hippyman

Member
you can get the asset index of the script (which is just a number) and pass that into the extension then use the GML function execute_script() to actually call it (if it is a GML extension then that is easy) if this is a C++ extension then it will have to use a GML helper to do the execute_script() i.e. on an onTick or step for the extension (you can have mixed C++ and GML functions in an extension)

Russell
Can you possibly elaborate a little more on what you mean by a GML helper?
I'm having issues visualizing this in my head.

Code:
//callback function
void callback_error(int error, const char* description) {
    fprintf(stderr, "ERROR: %s\n", description);
}

glfwSetErrorCallback(callback_error);
You just place the callback_error function into the SetErrorCallback function and callback_error is called automatically on the C++ side. So how would I know when to call the GML script?
 

GMWolf

aka fel666
The way I did it with before was to use the social event.
The DLL would call the GM social event, passing the script index to call.
Unfortunately, there is no way to get C++ to call GML scripts and get a return value. That is because the social event is async on the c++ end, and syncronous on the GML end. (GM will simply put the event on a stack and flush the stack once a frame.)
Fun fact, every async event works that way in GML. its a pain when dealing with DLLs and audio queues.

[edit] im using the words syncronous nad async in a very loose way. But to be fair so does GameMaker :p
 
Last edited:

hippyman

Member
The way I did it with before was to use the social event.
The DLL would call the GM social event, passing the script index to call.
Unfortunately, there is no way to get C++ to call GML scripts and get a return value. That is because the social event is async on the c++ end, and syncronous on the GML end. (GM will simply put the event on a stack and flush the stack once a frame.)
Fun fact, every async event works that way in GML. its a pain when dealing with DLLs and audio queues.
I considered the async event. I guess I was just hoping for a more direct way to do this. It'll probably be a little hacky, but I think I can make this work.


Thanks for the help guys!
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Still thinking about this, surely there must be a way...
@YellowAfterlife I'm sure you encountered this when writing Apollo. any hints?
You pass the data using a buffer and have the extension calls return a status code. If the DLL said that it's not done yet, you check what it asked for via the buffer, get that (call script/get variable/etc.), and call the DLL function again (which has it's own small state machine/coroutine for this).

If someone was willing to sponsor the effort, I could totally write a good, in-depth blog post covering all the different approaches used to make the process of making C++ extensions for GM not a self-torture, but this would take maybe 6-7 hours of work and thus is seemingly unlikely to occur.
 

GMWolf

aka fel666
You pass the data using a buffer and have the extension calls return a status code. If the DLL said that it's not done yet, you check what it asked for via the buffer, get that (call script/get variable/etc.), and call the DLL function again (which has it's own small state machine/coroutine for this).
Right so the dll has to wait for GM to execute a step...
 

GMWolf

aka fel666
It does not, flow goes GML->DLL->GML->DLL->...->GML in sync, you'd get nowhere with 1 frame latency on every call
ooh. I think I get it! That's quite smart!

So dll makes script request and returns.
GML then sees it asked for script, writes it to buffer and calls dll again, etc etc untill dll says it's done?
 

GMWolf

aka fel666
Thank you sir!

That's a great idea.
Hmm, it does mean I would have to move things into threads or something...
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Thank you sir!

That's a great idea.
Hmm, it does mean I would have to move things into threads or something...
You could, but ideally you shouldn't - I went from threading+mutex (for waiting for the game to finish) to threading+spinlock to coroutines with Apollo, and even between the later two the difference was around 5..7x on small operations
 

GMWolf

aka fel666
You could, but ideally you shouldn't - I went from threading+mutex (for waiting for the game to finish) to threading+spinlock to coroutines with Apollo, and even between the later two the difference was around 5..7x on small operations
Well, my concern is with calling GML scripts from a third party library I have no control over.
My first though was to move those calls to a thread, waiting for the GML to give the value back.
 

hippyman

Member
You pass the data using a buffer and have the extension calls return a status code. If the DLL said that it's not done yet, you check what it asked for via the buffer, get that (call script/get variable/etc.), and call the DLL function again (which has it's own small state machine/coroutine for this).

If someone was willing to sponsor the effort, I could totally write a good, in-depth blog post covering all the different approaches used to make the process of making C++ extensions for GM not a self-torture, but this would take maybe 6-7 hours of work and thus is seemingly unlikely to occur.
Are there benefits of doing this over using the async event?

And if I'm understanding correctly, does this basically mean you have a single DLL function and a buffer? Set a flag in the buffer and the DLL checks the flag and determines what function to run and put the return data back in the buffer for GM to process?

I didn't intend for this to be such a loaded question.
 
Top