We currently only support the Node.js engine, but if we also plan to embed either the Squirrel or Lua VM, we need to re-think how we bind built-ins to our VMs.
In the current implementation, we call the mod-level ModuleRegister method and pass down a wrapper that would contain the initialized scripting engine. The following snippet is an example of us rejecting all VMs except Node.js and then calling the respective Builtins::Register method, which fully anticipates the Node.js engine:
void Server::ModuleRegister(Framework::Scripting::Engines::SDKRegisterWrapper sdk) {
if (sdk.GetKind() != Framework::Scripting::ENGINE_NODE)
return;
const auto nodeSDK = sdk.GetNodeSDK();
MafiaMP::Scripting::Builtins::Register(nodeSDK->GetIsolate(), nodeSDK->GetModule());
}
A better portion of the built-ins is, however, engine-agnostic, as can be observed here:
That is thanks to the v8pp library that only requires a small footprint to register our class with the VM:
Despite that, we still have several methods that fully assume we rely only on Node.js and are thus incompatible with the other engines:
Events are the biggest offender:
static void EventPlayerDied(flecs::entity e) {
auto engine = reinterpret_cast<Framework::Scripting::Engines::Node::Engine*>(Framework::CoreModules::GetScriptingModule()->GetEngine());
auto playerObj = WrapHuman(engine, e);
engine->InvokeEvent("playerDied", playerObj);
}
static void EventPlayerConnected(flecs::entity e) {
auto engine = reinterpret_cast<Framework::Scripting::Engines::Node::Engine*>(Framework::CoreModules::GetScriptingModule()->GetEngine());
auto playerObj = WrapHuman(engine, e);
engine->InvokeEvent("playerConnected", playerObj);
}
static void EventPlayerDisconnected(flecs::entity e) {
auto engine = reinterpret_cast<Framework::Scripting::Engines::Node::Engine*>(Framework::CoreModules::GetScriptingModule()->GetEngine());
auto playerObj = WrapHuman(engine, e);
engine->InvokeEvent("playerDisconnected", playerObj);
}
Discussion
We need to find a way to allow other engines to reuse the existing binding layer without introducing too much friction and code duplication. Ideally, bindings should be written only once. Then, the engine-specific wrappers should do the rest of the job, avoiding the mistake of having multiple copies of the same API to maintain per engine.
Problem
We currently only support the Node.js engine, but if we also plan to embed either the Squirrel or Lua VM, we need to re-think how we bind built-ins to our VMs.
In the current implementation, we call the mod-level
ModuleRegister
method and pass down a wrapper that would contain the initialized scripting engine. The following snippet is an example of us rejecting all VMs except Node.js and then calling the respectiveBuiltins::Register
method, which fully anticipates the Node.js engine:A better portion of the built-ins is, however, engine-agnostic, as can be observed here:
That is thanks to the v8pp library that only requires a small footprint to register our class with the VM:
Despite that, we still have several methods that fully assume we rely only on Node.js and are thus incompatible with the other engines:
Events are the biggest offender:
Discussion
We need to find a way to allow other engines to reuse the existing binding layer without introducing too much friction and code duplication. Ideally, bindings should be written only once. Then, the engine-specific wrappers should do the rest of the job, avoiding the mistake of having multiple copies of the same API to maintain per engine.
Scope
Scripting layer and MafiaMP's bindings.