Scarab
A thin, game-agnostic 2D engine host built on the sunlight tile-map engine
Loading...
Searching...
No Matches
Scarab::Lua::LuaEngine Class Reference

Implements a C++ abstraction for using Lua engine;. More...

#include <luaengine.h>

Public Member Functions

 LuaEngine (SunLight ::Scripting ::ScriptProcessor *pScriptProcessor)
 Constructor. Initialize all class data;.
 
virtual ~LuaEngine (void)
 Destructor. Finalize all class data;.
 
bool RunFile (std ::string strFileName)
 Execute a lua script - this is the ONE entry point that loads the game's very first script (EngineHost::LoadLuaScript), before Lua's own overridden "dofile" global (LuaFileSystemApi::DoFile) even exists to be called. Originally used the C API's luaL_dofile(), which reads via a raw fopen() internally - a real gap found while building Phase 12's archive-distribution support: every other resource load in this engine (dofile, load_json, textures, sound, tilemaps) already routed through SunLight::FileSystem, but this one didn't, so the first script of an archive-distributed game could never even be reached. Reads the file itself via SunLight::FileSystem::FileSystemFactory instead (mirrors LuaFileSystemApi::DoFile's own approach exactly - luaL_loadbuffer + lua_pcall in place of luaL_loadfile's internal fopen), so this now works identically whether strFileName is a real loose-directory path or a virtual path inside a mounted archive.
 
void CallOnUpdate (uint32_t nDeltaMilli)
 Call the optional Lua on_update(dt) global once per frame, if defined. Absent global is a silent no-op so stages that don't define it keep working.
 
bool TryDispatchMoveSpritesToScreen (uint16_t nStateId)
 Dispatch a MOVE_SPRITES_TO_SCREEN_CMD state id to Lua, via the optional global on_move_sprites_to_screen(stateId). The state id itself is entirely Lua-owned (see src/wavestates.lua) - C++ just ferries the ScriptProcessor's queued integer back to Lua opaquely, so stage scripts' sp_move_sprites_to_screen(...) calls (and their sp_wait/sp_wait_queue_empty pacing) work the same regardless of which enemy type a given id belongs to.
 
bool TryDispatchLoadStage (uint16_t nStageId)
 Give Lua first refusal on a LOAD_STAGE_CMD state id, via the optional Lua global on_load_stage(stageId) (bootstrap.lua) - the same "Lua gets first refusal" shape as TryDispatchMoveSpritesToScreen. Since stage bootstrap is a single mechanism (not per-type like the enemy ports), there is no legacy C++ fallback here - Lua is expected to always claim a valid stage id.
 
int GetActiveEnemyCount (void)
 Ask Lua how many enemies it currently has active, via the optional global get_active_enemy_count(). EngineHost::CheckSpritesQueueEmpty's "is the screen clear, unblock sp_wait_queue_empty()" check is entirely driven by this - every enemy type is Lua/SpritePool-owned, so this count is the only source of truth for whether the screen is clear.
 
const std::string & GetApplicationDirectory (void) const
 Return the running executable's own directory (also exposed to Lua as APP_DIR by Init above) - used by EngineHost to locate the bootstrap entry script on disk before any Lua exists to do so itself.
 
void Init (Engine ::IRendererProvider *pRendererProvider, SunLight ::Sound ::SoundManager *pSoundManager, Engine ::SpritePool *pSpritePool)
 Give Lua access to the renderer provider/SoundManager/SpritePool and register the primitive API modules (camera, input, tilemap, sound, sprite) that depend on them. Called from EngineHost's constructor body (not it's member-init list) since it needs m_LuaEngine to already exist as a constructed object to call a method on it - the provider itself is just the constructor's own parameter, forwarded straight through (EngineHost keeps no ITileMap* member of it's own; it has no remaining C++-side use for one). Also resolves and exposes the running executable's own directory as the Lua global APP_DIR - deciding where resources actually live relative to that (BASE_PATH) is main.lua's own job, not C++'s; the one exception is the bootstrap entry script itself, which EngineHost must locate on disk before any Lua exists to make that decision (see GetApplicationDirectory below).
 
void AttachToTileMap (SunLight ::TileMap ::ITileMap &tileMap)
 Attach the collision listener to a renderer's collision manager. Called by the renderer provider's created-hook, once per renderer - the renderer no longer exists yet when Init() runs, since a script may create it (renderer_create) or leave it to the default.
 
void InstallVirtualClock (void)
 Headless (–headless) only - make Lua's own os.time()/ os.clock() follow the null renderer's virtual clock instead of real time (see LuaAppApi::InstallVirtualClock for the why and the set_timer-callback caveat). Must run after Init(), since the replacements read the draw surface Init() stashes.
 

Detailed Description

Implements a C++ abstraction for using Lua engine;.

Every other page in this reference documents functions your Lua script calls into the engine. This page is the reverse direction: global Lua functions the engine looks up and calls from C++, if you define them. Every one of these is optional — the engine checks whether the global exists and is a function before calling it, and silently no-ops if it isn't defined (except on_load_stage, see below).

Define these as plain global functions (not table members) — the engine looks them up by exact name via lua_getglobal.

The collision handlers are documented separately

collision_set_handler/collision_set_tile_handler follow the same "engine calls into a Lua global" shape as everything on this page, but since they're registered via an explicit function call rather than just defining a magic global name, they're documented alongside the rest of the collision API in collision.md.

Constructor & Destructor Documentation

◆ LuaEngine()

Scarab::Lua::LuaEngine::LuaEngine ( SunLight ::Scripting ::ScriptProcessor *  pScriptProcessor)

Constructor. Initialize all class data;.

Parameters
pScriptProcessorPointer to an initialized script processor;

◆ ~LuaEngine()

Scarab::Lua::LuaEngine::~LuaEngine ( void  )
virtual

Destructor. Finalize all class data;.

Member Function Documentation

◆ AttachToTileMap()

void Scarab::Lua::LuaEngine::AttachToTileMap ( SunLight ::TileMap ::ITileMap &  tileMap)

Attach the collision listener to a renderer's collision manager. Called by the renderer provider's created-hook, once per renderer - the renderer no longer exists yet when Init() runs, since a script may create it (renderer_create) or leave it to the default.

Parameters
tileMapThe just-created renderer's tile map;

◆ CallOnUpdate()

void Scarab::Lua::LuaEngine::CallOnUpdate ( uint32_t  nDeltaMilli)

Call the optional Lua on_update(dt) global once per frame, if defined. Absent global is a silent no-op so stages that don't define it keep working.

Parameters
nDeltaMilliMilliseconds elapsed since the last frame;
Lua-callable as:
on_update(deltaMilli)

Called once per frame, after the engine's own per-frame bookkeeping (script queue processing, sprite pool update). This is the main per-frame hook — virtually all real-time game logic (movement, input polling, timers you're tracking by hand) lives here.

Only one on_update global can exist — the engine calls exactly that one function per frame. If your project needs several independent per-frame systems, building a small fan-out (a table of registered callbacks, each invoked from your own single on_update) is a common pattern, but it's entirely your own code to write — the engine has no opinion on it.

function on_update(dt) print("frame delta: " .. dt .. "ms") end

◆ GetActiveEnemyCount()

int Scarab::Lua::LuaEngine::GetActiveEnemyCount ( void  )

Ask Lua how many enemies it currently has active, via the optional global get_active_enemy_count(). EngineHost::CheckSpritesQueueEmpty's "is the screen clear, unblock sp_wait_queue_empty()" check is entirely driven by this - every enemy type is Lua/SpritePool-owned, so this count is the only source of truth for whether the screen is clear.

Returns
The Lua-reported active enemy count, or 0 if no such global is defined.
Lua-callable as:
get_active_enemy_count() -> count

Called periodically by the engine to resolve sp_wait_queue_empty() (see scripting.md) — the queue only unblocks once this returns 0. If you never define this global at all, the engine treats it as always reporting 0 active enemies, so sp_wait_queue_empty() unblocks immediately rather than actually waiting — define this accurately if your stage scripts rely on sp_wait_queue_empty to gate wave pacing.

function get_active_enemy_count() local total = 0 for _, list in pairs(activeEnemiesByType) do total = total + #( list ) end return total end

◆ GetApplicationDirectory()

const std::string & Scarab::Lua::LuaEngine::GetApplicationDirectory ( void  ) const

Return the running executable's own directory (also exposed to Lua as APP_DIR by Init above) - used by EngineHost to locate the bootstrap entry script on disk before any Lua exists to do so itself.

Returns
The application's own directory (trailing separator included), or an empty string if Init hasn't run yet.

◆ Init()

void Scarab::Lua::LuaEngine::Init ( Engine ::IRendererProvider *  pRendererProvider,
SunLight ::Sound ::SoundManager *  pSoundManager,
Engine ::SpritePool *  pSpritePool 
)

Give Lua access to the renderer provider/SoundManager/SpritePool and register the primitive API modules (camera, input, tilemap, sound, sprite) that depend on them. Called from EngineHost's constructor body (not it's member-init list) since it needs m_LuaEngine to already exist as a constructed object to call a method on it - the provider itself is just the constructor's own parameter, forwarded straight through (EngineHost keeps no ITileMap* member of it's own; it has no remaining C++-side use for one). Also resolves and exposes the running executable's own directory as the Lua global APP_DIR - deciding where resources actually live relative to that (BASE_PATH) is main.lua's own job, not C++'s; the one exception is the bootstrap entry script itself, which EngineHost must locate on disk before any Lua exists to make that decision (see GetApplicationDirectory below).

Parameters
pRendererProviderPointer to the renderer provider every renderer-needing primitive reaches the tile map/draw surface through (the renderer itself doesn't exist yet - see IRendererProvider);
pSoundManagerPointer to the engine's sound manager instance;
pSpritePoolPointer to the engine's sprite pool instance;

◆ InstallVirtualClock()

void Scarab::Lua::LuaEngine::InstallVirtualClock ( void  )

Headless (–headless) only - make Lua's own os.time()/ os.clock() follow the null renderer's virtual clock instead of real time (see LuaAppApi::InstallVirtualClock for the why and the set_timer-callback caveat). Must run after Init(), since the replacements read the draw surface Init() stashes.

◆ RunFile()

bool Scarab::Lua::LuaEngine::RunFile ( std ::string  strFileName)

Execute a lua script - this is the ONE entry point that loads the game's very first script (EngineHost::LoadLuaScript), before Lua's own overridden "dofile" global (LuaFileSystemApi::DoFile) even exists to be called. Originally used the C API's luaL_dofile(), which reads via a raw fopen() internally - a real gap found while building Phase 12's archive-distribution support: every other resource load in this engine (dofile, load_json, textures, sound, tilemaps) already routed through SunLight::FileSystem, but this one didn't, so the first script of an archive-distributed game could never even be reached. Reads the file itself via SunLight::FileSystem::FileSystemFactory instead (mirrors LuaFileSystemApi::DoFile's own approach exactly - luaL_loadbuffer + lua_pcall in place of luaL_loadfile's internal fopen), so this now works identically whether strFileName is a real loose-directory path or a virtual path inside a mounted archive.

Parameters
strFileNameLua script file name to execute;
Returns
true If operation was succesful;
false If operation has failed;

◆ TryDispatchLoadStage()

bool Scarab::Lua::LuaEngine::TryDispatchLoadStage ( uint16_t  nStageId)

Give Lua first refusal on a LOAD_STAGE_CMD state id, via the optional Lua global on_load_stage(stageId) (bootstrap.lua) - the same "Lua gets first refusal" shape as TryDispatchMoveSpritesToScreen. Since stage bootstrap is a single mechanism (not per-type like the enemy ports), there is no legacy C++ fallback here - Lua is expected to always claim a valid stage id.

Parameters
nStageIdThe stage id (src/stageids.lua) received from the queue;
Returns
true if Lua loaded the stage's map and script successfully.
Lua-callable as:
on_load_stage(stageId) -> success

Called when the queue reaches an sp_load_stage(stageId) command. Unlike the other hooks, this one is expected to always be defined and to always claim a valid stageId — there's no C++-side fallback if it isn't. Typically loads a map (tilemap_load_map) and dofiles a stage script.

function on_load_stage(stageId) if stageId == STAGE_FIRST then tilemap_load_map(BASE_PATH .. "tilemap/corsair/corsair.tmx", MAP_ALIGNMENT_CENTER_WIDTH_BOTTOM) dofile(BASE_PATH .. "scripts/stages/1st_stage_corsair.lua") return true end return false end

◆ TryDispatchMoveSpritesToScreen()

bool Scarab::Lua::LuaEngine::TryDispatchMoveSpritesToScreen ( uint16_t  nStateId)

Dispatch a MOVE_SPRITES_TO_SCREEN_CMD state id to Lua, via the optional global on_move_sprites_to_screen(stateId). The state id itself is entirely Lua-owned (see src/wavestates.lua) - C++ just ferries the ScriptProcessor's queued integer back to Lua opaquely, so stage scripts' sp_move_sprites_to_screen(...) calls (and their sp_wait/sp_wait_queue_empty pacing) work the same regardless of which enemy type a given id belongs to.

Parameters
nStateIdThe wave-spawn state id received from the queue;
Returns
true if Lua claimed and handled this state id; false if Lua doesn't handle it (no global defined, or the handler explicitly declines, or no wave handler registered for this id).
Lua-callable as:
on_move_sprites_to_screen(stateId) -> handled

Called when the ScriptProcessor queue reaches an sp_move_sprites_to_screen(stateId) command (see scripting.md). Return true if you handled this stateId (spawned something); returning false/nothing tells the engine this particular wave-spawn id wasn't recognized.

function on_move_sprites_to_screen(stateId) if stateId == STATE_MOVE_SATELLITES_TO_SCREEN_RANDOM then – spawn logic here return true end return false end


The documentation for this class was generated from the following files: