MissionLoader.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. //===========================================================================================================================
  2. // Spirenkov Maxim, 2003
  3. //===========================================================================================================================//
  4. //
  5. //===========================================================================================================================
  6. // MissionLoader
  7. //============================================================================================
  8. #include "Mission.h"
  9. #include "MissionLoader.h"
  10. #include "..\..\Common_h\Mission\MissionFile.h"
  11. #include "..\..\common_h\corecmds.h"
  12. //#define MissionLoaderEnableThread
  13. //#define ENABLE_MEMORY_PROFILE
  14. #define MEMORY_PROFILE_CPP_FILE "string.h"
  15. #define MEMORY_PROFILE_CPP_LINE -1
  16. //============================================================================================
  17. #ifdef MissionLoaderEnableThread
  18. DWORD WINAPI MissionLoader::MissionLoaderThreadProc(LPVOID lpParameter)
  19. {
  20. ((MissionLoader *)lpParameter)->LoadObjects();
  21. return 0;
  22. }
  23. #endif
  24. //============================================================================================
  25. MissionLoader::MissionLoader(Mission & mis, const byte * _data, dword _size) : mission(mis)
  26. {
  27. data = _data;
  28. pnt = 0;
  29. size = _size;
  30. Assert(data != 0);
  31. Assert(size > 0);
  32. threadID = 0;
  33. threadHandle = 0;
  34. objectsCount = 0;
  35. stopLoading = false;
  36. }
  37. MissionLoader::~MissionLoader()
  38. {
  39. stopLoading = true;
  40. for(long i = 0; threadHandle && i < 100; i++)
  41. {
  42. Sleep(10);
  43. }
  44. #ifndef _XBOX
  45. if(threadHandle)
  46. {
  47. TerminateThread(threadHandle, 0);
  48. threadHandle = 0;
  49. }
  50. #endif
  51. }
  52. //============================================================================================
  53. //Начать процесс загрузки
  54. bool MissionLoader::StartProcess(float loadProgressRange)
  55. {
  56. //Проверим версию данных
  57. if(!CheckId()) return false;
  58. if(objectsCount)
  59. {
  60. loadStep = loadProgressRange/objectsCount;
  61. }else{
  62. loadStep = loadProgressRange;
  63. }
  64. #ifdef MissionLoaderEnableThread
  65. threadHandle = CreateThread(NULL, 0, MissionLoaderThreadProc, this, 0, &threadID);
  66. #else
  67. LoadObjects();
  68. #endif
  69. return true;
  70. }
  71. //Залочить список объектов
  72. void MissionLoader::LockObjects()
  73. {
  74. #ifdef MissionLoaderEnableThread
  75. critSection.Enter();
  76. #endif
  77. }
  78. //Освободить список объектов
  79. void MissionLoader::UnLockObjects()
  80. {
  81. #ifdef MissionLoaderEnableThread
  82. critSection.Leave();
  83. #endif
  84. }
  85. //Процесс загрузки окончен
  86. bool MissionLoader::IsDone()
  87. {
  88. LockObjects();
  89. bool res = !IsCan();
  90. UnLockObjects();
  91. return res && (threadHandle == 0);
  92. }
  93. //============================================================================================
  94. //Этапы загрузки
  95. //============================================================================================
  96. //Проверить версию
  97. bool MissionLoader::CheckId()
  98. {
  99. MissionFileId * hdr = (MissionFileId *)Get(sizeof(MissionFileId));
  100. if(!hdr) return false;
  101. const char * id = MISSION_FILE_ID;
  102. for(long i = 0; i < sizeof(hdr->id); i++) if(hdr->id[i] != id[i]) return false;
  103. if(SwizzleLong(hdr->ver) != MISSION_FILE_VER) return false;
  104. objectsCount = SwizzleLong(hdr->objectsCount);
  105. return true;
  106. }
  107. #ifdef ENABLE_MEMORY_PROFILE
  108. struct Data
  109. {
  110. enum {name_len = 80};
  111. dword n;
  112. dword m;
  113. dword b; char name[name_len];
  114. Data() : n(0),m(0),b(0) {}
  115. };
  116. static array<Data> table(_FL_);
  117. #endif
  118. //Загрузить объекты
  119. void MissionLoader::LoadObjects()
  120. {
  121. #ifdef ENABLE_MEMORY_PROFILE
  122. CoreCommand_GetMemStat stats1(MEMORY_PROFILE_CPP_FILE, MEMORY_PROFILE_CPP_LINE);
  123. api->ExecuteCoreCommand(stats1);
  124. api->Trace("Memory state at start loading...\n use memory: %u, blocks: %u; cpp file name: %s, cpp file line: %i",
  125. stats1.totalAllocSize,
  126. stats1.numBlocks,
  127. MEMORY_PROFILE_CPP_FILE,
  128. MEMORY_PROFILE_CPP_LINE);
  129. table.DelAll();
  130. #endif
  131. //Начинаем загрузку объектов миссии
  132. while(IsCan())
  133. {
  134. //Sleep(40); //Тест асинхронной загрузки
  135. if(stopLoading) break;
  136. LockObjects();
  137. LoadObject();
  138. UnLockObjects();
  139. api->SetWatchDog();
  140. }
  141. threadHandle = 0;
  142. stopLoading = true;
  143. #ifdef ENABLE_MEMORY_PROFILE
  144. api->Trace("\n%30s %14s %14s %14s %14s %14s","Class name","Objects count","Total memory","Total blocks","Memory","Blocks");
  145. api->Trace("");
  146. array<Data *>list(_FL_); list.AddElements(table.Size());
  147. for( int i = 0 ; i < table ; i++ )
  148. {
  149. Data *data = &table[i];
  150. list[i] = data;
  151. int j = i;
  152. while( j > 0 )
  153. {
  154. if( list[j - 1]->m < list[j]->m )
  155. {
  156. Data *t = list[j - 1];
  157. list[j - 1] = list[j];
  158. list[j] = t;
  159. }
  160. else
  161. break;
  162. j--;
  163. }
  164. }
  165. for( int i = 0 ; i < list ; i++ )
  166. {
  167. const Data &data = *list[i];
  168. api->Trace("%30s %14d %14d %14d %14d %14d",data.name,data.n,data.m,data.b,data.m/data.n,data.b/data.n);
  169. }
  170. api->Trace("");
  171. #endif
  172. }
  173. //Загрузить объект
  174. void MissionLoader::LoadObject()
  175. {
  176. //Данные объекта
  177. dword size = 0;
  178. const char * objectType = GetObjectData(size);
  179. if(!objectType)
  180. {
  181. api->Trace("MissionLoader::LoadObject -> can't get object information. mis file is damage?");
  182. return;
  183. }
  184. const void * data = Get(size);
  185. if(!data)
  186. {
  187. api->Trace("MissionLoader::LoadObject -> can't get data for object \"%s\"", objectType);
  188. return;
  189. }
  190. //Создаём объект
  191. #ifdef ENABLE_MEMORY_PROFILE
  192. const char * calcAllocsInFile = MEMORY_PROFILE_CPP_FILE;
  193. const long calcAllocsInLine = MEMORY_PROFILE_CPP_LINE;
  194. CoreCommand_GetMemStat stats1(calcAllocsInFile, calcAllocsInLine);
  195. api->ExecuteCoreCommand(stats1);
  196. api->Trace("Object %s",objectType);
  197. #endif
  198. MOPReader reader(data, size);
  199. if(!mission.CreateObjectEx(objectType, reader, data, size))
  200. {
  201. api->Trace("MissionLoader::LoadObject -> can't create object \"%s\" (type: \"%s\")", reader.GetObjectID(), objectType);
  202. }
  203. mission.LoadingProgress(loadStep);
  204. #ifdef ENABLE_MEMORY_PROFILE
  205. CoreCommand_GetMemStat stats2(calcAllocsInFile, calcAllocsInLine);
  206. api->ExecuteCoreCommand(stats2);
  207. if( stats2.totalAllocSize != stats1.totalAllocSize || stats2.numBlocks != stats1.numBlocks )
  208. {
  209. api->Trace("Object %s, use memory: %u, blocks: %u; cpp file name: %s, cpp file line: %i",
  210. objectType,
  211. stats2.totalAllocSize - stats1.totalAllocSize,
  212. stats2.numBlocks - stats1.numBlocks,
  213. calcAllocsInFile,
  214. calcAllocsInLine);
  215. for( int i = 0 ; i < table ; i++ )
  216. {
  217. if( string::IsEqual(table[i].name,objectType))
  218. break;
  219. }
  220. Data *data = null;
  221. if( i < table )
  222. data = &table[i];
  223. else
  224. {
  225. data = &table[table.Add()];
  226. strcpy_s(data->name,Data::name_len,objectType);
  227. }
  228. data->n++;
  229. data->m += stats2.totalAllocSize - stats1.totalAllocSize;
  230. data->b += stats2.numBlocks - stats1.numBlocks;
  231. }
  232. #endif
  233. }
  234. //Получить данные объекта
  235. const char * MissionLoader::GetObjectData(dword & datasize)
  236. {
  237. //Получаем первый символ
  238. const char * s = (const char *)Get(1);
  239. if(!s || !s[0]) return null;
  240. //Ищем окончание строки
  241. while(true)
  242. {
  243. const char * c = (const char *)Get(1);
  244. if(!c) return null;
  245. if(!c[0]) break;
  246. }
  247. //Получаем размер данных
  248. dword * size = (dword *)Get(sizeof(dword));
  249. if(!size) return null;
  250. datasize = SwizzleDWord(*size);
  251. return s;
  252. }
  253. //============================================================================================
  254. //Входные данные
  255. //============================================================================================
  256. //Получить данные
  257. __forceinline const void * MissionLoader::Get(dword s)
  258. {
  259. if(pnt + s > size) return null;
  260. const void * p = data + pnt;
  261. pnt += s;
  262. return p;
  263. }
  264. //Окончание потока
  265. bool MissionLoader::IsCan()
  266. {
  267. return pnt < size;
  268. }