afxChoreographer.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  2. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  3. // Copyright (C) 2015 Faust Logic, Inc.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to
  7. // deal in the Software without restriction, including without limitation the
  8. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9. // sell copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. // IN THE SOFTWARE.
  22. //
  23. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  24. #include "afx/arcaneFX.h"
  25. #include "console/engineAPI.h"
  26. #include "T3D/gameBase/gameConnection.h"
  27. #include "math/mathIO.h"
  28. #include "console/compiler.h"
  29. #include "afx/afxConstraint.h"
  30. #include "afx/afxChoreographer.h"
  31. #include "afx/afxEffectWrapper.h"
  32. #include "afx/util/afxParticlePool.h"
  33. #include "afx/forces/afxForceSet.h"
  34. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  35. IMPLEMENT_CO_DATABLOCK_V1(afxChoreographerData);
  36. ConsoleDocClass( afxChoreographerData,
  37. "@brief Datablock base class used by choreographers.\n\n"
  38. "@ingroup afxChoreographers\n"
  39. "@ingroup AFX\n"
  40. "@ingroup Datablocks\n"
  41. );
  42. afxChoreographerData::afxChoreographerData()
  43. {
  44. exec_on_new_clients = false;
  45. echo_packet_usage = 100;
  46. client_script_file = ST_NULLSTRING;
  47. client_init_func = ST_NULLSTRING;
  48. }
  49. afxChoreographerData::afxChoreographerData(const afxChoreographerData& other, bool temp_clone) : GameBaseData(other, temp_clone)
  50. {
  51. exec_on_new_clients = other.exec_on_new_clients;
  52. echo_packet_usage = other.echo_packet_usage;
  53. client_script_file = other.client_script_file;
  54. client_init_func = other.client_init_func;
  55. }
  56. #define myOffset(field) Offset(field, afxChoreographerData)
  57. void afxChoreographerData::initPersistFields()
  58. {
  59. docsURL;
  60. addField("execOnNewClients", TypeBool, myOffset(exec_on_new_clients),
  61. "...");
  62. addField("echoPacketUsage", TypeS8, myOffset(echo_packet_usage),
  63. "...");
  64. addField("clientScriptFile", TypeFilename, myOffset(client_script_file),
  65. "...");
  66. addField("clientInitFunction", TypeString, myOffset(client_init_func),
  67. "...");
  68. Parent::initPersistFields();
  69. }
  70. void afxChoreographerData::packData(BitStream* stream)
  71. {
  72. Parent::packData(stream);
  73. stream->write(exec_on_new_clients);
  74. stream->write(echo_packet_usage);
  75. stream->writeString(client_script_file);
  76. stream->writeString(client_init_func);
  77. }
  78. void afxChoreographerData::unpackData(BitStream* stream)
  79. {
  80. Parent::unpackData(stream);
  81. stream->read(&exec_on_new_clients);
  82. stream->read(&echo_packet_usage);
  83. client_script_file = stream->readSTString();
  84. client_init_func = stream->readSTString();
  85. }
  86. bool afxChoreographerData::preload(bool server, String &errorStr)
  87. {
  88. if (!Parent::preload(server, errorStr))
  89. return false;
  90. if (!server && client_script_file != ST_NULLSTRING)
  91. {
  92. Compiler::gSyntaxError = false;
  93. Con::evaluate(avar("exec(\"%s\");", client_script_file), false, 0);
  94. if (Compiler::gSyntaxError)
  95. {
  96. Con::errorf("afxChoreographerData: failed to exec clientScriptFile \"%s\" -- syntax error", client_script_file);
  97. Compiler::gSyntaxError = false;
  98. }
  99. }
  100. return true;
  101. }
  102. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  103. IMPLEMENT_CO_DATABLOCK_V1(afxChoreographer);
  104. ConsoleDocClass( afxChoreographer,
  105. "@brief Base class used by choreographers.\n\n"
  106. "@ingroup afxChoreographers\n"
  107. "@ingroup AFX\n"
  108. );
  109. afxChoreographer::afxChoreographer()
  110. {
  111. datablock = 0; // datablock initializer (union these?)
  112. exeblock = 0; // object to use in executef callouts
  113. // create the constraint manager
  114. constraint_mgr = new afxConstraintMgr();
  115. ranking = 0;
  116. lod = 0;
  117. exec_conds_mask = 0;
  118. choreographer_id = 0;
  119. mExtra = 0;
  120. started_with_newop = false;
  121. postpone_activation = false;
  122. remapped_cons_sent = false; // CONSTRAINT REMAPPING
  123. dyn_cons_defs = &dc_defs_a;
  124. dyn_cons_defs2 = &dc_defs_b;
  125. proc_after_obj = 0;
  126. trigger_mask = 0;
  127. force_set_mgr = 0;
  128. mOrderGUID = 0x0FFFFFFF;
  129. }
  130. afxChoreographer::~afxChoreographer()
  131. {
  132. explicit_clients.clear();
  133. for (S32 i = 0; i < dyn_cons_defs->size(); i++)
  134. {
  135. if ((*dyn_cons_defs)[i].cons_type == POINT_CONSTRAINT && (*dyn_cons_defs)[i].cons_obj.point != NULL)
  136. delete (*dyn_cons_defs)[i].cons_obj.point;
  137. else if ((*dyn_cons_defs)[i].cons_type == TRANSFORM_CONSTRAINT && (*dyn_cons_defs)[i].cons_obj.xfm != NULL)
  138. delete (*dyn_cons_defs)[i].cons_obj.xfm;
  139. }
  140. constraint_mgr->clearAllScopeableObjs();
  141. delete constraint_mgr;
  142. delete force_set_mgr;
  143. }
  144. void afxChoreographer::initPersistFields()
  145. {
  146. docsURL;
  147. // conditionals
  148. addField("extra", TYPEID<SimObject>(), Offset(mExtra, afxChoreographer),
  149. "...");
  150. addField("postponeActivation", TypeBool, Offset(postpone_activation, afxChoreographer),
  151. "...");
  152. Parent::initPersistFields();
  153. }
  154. bool afxChoreographer::onAdd()
  155. {
  156. if (!Parent::onAdd())
  157. return(false);
  158. if (isServerObject())
  159. choreographer_id = arcaneFX::registerChoreographer(this);
  160. else
  161. {
  162. if (proc_after_obj)
  163. {
  164. processAfter(proc_after_obj);
  165. proc_after_obj = 0;
  166. }
  167. force_set_mgr = new afxForceSetMgr();
  168. if (datablock && datablock->client_init_func != ST_NULLSTRING)
  169. Con::executef(datablock->client_init_func, getIdString());
  170. }
  171. return(true);
  172. }
  173. void afxChoreographer::onRemove()
  174. {
  175. for (S32 i = 0; i < particle_pools.size(); i++)
  176. if (particle_pools[i])
  177. particle_pools[i]->setChoreographer(0);
  178. particle_pools.clear();
  179. if (isServerObject())
  180. arcaneFX::unregisterChoreographer(this);
  181. else
  182. arcaneFX::unregisterClientChoreographer(this);
  183. choreographer_id = 0;
  184. Parent::onRemove();
  185. }
  186. void afxChoreographer::onDeleteNotify(SimObject* obj)
  187. {
  188. if (dynamic_cast<SceneObject*>(obj))
  189. {
  190. SceneObject* scn_obj = (SceneObject*)(obj);
  191. for (S32 i = 0; i < dyn_cons_defs->size(); i++)
  192. if ((*dyn_cons_defs)[i].cons_type != OBJECT_CONSTRAINT || (*dyn_cons_defs)[i].cons_obj.object != scn_obj)
  193. dyn_cons_defs2->push_back((*dyn_cons_defs)[i]);
  194. Vector<dynConstraintDef>* tmp = dyn_cons_defs;
  195. dyn_cons_defs = dyn_cons_defs2;
  196. dyn_cons_defs2 = tmp;
  197. dyn_cons_defs2->clear();
  198. if (isServerObject() && scn_obj->isScopeable())
  199. constraint_mgr->removeScopeableObject(scn_obj);
  200. }
  201. else if (dynamic_cast<NetConnection*>(obj))
  202. {
  203. removeExplicitClient((NetConnection*)obj);
  204. }
  205. Parent::onDeleteNotify(obj);
  206. }
  207. bool afxChoreographer::onNewDataBlock(GameBaseData* dptr, bool reload)
  208. {
  209. datablock = dynamic_cast<afxChoreographerData*>(dptr);
  210. if (!datablock || !Parent::onNewDataBlock(dptr, reload))
  211. return false;
  212. exeblock = datablock;
  213. return true;
  214. }
  215. void afxChoreographer::pack_constraint_info(NetConnection* conn, BitStream* stream)
  216. {
  217. stream->write(dyn_cons_defs->size());
  218. for (S32 i = 0; i < dyn_cons_defs->size(); i++)
  219. {
  220. if ((*dyn_cons_defs)[i].cons_type == OBJECT_CONSTRAINT && (*dyn_cons_defs)[i].cons_obj.object != NULL)
  221. {
  222. stream->writeString((*dyn_cons_defs)[i].cons_name);
  223. stream->write((*dyn_cons_defs)[i].cons_type);
  224. SceneObject* object = (*dyn_cons_defs)[i].cons_obj.object;
  225. S32 ghost_idx = conn->getGhostIndex(object);
  226. if (stream->writeFlag(ghost_idx != -1))
  227. {
  228. stream->writeRangedU32(U32(ghost_idx), 0, NetConnection::MaxGhostCount);
  229. }
  230. else
  231. {
  232. if (stream->writeFlag(object->getScopeId() > 0))
  233. {
  234. stream->writeInt(object->getScopeId(), NetObject::SCOPE_ID_BITS);
  235. stream->writeFlag(dynamic_cast<ShapeBase*>(object) != NULL);
  236. }
  237. }
  238. }
  239. else if ((*dyn_cons_defs)[i].cons_type == POINT_CONSTRAINT && (*dyn_cons_defs)[i].cons_obj.point != NULL)
  240. {
  241. stream->writeString((*dyn_cons_defs)[i].cons_name);
  242. stream->write((*dyn_cons_defs)[i].cons_type);
  243. mathWrite(*stream, *(*dyn_cons_defs)[i].cons_obj.point);
  244. }
  245. else if ((*dyn_cons_defs)[i].cons_type == TRANSFORM_CONSTRAINT && (*dyn_cons_defs)[i].cons_obj.xfm != NULL)
  246. {
  247. stream->writeString((*dyn_cons_defs)[i].cons_name);
  248. stream->write((*dyn_cons_defs)[i].cons_type);
  249. mathWrite(*stream, *(*dyn_cons_defs)[i].cons_obj.xfm);
  250. }
  251. }
  252. constraint_mgr->packConstraintNames(conn, stream);
  253. }
  254. void afxChoreographer::unpack_constraint_info(NetConnection* conn, BitStream* stream)
  255. {
  256. S32 n_defs;
  257. stream->read(&n_defs);
  258. dyn_cons_defs->clear();
  259. for (S32 i = 0; i < n_defs; i++)
  260. {
  261. StringTableEntry cons_name = stream->readSTString();
  262. U8 cons_type; stream->read(&cons_type);
  263. if (cons_type == OBJECT_CONSTRAINT)
  264. {
  265. SceneObject* scn_obj = NULL;
  266. if (stream->readFlag())
  267. {
  268. S32 ghost_idx = stream->readRangedU32(0, NetConnection::MaxGhostCount);
  269. scn_obj = dynamic_cast<SceneObject*>(conn->resolveGhost(ghost_idx));
  270. if (scn_obj)
  271. {
  272. addObjectConstraint(scn_obj, cons_name);
  273. }
  274. else
  275. Con::errorf("CANNOT RESOLVE GHOST %d %s", ghost_idx, cons_name);
  276. }
  277. else
  278. {
  279. if (stream->readFlag())
  280. {
  281. mScope_id = stream->readInt(NetObject::SCOPE_ID_BITS);
  282. bool is_shape = stream->readFlag();
  283. addObjectConstraint(mScope_id, cons_name, is_shape);
  284. }
  285. }
  286. }
  287. else if (cons_type == POINT_CONSTRAINT)
  288. {
  289. Point3F point;
  290. mathRead(*stream, &point);
  291. addPointConstraint(point, cons_name);
  292. }
  293. else if (cons_type == TRANSFORM_CONSTRAINT)
  294. {
  295. MatrixF xfm;
  296. mathRead(*stream, &xfm);
  297. addTransformConstraint(xfm, cons_name);
  298. }
  299. }
  300. constraint_mgr->unpackConstraintNames(stream);
  301. }
  302. void afxChoreographer::setup_dynamic_constraints()
  303. {
  304. for (S32 i = 0; i < dyn_cons_defs->size(); i++)
  305. {
  306. switch ((*dyn_cons_defs)[i].cons_type)
  307. {
  308. case OBJECT_CONSTRAINT:
  309. constraint_mgr->setReferenceObject((*dyn_cons_defs)[i].cons_name, (*dyn_cons_defs)[i].cons_obj.object);
  310. break;
  311. case POINT_CONSTRAINT:
  312. constraint_mgr->setReferencePoint((*dyn_cons_defs)[i].cons_name, *(*dyn_cons_defs)[i].cons_obj.point);
  313. break;
  314. case TRANSFORM_CONSTRAINT:
  315. constraint_mgr->setReferenceTransform((*dyn_cons_defs)[i].cons_name, *(*dyn_cons_defs)[i].cons_obj.xfm);
  316. break;
  317. case OBJECT_CONSTRAINT_SANS_OBJ:
  318. constraint_mgr->setReferenceObjectByScopeId((*dyn_cons_defs)[i].cons_name, (*dyn_cons_defs)[i].cons_obj.scope_id, false);
  319. break;
  320. case OBJECT_CONSTRAINT_SANS_SHAPE:
  321. constraint_mgr->setReferenceObjectByScopeId((*dyn_cons_defs)[i].cons_name, (*dyn_cons_defs)[i].cons_obj.scope_id, true);
  322. break;
  323. }
  324. }
  325. }
  326. afxChoreographer::dynConstraintDef* afxChoreographer::find_cons_def_by_name(const char* cons_name)
  327. {
  328. StringTableEntry cons_name_ste = StringTable->insert(cons_name);
  329. for (S32 i = 0; i < dyn_cons_defs->size(); i++)
  330. {
  331. if ((*dyn_cons_defs)[i].cons_name == cons_name_ste)
  332. return &((*dyn_cons_defs)[i]);
  333. }
  334. return 0;
  335. }
  336. void afxChoreographer::check_packet_usage(NetConnection* conn, BitStream* stream, S32 mark_stream_pos, const char* msg_tag)
  337. {
  338. S32 packed_size = stream->getCurPos() - mark_stream_pos;
  339. S32 current_headroom = stream->getMaxWriteBitNum()-(stream->getStreamSize()<<3);
  340. S32 max_headroom = stream->getMaxWriteBitNum()-(conn->getMaxRatePacketSize()<<3);
  341. if (packed_size > max_headroom)
  342. {
  343. Con::errorf("%s [%s] WARNING -- packed-bits (%d) > limit (%d) for max PacketSize settings. [%s]",
  344. msg_tag, datablock->getName(), packed_size, max_headroom, "PACKET OVERRUN POSSIBLE");
  345. Con::errorf("getMaxRatePacketSize()=%d getCurRatePacketSize()=%d", conn->getMaxRatePacketSize(), conn->getCurRatePacketSize());
  346. }
  347. // JTF Note: this current_headroom > 0 check is odd and occurs when object is created real early
  348. // in the startup, such as when the dead orc gets fatal damage and we try to post a text effect.
  349. else if (packed_size > current_headroom && current_headroom > 0)
  350. {
  351. Con::errorf("%s [%s] WARNING -- packed-bits (%d) > limit (%d) for current PacketSize settings. [%s]",
  352. msg_tag, datablock->getName(), packed_size, current_headroom, "PACKET OVERRUN POSSIBLE");
  353. }
  354. else
  355. {
  356. F32 percentage = 100.0f*((F32)packed_size/(F32)max_headroom);
  357. if (percentage >= datablock->echo_packet_usage)
  358. {
  359. Con::warnf("%s [%s] -- packed-bits (%d) < limit (%d). [%.1f%% full]", msg_tag, datablock->getName(),
  360. packed_size, max_headroom, percentage);
  361. }
  362. }
  363. }
  364. SceneObject* afxChoreographer::get_camera(Point3F* cam_pos) const
  365. {
  366. GameConnection* conn = GameConnection::getConnectionToServer();
  367. if (!conn)
  368. {
  369. if (cam_pos)
  370. cam_pos->zero();
  371. return 0;
  372. }
  373. SceneObject* cam_obj = conn->getCameraObject();
  374. if (cam_pos)
  375. {
  376. if (cam_obj)
  377. {
  378. MatrixF cam_mtx;
  379. conn->getControlCameraTransform(0, &cam_mtx);
  380. cam_mtx.getColumn(3, cam_pos);
  381. }
  382. else
  383. cam_pos->zero();
  384. }
  385. return cam_obj;
  386. }
  387. U32 afxChoreographer::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
  388. {
  389. U32 retMask = Parent::packUpdate(conn, mask, stream);
  390. if (stream->writeFlag(mask & InitialUpdateMask)) //-- INITIAL UPDATE ?
  391. {
  392. stream->write(ranking);
  393. stream->write(lod);
  394. stream->write(exec_conds_mask);
  395. stream->write(choreographer_id);
  396. // write dynamic fields beginning with arcaneFX::sParameterFieldPrefix
  397. SimFieldDictionaryIterator itr(getFieldDictionary());
  398. SimFieldDictionary::Entry* entry;
  399. U32 prefix_len = dStrlen(arcaneFX::sParameterFieldPrefix);
  400. if (prefix_len > 0)
  401. {
  402. while ((entry = *itr) != NULL)
  403. {
  404. if (dStrncmp(entry->slotName, arcaneFX::sParameterFieldPrefix, prefix_len) == 0)
  405. {
  406. stream->writeFlag(true);
  407. stream->writeString(entry->slotName);
  408. stream->writeLongString(1023, entry->value);
  409. }
  410. ++itr;
  411. }
  412. }
  413. stream->writeFlag(false);
  414. }
  415. if (stream->writeFlag(mask & TriggerMask))
  416. {
  417. stream->write(trigger_mask);
  418. }
  419. // CONSTRAINT REMAPPING <<
  420. if (stream->writeFlag((mask & RemapConstraintMask) && !remapped_cons_defs.empty()))
  421. {
  422. remapped_cons_sent = true;
  423. //Con::errorf("PACKING CONS REMAP %d conn:%d", remapped_cons_defs.size(), (U32) conn);
  424. stream->write(remapped_cons_defs.size());
  425. for (S32 i = 0; i < remapped_cons_defs.size(); i++)
  426. {
  427. if (remapped_cons_defs[i]->cons_type == OBJECT_CONSTRAINT && remapped_cons_defs[i]->cons_obj.object != NULL)
  428. {
  429. //Con::errorf("PACKING CONS REMAP: name %s", remapped_cons_defs[i]->cons_name);
  430. stream->writeString(remapped_cons_defs[i]->cons_name);
  431. //Con::errorf("PACKING CONS REMAP: type %d", remapped_cons_defs[i]->cons_type);
  432. stream->write(remapped_cons_defs[i]->cons_type);
  433. SceneObject* object = remapped_cons_defs[i]->cons_obj.object;
  434. S32 ghost_idx = conn->getGhostIndex(object);
  435. //Con::errorf("PACKING CONS REMAP: ghost %d", ghost_idx);
  436. if (stream->writeFlag(ghost_idx != -1))
  437. {
  438. stream->writeRangedU32(U32(ghost_idx), 0, NetConnection::MaxGhostCount);
  439. }
  440. else
  441. {
  442. if (stream->writeFlag(object->getScopeId() > 0))
  443. {
  444. stream->writeInt(object->getScopeId(), NetObject::SCOPE_ID_BITS);
  445. stream->writeFlag(dynamic_cast<ShapeBase*>(object) != NULL);
  446. }
  447. }
  448. }
  449. else if (remapped_cons_defs[i]->cons_type == POINT_CONSTRAINT && remapped_cons_defs[i]->cons_obj.point != NULL)
  450. {
  451. stream->writeString(remapped_cons_defs[i]->cons_name);
  452. stream->write(remapped_cons_defs[i]->cons_type);
  453. mathWrite(*stream, *remapped_cons_defs[i]->cons_obj.point);
  454. }
  455. else if (remapped_cons_defs[i]->cons_type == TRANSFORM_CONSTRAINT && remapped_cons_defs[i]->cons_obj.xfm != NULL)
  456. {
  457. stream->writeString(remapped_cons_defs[i]->cons_name);
  458. stream->write(remapped_cons_defs[i]->cons_type);
  459. mathWrite(*stream, *remapped_cons_defs[i]->cons_obj.xfm);
  460. }
  461. }
  462. }
  463. // CONSTRAINT REMAPPING >>
  464. AssertISV(stream->isValid(), "afxChoreographer::packUpdate(): write failure occurred, possibly caused by packet-size overrun.");
  465. return retMask;
  466. }
  467. void afxChoreographer::unpackUpdate(NetConnection * conn, BitStream * stream)
  468. {
  469. Parent::unpackUpdate(conn, stream);
  470. // InitialUpdate Only
  471. if (stream->readFlag())
  472. {
  473. stream->read(&ranking);
  474. stream->read(&lod);
  475. stream->read(&exec_conds_mask);
  476. stream->read(&choreographer_id);
  477. // read dynamic fields
  478. while(stream->readFlag())
  479. {
  480. char slotName[256];
  481. char value[1024];
  482. stream->readString(slotName);
  483. stream->readLongString(1023, value);
  484. setDataField(StringTable->insert(slotName), 0, value);
  485. }
  486. arcaneFX::registerClientChoreographer(this);
  487. }
  488. if (stream->readFlag()) // TriggerMask
  489. {
  490. stream->read(&trigger_mask);
  491. }
  492. // CONSTRAINT REMAPPING <<
  493. if (stream->readFlag()) // RemapConstraintMask
  494. {
  495. S32 n_defs;
  496. stream->read(&n_defs);
  497. for (S32 i = 0; i < n_defs; i++)
  498. {
  499. StringTableEntry cons_name = stream->readSTString();
  500. U8 cons_type; stream->read(&cons_type);
  501. if (cons_type == OBJECT_CONSTRAINT)
  502. {
  503. SceneObject* scn_obj = NULL;
  504. if (stream->readFlag())
  505. {
  506. S32 ghost_idx = stream->readRangedU32(0, NetConnection::MaxGhostCount);
  507. scn_obj = dynamic_cast<SceneObject*>(conn->resolveGhost(ghost_idx));
  508. if (scn_obj)
  509. {
  510. remapObjectConstraint(scn_obj, cons_name);
  511. }
  512. else
  513. Con::errorf("CANNOT RESOLVE GHOST %d %s", ghost_idx, cons_name);
  514. }
  515. else
  516. {
  517. if (stream->readFlag())
  518. {
  519. U16 scope_id = stream->readInt(NetObject::SCOPE_ID_BITS);
  520. bool is_shape = stream->readFlag();
  521. remapObjectConstraint(scope_id, cons_name, is_shape);
  522. }
  523. }
  524. }
  525. else if (cons_type == POINT_CONSTRAINT)
  526. {
  527. Point3F point;
  528. mathRead(*stream, &point);
  529. remapPointConstraint(point, cons_name);
  530. }
  531. else if (cons_type == TRANSFORM_CONSTRAINT)
  532. {
  533. MatrixF xfm;
  534. mathRead(*stream, &xfm);
  535. remapTransformConstraint(xfm, cons_name);
  536. }
  537. }
  538. }
  539. // CONSTRAINT REMAPPING >>
  540. }
  541. void afxChoreographer::executeScriptEvent(const char* method, afxConstraint* cons,
  542. const MatrixF& xfm, const char* data)
  543. {
  544. SceneObject* cons_obj = (cons) ? cons->getSceneObject() : NULL;
  545. char *arg_buf = Con::getArgBuffer(256);
  546. Point3F pos;
  547. xfm.getColumn(3,&pos);
  548. AngAxisF aa(xfm);
  549. dSprintf(arg_buf,256,"%g %g %g %g %g %g %g",
  550. pos.x, pos.y, pos.z,
  551. aa.axis.x, aa.axis.y, aa.axis.z, aa.angle);
  552. // CALL SCRIPT afxChoreographerData::method(%choreographer, %constraint, %transform, %data)
  553. Con::executef(exeblock, method,
  554. getIdString(),
  555. (cons_obj) ? cons_obj->getIdString() : "",
  556. arg_buf,
  557. data);
  558. }
  559. void afxChoreographer::addObjectConstraint(SceneObject* object, const char* cons_name)
  560. {
  561. if (!object || !cons_name)
  562. return;
  563. dynConstraintDef dyn_def;
  564. dyn_def.cons_name = StringTable->insert(cons_name);
  565. dyn_def.cons_type = OBJECT_CONSTRAINT;
  566. dyn_def.cons_obj.object = object;
  567. dyn_cons_defs->push_back(dyn_def);
  568. #if defined(AFX_CAP_SCOPE_TRACKING)
  569. if (isServerObject() && object->isScopeable())
  570. constraint_mgr->addScopeableObject(object);
  571. #endif
  572. constraint_mgr->defineConstraint(OBJECT_CONSTRAINT, dyn_def.cons_name);
  573. deleteNotify(object);
  574. }
  575. void afxChoreographer::addObjectConstraint(U16 scope_id, const char* cons_name, bool is_shape)
  576. {
  577. if (!cons_name)
  578. return;
  579. dynConstraintDef dyn_def;
  580. dyn_def.cons_name = StringTable->insert(cons_name);
  581. dyn_def.cons_type = (is_shape) ? OBJECT_CONSTRAINT_SANS_SHAPE : OBJECT_CONSTRAINT_SANS_OBJ;
  582. dyn_def.cons_obj.scope_id = scope_id;
  583. dyn_cons_defs->push_back(dyn_def);
  584. constraint_mgr->defineConstraint(OBJECT_CONSTRAINT, dyn_def.cons_name);
  585. }
  586. void afxChoreographer::addPointConstraint(Point3F& point, const char* cons_name)
  587. {
  588. dynConstraintDef dyn_def;
  589. dyn_def.cons_name = StringTable->insert(cons_name);
  590. dyn_def.cons_type = POINT_CONSTRAINT;
  591. dyn_def.cons_obj.point = new Point3F(point);
  592. dyn_cons_defs->push_back(dyn_def);
  593. constraint_mgr->defineConstraint(POINT_CONSTRAINT, dyn_def.cons_name);
  594. }
  595. void afxChoreographer::addTransformConstraint(MatrixF& xfm, const char* cons_name)
  596. {
  597. dynConstraintDef dyn_def;
  598. dyn_def.cons_name = StringTable->insert(cons_name);
  599. dyn_def.cons_type = TRANSFORM_CONSTRAINT;
  600. dyn_def.cons_obj.xfm = new MatrixF(xfm);
  601. dyn_cons_defs->push_back(dyn_def);
  602. constraint_mgr->defineConstraint(TRANSFORM_CONSTRAINT, dyn_def.cons_name);
  603. }
  604. // CONSTRAINT REMAPPING <<
  605. static inline U32 resolve_cons_spec(const char* source_spec, Point3F& pos, MatrixF& xfm, SceneObject** scn_obj)
  606. {
  607. AngAxisF aa;
  608. S32 args_n = dSscanf(source_spec, "%g %g %g %g %g %g %g",
  609. &pos.x, &pos.y, &pos.z,
  610. &aa.axis.x, &aa.axis.y, &aa.axis.z, &aa.angle);
  611. // TRANSFORM CONSTRAINT SRC
  612. if (args_n == 7)
  613. {
  614. aa.setMatrix(&xfm);
  615. xfm.setColumn(3,pos);
  616. return afxEffectDefs::TRANSFORM_CONSTRAINT;
  617. }
  618. // POINT CONSTRAINT SRC
  619. if (args_n == 3)
  620. {
  621. return afxEffectDefs::POINT_CONSTRAINT;
  622. }
  623. SimObject* cons_sim_obj = Sim::findObject(source_spec);
  624. *scn_obj = dynamic_cast<SceneObject*>(cons_sim_obj);
  625. if (*scn_obj)
  626. {
  627. return afxEffectDefs::OBJECT_CONSTRAINT;
  628. }
  629. return afxEffectDefs::UNDEFINED_CONSTRAINT_TYPE;
  630. }
  631. // CONSTRAINT REMAPPING >>
  632. bool afxChoreographer::addConstraint(const char* source_spec, const char* cons_name)
  633. {
  634. VectorF pos;
  635. MatrixF xfm;
  636. SceneObject* scn_obj;
  637. switch (resolve_cons_spec(source_spec, pos, xfm, &scn_obj))
  638. {
  639. case TRANSFORM_CONSTRAINT:
  640. addTransformConstraint(xfm, cons_name);
  641. return true;
  642. case POINT_CONSTRAINT:
  643. addPointConstraint(pos, cons_name);
  644. return true;
  645. case OBJECT_CONSTRAINT:
  646. addObjectConstraint(scn_obj, cons_name);
  647. return true;
  648. }
  649. return false;
  650. }
  651. void afxChoreographer::addNamedEffect(afxEffectWrapper* ew)
  652. {
  653. named_effects.addObject(ew);
  654. }
  655. void afxChoreographer::removeNamedEffect(afxEffectWrapper* ew)
  656. {
  657. named_effects.removeObject(ew);
  658. }
  659. afxEffectWrapper* afxChoreographer::findNamedEffect(StringTableEntry name)
  660. {
  661. return (afxEffectWrapper*) named_effects.findObject(name);
  662. }
  663. void afxChoreographer::setGhostConstraintObject(SceneObject* obj, StringTableEntry cons_name)
  664. {
  665. if (constraint_mgr)
  666. constraint_mgr->setReferenceObject(cons_name, obj);
  667. }
  668. void afxChoreographer::restoreScopedObject(SceneObject* obj)
  669. {
  670. constraint_mgr->restoreScopedObject(obj, this);
  671. constraint_mgr->adjustProcessOrdering(this);
  672. }
  673. void afxChoreographer::addExplicitClient(NetConnection* conn)
  674. {
  675. if (!conn)
  676. return;
  677. for (S32 i = 0; i < explicit_clients.size(); i++)
  678. {
  679. if (explicit_clients[i] == conn)
  680. return;
  681. }
  682. explicit_clients.push_back(conn);
  683. deleteNotify(conn);
  684. }
  685. void afxChoreographer::removeExplicitClient(NetConnection* conn)
  686. {
  687. if (!conn)
  688. return;
  689. for (S32 i = 0; i < explicit_clients.size(); i++)
  690. {
  691. if (explicit_clients[i] == conn)
  692. {
  693. clearNotify(conn);
  694. explicit_clients.erase_fast(i);
  695. return;
  696. }
  697. }
  698. }
  699. void afxChoreographer::postProcessAfterObject(GameBase* obj)
  700. {
  701. proc_after_obj = obj;
  702. }
  703. void afxChoreographer::setTriggerMask(U32 mask)
  704. {
  705. if (mask != trigger_mask)
  706. {
  707. trigger_mask = mask;
  708. setMaskBits(TriggerMask);
  709. }
  710. }
  711. afxParticlePool* afxChoreographer::findParticlePool(afxParticlePoolData* key_block, U32 key_index)
  712. {
  713. for (S32 i = 0; i < particle_pools.size(); i++)
  714. if (particle_pools[i] && particle_pools[i]->hasMatchingKeyBlock(key_block, key_index))
  715. return particle_pools[i];
  716. return 0;
  717. }
  718. void afxChoreographer::registerParticlePool(afxParticlePool* pool)
  719. {
  720. particle_pools.push_back(pool);
  721. }
  722. void afxChoreographer::unregisterParticlePool(afxParticlePool* pool)
  723. {
  724. for (S32 i = 0; i < particle_pools.size(); i++)
  725. if (particle_pools[i] == pool)
  726. {
  727. particle_pools.erase_fast(i);
  728. return;
  729. }
  730. }
  731. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  732. DefineEngineMethod( afxChoreographer, setRanking, void, ( U32 ranking ),,
  733. "Set a ranking value (0-255) for the choreographer.\n" )
  734. {
  735. object->setRanking((U8)ranking);
  736. }
  737. DefineEngineMethod( afxChoreographer, setLevelOfDetail, void, ( U32 lod ),,
  738. "Set a level-of-detail value (0-255) for the choreographer.\n" )
  739. {
  740. object->setLevelOfDetail((U8)lod);
  741. }
  742. DefineEngineMethod( afxChoreographer, setExecConditions, void, ( U32 mask ),,
  743. "Set a bitmask to specifiy the state of exec-conditions.\n" )
  744. {
  745. object->setExecConditions(afxChoreographer::USER_EXEC_CONDS_MASK & mask);
  746. }
  747. DefineEngineMethod( afxChoreographer, addConstraint, void, ( const char* source, const char* name),,
  748. "Add a dynamic constraint consistiing of a source and name. The source can be a SceneObject, a 3-valued position, or a 7-valued transform.\n" )
  749. {
  750. if (!object->addConstraint(source, name))
  751. Con::errorf("afxChoreographer::addConstraint() -- failed to resolve constraint source [%s].", source);
  752. }
  753. DefineEngineMethod( afxChoreographer, addExplicitClient, void, ( NetConnection* client ),,
  754. "Add an explicit client.\n" )
  755. {
  756. if (!client)
  757. {
  758. Con::errorf(ConsoleLogEntry::General, "afxChoreographer::addExplicitClient: Failed to resolve client connection");
  759. return;
  760. }
  761. object->addExplicitClient(client);
  762. }
  763. DefineEngineMethod( afxChoreographer, setTriggerBit, void, ( U32 bit_num ),,
  764. "Set a bit of the trigger-mask.\n" )
  765. {
  766. U32 set_bit = 1 << bit_num;
  767. object->setTriggerMask(set_bit | object->getTriggerMask());
  768. }
  769. DefineEngineMethod( afxChoreographer, clearTriggerBit, void, ( U32 bit_num ),,
  770. "Unset a bit of the trigger-mask.\n" )
  771. {
  772. U32 clear_bit = 1 << bit_num;
  773. object->setTriggerMask(~clear_bit & object->getTriggerMask());
  774. }
  775. DefineEngineMethod( afxChoreographer, testTriggerBit, bool, ( U32 bit_num ),,
  776. "Test state of a trigger-mask bit.\n" )
  777. {
  778. U32 test_bit = 1 << bit_num;
  779. return ((test_bit & object->getTriggerMask()) != 0);
  780. }
  781. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  782. // CONSTRAINT REMAPPING <<
  783. void afxChoreographer::remapObjectConstraint(SceneObject* object, const char* cons_name)
  784. {
  785. if (!object || !cons_name)
  786. return;
  787. // must be a constraint-def with a matching name in the list
  788. dynConstraintDef* dyn_def = find_cons_def_by_name(cons_name);
  789. if (!dyn_def)
  790. {
  791. Con::errorf("afxChoreographer::remapObjectConstraint() -- failed to find constraint name [%s].", cons_name);
  792. return;
  793. }
  794. // constraint-def must have matching name constraint-type
  795. if (dyn_def->cons_type != OBJECT_CONSTRAINT)
  796. {
  797. Con::errorf("afxChoreographer::remapObjectConstraint() -- remapped contraint type does not match existing constraint type.");
  798. return;
  799. }
  800. // nothing to do if new object is same as old
  801. if (dyn_def->cons_obj.object == object)
  802. {
  803. #ifdef TORQUE_DEBUG
  804. Con::warnf("afxChoreographer::remapObjectConstraint() -- remapped contraint object is same as existing object.");
  805. #endif
  806. return;
  807. }
  808. dyn_def->cons_obj.object = object;
  809. deleteNotify(object);
  810. constraint_mgr->setReferenceObject(StringTable->insert(cons_name), object);
  811. #if defined(AFX_CAP_SCOPE_TRACKING)
  812. if (isServerObject() && object->isScopeable())
  813. constraint_mgr->addScopeableObject(object);
  814. #endif
  815. if (isServerObject())
  816. {
  817. if (remapped_cons_sent)
  818. {
  819. remapped_cons_defs.clear();
  820. remapped_cons_sent = false;
  821. }
  822. remapped_cons_defs.push_back(dyn_def);
  823. setMaskBits(RemapConstraintMask);
  824. }
  825. }
  826. void afxChoreographer::remapObjectConstraint(U16 scope_id, const char* cons_name, bool is_shape)
  827. {
  828. if (!cons_name)
  829. return;
  830. // must be a constraint-def with a matching name in the list
  831. dynConstraintDef* dyn_def = find_cons_def_by_name(cons_name);
  832. if (!dyn_def)
  833. {
  834. Con::errorf("afxChoreographer::remapObjectConstraint() -- failed to find constraint name [%s].", cons_name);
  835. return;
  836. }
  837. // constraint-def must have matching name constraint-type
  838. if (dyn_def->cons_type != OBJECT_CONSTRAINT)
  839. {
  840. Con::errorf("afxChoreographer::remapObjectConstraint() -- remapped contraint type does not match existing constraint type.");
  841. return;
  842. }
  843. constraint_mgr->setReferenceObjectByScopeId(StringTable->insert(cons_name), scope_id, is_shape);
  844. }
  845. void afxChoreographer::remapPointConstraint(Point3F& point, const char* cons_name)
  846. {
  847. // must be a constraint-def with a matching name in the list
  848. dynConstraintDef* dyn_def = find_cons_def_by_name(cons_name);
  849. if (!dyn_def)
  850. {
  851. Con::errorf("afxChoreographer::remapPointConstraint() -- failed to find constraint name [%s].", cons_name);
  852. return;
  853. }
  854. // constraint-def must have matching name constraint-type
  855. if (dyn_def->cons_type != POINT_CONSTRAINT)
  856. {
  857. Con::errorf("afxChoreographer::remapPointConstraint() -- remapped contraint type does not match existing constraint type.");
  858. return;
  859. }
  860. *dyn_def->cons_obj.point = point;
  861. constraint_mgr->setReferencePoint(StringTable->insert(cons_name), point);
  862. if (isServerObject())
  863. {
  864. if (remapped_cons_sent)
  865. {
  866. remapped_cons_defs.clear();
  867. remapped_cons_sent = false;
  868. }
  869. remapped_cons_defs.push_back(dyn_def);
  870. setMaskBits(RemapConstraintMask);
  871. }
  872. }
  873. void afxChoreographer::remapTransformConstraint(MatrixF& xfm, const char* cons_name)
  874. {
  875. // must be a constraint-def with a matching name in the list
  876. dynConstraintDef* dyn_def = find_cons_def_by_name(cons_name);
  877. if (!dyn_def)
  878. {
  879. Con::errorf("afxChoreographer::remapTransformConstraint() -- failed to find constraint name [%s].", cons_name);
  880. return;
  881. }
  882. // constraint-def must have matching name constraint-type
  883. if (dyn_def->cons_type != POINT_CONSTRAINT)
  884. {
  885. Con::errorf("afxChoreographer::remapTransformConstraint() -- remapped contraint type does not match existing constraint type.");
  886. return;
  887. }
  888. *dyn_def->cons_obj.xfm = xfm;
  889. constraint_mgr->setReferenceTransform(StringTable->insert(cons_name), xfm);
  890. if (isServerObject())
  891. {
  892. if (remapped_cons_sent)
  893. {
  894. remapped_cons_defs.clear();
  895. remapped_cons_sent = false;
  896. }
  897. remapped_cons_defs.push_back(dyn_def);
  898. setMaskBits(RemapConstraintMask);
  899. }
  900. }
  901. bool afxChoreographer::remapConstraint(const char* source_spec, const char* cons_name)
  902. {
  903. SceneObject* scn_obj;
  904. Point3F pos;
  905. MatrixF xfm;
  906. switch (resolve_cons_spec(source_spec, pos, xfm, &scn_obj))
  907. {
  908. case TRANSFORM_CONSTRAINT:
  909. //addTransformConstraint(xfm, cons_name);
  910. return true;
  911. case POINT_CONSTRAINT:
  912. //addPointConstraint(pos, cons_name);
  913. return true;
  914. case OBJECT_CONSTRAINT:
  915. remapObjectConstraint(scn_obj, cons_name);
  916. return true;
  917. }
  918. return false;
  919. }
  920. DefineEngineMethod( afxChoreographer, remapConstraint, void, ( const char* source, const char* name),,
  921. "Remap a dynamic constraint to use a new source. The source can be a SceneObject, a 3-valued position, or a 7-valued transform. but must match type of existing source.\n" )
  922. {
  923. if (!object->remapConstraint(source, name))
  924. Con::errorf("afxChoreographer::remapConstraint() -- failed to resolve constraint source [%s].", source);
  925. }
  926. // CONSTRAINT REMAPPING >>
  927. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//