Skip to content
This repository was archived by the owner on Jan 5, 2024. It is now read-only.

Commit d95e6b6

Browse files
committed
Added support for multiple scripts to MOs and overhauled script loading to support it
Added methods to find scripts on an object and check if the object has a given script (both based on full path to script) Renamed UpdateScript method to UpdateScripts to be more accurate
1 parent 9fe8eb7 commit d95e6b6

File tree

4 files changed

+158
-163
lines changed

4 files changed

+158
-163
lines changed

Entities/Attachable.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,7 @@ void Attachable::Update()
545545
MOSRotating::Update();
546546

547547
// If we're attached to something, MoveableMan doesn't own us, and therefore isn't calling our ScriptUpdate (and our parent isn't calling it either), so we should here
548-
if (m_pParent && !m_ScriptPath.empty())
549-
UpdateScript();
548+
if (m_pParent) { UpdateScripts(); }
550549
}
551550

552551

Entities/MovableObject.cpp

Lines changed: 124 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void MovableObject::Clear()
7171
m_ToSettle = false;
7272
m_ToDelete = false;
7373
m_HUDVisible = true;
74-
m_ScriptPath.clear();
74+
m_LoadedScripts.clear();
7575
m_ScriptPresetName.clear();
7676
m_ScriptObjectName.clear();
7777
m_ScreenEffectFile.Reset();
@@ -205,10 +205,10 @@ int MovableObject::Create(const MovableObject &reference)
205205
m_MissionCritical = reference.m_MissionCritical;
206206
m_CanBeSquished = reference.m_CanBeSquished;
207207
m_HUDVisible = reference.m_HUDVisible;
208-
m_ScriptPath = reference.m_ScriptPath;
208+
for (std::pair<std::string, bool> scriptEntry : reference.m_LoadedScripts) {
209+
m_LoadedScripts.push_back({scriptEntry.first, scriptEntry.second});
210+
}
209211
m_ScriptPresetName = reference.m_ScriptPresetName;
210-
// Should be unique to the object, will be created lazily upon first UpdateScript
211-
// m_ScriptObjectName
212212
if (reference.m_pScreenEffect)
213213
{
214214
m_ScreenEffectFile = reference.m_ScreenEffectFile;
@@ -449,108 +449,113 @@ int MovableObject::Save(Writer &writer) const
449449
return 0;
450450
}
451451

452+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
452453

453-
//////////////////////////////////////////////////////////////////////////////////////////
454-
// Method: Destroy
455-
//////////////////////////////////////////////////////////////////////////////////////////
456-
// Description: Destroys and resets (through Clear()) the MovableObject object.
457-
458-
void MovableObject::Destroy(bool notInherited)
459-
{
460-
// Clean up the existence of this in the script state
461-
if (!m_ScriptObjectName.empty())
462-
{
463-
// Call the scripted destruction function, but only after first checking if it and this instance's Lua representation really exists
464-
g_LuaMan.RunScriptString("if " + m_ScriptPresetName + " and " + m_ScriptPresetName + ".Destroy and " + m_ScriptObjectName + " then " + m_ScriptPresetName + ".Destroy(" + m_ScriptObjectName + "); end");
465-
// Assign nil to the variable that held this' representation in Lua
466-
g_LuaMan.RunScriptString("if " + m_ScriptObjectName + " then " + m_ScriptObjectName + " = nil; end");
454+
void MovableObject::Destroy(bool notInherited) {
455+
if (!m_ScriptObjectName.empty()) {
456+
for (std::pair<std::string, bool> scriptEntry: m_LoadedScripts) {
457+
if (scriptEntry.second == true) {
458+
g_LuaMan.RunFunctionInPresetScript("Destroy", scriptEntry.first, m_ScriptPresetName, m_ScriptObjectName);
459+
}
460+
}
461+
g_LuaMan.RunScriptString(m_ScriptObjectName + " = nil;");
467462
}
468463

469-
if (!notInherited)
470-
SceneObject::Destroy();
464+
if (!notInherited) { SceneObject::Destroy(); }
471465
Clear();
472466

473467
g_MovableMan.UnregisterObject(this);
474468
}
475469

470+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
476471

477-
//////////////////////////////////////////////////////////////////////////////////////////
478-
// Virtual method: LoadScripts
479-
//////////////////////////////////////////////////////////////////////////////////////////
480-
// Description: Loads the preset scripts of this object, from a specified path.
481-
482-
int MovableObject::LoadScripts(string scriptPath)
483-
{
484-
if (scriptPath.empty())
472+
int MovableObject::LoadScript(std::string const &scriptPath, bool loadAsEnabledScript) {
473+
// Return an error if the script path is empty or already there
474+
if (scriptPath.empty()) {
485475
return -1;
486-
487-
// Read in the Lua script function definitions for this preset
488-
int error = 0;
489-
490-
// Save the script path
491-
m_ScriptPath = scriptPath;
476+
} else if (HasScript(scriptPath)) {
477+
return -2;
478+
}
479+
m_LoadedScripts.push_back({scriptPath, loadAsEnabledScript});
492480

493481
// Clear the temporary variable names that will hold the functions read in from the file
494-
if ((error = g_LuaMan.RunScriptString("Create = nil; Destroy = nil; Update = nil;")) < 0)
495-
return error;
496-
497-
// Run the file that specifies the Lua functions for this' operating logic
498-
if ((error = g_LuaMan.RunScriptFile(m_ScriptPath)) < 0)
499-
return error;
500-
482+
for (std::string functionName : GetSupportedScriptFunctionNames()) {
483+
if (g_LuaMan.RunScriptString(functionName + " = nil;") < 0) {
484+
return -3;
485+
}
486+
}
501487
// Create a new table for all presets and object instances of this class, to organize things a bit
502-
if ((error = g_LuaMan.RunScriptString("if not " + GetClassName() + "s then " + GetClassName() + "s = {}; end")) < 0)
503-
return error;
504-
// TODO WAIT A MINUTE.. is this an original preset????!! .. does it matter? A: not really
505-
// Get a new ID for this original preset so we can assign the read-in function definitions to it
506-
m_ScriptPresetName = GetClassName() + "s." + g_LuaMan.GetNewPresetID();
488+
if (g_LuaMan.RunScriptString(GetClassName() + "s = " + GetClassName() + "s or {};") < 0) {
489+
return -3;
490+
}
507491

508-
// Clear out the instance object name so it gets created in the state upon first UpdateScript
509-
m_ScriptObjectName.clear();
492+
// Run the specified lua file to load everything in it into the global namespace for assignment
493+
if (g_LuaMan.RunScriptFile(scriptPath) < 0) {
494+
return -4;
495+
}
510496

511-
// Under the class' table, create a new table for all functions of this specific preset and its unique ID
512-
if ((error = g_LuaMan.RunScriptString(m_ScriptPresetName + " = {};")) < 0)
513-
return error;
497+
// If there's no ScriptPresetName this is the first script being loaded for this preset, or scripts have been reloaded.
498+
// Generate a ScriptPresetName, setup a table for the preset's functions, and clear the instance object name so it gets created in the first run of UpdateScripts
499+
if (m_ScriptPresetName.empty()) {
500+
// TODO WAIT A MINUTE.. is this an original preset????!! .. does it matter? A: not really
501+
m_ScriptPresetName = GetClassName() + "s." + g_LuaMan.GetNewPresetID();
514502

515-
// Now assign the different functions read in from the script file to the permanent locations of this original preset's table
516-
if ((error = g_LuaMan.RunScriptString("if Create then " + m_ScriptPresetName + ".Create = Create; end;")) < 0)
517-
return error;
518-
if ((error = g_LuaMan.RunScriptString("if Destroy then " + m_ScriptPresetName + ".Destroy = Destroy; end;")) < 0)
519-
return error;
520-
if ((error = g_LuaMan.RunScriptString("if Update then " + m_ScriptPresetName + ".Update = Update; end;")) < 0)
521-
return error;
522-
if ((error = g_LuaMan.RunScriptString("if OnPieMenu then " + m_ScriptPresetName + ".OnPieMenu = OnPieMenu; end;")) < 0)
523-
return error;
503+
if (g_LuaMan.RunScriptString(m_ScriptPresetName + " = {};") < 0) {
504+
return -3;
505+
}
524506

525-
return error;
526-
}
507+
m_ScriptObjectName.clear();
508+
}
527509

510+
// Assign the different functions read in from the script to their permanent locations in the preset's table
511+
for (std::string functionName : GetSupportedScriptFunctionNames()) {
512+
if (g_LuaMan.GlobalIsDefined(functionName)) {
513+
int error = g_LuaMan.RunScriptString(
514+
m_ScriptPresetName + "." + functionName + " = " + m_ScriptPresetName + "." + functionName + " or {}; " +
515+
m_ScriptPresetName + "." + functionName + "[\"" + scriptPath + "\"] = " + functionName + ";"
516+
);
517+
518+
if (error < 0) {
519+
return -3;
520+
}
521+
}
522+
}
523+
return 0;
524+
}
528525

529-
//////////////////////////////////////////////////////////////////////////////////////////
530-
// Virtual method: ReloadScripts
531-
//////////////////////////////////////////////////////////////////////////////////////////
532-
// Description: Reloads the preset scripts of this object, from the same script file
533-
// path as was originally defined. This will also update the original
534-
// preset in the PresetMan with the updated scripts so future objects
535-
// spawned will use the new scripts.
526+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
536527

537-
int MovableObject::ReloadScripts()
538-
{
539-
int error = 0;
528+
int MovableObject::ReloadScripts() {
529+
if (m_LoadedScripts.empty()) {
530+
return 0;
531+
}
540532

541-
// Read in the Lua script function definitions for this preset
542-
if (!m_ScriptPath.empty())
543-
{
544-
// Reload the preset funcitons of this instance
545-
if ((error = LoadScripts(m_ScriptPath)) < 0)
546-
return error;
547-
// Now also reload the ones of the original preset of this so all future objects will use the new scripts
548-
MovableObject *pPreset = const_cast<MovableObject *>(dynamic_cast<const MovableObject *>(g_PresetMan.GetEntityPreset(GetClassName(), GetPresetName(), GetModuleID())));
549-
if (pPreset && pPreset != this)
550-
{
551-
if ((error = pPreset->LoadScripts(m_ScriptPath)) < 0)
552-
return error;
533+
auto clearScriptConfigurationAndLoadPreexistingScripts = [](MovableObject *object) {
534+
std::vector<std::pair<std::string, bool>> loadedScriptsCopy = object->m_LoadedScripts;
535+
object->m_LoadedScripts.clear();
536+
object->m_ScriptPresetName.clear();
537+
538+
int status = 0;
539+
for (std::pair<std::string, bool> scriptEntry : loadedScriptsCopy) {
540+
status = object->LoadScript(scriptEntry.first, scriptEntry.second);
541+
if (status < 0) {
542+
return status;
543+
}
553544
}
545+
return status;
546+
};
547+
548+
int status = clearScriptConfigurationAndLoadPreexistingScripts(this);
549+
if (status >= 0) {
550+
return status;
551+
}
552+
MovableObject *pPreset = const_cast<MovableObject *>(dynamic_cast<const MovableObject *>(g_PresetMan.GetEntityPreset(GetClassName(), GetPresetName(), GetModuleID())));
553+
if (pPreset && pPreset != this) {
554+
status = clearScriptConfigurationAndLoadPreexistingScripts(pPreset);
555+
}
556+
557+
return status;
558+
}
554559
}
555560

556561
return error;
@@ -811,75 +816,60 @@ void MovableObject::Update()
811816
}
812817
*/
813818

814-
//////////////////////////////////////////////////////////////////////////////////////////
815-
// Virtual method: UpdateScript
816-
//////////////////////////////////////////////////////////////////////////////////////////
817-
// Description: Updates this MovableObject's Lua script. Supposed to be done every
818-
// frame after the rest of the hardcoded C++ update is done.
819+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
819820

820-
int MovableObject::UpdateScript()
821-
{
822-
// This preset doesn't seem to have any script file defined, so then just return
823-
if (m_ScriptPath.empty() || m_ScriptPresetName.empty())
821+
int MovableObject::UpdateScripts() {
822+
if (m_LoadedScripts.empty() || m_ScriptPresetName.empty()) {
824823
return -1;
825-
826-
int error = 0;
824+
}
827825

828826
// Check to make sure the preset of this is still defined in the Lua state. If not, re-create it and recover gracefully
829-
if (!g_LuaMan.ExpressionIsTrue(m_ScriptPresetName, false))
830-
ReloadScripts();
827+
if (!g_LuaMan.ExpressionIsTrue(m_ScriptPresetName, false)) { ReloadScripts(); }
831828

832-
// First see if we even have a representation stored in the Lua state, and if not, create one
833-
if (m_ScriptObjectName.empty())
834-
{
835-
// Get the unique object identifier for this object and construct the object isntance name in Lua that points to this object so we can pass it into the preset functions
829+
// If we don't have a Lua representation for this object instance, create one and call the Lua Create function on it
830+
if (m_ScriptObjectName.empty()) {
836831
m_ScriptObjectName = GetClassName() + "s." + g_LuaMan.GetNewObjectID();
837832

838-
// Give access to this in the Lua state
833+
// Give Lua access to this object, then use that access to set up the object's Lua representation
839834
g_MovableMan.SetScriptedEntity(this);
840-
// Create the Lua variable which will hold the object instance of this instance for as long as it exists
841-
if ((error = g_LuaMan.RunScriptString(m_ScriptObjectName + " = To" + GetClassName() + "(MovableMan.ScriptedEntity);")) < 0)
842-
return error;
835+
if (g_LuaMan.RunScriptString(m_ScriptObjectName + " = To" + GetClassName() + "(MovableMan.ScriptedEntity);") < 0) {
836+
return -2;
837+
}
843838

844-
// Call the scripted creation function, but only after first checking if it and this instance's Lua representation really exists
845-
if ((error = g_LuaMan.RunScriptString("if " + m_ScriptPresetName + ".Create and " + m_ScriptObjectName + " then " + m_ScriptPresetName + ".Create(" + m_ScriptObjectName + "); end")) < 0)
846-
return error;
839+
for (std::pair<std::string, bool> scriptEntry : m_LoadedScripts) {
840+
if (g_LuaMan.RunFunctionInPresetScript("Create", scriptEntry.first, m_ScriptPresetName, m_ScriptObjectName) < 0) {
841+
return -3;
842+
}
843+
}
847844
}
848845

849-
// Call the defined function, but only after first checking if it and this instance's Lua representation exists
850-
if ((error = g_LuaMan.RunScriptString("if " + m_ScriptPresetName + ".Update and " + m_ScriptObjectName + " then " + m_ScriptPresetName + ".Update(" + m_ScriptObjectName + "); end")) < 0)
851-
return error;
846+
for (std::pair<std::string, bool> scriptEntry : m_LoadedScripts) {
847+
if (scriptEntry.second == true && g_LuaMan.RunFunctionInPresetScript("Update", scriptEntry.first, m_ScriptPresetName, m_ScriptObjectName) < 0) {
848+
return -3;
849+
}
850+
}
852851

853-
return error;
852+
return 0;
854853
}
855854

856-
//////////////////////////////////////////////////////////////////////////////////////////
857-
// Virtual method: OnPieMenu
858-
//////////////////////////////////////////////////////////////////////////////////////////
859-
// Description: Executes the Lua-defined OnPieMenu event handler.
860-
861-
int MovableObject::OnPieMenu(Actor * pActor)
862-
{
863-
if (!pActor)
864-
return -1;
865-
866-
// This preset doesn't seem to have any script file defined, so then just return
867-
if (m_ScriptPath.empty() || m_ScriptPresetName.empty())
868-
return -1;
869-
870-
if (m_ScriptObjectName.empty())
871-
return -1;
855+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
872856

857+
int MovableObject::OnPieMenu(Actor * pActor) {
858+
if (!pActor || m_LoadedScripts.empty() || m_ScriptPresetName.empty() || m_ScriptObjectName.empty()) {
859+
return -1;
860+
}
873861
m_pPieMenuActor = pActor;
874862

875-
int error = 0;
876-
877-
if ((error = g_LuaMan.RunScriptString("if " + m_ScriptPresetName + ".OnPieMenu and " + m_ScriptObjectName + " then " + m_ScriptPresetName + ".OnPieMenu(" + m_ScriptObjectName + "); end")) < 0)
878-
return error;
879-
880-
return error;
863+
int status = 0;
864+
for (std::pair<std::string, bool> scriptEntry : m_LoadedScripts) {
865+
status = scriptEntry.second == true ? g_LuaMan.RunFunctionInPresetScript("OnPieMenu", scriptEntry.first, m_ScriptPresetName, m_ScriptObjectName) : status;
866+
if (status < 0) { break; }
867+
}
868+
return status;
881869
}
882870

871+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
872+
883873
void MovableObject::Update()
884874
{
885875
if (m_RandomizeEffectRotAngleEveryFrame)

0 commit comments

Comments
 (0)