OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4DefList.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Object definition */
19 
20 #include "C4Include.h"
21 #include "object/C4DefList.h"
22 
23 #include "c4group/C4Components.h"
24 #include "config/C4Config.h"
25 #include "object/C4Def.h"
26 #include "platform/C4FileMonitor.h"
27 #include "game/C4GameVersion.h"
28 #include "c4group/C4Language.h"
29 #include "game/C4GameScript.h"
30 #include "control/C4Record.h"
31 
32 #include "lib/StdMeshLoader.h"
33 
34 namespace
35 {
36  class C4SkeletonManager : public StdMeshSkeletonLoader
37  {
38  virtual StdMeshSkeleton* GetSkeletonByDefinition(const char* definition) const
39  {
40  // find the definition
41  C4Def* def = ::Definitions.ID2Def(C4ID(definition));
42  if (!def)
43  {
44  DebugLogF("WARNING: Looking up skeleton from definition '%s' failed, because there is no such definition with that ID", definition);
45  return nullptr;
46  }
47 
48  // append animations, if the definition has a mesh
49  if (!def->Graphics.IsMesh())
50  {
51  DebugLogF("WARNING: Looking up skeleton from definition '%s' failed, because the definition has no mesh", definition);
52  return nullptr;
53  }
54  else
55  {
56  StdMesh* mesh = def->Graphics.Mesh;
57 
58  return &(mesh->GetSkeleton());
59  }
60  }
61  };
62 }
63 
64 C4DefList::C4DefList() : SkeletonLoader(new C4SkeletonManager)
65 {
66  Default();
67 }
68 
70 {
71  Clear();
72 }
73 
74 int32_t C4DefList::Load(C4Group &hGroup, DWORD dwLoadWhat,
75  const char *szLanguage,
76  C4SoundSystem *pSoundSystem,
77  bool fOverload,
78  bool fSearchMessage, int32_t iMinProgress, int32_t iMaxProgress, bool fLoadSysGroups)
79 {
80  int32_t iResult=0;
81  C4Def *nDef;
82  char szEntryname[_MAX_FNAME+1];
83  C4Group hChild;
84  bool fPrimaryDef=false;
85  bool fThisSearchMessage=false;
86  bool can_be_primary_def = SEqualNoCase(GetExtension(hGroup.GetName()), "ocd");
87 
88  // This search message
89  if (fSearchMessage)
90  if (can_be_primary_def
91  || SEqualNoCase(GetExtension(hGroup.GetName()),"ocs")
92  || SEqualNoCase(GetExtension(hGroup.GetName()),"ocf"))
93  {
94  fThisSearchMessage=true;
95  fSearchMessage=false;
96  }
97 
98  if (fThisSearchMessage) { LogF("%s...",GetFilename(hGroup.GetName())); }
99 
100  // Load primary definition
101  if (can_be_primary_def)
102  {
103  if ((nDef = new C4Def))
104  {
105  if (nDef->Load(hGroup, *SkeletonLoader, dwLoadWhat, szLanguage, pSoundSystem) && Add(nDef, fOverload))
106  {
107  iResult++; fPrimaryDef = true;
108  }
109  else
110  {
111  delete nDef;
112  }
113  }
114  }
115 
116  // Load sub definitions
117  int i = 0;
118  hGroup.ResetSearch();
119  while (hGroup.FindNextEntry(C4CFN_DefFiles,szEntryname))
120  if (hChild.OpenAsChild(&hGroup,szEntryname))
121  {
122  // Hack: Assume that there are sixteen sub definitions to avoid unnecessary I/O
123  int iSubMinProgress = std::min(iMaxProgress, iMinProgress + ((iMaxProgress - iMinProgress) * i) / 16);
124  int iSubMaxProgress = std::min(iMaxProgress, iMinProgress + ((iMaxProgress - iMinProgress) * (i + 1)) / 16);
125  ++i;
126  iResult += Load(hChild,dwLoadWhat,szLanguage,pSoundSystem,fOverload,fSearchMessage,iSubMinProgress,iSubMaxProgress);
127  hChild.Close();
128  }
129 
130  // load additional system scripts for def groups only
131  if (!fPrimaryDef && fLoadSysGroups) Game.LoadAdditionalSystemGroup(hGroup);
132 
133  if (fThisSearchMessage) { LogF(LoadResStr("IDS_PRC_DEFSLOADED"),iResult); }
134 
135  // progress (could go down one level of recursion...)
136  if (iMinProgress != iMaxProgress) Game.SetInitProgress(float(iMaxProgress));
137 
138  return iResult;
139 }
140 
141 int32_t C4DefList::Load(const char *szFilename,
142  DWORD dwLoadWhat, const char *szLanguage,
143  C4SoundSystem *pSoundSystem,
144  bool fOverload, int32_t iMinProgress, int32_t iMaxProgress)
145 {
146  // Load from specified file
147  C4Group hGroup;
148  if (!Reloc.Open(hGroup, szFilename))
149  {
150  // Specified file not found (failure)
151  LogFatal(FormatString(LoadResStr("IDS_PRC_DEFNOTFOUND"), szFilename).getData());
152  LoadFailure=true;
153  return 0; // 0 definitions loaded
154  }
155  int32_t nDefs = Load(hGroup,dwLoadWhat,szLanguage,pSoundSystem,fOverload,true,iMinProgress,iMaxProgress);
156  hGroup.Close();
157 
158  // progress (could go down one level of recursion...)
159  if (iMinProgress != iMaxProgress) Game.SetInitProgress(float(iMaxProgress));
160 
161  return nDefs;
162 }
163 
164 bool C4DefList::Add(C4Def *pDef, bool fOverload)
165 {
166  if (!pDef) return false;
167 
168  // Check old def to overload
169  C4Def *pLastDef = ID2Def(pDef->id);
170  if (pLastDef && !fOverload) return false;
171 
172  // Log overloaded def
174  if (pLastDef)
175  {
176  LogF(LoadResStr("IDS_PRC_DEFOVERLOAD"),pDef->GetName(),pLastDef->id.ToString());
178  {
179  LogF(" Old def at %s",pLastDef->Filename);
180  LogF(" Overload by %s",pDef->Filename);
181  }
182  }
183 
184  // Remove old def
185  Remove(pDef->id);
186 
187  // Add new def
188  pDef->Next=FirstDef;
189  FirstDef=pDef;
190 
191  return true;
192 }
193 
195 {
196  C4Def *cdef,*prev;
197  for (cdef=FirstDef,prev=nullptr; cdef; prev=cdef,cdef=cdef->Next)
198  if (cdef->id==id)
199  {
200  if (prev) prev->Next=cdef->Next;
201  else FirstDef=cdef->Next;
202  delete cdef;
203  return true;
204  }
205  return false;
206 }
207 
209 {
210  C4Def *cdef,*prev;
211  for (cdef=FirstDef,prev=nullptr; cdef; prev=cdef,cdef=cdef->Next)
212  if (cdef==def)
213  {
214  if (prev) prev->Next=cdef->Next;
215  else FirstDef=cdef->Next;
216  delete cdef;
217  return;
218  }
219 }
220 
221 void C4DefList::Clear()
222 {
223  C4Def *cdef,*next;
224  for (cdef=FirstDef; cdef; cdef=next)
225  {
226  next=cdef->Next;
227  delete cdef;
228  }
229  FirstDef=nullptr;
230  // clear quick access table
231  table.clear();
232  // clear loaded skeletons
233  SkeletonLoader->Clear();
234 }
235 
237 {
238  if (id==C4ID::None) return nullptr;
239  if (table.empty())
240  {
241  // table not yet built: search list
242  C4Def *cdef;
243  for (cdef=FirstDef; cdef; cdef=cdef->Next)
244  if (cdef->id==id) return cdef;
245  }
246  else
247  {
248  Table::const_iterator it = table.find(id);
249  if (it != table.end())
250  return it->second;
251  }
252  // none found
253  return nullptr;
254 }
255 
256 C4Def * C4DefList::GetByName(const StdStrBuf & name)
257 {
258  return ID2Def(C4ID(name));
259 }
260 
262 {
263  C4Def *cdef;
264  int32_t cindex;
265  for (cdef=FirstDef,cindex=0; cdef; cdef=cdef->Next,cindex++)
266  if (cdef->id==id) return cindex;
267  return -1;
268 }
269 
270 int32_t C4DefList::GetDefCount()
271 {
272  C4Def *cdef; int32_t ccount=0;
273  for (cdef=FirstDef; cdef; cdef=cdef->Next)
274  ccount++;
275  return ccount;
276 }
277 
278 C4Def* C4DefList::GetDef(int32_t iIndex)
279 {
280  C4Def *pDef; int32_t iCurrentIndex;
281  if (iIndex<0) return nullptr;
282  for (pDef=FirstDef,iCurrentIndex=-1; pDef; pDef=pDef->Next)
283  {
284  iCurrentIndex++;
285  if (iCurrentIndex==iIndex) return pDef;
286  }
287  return nullptr;
288 }
289 
290 std::vector<C4Def*> C4DefList::GetAllDefs(C4String *filter_property) const
291 {
292  // Collect vector of all definitions
293  // Filter for those where property evaluates to true if filter_property!=nullptr
294  std::vector<C4Def*> result;
295  result.reserve(filter_property ? 32 : table.size());
296  C4Value prop_val;
297  for (C4Def *def = FirstDef; def; def = def->Next)
298  {
299  if (filter_property)
300  {
301  if (!def->GetPropertyByS(filter_property, &prop_val)) continue;
302  if (!prop_val) continue;
303  }
304  result.push_back(def);
305  }
306  return result;
307 }
308 
309 C4Def *C4DefList::GetByPath(const char *szPath)
310 {
311  // search defs
312  const char *szDefPath;
313  for (C4Def *pDef = FirstDef; pDef; pDef = pDef->Next)
314  if ((szDefPath = Config.AtRelativePath(pDef->Filename)))
315  if (SEqual2NoCase(szPath, szDefPath))
316  {
317  // the definition itself?
318  if (!szPath[SLen(szDefPath)])
319  return pDef;
320  // or a component?
321  else if (szPath[SLen(szDefPath)] == '\\')
322  if (!strchr(szPath + SLen(szDefPath) + 1, '\\'))
323  return pDef;
324  }
325  // not found
326  return nullptr;
327 }
328 
330 {
331  C4Def *cdef,*prev,*next;
332  int32_t removed=0;
333  for (cdef=FirstDef,prev=nullptr; cdef; cdef=next)
334  {
335  next=cdef->Next;
336  if (cdef->Temporary)
337  {
338  if (prev) prev->Next=next;
339  else FirstDef=next;
340  delete cdef;
341  removed++;
342  }
343  else
344  prev=cdef;
345  }
346  // rebuild quick access table
347  BuildTable();
348  return removed;
349 }
350 
351 int32_t C4DefList::CheckEngineVersion(int32_t ver1, int32_t ver2)
352 {
353  int32_t rcount=0;
354  C4Def *cdef,*prev,*next;
355  for (cdef=FirstDef,prev=nullptr; cdef; cdef=next)
356  {
357  next=cdef->Next;
358  if (CompareVersion(cdef->rC4XVer[0],cdef->rC4XVer[1],ver1,ver2) > 0)
359  {
360  if (prev) prev->Next=cdef->Next;
361  else FirstDef=cdef->Next;
362  delete cdef;
363  rcount++;
364  }
365  else prev=cdef;
366  }
367  return rcount;
368 }
369 
371 {
372  int32_t rcount=0, rcount2;
373  C4Def *cdef,*prev,*next;
374  do
375  {
376  rcount2 = rcount;
377  for (cdef=FirstDef,prev=nullptr; cdef; cdef=next)
378  {
379  next=cdef->Next;
380  for (int32_t i = 0; i < cdef->RequireDef.GetNumberOfIDs(); i++)
381  if (GetIndex(cdef->RequireDef.GetID(i)) < 0)
382  {
383  (prev ? prev->Next : FirstDef) = cdef->Next;
384  delete cdef;
385  rcount++;
386  }
387  }
388  }
389  while (rcount != rcount2);
390  return rcount;
391 }
392 
393 void C4DefList::Draw(C4ID id, C4Facet &cgo, bool fSelected, int32_t iColor)
394 {
395  C4Def *cdef = ID2Def(id);
396  if (cdef) cdef->Draw(cgo,fSelected,iColor);
397 }
398 
400 {
401  FirstDef=nullptr;
402  LoadFailure=false;
403  table.clear();
404 }
405 
406 bool C4DefList::Reload(C4Def *pDef, DWORD dwLoadWhat, const char *szLanguage, C4SoundSystem *pSoundSystem)
407 {
408  // Safety
409  if (!pDef) return false;
410  // backup graphics names and pointers
411  // GfxBackup-dtor will ensure that upon loading-failure all graphics are reset to default
412  C4DefGraphicsPtrBackup GfxBackup;
413  GfxBackup.Add(&pDef->Graphics);
414  // Clear def
415  pDef->Clear(); // Assume filename is being kept
416  // Reload def
417  C4Group hGroup;
418  if (!hGroup.Open(pDef->Filename)) return false;
419  // clear all skeletons in that group, so that deleted skeletons are also deleted in the engine
420  SkeletonLoader->RemoveSkeletonsInGroup(hGroup.GetName());
421  // load the definition
422  if (!pDef->Load(hGroup, *SkeletonLoader, dwLoadWhat, szLanguage, pSoundSystem, &GfxBackup)) return false;
423  hGroup.Close();
424  // rebuild quick access table
425  BuildTable();
426  // handle skeleton appends and includes
428  // restore graphics
429  GfxBackup.AssignUpdate();
430  // Success
431  return true;
432 }
433 
434 bool C4DefList::DrawFontImage(const char* szImageTag, C4Facet& cgo, C4DrawTransform* pTransform)
435 {
436  return Game.DrawTextSpecImage(cgo, szImageTag, pTransform);
437 }
438 
439 float C4DefList::GetFontImageAspect(const char* szImageTag)
440 {
441  return Game.GetTextSpecImageAspect(szImageTag);
442 }
443 
445 {
446  for (Table::iterator it = table.begin(); it != table.end(); ++it)
447  it->second->Synchronize();
448 }
449 
451 {
452  for (Table::iterator it = table.begin(); it != table.end(); ++it)
453  it->second->ResetIncludeDependencies();
454 }
455 
457 {
458  // Sort all definitions by DefinitionPriority property (descending)
459  // Build vector of definitions
460  int32_t n = GetDefCount();
461  if (!n) return;
462  std::vector<C4Def *> def_vec;
463  def_vec.reserve(n);
464  for (C4Def *def = FirstDef; def; def = def->Next)
465  def_vec.push_back(def);
466  // Sort it
467  std::stable_sort(def_vec.begin(), def_vec.end(), [](C4Def *a, C4Def *b) {
468  return b->GetPropertyInt(P_DefinitionPriority) < a->GetPropertyInt(P_DefinitionPriority);
469  });
470  // Restore linked list in new definition order
471  C4Def *prev_def = nullptr;
472  for (C4Def *def : def_vec)
473  {
474  if (prev_def)
475  prev_def->Next = def;
476  else
477  FirstDef = def;
478  prev_def = def;
479  }
480  if (prev_def) prev_def->Next = nullptr;
481 }
482 
484 {
485  for (C4Def *def = FirstDef; def; def = def->Next)
486  {
487  if (Config.General.DebugRec)
488  {
489  // TODO: Might not be synchronous on runtime join since is run by joining
490  // client but not by host. Might need to go to Synchronize().
491  char sz[32+1];
492  strncpy(sz, def->id.ToString(), 32+1);
493  AddDbgRec(RCT_Definition, sz, 32);
494  }
495  C4AulParSet Pars(def);
496  def->Call(PSF_Definition, &Pars);
497  }
498 }
499 
501 {
502  table.clear();
503  for (C4Def *def = FirstDef; def; def = def->Next)
504  table.insert(std::make_pair(def->id, def));
505 }
506 
508 {
509  SkeletonLoader->ResolveIncompleteSkeletons();
510 }
511 
513 {
514  return *SkeletonLoader;
515 }
char * GetFilename(char *szPath)
Definition: StdFile.cpp:55
C4Def * ID2Def(C4ID id)
void SetInitProgress(float fToProgress)
Definition: C4Game.cpp:3389
virtual ~C4DefList()
bool Load(C4Group &hGroup, StdMeshSkeletonLoader &loader, DWORD dwLoadWhat, const char *szLanguage, class C4SoundSystem *pSoundSystem=nullptr, C4DefGraphicsPtrBackup *gfx_backup=nullptr)
C4ID id
Definition: C4Def.h:103
C4Config Config
Definition: C4Config.cpp:837
virtual const char * GetName() const
Definition: C4PropList.cpp:267
float GetTextSpecImageAspect(const char *szSpec)
Definition: C4Game.cpp:3763
int32_t VerboseObjectLoading
Definition: C4Config.h:100
C4Game Game
Definition: C4Globals.cpp:52
C4Def * GetDef(int32_t Index)
#define b
C4ConfigGeneral General
Definition: C4Config.h:252
void BuildTable()
Definition: C4DefList.cpp:500
C4Def * GetByPath(const char *szPath)
Definition: C4DefList.cpp:309
virtual float GetFontImageAspect(const char *szImageTag)
Definition: stub-handle.cpp:80
int CompareVersion(int iVer1, int iVer2, int iRVer1=C4XVER1, int iRVer2=C4XVER2)
Definition: C4GameVersion.h:51
bool Add(C4Def *ndef, bool fOverload)
bool SEqualNoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:184
int32_t GetDefCount()
const StdMeshSkeleton & GetSkeleton() const
Definition: StdMesh.h:205
bool Reload(C4Def *pDef, DWORD dwLoadWhat, const char *szLanguage, C4SoundSystem *pSoundSystem=nullptr)
Definition: C4DefList.cpp:406
C4Def * Next
Definition: C4Def.h:201
#define a
size_t SLen(const char *sptr)
Definition: Standard.h:78
virtual bool DrawFontImage(const char *szImageTag, C4Facet &rTarget, C4DrawTransform *pTransform)
Definition: stub-handle.cpp:79
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
void Add(C4DefGraphics *pGraphics)
bool Temporary
Definition: C4Def.h:202
C4ConfigGraphics Graphics
Definition: C4Config.h:254
StdMeshSkeletonLoader & GetSkeletonLoader()
Definition: C4DefList.cpp:512
int iResult
Definition: C4GroupMain.cpp:39
void Clear()
Definition: C4Def.cpp:326
bool DebugLogF(const char *strMessage...)
Definition: C4Log.cpp:281
void AppendAndIncludeSkeletons()
Definition: C4DefList.cpp:507
bool IsMesh() const
Definition: C4DefGraphics.h:73
const char * GetName() const
Definition: C4Group.cpp:1845
virtual bool GetPropertyByS(const C4String *k, C4Value *pResult) const
Definition: C4PropList.cpp:734
void Remove(C4Def *def)
Definition: C4DefList.cpp:208
void CallEveryDefinition()
Definition: stub-handle.cpp:77
int32_t CheckRequireDef()
Definition: C4DefList.cpp:370
bool Open(const char *szGroupName, bool fCreate=false)
Definition: C4Group.cpp:514
static const C4ID None
Definition: C4Id.h:42
void Draw(C4Facet &cgo, bool fSelected=false, DWORD iColor=0, C4Object *pObj=nullptr, int32_t iPhaseX=0, int32_t iPhaseY=0, C4DrawTransform *trans=nullptr, const char *graphicsName=nullptr)
Definition: C4Def.cpp:601
void AddDbgRec(C4RecordChunkType eType, const void *pData, int iSize)
Definition: C4Record.cpp:36
Definition: C4Def.h:100
bool Close()
Definition: C4Group.cpp:755
bool Open(C4Group &hGroup, const char *filename) const
Definition: C4Reloc.cpp:69
bool LogFatal(const char *szMessage)
Definition: C4Log.cpp:230
#define _MAX_FNAME
void Clear()
char * GetExtension(char *szFilename)
Definition: StdFile.cpp:131
int32_t rC4XVer[2]
Definition: C4Def.h:104
C4Def * GetByName(const StdStrBuf &)
Definition: C4Id.h:28
int32_t Load(C4Group &hGroup, DWORD dwLoadWhat, const char *szLanguage, C4SoundSystem *pSoundSystem=nullptr, bool fOverload=false, bool fSearchMessage=false, int32_t iMinProgress=0, int32_t iMaxProgress=0, bool fLoadSysGroups=true)
Definition: C4DefList.cpp:74
bool LoadFailure
Definition: C4DefList.h:31
C4Reloc Reloc
Definition: C4Reloc.cpp:22
void ResetIncludeDependencies()
Definition: stub-handle.cpp:78
void Draw(C4ID id, C4Facet &cgo, bool fSelected, int32_t iColor)
Definition: C4DefList.cpp:393
void Default()
Definition: C4DefList.cpp:399
void SortByPriority()
Definition: stub-handle.cpp:76
void Synchronize()
Definition: C4DefList.cpp:444
C4IDList RequireDef
Definition: C4Def.h:105
int32_t GetIndex(C4ID id)
Definition: C4DefList.cpp:261
bool FindNextEntry(const char *szWildCard, StdStrBuf *sFileName=nullptr, size_t *iSize=nullptr, bool fStartAtFilename=false)
Definition: C4Group.cpp:1780
const char * ToString() const
Definition: C4Id.h:62
int32_t CheckEngineVersion(int32_t ver1, int32_t ver2)
Definition: C4DefList.cpp:351
bool SEqual2NoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:197
#define PSF_Definition
Definition: C4GameScript.h:126
int32_t GetPropertyInt(C4PropertyName k, int32_t default_val=0) const
Definition: C4PropList.cpp:863
char Filename[_MAX_FNAME+1]
Definition: C4Def.h:179
#define C4CFN_DefFiles
Definition: C4Components.h:166
int32_t DebugRec
Definition: C4Config.h:61
void ResetSearch(bool reload_contents=false)
Definition: C4Group.cpp:1013
C4DefList Definitions
Definition: C4Globals.cpp:49
bool LoadAdditionalSystemGroup(class C4Group &parent_group)
Definition: C4Game.cpp:2888
const char * AtRelativePath(const char *szFilename)
Definition: C4Config.cpp:660
C4Value Call(C4PropertyName k, C4AulParSet *pPars=0, bool fPassErrors=false)
Definition: C4PropList.h:112
C4ID GetID(size_t index, int32_t *ipCount=nullptr) const
Definition: C4IDList.cpp:99
int32_t RemoveTemporary()
Definition: C4DefList.cpp:329
uint32_t DWORD
int32_t GetNumberOfIDs() const
Definition: C4IDList.cpp:197
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:253
C4DefGraphics Graphics
Definition: C4Def.h:194
std::vector< C4Def * > GetAllDefs(C4String *filter_property=nullptr) const
Definition: C4DefList.cpp:290
C4Def * FirstDef
Definition: C4DefList.h:35
bool OpenAsChild(C4Group *pMother, const char *szEntryName, bool fExclusive=false, bool fCreate=false)
Definition: C4Group.cpp:1585
Table table
Definition: C4DefList.h:33
bool DrawTextSpecImage(C4Facet &fctTarget, const char *szSpec, class C4DrawTransform *pTransform, uint32_t dwClr=0xff)
Definition: C4Game.cpp:3741
virtual StdMeshSkeleton * GetSkeletonByDefinition(const char *definition) const =0
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:277