Skip to content

Commit

Permalink
Mission system: use event callback to trigger setup/teardown.
Browse files Browse the repository at this point in the history
The mission-specific callbacks `loadMission(filename, rg)` and `unloadMission()` were decomissioned; instead the name and RG of the .mission file gets delivered via SE_ANGELSCRIPT_MANIPULATIONS+ASMANIP_SCRIPT_LOADED, (params #6 and #7) and unloading is triggered by SE_ANGELSCRIPT_MANIPULATIONS+ASMANIP_SCRIPT_UNLOADING.

This archives the same result with less copypasted callback-invocation code.

Minor changes: MANIP_ enum fields got renamed to ASMANIP_ to match C++ with AngelScript. Doxygen docs were added.
  • Loading branch information
ohlidalp committed Sep 10, 2023
1 parent 27e9683 commit 3073cb0
Show file tree
Hide file tree
Showing 12 changed files with 72 additions and 80 deletions.
10 changes: 9 additions & 1 deletion doc/angelscript/Script2Game/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,21 @@ void print(const string message);
SE_TRUCK_TELEPORT //!< triggered when the user teleports the truck, the argument refers to the Actor Instance ID (use `game.getTruckByNum()`)
SE_TRUCK_MOUSE_GRAB //!< triggered when the user uses the mouse to interact with the actor, the argument refers to the Actor Instance ID (use `game.getTruckByNum()`)

SE_ANGELSCRIPT_MANIPULATIONS //!< triggered when the user tries to dynamically use the scripting capabilities (prevent cheating)
SE_ANGELSCRIPT_MANIPULATIONS //!< triggered when the user tries to dynamically use the scripting capabilities (prevent cheating) args: #1 angelScriptManipulationType, #2 ScriptUnitId_t, #3 RoR::ScriptCategory, #4 unused, #5 script file name (*.as), #6 associated file name (i.e. *.mission), #7 associated file resource group (i.e. *.mission).

SE_GENERIC_MESSAGEBOX_CLICK //!< triggered when the user clicks on a message box button, the argument refers to the button pressed

SE_ALL_EVENTS = 0xffffffff,

};

/// Argument #2 of script event `SE_ANGELSCRIPT_MANIPULATIONS`
enum angelScriptManipulationType
{
ASMANIP_CONSOLE_SNIPPET_EXECUTED = 0, // 0 for Backwards compatibility.
ASMANIP_SCRIPT_LOADED, //!< Triggered after the script's `main()` completed; may trigger additional processing (for example, it delivers the *.mission file to mission system script).
ASMANIP_SCRIPT_UNLOADING //!< Triggered before unloading the script to let it clean up (important for missions).
};

enum inputEvents
{
Expand Down
33 changes: 20 additions & 13 deletions resources/scripts/mission_default.as
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,31 @@ MissionManager g_missions();
/* A mandatory startup function */
void main()
{
game.registerForEvent(SE_ANGELSCRIPT_MANIPULATIONS); // Necessary to receive mission setup info
game.log("default mission script loaded");
}

/* A mandatory callback for setting up a mission */
bool loadMission(string filename, string resource_group)
/* Event handler callback */
void eventCallbackEx(scriptEvents ev, int arg1, int arg2ex, int arg3ex, int arg4ex, string arg5ex, string arg6ex, string arg7ex, string arg8ex)
{
game.log("loading mission file '"+filename+"' (resource group '"+resource_group+"')");
bool result = g_missions.loadMission(filename, resource_group);
game.log("finished loading mission file '"+filename+"' (resource group '"+resource_group+"'), result: " + result);
return result;
if (ev == SE_ANGELSCRIPT_MANIPULATIONS)
{
// args: #1 angelScriptManipulationType, #2 ScriptUnitId_t, #3 RoR::ScriptCategory, #4 unused, #5 script file name (*.as), #6 associated file name (i.e. *.mission), #7 associated file resource group (i.e. *.mission).
angelScriptManipulationType manip = angelScriptManipulationType(arg1);
int nid = arg2ex;

if (manip == ASMANIP_SCRIPT_LOADED && nid == thisScript)
{
bool result = g_missions.loadMission(arg6ex, arg7ex);
//game.log("DBG mission_default.as: finished loading mission file '"+arg6ex+"' (resource group '"+arg7ex+"'), result: " + result);
}
else if (manip == ASMANIP_SCRIPT_UNLOADING && nid == thisScript)
{
g_missions.unloadMission();
//game.log("DBG mission_default.as: finished unloading mission");
}
}
}

/* A mandatory callback for cleanup after a mission */
void unloadMission()
{
game.log("unloading mission");
g_missions.unloadMission();
game.log("finished unloading mission");
}


23 changes: 18 additions & 5 deletions source/main/GameContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,29 @@ bool GameContext::LoadMission(CacheEntry* mission_entry)

// Load script
std::string scriptname = (mission_entry->mission_script != "") ? mission_entry->mission_script : DEFAULT_MISSION_SCRIPT;
ScriptUnitId_t scriptID = App::GetScriptEngine()->loadScript(scriptname, ScriptCategory::MISSION, /*associatedActor:*/nullptr, mission_entry);
if (scriptID == SCRIPTUNITID_INVALID)
ScriptUnitId_t nid = App::GetScriptEngine()->loadScript(scriptname, ScriptCategory::MISSION, /*associatedActor:*/nullptr, mission_entry);
if (nid == SCRIPTUNITID_INVALID)
{
App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR,
fmt::format(_L("Could not load mission script '{}'"), scriptname));
return false;
}

// Execute the setup routine
return App::GetScriptEngine()->invokeLoadMission(scriptID, mission_entry->fname, mission_entry->resource_group);

// Broadcast the SCRIPT_LOADED event with the *.mission file details;
// the handler script will intercept the event and process the file.
TRIGGER_EVENT_ASYNC(SE_ANGELSCRIPT_MANIPULATIONS, ASMANIP_SCRIPT_LOADED,
nid, (int)ScriptCategory::MISSION, 0, scriptname, mission_entry->fname, mission_entry->resource_group);
return true;
}

void GameContext::UnloadMission(ScriptUnitId_t nid)
{
ScriptUnit& unit = App::GetScriptEngine()->getScriptUnit(nid);
// we want to notify any running scripts that we might change something (prevent cheating)
App::GetScriptEngine()->triggerEvent(SE_ANGELSCRIPT_MANIPULATIONS,
ASMANIP_SCRIPT_UNLOADING, nid, (int)unit.scriptCategory, 0, unit.scriptName);
App::GetCacheSystem()->UnLoadResource(*unit.missionEntry);
App::GetScriptEngine()->unloadScript(nid);
}

// --------------------------------
Expand Down
3 changes: 2 additions & 1 deletion source/main/GameContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class GameContext
void UnloadTerrain();
const TerrainPtr& GetTerrain() { return m_terrain; }
bool LoadMission(CacheEntry* entry);
void UnloadMission(ScriptUnitId_t nid);

/// @}
/// @name Actors
Expand Down Expand Up @@ -164,7 +165,7 @@ class GameContext
/// @{

RaceSystem& GetRaceSystem() { return m_race_system; }
RepairMode& GetRepairMode() { return m_recovery_mode; }
RepairMode& GetRepairMode() { return m_recovery_mode; }
SceneMouse& GetSceneMouse() { return m_scene_mouse; }
void TeleportPlayer(float x, float z);
void UpdateGlobalInputEvents();
Expand Down
9 changes: 5 additions & 4 deletions source/main/gameplay/ScriptEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,20 @@ enum scriptEvents
SE_TRUCK_TELEPORT = BITMASK(16), //!< triggered when the user teleports the truck, the argument refers to the actor ID of the vehicle
SE_TRUCK_MOUSE_GRAB = BITMASK(17), //!< triggered when the user uses the mouse to interact with the actor, the argument refers to the actor ID

SE_ANGELSCRIPT_MANIPULATIONS = BITMASK(18), //!< triggered when the user tries to dynamically use the scripting capabilities (prevent cheating) args: #1 angelScriptManipulationType, #2 ScriptUnitId_t, #3 RoR::ScriptCategory, #4 unused, #5 filename
SE_ANGELSCRIPT_MANIPULATIONS = BITMASK(18), //!< triggered when the user tries to dynamically use the scripting capabilities (prevent cheating) args: #1 angelScriptManipulationType, #2 ScriptUnitId_t, #3 RoR::ScriptCategory, #4 unused, #5 script file name (*.as), #6 associated file name (i.e. *.mission), #7 associated file resource group (i.e. *.mission).

SE_GENERIC_MESSAGEBOX_CLICK = BITMASK(19), //!< triggered when the user clicks on a message box button, the argument refers to the button pressed

SE_ALL_EVENTS = 0xffffffff,

};

/// Argument #2 of script event `SE_ANGELSCRIPT_MANIPULATIONS`
enum angelScriptManipulationType
{
MANIP_CONSOLE_SNIPPET_EXECUTED = 0, // Backwards compat
MANIP_SCRIPT_LOADED,
MANIP_SCRIPT_UNLOADED
ASMANIP_CONSOLE_SNIPPET_EXECUTED = 0, // 0 for Backwards compatibility.
ASMANIP_SCRIPT_LOADED, //!< Triggered after the script's `main()` completed; may trigger additional processing (for example, it delivers the *.mission file to mission system script).
ASMANIP_SCRIPT_UNLOADING //!< Triggered before unloading the script to let it clean up (important for missions).
};

/// Args for `eventCallbackEx()` queued via `MSG_SIM_SCRIPT_EVENT_TRIGGERED`
Expand Down
11 changes: 5 additions & 6 deletions source/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ int main(int argc, char *argv[])
ScriptUnitId_t nid = App::GetScriptEngine()->loadScript(request->lsr_filename, request->lsr_category, actor);
// we want to notify any running scripts that we might change something (prevent cheating)
App::GetScriptEngine()->triggerEvent(SE_ANGELSCRIPT_MANIPULATIONS,
MANIP_SCRIPT_LOADED, nid, (int)request->lsr_category, 0, request->lsr_filename);
ASMANIP_SCRIPT_LOADED, nid, (int)request->lsr_category, 0, request->lsr_filename);
delete request;
break;
}
Expand All @@ -412,7 +412,7 @@ int main(int argc, char *argv[])
ScriptUnit& unit = App::GetScriptEngine()->getScriptUnit(*id);
// we want to notify any running scripts that we might change something (prevent cheating)
App::GetScriptEngine()->triggerEvent(SE_ANGELSCRIPT_MANIPULATIONS,
MANIP_SCRIPT_UNLOADED, *id, (int)unit.scriptCategory, 0, unit.scriptName);
ASMANIP_SCRIPT_UNLOADING, *id, (int)unit.scriptCategory, 0, unit.scriptName);
App::GetScriptEngine()->unloadScript(*id);
delete id;
break;
Expand Down Expand Up @@ -815,10 +815,9 @@ int main(int argc, char *argv[])

case MSG_SIM_UNLOAD_MISSION_REQUESTED:
{
ScriptUnitId_t* id = (ScriptUnitId_t*)m.payload;
App::GetScriptEngine()->invokeUnloadMission(*id);
App::GetScriptEngine()->unloadScript(*id);
delete id;
ScriptUnitId_t* nid = (ScriptUnitId_t*)m.payload;
App::GetGameContext()->UnloadMission(*nid);
delete nid;
break;
}

Expand Down
6 changes: 6 additions & 0 deletions source/main/resources/CacheSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,12 @@ void CacheSystem::LoadResource(CacheEntry& t)
ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/true);
ResourceGroupManager::getSingleton().addResourceLocation(t.resource_bundle_path, t.resource_bundle_type, group);
}
else if (t.fext == "mission")
{
// This is a MissionZip bundle - use `inGlobalPool=false` to prevent resource name conflicts.
ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/false);
ResourceGroupManager::getSingleton().addResourceLocation(t.resource_bundle_path, t.resource_bundle_type, group);
}
else if (t.fext == "skin")
{
// This is a SkinZip bundle - use `inGlobalPool=false` to prevent resource name conflicts.
Expand Down
38 changes: 0 additions & 38 deletions source/main/scripting/ScriptEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -705,9 +705,6 @@ int ScriptEngine::setupScriptUnit(int unit_id)

m_script_units[unit_id].defaultEventCallbackFunctionPtr = m_script_units[unit_id].scriptModule->GetFunctionByDecl("void defaultEventCallback(int, string, string, int)");

m_script_units[unit_id].loadMissionFunctionPtr = m_script_units[unit_id].scriptModule->GetFunctionByDecl("bool loadMission(string, string)");
m_script_units[unit_id].unloadMissionFunctionPtr = m_script_units[unit_id].scriptModule->GetFunctionByDecl("void unloadMission()");

// Find the function that is to be called.
auto main_func = m_script_units[unit_id].scriptModule->GetFunctionByDecl("void main()");
if ( main_func == nullptr )
Expand Down Expand Up @@ -828,41 +825,6 @@ ScriptUnit& ScriptEngine::getScriptUnit(ScriptUnitId_t unique_id)
return m_script_units[unique_id];
}

bool ScriptEngine::invokeLoadMission(ScriptUnitId_t id, const std::string& filename, const std::string& resource_group)
{
context->Prepare(this->getScriptUnit(id).loadMissionFunctionPtr);
context->SetArgObject(0, (void*)&filename);
context->SetArgObject(1, (void*)&resource_group);
m_currently_executing_script_unit = id;
int r = context->Execute();
m_currently_executing_script_unit = SCRIPTUNITID_INVALID;

if (r == AngelScript::asEXECUTION_FINISHED)
{
// The return value is only valid if the execution finished successfully
return static_cast<bool>(context->GetReturnDWord());
}
else
{
LOG(fmt::format("WARNING: Invoking `loadMission(filename='{}', resource_group='{}')` in '{}' ended with error code {}",
filename, resource_group, this->getScriptUnit(id).scriptName, r));
return false;
}
}

void ScriptEngine::invokeUnloadMission(ScriptUnitId_t id)
{
context->Prepare(this->getScriptUnit(id).unloadMissionFunctionPtr);
m_currently_executing_script_unit = id;
int r = context->Execute();
m_currently_executing_script_unit = SCRIPTUNITID_INVALID;

if (r != AngelScript::asEXECUTION_FINISHED)
{
LOG(fmt::format("WARNING: Invoking `unloadMission()` in '{}' ended with error code {}", this->getScriptUnit(id).scriptName, r));
}
}

int ScriptEngine::getNumLoadedMissions()
{
int count = 0;
Expand Down
6 changes: 1 addition & 5 deletions source/main/scripting/ScriptEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,10 @@ struct ScriptUnit
AngelScript::asIScriptFunction* eventCallbackFunctionPtr = nullptr; //!< script function pointer to the event callback function
AngelScript::asIScriptFunction* eventCallbackExFunctionPtr = nullptr; //!< script function pointer to the event callback function
AngelScript::asIScriptFunction* defaultEventCallbackFunctionPtr = nullptr; //!< script function pointer for spawner events
AngelScript::asIScriptFunction* loadMissionFunctionPtr = nullptr; //!< only `ScriptCategory::MISSION`, called to set up the mission.
AngelScript::asIScriptFunction* unloadMissionFunctionPtr = nullptr; //!< only `ScriptCategory::MISSION`, called to clean up the mission.
ActorPtr associatedActor; //!< For ScriptCategory::ACTOR
Ogre::String scriptName;
Ogre::String scriptHash;
CacheEntry* missionEntry = nullptr;
CacheEntry* missionEntry = nullptr; //!< For ScriptCategory::MISSION
};

typedef std::map<ScriptUnitId_t, ScriptUnit> ScriptUnitMap;
Expand Down Expand Up @@ -199,8 +197,6 @@ class ScriptEngine : public Ogre::LogListener

AngelScript::asIScriptEngine* getEngine() { return engine; };

bool invokeLoadMission(ScriptUnitId_t id, const std::string& filename, const std::string& resource_group);
void invokeUnloadMission(ScriptUnitId_t id);
int getNumLoadedMissions();

// method from Ogre::LogListener
Expand Down
6 changes: 3 additions & 3 deletions source/main/scripting/bindings/ScriptEventsAngelscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ void RoR::RegisterScriptEvents(asIScriptEngine *engine)
// enum angelScriptManipulationType
result = engine->RegisterEnum("angelScriptManipulationType"); ROR_ASSERT(result>=0);

result = engine->RegisterEnumValue("angelScriptManipulationType", "ASMANIP_CONSOLE_SNIPPET_EXECUTED", MANIP_CONSOLE_SNIPPET_EXECUTED); ROR_ASSERT(result >= 0);
result = engine->RegisterEnumValue("angelScriptManipulationType", "ASMANIP_SCRIPT_LOADED", MANIP_SCRIPT_LOADED); ROR_ASSERT(result >= 0);
result = engine->RegisterEnumValue("angelScriptManipulationType", "ASMANIP_SCRIPT_UNLOADED", MANIP_SCRIPT_UNLOADED); ROR_ASSERT(result >= 0);
result = engine->RegisterEnumValue("angelScriptManipulationType", "ASMANIP_CONSOLE_SNIPPET_EXECUTED", ASMANIP_CONSOLE_SNIPPET_EXECUTED); ROR_ASSERT(result >= 0);
result = engine->RegisterEnumValue("angelScriptManipulationType", "ASMANIP_SCRIPT_LOADED", ASMANIP_SCRIPT_LOADED); ROR_ASSERT(result >= 0);
result = engine->RegisterEnumValue("angelScriptManipulationType", "ASMANIP_SCRIPT_UNLOADING", ASMANIP_SCRIPT_UNLOADING); ROR_ASSERT(result >= 0);

}
2 changes: 1 addition & 1 deletion source/main/system/ConsoleCmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ class AsCmd: public ConsoleCmd

#ifdef USE_ANGELSCRIPT
// we want to notify any running scripts that we might change something (prevent cheating)
App::GetScriptEngine()->triggerEvent(SE_ANGELSCRIPT_MANIPULATIONS, MANIP_CONSOLE_SNIPPET_EXECUTED);
App::GetScriptEngine()->triggerEvent(SE_ANGELSCRIPT_MANIPULATIONS, ASMANIP_CONSOLE_SNIPPET_EXECUTED);

// Re-compose the code snippet
Str<1000> code;
Expand Down
5 changes: 2 additions & 3 deletions source/main/terrain/Terrain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,9 @@ void RoR::Terrain::dispose()
mission_script_IDs.push_back(pair.second.uniqueId);
}
}
for (ScriptUnitId_t id : mission_script_IDs)
for (ScriptUnitId_t nid : mission_script_IDs)
{
App::GetScriptEngine()->invokeUnloadMission(id);
App::GetScriptEngine()->unloadScript(id);
App::GetGameContext()->UnloadMission(nid);
}

m_disposed = true;
Expand Down

0 comments on commit 3073cb0

Please sign in to comment.