Skip to content

Commit

Permalink
Added scripts block to truck file and ACTOR script category
Browse files Browse the repository at this point in the history
Status: scripts are loaded but the global variable `thisActor` cannot be used by the script.
  • Loading branch information
ohlidalp committed Jan 2, 2023
1 parent 8bf9c0f commit b62281b
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 5 deletions.
6 changes: 6 additions & 0 deletions source/main/physics/ActorManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,12 @@ ActorPtr ActorManager::CreateNewActor(ActorSpawnRequest rq, RigDef::DocumentPtr
actor->m_replay_handler = new Replay(actor, App::sim_replay_length->getInt());
}

// Launch scripts (FIXME: ignores sectionconfig)
for (RigDef::Script const& script_def : def->root_module->scripts)
{
App::GetScriptEngine()->loadScript(script_def.filename, ScriptCategory::ACTOR, actor);
}

LOG(" ===== DONE LOADING VEHICLE");

if (App::diag_actor_dump->getBool())
Expand Down
7 changes: 7 additions & 0 deletions source/main/resources/rig_def_fileformat/RigDef_File.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ enum class Keyword
ROTATORS,
ROTATORS2,
SCREWPROPS,
SCRIPTS,
SECTION,
SECTIONCONFIG,
SET_BEAM_DEFAULTS,
Expand Down Expand Up @@ -1152,6 +1153,11 @@ struct Screwprop
float power = 0.f;
};

struct Script
{
std::string filename;
};

struct ShadowOptions
{
int shadow_mode = 0;
Expand Down Expand Up @@ -1603,6 +1609,7 @@ struct Document
std::vector<Rotator> rotators;
std::vector<Rotator2> rotators2;
std::vector<Screwprop> screwprops;
std::vector<Script> scripts;
std::vector<Shock> shocks;
std::vector<Shock2> shocks2;
std::vector<Shock3> shocks3;
Expand Down
12 changes: 12 additions & 0 deletions source/main/resources/rig_def_fileformat/RigDef_Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ void Parser::ProcessCurrentLine()
case Keyword::ROTATORS:
case Keyword::ROTATORS2: this->ParseRotatorsUnified(); return;
case Keyword::SCREWPROPS: this->ParseScrewprops(); return;
case Keyword::SCRIPTS: this->ParseScripts(); return;
case Keyword::SHOCKS: this->ParseShock(); return;
case Keyword::SHOCKS2: this->ParseShock2(); return;
case Keyword::SHOCKS3: this->ParseShock3(); return;
Expand Down Expand Up @@ -2084,6 +2085,17 @@ void Parser::ParseScrewprops()
m_current_module->screwprops.push_back(screwprop);
}

void Parser::ParseScripts()
{
if (!this->CheckNumArguments(1)) { return; }

Script script;

script.filename = this->GetArgStr(0);

m_current_module->scripts.push_back(script);
}

void Parser::ParseRotatorsUnified()
{
if (! this->CheckNumArguments(13)) { return; }
Expand Down
1 change: 1 addition & 0 deletions source/main/resources/rig_def_fileformat/RigDef_Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ class Parser
void ParseRopes();
void ParseRotatorsUnified();
void ParseScrewprops();
void ParseScripts();
void ParseSetCollisionRange();
void ParseSetSkeletonSettings();
void ParseShock();
Expand Down
1 change: 1 addition & 0 deletions source/main/resources/rig_def_fileformat/RigDef_Regexes.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ namespace Regexes
E_KEYWORD_BLOCK("rotators") \
E_KEYWORD_BLOCK("rotators2") \
E_KEYWORD_BLOCK("screwprops") \
E_KEYWORD_BLOCK("scripts") \
E_KEYWORD_INLINE("section") \
E_KEYWORD_INLINE("sectionconfig") \
E_KEYWORD_INLINE("set_beam_defaults") \
Expand Down
51 changes: 48 additions & 3 deletions source/main/scripting/ScriptEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ const char* RoR::ScriptCategoryToString(ScriptCategory c)
{
switch (c)
{
case ScriptCategory::INVALID: return "INVALID";
case ScriptCategory::ACTOR: return "ACTOR";
case ScriptCategory::TERRAIN: return "TERRAIN";
case ScriptCategory::CUSTOM: return "CUSTOM";
case ScriptCategory::INVALID: return "INVALID";
default: return "";
}
}
Expand Down Expand Up @@ -537,7 +538,7 @@ String ScriptEngine::composeModuleName(String const& scriptName, ScriptCategory
return fmt::format("{}(category:{},unique ID:{})", scriptName, ScriptCategoryToString(origin), id);
}

ScriptUnitId_t ScriptEngine::loadScript(String scriptName, ScriptCategory category/* = ScriptCategory::TERRAIN*/)
ScriptUnitId_t ScriptEngine::loadScript(String scriptName, ScriptCategory category/* = ScriptCategory::TERRAIN*/, ActorPtr associatedActor /*= nullptr*/)
{
// This function creates a new script unit, tries to set it up and removes it if setup fails.
// -----------------------------------------------------------------------------------------
Expand All @@ -554,7 +555,11 @@ ScriptUnitId_t ScriptEngine::loadScript(String scriptName, ScriptCategory catego
if (category == ScriptCategory::TERRAIN)
{
m_terrain_script_unit = unit_id;
}
}
else if (category == ScriptCategory::ACTOR)
{
m_script_units[unit_id].associatedActor = associatedActor;
}

// Perform the actual script loading, building and running main().
int result = this->setupScriptUnit(unit_id);
Expand Down Expand Up @@ -596,6 +601,17 @@ int ScriptEngine::setupScriptUnit(int unit_id)
}
m_script_units[unit_id].scriptModule = engine->GetModule(moduleName.c_str(), AngelScript::asGM_ONLY_IF_EXISTS);

// For actor scripts, compile global var `thisActor` to the module
if (m_script_units[unit_id].scriptCategory == ScriptCategory::ACTOR)
{
if (!this->setupActorScriptUnit(unit_id))
{
App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR,
fmt::format("Could not load script '{}' - failed to create global variable `thisActor`.", moduleName));
return -1;
}
}

// Load the script from the file system.
result = builder.AddSectionFromFile(m_script_units[unit_id].scriptName.c_str());
if ( result < 0 )
Expand Down Expand Up @@ -699,6 +715,35 @@ int ScriptEngine::setupScriptUnit(int unit_id)
return 0;
}

bool ScriptEngine::setupActorScriptUnit(int unit_id)
{
int compile_result = m_script_units[unit_id].scriptModule->CompileGlobalVar(m_script_units[unit_id].scriptName.c_str(), "BeamClass@ thisActor;", 0);
if (compile_result < 0)
{
SLOG("Could not compile global var `thisActor`");
return false;
}

int var_index = m_script_units[unit_id].scriptModule->GetGlobalVarIndexByName("thisActor");
if (var_index < 0)
{
SLOG("Could not find global var `thisActor`");
return false;
}

// Assign the global variable; Example: https://www.gamedev.net/forums/topic/644188-angelscript-2263-global-property-issues-solved/5069638/
Actor** thisActorAddr = (Actor**)m_script_units[unit_id].scriptModule->GetAddressOfGlobalVar(var_index);
if (thisActorAddr == nullptr)
{
SLOG("Could not retrieve address of global var `thisActor`");
return false;
}
*thisActorAddr = m_script_units[unit_id].associatedActor.GetRef();
(*thisActorAddr)->AddRef();

return true;
}

void ScriptEngine::unloadScript(ScriptUnitId_t id)
{
ROR_ASSERT(id != SCRIPTUNITID_INVALID);
Expand Down
8 changes: 6 additions & 2 deletions source/main/scripting/ScriptEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ namespace RoR {
enum class ScriptCategory
{
INVALID,
TERRAIN,
ACTOR, //!< Defined in truck file under 'scripts', contains global variable `BeamClass@ this_actor`.
TERRAIN, //!< Defined in terrn2 file under '[Scripts]', receives terrain eventbox notifications.
CUSTOM
};

Expand All @@ -70,6 +71,7 @@ struct ScriptUnit
AngelScript::asIScriptFunction* frameStepFunctionPtr = nullptr; //!< script function pointer to the frameStep function
AngelScript::asIScriptFunction* eventCallbackFunctionPtr = nullptr; //!< script function pointer to the event callback function
AngelScript::asIScriptFunction* defaultEventCallbackFunctionPtr = nullptr; //!< script function pointer for spawner events
ActorPtr associatedActor; //!< For ScriptCategory::ACTOR
Ogre::String scriptName;
Ogre::String scriptHash;
};
Expand All @@ -94,7 +96,7 @@ class ScriptEngine : public Ogre::LogListener, public ZeroedMemoryAllocator
* @param scriptname filename to load
* @return Unique ID of the script unit (because one script file can be loaded multiple times).
*/
ScriptUnitId_t loadScript(Ogre::String scriptname, ScriptCategory category = ScriptCategory::TERRAIN);
ScriptUnitId_t loadScript(Ogre::String scriptname, ScriptCategory category = ScriptCategory::TERRAIN, ActorPtr associatedActor = nullptr);

/**
* Unloads a script
Expand Down Expand Up @@ -202,6 +204,8 @@ class ScriptEngine : public Ogre::LogListener, public ZeroedMemoryAllocator
*/
int setupScriptUnit(int unit_id);

bool setupActorScriptUnit(int unit_id);

AngelScript::asIScriptEngine* engine; //!< instance of the scripting engine
AngelScript::asIScriptContext* context; //!< context in which all scripting happens
Ogre::Log* scriptLog;
Expand Down

0 comments on commit b62281b

Please sign in to comment.