ThingFactory.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: ThingFactory.cpp /////////////////////////////////////////////////////////////////////////
  24. // Created: Colin Day, April 2001
  25. // Desc: This is how we go and make our things, we make our things, we make our things!
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "Common/ThingFactory.h"
  30. #include "Common/ThingTemplate.h"
  31. #include "Common/FileSystem.h"
  32. #include "Common/GameAudio.h"
  33. #include "Common/MapObject.h"
  34. #include "Common/ModuleFactory.h"
  35. #include "Common/RandomValue.h"
  36. #include "GameLogic/GameLogic.h"
  37. #include "GameLogic/Object.h"
  38. #include "Common/Player.h"
  39. #include "Common/PlayerList.h"
  40. #include "GameLogic/PartitionManager.h"
  41. #include "GameLogic/Module/CreateModule.h"
  42. #include "Common/ProductionPrerequisite.h"
  43. #include "GameClient/GameClient.h"
  44. #include "GameClient/Drawable.h"
  45. #include "Common/INI.h"
  46. #ifdef _INTERNAL
  47. // for occasional debugging...
  48. ///#pragma optimize("", off)
  49. ///#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  50. #endif
  51. enum { TEMPLATE_HASH_SIZE = 12288 };
  52. // PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
  53. ThingFactory *TheThingFactory = NULL; ///< Thing manager singleton declaration
  54. // STATIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
  55. ///////////////////////////////////////////////////////////////////////////////////////////////////
  56. // PRIVATE METHODS
  57. ///////////////////////////////////////////////////////////////////////////////////////////////////
  58. //-------------------------------------------------------------------------------------------------
  59. /** Free all data loaded into this template database */
  60. //-------------------------------------------------------------------------------------------------
  61. void ThingFactory::freeDatabase( void )
  62. {
  63. while (m_firstTemplate)
  64. {
  65. ThingTemplate* tmpl = m_firstTemplate;
  66. m_firstTemplate = m_firstTemplate->friend_getNextTemplate();
  67. tmpl->deleteInstance();
  68. }
  69. m_templateHashMap.clear();
  70. } // end freeDatabase
  71. //-------------------------------------------------------------------------------------------------
  72. /** add the thing template passed in, into the databse */
  73. //-------------------------------------------------------------------------------------------------
  74. void ThingFactory::addTemplate( ThingTemplate *tmplate )
  75. {
  76. ThingTemplateHashMapIt tIt = m_templateHashMap.find(tmplate->getName());
  77. if (tIt != m_templateHashMap.end()) {
  78. DEBUG_CRASH(("Duplicate Thing Template name found: %s\n", tmplate->getName().str()));
  79. }
  80. // Link it to the list
  81. tmplate->friend_setNextTemplate(m_firstTemplate);
  82. m_firstTemplate = tmplate;
  83. // Add it to the hash table.
  84. m_templateHashMap[tmplate->getName()] = tmplate;
  85. } // end addTemplate
  86. ///////////////////////////////////////////////////////////////////////////////////////////////////
  87. // PUBLIC METHODS
  88. ///////////////////////////////////////////////////////////////////////////////////////////////////
  89. //-------------------------------------------------------------------------------------------------
  90. //-------------------------------------------------------------------------------------------------
  91. ThingFactory::ThingFactory()
  92. {
  93. m_firstTemplate = NULL;
  94. m_nextTemplateID = 1; // not zero!
  95. m_templateHashMap.resize( TEMPLATE_HASH_SIZE );
  96. } // end ThingFactory
  97. //-------------------------------------------------------------------------------------------------
  98. //-------------------------------------------------------------------------------------------------
  99. ThingFactory::~ThingFactory()
  100. {
  101. // free all the template data
  102. freeDatabase();
  103. } // end ~ThingFactory
  104. //-------------------------------------------------------------------------------------------------
  105. /** Create a new template with name 'name' and add to our template list */
  106. //-------------------------------------------------------------------------------------------------
  107. ThingTemplate *ThingFactory::newTemplate( const AsciiString& name )
  108. {
  109. ThingTemplate *newTemplate;
  110. // allocate template
  111. newTemplate = newInstance(ThingTemplate);
  112. // if the default template is present, get it and copy over any data to the new template
  113. const ThingTemplate *defaultT = findTemplate( AsciiString( "DefaultThingTemplate" ) );
  114. if( defaultT )
  115. {
  116. // copy over static data
  117. *newTemplate = *defaultT;
  118. newTemplate->setCopiedFromDefault();
  119. } // end if
  120. // give template a unique identifier
  121. newTemplate->friend_setTemplateID( m_nextTemplateID++ );
  122. DEBUG_ASSERTCRASH( m_nextTemplateID != 0, ("m_nextTemplateID wrapped to zero") );
  123. // assign name
  124. newTemplate->friend_setTemplateName( name );
  125. // add to list
  126. addTemplate( newTemplate );
  127. // return the newly created template
  128. return newTemplate;
  129. }
  130. //-------------------------------------------------------------------------------------------------
  131. /** Create newTemplate, copy data from final override of 'thingTemplate' to the newly created one,
  132. * and add newTemplate as the m_override of that final override. NOTE that newTemplate
  133. * is *NOT* added to master template list, it is a hidden place to store
  134. * override values for 'thingTemplate' */
  135. //-------------------------------------------------------------------------------------------------
  136. ThingTemplate* ThingFactory::newOverride( ThingTemplate *thingTemplate )
  137. {
  138. // sanity
  139. DEBUG_ASSERTCRASH( thingTemplate, ("newOverride(): NULL 'parent' thing template\n") );
  140. // sanity just for debuging, the weapon must be in the master list to do overrides
  141. DEBUG_ASSERTCRASH( findTemplate( thingTemplate->getName() ) != NULL,
  142. ("newOverride(): Thing template '%s' not in master list\n",
  143. thingTemplate->getName().str()) );
  144. // find final override of the 'parent' template
  145. ThingTemplate *child = (ThingTemplate*) thingTemplate->friend_getFinalOverride();
  146. // allocate new template
  147. ThingTemplate *newTemplate = newInstance(ThingTemplate);
  148. // copy data from final override to 'newTemplate' as a set of initial default values
  149. *newTemplate = *child;
  150. newTemplate->setCopiedFromDefault();
  151. newTemplate->markAsOverride();
  152. child->setNextOverride(newTemplate);
  153. // return the newly created override for us to set values with etc
  154. return newTemplate;
  155. } // end newOverride
  156. //-------------------------------------------------------------------------------------------------
  157. /** Init */
  158. //-------------------------------------------------------------------------------------------------
  159. void ThingFactory::init( void )
  160. {
  161. } // end init
  162. //-------------------------------------------------------------------------------------------------
  163. /** Reset */
  164. //-------------------------------------------------------------------------------------------------
  165. void ThingFactory::reset( void )
  166. {
  167. ThingTemplate *t;
  168. // go through all templates and delete any overrides
  169. for( t = m_firstTemplate; t; /* empty */ )
  170. {
  171. Bool possibleAdjustment = FALSE;
  172. // t itself can be deleted if it is something created for this map only. Therefore,
  173. // we need to store what the next item is so that we don't orphan a bunch of templates.
  174. ThingTemplate *nextT = t->friend_getNextTemplate();
  175. if (t == m_firstTemplate) {
  176. possibleAdjustment = TRUE;
  177. }
  178. // if stillValid is NULL after we delete the overrides, then this template was created for
  179. // this map only. If it also happens to be m_firstTemplate, then we need to update m_firstTemplate
  180. // as well. Finally, if it was only created for this map, we need to remove the name from the
  181. // hash map, to prevent any crashes.
  182. AsciiString templateName = t->getName();
  183. Overridable *stillValid = t->deleteOverrides();
  184. if (stillValid == NULL && possibleAdjustment) {
  185. m_firstTemplate = nextT;
  186. }
  187. if (stillValid == NULL) {
  188. // Also needs to be removed from the Hash map.
  189. m_templateHashMap.erase(templateName);
  190. }
  191. t = nextT;
  192. }
  193. } // end reset
  194. //-------------------------------------------------------------------------------------------------
  195. /** Update */
  196. //-------------------------------------------------------------------------------------------------
  197. void ThingFactory::update( void )
  198. {
  199. } // end update
  200. //-------------------------------------------------------------------------------------------------
  201. /** Return the template with the matching database name */
  202. //-------------------------------------------------------------------------------------------------
  203. const ThingTemplate *ThingFactory::findByTemplateID( UnsignedShort id )
  204. {
  205. for (ThingTemplate *tmpl = m_firstTemplate; tmpl; tmpl = tmpl->friend_getNextTemplate())
  206. {
  207. if (tmpl->getTemplateID() == id)
  208. return tmpl;
  209. }
  210. DEBUG_CRASH(("template %d not found\n",(Int)id));
  211. return NULL;
  212. }
  213. //-------------------------------------------------------------------------------------------------
  214. /** Return the template with the matching database name */
  215. //-------------------------------------------------------------------------------------------------
  216. ThingTemplate *ThingFactory::findTemplateInternal( const AsciiString& name )
  217. {
  218. ThingTemplateHashMapIt tIt = m_templateHashMap.find(name);
  219. if (tIt != m_templateHashMap.end()) {
  220. return tIt->second;
  221. }
  222. #ifdef LOAD_TEST_ASSETS
  223. if (!strncmp(name.str(), TEST_STRING, strlen(TEST_STRING)))
  224. {
  225. ThingTemplate *tmplate = newTemplate( AsciiString( "Un-namedTemplate" ) );
  226. // load the values
  227. tmplate->initForLTA( name );
  228. // Kinda lame, but necessary.
  229. m_templateHashMap.erase("Un-namedTemplate");
  230. m_templateHashMap[name] = tmplate;
  231. // add tmplate template to the database
  232. return findTemplateInternal( name );
  233. }
  234. #endif
  235. //DEBUG_LOG(("*** Object template %s not found\n",name.str()));
  236. return NULL;
  237. } // end getTemplate
  238. //=============================================================================
  239. Object *ThingFactory::newObject( const ThingTemplate *tmplate, Team *team, ObjectStatusBits statusBits )
  240. {
  241. if (tmplate == NULL)
  242. throw ERROR_BAD_ARG;
  243. const std::vector<AsciiString>& asv = tmplate->getBuildVariations();
  244. if (!asv.empty())
  245. {
  246. Int which = GameLogicRandomValue(0, asv.size()-1);
  247. const ThingTemplate* tmp = findTemplate( asv[which] );
  248. if (tmp != NULL)
  249. tmplate = tmp;
  250. }
  251. DEBUG_ASSERTCRASH(!tmplate->isKindOf(KINDOF_DRAWABLE_ONLY), ("You may not create Objects with the template %s, only Drawables\n",tmplate->getName().str()));
  252. // have the game logic create an object of the correct type.
  253. // (this will throw an exception on failure.)
  254. //Added ability to pass in optional statusBits. This is needed to be set prior to
  255. //the onCreate() calls... in the case of constructing.
  256. Object *obj = TheGameLogic->friend_createObject( tmplate, statusBits, team );
  257. // run the create function for the thing
  258. for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
  259. {
  260. CreateModuleInterface* create = (*m)->getCreate();
  261. if (!create)
  262. continue;
  263. create->onCreate();
  264. }
  265. //
  266. // all objects are part of the partition manager system, add it to that
  267. // system now
  268. //
  269. ThePartitionManager->registerObject( obj );
  270. obj->initObject();
  271. return obj;
  272. }
  273. //=============================================================================
  274. Drawable *ThingFactory::newDrawable(const ThingTemplate *tmplate, DrawableStatus statusBits)
  275. {
  276. if (tmplate == NULL)
  277. throw ERROR_BAD_ARG;
  278. Drawable *draw = TheGameClient->friend_createDrawable( tmplate, statusBits );
  279. /** @todo we should keep track of all the drawables we've allocated here
  280. but we'll wait until we have an drawable storage to do that cause it will
  281. all be tied together */
  282. return draw;
  283. } // end newDrawableByType
  284. #if defined(_DEBUG) || defined(_INTERNAL)
  285. AsciiString TheThingTemplateBeingParsedName;
  286. #endif
  287. //-------------------------------------------------------------------------------------------------
  288. /** Parse Object entry */
  289. //-------------------------------------------------------------------------------------------------
  290. /*static*/ void ThingFactory::parseObjectDefinition( INI* ini, const AsciiString& name, const AsciiString& reskinFrom )
  291. {
  292. #if defined(_DEBUG) || defined(_INTERNAL)
  293. TheThingTemplateBeingParsedName = name;
  294. #endif
  295. // find existing item if present
  296. ThingTemplate *thingTemplate = TheThingFactory->findTemplateInternal( name );
  297. if( !thingTemplate )
  298. {
  299. // no item is present, create a new one
  300. thingTemplate = TheThingFactory->newTemplate( name );
  301. if ( ini->getLoadType() == INI_LOAD_CREATE_OVERRIDES )
  302. {
  303. // This ThingTemplate is actually an override, so we will mark it as such so that it properly
  304. // gets deleted on ::reset().
  305. thingTemplate->markAsOverride();
  306. }
  307. }
  308. else if( ini->getLoadType() != INI_LOAD_CREATE_OVERRIDES )
  309. {
  310. //Holy crap, this sucks to debug!!!
  311. //If you have two different objects, the previous code would simply
  312. //allow you to define multiple objects with the same name, and just
  313. //nuke the old one with the new one. So, I (KM) have added this
  314. //assert to notify in case of two same-name objects.
  315. DEBUG_CRASH(( "[LINE: %d in '%s'] Duplicate factionunit %s found!", ini->getLineNum(), ini->getFilename().str(), name.str() ));
  316. }
  317. else
  318. {
  319. thingTemplate = TheThingFactory->newOverride( thingTemplate );
  320. }
  321. if (reskinFrom.isNotEmpty())
  322. {
  323. const ThingTemplate* reskinTmpl = TheThingFactory->findTemplate(reskinFrom);
  324. if (reskinTmpl)
  325. {
  326. thingTemplate->copyFrom(reskinTmpl);
  327. thingTemplate->setCopiedFromDefault();
  328. thingTemplate->setReskinnedFrom(reskinTmpl);
  329. ini->initFromINI( thingTemplate, thingTemplate->getReskinFieldParse() );
  330. }
  331. else
  332. {
  333. DEBUG_CRASH(("ObjectReskin must come after the original Object (%s, %s).\n",reskinFrom.str(),name.str()));
  334. throw INI_INVALID_DATA;
  335. }
  336. }
  337. else
  338. {
  339. ini->initFromINI( thingTemplate, thingTemplate->getFieldParse() );
  340. }
  341. thingTemplate->validate();
  342. #if defined(_DEBUG) || defined(_INTERNAL)
  343. TheThingTemplateBeingParsedName.clear();
  344. #endif
  345. }
  346. //#define CHECK_THING_NAMES
  347. #ifdef CHECK_THING_NAMES
  348. #include "Common/STLTypedefs.h"
  349. const char *outFilenameINI = "thing.txt";
  350. const char *outFilenameStringFile = "thingString.txt";
  351. void resetReportFile( void )
  352. {
  353. FILE *fp = fopen(outFilenameINI, "w");
  354. if (fp)
  355. {
  356. fprintf(fp, "-- ThingTemplate INI Report --\n\n");
  357. fclose(fp);
  358. }
  359. fp = fopen(outFilenameStringFile, "w");
  360. if (fp)
  361. {
  362. fprintf(fp, "-- ThingTemplate String File Report --\n\n");
  363. fclose(fp);
  364. }
  365. }
  366. AsciiStringList missingStrings;
  367. void reportMissingNameInStringFile( AsciiString templateName )
  368. {
  369. // see if we've seen it before
  370. AsciiStringListConstIterator cit = std::find(missingStrings.begin(), missingStrings.end(), templateName);
  371. if (cit != missingStrings.end())
  372. return;
  373. missingStrings.push_back(templateName);
  374. }
  375. void dumpMissingStringNames( void )
  376. {
  377. missingStrings.sort();
  378. FILE *fp = fopen(outFilenameStringFile, "w");
  379. if (fp)
  380. {
  381. fprintf(fp, "-- ThingTemplate String File Report --\n\n");
  382. for (AsciiStringListConstIterator cit = missingStrings.begin(); cit!=missingStrings.end(); cit++)
  383. {
  384. fprintf(fp, "OBJECT:%s\n\"%s\"\nEND\n\n", cit->str(), cit->str());
  385. }
  386. fclose(fp);
  387. }
  388. }
  389. AsciiStringList missingNames;
  390. void reportMissingNameInTemplate( AsciiString templateName )
  391. {
  392. // see if we've seen it before
  393. AsciiStringListConstIterator cit = std::find(missingNames.begin(), missingNames.end(), templateName);
  394. if (cit != missingNames.end())
  395. return;
  396. missingNames.push_back(templateName);
  397. FILE *fp = fopen(outFilenameINI, "a+");
  398. if (fp)
  399. {
  400. fprintf(fp, " DisplayName = OBJECT:%s\n", templateName.str());
  401. fclose(fp);
  402. }
  403. //reportMissingNameInStringFile( templateName );
  404. }
  405. #endif
  406. //-------------------------------------------------------------------------------------------------
  407. /** Post process phase after loading the database files */
  408. //-------------------------------------------------------------------------------------------------
  409. void ThingFactory::postProcessLoad()
  410. {
  411. #ifdef CHECK_THING_NAMES
  412. //resetReportFile();
  413. #endif
  414. // go through all thing templates
  415. for( ThingTemplate *thingTemplate = m_firstTemplate;
  416. thingTemplate;
  417. thingTemplate = thingTemplate->friend_getNextTemplate() )
  418. {
  419. // resolve the prerequisite names
  420. thingTemplate->resolveNames();
  421. #ifdef CHECK_THING_NAMES
  422. if (thingTemplate->getDisplayName().isEmpty())
  423. {
  424. reportMissingNameInTemplate( thingTemplate->getName() );
  425. }
  426. else if (wcsstr(thingTemplate->getDisplayName().str(), L"MISSING:"))
  427. {
  428. AsciiString asciiName;
  429. asciiName.translate(thingTemplate->getDisplayName());
  430. asciiName.removeLastChar();
  431. asciiName = asciiName.str() + 17;
  432. reportMissingNameInStringFile( asciiName );
  433. }
  434. #endif
  435. } // end for
  436. #ifdef CHECK_THING_NAMES
  437. dumpMissingStringNames();
  438. exit(0);
  439. #endif
  440. } // end postProcess