<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp

#include <NDK/Systems/PhysicsSystem2D.hpp>
#include <Nazara/Physics2D/RigidBody2D.hpp>
#include <NDK/World.hpp>
#include <NDK/Components/CollisionComponent2D.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Components/PhysicsComponent2D.hpp>
#include <NDK/Components/PhysicsComponent3D.hpp>

namespace Ndk
{
	/*!
	* \ingroup NDK
	* \class Ndk::PhysicsSystem2D
	* \brief NDK class that represents a two-dimensional physics system
	*
	* \remark This system is enabled if the entity has the trait: NodeComponent and any of these two: CollisionComponent3D or PhysicsComponent3D
	* \remark Static objects do not have a velocity specified by the physical engine
	*/

	/*!
	* \brief Constructs an PhysicsSystem object by default
	*/

	PhysicsSystem2D::PhysicsSystem2D()
	{
		Requires<NodeComponent>();
		RequiresAny<CollisionComponent2D, PhysicsComponent2D>();
		Excludes<PhysicsComponent3D>();
	}

	void PhysicsSystem2D::CreatePhysWorld() const
	{
		NazaraAssert(!m_physWorld, "Physics world should not be created twice");

		m_physWorld = std::make_unique<Nz::PhysWorld2D>();
	}

	void PhysicsSystem2D::DebugDraw(const DebugDrawOptions& options, bool drawShapes, bool drawConstraints, bool drawCollisions)
	{
		Nz::PhysWorld2D::DebugDrawOptions worldOptions{ options.constraintColor, options.collisionPointColor, options.shapeOutlineColor };

		if (options.colorCallback)
		{
			worldOptions.colorCallback = [&options, this](Nz::RigidBody2D& body, std::size_t shapeIndex, void* userdata)
			{
				return options.colorCallback(GetEntityFromBody(body), shapeIndex, userdata);
			};
		}

		worldOptions.circleCallback = options.circleCallback;
		worldOptions.dotCallback = options.dotCallback;
		worldOptions.polygonCallback = options.polygonCallback;
		worldOptions.segmentCallback = options.segmentCallback;
		worldOptions.thickSegmentCallback = options.thickSegmentCallback;

		worldOptions.userdata = options.userdata;

		GetPhysWorld().DebugDraw(worldOptions, drawShapes, drawConstraints, drawCollisions);
	}

	const EntityHandle& PhysicsSystem2D::GetEntityFromBody(const Nz::RigidBody2D& body) const
	{
		auto entityId = static_cast<EntityId>(reinterpret_cast<std::uintptr_t>(body.GetUserdata()));

		auto& world = GetWorld();

		NazaraAssert(world.IsEntityIdValid(entityId), "All Bodies of this world must be part of the physics world by using PhysicsComponent");

		return world.GetEntity(entityId);
	}

	bool PhysicsSystem2D::NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, EntityHandle* nearestBody)
	{
		Nz::RigidBody2D* body;
		bool res = GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &body);

		(*nearestBody) = GetEntityFromBody(*body);

		return res;
	}

	bool PhysicsSystem2D::NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result)
	{
		Nz::PhysWorld2D::NearestQueryResult queryResult;
		bool res = GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &queryResult);

		result->nearestBody = GetEntityFromBody(*queryResult.nearestBody);
		result->closestPoint = std::move(queryResult.closestPoint);
		result->fraction = std::move(queryResult.fraction);
		result->distance = queryResult.distance;

		return res;
	}

	bool PhysicsSystem2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<RaycastHit>* hitInfos)
	{
		std::vector<Nz::PhysWorld2D::RaycastHit> queryResult;
		bool res = GetPhysWorld().RaycastQuery(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult);

		for (auto& hitResult : queryResult)
		{
			hitInfos->push_back({
				GetEntityFromBody(*hitResult.nearestBody),
				std::move(hitResult.hitPos),
				std::move(hitResult.hitNormal),
				hitResult.fraction
				});
		}

		return res;
	}

	bool PhysicsSystem2D::RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo)
	{
		Nz::PhysWorld2D::RaycastHit queryResult;
		bool res = GetPhysWorld().RaycastQueryFirst(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult);

		hitInfo->body = GetEntityFromBody(*queryResult.nearestBody);
		hitInfo->hitPos = std::move(queryResult.hitPos);
		hitInfo->hitNormal = std::move(queryResult.hitNormal);
		hitInfo->fraction = queryResult.fraction;

		return res;
	}

	void PhysicsSystem2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<EntityHandle>* bodies)
	{
		std::vector<Nz::RigidBody2D*> queryResult;
		GetPhysWorld().RegionQuery(boundingBox, collisionGroup, categoryMask, collisionMask, &queryResult);

		for (auto& body : queryResult)
		{
			bodies->emplace_back(GetEntityFromBody(*body));
		}
	}

	/*!
	* \brief Operation to perform when entity is validated for the system
	*
	* \param entity Pointer to the entity
	* \param justAdded Is the entity newly added
	*/

	void PhysicsSystem2D::OnEntityValidation(Entity* entity, bool justAdded)
	{
		if (entity->HasComponent<PhysicsComponent2D>())
		{
			if (entity->GetComponent<PhysicsComponent2D>().IsNodeSynchronizationEnabled())
				m_dynamicObjects.Insert(entity);
			else
				m_dynamicObjects.Remove(entity);

			m_staticObjects.Remove(entity);
		}
		else
		{
			m_dynamicObjects.Remove(entity);
			m_staticObjects.Insert(entity);

		}

		if (!m_physWorld)
			CreatePhysWorld();
	}

	/*!
	* \brief Operation to perform when system is updated
	*
	* \param elapsedTime Delta time used for the update
	*/

	void PhysicsSystem2D::OnUpdate(float elapsedTime)
	{
		if (!m_physWorld)
			return;

		m_physWorld->Step(elapsedTime);

		for (const Ndk::EntityHandle& entity : m_dynamicObjects)
		{
			NodeComponent& node = entity->GetComponent<NodeComponent>();
			PhysicsComponent2D& phys = entity->GetComponent<PhysicsComponent2D>();

			Nz::RigidBody2D* body = phys.GetRigidBody();
			node.SetRotation(body->GetRotation(), Nz::CoordSys_Global);
			node.SetPosition(Nz::Vector3f(body->GetPosition(), node.GetPosition(Nz::CoordSys_Global).z), Nz::CoordSys_Global);
		}

		float invElapsedTime = 1.f / elapsedTime;
		for (const Ndk::EntityHandle& entity : m_staticObjects)
		{
			CollisionComponent2D& collision = entity->GetComponent<CollisionComponent2D>();
			NodeComponent& node = entity->GetComponent<NodeComponent>();

			Nz::RigidBody2D* body = collision.GetStaticBody();

			Nz::Vector2f oldPosition = body->GetPosition();
			Nz::Vector2f newPosition = Nz::Vector2f(node.GetPosition(Nz::CoordSys_Global));

			// To move static objects and ensure their collisions, we have to specify them a velocity
			// (/!\: the physical motor does not apply the speed on static objects)
			if (newPosition != oldPosition)
			{
				body->SetPosition(newPosition);
				body->SetVelocity((newPosition - oldPosition) * invElapsedTime);
			}
			else
				body->SetVelocity(Nz::Vector2f::Zero());

/*
			if (newRotation != oldRotation)
			{
				Nz::Quaternionf transition = newRotation * oldRotation.GetConjugate();
				Nz::EulerAnglesf angles = transition.ToEulerAngles();
				Nz::Vector3f angularVelocity(Nz::ToRadians(angles.pitch * invElapsedTime),
				                             Nz::ToRadians(angles.yaw * invElapsedTime),
				                             Nz::ToRadians(angles.roll * invElapsedTime));

				physObj->SetRotation(oldRotation);
				physObj->SetAngularVelocity(angularVelocity);
			}
			else
				physObj->SetAngularVelocity(Nz::Vector3f::Zero());
*/
		}
	}

	void PhysicsSystem2D::RegisterCallbacks(unsigned int collisionId, Callback callbacks)
	{
		Nz::PhysWorld2D::Callback worldCallbacks;

		if (callbacks.endCallback)
		{
			worldCallbacks.endCallback = [this, cb = std::move(callbacks.endCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.preSolveCallback)
		{
			worldCallbacks.preSolveCallback = [this, cb = std::move(callbacks.preSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.postSolveCallback)
		{
			worldCallbacks.postSolveCallback = [this, cb = std::move(callbacks.postSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.startCallback)
		{
			worldCallbacks.startCallback = [this, cb = std::move(callbacks.startCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		worldCallbacks.userdata = callbacks.userdata;

		m_physWorld->RegisterCallbacks(collisionId, worldCallbacks);
	}

	void PhysicsSystem2D::RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, Callback callbacks)
	{
		Nz::PhysWorld2D::Callback worldCallbacks{};

		if (callbacks.endCallback)
		{
			worldCallbacks.endCallback = [this, cb = std::move(callbacks.endCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.preSolveCallback)
		{
			worldCallbacks.preSolveCallback = [this, cb = std::move(callbacks.preSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.postSolveCallback)
		{
			worldCallbacks.postSolveCallback = [this, cb = std::move(callbacks.postSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.startCallback)
		{
			worldCallbacks.startCallback = [this, cb = std::move(callbacks.startCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		worldCallbacks.userdata = callbacks.userdata;

		m_physWorld->RegisterCallbacks(collisionIdA, collisionIdB, worldCallbacks);
	}

	SystemIndex PhysicsSystem2D::systemIndex;
}
<commit_msg>SDK/PhysicsSystem2D: Fix initial position/rotation<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp

#include <NDK/Systems/PhysicsSystem2D.hpp>
#include <Nazara/Physics2D/RigidBody2D.hpp>
#include <NDK/World.hpp>
#include <NDK/Components/CollisionComponent2D.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Components/PhysicsComponent2D.hpp>
#include <NDK/Components/PhysicsComponent3D.hpp>

namespace Ndk
{
	/*!
	* \ingroup NDK
	* \class Ndk::PhysicsSystem2D
	* \brief NDK class that represents a two-dimensional physics system
	*
	* \remark This system is enabled if the entity has the trait: NodeComponent and any of these two: CollisionComponent3D or PhysicsComponent3D
	* \remark Static objects do not have a velocity specified by the physical engine
	*/

	/*!
	* \brief Constructs an PhysicsSystem object by default
	*/

	PhysicsSystem2D::PhysicsSystem2D()
	{
		Requires<NodeComponent>();
		RequiresAny<CollisionComponent2D, PhysicsComponent2D>();
		Excludes<PhysicsComponent3D>();
	}

	void PhysicsSystem2D::CreatePhysWorld() const
	{
		NazaraAssert(!m_physWorld, "Physics world should not be created twice");

		m_physWorld = std::make_unique<Nz::PhysWorld2D>();
	}

	void PhysicsSystem2D::DebugDraw(const DebugDrawOptions& options, bool drawShapes, bool drawConstraints, bool drawCollisions)
	{
		Nz::PhysWorld2D::DebugDrawOptions worldOptions{ options.constraintColor, options.collisionPointColor, options.shapeOutlineColor };

		if (options.colorCallback)
		{
			worldOptions.colorCallback = [&options, this](Nz::RigidBody2D& body, std::size_t shapeIndex, void* userdata)
			{
				return options.colorCallback(GetEntityFromBody(body), shapeIndex, userdata);
			};
		}

		worldOptions.circleCallback = options.circleCallback;
		worldOptions.dotCallback = options.dotCallback;
		worldOptions.polygonCallback = options.polygonCallback;
		worldOptions.segmentCallback = options.segmentCallback;
		worldOptions.thickSegmentCallback = options.thickSegmentCallback;

		worldOptions.userdata = options.userdata;

		GetPhysWorld().DebugDraw(worldOptions, drawShapes, drawConstraints, drawCollisions);
	}

	const EntityHandle& PhysicsSystem2D::GetEntityFromBody(const Nz::RigidBody2D& body) const
	{
		auto entityId = static_cast<EntityId>(reinterpret_cast<std::uintptr_t>(body.GetUserdata()));

		auto& world = GetWorld();

		NazaraAssert(world.IsEntityIdValid(entityId), "All Bodies of this world must be part of the physics world by using PhysicsComponent");

		return world.GetEntity(entityId);
	}

	bool PhysicsSystem2D::NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, EntityHandle* nearestBody)
	{
		Nz::RigidBody2D* body;
		bool res = GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &body);

		(*nearestBody) = GetEntityFromBody(*body);

		return res;
	}

	bool PhysicsSystem2D::NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result)
	{
		Nz::PhysWorld2D::NearestQueryResult queryResult;
		bool res = GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &queryResult);

		result->nearestBody = GetEntityFromBody(*queryResult.nearestBody);
		result->closestPoint = std::move(queryResult.closestPoint);
		result->fraction = std::move(queryResult.fraction);
		result->distance = queryResult.distance;

		return res;
	}

	bool PhysicsSystem2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<RaycastHit>* hitInfos)
	{
		std::vector<Nz::PhysWorld2D::RaycastHit> queryResult;
		bool res = GetPhysWorld().RaycastQuery(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult);

		for (auto& hitResult : queryResult)
		{
			hitInfos->push_back({
				GetEntityFromBody(*hitResult.nearestBody),
				std::move(hitResult.hitPos),
				std::move(hitResult.hitNormal),
				hitResult.fraction
				});
		}

		return res;
	}

	bool PhysicsSystem2D::RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo)
	{
		Nz::PhysWorld2D::RaycastHit queryResult;
		bool res = GetPhysWorld().RaycastQueryFirst(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult);

		hitInfo->body = GetEntityFromBody(*queryResult.nearestBody);
		hitInfo->hitPos = std::move(queryResult.hitPos);
		hitInfo->hitNormal = std::move(queryResult.hitNormal);
		hitInfo->fraction = queryResult.fraction;

		return res;
	}

	void PhysicsSystem2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<EntityHandle>* bodies)
	{
		std::vector<Nz::RigidBody2D*> queryResult;
		GetPhysWorld().RegionQuery(boundingBox, collisionGroup, categoryMask, collisionMask, &queryResult);

		for (auto& body : queryResult)
		{
			bodies->emplace_back(GetEntityFromBody(*body));
		}
	}

	/*!
	* \brief Operation to perform when entity is validated for the system
	*
	* \param entity Pointer to the entity
	* \param justAdded Is the entity newly added
	*/

	void PhysicsSystem2D::OnEntityValidation(Entity* entity, bool justAdded)
	{
		if (entity->HasComponent<PhysicsComponent2D>())
		{
			if (entity->GetComponent<PhysicsComponent2D>().IsNodeSynchronizationEnabled())
				m_dynamicObjects.Insert(entity);
			else
				m_dynamicObjects.Remove(entity);

			m_staticObjects.Remove(entity);
		}
		else
		{
			m_dynamicObjects.Remove(entity);
			m_staticObjects.Insert(entity);

			// If entities just got added to the system, teleport them to their NodeComponent position/rotation
			// This will prevent the physics engine to mess with the scene while correcting position/rotation
			if (justAdded)
			{
				auto& collision = entity->GetComponent<CollisionComponent2D>();
				auto& node = entity->GetComponent<NodeComponent>();

				Nz::RigidBody2D* physObj = collision.GetStaticBody();
				physObj->SetPosition(Nz::Vector2f(node.GetPosition()));
				//physObj->SetRotation(node.GetRotation());
			}
		}

		if (!m_physWorld)
			CreatePhysWorld();
	}

	/*!
	* \brief Operation to perform when system is updated
	*
	* \param elapsedTime Delta time used for the update
	*/

	void PhysicsSystem2D::OnUpdate(float elapsedTime)
	{
		if (!m_physWorld)
			return;

		m_physWorld->Step(elapsedTime);

		for (const Ndk::EntityHandle& entity : m_dynamicObjects)
		{
			NodeComponent& node = entity->GetComponent<NodeComponent>();
			PhysicsComponent2D& phys = entity->GetComponent<PhysicsComponent2D>();

			Nz::RigidBody2D* body = phys.GetRigidBody();
			node.SetRotation(body->GetRotation(), Nz::CoordSys_Global);
			node.SetPosition(Nz::Vector3f(body->GetPosition(), node.GetPosition(Nz::CoordSys_Global).z), Nz::CoordSys_Global);
		}

		float invElapsedTime = 1.f / elapsedTime;
		for (const Ndk::EntityHandle& entity : m_staticObjects)
		{
			CollisionComponent2D& collision = entity->GetComponent<CollisionComponent2D>();
			NodeComponent& node = entity->GetComponent<NodeComponent>();

			Nz::RigidBody2D* body = collision.GetStaticBody();

			Nz::Vector2f oldPosition = body->GetPosition();
			Nz::Vector2f newPosition = Nz::Vector2f(node.GetPosition(Nz::CoordSys_Global));

			// To move static objects and ensure their collisions, we have to specify them a velocity
			// (/!\: the physical motor does not apply the speed on static objects)
			if (newPosition != oldPosition)
			{
				body->SetPosition(newPosition);
				body->SetVelocity((newPosition - oldPosition) * invElapsedTime);
			}
			else
				body->SetVelocity(Nz::Vector2f::Zero());

/*
			if (newRotation != oldRotation)
			{
				Nz::Quaternionf transition = newRotation * oldRotation.GetConjugate();
				Nz::EulerAnglesf angles = transition.ToEulerAngles();
				Nz::Vector3f angularVelocity(Nz::ToRadians(angles.pitch * invElapsedTime),
				                             Nz::ToRadians(angles.yaw * invElapsedTime),
				                             Nz::ToRadians(angles.roll * invElapsedTime));

				physObj->SetRotation(oldRotation);
				physObj->SetAngularVelocity(angularVelocity);
			}
			else
				physObj->SetAngularVelocity(Nz::Vector3f::Zero());
*/
		}
	}

	void PhysicsSystem2D::RegisterCallbacks(unsigned int collisionId, Callback callbacks)
	{
		Nz::PhysWorld2D::Callback worldCallbacks;

		if (callbacks.endCallback)
		{
			worldCallbacks.endCallback = [this, cb = std::move(callbacks.endCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.preSolveCallback)
		{
			worldCallbacks.preSolveCallback = [this, cb = std::move(callbacks.preSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.postSolveCallback)
		{
			worldCallbacks.postSolveCallback = [this, cb = std::move(callbacks.postSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.startCallback)
		{
			worldCallbacks.startCallback = [this, cb = std::move(callbacks.startCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		worldCallbacks.userdata = callbacks.userdata;

		m_physWorld->RegisterCallbacks(collisionId, worldCallbacks);
	}

	void PhysicsSystem2D::RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, Callback callbacks)
	{
		Nz::PhysWorld2D::Callback worldCallbacks{};

		if (callbacks.endCallback)
		{
			worldCallbacks.endCallback = [this, cb = std::move(callbacks.endCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.preSolveCallback)
		{
			worldCallbacks.preSolveCallback = [this, cb = std::move(callbacks.preSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.postSolveCallback)
		{
			worldCallbacks.postSolveCallback = [this, cb = std::move(callbacks.postSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		if (callbacks.startCallback)
		{
			worldCallbacks.startCallback = [this, cb = std::move(callbacks.startCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
			{
				return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
			};
		}

		worldCallbacks.userdata = callbacks.userdata;

		m_physWorld->RegisterCallbacks(collisionIdA, collisionIdB, worldCallbacks);
	}

	SystemIndex PhysicsSystem2D::systemIndex;
}
<|endoftext|>


<commit_before>/*
 * Main.cpp
 *
 * Created on: Dec 31, 2014
 * Author: jrparks
 */
#include <opencv2/opencv.hpp>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <stdio.h>
#include "zedin.hpp"

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    ZedIn camera(argc == 2 ? argv[1] : NULL);
    //ZedIn camera(NULL, argc == 2 ? argv[1] : NULL);

    char name[PATH_MAX];
    int  index = 0;
    int  rc;
    struct stat statbuf;
    do
    {
        sprintf(name, "cap%d.avi", index++);
        rc = stat(name, &statbuf);
    } while (rc == 0);
    VideoWriter outputVideo(name, CV_FOURCC('M', 'J', 'P', 'G'), 30, Size(camera.width(), camera.height()), true);
    Mat frame;

    while (true)
    {
        camera.getNextFrame(frame, false);
        if (!frame.empty())
        {
            outputVideo << frame;
        }
        else
        {
            fprintf(stderr, "Unable to grab frame.\n");
            break;
        }
	imshow("Frame", frame);
        uchar wait_key = cv::waitKey(2);
        if ((wait_key == 27) || (wait_key == 32))
        {
            break;
        }
    }
    fprintf(stdout, "Closing camera.\n");
}
<commit_msg>Allow svo->zms conversion<commit_after>/*
 * Main.cpp
 *
 * Created on: Dec 31, 2014
 * Author: jrparks
 */
#include <opencv2/opencv.hpp>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <stdio.h>
#include "zedin.hpp"

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
	ZedIn camera(argc >= 2 ? argv[1] : NULL, argc == 3 ? argv[2] : NULL);
	//ZedIn camera(NULL, argc == 2 ? argv[1] : NULL);

	VideoWriter outputVideo;
	if (argc < 3)
	{
		char name[PATH_MAX];
		int  index = 0;
		int  rc;
		struct stat statbuf;
		do
		{
			sprintf(name, "cap%d.avi", index++);
			rc = stat(name, &statbuf);
		} while (rc == 0);
		outputVideo = VideoWriter(name, CV_FOURCC('M', 'J', 'P', 'G'), 30, Size(camera.width(), camera.height()), true);
	}
	Mat frame;

	while (true)
	{
		camera.getNextFrame(frame, false);
		if (!frame.empty())
		{
			if (argc < 3)
			{
				outputVideo << frame;
			}
		}
		else
		{
			fprintf(stderr, "Unable to grab frame.\n");
			break;
		}
		if (argc < 3)
		{
			imshow("Frame", frame);
			uchar wait_key = cv::waitKey(2);
			if ((wait_key == 27) || (wait_key == 32))
			{
				break;
			}
		}
	}
	fprintf(stdout, "Closing camera.\n");
}
<|endoftext|>


<commit_before>#pragma once
/*
* Covariant Mozart Utility Library: Any
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2016 Michael Lee(李登淳)
* Email: China-LDC@outlook.com
* Github: https://github.com/mikecovlee
* Website: http://ldc.atd3.cn
*
* Version: 17.2.1
*/
#include "./base.hpp"
#include <iostream>

namespace std {
	template<typename T> std::string to_string(const T&)
	{
		throw cov::error("E000D");
	}
	template<> std::string to_string<std::string>(const std::string& str)
	{
		return str;
	}
	template<> std::string to_string<bool>(const bool& v)
	{
		if(v)
			return "True";
		else
			return "False";
	}
}

namespace cov {
	template < typename _Tp > class compare_helper {
		template < typename T,typename X=bool >struct matcher;
		template < typename T > static constexpr bool match(T*)
		{
			return false;
		}
		template < typename T > static constexpr bool match(matcher < T, decltype(std::declval<T>()==std::declval<T>()) > *)
		{
			return true;
		}
	public:
		static constexpr bool value = match < _Tp > (nullptr);
	};
	template<typename,bool> struct compare_if;
	template<typename T>struct compare_if<T,true> {
		static bool compare(const T& a,const T& b)
		{
			return a==b;
		}
	};
	template<typename T>struct compare_if<T,false> {
		static bool compare(const T& a,const T& b)
		{
			return &a==&b;
		}
	};
	template<typename T>bool compare(const T& a,const T& b)
	{
		return compare_if<T,compare_helper<T>::value>::compare(a,b);
	}
	class any final {
		class baseHolder {
		public:
			baseHolder() = default;
			virtual ~ baseHolder() = default;
			virtual const std::type_info & type() const = 0;
			virtual baseHolder *duplicate() = 0;
			virtual bool compare(const baseHolder *) const = 0;
			virtual std::string to_string() const = 0;
		};
		template < typename T > class holder:public baseHolder {
		protected:
			T mDat;
		public:
			holder() = default;
			holder(const T& dat):mDat(dat) {}
			virtual ~ holder() = default;
			virtual const std::type_info & type() const override
			{
				return typeid(T);
			}
			virtual baseHolder *duplicate() override
			{
				return new holder(mDat);
			}
			virtual bool compare(const baseHolder * obj)const override
			{
				if (obj->type() == this->type()) {
					const holder < T > *ptr = dynamic_cast < const holder < T > *>(obj);
					return ptr!=nullptr?cov::compare(mDat,ptr->data()):false;
				}
				return false;
			}
			virtual std::string to_string() const override
			{
				return std::move(std::to_string(mDat));
			}
			T & data()
			{
				return mDat;
			}
			const T & data() const
			{
				return mDat;
			}
			void data(const T & dat)
			{
				mDat = dat;
			}
		};
		using size_t=unsigned long;
		struct proxy {
			mutable size_t refcount=1;
			baseHolder* data=nullptr;
			proxy()=default;
			proxy(size_t rc,baseHolder* d):refcount(rc),data(d) {}
			~proxy()
			{
				delete data;
			}
		};
		proxy* mDat=nullptr;
		proxy* duplicate() const noexcept
		{
			if(mDat!=nullptr) {
				++mDat->refcount;
			}
			return mDat;
		}
		void recycle() noexcept
		{
			if(mDat!=nullptr) {
				--mDat->refcount;
				if(mDat->refcount==0) {
					delete mDat;
					mDat=nullptr;
				}
			}
		}
	public:
		static any infer_value(const std::string&);
		void swap(any& obj) noexcept
		{
			proxy* tmp=this->mDat;
			this->mDat=obj.mDat;
			obj.mDat=tmp;
		}
		void swap(any&& obj) noexcept
		{
			proxy* tmp=this->mDat;
			this->mDat=obj.mDat;
			obj.mDat=tmp;
		}
		void clone() noexcept
		{
			if(mDat!=nullptr) {
				proxy* dat=new proxy(1,mDat->data->duplicate());
				recycle();
				mDat=dat;
			}
		}
		bool usable() const noexcept
		{
			return mDat != nullptr;
		}
		any()=default;
		template < typename T > any(const T & dat):mDat(new proxy(1,new holder < T > (dat))) {}
		any(const any & v):mDat(v.duplicate()) {}
		any(any&& v) noexcept
		{
			swap(std::forward<any>(v));
		}
		~any()
		{
			recycle();
		}
		const std::type_info & type() const
		{
			return this->mDat != nullptr?this->mDat->data->type():typeid(void);
		}
		std::string to_string() const
		{
			if(this->mDat == nullptr)
				return "Null";
			return std::move(this->mDat->data->to_string());
		}
		any & operator=(const any & var)
		{
			if(&var!=this) {
				recycle();
				mDat = var.duplicate();
			}
			return *this;
		}
		any & operator=(any&& var) noexcept
		{
			if(&var!=this)
				swap(std::forward<any>(var));
			return *this;
		}
		bool operator==(const any & var) const
		{
			return usable()?this->mDat->data->compare(var.mDat->data):!var.usable();
		}
		bool operator!=(const any & var)const
		{
			return usable()?!this->mDat->data->compare(var.mDat->data):var.usable();
		}
		template < typename T > T & val(bool raw=false)
		{
			if(typeid(T) != this->type())
				throw cov::error("E0006");
			if(this->mDat == nullptr)
				throw cov::error("E0005");
			if(!raw)
				clone();
			return dynamic_cast < holder < T > *>(this->mDat->data)->data();
		}
		template < typename T > const T & val(bool raw=false) const
		{
			if(typeid(T) != this->type())
				throw cov::error("E0006");
			if(this->mDat == nullptr)
				throw cov::error("E0005");
			return dynamic_cast < const holder < T > *>(this->mDat->data)->data();
		}
		template < typename T > const T& const_val() const
		{
			if(typeid(T) != this->type())
				throw cov::error("E0006");
			if(this->mDat == nullptr)
				throw cov::error("E0005");
			return dynamic_cast < const holder < T > *>(this->mDat->data)->data();
		}
		template < typename T > operator T&()
		{
			return this->val<T>();
		}
		template < typename T > operator const T&() const
		{
			return this->const_val<T>();
		}
		void assign(const any& obj,bool raw=false)
		{
			if(&obj!=this) {
				if(mDat!=nullptr&&obj.mDat!=nullptr&&raw) {
					mDat->data=obj.mDat->data->duplicate();
				} else {
					recycle();
					if(obj.mDat!=nullptr)
						mDat=new proxy(1,obj.mDat->data->duplicate());
					else
						mDat=nullptr;
				}
			}
		}
		template < typename T > void assign(const T & dat,bool raw=false)
		{
			if(raw)
				mDat->data=new holder < T > (dat);
			else {
				recycle();
				mDat = new proxy(1,new holder < T > (dat));
			}
		}
		template < typename T > any & operator=(const T & dat)
		{
			assign(dat);
			return *this;
		}
	};
	template<int N> class any::holder<char[N]>:public any::holder<std::string> {
	public:
		using holder<std::string>::holder;
	};
	template<> class any::holder<std::type_info>:public any::holder<std::type_index> {
	public:
		using holder<std::type_index>::holder;
	};
}

cov::any cov::any::infer_value(const std::string& str)
{
	if(str=="true"||str=="True"||str=="TRUE")
		return true;
	if(str=="false"||str=="False"||str=="FALSE")
		return false;
	enum types {
		interger,floating,other
	} type=types::interger;
	for(auto& it:str) {
		if(!std::isdigit(it)&&it!='.') {
			type=other;
			break;
		}
		if(!std::isdigit(it)&&it=='.') {
			if(type==interger) {
				type=floating;
				continue;
			}
			if(type==floating) {
				type=other;
				break;
			}
		}
	}
	switch(type) {
	case interger:
		try {
			return std::stoi(str);
		} catch(std::out_of_range) {
			try {
				return std::stol(str);
			} catch(std::out_of_range) {
				try {
					return std::stoll(str);
				} catch(std::out_of_range) {
					return str;
				}
			}
		}
	case floating:
		return std::stod(str);
	case other:
		break;
	}
	return str;
}

std::istream& operator>>(std::istream& in,cov::any& val)
{
	static std::string str;
	in>>str;
	val=cov::any::infer_value(str);
	return in;
}

std::ostream& operator<<(std::ostream& out,const cov::any& val)
{
	out<<val.to_string();
	return out;
}
<commit_msg>修复cov::any的内存泄露问题<commit_after>#pragma once
/*
* Covariant Mozart Utility Library: Any
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2016 Michael Lee(李登淳)
* Email: China-LDC@outlook.com
* Github: https://github.com/mikecovlee
* Website: http://ldc.atd3.cn
*
* Version: 17.2.1
*/
#include "./base.hpp"
#include <iostream>

namespace std {
	template<typename T> std::string to_string(const T&)
	{
		throw cov::error("E000D");
	}
	template<> std::string to_string<std::string>(const std::string& str)
	{
		return str;
	}
	template<> std::string to_string<bool>(const bool& v)
	{
		if(v)
			return "True";
		else
			return "False";
	}
}

namespace cov {
	template < typename _Tp > class compare_helper {
		template < typename T,typename X=bool >struct matcher;
		template < typename T > static constexpr bool match(T*)
		{
			return false;
		}
		template < typename T > static constexpr bool match(matcher < T, decltype(std::declval<T>()==std::declval<T>()) > *)
		{
			return true;
		}
	public:
		static constexpr bool value = match < _Tp > (nullptr);
	};
	template<typename,bool> struct compare_if;
	template<typename T>struct compare_if<T,true> {
		static bool compare(const T& a,const T& b)
		{
			return a==b;
		}
	};
	template<typename T>struct compare_if<T,false> {
		static bool compare(const T& a,const T& b)
		{
			return &a==&b;
		}
	};
	template<typename T>bool compare(const T& a,const T& b)
	{
		return compare_if<T,compare_helper<T>::value>::compare(a,b);
	}
	class any final {
		class baseHolder {
		public:
			baseHolder() = default;
			virtual ~ baseHolder() = default;
			virtual const std::type_info & type() const = 0;
			virtual baseHolder *duplicate() = 0;
			virtual bool compare(const baseHolder *) const = 0;
			virtual std::string to_string() const = 0;
		};
		template < typename T > class holder:public baseHolder {
		protected:
			T mDat;
		public:
			holder() = default;
			holder(const T& dat):mDat(dat) {}
			virtual ~ holder() = default;
			virtual const std::type_info & type() const override
			{
				return typeid(T);
			}
			virtual baseHolder *duplicate() override
			{
				return new holder(mDat);
			}
			virtual bool compare(const baseHolder * obj)const override
			{
				if (obj->type() == this->type()) {
					const holder < T > *ptr = dynamic_cast < const holder < T > *>(obj);
					return ptr!=nullptr?cov::compare(mDat,ptr->data()):false;
				}
				return false;
			}
			virtual std::string to_string() const override
			{
				return std::move(std::to_string(mDat));
			}
			T & data()
			{
				return mDat;
			}
			const T & data() const
			{
				return mDat;
			}
			void data(const T & dat)
			{
				mDat = dat;
			}
		};
		using size_t=unsigned long;
		struct proxy {
			mutable size_t refcount=1;
			baseHolder* data=nullptr;
			proxy()=default;
			proxy(size_t rc,baseHolder* d):refcount(rc),data(d) {}
			~proxy()
			{
				delete data;
			}
		};
		proxy* mDat=nullptr;
		proxy* duplicate() const noexcept
		{
			if(mDat!=nullptr) {
				++mDat->refcount;
			}
			return mDat;
		}
		void recycle() noexcept
		{
			if(mDat!=nullptr) {
				--mDat->refcount;
				if(mDat->refcount==0) {
					delete mDat;
					mDat=nullptr;
				}
			}
		}
	public:
		static any infer_value(const std::string&);
		void swap(any& obj) noexcept
		{
			proxy* tmp=this->mDat;
			this->mDat=obj.mDat;
			obj.mDat=tmp;
		}
		void swap(any&& obj) noexcept
		{
			proxy* tmp=this->mDat;
			this->mDat=obj.mDat;
			obj.mDat=tmp;
		}
		void clone() noexcept
		{
			if(mDat!=nullptr) {
				proxy* dat=new proxy(1,mDat->data->duplicate());
				recycle();
				mDat=dat;
			}
		}
		bool usable() const noexcept
		{
			return mDat != nullptr;
		}
		any()=default;
		template < typename T > any(const T & dat):mDat(new proxy(1,new holder < T > (dat))) {}
		any(const any & v):mDat(v.duplicate()) {}
		any(any&& v) noexcept
		{
			swap(std::forward<any>(v));
		}
		~any()
		{
			recycle();
		}
		const std::type_info & type() const
		{
			return this->mDat != nullptr?this->mDat->data->type():typeid(void);
		}
		std::string to_string() const
		{
			if(this->mDat == nullptr)
				return "Null";
			return std::move(this->mDat->data->to_string());
		}
		any & operator=(const any & var)
		{
			if(&var!=this) {
				recycle();
				mDat = var.duplicate();
			}
			return *this;
		}
		any & operator=(any&& var) noexcept
		{
			if(&var!=this)
				swap(std::forward<any>(var));
			return *this;
		}
		bool operator==(const any & var) const
		{
			return usable()?this->mDat->data->compare(var.mDat->data):!var.usable();
		}
		bool operator!=(const any & var)const
		{
			return usable()?!this->mDat->data->compare(var.mDat->data):var.usable();
		}
		template < typename T > T & val(bool raw=false)
		{
			if(typeid(T) != this->type())
				throw cov::error("E0006");
			if(this->mDat == nullptr)
				throw cov::error("E0005");
			if(!raw)
				clone();
			return dynamic_cast < holder < T > *>(this->mDat->data)->data();
		}
		template < typename T > const T & val(bool raw=false) const
		{
			if(typeid(T) != this->type())
				throw cov::error("E0006");
			if(this->mDat == nullptr)
				throw cov::error("E0005");
			return dynamic_cast < const holder < T > *>(this->mDat->data)->data();
		}
		template < typename T > const T& const_val() const
		{
			if(typeid(T) != this->type())
				throw cov::error("E0006");
			if(this->mDat == nullptr)
				throw cov::error("E0005");
			return dynamic_cast < const holder < T > *>(this->mDat->data)->data();
		}
		template < typename T > operator T&()
		{
			return this->val<T>();
		}
		template < typename T > operator const T&() const
		{
			return this->const_val<T>();
		}
		void assign(const any& obj,bool raw=false)
		{
			if(&obj!=this) {
				if(mDat!=nullptr&&obj.mDat!=nullptr&&raw) {
					delete mDat->data;
					mDat->data=obj.mDat->data->duplicate();
				} else {
					recycle();
					if(obj.mDat!=nullptr)
						mDat=new proxy(1,obj.mDat->data->duplicate());
					else
						mDat=nullptr;
				}
			}
		}
		template < typename T > void assign(const T & dat,bool raw=false)
		{
			if(raw) {
				delete mDat->data;
				mDat->data=new holder < T > (dat);
			} else {
				recycle();
				mDat = new proxy(1,new holder < T > (dat));
			}
		}
		template < typename T > any & operator=(const T & dat)
		{
			assign(dat);
			return *this;
		}
	};
	template<int N> class any::holder<char[N]>:public any::holder<std::string> {
	public:
		using holder<std::string>::holder;
	};
	template<> class any::holder<std::type_info>:public any::holder<std::type_index> {
	public:
		using holder<std::type_index>::holder;
	};
}

cov::any cov::any::infer_value(const std::string& str)
{
	if(str=="true"||str=="True"||str=="TRUE")
		return true;
	if(str=="false"||str=="False"||str=="FALSE")
		return false;
	enum types {
		interger,floating,other
	} type=types::interger;
	for(auto& it:str) {
		if(!std::isdigit(it)&&it!='.') {
			type=other;
			break;
		}
		if(!std::isdigit(it)&&it=='.') {
			if(type==interger) {
				type=floating;
				continue;
			}
			if(type==floating) {
				type=other;
				break;
			}
		}
	}
	switch(type) {
	case interger:
		try {
			return std::stoi(str);
		} catch(std::out_of_range) {
			try {
				return std::stol(str);
			} catch(std::out_of_range) {
				try {
					return std::stoll(str);
				} catch(std::out_of_range) {
					return str;
				}
			}
		}
	case floating:
		return std::stod(str);
	case other:
		break;
	}
	return str;
}

std::istream& operator>>(std::istream& in,cov::any& val)
{
	static std::string str;
	in>>str;
	val=cov::any::infer_value(str);
	return in;
}

std::ostream& operator<<(std::ostream& out,const cov::any& val)
{
	out<<val.to_string();
	return out;
}
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	pqxx/field.hxx
 *
 *   DESCRIPTION
 *      definitions for the pqxx::field class.
 *   pqxx::field refers to a field in a query result.
 *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/field instead.
 *
 * Copyright (c) 2001-2015, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#ifndef PQXX_H_FIELD
#define PQXX_H_FIELD

#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"

#if defined(PQXX_HAVE_OPTIONAL)
#include <optional>
#endif

#if defined(PQXX_HAVE_EXP_OPTIONAL)
#include <experimental/optional>
#endif

#include "pqxx/strconv"

/* Methods tested in eg. self-test program test001 are marked with "//[t1]"
 */

namespace pqxx
{
class result;
class row;

typedef unsigned int row_size_type;
typedef signed int row_difference_type;

/// Reference to a field in a result set.
/** A field represents one entry in a row.  It represents an actual value
 * in the result set, and can be converted to various types.
 */
class PQXX_LIBEXPORT field
{
public:
  typedef size_t size_type;

  /// Constructor.
  /** Create field as reference to a field in a result set.
   * @param R Row that this field is part of.
   * @param C Column number of this field.
   */
  field(const row &R, row_size_type C) PQXX_NOEXCEPT;		//[t1]

  /**
   * @name Comparison
   */
  //@{
  /// Byte-by-byte comparison of two fields (all nulls are considered equal)
  /** @warning null handling is still open to discussion and change!
   *
   * Handling of null values differs from that in SQL where a comparison
   * involving a null value yields null, so nulls are never considered equal
   * to one another or even to themselves.
   *
   * Null handling also probably differs from the closest equivalent in C++,
   * which is the NaN (Not-a-Number) value, a singularity comparable to
   * SQL's null.  This is because the builtin == operator demands that a == a.
   *
   * The usefulness of this operator is questionable.  No interpretation
   * whatsoever is imposed on the data; 0 and 0.0 are considered different,
   * as are null vs. the empty string, or even different (but possibly
   * equivalent and equally valid) encodings of the same Unicode character
   * etc.
   */
  bool operator==(const field &) const;				//[t75]

  /// Byte-by-byte comparison (all nulls are considered equal)
  /** @warning See operator==() for important information about this operator
   */
  bool operator!=(const field &rhs) const				//[t82]
						    {return !operator==(rhs);}
  //@}

  /**
   * @name Column information
   */
  //@{
  /// Column name
  const char *name() const;						//[t11]

  /// Column type
  oid type() const;							//[t7]

  /// What table did this column come from?
  oid table() const;							//[t2]

  row_size_type num() const { return col(); }				//[t82]

  /// What column number in its originating table did this column come from?
  row_size_type table_column() const;					//[t93]
  //@}

  /**
   * @name Content access
   */
  //@{
  /// Read as plain C string
  /** Since the field's data is stored internally in the form of a
   * zero-terminated C string, this is the fastest way to read it.  Use the
   * to() or as() functions to convert the string to other types such as
   * @c int, or to C++ strings.
   */
  const char *c_str() const;						//[t2]

  /// Read value into Obj; or leave Obj untouched and return @c false if null
  template<typename T> bool to(T &Obj) const				//[t3]
  {
    const char *const bytes = c_str();
    if (!bytes[0] && is_null()) return false;
    from_string(bytes, Obj);
    return true;
  }

  /// Read value into Obj; or leave Obj untouched and return @c false if null
  template<typename T> bool operator>>(T &Obj) const			//[t7]
      { return to(Obj); }

#ifdef PQXX_NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION
  /// Specialization: to(string &)
  template<> bool to<std::string>(std::string &Obj) const;

  /// Specialization: <tt>to(const char *&)</tt>.
  /** The buffer has the same lifetime as the result, so take care not to
   * use it after the result is destroyed.
   */
  template<> bool to<const char *>(const char *&Obj) const;
#endif

  /// Read value into Obj; or use Default & return @c false if null
  template<typename T> bool to(T &Obj, const T &Default) const	//[t12]
  {
    const bool NotNull = to(Obj);
    if (!NotNull) Obj = Default;
    return NotNull;
  }

  /// Return value as object of given type, or Default if null
  /** Note that unless the function is instantiated with an explicit template
   * argument, the Default value's type also determines the result type.
   */
  template<typename T> T as(const T &Default) const			//[t1]
  {
    T Obj;
    to(Obj, Default);
    return Obj;
  }

  /// Return value as object of given type, or throw exception if null
  template<typename T> T as() const					//[t45]
  {
    T Obj;
    const bool NotNull = to(Obj);
    if (!NotNull) Obj = string_traits<T>::null();
    return Obj;
  }

#if defined(PQXX_HAVE_OPTIONAL)
  /// Return value as std::optional, or blank value if null.
  template<typename T> std::optional<T> get() const
  {
    typedef std::optional<T> optional;
    if (is_null()) return optional();
    else return optional(as<T>());
  }
#endif

#if defined(PQXX_HAVE_EXP_OPTIONAL)
  /// Return value as std::experimental::optional, or blank value if null.
  template<typename T> std::experimental::optional<T> get() const
  {
    typedef std::experimental::optional<T> optional;
    if (is_null()) return optional();
    else return optional(as<T>());
  }
#endif

  /// Is this field's value null?
  bool is_null() const PQXX_NOEXCEPT;					//[t12]

  /// Return number of bytes taken up by the field's value.
  /**
   * Includes the terminating zero byte.
   */
  size_type size() const PQXX_NOEXCEPT;					//[t11]
  //@}

protected:
  const result *home() const PQXX_NOEXCEPT { return m_home; }
  size_t idx() const PQXX_NOEXCEPT { return m_row; }
  row_size_type col() const PQXX_NOEXCEPT { return m_col; }

  row_size_type m_col;

private:
  const result *m_home;
  size_t m_row;
};

/// Specialization: <tt>to(string &)</tt>.
template<>
inline bool field::to<std::string>(std::string &Obj) const
{
  const char *const bytes = c_str();
  if (!bytes[0] && is_null()) return false;
  Obj = std::string(bytes, size());
  return true;
}

/// Specialization: <tt>to(const char *&)</tt>.
/** The buffer has the same lifetime as the data in this result (i.e. of this
 * result object, or the last remaining one copied from it etc.), so take care
 * not to use it after the last result object referring to this query result is
 * destroyed.
 */
template<>
inline bool field::to<const char *>(const char *&Obj) const
{
  if (is_null()) return false;
  Obj = c_str();
  return true;
}

template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR> >
  class field_streambuf :
  public std::basic_streambuf<CHAR, TRAITS>
{
public:
  typedef CHAR char_type;
  typedef TRAITS traits_type;
  typedef typename traits_type::int_type int_type;
  typedef typename traits_type::pos_type pos_type;
  typedef typename traits_type::off_type off_type;
  typedef std::ios::openmode openmode;
  typedef std::ios::seekdir seekdir;

  explicit field_streambuf(const field &F) :			//[t74]
    m_Field(F)
  {
    initialize();
  }

protected:
  virtual int sync() PQXX_OVERRIDE { return traits_type::eof(); }

protected:
  virtual pos_type seekoff(off_type, seekdir, openmode) PQXX_OVERRIDE
	{ return traits_type::eof(); }
  virtual pos_type seekpos(pos_type, openmode) PQXX_OVERRIDE
	{return traits_type::eof();}
  virtual int_type overflow(int_type) PQXX_OVERRIDE
	{ return traits_type::eof(); }
  virtual int_type underflow() PQXX_OVERRIDE
	{ return traits_type::eof(); }

private:
  const field &m_Field;

  int_type initialize()
  {
    char_type *G =
      reinterpret_cast<char_type *>(const_cast<char *>(m_Field.c_str()));
    this->setg(G, G, G + m_Field.size());
    return int_type(m_Field.size());
  }
};

/// Input stream that gets its data from a result field
/** Use this class exactly as you would any other istream to read data from a
 * field.  All formatting and streaming operations of @c std::istream are
 * supported.  What you'll typically want to use, however, is the fieldstream
 * typedef (which defines a basic_fieldstream for @c char).  This is similar to
 * how e.g. @c std::ifstream relates to @c std::basic_ifstream.
 *
 * This class has only been tested for the char type (and its default traits).
 */
template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR> >
  class basic_fieldstream :
    public std::basic_istream<CHAR, TRAITS>
{
  typedef std::basic_istream<CHAR, TRAITS> super;

public:
  typedef CHAR char_type;
  typedef TRAITS traits_type;
  typedef typename traits_type::int_type int_type;
  typedef typename traits_type::pos_type pos_type;
  typedef typename traits_type::off_type off_type;

  basic_fieldstream(const field &F) : super(0), m_Buf(F)
	{ super::init(&m_Buf); }

private:
  field_streambuf<CHAR, TRAITS> m_Buf;
};

typedef basic_fieldstream<char> fieldstream;

} // namespace pqxx

#include "pqxx/compiler-internal-post.hxx"

#endif
<commit_msg>Unify field::get() implementations.<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	pqxx/field.hxx
 *
 *   DESCRIPTION
 *      definitions for the pqxx::field class.
 *   pqxx::field refers to a field in a query result.
 *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/field instead.
 *
 * Copyright (c) 2001-2015, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#ifndef PQXX_H_FIELD
#define PQXX_H_FIELD

#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"

#if defined(PQXX_HAVE_OPTIONAL)
#include <optional>
#endif

#if defined(PQXX_HAVE_EXP_OPTIONAL)
#include <experimental/optional>
#endif

#include "pqxx/strconv"

/* Methods tested in eg. self-test program test001 are marked with "//[t1]"
 */

namespace pqxx
{
class result;
class row;

typedef unsigned int row_size_type;
typedef signed int row_difference_type;

/// Reference to a field in a result set.
/** A field represents one entry in a row.  It represents an actual value
 * in the result set, and can be converted to various types.
 */
class PQXX_LIBEXPORT field
{
public:
  typedef size_t size_type;

  /// Constructor.
  /** Create field as reference to a field in a result set.
   * @param R Row that this field is part of.
   * @param C Column number of this field.
   */
  field(const row &R, row_size_type C) PQXX_NOEXCEPT;		//[t1]

  /**
   * @name Comparison
   */
  //@{
  /// Byte-by-byte comparison of two fields (all nulls are considered equal)
  /** @warning null handling is still open to discussion and change!
   *
   * Handling of null values differs from that in SQL where a comparison
   * involving a null value yields null, so nulls are never considered equal
   * to one another or even to themselves.
   *
   * Null handling also probably differs from the closest equivalent in C++,
   * which is the NaN (Not-a-Number) value, a singularity comparable to
   * SQL's null.  This is because the builtin == operator demands that a == a.
   *
   * The usefulness of this operator is questionable.  No interpretation
   * whatsoever is imposed on the data; 0 and 0.0 are considered different,
   * as are null vs. the empty string, or even different (but possibly
   * equivalent and equally valid) encodings of the same Unicode character
   * etc.
   */
  bool operator==(const field &) const;				//[t75]

  /// Byte-by-byte comparison (all nulls are considered equal)
  /** @warning See operator==() for important information about this operator
   */
  bool operator!=(const field &rhs) const				//[t82]
						    {return !operator==(rhs);}
  //@}

  /**
   * @name Column information
   */
  //@{
  /// Column name
  const char *name() const;						//[t11]

  /// Column type
  oid type() const;							//[t7]

  /// What table did this column come from?
  oid table() const;							//[t2]

  row_size_type num() const { return col(); }				//[t82]

  /// What column number in its originating table did this column come from?
  row_size_type table_column() const;					//[t93]
  //@}

  /**
   * @name Content access
   */
  //@{
  /// Read as plain C string
  /** Since the field's data is stored internally in the form of a
   * zero-terminated C string, this is the fastest way to read it.  Use the
   * to() or as() functions to convert the string to other types such as
   * @c int, or to C++ strings.
   */
  const char *c_str() const;						//[t2]

  /// Read value into Obj; or leave Obj untouched and return @c false if null
  template<typename T> bool to(T &Obj) const				//[t3]
  {
    const char *const bytes = c_str();
    if (!bytes[0] && is_null()) return false;
    from_string(bytes, Obj);
    return true;
  }

  /// Read value into Obj; or leave Obj untouched and return @c false if null
  template<typename T> bool operator>>(T &Obj) const			//[t7]
      { return to(Obj); }

#ifdef PQXX_NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION
  /// Specialization: to(string &)
  template<> bool to<std::string>(std::string &Obj) const;

  /// Specialization: <tt>to(const char *&)</tt>.
  /** The buffer has the same lifetime as the result, so take care not to
   * use it after the result is destroyed.
   */
  template<> bool to<const char *>(const char *&Obj) const;
#endif

  /// Read value into Obj; or use Default & return @c false if null
  template<typename T> bool to(T &Obj, const T &Default) const	//[t12]
  {
    const bool NotNull = to(Obj);
    if (!NotNull) Obj = Default;
    return NotNull;
  }

  /// Return value as object of given type, or Default if null
  /** Note that unless the function is instantiated with an explicit template
   * argument, the Default value's type also determines the result type.
   */
  template<typename T> T as(const T &Default) const			//[t1]
  {
    T Obj;
    to(Obj, Default);
    return Obj;
  }

  /// Return value as object of given type, or throw exception if null
  template<typename T> T as() const					//[t45]
  {
    T Obj;
    const bool NotNull = to(Obj);
    if (!NotNull) Obj = string_traits<T>::null();
    return Obj;
  }

#if defined(PQXX_HAVE_OPTIONAL)
  /// Return value as std::optional, or blank value if null.
  template<typename T> std::optional<T> get() const
	{ return get_opt<T, std::optional<T> >(); }
#endif

#if defined(PQXX_HAVE_EXP_OPTIONAL)
  /// Return value as std::experimental::optional, or blank value if null.
  template<typename T> std::experimental::optional<T> get() const
	{ return get_opt<T, std::experimental::optional<T> >(); }
#endif

  /// Is this field's value null?
  bool is_null() const PQXX_NOEXCEPT;					//[t12]

  /// Return number of bytes taken up by the field's value.
  /**
   * Includes the terminating zero byte.
   */
  size_type size() const PQXX_NOEXCEPT;					//[t11]
  //@}

protected:
  const result *home() const PQXX_NOEXCEPT { return m_home; }
  size_t idx() const PQXX_NOEXCEPT { return m_row; }
  row_size_type col() const PQXX_NOEXCEPT { return m_col; }

  row_size_type m_col;

private:
  /// Implementation for get().
  /**
   * Abstracts away the difference between std::optional and
   * std::experimental::optional.  Both can be supported at the same time,
   * so pre-C++17 code can still work once the compiler defaults to C++17.
   */
  template<typename T, typename OPTIONAL> OPTIONAL get_opt() const
  {
    if (is_null()) return OPTIONAL();
    else return OPTIONAL(as<T>());
  }

  const result *m_home;
  size_t m_row;
};

/// Specialization: <tt>to(string &)</tt>.
template<>
inline bool field::to<std::string>(std::string &Obj) const
{
  const char *const bytes = c_str();
  if (!bytes[0] && is_null()) return false;
  Obj = std::string(bytes, size());
  return true;
}

/// Specialization: <tt>to(const char *&)</tt>.
/** The buffer has the same lifetime as the data in this result (i.e. of this
 * result object, or the last remaining one copied from it etc.), so take care
 * not to use it after the last result object referring to this query result is
 * destroyed.
 */
template<>
inline bool field::to<const char *>(const char *&Obj) const
{
  if (is_null()) return false;
  Obj = c_str();
  return true;
}

template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR> >
  class field_streambuf :
  public std::basic_streambuf<CHAR, TRAITS>
{
public:
  typedef CHAR char_type;
  typedef TRAITS traits_type;
  typedef typename traits_type::int_type int_type;
  typedef typename traits_type::pos_type pos_type;
  typedef typename traits_type::off_type off_type;
  typedef std::ios::openmode openmode;
  typedef std::ios::seekdir seekdir;

  explicit field_streambuf(const field &F) :			//[t74]
    m_Field(F)
  {
    initialize();
  }

protected:
  virtual int sync() PQXX_OVERRIDE { return traits_type::eof(); }

protected:
  virtual pos_type seekoff(off_type, seekdir, openmode) PQXX_OVERRIDE
	{ return traits_type::eof(); }
  virtual pos_type seekpos(pos_type, openmode) PQXX_OVERRIDE
	{return traits_type::eof();}
  virtual int_type overflow(int_type) PQXX_OVERRIDE
	{ return traits_type::eof(); }
  virtual int_type underflow() PQXX_OVERRIDE
	{ return traits_type::eof(); }

private:
  const field &m_Field;

  int_type initialize()
  {
    char_type *G =
      reinterpret_cast<char_type *>(const_cast<char *>(m_Field.c_str()));
    this->setg(G, G, G + m_Field.size());
    return int_type(m_Field.size());
  }
};

/// Input stream that gets its data from a result field
/** Use this class exactly as you would any other istream to read data from a
 * field.  All formatting and streaming operations of @c std::istream are
 * supported.  What you'll typically want to use, however, is the fieldstream
 * typedef (which defines a basic_fieldstream for @c char).  This is similar to
 * how e.g. @c std::ifstream relates to @c std::basic_ifstream.
 *
 * This class has only been tested for the char type (and its default traits).
 */
template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR> >
  class basic_fieldstream :
    public std::basic_istream<CHAR, TRAITS>
{
  typedef std::basic_istream<CHAR, TRAITS> super;

public:
  typedef CHAR char_type;
  typedef TRAITS traits_type;
  typedef typename traits_type::int_type int_type;
  typedef typename traits_type::pos_type pos_type;
  typedef typename traits_type::off_type off_type;

  basic_fieldstream(const field &F) : super(0), m_Buf(F)
	{ super::init(&m_Buf); }

private:
  field_streambuf<CHAR, TRAITS> m_Buf;
};

typedef basic_fieldstream<char> fieldstream;

} // namespace pqxx

#include "pqxx/compiler-internal-post.hxx"

#endif
<|endoftext|>


<commit_before>
#include "tst_lua_call_values.h"

#include "object.h"
#include "objectmanager.h"
#include "connection.h"
#include "lua_task.h"
#include "connectionmanager.h"

#include "luatestdata.h"

/*
  COMMAND PARSING

player    an object, the player who typed the command
this      an object, the object on which this verb was found
caller    an object, the same as `player'
verb      a string, the first word of the command
argstr    a string, everything after the first word of the command
args      a list of strings, the words in `argstr'
dobjstr   a string, the direct object string found during parsing
dobj      an object, the direct object value found during matching
prepstr   a string, the prepositional phrase found during parsing
iobjstr   a string, the indirect object string
iobj      an object, the indirect object value
*/

/*
GENERAL

For others, the general meaning of the value is consistent, though the value itself is
different for different situations:

player
	an object, the player who typed the command that started the task that involved
	running this piece of code.
this
	an object, the object on which the currently-running verb was found.
caller
	an object, the object on which the verb that called the currently-running verb was
	found. For the first verb called for a given command, `caller' has the same value
	as `player'.
verb
	a string, the name by which the currently-running verb was identified.
args
	a list, the arguments given to this verb. For the first verb called for a given
	command, this is a list of strings, the words on the command line.

The rest of the so-called "built-in" variables are only really meaningful for the first
verb called for a given command. Their semantics is given in the discussion of command
parsing, above.
*/

/*
Functions are always called by the program for some verb; that program is running with
the permissions of some player, usually the owner of the verb in question (it is not
always the owner, though; wizards can use set_task_pperms() to change the permissions
`on the fly'). In the function descriptions below, we refer to the player whose
permissions are being used as the programmer.

Function: none set_task_perms (obj who)
	Changes the permissions with which the currently-executing verb is running to be
	those of who. If the programmer is neither who nor a wizard, then E_PERM is raised.

	Note: This does not change the owner of the currently-running verb, only the
	permissions of this particular invocation. It is used in verbs owned by wizards
	to make themselves run with lesser (usually non-wizard) permissions.

*/

/*
Function: list eval (str string)
	The MOO-code compiler processes string as if it were to be the program associated
	with some verb and, if no errors are found, that fictional verb is invoked. If the
	programmer is not, in fact, a programmer, then E_PERM is raised. The normal result
	of calling eval() is a two element list. The first element is true if there were
	no compilation errors and false otherwise. The second element is either the result
	returned from the fictional verb (if there were no compilation errors) or a list of
	the compiler's error messages (otherwise).

	When the fictional verb is invoked, the various built-in variables have values as
	shown below:

	player    the same as in the calling verb
	this      #-1
	caller    the same as the initial value of this in the calling verb

	args      {}
	argstr    ""

	verb      ""
	dobjstr   ""
	dobj      #-1
	prepstr   ""
	iobjstr   ""
	iobj      #-1

	The fictional verb runs with the permissions of the programmer and as if its
	`d' permissions bit were on.

	eval("return 3 + 4;")   =>   {1, 7}

*/

void TestLuaCallValues::luaCallValueFirst_data()
{
	QTest::addColumn<QString>( "pType" );
	QTest::addColumn<bool>( "pWizard" );
	QTest::addColumn<ObjectId>( "pResult" );

	QTest::newRow( "object" )      << "object"      << false << OBJECT_NONE;
	QTest::newRow( "caller" )      << "caller"      << false << 3;
	QTest::newRow( "player" )      << "player"      << false << 3;
	QTest::newRow( "permissions" ) << "permissions" << false << 3;

	QTest::newRow( "object (wizard)" )      << "object"      << true  << OBJECT_NONE;
	QTest::newRow( "caller (wizard)" )      << "caller"      << true  << 0;
	QTest::newRow( "player (wizard)" )      << "player"      << true  << 0;
	QTest::newRow( "permissions (wizard)" ) << "permissions" << true  << 0;
}

void TestLuaCallValues::luaCallValueFirst( void )
{
	QFETCH( QString,  pType );
	QFETCH( bool, pWizard );
	QFETCH( ObjectId, pResult );

	LuaTestData			 TD;

	Object				*O  = TD.OM.newObject();

	O->setParent( 2 );
	O->setOwner( TD.programmerId() );

	// Add property to hold result

	Property		P;

	P.initialise();

	P.setValue( "string" );
	P.setOwner( TD.programmerId() );

	O->propAdd( "result", P );

	// Call test

	TD.execute( QString( ";o( %1 ).result = moo.%2.id" ).arg( O->id() ).arg( pType ), pWizard ? OBJECT_SYSTEM : TD.programmerId() );

	// Check result

	Property	*R = O->prop( "result" );

	QVERIFY( R );
	QVERIFY( R->type() == QVariant::String );
	QCOMPARE( R->value().toString(), QString( "%1" ).arg( pResult ) );	// moo.eval sets object to -1
}

void TestLuaCallValues::luaCallValueSecond_data()
{
	QTest::addColumn<QString>( "pType" );
	QTest::addColumn<bool>( "pWizard" );
	QTest::addColumn<ObjectId>( "pResult" );

	QTest::newRow( "object" )      << "object"      << false << 4;
	QTest::newRow( "caller" )      << "caller"      << false << -1;
	QTest::newRow( "player" )      << "player"      << false << 3;
	QTest::newRow( "permissions" ) << "permissions" << false << 4;

	QTest::newRow( "object (wizard)" )      << "object"      << true  << 4;
	QTest::newRow( "caller (wizard)" )      << "caller"      << true  << OBJECT_NONE;
	QTest::newRow( "player (wizard)" )      << "player"      << true  << 3;
	QTest::newRow( "permissions (wizard)" ) << "permissions" << true  << 4;
}

void TestLuaCallValues::luaCallValueSecond()
{
	QFETCH( QString,  pType );
	QFETCH( bool, pWizard );
	QFETCH( ObjectId, pResult );

	LuaTestData			 TD;

	TD.Programmer->setWizard( pWizard );

	Object				*O  = TD.OM.newObject();

	O->setParent( 2 );

	// Add property to hold result

	Property		P;

	P.initialise();

	P.setValue( "string" );
	P.setOwner( O->id() );

	O->propAdd( "result", P );

	// Add verb

	Verb			 V;

	V.initialise();

	V.setOwner( O->id() );
	V.setScript( QString( "moo.object.result = tostring( moo.%1.id )" ).arg( pType ) );

	O->verbAdd( "test", V );

	// Call test

	TD.execute( QString( ";o( %1 ):test()" ).arg( O->id() ) );

	// Check result

	Property	*R = O->prop( "result" );

	QVERIFY( R );
	QVERIFY( R->type() == QVariant::String );
	QCOMPARE( R->value().toString(), QString( "%1" ).arg( pResult ) );
}

void TestLuaCallValues::luaCallValueThird_data()
{
	QTest::addColumn<QString>( "pType" );
	QTest::addColumn<bool>( "pWizard" );
	QTest::addColumn<ObjectId>( "pResult" );

	QTest::newRow( "object" )      << "object"      << false << 5;
	QTest::newRow( "caller" )      << "caller"      << false << 4;
	QTest::newRow( "player" )      << "player"      << false << 3;
	QTest::newRow( "permissions" ) << "permissions" << false << 5;

	QTest::newRow( "object (wizard)" )      << "object"      << true  << 5;
	QTest::newRow( "caller (wizard)" )      << "caller"      << true  << 4;
	QTest::newRow( "player (wizard)" )      << "player"      << true  << 3;
	QTest::newRow( "permissions (wizard)" ) << "permissions" << true  << 5;
}

void TestLuaCallValues::luaCallValueThird()
{
	QFETCH( QString,  pType );
	QFETCH( bool, pWizard );
	QFETCH( ObjectId, pResult );

	LuaTestData			 TD;

	TD.Programmer->setWizard( pWizard );

	Object				*O1 = TD.OM.newObject();
	Object				*O2 = TD.OM.newObject();

	O1->setParent( 2 );
	O2->setParent( 1 );

	// Add property to hold result

	Property		P2;

	P2.initialise();

	P2.setValue( "result" );
	P2.setOwner( O2->id() );

	O2->propAdd( "result", P2 );

	// Add verb

	Verb			 V1;

	V1.initialise();

	V1.setOwner( O1->id() );
	V1.setScript( QString( "o( %1 ):test()" ).arg( O2->id() ) );

	O1->verbAdd( "test", V1);

	// Add verb

	Verb			 V2;

	V2.initialise();

	V2.setOwner( O2->id() );
	V2.setScript( QString( "o( %1 ).result = tostring( moo.%2.id )" ).arg( O2->id() ).arg( pType ) );

	O2->verbAdd( "test", V2 );

	// Call test

	TD.execute( QString( ";o( %1 ):test()" ).arg( O1->id() ) );

	// Check result

	QVariant R = O2->propValue( "result" );

	QCOMPARE( R.toString(), QString( "%1" ).arg( pResult ) );
}

void TestLuaCallValues::luaCallValueInherit()
{
	LuaTestData			 TD;

	TD.Programmer->setWizard( false );

	Object			*Root = TD.OM.rootObject();

	Root->propAdd( "result", "no result", Root->id() );

	Root->prop( "result" )->setChange( false );

	Object			*O1 = TD.OM.object( 2 );

	if( true )
	{
		Verb			V;

		V.initialise();

		V.setDirectObjectArgument( NONE );
		V.setIndirectObjectArgument( NONE );
		V.setPrepositionArgument( NONE );

		V.setScript( QString( "moo.object.result = tostring( %1 )" ).arg( 23 ) );

		V.setOwner( Root->id() );

		Root->verbAdd( "test", V );
	}

	lua_task T  = TD.execute( QString( ";o( %1 ):test()" ).arg( O1->id() ) );

	QCOMPARE( T.error(), false );

	QCOMPARE( O1->propValue( "result" ).toString(), "23" );
}

QTEST_GUILESS_MAIN( TestLuaCallValues )

#include "tst_lua_call_values.moc"
<commit_msg>Another test fix<commit_after>
#include "tst_lua_call_values.h"

#include "object.h"
#include "objectmanager.h"
#include "connection.h"
#include "lua_task.h"
#include "connectionmanager.h"

#include "luatestdata.h"

/*
  COMMAND PARSING

player    an object, the player who typed the command
this      an object, the object on which this verb was found
caller    an object, the same as `player'
verb      a string, the first word of the command
argstr    a string, everything after the first word of the command
args      a list of strings, the words in `argstr'
dobjstr   a string, the direct object string found during parsing
dobj      an object, the direct object value found during matching
prepstr   a string, the prepositional phrase found during parsing
iobjstr   a string, the indirect object string
iobj      an object, the indirect object value
*/

/*
GENERAL

For others, the general meaning of the value is consistent, though the value itself is
different for different situations:

player
	an object, the player who typed the command that started the task that involved
	running this piece of code.
this
	an object, the object on which the currently-running verb was found.
caller
	an object, the object on which the verb that called the currently-running verb was
	found. For the first verb called for a given command, `caller' has the same value
	as `player'.
verb
	a string, the name by which the currently-running verb was identified.
args
	a list, the arguments given to this verb. For the first verb called for a given
	command, this is a list of strings, the words on the command line.

The rest of the so-called "built-in" variables are only really meaningful for the first
verb called for a given command. Their semantics is given in the discussion of command
parsing, above.
*/

/*
Functions are always called by the program for some verb; that program is running with
the permissions of some player, usually the owner of the verb in question (it is not
always the owner, though; wizards can use set_task_pperms() to change the permissions
`on the fly'). In the function descriptions below, we refer to the player whose
permissions are being used as the programmer.

Function: none set_task_perms (obj who)
	Changes the permissions with which the currently-executing verb is running to be
	those of who. If the programmer is neither who nor a wizard, then E_PERM is raised.

	Note: This does not change the owner of the currently-running verb, only the
	permissions of this particular invocation. It is used in verbs owned by wizards
	to make themselves run with lesser (usually non-wizard) permissions.

*/

/*
Function: list eval (str string)
	The MOO-code compiler processes string as if it were to be the program associated
	with some verb and, if no errors are found, that fictional verb is invoked. If the
	programmer is not, in fact, a programmer, then E_PERM is raised. The normal result
	of calling eval() is a two element list. The first element is true if there were
	no compilation errors and false otherwise. The second element is either the result
	returned from the fictional verb (if there were no compilation errors) or a list of
	the compiler's error messages (otherwise).

	When the fictional verb is invoked, the various built-in variables have values as
	shown below:

	player    the same as in the calling verb
	this      #-1
	caller    the same as the initial value of this in the calling verb

	args      {}
	argstr    ""

	verb      ""
	dobjstr   ""
	dobj      #-1
	prepstr   ""
	iobjstr   ""
	iobj      #-1

	The fictional verb runs with the permissions of the programmer and as if its
	`d' permissions bit were on.

	eval("return 3 + 4;")   =>   {1, 7}

*/

void TestLuaCallValues::luaCallValueFirst_data()
{
	QTest::addColumn<QString>( "pType" );
	QTest::addColumn<bool>( "pWizard" );
	QTest::addColumn<ObjectId>( "pResult" );

	QTest::newRow( "object" )      << "object"      << false << OBJECT_NONE;
	QTest::newRow( "caller" )      << "caller"      << false << 3;
	QTest::newRow( "player" )      << "player"      << false << 3;
	QTest::newRow( "permissions" ) << "permissions" << false << 3;

	QTest::newRow( "object (wizard)" )      << "object"      << true  << OBJECT_NONE;
	QTest::newRow( "caller (wizard)" )      << "caller"      << true  << 0;
	QTest::newRow( "player (wizard)" )      << "player"      << true  << 0;
	QTest::newRow( "permissions (wizard)" ) << "permissions" << true  << 0;
}

void TestLuaCallValues::luaCallValueFirst( void )
{
	QFETCH( QString,  pType );
	QFETCH( bool, pWizard );
	QFETCH( ObjectId, pResult );

	LuaTestData			 TD;

	Object				*O  = TD.OM.newObject();

	O->setParent( 2 );
	O->setOwner( TD.programmerId() );

	// Add property to hold result

	Property		P;

	P.initialise();

	P.setValue( "string" );
	P.setOwner( TD.programmerId() );

	O->propAdd( "result", P );

	// Call test

	TD.execute( QString( ";o( %1 ).result = moo.%2.id" ).arg( O->id() ).arg( pType ), pWizard ? OBJECT_SYSTEM : TD.programmerId() );

	// Check result

	Property	*R = O->prop( "result" );

	QVERIFY( R );
	QVERIFY( R->type() == QVariant::String );
	QCOMPARE( R->value().toString(), QString( "%1" ).arg( pResult ) );	// moo.eval sets object to -1
}

void TestLuaCallValues::luaCallValueSecond_data()
{
	QTest::addColumn<QString>( "pType" );
	QTest::addColumn<bool>( "pWizard" );
	QTest::addColumn<ObjectId>( "pResult" );

	QTest::newRow( "object" )      << "object"      << false << 4;
	QTest::newRow( "caller" )      << "caller"      << false << -1;
	QTest::newRow( "player" )      << "player"      << false << 3;
	QTest::newRow( "permissions" ) << "permissions" << false << 4;

	QTest::newRow( "object (wizard)" )      << "object"      << true  << 4;
	QTest::newRow( "caller (wizard)" )      << "caller"      << true  << OBJECT_NONE;
	QTest::newRow( "player (wizard)" )      << "player"      << true  << 3;
	QTest::newRow( "permissions (wizard)" ) << "permissions" << true  << 4;
}

void TestLuaCallValues::luaCallValueSecond()
{
	QFETCH( QString,  pType );
	QFETCH( bool, pWizard );
	QFETCH( ObjectId, pResult );

	LuaTestData			 TD;

	TD.Programmer->setWizard( pWizard );

	Object				*O  = TD.OM.newObject();

	O->setParent( 2 );

	// Add property to hold result

	Property		P;

	P.initialise();

	P.setValue( "string" );
	P.setOwner( O->id() );

	O->propAdd( "result", P );

	// Add verb

	Verb			 V;

	V.initialise();

	V.setOwner( O->id() );
	V.setScript( QString( "moo.object.result = tostring( moo.%1.id )" ).arg( pType ) );

	O->verbAdd( "test", V );

	// Call test

	TD.execute( QString( ";o( %1 ):test()" ).arg( O->id() ) );

	// Check result

	Property	*R = O->prop( "result" );

	QVERIFY( R );
	QVERIFY( R->type() == QVariant::String );
	QCOMPARE( R->value().toString(), QString( "%1" ).arg( pResult ) );
}

void TestLuaCallValues::luaCallValueThird_data()
{
	QTest::addColumn<QString>( "pType" );
	QTest::addColumn<bool>( "pWizard" );
	QTest::addColumn<ObjectId>( "pResult" );

	QTest::newRow( "object" )      << "object"      << false << 5;
	QTest::newRow( "caller" )      << "caller"      << false << 4;
	QTest::newRow( "player" )      << "player"      << false << 3;
	QTest::newRow( "permissions" ) << "permissions" << false << 5;

	QTest::newRow( "object (wizard)" )      << "object"      << true  << 5;
	QTest::newRow( "caller (wizard)" )      << "caller"      << true  << 4;
	QTest::newRow( "player (wizard)" )      << "player"      << true  << 3;
	QTest::newRow( "permissions (wizard)" ) << "permissions" << true  << 5;
}

void TestLuaCallValues::luaCallValueThird()
{
	QFETCH( QString,  pType );
	QFETCH( bool, pWizard );
	QFETCH( ObjectId, pResult );

	LuaTestData			 TD;

	TD.Programmer->setWizard( pWizard );

	Object				*O1 = TD.OM.newObject();
	Object				*O2 = TD.OM.newObject();

	O1->setParent( 2 );
	O2->setParent( 1 );

	// Add property to hold result

	Property		P2;

	P2.initialise();

	P2.setValue( "result" );
	P2.setOwner( O2->id() );

	O2->propAdd( "result", P2 );

	// Add verb

	Verb			 V1;

	V1.initialise();

	V1.setOwner( O1->id() );
	V1.setScript( QString( "o( %1 ):test()" ).arg( O2->id() ) );

	O1->verbAdd( "test", V1);

	// Add verb

	Verb			 V2;

	V2.initialise();

	V2.setOwner( O2->id() );
	V2.setScript( QString( "o( %1 ).result = tostring( moo.%2.id )" ).arg( O2->id() ).arg( pType ) );

	O2->verbAdd( "test", V2 );

	// Call test

	TD.execute( QString( ";o( %1 ):test()" ).arg( O1->id() ) );

	// Check result

	QVariant R = O2->propValue( "result" );

	QCOMPARE( R.toString(), QString( "%1" ).arg( pResult ) );
}

void TestLuaCallValues::luaCallValueInherit()
{
	LuaTestData			 TD;

	TD.Programmer->setWizard( false );

	Object			*Root = TD.OM.rootObject();

	Root->propAdd( "result", "no result", Root->id() );

	Root->prop( "result" )->setChange( false );

	Object			*O1 = TD.OM.object( 2 );

	if( true )
	{
		Verb			V;

		V.initialise();

		V.setDirectObjectArgument( NONE );
		V.setIndirectObjectArgument( NONE );
		V.setPrepositionArgument( NONE );

		V.setScript( QString( "moo.object.result = tostring( %1 )" ).arg( 23 ) );

		V.setOwner( Root->id() );

		Root->verbAdd( "test", V );
	}

	lua_task T  = TD.execute( QString( ";o( %1 ):test()" ).arg( O1->id() ) );

	QCOMPARE( T.error(), false );

	QCOMPARE( O1->propValue( "result" ).toString(), QString( "23" ) );
}

QTEST_GUILESS_MAIN( TestLuaCallValues )

#include "tst_lua_call_values.moc"
<|endoftext|>