AlexVinS 4 роки тому
батько
коміт
ec6f7b88fe

+ 1 - 0
lib/VCMI_lib.cbp

@@ -182,6 +182,7 @@
 		<Unit filename="../scripts/lib/erm/MA.lua" />
 		<Unit filename="../scripts/lib/erm/MF.lua" />
 		<Unit filename="../scripts/lib/erm/MF_T.lua" />
+		<Unit filename="../scripts/lib/erm/OB_T.lua" />
 		<Unit filename="../scripts/lib/erm/OW.lua" />
 		<Unit filename="../scripts/lib/erm/PI_T.lua" />
 		<Unit filename="../scripts/lib/erm/ReceiverBase.lua" />

+ 85 - 9
scripting/lua/LuaStack.h

@@ -211,16 +211,38 @@ public:
 	bool tryGet(int position, double & value);
 	bool tryGet(int position, std::string & value);
 
-	template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value, int>::type = 0>
-	bool tryGet(int position, T * & value)
+	template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value && std::is_const<T>::value, int>::type = 0>
+	STRONG_INLINE bool tryGet(int position, T * & value)
 	{
-		return tryGetUData(position, value);
+		using NCValue = typename std::remove_const<T>::type;
+
+		using UData = NCValue *;
+		using CUData = T *;
+
+		return tryGetCUData<T *, UData, CUData>(position, value);
 	}
 
-	template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value, int>::type = 0>
-	bool tryGet(int position, std::shared_ptr<T> & value)
+	template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value && !std::is_const<T>::value, int>::type = 0>
+	STRONG_INLINE bool tryGet(int position, T * & value)
+	{
+		return tryGetUData<T *>(position, value);
+	}
+
+	template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value && std::is_const<T>::value, int>::type = 0>
+	STRONG_INLINE bool tryGet(int position, std::shared_ptr<T> & value)
+	{
+		using NCValue = typename std::remove_const<T>::type;
+
+		using UData = std::shared_ptr<NCValue>;
+		using CUData = std::shared_ptr<T>;
+
+		return tryGetCUData<std::shared_ptr<T>, UData, CUData>(position, value);
+	}
+
+	template<typename T, typename std::enable_if<detail::IsRegularClass<T>::value && !std::is_const<T>::value, int>::type = 0>
+	STRONG_INLINE bool tryGet(int position, std::shared_ptr<T> & value)
 	{
-		return tryGetUData(position, value);
+		return tryGetUData<std::shared_ptr<T>>(position, value);
 	}
 
 	template<typename U>
@@ -228,13 +250,67 @@ public:
 	{
 		static auto KEY = api::TypeRegistry::get()->getKey<U>();
 
-		void * raw = luaL_checkudata(L, position, KEY);
+		void * raw = lua_touserdata(L, position);
 
 		if(!raw)
 			return false;
 
-		value = *(static_cast<U *>(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<U *>(raw));
+			lua_pop(L, 2);
+			return true;
+		}
+
+		lua_pop(L, 2);
+		return false;
+	}
+
+	template<typename T, typename U, typename CU>
+	bool tryGetCUData(int position, T & value)
+	{
+		static auto KEY = api::TypeRegistry::get()->getKey<U>();
+		static auto C_KEY = api::TypeRegistry::get()->getKey<CU>();
+
+		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<U *>(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<CU *>(raw));
+			lua_pop(L, 2);
+			return true;
+		}
+
+		lua_pop(L, 2);
+		return false;
 	}
 
 	bool tryGet(int position, JsonNode & value);

+ 9 - 1
scripting/lua/LuaWrapper.h

@@ -161,13 +161,16 @@ class OpaqueWrapper : public RegistarBase
 {
 public:
 	using ObjectType = typename std::remove_cv<T>::type;
-	using UDataType = T *;
+	using UDataType = ObjectType *;
+	using CUDataType = const ObjectType *;
+
 	using RegType = detail::RegType<UDataType>;
 	using CustomRegType = detail::CustomRegType;
 
 	void pushMetatable(lua_State * L) const override final
 	{
 		static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
+		static auto S_KEY = api::TypeRegistry::get()->getKey<CUDataType>();
 
 		LuaStack S(L);
 
@@ -176,6 +179,11 @@ public:
 
 		S.balance();
 
+		if(luaL_newmetatable(L, S_KEY) != 0)
+			adjustMetatable(L);
+
+		S.balance();
+
 		detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);
 
 		adjustStaticTable(L);

+ 0 - 2
scripting/lua/api/Creature.cpp

@@ -26,8 +26,6 @@ VCMI_REGISTER_CORE_SCRIPT_API(CreatureProxy, "Creature");
 
 const std::vector<CreatureProxy::RegType> CreatureProxy::REGISTER =
 {
-	{"accessBonuses", LuaCallWrapper<const EntityWithBonuses<CreatureID>>::createFunctor(&EntityWithBonuses<CreatureID>::accessBonuses)},
-
 	{"getCost", LuaCallWrapper<const Creature>::createFunctor(&Creature::getCost)},
 	{"isDoubleWide", LuaCallWrapper<const Creature>::createFunctor(&Creature::isDoubleWide)},
 };

+ 2 - 2
scripting/lua/api/ObjectInstance.h

@@ -21,10 +21,10 @@ namespace scripting
 namespace api
 {
 
-class ObjectInstanceProxy : public OpaqueWrapper<const IObjectInterface, ObjectInstanceProxy>
+class ObjectInstanceProxy : public OpaqueWrapper<const CGObjectInstance, ObjectInstanceProxy>
 {
 public:
-	using Wrapper = OpaqueWrapper<const IObjectInterface, ObjectInstanceProxy>;
+	using Wrapper = OpaqueWrapper<const CGObjectInstance, ObjectInstanceProxy>;
 	static const std::vector<typename Wrapper::RegType> REGISTER;
 	static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
 };

+ 15 - 0
scripting/lua/api/events/AdventureEvents.cpp

@@ -39,6 +39,21 @@ const std::vector<ObjectVisitStartedProxy::CustomRegType> ObjectVisitStartedProx
 		&SubscriptionRegistryProxy<ObjectVisitStartedProxy>::subscribeAfter,
 		true
 	},
+	{
+		"getPlayer",
+		LuaMethodWrapper<ObjectVisitStarted, PlayerColor(ObjectVisitStarted:: *)()const, &ObjectVisitStarted::getPlayer>::invoke,
+		false
+	},
+	{
+		"getHero",
+		LuaMethodWrapper<ObjectVisitStarted, ObjectInstanceID(ObjectVisitStarted:: *)()const, &ObjectVisitStarted::getHero>::invoke,
+		false
+	},
+	{
+		"getObject",
+		LuaMethodWrapper<ObjectVisitStarted, ObjectInstanceID(ObjectVisitStarted:: *)()const, &ObjectVisitStarted::getObject>::invoke,
+		false
+	},
 };
 
 }

+ 1 - 1
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 = {}
 

+ 1 - 1
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

+ 27 - 0
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

+ 6 - 3
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();
 }
 
 }