1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 /*************************************************************************
4 -------------------------------------------------------------------------
8 -------------------------------------------------------------------------
10 - 23:8:2004 15:52 : Created by Márcio Martins
12 *************************************************************************/
14 #include "ActorSystem.h"
15 #include "Network/GameServerChannel.h"
16 #include "Network/GameServerNub.h"
17 #include <CryString/CryPath.h>
18 #include "CryAction.h"
20 //------------------------------------------------------------------------
21 void CActorSystem::DemoSpectatorSystem::SwitchSpectator(TActorMap
* pActors
, EntityId id
)
23 if (pActors
->size() <= 1)
26 IActor
* nextActor
, * lastActor
;
28 lastActor
= (*pActors
)[m_currentActor
];
32 TActorMap::const_iterator it
= pActors
->begin();
33 while (it
->first
!= m_currentActor
)
36 if (it
== pActors
->end())
37 it
= pActors
->begin();
38 nextActor
= it
->second
;
42 nextActor
= (*pActors
)[id
];
47 if (nextActor
== lastActor
)
50 m_currentActor
= nextActor
->GetEntityId();
51 if (IView
* view
= gEnv
->pGameFramework
->GetIViewSystem()->GetActiveView())
52 view
->LinkTo(nextActor
->GetEntity());
54 nextActor
->SwitchDemoModeSpectator(true);
55 lastActor
->SwitchDemoModeSpectator(false);
58 //------------------------------------------------------------------------
59 CActorSystem::CActorSystem(ISystem
* pSystem
, IEntitySystem
* pEntitySystem
)
61 m_pEntitySystem(pEntitySystem
)
63 m_demoPlaybackMappedOriginalServerPlayer
= 0;
65 if (gEnv
->pEntitySystem
)
67 gEnv
->pEntitySystem
->AddSink(this, IEntitySystem::OnReused
);
71 // Iterators now have their destructors called before they enter the pool - so we only need to free the memory here {2008/12/09}
72 void DeleteActorIterator(IActorIterator
* ptr
) { operator delete(ptr
); }
74 //------------------------------------------------------------------------
75 CActorSystem::~CActorSystem()
77 if (gEnv
->pEntitySystem
)
79 gEnv
->pEntitySystem
->RemoveSink(this);
82 std::for_each(m_iteratorPool
.begin(), m_iteratorPool
.end(), DeleteActorIterator
);
83 // delete the created userdata in each class
84 for (TActorClassMap::iterator it
= m_classes
.begin(); it
!= m_classes
.end(); ++it
)
86 IEntityClass
* pClass
= m_pEntitySystem
->GetClassRegistry()->FindClass(it
->first
.c_str());
88 delete (char*)pClass
->GetUserProxyData();
92 void CActorSystem::Reset()
94 if (GetISystem()->IsSerializingFile() == 1)
96 TActorMap::iterator it
= m_actors
.begin();
97 IEntitySystem
* pEntitySystem
= gEnv
->pEntitySystem
;
98 for (; it
!= m_actors
.end(); )
100 EntityId id
= it
->first
;
101 IEntity
* pEntity
= pEntitySystem
->GetEntity(id
);
108 TActorMap::iterator eraseIt
= it
++;
109 m_actors
.erase(eraseIt
);
114 std::for_each(m_iteratorPool
.begin(), m_iteratorPool
.end(), DeleteActorIterator
);
115 stl::free_container(m_iteratorPool
);
118 //------------------------------------------------------------------------
119 IActor
* CActorSystem::GetActor(EntityId entityId
)
121 TActorMap::iterator it
= m_actors
.find(entityId
);
123 if (it
!= m_actors
.end())
131 //------------------------------------------------------------------------
132 IActor
* CActorSystem::GetActorByChannelId(uint16 channelId
)
134 for (TActorMap::iterator it
= m_actors
.begin(); it
!= m_actors
.end(); ++it
)
136 if (it
->second
->GetGameObject()->GetChannelId() == channelId
)
145 //------------------------------------------------------------------------
146 IActor
* CActorSystem::CreateActor(uint16 channelId
, const char* name
, const char* actorClass
, const Vec3
& pos
, const Quat
& rot
, const Vec3
& scale
, EntityId id
)
148 // get the entity class
149 IEntityClass
* pEntityClass
= m_pEntitySystem
->GetClassRegistry()->FindClass(actorClass
);
153 CRY_ASSERT(pEntityClass
);
158 // if a channel is specified and already has a player,
159 // use that entity id
161 bool bIsClient
= false;
164 if (CGameServerNub
* pGameServerNub
= CCryAction::GetCryAction()->GetGameServerNub())
165 if (CGameServerChannel
* pGameServerChannel
= pGameServerNub
->GetChannel(channelId
))
166 if (pGameServerChannel
->GetNetChannel()->IsLocal())
168 id
= LOCAL_PLAYER_ENTITY_ID
;
170 if (IsDemoPlayback()) //if playing a demo - spectator id is changed
171 m_demoSpectatorSystem
.m_currentActor
= m_demoSpectatorSystem
.m_originalActor
= id
;
175 IGameObjectSystem::SEntitySpawnParamsForGameObjectWithPreactivatedExtension userData
;
176 userData
.hookFunction
= HookCreateActor
;
177 userData
.pUserData
= &channelId
;
179 SEntitySpawnParams params
;
181 params
.pUserData
= (void*)&userData
;
183 params
.vPosition
= pos
;
184 params
.qRotation
= rot
;
185 params
.vScale
= scale
;
186 params
.nFlags
= ENTITY_FLAG_TRIGGER_AREAS
;
187 params
.nFlagsExtended
= ENTITY_FLAG_EXTENDED_NEEDS_MOVEINSIDE
; // ensures the audio triggered on the actor entity will get proper environment values
189 params
.pClass
= pEntityClass
;
191 IEntity
* pEntity
= m_pEntitySystem
->SpawnEntity(params
);
199 return GetActor(pEntity
->GetId());
202 //------------------------------------------------------------------------
203 void CActorSystem::SetDemoPlaybackMappedOriginalServerPlayer(EntityId id
)
205 m_demoPlaybackMappedOriginalServerPlayer
= id
;
208 EntityId
CActorSystem::GetDemoPlaybackMappedOriginalServerPlayer() const
210 return m_demoPlaybackMappedOriginalServerPlayer
;
213 //------------------------------------------------------------------------
214 void CActorSystem::SwitchDemoSpectator(EntityId id
)
216 m_demoSpectatorSystem
.SwitchSpectator(&m_actors
, id
);
219 //------------------------------------------------------------------------
220 IActor
* CActorSystem::GetCurrentDemoSpectator()
222 return m_actors
[m_demoSpectatorSystem
.m_currentActor
];
225 //------------------------------------------------------------------------
226 IActor
* CActorSystem::GetOriginalDemoSpectator()
228 return m_actors
[m_demoSpectatorSystem
.m_originalActor
];
231 //------------------------------------------------------------------------
232 void CActorSystem::RegisterActorClass(const char* name
, IGameFramework::IActorCreator
* pCreator
, bool isAI
)
234 IEntityClassRegistry::SEntityClassDesc actorClass
;
236 char scriptName
[1024] = { 0 };
238 cry_sprintf(scriptName
, "Scripts/Entities/Actor/%s.lua", name
);
240 cry_sprintf(scriptName
, "Scripts/Entities/AI/%s.lua", name
);
242 // Allow the name to contain relative path, but use only the name part as class name.
243 string
className(PathUtil::GetFile(name
));
244 actorClass
.sName
= className
.c_str();
245 actorClass
.sScriptFile
= scriptName
;
247 actorClass
.flags
|= ECLF_INVISIBLE
;
249 CCryAction::GetCryAction()->GetIGameObjectSystem()->RegisterExtension(className
.c_str(), pCreator
, &actorClass
);
251 SActorClassDesc classDesc
;
252 classDesc
.pEntityClass
= gEnv
->pEntitySystem
->GetClassRegistry()->FindClass(className
.c_str());
253 classDesc
.pCreator
= pCreator
;
255 m_classes
.insert(TActorClassMap::value_type(name
, classDesc
));
257 // Automatically register scheduling profile
258 gEnv
->pGameFramework
->GetIGameObjectSystem()->RegisterSchedulingProfile(actorClass
.sName
, "dude", "own");
261 //------------------------------------------------------------------------
262 void CActorSystem::AddActor(EntityId entityId
, IActor
* pProxy
)
264 m_actors
.insert(TActorMap::value_type(entityId
, pProxy
));
267 //------------------------------------------------------------------------
268 void CActorSystem::RemoveActor(EntityId entityId
)
270 stl::member_find_and_erase(m_actors
, entityId
);
273 //------------------------------------------------------------------------
274 bool CActorSystem::HookCreateActor(IEntity
* pEntity
, IGameObject
* pGameObject
, void* pUserData
)
276 pGameObject
->SetChannelId(*reinterpret_cast<uint16
*>(pUserData
));
280 //---------------------------------------------------------------------
281 void CActorSystem::Reload()
284 Scan(m_actorParamsFolder
.c_str());
287 //---------------------------------------------------------------------
288 void CActorSystem::Scan(const char* folderName
)
290 stack_string folder
= folderName
;
291 stack_string search
= folder
;
292 stack_string subName
;
293 stack_string xmlFile
;
296 ICryPak
* pPak
= gEnv
->pCryPak
;
299 intptr_t handle
= pPak
->FindFirst(search
.c_str(), &fd
);
300 //Scan only one directory, not recursion supported (add it if need it)
305 if (!strcmp(fd
.name
, ".") || !strcmp(fd
.name
, ".."))
308 const char* fileExtension
= PathUtil::GetExt(fd
.name
);
309 if (stricmp(fileExtension
, "xml"))
314 xmlFile
= folder
+ "/" + fd
.name
;
315 XmlNodeRef rootNode
= gEnv
->pSystem
->LoadXmlFromFile(xmlFile
.c_str());
319 ActorSystemErrorMessage(xmlFile
.c_str(), "Root xml node couldn't be loaded", true);
323 if (!ScanXML(rootNode
, xmlFile
.c_str()))
329 while (pPak
->FindNext(handle
, &fd
) >= 0);
332 m_actorParamsFolder
= folderName
;
335 //--------------------------------------------------------------------
336 bool CActorSystem::ScanXML(const XmlNodeRef
& root
, const char* xmlFile
)
338 if (strcmpi(root
->getTag(), "ActorParams") && strcmpi(root
->getTag(), "EntityClassParams"))
340 CryFixedStringT
<128> errorBuffer
;
341 errorBuffer
.Format("Root tag is '%s', expecting 'ActorParams' or 'EntityClassParams', Skipping...");
342 ActorSystemErrorMessage(xmlFile
, errorBuffer
.c_str(), true);
346 const char* type
= root
->getAttr("type");
349 ActorSystemErrorMessage(xmlFile
, "Actor/EntityClass params file does not contain attribute 'type'! Skipping...", true);
353 TActorParamsMap::iterator dit
= m_actorParams
.find(CONST_TEMP_STRING(type
));
355 //Insert only if new, might be reloading...
356 if (dit
== m_actorParams
.end())
358 std::pair
<TActorParamsMap::iterator
, bool> result
= m_actorParams
.insert(TActorParamsMap::value_type(type
, SActorParamsDesc()));
362 SActorParamsDesc
& desc
= dit
->second
;
365 desc
.params
->Release();
367 desc
.params
= new CItemParamsNode();
368 desc
.params
->ConvertFromXML(root
);
373 //-----------------------------------------------------------------
374 const IItemParamsNode
* CActorSystem::GetActorParams(const char* actorClass
) const
376 TActorParamsMap::const_iterator it
= m_actorParams
.find(CONST_TEMP_STRING(actorClass
));
377 if (it
!= m_actorParams
.end())
379 return it
->second
.params
;
385 //-----------------------------------------------------------------
386 bool CActorSystem::IsActorClass(IEntityClass
* pClass
) const
388 bool bResult
= false;
390 TActorClassMap::const_iterator itClass
= m_classes
.begin();
391 TActorClassMap::const_iterator itClassEnd
= m_classes
.end();
392 for (; !bResult
&& itClass
!= itClassEnd
; ++itClass
)
394 const SActorClassDesc
& classDesc
= itClass
->second
;
395 bResult
= (pClass
== classDesc
.pEntityClass
);
401 //------------------------------------------------------------------------
402 bool CActorSystem::OnBeforeSpawn(SEntitySpawnParams
& params
)
404 return true; // nothing else (but needed to implement IEntitySystemSink)
407 //------------------------------------------------------------------------
408 void CActorSystem::OnSpawn(IEntity
* pEntity
, SEntitySpawnParams
& params
)
410 // nothing (but needed to implement IEntitySystemSink)
413 //------------------------------------------------------------------------
414 bool CActorSystem::OnRemove(IEntity
* pEntity
)
416 return true; // nothing else (but needed to implement IEntitySystemSink)
419 //------------------------------------------------------------------------
420 void CActorSystem::OnReused(IEntity
* pEntity
, SEntitySpawnParams
& params
)
422 for (TActorMap::const_iterator it
= m_actors
.begin(); it
!= m_actors
.end(); ++it
)
424 IActor
* actor
= it
->second
;
425 IEntity
* ent
= actor
->GetEntity();
427 if (ent
&& ent
== pEntity
)
429 actor
->OnReused(pEntity
, params
);
434 //------------------------------------------------------------------------
435 void CActorSystem::GetMemoryUsage(class ICrySizer
* pSizer
) const
437 pSizer
->Add(sizeof *this);
440 IActorIteratorPtr
CActorSystem::CreateActorIterator()
442 if (m_iteratorPool
.empty())
444 return new CActorIterator(this);
448 CActorIterator
* pIter
= m_iteratorPool
.back();
449 m_iteratorPool
.pop_back();
450 new(pIter
) CActorIterator(this);
455 void CActorSystem::ActorSystemErrorMessage(const char* fileName
, const char* errorInfo
, bool displayErrorDialog
)
457 if ((fileName
== NULL
) || (errorInfo
== NULL
))
460 CryFixedStringT
<1024> messageBuffer
;
461 messageBuffer
.Format("ERROR: Failed to load '%s'. Required data missing, which could lead to un-expected game behavior or crashes. ( %s )", fileName
, errorInfo
);
463 CryLogAlways("%s", messageBuffer
.c_str());
465 if (displayErrorDialog
)
467 CryMessageBox(messageBuffer
.c_str(), "Error", eMB_Error
);
471 void CActorSystem::GetMemoryStatistics(ICrySizer
* pSizer
)
473 SIZER_SUBCOMPONENT_NAME(pSizer
, "ActorSystem");
474 pSizer
->AddObject(this, sizeof(*this));
475 pSizer
->AddObject(m_actors
);