diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Bindings/LuaState.cpp | 76 | ||||
-rw-r--r-- | src/Bindings/LuaState.h | 39 |
2 files changed, 111 insertions, 4 deletions
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index fd29e8e34..b5832802d 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -341,6 +341,33 @@ void cLuaState::cStackTable::ForEachArrayElement(std::function<bool(cLuaState & +void cLuaState::cStackTable::ForEachElement(std::function<bool(cLuaState & a_LuaState)> a_ElementCallback) const +{ + #ifdef _DEBUG + auto stackTop = lua_gettop(m_LuaState); + #endif + lua_pushvalue(m_LuaState, m_StackPos); // Stk: <table> + lua_pushnil(m_LuaState); // Stk: <table> nil + while (lua_next(m_LuaState, -2)) // Stk: <table> <key> <val> + { + auto shouldAbort = a_ElementCallback(m_LuaState); + ASSERT(lua_gettop(m_LuaState) == stackTop + 3); // The element callback must not change the Lua stack below the value + lua_pop(m_LuaState, 1); // Stk: <table> <key> + if (shouldAbort) + { + // The callback wants to abort + lua_pop(m_LuaState, 2); // Stk: empty + return; + } + } + // Stk: <table> + lua_pop(m_LuaState, 1); // Stk: empty +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cLuaState: @@ -748,6 +775,24 @@ void cLuaState::Push(const AString & a_String) +void cLuaState::Push(const AStringMap & a_Dictionary) +{ + ASSERT(IsValid()); + + lua_createtable(m_LuaState, 0, static_cast<int>(a_Dictionary.size())); + int newTable = lua_gettop(m_LuaState); + for (const auto & item: a_Dictionary) + { + Push(item.first); // key + Push(item.second); // value + lua_rawset(m_LuaState, newTable); + } +} + + + + + void cLuaState::Push(const AStringVector & a_Vector) { ASSERT(IsValid()); @@ -1113,6 +1158,37 @@ bool cLuaState::GetStackValue(int a_StackPos, AString & a_Value) +bool cLuaState::GetStackValue(int a_StackPos, AStringMap & a_Value) +{ + // Retrieve all values in a string => string dictionary table: + if (!lua_istable(m_LuaState, a_StackPos)) + { + return false; + } + cStackTable tbl(*this, a_StackPos); + bool isValid = true; + tbl.ForEachElement([&isValid, &a_Value](cLuaState & a_LuaState) + { + AString key, val; + if (a_LuaState.GetStackValues(-2, key, val)) + { + a_Value[key] = val; + } + else + { + isValid = false; + return true; + } + return false; + } + ); + return isValid; +} + + + + + bool cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) { a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0); diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 60ae840b0..303a59327 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -309,6 +309,24 @@ public: typedef UniquePtr<cTableRef> cTableRefPtr; + /** Represents a parameter that is optional - calling a GetStackValue() with this object will not fail if the value on the Lua stack is nil. + Note that the GetStackValue() will still fail if the param is present but of a different type. + The class itself is just a marker so that the template magic will select the correct GetStackValue() overload. */ + template <typename T> + class cOptionalParam + { + public: + explicit cOptionalParam(T & a_Dest): + m_Dest(a_Dest) + { + } + + T & GetDest(void) { return m_Dest; } + + protected: + T & m_Dest; + }; + /** A dummy class that's used only to delimit function args from return values for cLuaState::Call() */ class cRet { @@ -475,6 +493,7 @@ public: // Push a const value onto the stack (keep alpha-sorted): void Push(const AString & a_String); + void Push(const AStringMap & a_Dictionary); void Push(const AStringVector & a_Vector); void Push(const cCraftingGrid * a_Grid); void Push(const cCraftingRecipe * a_Recipe); @@ -508,6 +527,7 @@ public: // Returns whether value was changed // Enum values are checked for their allowed values and fail if the value is not assigned. bool GetStackValue(int a_StackPos, AString & a_Value); + bool GetStackValue(int a_StackPos, AStringMap & a_Value); bool GetStackValue(int a_StackPos, bool & a_Value); bool GetStackValue(int a_StackPos, cCallback & a_Callback); bool GetStackValue(int a_StackPos, cCallbackPtr & a_Callback); @@ -549,6 +569,17 @@ public: return true; } + /** Retrieves an optional value on the stack - doesn't fail if the stack contains nil instead of the value. */ + template <typename T> + bool GetStackValue(int a_StackPos, cOptionalParam<T> && a_ReturnedVal) + { + if (lua_isnoneornil(m_LuaState, a_StackPos)) + { + return true; + } + return GetStackValue(a_StackPos, a_ReturnedVal.GetDest()); + } + /** Pushes the named value in the table at the top of the stack. a_Name may be a path containing multiple table levels, such as "cChatColor.Blue". If the value is found, it is pushed on top of the stack and the returned cStackValue is valid. @@ -606,14 +637,14 @@ public: } /** Retrieves a list of values from the Lua stack, starting at the specified index. */ - template <typename T, typename... Args> - inline bool GetStackValues(int a_StartStackPos, T & a_Ret, Args &&... args) + template <typename Arg1, typename... Args> + inline bool GetStackValues(int a_StartStackPos, Arg1 && a_Arg1, Args &&... args) { - if (!GetStackValue(a_StartStackPos, a_Ret)) + if (!GetStackValue(a_StartStackPos, std::forward<Arg1>(a_Arg1))) { return false; } - return GetStackValues(a_StartStackPos + 1, args...); + return GetStackValues(a_StartStackPos + 1, std::forward<Args>(args)...); } /** Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions */ |