So how does SourceMod handle different scripting languages anyway? Doesn’t that seem rather crazy? Here’s a look into how exactly this was achieved.
In the world of scripting, plugins provide one, and only one functionality – callbacks. They have entrypoints which hook or modify functionality in a parent application. These entry points are known as “events”, “callbacks”, or “public functions”. Much like an external C function, they can be looked up, by name, by the parent virtual machine/bytecode interpreter.
Therefore, MetaEng’s task is fairly simple, right? All it has to do is create a layer for finding a named function in an object and call that function with basic data types. For example,
IScript *script = Plugin->GetPluginScript(); //get MetaEng Context IForward *f = g_ForwardMngr.SingleForward(script, "plugin_init", 0); f->Execute();
And this is exactly how MetaEng works. There are three important pieces to the MetaEng model:
- Forwards – Execution interface for scripts.
- Scripts – Interface for very basic and generic scripting functions.
- MetaEngines – Implements a specific Script type (such as C++, AMX, or JavaScript).
Unfortunately, that’s just the interface side of things. It gets much more complicated when other topics are introduced – such as, how do we implement a universal method of passing parameters? How is the Forward layer implemented? How are plugins written in C/C++? What happens if a Script is destroyed/unloaded and Forwards are not removed?
And, perhaps most important, how do Natives work? Natives are functions native to the host application that can be called from a script. How does the host application, SourceMod, reconcile the fact that there is one set of natives written in C++, but many scripting languages?
I’ll answer these questions in the upcoming additions.