Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ObjectManager.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2013 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "ObjectManager.h"
21 
22 #include "graphics/ObjectBase.h"
23 #include "graphics/ObjectEntry.h"
24 #include "ps/CLogger.h"
25 #include "ps/Game.h"
26 #include "ps/Profile.h"
27 #include "ps/Filesystem.h"
31 
32 template<typename T, typename S>
33 static void delete_pair_2nd(std::pair<T,S> v)
34 {
35  delete v.second;
36 }
37 
38 template<typename T>
40 {
41  T x;
42  second_equals(const T& x) : x(x) {}
43  template<typename S> bool operator()(const S& v) { return v.second == x; }
44 };
45 
47 {
48  if (ActorName < a.ActorName)
49  return true;
50  else if (ActorName > a.ActorName)
51  return false;
52  else
53  return ActorVariation < a.ActorVariation;
54 }
55 
56 static Status ReloadChangedFileCB(void* param, const VfsPath& path)
57 {
58  return static_cast<CObjectManager*>(param)->ReloadChangedFile(path);
59 }
60 
61 CObjectManager::CObjectManager(CMeshManager& meshManager, CSkeletonAnimManager& skeletonAnimManager, CSimulation2& simulation)
62 : m_MeshManager(meshManager), m_SkeletonAnimManager(skeletonAnimManager), m_Simulation(simulation)
63 {
65 }
66 
68 {
69  UnloadObjects();
70 
72 }
73 
74 
76 {
77  ENSURE(!objectname.empty());
78 
79  // See if the base type has been loaded yet:
80 
81  std::map<CStrW, CObjectBase*>::iterator it = m_ObjectBases.find(objectname);
82  if (it != m_ObjectBases.end())
83  return it->second;
84 
85  // Not already loaded, so try to load it:
86 
87  CObjectBase* obj = new CObjectBase(*this);
88 
89  VfsPath pathname = VfsPath("art/actors/") / objectname;
90 
91  if (obj->Load(pathname))
92  {
93  m_ObjectBases[objectname] = obj;
94  return obj;
95  }
96  else
97  delete obj;
98 
99  LOGERROR(L"CObjectManager::FindObjectBase(): Cannot find object '%ls'", objectname.c_str());
100 
101  return 0;
102 }
103 
105 {
106  std::vector<std::set<CStr> > selections; // TODO - should this really be empty?
107  return FindObjectVariation(objname, selections);
108 }
109 
110 CObjectEntry* CObjectManager::FindObjectVariation(const CStrW& objname, const std::vector<std::set<CStr> >& selections)
111 {
112  CObjectBase* base = FindObjectBase(objname);
113 
114  if (! base)
115  return NULL;
116 
117  return FindObjectVariation(base, selections);
118 }
119 
120 CObjectEntry* CObjectManager::FindObjectVariation(CObjectBase* base, const std::vector<std::set<CStr> >& selections)
121 {
122  PROFILE("object variation loading");
123 
124  // Look to see whether this particular variation has already been loaded
125 
126  std::vector<u8> choices = base->CalculateVariationKey(selections);
127  ObjectKey key (base->m_Pathname.string(), choices);
128 
129  std::map<ObjectKey, CObjectEntry*>::iterator it = m_Objects.find(key);
130  if (it != m_Objects.end() && !it->second->m_Outdated)
131  return it->second;
132 
133  // If it hasn't been loaded, load it now
134 
135  // TODO: If there was an existing ObjectEntry, but it's outdated (due to hotloading),
136  // we'll get a memory leak when replacing its entry in m_Objects. The problem is
137  // some CUnits might still have a pointer to the old ObjectEntry so we probably can't
138  // just delete it now. Probably we need to redesign the caching/hotloading system so it
139  // makes more sense (e.g. use shared_ptr); for now I'll just leak, to avoid making the logic
140  // more complex than it is already is, since this only matters for the rare case of hotloading.
141 
142  CObjectEntry* obj = new CObjectEntry(base, m_Simulation); // TODO: type ?
143 
144  // TODO (for some efficiency): use the pre-calculated choices for this object,
145  // which has already worked out what to do for props, instead of passing the
146  // selections into BuildVariation and having it recalculate the props' choices.
147 
148  if (! obj->BuildVariation(selections, choices, *this))
149  {
150  DeleteObject(obj);
151  return NULL;
152  }
153 
154  m_Objects[key] = obj;
155 
156  return obj;
157 }
158 
160 {
162  if (!cmpTerrain)
163  return NULL;
164  return cmpTerrain->GetCTerrain();
165 }
166 
168 {
169  std::map<ObjectKey, CObjectEntry*>::iterator it;
170  while (m_Objects.end() != (it = find_if(m_Objects.begin(), m_Objects.end(), second_equals<CObjectEntry*>(entry))))
171  m_Objects.erase(it);
172 
173  delete entry;
174 }
175 
176 
178 {
179  std::for_each(
180  m_Objects.begin(),
181  m_Objects.end(),
182  delete_pair_2nd<ObjectKey, CObjectEntry*>
183  );
184  m_Objects.clear();
185 
186  std::for_each(
187  m_ObjectBases.begin(),
188  m_ObjectBases.end(),
189  delete_pair_2nd<CStrW, CObjectBase*>
190  );
191  m_ObjectBases.clear();
192 }
193 
195 {
196  // Mark old entries as outdated so we don't reload them from the cache
197  for (std::map<ObjectKey, CObjectEntry*>::iterator it = m_Objects.begin(); it != m_Objects.end(); ++it)
198  if (it->second->m_Base->UsesFile(path))
199  it->second->m_Outdated = true;
200 
201  // Reload actors that use a changed object
202  for (std::map<CStrW, CObjectBase*>::iterator it = m_ObjectBases.begin(); it != m_ObjectBases.end(); ++it)
203  {
204  if (it->second->UsesFile(path))
205  {
206  it->second->Reload();
207 
208  // Slightly ugly hack: The graphics system doesn't preserve enough information to regenerate the
209  // object with all correct variations, and we don't want to waste space storing it just for the
210  // rare occurrence of hotloading, so we'll tell the component (which does preserve the information)
211  // to do the reloading itself
213  for (CSimulation2::InterfaceListUnordered::const_iterator eit = cmps.begin(); eit != cmps.end(); ++eit)
214  static_cast<ICmpVisual*>(eit->second)->Hotload(it->first);
215  }
216  }
217 
218  return INFO::OK;
219 }
Path VfsPath
VFS path of the form &quot;(dir/)*file?&quot;.
Definition: vfs_path.h:40
CObjectEntry * FindObject(const CStrW &objname)
const Status OK
Definition: status.h:386
#define LOGERROR
Definition: CLogger.h:35
CObjectBase * FindObjectBase(const CStrW &objname)
std::vector< u8 > ActorVariation
Definition: ObjectManager.h:51
static void delete_pair_2nd(std::pair< T, S > v)
const InterfaceListUnordered & GetEntitiesWithInterfaceUnordered(int iid)
Returns a list of components implementing the given interface, and their associated entities...
const entity_id_t SYSTEM_ENTITY
Entity ID for singleton &#39;system&#39; components.
Definition: Entity.h:44
Public API for simulation system.
Definition: Simulation2.h:46
Status ReloadChangedFile(const VfsPath &path)
Reload any scripts that were loaded from the given filename.
CTerrain * GetTerrain()
Get the terrain object that actors managed by this manager should be linked with (primarily for the p...
CMeshManager & m_MeshManager
Definition: ObjectManager.h:89
CObjectEntry * FindObjectVariation(const CStrW &objname, const std::vector< std::set< CStr > > &selections)
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
second_equals(const T &x)
std::vector< u8 > CalculateVariationKey(const std::vector< std::set< CStr > > &selections)
Definition: ObjectBase.cpp:301
void UnregisterFileReloadFunc(FileReloadFunc func, void *obj)
delete a callback function registered with RegisterFileReloadFunc (removes any with the same func and...
Definition: Filesystem.cpp:44
void RegisterFileReloadFunc(FileReloadFunc func, void *obj)
register a callback function to be called by ReloadChangedFiles
Definition: Filesystem.cpp:39
Definition: path.h:75
const String & string() const
Definition: path.h:123
CSkeletonAnimManager & m_SkeletonAnimManager
Definition: ObjectManager.h:90
pthread_key_t key
Definition: wpthread.cpp:140
bool operator()(const S &v)
VfsPath m_Pathname
Definition: ObjectBase.h:161
#define PROFILE(name)
Definition: Profile.h:195
i64 Status
Error handling system.
Definition: status.h:171
#define T(string_literal)
Definition: secure_crt.cpp:70
std::map< CStrW, CObjectBase * > m_ObjectBases
Definition: ObjectManager.h:94
bool operator<(const CObjectManager::ObjectKey &a) const
A simplified syntax for accessing entity components.
Definition: CmpPtr.h:55
virtual CTerrain * GetCTerrain()=0
static Status ReloadChangedFileCB(void *param, const VfsPath &path)
boost::unordered_map< entity_id_t, IComponent * > InterfaceListUnordered
Definition: Simulation2.h:197
void DeleteObject(CObjectEntry *entry)
std::map< ObjectKey, CObjectEntry * > m_Objects
Definition: ObjectManager.h:93
CObjectManager(CMeshManager &meshManager, CSkeletonAnimManager &skeletonAnimManager, CSimulation2 &simulation)
CSimulation2 & m_Simulation
Definition: ObjectManager.h:91