afxChoreographer.cpp 32 KB

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