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

Commit

Permalink
Unfucked actibity scripting to use actual lua parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Causeless committed Nov 4, 2023
1 parent 8d07073 commit f664d7c
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 74 deletions.
100 changes: 43 additions & 57 deletions Activities/GAScripted.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,63 +184,38 @@ void GAScripted::Destroy(bool notInherited) {
// spawned will use the new scripts.

int GAScripted::ReloadScripts() {
int error = 0;

// Read in the Lua script function definitions for this preset
if (!m_ScriptPath.empty()) {
// Get the required Area:s from the new script
CollectRequiredAreas();

// If it hasn't been yet, run the file that specifies the Lua functions for this' operating logic (including the scene test function)
if (!g_LuaMan.GetMasterScriptState().GlobalIsDefined(m_LuaClassName)) {
// Temporarily store this Activity so the Lua state can access it
g_LuaMan.GetMasterScriptState().SetTempEntity(this);
// Define the var that will hold the script file definitions
if ((error = g_LuaMan.GetMasterScriptState().RunScriptString(m_LuaClassName + " = ToGameActivity(LuaMan.TempEntity);")) < 0) {
return error;
}
}
if (m_ScriptPath.empty()) {
return 0;
}

// Load and run the file, defining all the scripted functions of this Activity
if ((error = g_LuaMan.GetMasterScriptState().RunScriptFile(m_ScriptPath)) < 0) {
return error;
}
CollectRequiredAreas();

std::string luaClearSupportedFunctionsString;
for (const std::string& functionName : GetSupportedScriptFunctionNames()) {
luaClearSupportedFunctionsString += m_LuaClassName + "." + functionName + " = nil;";
}

return error;
if (g_LuaMan.GetMasterScriptState().RunScriptString(luaClearSupportedFunctionsString) < 0) {
return -1;
}

std::unordered_map<std::string, LuabindObjectWrapper*> scriptFileFunctions;
if (g_LuaMan.GetMasterScriptState().RunScriptFileAndRetrieveFunctions(m_ScriptPath, m_LuaClassName, GetSupportedScriptFunctionNames(), scriptFileFunctions) < 0) {
return -2;
}

m_ScriptFunctions.clear();
for (const auto& [functionName, functionObject] : scriptFileFunctions) {
m_ScriptFunctions[functionName] = std::unique_ptr<LuabindObjectWrapper>(functionObject);
}

return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool GAScripted::HasSaveFunction() const {
//TODO this method is complicated and manually parsing lua like this sucks. It should be replaceable with a simple check if the function exists in Lua, but it wasn't working when I tried so I just copied this from SceneIsCompatible.
std::ifstream scriptInputFileStream(m_ScriptPath);
if (scriptInputFileStream.good()) {
std::string::size_type commentPos;
bool inBlockComment = false;
while (!scriptInputFileStream.eof()) {
char rawLine[512];
scriptInputFileStream.getline(rawLine, 512);
std::string currentLine(rawLine);

if (!inBlockComment) {
commentPos = currentLine.find("--[[", 0);
inBlockComment = commentPos != std::string::npos;
}
if (inBlockComment) {
commentPos = currentLine.find("]]", commentPos == std::string::npos ? 0 : commentPos);
inBlockComment = commentPos != std::string::npos;
}
if (!inBlockComment) {
commentPos = currentLine.find("--", 0);
std::string::size_type foundTextPos = currentLine.find("OnSave");
if (foundTextPos != std::string::npos && foundTextPos < commentPos) {
return true;
}
}
}
}
return false;
return m_ScriptFunctions.find("OnSave") != m_ScriptFunctions.end();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -329,13 +304,16 @@ int GAScripted::Start() {
}

// Run the file that specifies the Lua functions for this' operating logic
if ((error = g_LuaMan.GetMasterScriptState().RunScriptFile(m_ScriptPath)) < 0) {
if (ReloadScripts() < 0) {
return error;
}

// Call the defined function, but only after first checking if it exists
if ((error = g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".StartActivity then " + m_LuaClassName + ":StartActivity( " + (initialActivityState == ActivityState::NotStarted ? "true" : "false") + "); end")) < 0) {
return error;
// Call the create function, but only after first checking if it exists
auto createItr = m_ScriptFunctions.find("StartActivity");
if (createItr != m_ScriptFunctions.end()) {
if ((error = g_LuaMan.GetMasterScriptState().RunScriptFunctionObject(createItr->second.get(), m_LuaClassName, "", {}, { initialActivityState == ActivityState::NotStarted ? "true" : "false" }, {})) < 0) {
return error;
}
}

// Clear active global scripts
Expand Down Expand Up @@ -378,7 +356,10 @@ void GAScripted::SetPaused(bool pause) {
GameActivity::SetPaused(pause);

// Call the defined function, but only after first checking if it exists
g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".PauseActivity then " + m_LuaClassName + ":PauseActivity(" + (pause ? "true" : "false") + "); end");
auto pauseItr = m_ScriptFunctions.find("PauseActivity");
if (pauseItr != m_ScriptFunctions.end()) {
g_LuaMan.GetMasterScriptState().RunScriptFunctionObject(pauseItr->second.get(), m_LuaClassName, "", {}, { pause ? "true" : "false" }, {});
}

// Pause all global scripts
for (std::vector<GlobalScript *>::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) {
Expand All @@ -398,8 +379,10 @@ void GAScripted::End() {
GameActivity::End();

// Call the defined function, but only after first checking if it exists
g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".EndActivity then " + m_LuaClassName + ":EndActivity(); end");

auto endItr = m_ScriptFunctions.find("EndActivity");
if (endItr != m_ScriptFunctions.end()) {
g_LuaMan.GetMasterScriptState().RunScriptFunctionObject(endItr->second.get(), m_LuaClassName, "", {}, {}, {});
}

// End all global scripts
for (std::vector<GlobalScript *>::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) {
Expand Down Expand Up @@ -457,7 +440,10 @@ void GAScripted::Update() {
AddPieSlicesToActiveActorPieMenus();

// Call the defined function, but only after first checking if it exists
g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".UpdateActivity then " + m_LuaClassName + ":UpdateActivity(); end");
auto updateItr = m_ScriptFunctions.find("UpdateActivity");
if (updateItr != m_ScriptFunctions.end()) {
g_LuaMan.GetMasterScriptState().RunScriptFunctionObject(updateItr->second.get(), m_LuaClassName, "", {}, {}, {});
}

UpdateGlobalScripts(false);
}
Expand Down
5 changes: 5 additions & 0 deletions Activities/GAScripted.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "GlobalScript.h"
#include "Box.h"

#include "LuabindObjectWrapper.h"

namespace RTE
{

Expand All @@ -41,6 +43,7 @@ class GAScripted : public GameActivity {

public:

ScriptFunctionNames("StartActivity", "UpdateActivity", "PauseActivity", "EndActivity", "OnSave");

// Concrete allocation and cloning definitions
EntityAllocation(GAScripted);
Expand Down Expand Up @@ -283,6 +286,8 @@ ClassInfoGetters;
// The list of global scripts allowed to run during this activity
std::vector<GlobalScript *> m_GlobalScriptsList;

std::unordered_map<std::string, std::unique_ptr<LuabindObjectWrapper>> m_ScriptFunctions; //!< A map of LuabindObjectWrappers that hold Lua functions. Used to maintain script execution order and avoid extraneous Lua calls.


//////////////////////////////////////////////////////////////////////////////////////////
// Private member variable and method declarations
Expand Down
2 changes: 1 addition & 1 deletion Entities/MovableObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ int MovableObject::LoadScript(const std::string &scriptPath, bool loadAsEnabledS
m_AllLoadedScripts.try_emplace(scriptPath, loadAsEnabledScript);

std::unordered_map<std::string, LuabindObjectWrapper *> scriptFileFunctions;
if (usedState.RunScriptFileAndRetrieveFunctions(scriptPath, GetSupportedScriptFunctionNames(), scriptFileFunctions) < 0) {
if (usedState.RunScriptFileAndRetrieveFunctions(scriptPath, "", GetSupportedScriptFunctionNames(), scriptFileFunctions) < 0) {
return -5;
}
for (const auto &[functionName, functionObject] : scriptFileFunctions) {
Expand Down
12 changes: 0 additions & 12 deletions Entities/MovableObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,6 @@ struct BITMAP;

namespace RTE {

#pragma region Global Macro Definitions
#define ScriptFunctionNames(...) \
virtual std::vector<std::string> GetSupportedScriptFunctionNames() const { return {__VA_ARGS__}; }

#define AddScriptFunctionNames(PARENT, ...) \
std::vector<std::string> GetSupportedScriptFunctionNames() const override { \
std::vector<std::string> functionNames = PARENT::GetSupportedScriptFunctionNames(); \
functionNames.insert(functionNames.end(), {__VA_ARGS__}); \
return functionNames; \
}
#pragma endregion

struct HitData;

class MOSRotating;
Expand Down
2 changes: 1 addition & 1 deletion Entities/PieSlice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ namespace RTE {
std::string filePath = m_LuabindFunctionObject->GetFilePath();
std::unordered_map<std::string, LuabindObjectWrapper *> scriptFileFunctions;

status = g_LuaMan.GetMasterScriptState().RunScriptFileAndRetrieveFunctions(filePath, { m_FunctionName }, scriptFileFunctions);
status = g_LuaMan.GetMasterScriptState().RunScriptFileAndRetrieveFunctions(filePath, "", { m_FunctionName }, scriptFileFunctions);
if (scriptFileFunctions.find(m_FunctionName) != scriptFileFunctions.end()) {
m_LuabindFunctionObject = std::unique_ptr<LuabindObjectWrapper>(scriptFileFunctions.at(m_FunctionName));
}
Expand Down
12 changes: 12 additions & 0 deletions Lua/LuabindObjectWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ namespace luabind::adl {

namespace RTE {

#pragma region Global Macro Definitions
#define ScriptFunctionNames(...) \
virtual std::vector<std::string> GetSupportedScriptFunctionNames() const { return {__VA_ARGS__}; }

#define AddScriptFunctionNames(PARENT, ...) \
std::vector<std::string> GetSupportedScriptFunctionNames() const override { \
std::vector<std::string> functionNames = PARENT::GetSupportedScriptFunctionNames(); \
functionNames.insert(functionNames.end(), {__VA_ARGS__}); \
return functionNames; \
}
#pragma endregion

/// <summary>
/// A wrapper for luabind objects, to avoid include problems with luabind.
/// </summary>
Expand Down
15 changes: 13 additions & 2 deletions Managers/LuaMan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,16 +643,27 @@ namespace RTE {

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int LuaStateWrapper::RunScriptFileAndRetrieveFunctions(const std::string &filePath, const std::vector<std::string> &functionNamesToLookFor, std::unordered_map<std::string, LuabindObjectWrapper *> &outFunctionNamesAndObjects) {
int LuaStateWrapper::RunScriptFileAndRetrieveFunctions(const std::string &filePath, const std::string &prefix, const std::vector<std::string> &functionNamesToLookFor, std::unordered_map<std::string, LuabindObjectWrapper *> &outFunctionNamesAndObjects) {
if (int error = RunScriptFile(filePath); error < 0) {
return error;
}

std::lock_guard<std::recursive_mutex> lock(m_Mutex);
s_currentLuaState = this;

luabind::object prefixObject;
if (prefix == "") {
prefixObject = luabind::globals(m_State);
} else {
prefixObject = luabind::globals(m_State)[prefix];
}

if (luabind::type(prefixObject) == LUA_TNIL) {
return -1;
}

for (const std::string &functionName : functionNamesToLookFor) {
luabind::object functionObject = luabind::globals(m_State)[functionName];
luabind::object functionObject = prefixObject[functionName];
if (luabind::type(functionObject) == LUA_TFUNCTION) {
luabind::object *functionObjectCopyForStoring = new luabind::object(functionObject);
outFunctionNamesAndObjects.try_emplace(functionName, new LuabindObjectWrapper(functionObjectCopyForStoring, filePath));
Expand Down
3 changes: 2 additions & 1 deletion Managers/LuaMan.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,11 @@ namespace RTE {
/// Opens and loads a file containing a script and runs it on the state, then retrieves all of the specified functions that exist into the output map.
/// </summary>
/// <param name="filePath">The path to the file to load and run.</param>
/// <param name="prefix">The prefix before each function we're looking for. With normal objects this is usually nothing (free floating), but activities expect the activity name beforehand.</param>
/// <param name="functionNamesToLookFor">The vector of strings defining the function names to be retrieved.</param>
/// <param name="outFunctionNamesAndObjects">The map of function names to LuabindObjectWrappers to be retrieved from the script that was run.</param>
/// <returns>Returns less than zero if any errors encountered when running this script. To get the actual error string, call GetLastError.</returns>
int RunScriptFileAndRetrieveFunctions(const std::string &filePath, const std::vector<std::string> &functionNamesToLookFor, std::unordered_map<std::string, LuabindObjectWrapper *> &outFunctionNamesAndObjects);
int RunScriptFileAndRetrieveFunctions(const std::string &filePath, const std::string &prefix, const std::vector<std::string> &functionNamesToLookFor, std::unordered_map<std::string, LuabindObjectWrapper *> &outFunctionNamesAndObjects);
#pragma endregion

#pragma region Concrete Methods
Expand Down

0 comments on commit f664d7c

Please sign in to comment.