diff --git a/lib/VCMI_lib.cbp b/lib/VCMI_lib.cbp index 98bf37af0..97d17da8d 100644 --- a/lib/VCMI_lib.cbp +++ b/lib/VCMI_lib.cbp @@ -182,6 +182,7 @@ + diff --git a/scripting/lua/LuaStack.h b/scripting/lua/LuaStack.h index e3b721537..e2c63ccf2 100644 --- a/scripting/lua/LuaStack.h +++ b/scripting/lua/LuaStack.h @@ -211,16 +211,38 @@ public: bool tryGet(int position, double & value); bool tryGet(int position, std::string & value); - template::value, int>::type = 0> - bool tryGet(int position, T * & value) + template::value && std::is_const::value, int>::type = 0> + STRONG_INLINE bool tryGet(int position, T * & value) { - return tryGetUData(position, value); + using NCValue = typename std::remove_const::type; + + using UData = NCValue *; + using CUData = T *; + + return tryGetCUData(position, value); } - template::value, int>::type = 0> - bool tryGet(int position, std::shared_ptr & value) + template::value && !std::is_const::value, int>::type = 0> + STRONG_INLINE bool tryGet(int position, T * & value) { - return tryGetUData(position, value); + return tryGetUData(position, value); + } + + template::value && std::is_const::value, int>::type = 0> + STRONG_INLINE bool tryGet(int position, std::shared_ptr & value) + { + using NCValue = typename std::remove_const::type; + + using UData = std::shared_ptr; + using CUData = std::shared_ptr; + + return tryGetCUData, UData, CUData>(position, value); + } + + template::value && !std::is_const::value, int>::type = 0> + STRONG_INLINE bool tryGet(int position, std::shared_ptr & value) + { + return tryGetUData>(position, value); } template @@ -228,13 +250,67 @@ public: { static auto KEY = api::TypeRegistry::get()->getKey(); - void * raw = luaL_checkudata(L, position, KEY); + void * raw = lua_touserdata(L, position); if(!raw) return false; - value = *(static_cast(raw)); - return true; + if(lua_getmetatable(L, position) == 0) + return false; + + lua_getfield(L, LUA_REGISTRYINDEX, KEY); + + if(lua_rawequal(L, -1, -2) == 1) + { + value = *(static_cast(raw)); + lua_pop(L, 2); + return true; + } + + lua_pop(L, 2); + return false; + } + + template + bool tryGetCUData(int position, T & value) + { + static auto KEY = api::TypeRegistry::get()->getKey(); + static auto C_KEY = api::TypeRegistry::get()->getKey(); + + void * raw = lua_touserdata(L, position); + + if(!raw) + return false; + + if(lua_getmetatable(L, position) == 0) + return false; + + //top is metatable + + lua_getfield(L, LUA_REGISTRYINDEX, KEY); + + if(lua_rawequal(L, -1, -2) == 1) + { + value = *(static_cast(raw)); + lua_pop(L, 2); + return true; + } + + lua_pop(L, 1); + + //top is metatable + + lua_getfield(L, LUA_REGISTRYINDEX, C_KEY); + + if(lua_rawequal(L, -1, -2) == 1) + { + value = *(static_cast(raw)); + lua_pop(L, 2); + return true; + } + + lua_pop(L, 2); + return false; } bool tryGet(int position, JsonNode & value); diff --git a/scripting/lua/LuaWrapper.h b/scripting/lua/LuaWrapper.h index aa4794bff..f809d21ea 100644 --- a/scripting/lua/LuaWrapper.h +++ b/scripting/lua/LuaWrapper.h @@ -161,13 +161,16 @@ class OpaqueWrapper : public RegistarBase { public: using ObjectType = typename std::remove_cv::type; - using UDataType = T *; + using UDataType = ObjectType *; + using CUDataType = const ObjectType *; + using RegType = detail::RegType; using CustomRegType = detail::CustomRegType; void pushMetatable(lua_State * L) const override final { static auto KEY = api::TypeRegistry::get()->getKey(); + static auto S_KEY = api::TypeRegistry::get()->getKey(); LuaStack S(L); @@ -176,6 +179,11 @@ public: S.balance(); + if(luaL_newmetatable(L, S_KEY) != 0) + adjustMetatable(L); + + S.balance(); + detail::Dispatcher::pushStaticTable(L); adjustStaticTable(L); diff --git a/scripting/lua/api/Creature.cpp b/scripting/lua/api/Creature.cpp index bc6f0a971..6adc4e4fb 100644 --- a/scripting/lua/api/Creature.cpp +++ b/scripting/lua/api/Creature.cpp @@ -26,8 +26,6 @@ VCMI_REGISTER_CORE_SCRIPT_API(CreatureProxy, "Creature"); const std::vector CreatureProxy::REGISTER = { - {"accessBonuses", LuaCallWrapper>::createFunctor(&EntityWithBonuses::accessBonuses)}, - {"getCost", LuaCallWrapper::createFunctor(&Creature::getCost)}, {"isDoubleWide", LuaCallWrapper::createFunctor(&Creature::isDoubleWide)}, }; diff --git a/scripting/lua/api/ObjectInstance.h b/scripting/lua/api/ObjectInstance.h index 0b6746c25..134f366cd 100644 --- a/scripting/lua/api/ObjectInstance.h +++ b/scripting/lua/api/ObjectInstance.h @@ -21,10 +21,10 @@ namespace scripting namespace api { -class ObjectInstanceProxy : public OpaqueWrapper +class ObjectInstanceProxy : public OpaqueWrapper { public: - using Wrapper = OpaqueWrapper; + using Wrapper = OpaqueWrapper; static const std::vector REGISTER; static const std::vector REGISTER_CUSTOM; }; diff --git a/scripting/lua/api/events/AdventureEvents.cpp b/scripting/lua/api/events/AdventureEvents.cpp index bd86596bb..f6d36bf00 100644 --- a/scripting/lua/api/events/AdventureEvents.cpp +++ b/scripting/lua/api/events/AdventureEvents.cpp @@ -39,6 +39,21 @@ const std::vector ObjectVisitStartedProx &SubscriptionRegistryProxy::subscribeAfter, true }, + { + "getPlayer", + LuaMethodWrapper::invoke, + false + }, + { + "getHero", + LuaMethodWrapper::invoke, + false + }, + { + "getObject", + LuaMethodWrapper::invoke, + false + }, }; } diff --git a/scripts/lib/erm.lua b/scripts/lib/erm.lua index aa7140a1e..a09eb0777 100644 --- a/scripts/lib/erm.lua +++ b/scripts/lib/erm.lua @@ -200,7 +200,7 @@ end !?TL client only? depends on time limit feature ]] -local supportedTriggers = {"PI", "FU", "GM", "MF", "TM"} +local supportedTriggers = {"PI", "FU", "GM", "MF", "OB", "TM"} local TriggerLoaders = {} diff --git a/scripts/lib/erm/MF_T.lua b/scripts/lib/erm/MF_T.lua index 4f3fd343e..b427ea366 100644 --- a/scripts/lib/erm/MF_T.lua +++ b/scripts/lib/erm/MF_T.lua @@ -6,7 +6,7 @@ local trigger = TriggerBase:new() function trigger:new(o) o = TriggerBase.new(self, o) - o.sub = ApplyDamage.subscribeBefore(EVENT_BUS, function(event) + o.sub = ApplyDamage.subscribeBefore(eventBus, function(event) o:call(event) end) return o diff --git a/scripts/lib/erm/OB_T.lua b/scripts/lib/erm/OB_T.lua new file mode 100644 index 000000000..df4c01659 --- /dev/null +++ b/scripts/lib/erm/OB_T.lua @@ -0,0 +1,27 @@ +local TriggerBase = require("core:erm.TriggerBase") +local ObjectVisitStarted = require("events.ObjectVisitStarted") +local eventBus = EVENT_BUS +local game = GAME + +local trigger = TriggerBase:new() + +function trigger:new(o) + o = TriggerBase.new(self, o) + + local id1 = tonumber(o.id[1]) + + o.sub = ObjectVisitStarted.subscribeBefore(eventBus, + function(event) + local objIndex = event:getObject() + + local obj = game:getObj(objIndex, false) + + if obj:getObjGroupIndex() == id1 then + o:call(event) + end + end) + + return o +end + +return trigger diff --git a/test/erm/ERM_OB_T.cpp b/test/erm/ERM_OB_T.cpp index 05f52b826..f8767f667 100644 --- a/test/erm/ERM_OB_T.cpp +++ b/test/erm/ERM_OB_T.cpp @@ -42,23 +42,26 @@ protected: TEST_F(ERM_OB_T, ByTypeIndex) { - EXPECT_CALL(infoMock, getObj(Eq(ObjectInstanceID(234)), _)).WillRepeatedly(Return(&objectMock)); - EXPECT_CALL(objectMock, getObjGroupIndex()).WillRepeatedly(Return(420)); + EXPECT_CALL(infoMock, getObj(Eq(ObjectInstanceID(234)), _)).Times(AtLeast(1)).WillRepeatedly(Return(&objectMock)); + EXPECT_CALL(objectMock, getObjGroupIndex()).Times(AtLeast(1)).WillRepeatedly(Return(420)); loadScript(VLC->scriptHandler->erm, "VERM\n" "!?OB420;\n" "!!VRv42:S4;\n" + "!?OB421;\n" + "!!VRv43:S5;\n" ); SCOPED_TRACE("\n" + subject->code); runClientServer(); - events::ObjectVisitStarted::defaultExecute(&eventBus, nullptr, PlayerColor(2), ObjectInstanceID(234), ObjectInstanceID(235)); + events::ObjectVisitStarted::defaultExecute(&eventBus, nullptr, PlayerColor(2), ObjectInstanceID(235), ObjectInstanceID(234)); const JsonNode actualState = context->saveState(); EXPECT_EQ(actualState["ERM"]["v"]["42"], JsonUtils::floatNode(4)) << actualState.toJson(); + EXPECT_TRUE(actualState["ERM"]["v"]["43"].isNull()) << actualState.toJson(); } }