samp-node Plugin Architecture and libnode Embedding

samp-node Plugin Architecture and libnode Embedding An architecture diagram generated by Archify. sampgdk · static bridge lib · Host: open.mp sampgdk static bridge lib open.mp Server · host and natives · Host: open.mp open.mp Server host and natives Load / Unload · plugin entry points · Plugin export entry Load / Unload plugin entry points OnPublicCall · callback dispatch · Plugin export entry OnPublicCall callback dispatch nodeimpl.cpp · init and Tick · Embedded runtime nodeimpl.cpp init and Tick resource.cpp · bootstrap load · Embedded runtime resource.cpp bootstrap load libnode and V8 · Node 22 shared lib · Embedded runtime libnode and V8 Node 22 shared lib events.cpp · event registry · Events and marshalling events.cpp event registry natives.cpp · native args · Events and marshalling natives.cpp native args callbacks.cpp · public args · Events and marshalling callbacks.cpp public args entry_file module · gamemode entry · JS resource layer entry_file module gamemode entry @infernus/core · event engine · JS resource layer @infernus/core event engine global samp object · JS call surface · JS resource layer global samp object JS call surface loads plugin PLUGIN_EXPORT Initialize LoadResource CreateEnv dynamic import register / on OnPublicCall events[name]->call calls trigger callNative callPublic InvokeNativeArray Host: open.mp Plugin export entry Embedded runtime Events and marshalling JS resource layer Legend Frontend Backend Cloud

Plugin exports and startup order

  • • Load() reads samp-node.json, then Log::Init, sampgdk::Load, Initialize and LoadResource
  • • Supports() declares AMX-native and PROCESS_TICK support
  • • OnPublicCall checks js_calling_public to prevent recursion; AmxLoad registers SAMPNode_CallEvent

libnode embedding and bootstrap

  • • InitializeOncePerProcess, then MultiIsolatePlatform::Create(4), NewIsolate and a uv_loop
  • • functions::init injects global samp, then CreateEnvironment loads the bootstrap
  • • bootstrap sets ipv4first, imports entry_file, then __internal_esmLoaded releases the wait

Single-thread loop and sync bridge

  • • No separate Node thread: ProcessTick per frame runs microtasks, uv_run(NOWAIT), DrainTasks
  • • An async listener's Promise is settled by spinning the event loop, then read
  • • callNative uses FindNative with format-string marshalling; callPublic walks every AMX instance