
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_ServerEntity_Teleporter.cpp
// Author : Andy Tate
// Date   : 27-Feb-2007
//
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

#if !defined(ASURA_DONT_USE_TELEPORTERS)

// This file's header...
#include "Entity/Intangible/Asura_ServerEntity_Teleporter.h"

// Asura independent header-files...
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Entity/Asura_Entity_Classification.h"
#include "Entity/Spawners/Asura_ServerEntity_TeleportDestination.h"
#include "Network/Asura_Message.h"
#include "Teleport/Asura_Teleport_Messages.h"

#if defined(ASURA_TOOLS)
// Tools header-files...
#include "EntityTemplate/Tools_EntityTemplate_System.h"
#endif	// defined(ASURA_TOOLS)


////////////////////////////////////////////////////////////////////////////////
// Static variable declarations...
////////////////////////////////////////////////////////////////////////////////

Asura_Hashed_List<Asura_ServerEntity_Teleporter>	Asura_ServerEntity_Teleporter::s_xList;


////////////////////////////////////////////////////////////////////////////////
// Private functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Protected functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ServerEntity_Teleporter::Asura_ServerEntity_Teleporter
// Author       : Andy Tate
// Date         : 28-Feb-2007
////////////////////////////////////////////////////////////////////////////////

Asura_ServerEntity_Teleporter::Asura_ServerEntity_Teleporter(const Asura_Guid uGuid)
: Asura_Entity_Server(uGuid)
, m_uFlags(0)
, m_fFadeOutDuration(0.250f)
, m_fFadeInDuration(0.250f)
, m_uFadeColour(0xFF000000)
{
	Classification	= AsuraEntityClass_Teleporter;
	m_bPerformFade	= true;

	for(u_int u = 0; u < ASURA_TELEPORTER_ENTITY_MAX_DESTINATIONS; ++u)
	{
		m_auDestinationGuids[u]	= ASURA_GUID_UNREGISTERED;
	}

	SetNeverUpdateClient();
	s_xList.AddToList(this);
}

/// End of function 'Asura_ServerEntity_Teleporter::Asura_ServerEntity_Teleporter'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ServerEntity_Teleporter::~Asura_ServerEntity_Teleporter
// Author       : Andy Tate
// Date         : 28-Feb-2007
////////////////////////////////////////////////////////////////////////////////

Asura_ServerEntity_Teleporter::~Asura_ServerEntity_Teleporter()
{
	s_xList.RemoveFromList(this);
}

/// End of function 'Asura_ServerEntity_Teleporter::~Asura_ServerEntity_Teleporter'. ///



////////////////////////////////////////////////////////////////////////////////
// Public functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ServerEntity_Teleporter::Create
// Author       : Andy Tate
// Date         : 28-Feb-2007
////////////////////////////////////////////////////////////////////////////////

Asura_ServerEntity_Teleporter* Asura_ServerEntity_Teleporter::Create(const Asura_Guid uGuid)
{
	return(new Asura_ServerEntity_Teleporter(uGuid));
}

/// End of function 'Asura_ServerEntity_Teleporter::Create'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ServerEntity_Teleporter::ReadFromChunkStream
// Author       : Andy Tate
// Date         : 28-Feb-2007
////////////////////////////////////////////////////////////////////////////////

void Asura_ServerEntity_Teleporter::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	u_int	uVersion;

	// Check the version
	xStream >> uVersion;

	if(uVersion > uTELEPORT_CHUNK_VERSION)
	{
		Asura_Assertf(false, ("Unexpected chunk-version for teleporter - aborting read."));
		return;
	}

	if (uVersion >= 1)
	{
		PARENT::ReadFromChunkStream(xStream);
	}

	Asura_ReadFromStream_Bitfield_Wrapper<u_int> xBitfield(m_uFlags);
	xStream >> xBitfield;
	xStream >> m_fFadeOutDuration;
	xStream >> m_fFadeInDuration;
	xStream >> m_uFadeColour;

	////////////////////////////////////////////////////////////////////////////////
	// NOTE: Always read the Guids last for cross-project compatability...
	////////////////////////////////////////////////////////////////////////////////
	u_int uNumDestinationGuids;
	xStream >> uNumDestinationGuids;

	for(u_int u = 0; u < uNumDestinationGuids; ++u)
	{
		if ( u < ASURA_TELEPORTER_ENTITY_MAX_DESTINATIONS)
		{
			xStream >> m_auDestinationGuids[u];
		}
		else
		{
			u_int uDummy;
			xStream >> uDummy;
		}
	}

	for(u_int u = uNumDestinationGuids; u < ASURA_TELEPORTER_ENTITY_MAX_DESTINATIONS; ++u)
	{
		m_auDestinationGuids[u]	= ASURA_GUID_UNREGISTERED;
	}

	SetNeverUpdates(true);
}

/// End of function 'Asura_ServerEntity_Teleporter::ReadFromChunkStream'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ServerEntity_Teleporter::WriteToChunkStream
// Author       : Andy Tate
// Date         : 28-Feb-2007
////////////////////////////////////////////////////////////////////////////////

void Asura_ServerEntity_Teleporter::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{

	// Write the version...
	xStream << uTELEPORT_CHUNK_VERSION;

	PARENT::WriteToChunkStream(xStream);

	// Write the data...
	Asura_WriteToStream_Bitfield_Wrapper<u_int> xBitfield(m_uFlags);
	xBitfield.Add(m_bActive, 1);
	xBitfield.Add(m_bPerformFade, 1);
	xStream << xBitfield;
	xStream << m_fFadeOutDuration;
	xStream << m_fFadeInDuration;
	xStream << m_uFadeColour;

	////////////////////////////////////////////////////////////////////////////////
	// NOTE: Always write the Guids last for cross-project compatability...
	////////////////////////////////////////////////////////////////////////////////
	const u_int uNumDestinationGuids = ASURA_TELEPORTER_ENTITY_MAX_DESTINATIONS;
	xStream << uNumDestinationGuids;
	for(u_int u = 0; u < uNumDestinationGuids; ++u)
	{
		xStream << m_auDestinationGuids[u];
	}
}

/// End of function 'Asura_ServerEntity_Teleporter::WriteToChunkStream'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ServerEntity_Teleporter::SetActive
// Author       : Andy Tate
// Date         : 27-Feb-2007
////////////////////////////////////////////////////////////////////////////////

bool Asura_ServerEntity_Teleporter::SetActive(const bool bActive)
{
	if(IsActive() == bActive)
	{
		return(false);
	}
	else
	{
		m_bActive	= bActive;
		return(true);
	}
}

/// End of function 'Asura_ServerEntity_Teleporter::SetActive'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ServerEntity_Teleporter::HandleMessage
// Author       : Andy Tate
// Date         : 27-Feb-2007
////////////////////////////////////////////////////////////////////////////////

bool Asura_ServerEntity_Teleporter::HandleMessage(const Asura_Message* pxMessage)
{
	switch(pxMessage->GetMsgID())
	{
		case ASURA_MSG_ACTIVATE:
		{
			SetActive(true);
			return(true);
		}

		case ASURA_MSG_DEACTIVATE:
		{
			SetActive(false);
			return(true);
		}

		case ASURA_MSGID_TELEPORT_ENTITY:
		{
			if(IsActive())
			{
				const Asura_Message_TeleportEntity* pxData = static_cast<const Asura_Message_TeleportEntity*>(pxMessage->GetData());

				if(pxData != NULL)
				{
					const Asura_Guid	uGuidToTeleport		= pxData->GetGuidToTeleport();
					const Asura_Guid	uDestinationGuid	= m_auDestinationGuids[0];

					// Teleport the specified entity to the first start-point...
					Asura_Teleport_System::TeleportEntity(uGuidToTeleport, uDestinationGuid);
				}
			}
			return(true);
		}

		case ASURA_MSG_TRIGGER:
		{
			if(IsActive())
			{
				Asura_Message*	pxTeleportMessage	= Asura_Network::CreateMessage(ASURA_MSGID_BEGIN_PLAYER_TELEPORT, sizeof(Asura_Message_BeginPlayerTeleport));

				// This is now done by setting a flag in the game core, using the following message
				if(pxTeleportMessage != NULL)
				{
					Asura_Message_BeginPlayerTeleport*	pxData	= static_cast<Asura_Message_BeginPlayerTeleport*>(pxTeleportMessage->GetData());

					if(pxData != NULL)
					{
						// Generate the message...
						pxData->Reset();

						if(m_bPerformFade)
						{
							pxData->SetFadeColour(m_uFadeColour);
							pxData->SetFadeInDuration(m_fFadeInDuration);
							pxData->SetFadeOutDuration(m_fFadeOutDuration);
						}
						else
						{
							pxData->SetFadeColour(0x00000000);
						}

						for(u_int u = 0; u < ASURA_TELEPORTER_ENTITY_MAX_DESTINATIONS; ++u)
						{
							const Asura_Guid								uDestinationGuid	= m_auDestinationGuids[u];
							const Asura_ServerEntity_TeleportDestination*	pxDestinationEntity	= Asura_ServerEntity_TeleportDestination::FindEntity(uDestinationGuid);

							if(pxDestinationEntity != NULL)
							{
								const Asura_Vector_3&	xPosition		= pxDestinationEntity->GetPosition();
								const Asura_Quat&		xOrientation	= pxDestinationEntity->GetOrientation();

								// ...generate the packet-data for our client-machines...
								pxData->SetDestinationData(u, xPosition, xOrientation);
							}
						}
					}

					pxTeleportMessage->UseGuaranteedDelivery();
					Send(pxTeleportMessage, ASURA_GUID_ALL_CLIENTMACHINES);
				}
			}
			return(true);
		}

		default:
		{
			return(PARENT::HandleMessage(pxMessage));
		}
	}		// End of switch.
}

/// End of function 'Asura_ServerEntity_Teleporter::HandleMessage'. ///


#if defined(ASURA_TOOLS)

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ServerEntity_Teleporter::ApplyChangesForTemplateInstance
// Author       : Andy Tate
// Date         : 7-Mar-2007
////////////////////////////////////////////////////////////////////////////////

void Asura_ServerEntity_Teleporter::ApplyChangesForTemplateInstance(Tools_EntityTemplateInstance* pxInstance)
{
	// Call the base-function...
	PARENT::ApplyChangesForTemplateInstance(pxInstance);

	// Convert our GUIDs accordingly...
	for(u_int u = 0; u < ASURA_TELEPORTER_ENTITY_MAX_DESTINATIONS; ++u)
	{
		if(m_auDestinationGuids[u] != ASURA_GUID_UNREGISTERED)
		{
			m_auDestinationGuids[u]	= pxInstance->ConvertGuid(m_auDestinationGuids[u]);
		}
	}
}

/// End of function 'Asura_ServerEntity_Teleporter::ApplyChangesForTemplateInstance'. ///

#endif	// defined(ASURA_TOOLS)

#endif	// !defined(ASURA_DONT_USE_TELEPORTERS)


/// End of file. ///
