//
// Asura_Chunk_Entity.cpp
//
// Created by Richard Rice - 30/04/2002
// 
// Copyright (C) 2002 Rebellion, All Rights Reserved.
//


#include "Core/Asura.h"

// This file's header.
#include "ChunkSystem/Asura_Chunk_Entity.h"

// Engine independent.
#include "Animation/Asura_TextureAnimation.h"
#include "Core/Asura_PlatformBasics.h"
#ifdef ASURA_TOOLS
#include "Core/Asura_TextureManagement.h"
#endif
#include "Core/Memory/Asura_Mem.h"
#include "ChunkSystem/Asura_Chunk_Cutscene.h"
#include "ChunkSystem/Asura_Chunk_Loaders.h"
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "ChunkSystem/Asura_Chunk_Texture.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "Core/Asura_NameTree.h"
#include "Core/Memory/Asura_ResourceAllocator.h"
#include "Cutscene/Asura_Cutscene_System.h"
#include "Debugging/Asura_Assert.h"
#include "Entity/Asura_Entity.h"
#include "Entity/Asura_Entity_Classification.h"
#include "Entity/Asura_StaticMessage_System.h"
#if defined(ASURA_USE_AFFECTORS)
#include "Entity/Affector/Asura_ServerEntity_Affector.h"
#include "Entity/Affector/Asura_ServerEntity_Affector_Wind.h"
#endif	// defined(ASURA_USE_AFFECTORS)
#include "Entity/Animation/Asura_ServerEntity_EnvTextureAnimControl.h"
#ifdef ASURA_USE_ATTRACTORS
#include "Entity/Attractors/Asura_ServerEntity_AttractorController.h"
#endif
#ifdef ASURA_USE_CONTAINER_SYSTEM
#include "Entity/Container/Asura_Container_Messages.h"
#include "Entity/Container/Asura_ServerEntity_Container.h"
#endif //#ifdef ASURA_USE_CONTAINER_SYSTEM
#include "Entity/Cutscene/Asura_ServerEntity_CutsceneController.h"

#ifdef ASURA_USE_VIDEO_TO_TEXTURE_SYSTEM
#include "Entity/FMVController/Asura_FMVController_Messages.h"

#include "Entity/FMVController/Asura_ClientEntity_FMVController.h"
#include "Entity/FMVController/Asura_ServerEntity_FMVController.h"

#include "Entity/FMVController/Asura_ClientEntity_FMVSpeaker.h"
#include "Entity/FMVController/Asura_ServerEntity_FMVSpeaker.h"
#endif

#if !defined(ASURA_DONT_USE_TELEPORTERS)
#include "Entity/Intangible/Asura_ServerEntity_Teleporter.h"
#include "Entity/Spawners/Asura_ServerEntity_TeleportDestination.h"
#endif	// !defined(ASURA_DONT_USE_TELEPORTERS)
#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
#include "Entity/Intangible/Asura_ClientEntity_ConsoleVar.h"
#include "Entity/Intangible/Asura_ServerEntity_ConsoleVar.h"
#endif //ASURA_SUPPORT_COMMAND_CONSOLE
#include "Entity/Intangible/Asura_ServerEntity_ForceField_Conveyor.h"
#include "Entity/Locations/Asura_ServerEntity_Node.h"
#include "Entity/Locations/OrientedNode/Asura_ServerNode_OrientedNode.h"
#include "Entity/Locations/Spline/Asura_ServerNode_Spline.h"
#include "Entity/Locations/OrientedNode/LiftNode/Asura_ServerNode_LiftNode.h"
#include "Entity/Locations/Spline/LiftSpline/Asura_ServerNode_LiftSpline.h"
#ifdef ASURA_USE_AXON
#include "Core/Axon_Messages.h"
#include "Entity/Locations/GuardZone/Asura_ServerNode_GuardZone.h"
#include "Entity/Locations/OrientedNode/CoverpointNode/Asura_ServerNode_Coverpoint.h"
#ifdef ASURA_USE_GAMESCENE
#include "Entity/Locations/OrientedNode/GamesceneNode/Asura_ServerNode_GamesceneNode.h"
#include "Entity/Locations/OrientedNode/GamesceneNode/AttractorNode/Asura_ServerNode_GamesceneAttractor.h"
#include "Entity/Locations/Spline/GamesceneSpline/Asura_ServerNode_GamesceneSpline.h"
#endif
#include "Entity/Locations/OrientedNode/GamesceneNode/Asura_ServerNode_GS2Node.h"
#include "Entity/Locations/OrientedNode/GamesceneNode/AttractorNode/Asura_ServerNode_GS2Attractor.h"
#include "Entity/Locations/Spline/GamesceneSpline/Asura_ServerNode_GS2Spline.h"
#endif
#include "Entity/Objective/Asura_ServerEntity_Objective.h"
#include "Entity/ParticleGenerator/Asura_ServerEntity_PFX_Effect.h"
#include "Entity/ParticleGenerator/Asura_ClientEntity_PFX_Effect.h"
#include "Entity/PhysicalObject/Asura_ApplyForce_Messages.h"
#include "Entity/Sound/Asura_ServerEntity_StreamingBackgroundSoundController.h"
#include "Entity/Spawners/Asura_ServerEntity_StartPoint.h"
#include "Entity/Spawners/Asura_ClientEntity_StartPoint.h"
#include "Entity/Triggers/Asura_ClientEntity_SoundController.h"
#include "Entity/Triggers/Asura_ServerEntity_AdvancedVolumeTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_ClockTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_CountedTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_DynamicMusicTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_SoundController.h"
#include "Entity/Triggers/Asura_ServerEntity_SplitterBlock.h"
#include "Entity/Triggers/Asura_ServerEntity_TimeTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_TimelineTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_MusicTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_MetaMusicTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_FMVTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_LookAtTrigger.h"
#include "Entity/Triggers/Asura_ClientEntity_LookAtTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_LogicTrigger.h"
#include "Entity/Triggers/Asura_ClientEntity_ClientVolumeTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_ClientVolumeTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_ProxyTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_WaypointBlockerVolume.h"
#include "Entity/Triggers/EffectVolume/Asura_ServerEntity_EffectVolume.h"
#ifdef ASURA_USE_DIALOGUE_SYSTEM
#include "Entity/Triggers/Asura_ServerEntity_DialogueTrigger.h"
#include "Entity/Sound/Asura_ServerEntity_DialogueController.h"
#endif // #ifdef ASURA_USE_DIALOGUE_SYSTEM
#include "Entity/EntityTemplate/Asura_ServerEntity_Template.h"

#include "FileAccess/Asura_FileAccess.h"
#include "FSFX/Asura_FSFX_System.h"

#ifdef ASURA_USE_GUI_MENU_SYSTEM
//#include "GUIMenu/Asura_GUIMenu_Message.h"
#include "GUIMenu/Asura_GUIMenu_System.h"
#endif
#include "Network/Asura_Network.h"
#include "Sound/Asura_Sound_Mixer.h"
#ifdef ASURA_USE_METAMUSICZONES
#include "Sound/Asura_MetaMusic_System.h"
#endif //ASURA_USE_METAMUSICZONES
// For messages
#include "Entity/PhysicalObject/Asura_ServerEntity_Lift.h"
#include "Entity/PhysicalObject/Asura_ServerEntity_PhysicalObject.h"
#include "Entity/Glass/Asura_Entity_Glass_Messages.h"

#ifdef ASURA_USE_DEBUG_MESSAGE_TRIGGER
#include "Entity/Triggers/Asura_ServerEntity_DebugMessageTrigger.h"
#include "Entity/Triggers/Asura_ServerEntity_DebugWaypointTrigger.h"
#endif // ASURA_USE_DEBUG_MESSAGE_TRIGGER

#include "Sound/Asura_Sound.h"
#ifdef ASURA_USE_DIALOGUE_SYSTEM
#include "Sound/Asura_Dialogue.h"
#include "Sound/Asura_Dialogue_System.h"
#endif
#include "Sound/Asura_Sound.h"
#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
#include "Sound/Asura_Dynamic_Music_System.h"
#endif

#if defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)
#include "Streaming/Asura_Streaming_System.h"
#endif	// defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)
#if !defined(ASURA_DONT_USE_TELEPORTERS)
#include "Teleport/Asura_Teleport_Messages.h"
#endif	// !defined(ASURA_DONT_USE_TELEPORTERS)

#ifdef ASURA_TARGET_SM3
#include "Entity/DynamicLight/Asura_DynamicLight_Messages.h"
#endif

// Tools.
#ifdef ASURA_TOOLS
#include "Entity/Tools_Entity_Data.h"
#include "Entity/Tools_SecondaryEntityFile_System.h"
#endif

#ifdef ASURA_TARGET_SM3
#include "Entity/Projector/Asura_ServerEntity_Projector.h"
#include "Entity/Projector/Asura_ClientEntity_Projector.h"
#include "Entity/DynamicLight/Asura_ServerEntity_DynamicLight.h"
#include "Entity/DynamicLight/Asura_ClientEntity_DynamicLight.h"
#include "Entity/LightShaft/Asura_ServerEntity_LightShaft.h"
#include "Entity/LightShaft/Asura_ClientEntity_LightShaft.h"
#endif

#if defined(ASURA_MEMORYMANAGEMENT_FILL)
DEBUGVAR bool	dbg_bCheckGuardBytesForEveryChunkEntity	= false;
#endif	//defined(ASURA_MEMORYMANAGEMENT_FILL)

///////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------**
** Asura_Chunk_Entity **
**--------------------*/

bool Asura_Chunk_Entity::Process( const char* pcChunkBuffer ) const
{
	Asura_Chunk_ChunkBuffer_Stream	xStream(pcChunkBuffer);
	const char* const	pcChunkBufferStart	= pcChunkBuffer;
#if defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS) && !defined(ASURA_TOOLS)
	const Asura_Guid	uGuid				= Asura_Streaming_System::MakeCurrentMasterZoneGuid(Guid);
#else
	const Asura_Guid	uGuid				= Guid;
#endif	// defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS) && !defined(ASURA_TOOLS)

#if defined(ASURA_TOOLS)
	/// Richard May - 29/11/2002 17:56:35 - gated this function as it might not be a tools-created entity!
	if( (uGuid >= ASURA_GUID_TOOLSCREATEDENTITY_START) && (uGuid <= ASURA_GUID_TOOLSCREATEDENTITY_END) )
	{
		Asura_Entity_System::RegisterToolsGuid(uGuid);
	}
	else
#endif	// defined(ASURA_TOOLS)
	{
		if( uGuid >= ASURA_GUID_GAMECREATEDENTITY_START )
		{
			// if it's _not_ a tools created entity, we need to register it as a game created entity
			Asura_Entity_System::RegisterGameCreatedGuid(uGuid);			
		}
	}

	if( Asura_Network::IsServer() && !(Flags & ChunkFlag_ClientOnly))
	{
		bool bParseChunk = true;
		//Make sure the entity doesn't already exist.
		Asura_Entity_Server* pxExistingEntity = Asura_Entity_Server::FindEntity(uGuid);
		if(pxExistingEntity)
		{
			if(pxExistingEntity->AllowOverwriteOnLoad())
			{
				if(Classification != pxExistingEntity->GetClassification())
				{
					Asura_Assertf(false, ("Server entity with uGuid %d already exists , and has a different classification- ignoring subsequent occurences of this entity. Old classification: %d; New Classification: %d", uGuid, pxExistingEntity->GetClassification(), Classification ));
					bParseChunk = false;
				}
			}
			else
			{
				Asura_Assertf(false, ("Server entity with uGuid %d already exists - ignoring subsequent occurences of this entity. Old classification: %d; New Classification: %d", uGuid, pxExistingEntity->GetClassification(), Classification ));
				bParseChunk = false;
			}
		}

		if ( bParseChunk && !Project_Process(pcChunkBuffer) )
		{
			//create the appropriate entity type
			switch(Classification)
			{
				case AsuraEntityClass_VolumeTriggerRedundant:
					Asura_Assert(false, "The old volume trigger class is now redundant");
					break;

				case AsuraEntityClass_TimeTrigger:
					Asura_ServerEntity_TimeTrigger::CreateFromChunkBuffer(uGuid,pcChunkBuffer);
					break;

				case AsuraEntityClass_TimelineTrigger:
					Asura_ServerEntity_TimelineTrigger::CreateFromChunkStream(uGuid, xStream);
					break;

				case AsuraEntityClass_CutsceneController:
					Asura_ServerEntity_CutsceneController::CreateFromChunkBuffer(uGuid,pcChunkBuffer);
					break;

				case AsuraEntityClass_SplitterBlock:
					Asura_ServerEntity_SplitterBlock::CreateFromChunkStream(uGuid, xStream);
					break;

				case AsuraEntityClass_CountedTrigger:
					Asura_ServerEntity_CountedTrigger::CreateFromChunkStream(uGuid, xStream);
					break;

				case AsuraEntityClass_SoundController:
					Asura_ServerEntity_SoundController::CreateFromChunkStream(uGuid, xStream);
					break;

#if !defined(ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM)
				case AsuraEntityClass_MusicTrigger:
					Asura_ServerEntity_MusicTrigger::CreateFromChunkBuffer(uGuid,pcChunkBuffer);
					break;

				case AsuraEntityClass_MetaMusicTrigger:
					Asura_ServerEntity_MetaMusicTrigger::CreateFromChunkBuffer(uGuid,pcChunkBuffer);
					break;
#endif	//!defined(ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM)

				case AsuraEntityClass_FMVTrigger:
					Asura_ServerEntity_FMVTrigger::CreateFromChunkBuffer(uGuid,pcChunkBuffer);
					break;

				case AsuraEntityClass_Template:
					Asura_ServerEntity_Template::CreateFromChunkStream(uGuid, xStream);
					break;

				case AsuraEntityClass_LookAtTrigger:
					Asura_ServerEntity_LookAtTrigger::CreateFromChunkStream(uGuid, xStream);
					break;

				case AsuraEntityClass_ClockTrigger:
					Asura_ServerEntity_ClockTrigger::CreateFromChunkBuffer(uGuid, pcChunkBuffer);
					break;

				case AsuraEntityClass_PFX_Effect:
					Asura_ServerEntity_PFX_Effect::CreateFromChunkStream(uGuid, xStream);
					break;

				case AsuraEntityClass_LogicTrigger:
					Asura_ServerEntity_LogicTrigger::Create(uGuid, xStream);
					break;

				case AsuraEntityClass_ClientVolumeTrigger :
					Asura_ServerEntity_ClientVolumeTrigger::CreateFromChunkBuffer(uGuid,pcChunkBuffer);
					break;

				case AsuraEntityClass_StartPoint:
				{
					Asura_ServerEntity_StartPoint::Create( uGuid, xStream );
					break;
				}

				case AsuraEntityClass_EnvTextureAnimControl :
					Asura_ServerEntity_EnvTextureAnimControl::CreateFromChunkBuffer(uGuid, pcChunkBuffer);
					break;

#ifdef ASURA_USE_DEBUG_MESSAGE_TRIGGER
				case AsuraEntityClass_DebugMessageTrigger:
					Asura_ServerEntity_DebugMessageTrigger::Create( uGuid, xStream );
					break;
				case AsuraEntityClass_DebugWaypointTrigger:
					Asura_ServerEntity_DebugWaypointTrigger::Create( uGuid, xStream );
					break;
#endif // ASURA_USE_DEBUG_MESSAGE_TRIGGER

				case AsuraEntityClass_ProxyTrigger :
					Asura_ServerEntity_ProxyTrigger::Create(uGuid, xStream);
					break;

                case AsuraEntityClass_Node:
                    Asura_ServerEntity_Node::CreateFromChunkStream(uGuid, xStream);
                    break;

                case AsuraEntityClass_OrientedNode:
                    Asura_ServerNode_OrientedNode::CreateFromChunkStream(uGuid, xStream);
                    break;

                case AsuraEntityClass_Spline:
                    Asura_ServerNode_Spline::CreateFromChunkStream(uGuid, xStream);
                    break;

                case AsuraEntityClass_LiftNode:
                    Asura_ServerNode_LiftNode::CreateFromChunkStream(uGuid, xStream);
                    break;

                case AsuraEntityClass_LiftSpline:
                    Asura_ServerNode_LiftSpline::CreateFromChunkStream(uGuid, xStream);
                    break;

#ifdef ASURA_USE_AXON
#ifdef ASURA_USE_GAMESCENE
                case AsuraEntityClass_GamesceneNode:
					Asura_ServerNode_GamesceneNode::CreateFromChunkStream(uGuid, xStream);
                    break;

				case AsuraEntityClass_AttractorNode:
					Asura_ServerNode_GamesceneAttractor::CreateFromChunkStream(uGuid, xStream);
					break;

				case AsuraEntityClass_GamesceneSpline:
					Asura_ServerNode_GamesceneSpline::CreateFromChunkStream(uGuid, xStream);
					break;

				case AsuraEntityClass_GamesceneBase:
					break;
#endif // ASURA_USE_GAMESCENE

                case AsuraEntityClass_CoverpointNode:
                    Asura_ServerNode_Coverpoint::CreateFromChunkStream(uGuid, xStream);
                    break;

                case AsuraEntityClass_GuardZone:
                    Asura_ServerNode_GuardZone::CreateFromChunkStream(uGuid, xStream);
                    break;

				case AsuraEntityClass_GS2Node:
					Asura_ServerNode_GS2Node::Create( uGuid, xStream );
					break;

				case AsuraEntityClass_GS2Spline:
					Asura_ServerNode_GS2Spline::Create( uGuid, xStream );
					break;

				case AsuraEntityClass_GS2Attractor:
					Asura_ServerNode_GS2Attractor::Create( uGuid, xStream );
					break;
#endif // ASURA_USE_AXON

#ifdef ASURA_USE_DIALOGUE_SYSTEM
				case AsuraEntityClass_DialogueTrigger:
					Asura_ServerEntity_DialogueTrigger::CreateFromChunkBuffer(uGuid, pcChunkBuffer);
					break;

				case AsuraEntityClass_DialogueController:
					Asura_ServerEntity_DialogueController::CreateFromChunkStream(uGuid, xStream);
					break;
#endif // #ifdef ASURA_USE_DIALOGUE_SYSTEM

#if defined(ASURA_USE_AFFECTORS)
				case AsuraEntityClass_Affector:
					Asura_ServerEntity_Affector::Create(uGuid, xStream);
					break;

				case AsuraEntityClass_Affector_Wind:
					Asura_ServerEntity_Affector_Wind::Create(uGuid, xStream);
					break;
#endif	// defined(ASURA_USE_AFFECTORS)

#ifdef ASURA_TARGET_SM3
				case AsuraEntityClass_Projector :
					Asura_ServerEntity_Projector::CreateFromChunkStream(Guid, xStream);
					break;

				case AsuraEntityClass_DynamicLight :
					Asura_ServerEntity_DynamicLight::CreateFromChunkStream(Guid, xStream);
					break;

				case AsuraEntityClass_LightShaft :
					Asura_ServerEntity_LightShaft::CreateFromChunkStream(Guid, xStream);
					break;
#endif

#if !defined(ASURA_DONT_USE_TELEPORTERS)
				case AsuraEntityClass_Teleporter:
				{
					Asura_Entity_Server*	pxServerEntity	= Asura_ServerEntity_Teleporter::Create(Guid);
					pxServerEntity->ReadFromChunkStream(xStream);
					break;
				}

				case AsuraEntityClass_TeleportDestination:
				{
					Asura_Entity_Server*	pxServerEntity	= Asura_ServerEntity_TeleportDestination::Create(Guid);
					pxServerEntity->ReadFromChunkStream(xStream);
					break;
				}
#endif	// !defined(ASURA_DONT_USE_TELEPORTERS)

				case AsuraEntityClass_ForceField_Conveyor:
				{
					Asura_ServerEntity_ForceField_Conveyor::Create(Guid, xStream);
					break;
				}

#ifdef ASURA_USE_ATTRACTORS
				case AsuraEntityClass_AttractorController :
				{
					Asura_ServerEntity_AttractorController::Create(Guid , xStream);					
					break;
				}
#endif //ASURA_USE_ATTRACTORS

#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
				case AsuraEntityClass_ConsoleVar:
				{
					Asura_Entity_Server* pxServerEntity = new Asura_ServerEntity_ConsoleVar(Guid);
					pxServerEntity->ReadFromChunkStream(xStream);
					break;
				}
#endif //ASURA_SUPPORT_COMMAND_CONSOLE

				case AsuraEntityClass_StreamingBackgroundSoundController :
				{
					Asura_ServerEntity_StreamingBackgroundSoundController::Create(Guid , xStream);					
					break;
				}

				case AsuraEntityClass_WaypointBlockerVolume:
				{
					Asura_ServerEntity_WaypointBlockerVolume::Create( uGuid, xStream );
					break;
				}

				case AsuraEntityClass_Objective:
				{
					Asura_ServerEntity_Objective::Create( uGuid, xStream );
					break;
				}

#ifdef ASURA_USE_CONTAINER_SYSTEM
				case AsuraEntityClass_Container:
				{
					Asura_ServerEntity_Container::Create( uGuid, xStream );
					break;
				}
#endif //#ifdef ASURA_USE_CONTAINER_SYSTEM
				
#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
				case AsuraEntityClass_DynamicMusicTrigger:
				{
					Asura_ServerEntity_DynamicMusicTrigger::CreateFromChunkStream(uGuid, xStream);
					break;
				}
#endif
				case AsuraEntityClass_EffectVolume:
				{
					Asura_ServerEntity_EffectVolume::CreateFromChunkStream(uGuid, xStream);
					break;
				}

#ifdef ASURA_USE_VIDEO_TO_TEXTURE_SYSTEM
				case AsuraEntityClass_FMVController:
				{
					Asura_ServerEntity_FMVController::CreateFromChunkStream(uGuid, xStream);
					break;
				}

				case AsuraEntityClass_FMVSpeaker:
				{
					Asura_ServerEntity_FMVSpeaker::CreateFromChunkStream(uGuid, xStream);
					break;
				}
#endif

				default: 
				{
					Asura_Assertf(false,("Unknown entity type %s while loading chunk data, guid: %u", 
									Asura_Network::GetEntityClassificationDesc(Classification), Guid ) ); 
					break;
				}
			}	// End of switch.
		}

#if defined(ASURA_MEMORYMANAGEMENT_FILL)
		if(dbg_bCheckGuardBytesForEveryChunkEntity)
		{
			Asura_MemoryManagement_System::CheckMallocGuardBytes();
		}
#endif	//defined(ASURA_MEMORYMANAGEMENT_FILL)
	}

	/// DWE - 31/07/2003 16:17:32 - Glass is a special case (oh yay)
	/// It has server entities on all machines (including clients. 
	/// so they can access all the initialisation data (texture name... etc.)
	/// without it sending a big fat message everytime it is created
	/// Think of it like the shape table for shapes, it exists on all machines for
	/// reference when creating the entities.
	if(Classification == AsuraEntityClass_Glass && !Asura_Network::IsServer())
	{
		Project_Process(pcChunkBuffer);
	}

	// Most entities get created via a server-message.
	// Only (fairly) static entities like glass are likely to be initialised
	// here. aw.
	// MGH 26/9/02: *FIXME* Note: doing this breaks multiplayer games, as the glass etc 
	// may have been destroyed by the time the player connects.
	pcChunkBuffer = pcChunkBufferStart;
	if( Asura_Network::IsClient() && !(Flags & ChunkFlag_ServerOnly))
	{
		bool bParseChunk = true;
		//Make sure the entity doesn't already exist.
		Asura_Entity_Client* pxExistingEntity = Asura_Entity_Client::FindEntity(uGuid);
		if(pxExistingEntity)
		{
			if(pxExistingEntity->AllowOverwriteOnLoad())
			{
				if(Classification != pxExistingEntity->GetClassification())
				{
					Asura_Assertf(false, ("Client entity with uGuid %d already exists , and has a different classification- ignoring subsequent occurences of this entity. Old classification: %d; New Classification: %d", uGuid, pxExistingEntity->GetClassification(), Classification ));
					bParseChunk = false;
				}
			}
			else
			{
				Asura_Assertf(false, ("Client entity with uGuid %d already exists - ignoring subsequent occurences of this entity. Old classification: %d; New Classification: %d", uGuid, pxExistingEntity->GetClassification(), Classification ));
				bParseChunk = false;
			}
		}
		
		if ( bParseChunk )
		{
            if ( !Project_ProcessClientEntities(pcChunkBuffer) )
            {
			    switch(Classification)
			    {
				    case AsuraEntityClass_SoundController:
					{
					    Asura_Chunk_ChunkBuffer_Stream xClientStream(pcChunkBuffer);
					    Asura_ClientEntity_SoundController::CreateFromChunkStream(uGuid, xClientStream);
					    break;
					}

				    case AsuraEntityClass_LookAtTrigger:
					    // Since not every project is using the initial client create message sending code yet, we need some way to make sure the create message for a look-at trigger is sent.
						// The only really reliable way to do it is to send on processing this chunk.
						// Previously we created the entity at this point too, but that's pointless really and the implementation was slightly broken. Instead, just send the request.
					case AsuraEntityClass_EffectVolume: // Effect volumes also need this for the time being.
						Asura_Entity_System::SendRequestCreateMessage(uGuid, Classification);
					    break;

				    case AsuraEntityClass_PFX_Effect:
					    Asura_ClientEntity_PFX_Effect::CreateFromChunkStream(uGuid, xStream);
					    break;

				    case AsuraEntityClass_ClientVolumeTrigger:
					    new Asura_ClientEntity_ClientVolumeTrigger(uGuid,pcChunkBuffer);
					    break;

#ifdef ASURA_TARGET_SM3
				    case AsuraEntityClass_Projector:
				    {
					    // Got to create a new stream, as the xStream used for the server entity has been 'used up',
					    //  and it doesn't look like there's a stream equivalent of the 'pcChunkBuffer = pcChunkBufferStart'						
					    Asura_Chunk_ChunkBuffer_Stream xClientStream(pcChunkBuffer);
						Asura_ClientEntity_Projector::CreateFromChunkStream(uGuid,xClientStream);
                        break;
				    }

				    case AsuraEntityClass_DynamicLight:
				    {
					    Asura_Chunk_ChunkBuffer_Stream xClientStream(pcChunkBuffer);
						Asura_ClientEntity_DynamicLight::CreateFromChunkStream(uGuid,xClientStream);
                        break;
				    }

				    case AsuraEntityClass_LightShaft:
				    {
					    Asura_Chunk_ChunkBuffer_Stream xClientStream(pcChunkBuffer);
					    Asura_ClientEntity_LightShaft::CreateFromChunkStream(uGuid,xClientStream);
                        break;
				    }
#endif
				    case AsuraEntityClass_StartPoint:
				    {
					    // As project class above, we need to create a new chunk stream
					    Asura_Chunk_ChunkBuffer_Stream xClientStream(pcChunkBuffer);
					    Asura_ClientEntity_StartPoint::Create(uGuid,xClientStream);
					    break;
				    }						

#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
				    case AsuraEntityClass_ConsoleVar:
				    {
					    // We need to create a new chunk stream
					    Asura_Chunk_ChunkBuffer_Stream xClientStream(pcChunkBuffer);
					    Asura_ClientEntity_ConsoleVar::Create(uGuid, xClientStream);
					    break;
				    }
#endif //ASURA_SUPPORT_COMMAND_CONSOLE
	
#ifdef ASURA_USE_VIDEO_TO_TEXTURE_SYSTEM
					case AsuraEntityClass_FMVController:
					{
						Asura_Chunk_ChunkBuffer_Stream xClientStream(pcChunkBuffer);
						Asura_ClientEntity_FMVController::CreateFromChunkStream(uGuid, xClientStream);
						break;
					}

					case AsuraEntityClass_FMVSpeaker:
					{
						Asura_Chunk_ChunkBuffer_Stream xClientStream(pcChunkBuffer);
						Asura_ClientEntity_FMVSpeaker::CreateFromChunkStream(uGuid, xClientStream);
						break;
					}
#endif

					default:
					    break;
			    }		// End of switch.
            }

#if defined(ASURA_MEMORYMANAGEMENT_FILL)
			if(dbg_bCheckGuardBytesForEveryChunkEntity)
			{
				Asura_MemoryManagement_System::CheckMallocGuardBytes();
			}
#endif	//defined(ASURA_MEMORYMANAGEMENT_FILL)
		}
	}

	return true;
}


// copy the hack used in the FileHandle Process() function: read from stream 
// into a temp chunk buffer and call the old chunk buffer code.
bool Asura_Chunk_Entity::Process(Asura_Chunk_Stream& xStream) const
{
	int iBytesRemaining = Size - sizeof(Asura_Chunk_Entity);
	char* pcTempChunkBfr = Asura_ChunkLoading_System::Platform_GetTempChunkMemory( iBytesRemaining );

	xStream.Read( iBytesRemaining, pcTempChunkBfr );
	Process( pcTempChunkBfr );

	Asura_ChunkLoading_System::Platform_ReturnTempChunkMemory( pcTempChunkBfr );

	return true;
}


bool Asura_Chunk_Entity::Process( Asura_Handle iFileHandle ) const
{
	int iBytesRemaining = Size - sizeof(Asura_Chunk_Entity);
    char* pcTempChunkBfr = Asura_ChunkLoading_System::Platform_GetTempChunkMemory( iBytesRemaining );

    Asura_FileAccess::ReadData( iFileHandle, pcTempChunkBfr, iBytesRemaining );
    Process( pcTempChunkBfr );

	Asura_ChunkLoading_System::Platform_ReturnTempChunkMemory( pcTempChunkBfr );

	return true;
}

void Asura_Chunk_Entity::Create( Asura_Entity_Server* pxEntity, Asura_SaveBlock_Base& xSaveBlock )
{
#ifdef ASURA_TOOLS
	if(Tools_Level_Export::IsExport())
	{
		//check for entites that aren't needed in exported levels.
		if(!Tools_Level_Export::ShouldExportEntityClass(pxEntity->GetClassification()))
		{
			return;
		}
		
		if(!pxEntity->ShouldIncludeInLevelExport())
		{
			return;
		}
	}
#endif

	if(!pxEntity->CanBeSavedToChunk())
	{
		//Couple of checks in case I've failed to update entities that are supposed to be saved
		//RAR 04/10/2006
		bool bSave = false;
		#ifdef ASURA_TOOLS
		//I think any entity that gets tools data ought to be saved
		if(pxEntity->ToolsData)
		{
			Asura_Assert(0,"entity->CanBeSavedToChunk() returned false , but entity has tools data.\n Attempting to save anyway");
			bSave = true;
		}
		#endif
		if(!bSave) return;

	}

	// Is this an old-style entity?

	if (pxEntity->IsFilledFromChunkBuffer())
	{
		//Yes - find the size required
		int chunkSize =  pxEntity->GetChunkBufferSize();
		if(!chunkSize) return;
		Asura_Assert( (chunkSize & 3)==0, "Chunk size is not a multiple of 4 bytes.  This will crash on the PS2" );
		chunkSize += sizeof(Asura_Chunk_Entity);

		Asura_Chunk_Entity *chunk = (Asura_Chunk_Entity*) Asura_ChunkLoading_System::Platform_GetTempChunkMemory(chunkSize);
		if (!chunk)
		{
			return;
		}
		memset(chunk,0,sizeof(Asura_Chunk_Entity));

		//fill in the common chunk details
		chunk->ID = ASURA_CHUNK_ENTITY;
		ASURA_CHUNK_VERIFY(chunk->ID, int);
		chunk->Size = chunkSize;
		ASURA_CHUNK_VERIFY(chunk->Size, int);
		chunk->Version = CURRENT_CHUNK_VERSION;
		ASURA_CHUNK_VERIFY(chunk->Version, int);
		chunk->Flags = 0;
		if(pxEntity->IsChunkBufferServerOnly())
		{
			chunk->Flags |= ChunkFlag_ServerOnly;
		}
		ASURA_CHUNK_VERIFY(chunk->Flags, int);

		//and the common entity stuff
		chunk->Guid = pxEntity->GetGuid();
		ASURA_CHUNK_VERIFY(chunk->Guid, Asura_Guid);
		chunk->Classification = pxEntity->GetClassification();
		ASURA_CHUNK_VERIFY(chunk->Classification, unsigned short);
		chunk->m_usPadding = 0;

		char* chunkBuffer = (char*)(chunk+1);

		//and the rest
		pxEntity->FillInChunkBuffer(chunkBuffer);

		// MGH 2/10/02: Make sure that GetChunkBufferSize and FillInChunkBuffer agree
		// about how much data is being written out.
		Asura_Assert(int(chunkBuffer - (char*)(chunk))==chunkSize,"GetChunkBufferSize returned incorrect value");
		
		// write the chunk buffer to the save block
		xSaveBlock.AddData(chunk, chunkSize);

		Asura_ChunkLoading_System::Platform_ReturnTempChunkMemory(reinterpret_cast<char*>(chunk));
		chunk = NULL;

#ifdef _DEBUG
		// The plan is to get rid of chunk buffers, so print a message if this classification is different 
		// from the last reported one. Entities are sorted in the save block so this should result in exactly 
		// one message per classification.
		u_short usClassification = pxEntity->GetClassification();
		static u_short usLastClassification = AsuraEntityClass_NotSet;
		if (usLastClassification != usClassification)
		{
			Asura_OutputToDebugger(("old-style chunk data for entity type %s\n", 
				Asura_Network::GetEntityClassificationDesc(usClassification)));
			usLastClassification = usClassification;
		}
#endif
	}
    else
	{
		Asura_Chunk_SaveBlock_Stream	xStream(&xSaveBlock);

		u_int uChunkFlags = 0;
		if(pxEntity->IsChunkBufferServerOnly())
		{
			uChunkFlags |= ChunkFlag_ServerOnly;
		}

		// Begin writing the chunk...
		xStream.WriteChunk_Start(ASURA_CHUNK_ENTITY, CURRENT_CHUNK_VERSION, uChunkFlags);

		// ...and the common entity stuff...
		xStream << pxEntity->GetGuid();
		xStream << pxEntity->GetClassification();

        // We shouldn't need any further padding, but in case something changes...
        xStream.Write4BytePadding();

		// Write the entity data itself...
		pxEntity->WriteToChunkStream(xStream);
		xStream.Write4BytePadding();

		// Finally, end writing this chunk...
		xStream.WriteChunk_End();
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////
/*------------------------------**
** Asura_Chunk_Entity_ToolsData **
**------------------------------*/

// Version history
// 1: Added m_xComment
// 2: Added scale
// 3: Secondary entity data
// 4: Added m_xOrientation
// 5: Added m_uPlatforms flag
// 6: Replaced uniform scale with non-uniform scale
// 7: Added m_uLightSets flag
// 8: Added m_uParentTemplate
// 9: Added m_uProjectFlags
// 10: Added m_xEntityBrowserPath
// 11: Added m_xCreationData and m_xLastModified strings to Tools data (AN 31/03/09)

#define ASURA_CHUNK_ENTITY_TOOLSDATA_VERSION 11

bool Asura_Chunk_Entity_ToolsData::Process(const char* chunkBuffer,struct Tools_Entity_Data* pxToolsData /*= 0*/) const
{
	#ifdef ASURA_TOOLS
	Asura_Assert(Version<=ASURA_CHUNK_ENTITY_TOOLSDATA_VERSION,"Unknown chunk version");

	// tools must be configured as a server for entity editing to work
	if (Asura_Network::IsServer())
	{

		//If no toolsdata pointer has been passed , then find the entity that it should be attached to
		if(!pxToolsData)
		{
			//find the entity
			Asura_Entity_Server* entity = Asura_Entity_Server::FindEntity(Guid);
			Asura_Assertf(entity,("Failed to find the entity to attach tools data. This may happen if the entity type is no longer valid.\nName : %s\nGuid : %u",chunkBuffer,Guid));
			
			if(entity)
			{
				Asura_Assert(entity->ToolsData==0,"");
				//allocate toolsdata
				pxToolsData = entity->ToolsData = new Tools_Entity_Data;
			}
		}
		if(pxToolsData)
		{
			//and fill it in
			pxToolsData->Position = Position;
			ASURA_CHUNK_EXTRACT_STRING(chunkBuffer, pxToolsData->Name);
			if(Version>=1)
			{
				ASURA_CHUNK_EXTRACT_STRING(chunkBuffer, pxToolsData->m_xComment);
			}
			
			if(Version>=11)
			{
				ASURA_CHUNK_EXTRACT_STRING(chunkBuffer, pxToolsData->m_xCreationData);
				ASURA_CHUNK_EXTRACT_STRING(chunkBuffer, pxToolsData->m_xLastModified);
			}

			if(Version>=6)
			{
				ASURA_CHUNK_EXTRACT(chunkBuffer,pxToolsData->m_xScale,Asura_Vector_3);
			}
			else if(Version>=2)
			{
				float fScale;
				ASURA_CHUNK_EXTRACT(chunkBuffer,fScale,float);
				pxToolsData->m_xScale.x = fScale;
				pxToolsData->m_xScale.y = fScale;
				pxToolsData->m_xScale.z = fScale;
			}

			if(Version>=3)
			{
				ASURA_CHUNK_EXTRACT(chunkBuffer,pxToolsData->m_iSecondaryEntityID,int);
				ASURA_CHUNK_EXTRACT_STRING(chunkBuffer,pxToolsData->m_xSecondaryEntityFilename);
				
				//Secondary entity filename is expected to be an empty string , rather than null , if
				//the entity belongs to the main file. Fixing this upon load to deal with old 
				//export to template code.
				//RAR 11/12/2006
				if(pxToolsData->m_xSecondaryEntityFilename.IsNull())
				{
					pxToolsData->m_xSecondaryEntityFilename = "";
				}
			}

			if(Version>=4)
			{
				ASURA_CHUNK_EXTRACT(chunkBuffer,pxToolsData->m_xOrientation,Asura_Matrix_3x3);
			}

			if(Version>=5)
			{
				ASURA_CHUNK_EXTRACT(chunkBuffer,pxToolsData->m_uPlatforms,u_int);
			}
			if(Version>=7)
			{
				ASURA_CHUNK_EXTRACT(chunkBuffer,pxToolsData->m_uLightSets,u_int);
			}
			if(Version>=8)
			{
				ASURA_CHUNK_EXTRACT(chunkBuffer,pxToolsData->m_uParentTemplate,Asura_Guid);
			}
			if(Version>=9)
			{
				ASURA_CHUNK_EXTRACT(chunkBuffer,pxToolsData->m_uProjectFlags,u_int);
			}

			if(Version>=10)
			{
				ASURA_CHUNK_EXTRACT_STRING(chunkBuffer, pxToolsData->m_xEntityBrowserPath);
			}

			pxToolsData->ToolsObject = 0;
			return true;
		}
	}
	#endif

	return false;
}


bool Asura_Chunk_Entity_ToolsData::Process(Asura_Handle fileHandle) const
{
	#ifdef ASURA_TOOLS

	//read in the rest of the chunk
	int size = Size - sizeof(Asura_Chunk_Entity_ToolsData);
	char* chunkBuffer = new char[size];
	Asura_FileAccess::ReadData(fileHandle,chunkBuffer,size);

	Process(chunkBuffer);

	delete [] chunkBuffer;

	return true;
	#else
	return false;
	#endif
}

// copying the fileHandle process function hack.
// Should change things so chunkbuffer is no longer used.
bool Asura_Chunk_Entity_ToolsData::Process(Asura_Chunk_Stream& xStream) const
{
	#ifdef ASURA_TOOLS

	//read in the rest of the chunk
	int size = Size - sizeof(Asura_Chunk_Entity_ToolsData);
	char* chunkBuffer = new char[size];
	xStream.Read(size, chunkBuffer);

	Process(chunkBuffer);

	delete [] chunkBuffer;

	return true;
	#else
	return false;
	#endif
}


#ifdef ASURA_TOOLS
void Asura_Chunk_Entity_ToolsData::Create(Asura_Entity_Server* pxEntity,Asura_SaveBlock_Base& xSaveBlock,bool bSavingToTemplateFile)
{
	//don't bother if no tools data exists
	if(!pxEntity->ToolsData) return;
	
	Asura_Chunk_SaveBlock_Stream xStream(&xSaveBlock);

	//fill in the common chunk details
	xStream.WriteChunk_Start(ASURA_CHUNK_ENTITY_TOOLSDATA, ASURA_CHUNK_ENTITY_TOOLSDATA_VERSION, 0);

	//and the rest
	xStream << pxEntity->GetGuid();
	xStream << pxEntity->ToolsData->Position;

	xStream << pxEntity->ToolsData->Name;
	xStream << pxEntity->ToolsData->m_xComment;

	xStream << pxEntity->ToolsData->m_xCreationData;
	xStream << pxEntity->ToolsData->m_xLastModified;

	xStream << pxEntity->ToolsData->m_xScale;

	if(bSavingToTemplateFile)
	{
		//When exporting entities to a template file ,the secondary entity file stuff isn't relevant , and
		//needs to be zeroed to prevent problems when the template is used.
		//RAR 07/06/2006
		Asura_String xBlankString = "";
		xStream << 0;
		xStream << xBlankString;
	}
	else
	{
		xStream << pxEntity->ToolsData->m_iSecondaryEntityID;
		xStream << pxEntity->ToolsData->m_xSecondaryEntityFilename;
	}

	xStream << pxEntity->ToolsData->m_xOrientation;

	xStream << pxEntity->ToolsData->m_uPlatforms;
	xStream << pxEntity->ToolsData->m_uLightSets;
	xStream << pxEntity->ToolsData->m_uParentTemplate;
	xStream << pxEntity->ToolsData->m_uProjectFlags;
	if(bSavingToTemplateFile)
	{
		Asura_String xNullString;
		xStream << xNullString;
	}
	else
	{
		xStream << pxEntity->ToolsData->m_xEntityBrowserPath;
	}

	xStream.WriteChunk_End();
}
#endif

////////////////////////////////////////////////////////////////////////////////////////////
/*----------------------------**
** Asura_Chunk_StaticMessages **
**----------------------------*/

#define ASURA_CHUNK_STATICMESSAGES_VERSION			0x00000007


int Asura_Chunk_StaticMessages::GetCurrentMaskedVersion()
{
	return ASURA_CHUNK_STATICMESSAGES_VERSION;
}

bool Asura_Chunk_StaticMessages::Process(Asura_Handle iFileHandle)
{
	int iBytesRemaining = Size - sizeof(Asura_Chunk_StaticMessages);
	char* pcTempChunkBfr = Asura_ChunkLoading_System::Platform_GetTempChunkMemory( iBytesRemaining );

	Asura_FileAccess::ReadData( iFileHandle, pcTempChunkBfr, iBytesRemaining );
	Asura_Chunk_Memory_Stream xStream( iBytesRemaining, pcTempChunkBfr );
	Process( xStream );
	Asura_ChunkLoading_System::Platform_ReturnTempChunkMemory( pcTempChunkBfr );

	return true;
}

bool Asura_Chunk_StaticMessages::Process( Asura_Chunk_Stream& xStream )
{
	Asura_Assert(Version<=ASURA_CHUNK_STATICMESSAGES_VERSION,"Unknown chunk version");

	//find out which message set this is
	int iMessageSet = 0;
	if(Version>=2)
	{
		xStream >> iMessageSet;

		if ( iMessageSet < ASURA_STATICMESSAGE_ENTITYSET || ASURA_STATICMESSAGE_NUMSETS <= iMessageSet )
		{
			Asura_Assert( false, "Asura_Chunk_StaticMessages::Process - unknown message set index" );
			return false;
		}
	}

	bool bHasToolsData = (Flags & ChunkFlag_HasToolsData) ? true : false;

	Asura_StaticMessageSet& xSet = Asura_StaticMessage_System::GetCurrentHandler().m_xMessageSet[iMessageSet];

	//allocate message blocks
	Asura_Assert(!xSet.m_usNumberOfMessageBlocks,"Static messages have already been allocated.");
	xSet.SetupStorageSpace((unsigned short)NumberOfMessageBlocks);

	if(Version > 6)
	{
		//New version - message can be loaded by Asura_StaticMessageBlock directly
		for(int i=0; i<NumberOfMessageBlocks; i++)
		{
			bool bValid;
			xStream >> bValid;
			if(bValid)
			{
				xSet.m_ppxMessageBlocks[i] = new Asura_StaticMessageBlock;
				xSet.m_ppxMessageBlocks[i]->ReadFromChunkStream(xStream);
			}
		}
	}
	else
	{
		//Old version - message weren't saved using Asura_StaticMessageBlock , so they need to be converted
		
		//read in the message block sizes
		if(NumberOfMessageBlocks)
		{
			for(int i=0; i<NumberOfMessageBlocks; i++)
			{
				u_char ucNumMessages;
				xStream >> ucNumMessages;

				if(ucNumMessages)
				{
					xSet.m_ppxMessageBlocks[i] = new Asura_StaticMessageBlock();
					xSet.m_ppxMessageBlocks[i]->AllocateMessages(ucNumMessages);

				}
			}
		}

		//read in the messages for each message block
		if(Version == 0)
		{
			//This version is from 2002 or so.
			Asura_Assert(0, "Skipping ancient static message block chunk");
			return false;
		}
		else
		{
			for(int i=0;i<xSet.m_usNumberOfMessageBlocks;i++)
			{
				Asura_StaticMessageBlock* pxMessageBlock = xSet.m_ppxMessageBlocks[i];
				if(pxMessageBlock)
				{
					pxMessageBlock->ReadOldStaticMessageChunkFromChunkStream(xStream, Version, bHasToolsData);
				}
			}
		}
	}
	return true;
}

//If updating this , then SkipSingleMessageInChunkStream will need changing as well
void Asura_Chunk_StaticMessages::ReadSingleMessageFromChunkStream(int iVersion,Asura_Chunk_Stream& xStream, Asura_StaticMessage* pxMessage,bool bHasToolsData)
{
	//Not handling any of the earlier versions in this function , since nothing will have been created that needs it.
	//RAR 15/11/2006
	Asura_Assert(iVersion>=5 && iVersion<=ASURA_CHUNK_STATICMESSAGES_VERSION,"Unknown chunk version for static message");

	xStream >> pxMessage->m_usMsgID;
	xStream >> pxMessage->m_usDataSize;
	xStream >> pxMessage->m_uSendTo;
#if defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)
	pxMessage->m_uSendTo = Asura_Streaming_System::MakeCurrentMasterZoneGuid(pxMessage->m_uSendTo);
#endif	// defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)
	xStream >> pxMessage->m_fDelay;
	xStream >> pxMessage->m_fProbability;

    if( iVersion >= 6 )
    {
        xStream >> pxMessage->m_uFlags;
    }

	if(bHasToolsData)
	{
		#ifdef ASURA_TOOLS
		xStream >> pxMessage->m_uToolsFlags;
		#else
		xStream.Skip(sizeof(u_int));
		#endif
	}

	if(pxMessage->m_usDataSize)
	{
		u_int uSizeInChunk = (pxMessage->m_usDataSize+3)&~3;
	
		Asura_ResourcePushType(ASURA_RESOURCE_STATIC_MESSAGE);
		Asura_ResourceAllocateMemoryBlock(pxMessage->m_pData, uSizeInChunk, ASURA_ALIGN_4_BYTE);
		Asura_ResourcePopType();
	
		xStream.Read(uSizeInChunk,pxMessage->m_pData);

		#if defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)
		// This is necessary to ensure that unique GUIDs are available when streaming...
		FixGuidsForStreaming(*pxMessage);
		#endif	// defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)
	}
	else
	{
		pxMessage->m_pData = 0;
	}
#ifdef ASURA_TOOLS
	// Fix up the data for old versions
	FixData(pxMessage);
#endif
}

#ifdef ASURA_TOOLS
void Asura_Chunk_StaticMessages::SkipSingleMessageInChunkStream(int iVersion, Asura_Chunk_Stream& xStream, bool bHasToolsData)
{
	u_short usDataSize;
	xStream.Skip(sizeof(u_short));//skip msg id
	xStream >> usDataSize;
	
	u_int uAmountToSkip = sizeof(Asura_Guid);//skip SendTo
	if(iVersion >= 3)
	{
		uAmountToSkip += sizeof(float); //skip m_fDelay
	}
	if(iVersion >= 5)
	{
		uAmountToSkip += sizeof(float); //skip m_fProbability
	}
	if( iVersion >= 6 )
	{
	    uAmountToSkip += sizeof(u_int); // Skip m_uFlags.
	}
	if(bHasToolsData && iVersion >= 4)
	{
		uAmountToSkip += sizeof(u_int); // skip tools flags
	}

	//skip extra message data
	uAmountToSkip += (usDataSize+3)&~3;

	xStream.Skip(uAmountToSkip); 
}
#endif //ASURA_TOOLS


#if defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)
bool Asura_Chunk_StaticMessages::FixGuidsForStreaming(Asura_StaticMessage& xMessage)
{
	switch(xMessage.m_usMsgID)
	{
		case ASURA_MSG_INITIALISE:
		case ASURA_MSG_DESTRUCT:
		case ASURA_MSG_ACTIVATE:
		case ASURA_MSG_DEACTIVATE:
		case ASURA_MSG_TRIGGER:
		case ASURA_MSG_UNTRIGGER:
		case ASURA_MSG_LOCK:
		case ASURA_MSG_UNLOCK:
		case ASURA_MSG_RESET:
		case ASURA_MSG_SPLITTER_ACTIVATEOUTPUT:
		case ASURA_MSG_SPLITTER_DEACTIVATEOUTPUT:
		case ASURA_MSG_SPLITTER_TRIGGEROUTPUT:
		case ASURA_MSG_CHANGE_ANIMATION:
		case ASURA_MSG_GLASS_SMASH:
		case ASURA_MSG_LIFTCALL:
		case ASURA_MSG_SWITCHON:
		case ASURA_MSG_SWITCHOFF:
		case ASURA_MSG_TEMPLATE_TRIGGERINPUT:
		case ASURA_MSG_TEMPLATE_TRIGGEROUTPUT:
		case ASURA_MSG_ACTIVATECUTSCENEWITHTIME:
		case ASURA_MSG_LOGICTRIGGER_INPUTON:
		case ASURA_MSG_LOGICTRIGGER_INPUTOFF:
		case ASURA_MSG_CUTSCENE_ENABLEEVENT:
		case ASURA_MSG_CUTSCENE_DISABLEEVENT:
		case ASURA_MSG_CUTSCENE_SETCAMERA:
		case ASURA_MSG_TIMELINETRIGGER_ENABLEMESSAGE:
		case ASURA_MSG_TIMELINETRIGGER_DISABLEMESSAGE:
		case ASURA_MSG_TEXTUREANIMATION:
		case ASURA_MSG_HIDE:
		case ASURA_MSG_UNHIDE:
		case ASURA_MSG_COLLISIONSON:
		case ASURA_MSG_COLLISIONSOFF:
		case ASURA_MSG_METAMUSIC_ACTIVATEZONE:
		case ASURA_MSG_METAMUSIC_DEACTIVATEZONE:
		case ASURA_MSG_SET_FSFX:
		case ASURA_MSG_SET_FSFX_NEW:
		case ASURA_MSG_SET_DESTRUCTIBLE:
		case ASURA_MSG_SETTIMER:
		case ASURA_MSG_TIMETRIGGER_SETTRIGGERTIME:
		case ASURA_MSG_TIMETRIGGER_ADDTOTRIGGERTIME:
		case ASURA_MSG_TIMELINETRIGGER_SETTRIGGERTIME:
		case ASURA_MSG_PAUSETIMER:
		case ASURA_MSG_UNPAUSETIMER:
		case ASURA_MSG_COUNTEDTRIGGER_ENABLEMESSAGE :
		case ASURA_MSG_COUNTEDTRIGGER_DISABLEMESSAGE :
		case ASURA_MSG_COUNTEDTRIGGER_SETTRIGGERCOUNT :
		case ASURA_MSG_COUNTEDTRIGGER_SETCOUNTER :
		case ASURA_MSG_COUNTEDTRIGGER_ADDCOUNTER :
		case ASURA_MSG_PROXY_ACTIVATE :
		case ASURA_MSG_PROXY_DEACTIVATE :
		case ASURA_MSG_AXON_GAMESCENE_LEAVE_GAMESCENE_AI:
		case ASURA_MSG_AXON_GAMESCENE_NEVER_STOP_AT_NODE:
		case ASURA_MSG_AXON_GS2_ANIM_SEQUENCE_DATA:
		case ASURA_MSG_AXON_GAMESCENE_ATTRACTOR_NODE_ARRIVED:
		case ASURA_MSG_AXON_ENABLE_LINK:
		case ASURA_MSG_AXON_DISABLE_LINK:
		case ASURA_MSG_LIFT_START:
		case ASURA_MSG_LIFT_STOP:
		case ASURA_MSG_LIFT_REVERSE:
		case ASURA_MSG_LIFT_SETFLAGS:
		case ASURA_MSG_LIFT_NODE_SETFLAGS:
		case ASURA_MSG_DIALOGUE_FROMINSTANCE :
		case ASURA_MSG_DIALOGUE_CANCELSUBTITLE:
		case ASURA_MSG_TIMETRIGGER_ADDTIME:
		case ASURA_MSG_CHANGE_CONSOLEVAR:
		case ASURA_MSG_PLAY_PFX_ON_ENTITY:
		case ASURA_MSG_CONTAINER_CHANGE_STATE:
		case ASURA_MSG_CONTAINER_CHANGE_STATE_EXTENDED:
		{
			// These messages don't have any GUIDs to modify...
			return(true);
		}

		case ASURA_MSG_PROXY_ADDTARGET:
		case ASURA_MSG_PROXY_REMOVETARGET:
		case ASURA_MSG_PROXY_SETTARGET:
		{
			Asura_Message_ProxyTrigger_Target* pxMessage = (Asura_Message_ProxyTrigger_Target*) xMessage.m_pData;
			pxMessage->m_uTargetGuid = Asura_Streaming_System::MakeCurrentMasterZoneGuid(pxMessage->m_uTargetGuid);

			return true;
		}

#ifdef ASURA_USE_DIALOGUE_SYSTEM
		case ASURA_MSG_DIALOGUE_PLAYLINE:
		case ASURA_MSG_DIALOGUE_PLAYLINEONENTITY:
		{
			Asura_Message_Dialogue_PlayLine* pxData = (Asura_Message_Dialogue_PlayLine*) xMessage.m_pData;
			//no guid in this message ,but we need to store the current handler ID so that the dialogue system
			//knows where to find stuff
			pxData->m_uHandlerID = Asura_Dialogue_Storage::GetCurrentHandler().GetHandlerID();
			return true;
		}

		// TY - Do the same for dialogue controller messages I guess?
		case ASURA_MSG_DIALOGUE_PLAYLINE_CONTROLLER:
		{
			Asura_Msg_Dialogue_PlayLine_Controller* pxData = static_cast<Asura_Msg_Dialogue_PlayLine_Controller*>( xMessage.m_pData );
			pxData->m_uHandlerID = Asura_Dialogue_Storage::GetCurrentHandler().GetHandlerID();

			return true;
		}

		case ASURA_MSG_DIALOGUE_STOPLINE_CONTROLLER:
		{
			Asura_Msg_Dialogue_StopLine_Controller* pxData = static_cast<Asura_Msg_Dialogue_StopLine_Controller*>( xMessage.m_pData );
			pxData->m_uHandlerID = Asura_Dialogue_Storage::GetCurrentHandler().GetHandlerID();
			
			return true;
		}

#endif

#ifdef ASURA_USE_AXON
		case ASURA_MSG_AXON_GS2_PATHFIND_TO_NODE:
		{
			Axon_Msg_Gamescene_Pathfind_To_Node* pxPTNMsg = static_cast< Axon_Msg_Gamescene_Pathfind_To_Node* >( xMessage.m_pData );
			pxPTNMsg->m_uNodeGuid = Asura_Streaming_System::MakeCurrentMasterZoneGuid( pxPTNMsg->m_uNodeGuid );
			return true;
		}

		case ASURA_MSG_AXON_GS2_DONT_STOP_AT_NODE:
		{
			Axon_Msg_GS2_Dont_Stop_At_Node* pxDSANMsg = static_cast< Axon_Msg_GS2_Dont_Stop_At_Node* >( xMessage.m_pData );
			pxDSANMsg->m_uNodeGuid = Asura_Streaming_System::MakeCurrentMasterZoneGuid( pxDSANMsg->m_uNodeGuid );
			return true;
		}

		case ASURA_MSG_AXON_GS2_SET_LINK_WEIGHT:
		{
			Axon_Msg_GS2_Set_Link_Weight* pxSLWMsg = static_cast< Axon_Msg_GS2_Set_Link_Weight* >( xMessage.m_pData );
			BoolGuidWeight* pxBGWArray = pxSLWMsg->GetBGWArray();
			for ( u_int u = 0; u < pxSLWMsg->m_uNumEntries; ++u )
			{
				pxBGWArray[ u ].m_uLinkGuid = Asura_Streaming_System::MakeCurrentMasterZoneGuid( pxBGWArray[ u ].m_uLinkGuid );
			}
			return true;
		}

		case ASURA_MSG_AXON_GS2_TAKE_LINK:
		{
			Axon_Msg_GS2_Take_Link* pxTLMsg = static_cast< Axon_Msg_GS2_Take_Link* >( xMessage.m_pData );
			pxTLMsg->m_uLinkGuid = Asura_Streaming_System::MakeCurrentMasterZoneGuid( pxTLMsg->m_uLinkGuid );
			return true;
		}

		case ASURA_MSG_AXON_GS2_TELEPORT_TO_NODE:
		{
			Axon_Msg_GS2_Teleport_To_Node* pxTTNMsg = static_cast< Axon_Msg_GS2_Teleport_To_Node* >( xMessage.m_pData );
			pxTTNMsg->m_uNodeGuid = Asura_Streaming_System::MakeCurrentMasterZoneGuid( pxTTNMsg->m_uNodeGuid );
			return true;
		}

		case ASURA_MSG_AXON_GS2_ATTRACTOR_PULSE:
		{
			Axon_Msg_GS2_Attractor_Node_Pulse* pxANPMsg = static_cast< Axon_Msg_GS2_Attractor_Node_Pulse* >( xMessage.m_pData );
			pxANPMsg->m_uAttractorGuid = Asura_Streaming_System::MakeCurrentMasterZoneGuid( pxANPMsg->m_uAttractorGuid );
			return true;
		}

		case ASURA_MSG_AXON_GS2_ATTRACTOR_CANCEL:
		{
			Axon_Msg_GS2_Attractor_Node_Cancel* pxANCMsg = static_cast< Axon_Msg_GS2_Attractor_Node_Cancel* >( xMessage.m_pData );
			pxANCMsg->m_uAttractorGuid = Asura_Streaming_System::MakeCurrentMasterZoneGuid( pxANCMsg->m_uAttractorGuid );
			return true;
		}
#endif //#ifdef ASURA_USE_AXON

		default:
		{
			const bool	bSuccess	= Project_FixGuidsForStreaming(xMessage);

			Asura_Assert(bSuccess, "Fix GUIDs not handled for this message-ID.");
			return(bSuccess);
		}
	}
}
#endif	// defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)

#ifdef ASURA_TOOLS
u_short Asura_Chunk_StaticMessages::ProcessSingleMessageBlock(const char* pcChunkBuffer,u_short usBlockID) const
{

	if(usBlockID == ASURA_STATICMESSAGE_EMPTYBLOCK) return ASURA_STATICMESSAGE_EMPTYBLOCK;

	if(Version<2 || Version>ASURA_CHUNK_STATICMESSAGES_VERSION)
	{
		Asura_Assertf(0,("ProcessSingleMessageBlock unable to deal with chunk version %d",Version));
		return ASURA_STATICMESSAGE_EMPTYBLOCK;
	}

	bool bHasToolsData = (Flags & ChunkFlag_HasToolsData) ? true : false;

	Asura_Chunk_ChunkBuffer_Stream xStream(pcChunkBuffer);
	
	//find out which message set this is
	int iMessageSet = 0;
	xStream >> iMessageSet;

 	if(iMessageSet>=ASURA_STATICMESSAGE_NUMSETS)
 	{
 		Asura_Assert(iMessageSet<ASURA_STATICMESSAGE_NUMSETS,"Unknown message set index");
 		return ASURA_STATICMESSAGE_EMPTYBLOCK;
 	}
	Asura_StaticMessageSet& xSet = Asura_StaticMessage_System::GetCurrentHandler().m_xMessageSet[iMessageSet];

	
	//convert the message block ID to an index
	int iIndex;
	Asura_StaticMessageSetIndex eSet;
	if(!Asura_StaticMessage_System::ConvertIDToIndex(usBlockID,&iIndex,&eSet) || 
	   eSet != iMessageSet || 
	   iIndex>=NumberOfMessageBlocks)
	{
		//message block doesn't exist in this chunk
 		return ASURA_STATICMESSAGE_EMPTYBLOCK;
	}

	if(Version > 6)
	{
		//skip past the unwanted message blocks
		bool bValid;
		for(int i=0; i<iIndex; i++)
		{
			xStream >> bValid;
			if(bValid)
			{
				Asura_StaticMessageBlock::SkipInChunkStream(xStream);
			}
		}

		xStream >> bValid;
		if(!bValid) return ASURA_STATICMESSAGE_EMPTYBLOCK;
		
		//find the index of a free message block to copy the messages in to
		u_short usBlockIndex = xSet.AllocateMessageBlock();
		Asura_StaticMessageBlock* pxMessageBlock = xSet.m_ppxMessageBlocks[usBlockIndex];
		pxMessageBlock->ReadFromChunkStream(xStream);

		return Asura_StaticMessage_System::ConvertIndexToID(eSet,usBlockIndex);
	}
	else
	{
		//Find out how many messages need to be skipped to get to the start of the correct message block
		int iMessagesToSkip = 0;
		u_char ucNumMessages;
		for(int i=0;i<iIndex;i++)
		{
			xStream >> ucNumMessages;
			iMessagesToSkip += ucNumMessages;
		}
		//and get the number in the message block we want
		xStream >> ucNumMessages;
		int iMessagesInBlock = ucNumMessages;

		//skip past the remaining message sizes
		xStream.Skip(NumberOfMessageBlocks - (iIndex + 1));

		if(!iMessagesInBlock)
		{
			//no messages , so forget it
			return ASURA_STATICMESSAGE_EMPTYBLOCK;
		}

		//skip the unwanted messages
		for(int i=0;i<iMessagesToSkip;i++)
		{
			SkipSingleMessageInChunkStream(Version, xStream, bHasToolsData);
		}	

		//find the index of a free message block to copy the messages in to
		u_short usBlockIndex = xSet.AllocateMessageBlock();
		Asura_StaticMessageBlock* pxMessageBlock = xSet.m_ppxMessageBlocks[usBlockIndex];
		pxMessageBlock->AllocateMessages(iMessagesInBlock);
	
		pxMessageBlock->ReadOldStaticMessageChunkFromChunkStream(xStream, Version, bHasToolsData);

		return Asura_StaticMessage_System::ConvertIndexToID(eSet,usBlockIndex);
	}
}
#endif //ASURA_TOOLS

#ifdef ASURA_TOOLS
void Asura_Chunk_StaticMessages::Create(Asura_SaveBlock& saveBlock,int iMessageSet)
{
	Asura_Assert(iMessageSet<ASURA_STATICMESSAGE_NUMSETS,"");
	Asura_StaticMessageSet& xSet = Asura_StaticMessage_System::GetCurrentHandler().m_xMessageSet[iMessageSet];

	int iChunkFlags = 0;

	bool bIncludeToolsData = false;
	if(!Tools_Level_Export::IsExport())
	{
		iChunkFlags |= ChunkFlag_HasToolsData;
		bIncludeToolsData = true;
	}


	Asura_Chunk_SaveBlock_Stream	xStream (&saveBlock);

	const int						iNumberOfMessageBlocks	= xSet.m_usNumberOfMessageBlocks;


	// Write the data...

	xStream.WriteChunk_Start	(ASURA_CHUNK_STATICMESSAGES, ASURA_CHUNK_STATICMESSAGES_VERSION, iChunkFlags);

	xStream << iNumberOfMessageBlocks;
	xStream << iMessageSet;


	// Fill in all the message block sizes...

	for (int i = 0; i < xSet.m_usNumberOfMessageBlocks; i++)
	{
		bool bValid = xSet.m_ppxMessageBlocks[i] ? true : false;
		xStream << bValid;
		if(bValid)
		{
			xSet.m_ppxMessageBlocks[i]->WriteToChunkStream(xStream);
		}
	}

	xStream.WriteChunk_End	();
}

void Asura_Chunk_StaticMessages::WriteSingleMessageToChunkStream(Asura_Chunk_Stream& xStream, Asura_StaticMessage* pxMessage, bool bIncludeToolsData)
{
	xStream << pxMessage->m_usMsgID;
	xStream << pxMessage->m_usDataSize;
	xStream << pxMessage->m_uSendTo;
	xStream << pxMessage->m_fDelay;
	xStream << pxMessage->m_fProbability;
    xStream << pxMessage->m_uFlags;
	if(bIncludeToolsData)
	{
		xStream << pxMessage->m_uToolsFlags;
	}

	if (0 < pxMessage->m_usDataSize)
	{
		// KOR - 08/05/2003 19:02:20 - Unfortunately, we have to know the structure of the data
		// to endian swap it. This requires a switch on Asura messages and a separate project
		// specific handler is required too
		#ifdef ASURA_ASSERT
		u_int uDataStartPosition = xStream.GetPosition();
		#endif
		bool bHandledByProject = false;
		u_int uSizeInChunk = (pxMessage->m_usDataSize+3)&~3;
		
		if(pxMessage->m_usMsgID >= ASURA_MSG_PROJECT_SPECIFIC)
		{
			//Making use of Project_FillInChunkBuffer for now here ,to avoid projects having to implement
			//both chunk buffer and chunk stream versions.
			//RAR 15/11/2006
			char acBuffer[1024];
			if(uSizeInChunk < sizeof(acBuffer))
			{
				char* pcChunkBuffer = acBuffer;
				if(Project_FillInChunkBuffer(pcChunkBuffer,pxMessage))
				{
					xStream.Write(uSizeInChunk, acBuffer);
					bHandledByProject = true;

				}
			}
			else
			{
				Asura_Assert(uSizeInChunk < sizeof(acBuffer),"Buffer for saving message isn't large enough");
			}
		}
		else
		{
			Asura_Assert(pxMessage->m_usMsgID < ASURA_MSG_END_OF_STATIC_MESSAGES, "Attempted to save static pxMessage with dynamic pxMessage ID");
		}

		if(!bHandledByProject)
		{
			switch(pxMessage->m_usMsgID)
			{
				case ASURA_MSG_SPLITTER_ACTIVATEOUTPUT: 
				case ASURA_MSG_SPLITTER_DEACTIVATEOUTPUT:
				case ASURA_MSG_SPLITTER_TRIGGEROUTPUT:
				{
					Asura_Message_SplitterBlock_Output*	pxSplitterMessage	= (Asura_Message_SplitterBlock_Output*)pxMessage->m_pData;

					// One unsigned
					xStream << pxSplitterMessage->m_uOutputIndex;
					break;
				}

				case ASURA_MSG_CHANGE_ANIMATION:
				{
					Asura_Message_PhysicalObject_ChangeAnimation*	pxAnimMessage	= (Asura_Message_PhysicalObject_ChangeAnimation*)pxMessage->m_pData;

					// Two unsigned, one int, three floats
				    xStream << pxAnimMessage->m_uAnimID;
				    xStream << pxAnimMessage->m_uAnimFileID;
				    xStream << pxAnimMessage->m_iFlags;
				    xStream << pxAnimMessage->m_fTweenDuration;
					xStream << pxAnimMessage->m_fStartTime;
					xStream << pxAnimMessage->m_fEndTime;
					break;
				}

				case ASURA_MSG_GLASS_SMASH:
				{
					Asura_Message_Glass_Smash*					pxGlassMessage	= (Asura_Message_Glass_Smash*)pxMessage->m_pData;

					Asura_WriteToStream_Bitfield_Wrapper<u_int>	xFlagsBitfield(pxGlassMessage->m_uFlags);

					// Fill-in the bitfield...
					xFlagsBitfield.Add	(pxGlassMessage->m_bSmashInPositiveZDir,	1);

					// Float and bool
					xStream << pxGlassMessage->m_fPower;
					xStream << xFlagsBitfield;
					break;
				}

				case ASURA_MSG_LIFTCALL:
				{
					Asura_MsgData_LiftCall*	pxLiftMessage	= (Asura_MsgData_LiftCall*)pxMessage->m_pData;

					xStream << pxLiftMessage->uStopNumber;
					break;
				}

				case ASURA_MSG_TEMPLATE_TRIGGERINPUT:
				case ASURA_MSG_TEMPLATE_TRIGGEROUTPUT:
				{
					Asura_Message_Template_Trigger*	pxTriggerMessage	= (Asura_Message_Template_Trigger*)pxMessage->m_pData;

					xStream << pxTriggerMessage->m_uNameHash;
					break;
				}

				case ASURA_MSG_ACTIVATECUTSCENEWITHTIME:
				{
					Asura_Message_ActivateCutsceneWithTime*	pxCutsceneMessage	= reinterpret_cast<Asura_Message_ActivateCutsceneWithTime *>(pxMessage->m_pData);

					xStream << pxCutsceneMessage->m_fStartTime;
					break;
				}

				case ASURA_MSG_LOGICTRIGGER_INPUTON: 
				case ASURA_MSG_LOGICTRIGGER_INPUTOFF:
				{
					Asura_Message_LogicTrigger_Input*	pxLogicTriggerMessage	= (Asura_Message_LogicTrigger_Input*)pxMessage->m_pData;

					// One unsigned
					xStream << pxLogicTriggerMessage->m_uInputHash;
					break;
				}

				case ASURA_MSG_CUTSCENE_ENABLEEVENT: 
				case ASURA_MSG_CUTSCENE_DISABLEEVENT:
				{
					Asura_Message_CutsceneEventID*	pxCutsceneMessage	= (Asura_Message_CutsceneEventID*)pxMessage->m_pData;

					// One int
					xStream << pxCutsceneMessage->m_iEventID;
					break;
				}

				case ASURA_MSG_CUTSCENE_SETCAMERA: 
				{
					Asura_Message_Cutscene_SetCamera*	pxCutsceneMessage	= (Asura_Message_Cutscene_SetCamera*)pxMessage->m_pData;

					xStream << pxCutsceneMessage->m_uCameraHash;
					break;
				}

				case ASURA_MSG_TIMELINETRIGGER_ENABLEMESSAGE:
				case ASURA_MSG_TIMELINETRIGGER_DISABLEMESSAGE:
				{
					Asura_Message_TimelineTrigger*	pxTriggerMessage	= (Asura_Message_TimelineTrigger*)pxMessage->m_pData;

					xStream << pxTriggerMessage->m_uMessageHash;
					break;
				}

				case ASURA_MSG_SETTIMER:
				{
					Asura_Message_SetTimer* pxMessageData = (Asura_Message_SetTimer*)pxMessage->m_pData;
					xStream << pxMessageData->m_fTimer;
					break;
				}

				case ASURA_MSG_TIMETRIGGER_SETTRIGGERTIME:
				{
					Asura_Message_TimeTrigger_SetTriggerTime* pxMessageData = (Asura_Message_TimeTrigger_SetTriggerTime*)pxMessage->m_pData;
					xStream << pxMessageData->m_fTriggerTime;
					break;
				}

				case ASURA_MSG_TIMETRIGGER_ADDTOTRIGGERTIME:
				{
					Asura_Message_TimeTrigger_AddToTriggerTime* pxMessageData = (Asura_Message_TimeTrigger_AddToTriggerTime*)pxMessage->m_pData;
					xStream << pxMessageData->m_fTriggerTimeDelta;
					break;
				}

				case ASURA_MSG_TIMETRIGGER_ADDTIME:
				{
					Asura_Message_TimeTrigger_AddTime* pxMessageData = (Asura_Message_TimeTrigger_AddTime*)pxMessage->m_pData;
					xStream << pxMessageData->m_fTimeDelta;
					break;
				}


				case ASURA_MSG_TIMELINETRIGGER_SETTRIGGERTIME:
				{
					Asura_Message_TimelineTrigger_SetTriggerTime* pxMessageData = (Asura_Message_TimelineTrigger_SetTriggerTime*)pxMessage->m_pData;
					xStream << pxMessageData->m_uMessageHash;
					xStream << pxMessageData->m_fTriggerTime;
					break;
				}
				
				case ASURA_MSG_COUNTEDTRIGGER_ENABLEMESSAGE:
				case ASURA_MSG_COUNTEDTRIGGER_DISABLEMESSAGE:
				{
					Asura_Message_CountedTrigger_MessageHash* pxTriggerMessage	= (Asura_Message_CountedTrigger_MessageHash*)pxMessage->m_pData;

					xStream << pxTriggerMessage->m_uMessageHash;
					break;
				}

				case ASURA_MSG_COUNTEDTRIGGER_SETCOUNTER:
				{
					Asura_Message_CountedTrigger_SetCounter* pxMessageData = (Asura_Message_CountedTrigger_SetCounter*)pxMessage->m_pData;
					xStream << pxMessageData->m_iCounter;
					break;
				}

				case ASURA_MSG_COUNTEDTRIGGER_ADDCOUNTER:
				{
					Asura_Message_CountedTrigger_AddCounter* pxMessageData = (Asura_Message_CountedTrigger_AddCounter*)pxMessage->m_pData;
					xStream << pxMessageData->m_iChange;
					break;
				}

				case ASURA_MSG_COUNTEDTRIGGER_SETTRIGGERCOUNT:
				{
					Asura_Message_CountedTrigger_SetTriggerCount* pxMessageData = (Asura_Message_CountedTrigger_SetTriggerCount*)pxMessage->m_pData;
					xStream << pxMessageData->m_uMessageHash;
					xStream << pxMessageData->m_iTriggerCount;
					break;
				}
				
#ifdef ASURA_USE_METAMUSICZONES
				case ASURA_MSG_METAMUSIC_ACTIVATEZONE :
				case ASURA_MSG_METAMUSIC_DEACTIVATEZONE :
				{
					Asura_MsgData_MetaMusic_Zone* pxMessageData = (Asura_MsgData_MetaMusic_Zone*)pxMessage->m_pData;
					xStream << pxMessageData->m_uZoneID;
					break;
				}
#endif //ASURA_USE_METAMUSICZONES

				case ASURA_MSG_TEXTUREANIMATION:
				{
					Asura_Message_TextureAnimation*				pxTextureMessage	= (Asura_Message_TextureAnimation*)pxMessage->m_pData;

					Asura_WriteToStream_Bitfield_Wrapper<u_int>	xFlagsBitfield(pxTextureMessage->m_uFlags);

					xFlagsBitfield.Add	(pxTextureMessage->m_bChangeSequence,	1);
					xFlagsBitfield.Add	(pxTextureMessage->m_bChangeSpeed,		1);

					xStream << xFlagsBitfield;
					xStream << pxTextureMessage->m_uSequence;
					xStream << pxTextureMessage->m_fSpeed;
					break;
				}

				case ASURA_MSG_PROXY_ADDTARGET :
				case ASURA_MSG_PROXY_REMOVETARGET :
				case ASURA_MSG_PROXY_SETTARGET :
				{
					Asura_Message_ProxyTrigger_Target* pxMessageData = (Asura_Message_ProxyTrigger_Target*) pxMessage->m_pData;

					xStream << pxMessageData->m_uTargetGuid;
					break;
				}

				case ASURA_MSG_SET_FSFX :
				{
					const Asura_Guid* const pxMessageData = static_cast< const Asura_Guid* >( pxMessage->m_pData );
					xStream << *pxMessageData;
					break;
				}

#if defined(ASURA_USE_FSFX)
				case ASURA_MSG_SET_FSFX_NEW :
				{
					const Asura_FSFX_Message* const pxMessageData = static_cast< const Asura_FSFX_Message* >( pxMessage->m_pData );
					xStream << pxMessageData->m_xID;
					xStream << pxMessageData->m_fValue;
					xStream << pxMessageData->m_fTime;
					break;
				}
#endif

				case ASURA_MSG_SOUND_MIXER_PRESET:
				case ASURA_MSG_SOUND_MIXER_PRESET_QUEUE:
				case ASURA_MSG_SOUND_MIXER_PRESET_UNQUEUE:
				{
					const Asura_Message_SoundMixerPreset*	pxMessageData	= static_cast<const Asura_Message_SoundMixerPreset*>(pxMessage->m_pData);

					xStream << pxMessageData->m_uHashID;
					xStream << pxMessageData->m_fFadeTime;
					break;
				}

#if !defined(ASURA_USE_AUDIO_SYSTEM)
				case ASURA_MSG_SOUND_SET_REVERB:
				{
					const Asura_Message_SoundReverb*	pxMessageData	= static_cast<const Asura_Message_SoundReverb*>(pxMessage->m_pData);

					xStream << pxMessageData->m_iReverbID;
					break;
				}
#endif

				case ASURA_MSG_LIFT_SETFLAGS:
				{
					const Asura_Message_Lift_SetFlags* const pxLiftMessage = static_cast< const Asura_Message_Lift_SetFlags* >( pxMessage->m_pData );
					pxLiftMessage->WriteToChunkStream(xStream);
					break;
				}

				case ASURA_MSG_LIFT_NODE_SETFLAGS:
				{
					const Asura_Message_Lift_Node_SetFlags* const pxLiftMessage = static_cast< const Asura_Message_Lift_Node_SetFlags* >( pxMessage->m_pData );
					pxLiftMessage->WriteToChunkStream(xStream);
					break;
				}

				case ASURA_MSG_LIFT_GOTO_NODE:
				{
					const Asura_MsgData_Lift_Goto_Node* const pxLiftMessage = static_cast< const Asura_MsgData_Lift_Goto_Node* >( pxMessage->m_pData );
					pxLiftMessage->WriteToChunkStream(xStream);
					break;

				}

#ifdef ASURA_USE_DIALOGUE_SYSTEM
				case ASURA_MSG_DIALOGUE_FROMINSTANCE :
				{
					const u_int* puData = (const u_int*) pxMessage->m_pData;
					xStream << (*puData);
					break;
				}
					
				case ASURA_MSG_DIALOGUE_PLAYLINE :
				case ASURA_MSG_DIALOGUE_PLAYLINEONENTITY :
				{
					const Asura_Message_Dialogue_PlayLine* pxData = (const Asura_Message_Dialogue_PlayLine*) pxMessage->m_pData;
					xStream << (pxData->m_uLineID);
					xStream << (pxData->m_uHandlerID);
					break;
				}

				case ASURA_MSG_DIALOGUE_CONTROLLER_INTERRUPT:
				{
					const Asura_Msg_Dialogue_Interrupt* pxData = static_cast<const Asura_Msg_Dialogue_Interrupt*>( pxMessage->m_pData );
					xStream << pxData->m_bImmediate;
					xStream.WritePadding(3);
					break;
				}

				case ASURA_MSG_DIALOGUE_CONTROLLER_TOGGLE_LINE:
				{
					const Asura_Msg_Dialogue_ToggleLine* pxData = static_cast<const Asura_Msg_Dialogue_ToggleLine*>( pxMessage->m_pData );
					xStream << pxData->m_uLineID;
					xStream << pxData->m_bEnable;
					xStream.WritePadding(3);
					break;
				}

				case ASURA_MSG_DIALOGUE_CONTROLLER_TRIGGER_LINE:
				{
					const Asura_Msg_Dialogue_TriggerLine* pxData = static_cast<const Asura_Msg_Dialogue_TriggerLine*>( pxMessage->m_pData );
					xStream << pxData->m_uLineID;
					break;
				}

#endif
				case ASURA_MSG_APPLY_LINEAR_FORCE:
				{
					const Asura_Msg_ApplyForce_Linear* pxApplyLinearForceMessage = static_cast<const Asura_Msg_ApplyForce_Linear*>( pxMessage->m_pData );
					pxApplyLinearForceMessage->WriteToChunkStream( xStream );
					break;
				}

				case ASURA_MSG_APPLY_RADIAL_FORCE:
				{
					const Asura_Msg_ApplyForce_Radial* pxApplyRadialForceMessage = static_cast<const Asura_Msg_ApplyForce_Radial*>( pxMessage->m_pData );
					pxApplyRadialForceMessage->WriteToChunkStream( xStream );
					break;
				}

#ifdef ASURA_USE_VIDEO_TO_TEXTURE_SYSTEM
				case ASURA_MSG_FMV_CONTROLLER_PLAY:
				{
					const Asura_Msg_FMV_Controller_Play* const pxData = static_cast< const Asura_Msg_FMV_Controller_Play* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					break;
				}

				case ASURA_MSG_FMV_CONTROLLER_PAUSE:
				{
					const Asura_Msg_FMV_Controller_Pause* const pxData = static_cast< const Asura_Msg_FMV_Controller_Pause* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					break;
				}
#endif

#ifdef ASURA_USE_AXON
				case ASURA_MSG_AXON_GAMESCENE_ATTRACT_TO_NODE:
				{
					const Axon_Msg_Gamescene_Attract_To_Node* pxData = static_cast< const Axon_Msg_Gamescene_Attract_To_Node* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_uAttractorGuid;
					xStream << pxData->m_fSpeed;
					break;
				}

				case ASURA_MSG_AXON_GAMESCENE_ACTOR_ATTRACT_TO_NODE:
				{
					const Axon_Msg_Gamescene_Actor_Attract_To_Node* pxData = static_cast< const Axon_Msg_Gamescene_Actor_Attract_To_Node* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_uNodeGuid;
					xStream << pxData->m_fSpeed;
					break;
				}

				case ASURA_MSG_AXON_GAMESCENE_SET_ATTRACTOR_FLAGS:
				{
					xStream << 0;
					xStream << 0;
					break;
				}

				case ASURA_MSG_AXON_GS2_TELEPORT_TO_NODE:
				case ASURA_MSG_AXON_GAMESCENE_TELEPORT_TO_NODE:
				{
					const Axon_Msg_GS2_Teleport_To_Node* pxData = static_cast< const Axon_Msg_GS2_Teleport_To_Node* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_uNodeGuid;
					break;
				}

				case ASURA_MSG_AXON_GAMESCENE_LEAVE_NODE_IF_THERE:
				{
					const Axon_Msg_Gamescene_Leave_Node_If_There* pxData = static_cast< const Axon_Msg_Gamescene_Leave_Node_If_There* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_uNodeGuid;
					break;
				}

				case ASURA_MSG_AXON_GS2_SET_NODE_PARAMS:
				{
					const Axon_Msg_GS2_Set_Node_Params* pxData = static_cast< const Axon_Msg_GS2_Set_Node_Params* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_iDataValidFlags;
					xStream << (u_int)( pxData->m_bStopAtNode ? 1 : 0 );
					xStream << pxData->m_uAnimSet;
					xStream << pxData->m_iExitCondition;
					xStream << pxData->m_fMinExitWaitTime;
					xStream << pxData->m_fMaxExitWaitTime;
					break;
				}

				case ASURA_MSG_AXON_GS2_DONT_STOP_AT_NODE:
				{
					const Axon_Msg_GS2_Dont_Stop_At_Node* pxData = static_cast< const Axon_Msg_GS2_Dont_Stop_At_Node* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_iNodeType;
					xStream << pxData->m_uNodeGuid;
					break;
				}

				case ASURA_MSG_AXON_GS2_TAKE_LINK:
				{
					const Axon_Msg_GS2_Take_Link* pxData = static_cast< const Axon_Msg_GS2_Take_Link* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_uLinkGuid;
					break;
				}

				case ASURA_MSG_AXON_GS2_SET_LINK_WEIGHT:
				{
					const Axon_Msg_GS2_Set_Link_Weight* pxData = static_cast< const Axon_Msg_GS2_Set_Link_Weight* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_uNumEntries;

					const Axon_Msg_GS2_Set_Link_Weight::BoolGuidWeight* pxBGWArray = pxData->GetBGWArray();
					for ( u_int u = 0; u < pxData->m_uNumEntries; ++u )
					{
						const u_int uBoolWrapper = pxBGWArray[ u ].m_bInUse;
						xStream << uBoolWrapper;
						xStream << pxBGWArray[ u ].m_uLinkGuid;
						xStream << pxBGWArray[ u ].m_fWeight;
					}

					break;
				}

				case ASURA_MSG_AXON_GS2_ANIM_CHANGE:
				{
					const Axon_Msg_GS2_Anim_Change* pxData = static_cast< const Axon_Msg_GS2_Anim_Change* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_uAnimSet;
					break;
				}

				case ASURA_MSG_AXON_GS2_PATHFIND_TO_NODE:
				{
					const Axon_Msg_GS2_Pathfind_To_Node* pxData = static_cast< const Axon_Msg_GS2_Pathfind_To_Node* >( pxMessage->m_pData );
					xStream << pxData->m_uVersion;
					xStream << pxData->m_uDestNodeGuid;
					break;
				}
#endif // ASURA_USE_AXON

#ifdef ASURA_USE_GUI_MENU_SYSTEM
				case ASURA_MSG_GUIMENU_ACTIVATE:
				{
					const Asura_Message_GUIMenu_Activate* pxData = static_cast< const Asura_Message_GUIMenu_Activate* >( pxMessage->m_pData );

					xStream << pxData->uHashMenuPageID;
					break;
				}
#endif


#if !defined(ASURA_DONT_USE_TELEPORTERS)
				case ASURA_MSGID_TELEPORT_ENTITY:
					{
						const Asura_Message_TeleportEntity*	pxData	= static_cast<const Asura_Message_TeleportEntity*>(pxMessage->m_pData);
						const Asura_Guid					uGuid	= pxData->GetGuidToTeleport();

						xStream << uGuid;
						break;
					}
#endif	// !defined(ASURA_DONT_USE_TELEPORTERS)

#ifdef ASURA_TARGET_SM3
				case ASURA_MSG_DYNAMICLIGHT_FADE:
				{
					const Asura_Message_DynamicLight_Fade*	pxData	= static_cast<const Asura_Message_DynamicLight_Fade*>(pxMessage->m_pData);
					
					xStream << pxData->m_fTargetR;
					xStream << pxData->m_fTargetG;
					xStream << pxData->m_fTargetB;
					xStream << pxData->m_fTargetRange;
					xStream << pxData->m_fTargetIntensity;
					xStream << pxData->m_fDuration;
					xStream << pxData->m_uFlags;
					break;
				}
#endif

				case ASURA_MSG_SET_DESTRUCTIBLE :
				{
					const bool* pbData = static_cast<bool*>(pxMessage->m_pData);
					xStream << *pbData;
					xStream.WritePadding(3);
					break;
				}


#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
				case ASURA_MSG_CHANGE_CONSOLEVAR:
				{
					const Asura_Message_Change_ConsoleVar* pxData = static_cast<const Asura_Message_Change_ConsoleVar*>(pxMessage->m_pData);
					xStream << pxData->m_iFlags;
					xStream << pxData->m_fData;
					
					break;
				}
#endif //ASURA_SUPPORT_COMMAND_CONSOLE

				case ASURA_MSG_PLAY_PFX_ON_ENTITY:
				{
					const Asura_Msg_PlayPFXOnEntity* pxData = static_cast<const Asura_Msg_PlayPFXOnEntity*>(pxMessage->m_pData);
					
					xStream << pxData->m_uPFXEffectHash;
					xStream << pxData->m_uMarkerHash;
					xStream << pxData->m_uPlayPFXFlags;
					xStream << pxData->m_uDummy;
					
					for(u_int u=0;u<ASURA_MSG_PLAY_PFX_MAX_CHARS;++u)
					{
						xStream << pxData->m_xMarkerString[u];
					}
					
					break;
				}

#ifdef ASURA_USE_CONTAINER_SYSTEM
				case ASURA_MSG_CONTAINER_CHANGE_STATE:
				{
					const Asura_Message_Container_ChangeState* pxData = static_cast<const Asura_Message_Container_ChangeState*>(pxMessage->m_pData);
					xStream << pxData->m_uStateHash;
					break;
				}

				case ASURA_MSG_CONTAINER_CHANGE_STATE_EXTENDED:
				{
					const Asura_Message_Container_ChangeStateExtended* pxData = static_cast<const Asura_Message_Container_ChangeStateExtended*>(pxMessage->m_pData);
					xStream << pxData->m_uInputIndex;
					xStream << pxData->m_uStateHash;
					break;
				}
#endif //ASURA_USE_CONTAINER_SYSTEM

#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
				case ASURA_MSG_DYNAMIC_MUSIC_TRIGGER:
				{
					const Asura_MsgData_DynamicMusic_Trigger* pxData = static_cast<const Asura_MsgData_DynamicMusic_Trigger*>(pxMessage->m_pData);
					xStream << pxData->m_uTriggerHash;
					break;
				}
#endif



				default:
				{
					Asura_Assertf( false, ("Unhandled static message ID (%u). If exporting to a big-endian platform (such as GC, 360 or PS3) this message will be broken.", pxMessage->m_usMsgID) );
					xStream.Write(pxMessage->m_usDataSize, pxMessage->m_pData);

					if(uSizeInChunk > pxMessage->m_usDataSize) xStream.WritePadding(uSizeInChunk - pxMessage->m_usDataSize);
					break;
				}
			}		// End of switch.
		}

		//make sure the right amount has been written
		u_int uDataWritten = xStream.GetPosition() - uDataStartPosition;
		if(uDataWritten != uSizeInChunk)
		{
			Asura_Assertf( ( uDataWritten == uSizeInChunk ),
				( "Size mismatch writing static message '%s' data: expected %u, wrote %u",
				Asura_Network::GetMsgIDDesc( pxMessage->m_usMsgID ), uSizeInChunk, uDataWritten ) );
			if(uSizeInChunk > uDataWritten)
			{
				// If we have not written enough data fill the chunk buffer up with the missing data. This won't take into account
				// endianness, but it will stop the static messages from being corrupted on load.
				char* pcExtraData = &( static_cast< char* >( pxMessage->m_pData )[ uDataWritten ] );
				xStream.Write(uSizeInChunk - uDataWritten, pcExtraData);
			}
		
		}
	}
}
#endif //ASURA_TOOLS

#ifdef ASURA_TOOLS
void Asura_Chunk_StaticMessages::FixData(Asura_StaticMessage* pxMessage)
{
	if(Project_FixData(pxMessage))
	{
		return;
	}

	switch(pxMessage->m_usMsgID)
	{
		case ASURA_MSG_CHANGE_ANIMATION:
		{
			//Old messages need to be enlarged. RAR 24/08/2006
			if(pxMessage->m_usDataSize == 16)
			{
				//set defaults in a new message
				Asura_Message_PhysicalObject_ChangeAnimation xData;
				xData.Initialise();

				//copy the bits we have
				Asura_Mem::Copy(&xData,pxMessage->m_pData,pxMessage->m_usDataSize);

				//reallocate the data in the message
				pxMessage->DeallocateMessageData();
				pxMessage->AllocateMessageData(sizeof(xData),false);

				//fill in the corrected message data
				Asura_Mem::Copy(pxMessage->m_pData,&xData,pxMessage->m_usDataSize);
			}
			Asura_Assert(pxMessage->m_usDataSize == sizeof(Asura_Message_PhysicalObject_ChangeAnimation),"Unexpected size for change animation message");
			break;
		}

#ifdef ASURA_USE_AXON
		case ASURA_MSG_AXON_GAMESCENE_ATTRACT_TO_NODE:
		{
			if (pxMessage->m_usDataSize == 8)
			{
				//set defaults in a new message
				Axon_Msg_Gamescene_Attract_To_Node xData;
				xData.Initialise();

				//copy the bits we have
				Asura_Mem::Copy(&xData,pxMessage->m_pData,pxMessage->m_usDataSize);

				xData.m_uVersion = Axon_Msg_Gamescene_Attract_To_Node::CURRENT_VERSION;

				//reallocate the data in the message
				pxMessage->DeallocateMessageData();
				pxMessage->AllocateMessageData(sizeof(xData),false);

				//fill in the corrected message data
				Asura_Mem::Copy(pxMessage->m_pData,&xData,pxMessage->m_usDataSize);
			}
			Asura_Assert(pxMessage->m_usDataSize == sizeof(Axon_Msg_Gamescene_Attract_To_Node),"Unexpected size for attract to node message");
			break;
		}
#endif // ASURA_USE_AXON

		case ASURA_MSG_PLAY_PFX_ON_ENTITY:
		{
			if(pxMessage->m_usDataSize == 16) // old data
			{
				Asura_Msg_PlayPFXOnEntity xData;
				xData.Reset();

				struct OLD_DATA {
					Asura_Hash_ID m_uPFXEffectHash;
					Asura_Hash_ID m_uMarkerHash;
					u_int m_uPlayPFXFlags;	
					u_int m_uDummy;			
				} xOldData;

				Asura_Mem::Copy( &xOldData, pxMessage->m_pData, pxMessage->m_usDataSize );

				pxMessage->DeallocateMessageData();
				pxMessage->AllocateMessageData(sizeof(Asura_Msg_PlayPFXOnEntity), false);

				Asura_Msg_PlayPFXOnEntity* pxData = static_cast<Asura_Msg_PlayPFXOnEntity*>(pxMessage->m_pData);

				pxData->m_uPFXEffectHash = xOldData.m_uPFXEffectHash;
				pxData->m_uMarkerHash = xOldData.m_uMarkerHash;
				pxData->m_uPlayPFXFlags = xOldData.m_uPlayPFXFlags;
				pxData->m_uDummy = xOldData.m_uDummy;

				pxData->m_xMarkerString[0] = 0;
			}
			break;
		}
	}	
}
#endif // ASURA_TOOLS
///////////////////////////////////////////////////////////////////////////////////////////////
/*-----------------------------------**
** Asura_Chunk_StaticMessages_InGame **
**-----------------------------------*/

#define ASURA_CHUNK_STATICMESSAGES_INGAME_VERSION 2


bool Asura_Chunk_StaticMessages_InGame::Process(Asura_Chunk_Stream& xStream) const
{
	if (Version > ASURA_CHUNK_STATICMESSAGES_INGAME_VERSION)
	{
		Asura_Assertf(false, ("Unknown chunk version %d for in game static message system",Version));
		return false;
	}
	if(Version < 2)
	{
		Asura_Assert(0,"Old version of in game static message chunk not supported");
		return false;
	}

	Asura_Assert(!Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessages,"Delayed message queue should have been cleared out before loading");

	xStream >> Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessages;
	Asura_Assert(Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessages <= ASURA_STATICMESSAGE_MAXDELAYEDMESSAGES,"Too many messages in save block");

	Asura_DelayedStaticMessage* pxDelayedMessage = Asura_StaticMessage_System::GetCurrentHandler().m_xDelayedMessages;
	for(int i=0;i<Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessages;i++,pxDelayedMessage++)
	{
		pxDelayedMessage->ReadFromChunkStream(xStream);

#if defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS) && !defined(ASURA_TOOLS)
		pxDelayedMessage->m_uFromGuid	= Asura_Streaming_System::MakeCurrentMasterZoneGuid(pxDelayedMessage->m_uFromGuid);
#endif	// defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS) && !defined(ASURA_TOOLS)
	}
	
	return true;	
}

bool Asura_Chunk_StaticMessages_InGame::Process(const char* pcChunkBuffer) const
{
	Asura_Chunk_Memory_Stream xStream(Size-sizeof(this),pcChunkBuffer);
	return Process(xStream);
}

void Asura_Chunk_StaticMessages_InGame::Create(Asura_Chunk_Stream& xStream)
{
	//chunk only needed if there are some delayed messages in the system
	if(!Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessages && !Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessagesBeingSent) return;

	xStream.WriteChunk_Start(ASURA_CHUNK_STATICMESSAGES_INGAME, ASURA_CHUNK_STATICMESSAGES_INGAME_VERSION, 0);

	xStream << Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessages + Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessagesBeingSent;

	//Add all the messages in the main part of the 'queue'
	const Asura_DelayedStaticMessage* pxDelayedMessage = Asura_StaticMessage_System::GetCurrentHandler().m_xDelayedMessages;
	for(int i=0;i<Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessages;i++,pxDelayedMessage++)
	{
		pxDelayedMessage->WriteToChunkStream(xStream);
	}

	//Add the messages that are in the process of being sent.
	//(Will only happen if a save takes place half-way through the static message system update)
	//This will result in the messages reappearing in the main part of the queue on reload , but that
	//should be okay ,since they will end up being sent on the first update after reloading
	pxDelayedMessage = &Asura_StaticMessage_System::GetCurrentHandler().m_xDelayedMessages[ASURA_STATICMESSAGE_MAXDELAYEDMESSAGES-1];
	for(int i=0;i<Asura_StaticMessage_System::GetCurrentHandler().m_iNumDelayedMessagesBeingSent;i++,pxDelayedMessage--)
	{
		pxDelayedMessage->WriteToChunkStream(xStream);
	}

	
	xStream.WriteChunk_End();
}

void Asura_Chunk_StaticMessages_InGame::Create(Asura_SaveBlock_Base& xSaveBlock)
{
	Asura_Chunk_SaveBlock_Stream xStream(&xSaveBlock);
	Create(xStream);
}

///////////////////////////////////////////////////////////////////////////////////////////////
/*-----------------------------**
** Asura_Chunk_Entity_NextGuid **
**-----------------------------*/
#ifdef ASURA_TOOLS

#define ASURA_CHUNK_ENTITY_NEXTGUID_VERSION 1

bool Asura_Chunk_Entity_NextGuid::Process(Asura_Handle iFileHandle) const
{
	Asura_Chunk_File_Stream xStream (iFileHandle);
	return Process(xStream);
}

bool Asura_Chunk_Entity_NextGuid::Process(Asura_Chunk_Stream& xStream) const
{
	Asura_Assertf(Version<=ASURA_CHUNK_ENTITY_NEXTGUID_VERSION,("Unknown chunk version %d for Asura_Chunk_Entity_NextGuid",Version));

	if(Version == 0)
	{	
		if(m_uNextGuid == ASURA_GUID_TOOLS_ENTITYFILE_START || m_uNextGuid == ASURA_GUID_TOOLS_CUTSCENEFILE_START)
		{
			//if the next guid is the start of one of the ranges , then there is no need to do anything
			return true;
		}
		//set the next guid by registering the guid immediately before it
		Asura_Guid uGuidToRegister = m_uNextGuid-1;
		Asura_Assert(uGuidToRegister>=ASURA_GUID_TOOLSCREATEDENTITY_START && uGuidToRegister<=ASURA_GUID_TOOLSCREATEDENTITY_END,"Not expecting to get guids outside of the tools guid range");

		Asura_Entity_System::RegisterToolsGuid(uGuidToRegister);
	}
	else
	{
		int iRange = 0;
		xStream >> iRange;

		Asura_Assert(iRange>=0 && iRange < TOOLS_NUM_GUIDRANGE, "Unexpected guid range index");

		if(iRange>=0 && iRange < TOOLS_NUM_GUIDRANGE)
		{
			Asura_Entity_System::SetNextToolsCreatedGuid((Tools_GuidRange)iRange, m_uNextGuid);
		}
	}

	return true;
}

void Asura_Chunk_Entity_NextGuid::Create(int iRange,Asura_SaveBlock_Base& xSaveBlock)
{
	Asura_Assert(iRange>=0 && iRange < TOOLS_NUM_GUIDRANGE, "Unexpected guid range index");
	Asura_Guid uNextGuid = Asura_Entity_System::GetNextToolsCreatedGuid((Tools_GuidRange) iRange);


	Asura_Chunk_SaveBlock_Stream	xStream(&xSaveBlock);


	// Write the data...

	xStream.WriteChunk_Start(ASURA_CHUNK_ENTITY_NEXTGUID, ASURA_CHUNK_ENTITY_NEXTGUID_VERSION, 0);

	xStream << uNextGuid;
	xStream << iRange;

	xStream.WriteChunk_End();
}
#endif //ASURA_TOOLS

////////////////////////////////////////////////////////////////////////////////////////////
/*----------------------------------**
** Asura_Chunk_Entity_SecondaryFile **
**----------------------------------*/

#ifdef ASURA_TOOLS

#define ASURA_CHUNK_ENTITY_SECONDARYFILE_VERSION 0

bool Asura_Chunk_Entity_SecondaryFile::Process(Asura_Handle iFileHandle) const
{
	Asura_Assert(Version<=ASURA_CHUNK_ENTITY_SECONDARYFILE_VERSION,"Unknown chunk version");

	//read the name
	Asura_String xName;
	ASURA_CHUNK_FILEEXTRACT_STRING(iFileHandle,xName);

	//and add to the tools system
	Tools_SecondaryEntityFile_System::AddFileFromLoad(xName.GetString(),m_iFileVersion,m_iNextID, Flags);

	return true;
}

void Asura_Chunk_Entity_SecondaryFile::Create(const class Tools_SecondaryEntityFile* pxFile,Asura_SaveBlock_Base& xSaveBlock)
{
	//find the size required
	int iChunkSize = sizeof(Asura_Chunk_Entity_SecondaryFile);
	iChunkSize += pxFile->m_xName.GetSizeInInts()*4;
	
	Asura_Chunk_SaveBlock_Stream xStream(&xSaveBlock);
	int iFlags = 0;
	if(pxFile->m_bCommonFile) iFlags |= ChunkFlag_CommonFile;
	if(pxFile->m_bMissionDir) iFlags |= ChunkFlag_MissionDir;
	xStream.WriteChunk_Start(ASURA_CHUNK_ENTITY_SECONDARYFILE, ASURA_CHUNK_ENTITY_SECONDARYFILE_VERSION, iFlags);
	
	xStream << pxFile->m_iFileVersionToSave;
	xStream << pxFile->m_iNextID;
	
	xStream << pxFile->m_xName;

	xStream.WriteChunk_End();
}


#endif //ASURA_TOOLS

////////////////////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_TOOLS
#include "ChunkSystem/Asura_Chunk_Phonons.h"

static void AddEntityTextureToTree(int iTextureID,void* pTree)
{
	Asura_NameTree* pxNameTree = (Asura_NameTree*) pTree;
	Asura_Assert(pxNameTree,"");

	if(iTextureID != ASURA_TEXTURE_NONE)
	{
		const Asura_String* pxName = Asura_Texture_Management::GetTextureName(iTextureID);
		if(pxName)
		{
        	int iIndex;
       		// add name to tree
        	pxNameTree->FindNodeIndexByName(pxName->GetString(), true, iIndex);
		}
		
	}
}

void BuildEntityTextureTree(Asura_NameTree* pxNameTree,Asura_Guid uMinGuid,Asura_Guid uMaxGuid)
{
	//check entities to see which textures are being used
	for(Asura_Classified_List_It<Asura_Entity_Server> it(Asura_Entity_Server::GetList());!it.Done();it.Next())
	{
		Asura_Entity_Server* entity = it.GetCurrent();
		//ignore entities marked for destruction
		if(entity->IsDestroyed()) continue;
		//and those with non entity file tools guids
		if(entity->GetGuid()<uMinGuid || entity->GetGuid()>uMaxGuid) continue;

		//add textures used by this entity to the list
		entity->TraverseUsedTextures(AddEntityTextureToTree,pxNameTree);
	}
}

bool SaveCutscenes(const char* pszFilename)
{
	Asura_SaveBlock xSaveBlock;

	//save the static messages
	Asura_Chunk_StaticMessages::Create(xSaveBlock,ASURA_STATICMESSAGE_CUTSCENESET);


	//save textures needed by cutscenes
	Asura_NameTree xTextureTree;
	Asura_Cutscene_System::BuildUsedTextureTree(&xTextureTree);
	if(xTextureTree.GetNumberOfNodes())
	{
		Asura_Chunk_TextureNames::Create(&xTextureTree,&xSaveBlock);
	}
	
	//save the cutscenes
	for(int i=0;i<Asura_Cutscene_System::GetNumberOfCutscenes();i++)
	{
		Asura_Chunk_Cutscene::Create(Asura_Cutscene_System::GetCutsceneByIndex(i),xSaveBlock);
	}

	Asura_Chunk_Entity_NextGuid::Create(TOOLS_GUIDRANGE_CUTSCENE ,xSaveBlock);
	
	//and the cutscene file entites
	for(Asura_Classified_List_It<Asura_Entity_Server> it(Asura_Entity_Server::GetList());!it.Done();it.Next())
	{
		Asura_Entity_Server* entity = it.GetCurrent();
		//ignore entities marked for destruction
		if(entity->IsDestroyed()) continue;
		//and those with non cutscene file guids
		if(entity->GetGuid()<ASURA_GUID_TOOLS_CUTSCENEFILE_START || entity->GetGuid()>ASURA_GUID_TOOLS_CUTSCENEFILE_END) continue;

		//save this entity
		Asura_Chunk_Entity::Create((Asura_Entity_Server*)entity,xSaveBlock);

		#ifdef ASURA_TOOLS
		//and its tools data
		Asura_Chunk_Entity_ToolsData::Create((Asura_Entity_Server*)entity,xSaveBlock);
		#endif

	}

	xSaveBlock.AddAsuraTerminator();

	return xSaveBlock.SaveFile(pszFilename,true);
}

#endif // ASURA_TOOLS
