afxSelectron.cpp
Engine/source/afx/afxSelectron.cpp
Classes:
Public Defines
define
myOffset(field) (field, )
Public Functions
ConsoleDocClass(afxSelectron , "@brief A choreographer <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> selection <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effects.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxChoreographers\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" )
ConsoleDocClass(afxSelectronData , "@brief Defines the properties of an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxSelectronData.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxChoreographers\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
DefineEngineFunction(startSelectron , S32 , (SceneObject *selectedObj, unsigned int subcode, SimObject *extra) , (nullAsType< SceneObject * >(), 0, nullAsType< SimObject * >()) , "Instantiates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selectron.\n\n</a>" "@ingroup AFX" )
DefineEngineMethod(afxSelectron , interrupt , void , () , "Interrupts and deletes <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> running <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selectron.\n\n</a>" "@ingroup AFX" )
DefineEngineMethod(afxSelectron , setTimeFactor , void , (float factor) , (1.0f) , "Sets the time factor of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selectron.\n\n</a>" "@ingroup AFX" )
DefineEngineMethod(afxSelectron , stopSelectron , void , () , "Stops and deletes <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> running <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selectron.\n\n</a>" "@ingroup AFX" )
DefineEngineMethod(afxSelectronData , reset , void , () , "Resets <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> selectron datablock during <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reload.\n\n</a>" "@ingroup AFX" )
expand_fx_list(afxEffectList & fx_list, const char * tag)
Detailed Description
Public Defines
myOffset(field) (field, )
Public Functions
ConsoleDocClass(afxSelectron , "@brief A choreographer <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> selection <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effects.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxChoreographers\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" )
ConsoleDocClass(afxSelectronData , "@brief Defines the properties of an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxSelectronData.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxChoreographers\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
DefineEngineFunction(startSelectron , S32 , (SceneObject *selectedObj, unsigned int subcode, SimObject *extra) , (nullAsType< SceneObject * >(), 0, nullAsType< SimObject * >()) , "Instantiates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selectron.\n\n</a>" "@ingroup AFX" )
DefineEngineMethod(afxSelectron , interrupt , void , () , "Interrupts and deletes <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> running <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selectron.\n\n</a>" "@ingroup AFX" )
DefineEngineMethod(afxSelectron , setTimeFactor , void , (float factor) , (1.0f) , "Sets the time factor of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selectron.\n\n</a>" "@ingroup AFX" )
DefineEngineMethod(afxSelectron , stopSelectron , void , () , "Stops and deletes <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> running <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selectron.\n\n</a>" "@ingroup AFX" )
DefineEngineMethod(afxSelectronData , reset , void , () , "Resets <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> selectron datablock during <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reload.\n\n</a>" "@ingroup AFX" )
expand_fx_list(afxEffectList & fx_list, const char * tag)
IMPLEMENT_CO_DATABLOCK_V1(afxSelectronData )
IMPLEMENT_CO_NETOBJECT_V1(afxSelectron )
1 2 3//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 4// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 5// Copyright (C) 2015 Faust Logic, Inc. 6// 7// Permission is hereby granted, free of charge, to any person obtaining a copy 8// of this software and associated documentation files (the "Software"), to 9// deal in the Software without restriction, including without limitation the 10// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11// sell copies of the Software, and to permit persons to whom the Software is 12// furnished to do so, subject to the following conditions: 13// 14// The above copyright notice and this permission notice shall be included in 15// all copies or substantial portions of the Software. 16// 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23// IN THE SOFTWARE. 24// 25//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 26 27#include "afx/arcaneFX.h" 28 29#include "console/engineAPI.h" 30#include "T3D/gameBase/gameConnection.h" 31#include "sfx/sfxSystem.h" 32 33#include "afx/afxChoreographer.h" 34#include "afx/afxSelectron.h" 35 36//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 37// afxSelectronData::ewValidator 38// 39// When an effect is added using "addEffect", this validator intercepts the value 40// and adds it to the dynamic effects list. 41// 42void afxSelectronData::ewValidator::validateType(SimObject* object, void* typePtr) 43{ 44 afxSelectronData* sele_data = dynamic_cast<afxSelectronData*>(object); 45 afxEffectBaseData** ew = (afxEffectBaseData**)(typePtr); 46 47 if (sele_data && ew) 48 { 49 switch (id) 50 { 51 case MAIN_PHRASE: 52 sele_data->main_fx_list.push_back(*ew); 53 break; 54 case SELECT_PHRASE: 55 sele_data->select_fx_list.push_back(*ew); 56 break; 57 case DESELECT_PHRASE: 58 sele_data->deselect_fx_list.push_back(*ew); 59 break; 60 } 61 *ew = 0; 62 } 63} 64 65//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 66 67class SelectronFinishStartupEvent : public SimEvent 68{ 69public: 70 void process(SimObject* obj) 71 { 72 afxSelectron* selectron = dynamic_cast<afxSelectron*>(obj); 73 if (selectron) 74 selectron->finish_startup(); 75 } 76}; 77 78//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 79//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 80// afxSelectronData 81 82IMPLEMENT_CO_DATABLOCK_V1(afxSelectronData); 83 84ConsoleDocClass( afxSelectronData, 85 "@brief Defines the properties of an afxSelectronData.\n\n" 86 87 "@ingroup afxChoreographers\n" 88 "@ingroup AFX\n" 89 "@ingroup Datablocks\n" 90); 91 92afxSelectronData::afxSelectronData() 93{ 94 main_dur = 0.0f; 95 select_dur = 0.0f; 96 deselect_dur = 0.0f; 97 98 n_main_loops = 1; 99 n_select_loops = 1; 100 n_deselect_loops = 1; 101 102 registered = false; 103 104 obj_type_style = 0; 105 obj_type_mask = 0; 106 107 // dummy entry holds effect-wrapper pointer while a special validator 108 // grabs it and adds it to an appropriate effects list 109 dummy_fx_entry = NULL; 110 111 // marked true if datablock ids need to 112 // be converted into pointers 113 do_id_convert = false; 114} 115 116afxSelectronData::afxSelectronData(const afxSelectronData& other, bool temp_clone) : afxChoreographerData(other, temp_clone) 117{ 118 main_dur = other.main_dur; 119 select_dur = other.select_dur; 120 deselect_dur = other.deselect_dur; 121 n_main_loops = other.n_main_loops; 122 n_select_loops = other.n_select_loops; 123 n_deselect_loops = other.n_deselect_loops; 124 registered = false; 125 obj_type_style = other.obj_type_style; 126 obj_type_mask = other.obj_type_mask; 127 dummy_fx_entry = other.dummy_fx_entry; 128 do_id_convert = other.do_id_convert; 129 130 main_fx_list = other.main_fx_list; 131 select_fx_list = other.select_fx_list; 132 deselect_fx_list = other.deselect_fx_list; 133} 134 135afxSelectronData::~afxSelectronData() 136{ 137 if (registered && !isTempClone()) 138 arcaneFX::unregisterSelectronData(this); 139} 140 141void afxSelectronData::reloadReset() 142{ 143 main_fx_list.clear(); 144 select_fx_list.clear(); 145 deselect_fx_list.clear(); 146} 147 148#define myOffset(field) Offset(field, afxSelectronData) 149 150void afxSelectronData::initPersistFields() 151{ 152 static ewValidator _mainPhrase(MAIN_PHRASE); 153 static ewValidator _selectPhrase(SELECT_PHRASE); 154 static ewValidator _deselectPhrase(DESELECT_PHRASE); 155 156 addField("mainDur", TypeF32, myOffset(main_dur), 157 "..."); 158 addField("selectDur", TypeF32, myOffset(select_dur), 159 "..."); 160 addField("deselectDur", TypeF32, myOffset(deselect_dur), 161 "..."); 162 addField("mainRepeats", TypeS32, myOffset(n_main_loops), 163 "..."); 164 addField("selectRepeats", TypeS32, myOffset(n_select_loops), 165 "..."); 166 addField("deselectRepeats", TypeS32, myOffset(n_deselect_loops), 167 "..."); 168 addField("selectionTypeMask", TypeS32, myOffset(obj_type_mask), 169 "..."); 170 addField("selectionTypeStyle", TypeS8, myOffset(obj_type_style), 171 "..."); 172 173 // effect lists 174 // for each of these, dummy_fx_entry is set and then a validator adds it to the appropriate effects list 175 addFieldV("addMainEffect", TYPEID<afxEffectBaseData>(), myOffset(dummy_fx_entry), &_mainPhrase, 176 "..."); 177 addFieldV("addSelectEffect", TYPEID<afxEffectBaseData>(), myOffset(dummy_fx_entry), &_selectPhrase, 178 "..."); 179 addFieldV("addDeselectEffect", TYPEID<afxEffectBaseData>(), myOffset(dummy_fx_entry), &_deselectPhrase, 180 "..."); 181 182 // deprecated 183 addField("numMainLoops", TypeS32, myOffset(n_main_loops), 184 "..."); 185 addField("numSelectLoops", TypeS32, myOffset(n_select_loops), 186 "..."); 187 addField("numDeselectLoops", TypeS32, myOffset(n_deselect_loops), 188 "..."); 189 190 Parent::initPersistFields(); 191 192 // disallow some field substitutions 193 disableFieldSubstitutions("addMainEffect"); 194 disableFieldSubstitutions("addSelectEffect"); 195 disableFieldSubstitutions("addDeselectEffect"); 196} 197 198bool afxSelectronData::onAdd() 199{ 200 if (Parent::onAdd() == false) 201 return false; 202 203 return true; 204} 205 206void afxSelectronData::pack_fx(BitStream* stream, const afxEffectList& fx, bool packed) 207{ 208 stream->writeInt(fx.size(), EFFECTS_PER_PHRASE_BITS); 209 for (int i = 0; i < fx.size(); i++) 210 writeDatablockID(stream, fx[i], packed); 211} 212 213void afxSelectronData::unpack_fx(BitStream* stream, afxEffectList& fx) 214{ 215 fx.clear(); 216 S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS); 217 for (int i = 0; i < n_fx; i++) 218 fx.push_back((afxEffectWrapperData*)(uintptr_t)readDatablockID(stream)); 219} 220 221void afxSelectronData::packData(BitStream* stream) 222{ 223 Parent::packData(stream); 224 225 stream->write(main_dur); 226 stream->write(select_dur); 227 stream->write(deselect_dur); 228 stream->write(n_main_loops); 229 stream->write(n_select_loops); 230 stream->write(n_deselect_loops); 231 stream->write(obj_type_style); 232 stream->write(obj_type_mask); 233 234 pack_fx(stream, main_fx_list, mPacked); 235 pack_fx(stream, select_fx_list, mPacked); 236 pack_fx(stream, deselect_fx_list, mPacked); 237} 238 239void afxSelectronData::unpackData(BitStream* stream) 240{ 241 Parent::unpackData(stream); 242 243 stream->read(&main_dur); 244 stream->read(&select_dur); 245 stream->read(&deselect_dur); 246 stream->read(&n_main_loops); 247 stream->read(&n_select_loops); 248 stream->read(&n_deselect_loops); 249 stream->read(&obj_type_style); 250 stream->read(&obj_type_mask); 251 252 do_id_convert = true; 253 unpack_fx(stream, main_fx_list); 254 unpack_fx(stream, select_fx_list); 255 unpack_fx(stream, deselect_fx_list); 256} 257 258inline void expand_fx_list(afxEffectList& fx_list, const char* tag) 259{ 260 for (S32 i = 0; i < fx_list.size(); i++) 261 { 262 SimObjectId db_id = SimObjectId((uintptr_t)fx_list[i]); 263 if (db_id != 0) 264 { 265 // try to convert id to pointer 266 if (!Sim::findObject(db_id, fx_list[i])) 267 { 268 Con::errorf(ConsoleLogEntry::General, 269 "afxSelectronData::preload() -- bad datablockId: 0x%x (%s)", 270 db_id, tag); 271 } 272 } 273 } 274} 275 276bool afxSelectronData::preload(bool server, String &errorStr) 277{ 278 if (!Parent::preload(server, errorStr)) 279 return false; 280 281 // Resolve objects transmitted from server 282 if (!server) 283 { 284 if (do_id_convert) 285 { 286 expand_fx_list(main_fx_list, "main"); 287 expand_fx_list(select_fx_list, "select"); 288 expand_fx_list(deselect_fx_list, "deselect"); 289 do_id_convert = false; 290 } 291 292 // this is where a selectron registers itself with the rest of AFX 293 if (!registered) 294 { 295 arcaneFX::registerSelectronData(this); 296 registered = true; 297 } 298 } 299 300 return true; 301} 302 303void afxSelectronData::gatherConstraintDefs(Vector<afxConstraintDef>& defs) 304{ 305 afxConstraintDef::gather_cons_defs(defs, main_fx_list); 306 afxConstraintDef::gather_cons_defs(defs, select_fx_list); 307 afxConstraintDef::gather_cons_defs(defs, deselect_fx_list); 308} 309 310//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~// 311 312DefineEngineMethod(afxSelectronData, reset, void, (),, 313 "Resets a selectron datablock during reload.\n\n" 314 "@ingroup AFX") 315{ 316 object->reloadReset(); 317} 318 319//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 320//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 321// afxSelectron 322 323IMPLEMENT_CO_NETOBJECT_V1(afxSelectron); 324 325ConsoleDocClass( afxSelectron, 326 "@brief A choreographer for selection effects.\n\n" 327 328 "@ingroup afxChoreographers\n" 329 "@ingroup AFX\n" 330); 331 332StringTableEntry afxSelectron::CAMERA_CONS; 333StringTableEntry afxSelectron::LISTENER_CONS; 334StringTableEntry afxSelectron::FREE_TARGET_CONS; 335 336void afxSelectron::init() 337{ 338 client_only = true; 339 mNetFlags.clear(Ghostable | ScopeAlways); 340 mNetFlags.set(IsGhost); 341 342 // setup static predefined constraint names 343 if (CAMERA_CONS == 0) 344 { 345 CAMERA_CONS = StringTable->insert("camera"); 346 LISTENER_CONS = StringTable->insert("listener"); 347 FREE_TARGET_CONS = StringTable->insert("freeTarget"); 348 } 349 350 datablock = NULL; 351 exeblock = NULL; 352 353 constraints_initialized = false; 354 355 effect_state = (U8) INACTIVE_STATE; 356 effect_elapsed = 0; 357 358 // define named constraints 359 constraint_mgr->defineConstraint(CAMERA_CONSTRAINT, CAMERA_CONS); 360 constraint_mgr->defineConstraint(POINT_CONSTRAINT, LISTENER_CONS); 361 constraint_mgr->defineConstraint(POINT_CONSTRAINT, FREE_TARGET_CONS); 362 363 for (S32 i = 0; i < NUM_PHRASES; i++) 364 phrases[i] = NULL; 365 366 time_factor = 1.0f; 367 camera_cons_obj = 0; 368 369 marks_mask = 0; 370} 371 372afxSelectron::afxSelectron() 373{ 374 started_with_newop = true; 375 init(); 376} 377 378afxSelectron::afxSelectron(bool not_default) 379{ 380 started_with_newop = false; 381 init(); 382} 383 384afxSelectron::~afxSelectron() 385{ 386 for (S32 i = 0; i < NUM_PHRASES; i++) 387 { 388 if (phrases[i]) 389 { 390 phrases[i]->interrupt(effect_elapsed); 391 delete phrases[i]; 392 } 393 } 394 395 if (datablock && datablock->isTempClone()) 396 { 397 delete datablock; 398 datablock = 0; 399 } 400} 401 402//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 403 404// STANDARD OVERLOADED METHODS // 405 406bool afxSelectron::onNewDataBlock(GameBaseData* dptr, bool reload) 407{ 408 datablock = dynamic_cast<afxSelectronData*>(dptr); 409 if (!datablock || !Parent::onNewDataBlock(dptr, reload)) 410 return false; 411 412 exeblock = datablock; 413 414 return true; 415} 416 417void afxSelectron::processTick(const Move* m) 418{ 419 Parent::processTick(m); 420 421 // don't process moves or client ticks 422 if (m != 0 || isClientObject()) 423 return; 424 425 process_server(); 426} 427 428void afxSelectron::advanceTime(F32 dt) 429{ 430 Parent::advanceTime(dt); 431 432 process_client(dt); 433} 434 435bool afxSelectron::onAdd() 436{ 437 if (started_with_newop) 438 { 439 Con::errorf("afxSelectron::onAdd() -- selectrons cannot be created with the \"new\" operator. Use startSelectron() instead."); 440 return false; 441 } 442 443 NetConnection* conn = NetConnection::getConnectionToServer(); 444 if (!conn || !Parent::onAdd()) 445 return false; 446 447 conn->addObject(this); 448 449 return true; 450} 451 452void afxSelectron::onRemove() 453{ 454 getContainer()->removeObject(this); 455 Parent::onRemove(); 456} 457 458//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 459 460U32 afxSelectron::packUpdate(NetConnection* conn, U32 mask, BitStream* stream) 461{ 462 U32 retMask = Parent::packUpdate(conn, mask, stream); 463 464 // InitialUpdate 465 if (stream->writeFlag(mask & InitialUpdateMask)) 466 { 467 stream->write(time_factor); 468 469 GameConnection* gconn = dynamic_cast<GameConnection*>(conn); 470 bool zoned_in = (gconn) ? gconn->isZonedIn() : false; 471 if (stream->writeFlag(zoned_in)) 472 pack_constraint_info(conn, stream); 473 } 474 475 // StateEvent or SyncEvent 476 if (stream->writeFlag((mask & StateEventMask) || (mask & SyncEventMask))) 477 { 478 stream->write(marks_mask); 479 stream->write(effect_state); 480 stream->write(effect_elapsed); 481 } 482 483 // SyncEvent 484 bool do_sync_event = ((mask & SyncEventMask) && !(mask & InitialUpdateMask)); 485 if (stream->writeFlag(do_sync_event)) 486 { 487 pack_constraint_info(conn, stream); 488 } 489 490 return retMask; 491} 492 493//~~~~~~~~~~~~~~~~~~~~// 494 495void afxSelectron::unpackUpdate(NetConnection * conn, BitStream * stream) 496{ 497 Parent::unpackUpdate(conn, stream); 498 499 bool initial_update = false; 500 bool zoned_in = true; 501 bool do_sync_event = false; 502 U8 new_marks_mask = 0; 503 U8 new_state = INACTIVE_STATE; 504 F32 new_elapsed = 0; 505 506 // InitialUpdate Only 507 if (stream->readFlag()) 508 { 509 initial_update = true; 510 511 stream->read(&time_factor); 512 513 // if client is marked as fully zoned in 514 if ((zoned_in = stream->readFlag()) == true) 515 { 516 unpack_constraint_info(conn, stream); 517 init_constraints(); 518 } 519 } 520 521 // StateEvent or SyncEvent 522 // this state data is sent for both state-events and 523 // sync-events 524 if (stream->readFlag()) 525 { 526 stream->read(&new_marks_mask); 527 stream->read(&new_state); 528 stream->read(&new_elapsed); 529 530 marks_mask = new_marks_mask; 531 } 532 533 // SyncEvent 534 do_sync_event = stream->readFlag(); 535 if (do_sync_event) 536 { 537 unpack_constraint_info(conn, stream); 538 init_constraints(); 539 } 540 541 //~~~~~~~~~~~~~~~~~~~~// 542 543 if (!zoned_in) 544 effect_state = LATE_STATE; 545 546 // need to adjust state info to get all synced up with spell on server 547 if (do_sync_event && !initial_update) 548 sync_client(new_marks_mask, new_state, new_elapsed); 549} 550 551void afxSelectron::sync_with_clients() 552{ 553 setMaskBits(SyncEventMask); 554} 555 556//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 557// private 558 559bool afxSelectron::state_expired() 560{ 561 afxPhrase* phrase = (effect_state == ACTIVE_STATE) ? phrases[MAIN_PHRASE] : NULL; 562 563 if (phrase) 564 { 565 if (phrase->expired(effect_elapsed)) 566 return (!phrase->recycle(effect_elapsed)); 567 return false; 568 } 569 570 return true; 571} 572 573void afxSelectron::init_constraints() 574{ 575 if (constraints_initialized) 576 { 577 //Con::printf("CONSTRAINTS ALREADY INITIALIZED"); 578 return; 579 } 580 581 Vector<afxConstraintDef> defs; 582 datablock->gatherConstraintDefs(defs); 583 584 constraint_mgr->initConstraintDefs(defs, isServerObject()); 585 586 if (isClientObject()) 587 { 588 // find local camera 589 camera_cons_obj = get_camera(); 590 if (camera_cons_obj) 591 camera_cons_id = constraint_mgr->setReferenceObject(CAMERA_CONS, camera_cons_obj); 592 593 // find local listener 594 Point3F listener_pos; 595 listener_pos = SFX->getListener().getTransform().getPosition(); 596 listener_cons_id = constraint_mgr->setReferencePoint(LISTENER_CONS, listener_pos); 597 598 // find free target 599 free_target_cons_id = constraint_mgr->setReferencePoint(FREE_TARGET_CONS, arcaneFX::sFreeTargetPos); 600 } 601 602 constraint_mgr->adjustProcessOrdering(this); 603 604 constraints_initialized = true; 605} 606 607void afxSelectron::setup_main_fx() 608{ 609 phrases[MAIN_PHRASE] = new afxPhrase(isServerObject(), true); 610 611 if (phrases[MAIN_PHRASE]) 612 phrases[MAIN_PHRASE]->init(datablock->main_fx_list, datablock->main_dur, this, time_factor, 613 datablock->n_main_loops); 614} 615 616void afxSelectron::setup_select_fx() 617{ 618 phrases[SELECT_PHRASE] = new afxPhrase(isServerObject(), true); 619 620 if (phrases[SELECT_PHRASE]) 621 phrases[SELECT_PHRASE]->init(datablock->select_fx_list, -1, this, time_factor, 1); 622} 623 624void afxSelectron::setup_deselect_fx() 625{ 626 phrases[DESELECT_PHRASE] = new afxPhrase(isServerObject(), true); 627 628 if (phrases[DESELECT_PHRASE]) 629 phrases[DESELECT_PHRASE]->init(datablock->deselect_fx_list, -1, this, time_factor, 1); 630} 631 632bool afxSelectron::cleanup_over() 633{ 634 for (S32 i = 0; i < NUM_PHRASES; i++) 635 if (phrases[i] && !phrases[i]->isEmpty()) 636 return false; 637 638 return true; 639} 640 641//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 642// private 643 644void afxSelectron::process_server() 645{ 646 if (effect_state != INACTIVE_STATE) 647 effect_elapsed += TickSec; 648 649 U8 pending_state = effect_state; 650 651 // check for state changes 652 switch (effect_state) 653 { 654 case INACTIVE_STATE: 655 if (marks_mask & MARK_ACTIVATE) 656 pending_state = ACTIVE_STATE; 657 break; 658 case ACTIVE_STATE: 659 if (marks_mask & MARK_INTERRUPT) 660 pending_state = CLEANUP_STATE; 661 else if (marks_mask & MARK_SHUTDOWN) 662 pending_state = CLEANUP_STATE; 663 else if (state_expired()) 664 pending_state = CLEANUP_STATE; 665 break; 666 case CLEANUP_STATE: 667 if (cleanup_over()) 668 pending_state = DONE_STATE; 669 break; 670 } 671 672 if (effect_state != pending_state) 673 change_state_s(pending_state); 674 675 if (effect_state == INACTIVE_STATE) 676 return; 677 678 //--------------------------// 679 680 // sample the constraints 681 constraint_mgr->sample(TickSec, Platform::getVirtualMilliseconds()); 682 683 for (S32 i = 0; i < NUM_PHRASES; i++) 684 if (phrases[i]) 685 phrases[i]->update(TickSec, effect_elapsed); 686} 687 688void afxSelectron::change_state_s(U8 pending_state) 689{ 690 if (effect_state == pending_state) 691 return; 692 693 switch (effect_state) 694 { 695 case INACTIVE_STATE: 696 break; 697 case ACTIVE_STATE: 698 leave_active_state_s(); 699 break; 700 case CLEANUP_STATE: 701 break; 702 case DONE_STATE: 703 break; 704 } 705 706 effect_state = pending_state; 707 708 switch (pending_state) 709 { 710 case INACTIVE_STATE: 711 break; 712 case ACTIVE_STATE: 713 enter_active_state_s(); 714 break; 715 case CLEANUP_STATE: 716 enter_cleanup_state_s(); 717 break; 718 case DONE_STATE: 719 enter_done_state_s(); 720 break; 721 } 722} 723 724void afxSelectron::enter_done_state_s() 725{ 726 postEvent(DEACTIVATE_EVENT); 727 728 F32 done_time = effect_elapsed; 729 730 for (S32 i = 0; i < NUM_PHRASES; i++) 731 { 732 if (phrases[i]) 733 { 734 F32 phrase_done; 735 if (phrases[i]->willStop() && phrases[i]->isInfinite()) 736 phrase_done = effect_elapsed + phrases[i]->calcAfterLife(); 737 else 738 phrase_done = phrases[i]->calcDoneTime(); 739 if (phrase_done > done_time) 740 done_time = phrase_done; 741 } 742 } 743 744 F32 time_left = done_time - effect_elapsed; 745 if (time_left < 0) 746 time_left = 0; 747 748 Sim::postEvent(this, new ObjectDeleteEvent, Sim::getCurrentTime() + time_left*1000 + 500); 749 750 // CALL SCRIPT afxSelectronData::onDeactivate(%sele) 751 Con::executef(datablock, "onDeactivate", getIdString()); 752} 753 754void afxSelectron::enter_active_state_s() 755{ 756 // stamp constraint-mgr starting time 757 constraint_mgr->setStartTime(Platform::getVirtualMilliseconds()); 758 effect_elapsed = 0; 759 760 setup_dynamic_constraints(); 761 762 // start casting effects 763 setup_main_fx(); 764 if (phrases[MAIN_PHRASE]) 765 phrases[MAIN_PHRASE]->start(effect_elapsed, effect_elapsed); 766 767 setup_select_fx(); 768 if (phrases[SELECT_PHRASE]) 769 phrases[SELECT_PHRASE]->start(effect_elapsed, effect_elapsed); 770} 771 772void afxSelectron::leave_active_state_s() 773{ 774 if (phrases[MAIN_PHRASE]) 775 phrases[MAIN_PHRASE]->stop(effect_elapsed); 776} 777 778void afxSelectron::enter_cleanup_state_s() 779{ 780 // start deselect effects 781 setup_deselect_fx(); 782 if (phrases[SELECT_PHRASE]) 783 phrases[SELECT_PHRASE]->interrupt(effect_elapsed); 784 if (phrases[DESELECT_PHRASE]) 785 phrases[DESELECT_PHRASE]->start(effect_elapsed, effect_elapsed); 786 787 postEvent(SHUTDOWN_EVENT); 788} 789 790//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 791// private 792 793void afxSelectron::process_client(F32 dt) 794{ 795 effect_elapsed += dt; 796 797 U8 pending_state = effect_state; 798 799 // check for state changes 800 switch (effect_state) 801 { 802 case INACTIVE_STATE: 803 if (marks_mask & MARK_ACTIVATE) 804 pending_state = ACTIVE_STATE; 805 break; 806 case ACTIVE_STATE: 807 if (marks_mask & MARK_INTERRUPT) 808 pending_state = CLEANUP_STATE; 809 else if (marks_mask & MARK_SHUTDOWN) 810 pending_state = CLEANUP_STATE; 811 else if (state_expired()) 812 pending_state = CLEANUP_STATE; 813 break; 814 case CLEANUP_STATE: 815 if (cleanup_over()) 816 pending_state = DONE_STATE; 817 break; 818 } 819 820 if (effect_state != pending_state) 821 change_state_c(pending_state); 822 823 if (effect_state == INACTIVE_STATE) 824 return; 825 826 //--------------------------// 827 828 // update the listener constraint position 829 if (!listener_cons_id.undefined()) 830 { 831 Point3F listener_pos; 832 listener_pos = SFX->getListener().getTransform().getPosition(); 833 constraint_mgr->setReferencePoint(listener_cons_id, listener_pos); 834 } 835 836 // update the free target constraint position 837 if (!free_target_cons_id.undefined()) 838 { 839 if (!arcaneFX::sFreeTargetPosValid) 840 constraint_mgr->invalidateReference(free_target_cons_id); 841 else 842 constraint_mgr->setReferencePoint(free_target_cons_id, arcaneFX::sFreeTargetPos); 843 } 844 845 // find local camera position 846 Point3F cam_pos; 847 SceneObject* current_cam = get_camera(&cam_pos); 848 849 // detect camera changes 850 if (!camera_cons_id.undefined() && current_cam != camera_cons_obj) 851 { 852 constraint_mgr->setReferenceObject(camera_cons_id, current_cam); 853 camera_cons_obj = current_cam; 854 } 855 856 // sample the constraints 857 constraint_mgr->sample(dt, Platform::getVirtualMilliseconds(), (current_cam) ? &cam_pos : 0); 858 859 // update active effects lists 860 for (S32 i = 0; i < NUM_PHRASES; i++) 861 if (phrases[i]) 862 phrases[i]->update(dt, effect_elapsed); 863 864} 865 866void afxSelectron::change_state_c(U8 pending_state) 867{ 868 if (effect_state == pending_state) 869 return; 870 871 switch (effect_state) 872 { 873 case INACTIVE_STATE: 874 break; 875 case ACTIVE_STATE: 876 leave_active_state_c(); 877 break; 878 case CLEANUP_STATE: 879 break; 880 case DONE_STATE: 881 break; 882 } 883 884 effect_state = pending_state; 885 886 switch (pending_state) 887 { 888 case INACTIVE_STATE: 889 break; 890 case ACTIVE_STATE: 891 enter_active_state_c(effect_elapsed); 892 break; 893 case CLEANUP_STATE: 894 enter_cleanup_state_c(); 895 break; 896 case DONE_STATE: 897 enter_done_state_c(); 898 break; 899 } 900} 901 902void afxSelectron::enter_active_state_c(F32 starttime) 903{ 904 // stamp constraint-mgr starting time 905 constraint_mgr->setStartTime(Platform::getVirtualMilliseconds() - (U32)(effect_elapsed*1000)); 906 ///effect_elapsed = 0; 907 908 setup_dynamic_constraints(); 909 910 setup_main_fx(); 911 if (phrases[MAIN_PHRASE]) 912 phrases[MAIN_PHRASE]->start(starttime, effect_elapsed); 913 914 setup_select_fx(); 915 if (phrases[SELECT_PHRASE]) 916 phrases[SELECT_PHRASE]->start(starttime, effect_elapsed); 917} 918 919void afxSelectron::leave_active_state_c() 920{ 921 if (phrases[MAIN_PHRASE]) 922 { 923 //if (marks_mask & MARK_INTERRUPT) 924 // active_phrase->interrupt(effect_elapsed); 925 //else 926 phrases[MAIN_PHRASE]->stop(effect_elapsed); 927 } 928} 929 930void afxSelectron::enter_cleanup_state_c() 931{ 932 if (!client_only) 933 return; 934 935 // start deselect effects 936 setup_deselect_fx(); 937 if (phrases[DESELECT_PHRASE]) 938 phrases[DESELECT_PHRASE]->start(effect_elapsed, effect_elapsed); 939 940 postEvent(SHUTDOWN_EVENT); 941} 942 943void afxSelectron::enter_done_state_c() 944{ 945 if (!client_only) 946 return; 947 948 postEvent(DEACTIVATE_EVENT); 949 950 F32 done_time = effect_elapsed; 951 952 for (S32 i = 0; i < NUM_PHRASES; i++) 953 { 954 if (phrases[i]) 955 { 956 F32 phrase_done; 957 if (phrases[i]->willStop() && phrases[i]->isInfinite()) 958 phrase_done = effect_elapsed + phrases[i]->calcAfterLife(); 959 else 960 phrase_done = phrases[i]->calcDoneTime(); 961 if (phrase_done > done_time) 962 done_time = phrase_done; 963 } 964 } 965 966 F32 time_left = done_time - effect_elapsed; 967 if (time_left < 0) 968 time_left = 0; 969 970 Sim::postEvent(this, new ObjectDeleteEvent, Sim::getCurrentTime() + time_left*1000 + 500); 971 972 // CALL SCRIPT afxSelectronData::onDeactivate(%selectron) 973 Con::executef(datablock, "onDeactivate", getIdString()); 974} 975 976void afxSelectron::sync_client(U16 marks, U8 state, F32 elapsed) 977{ 978 //Con::printf("SYNC marks=%d old_state=%d state=%d elapsed=%g", 979 // marks, effect_state, state, elapsed); 980 981 if (effect_state != LATE_STATE) 982 return; 983 984 marks_mask = marks; 985 986 // don't want to be started on late zoning clients 987 if (!datablock->exec_on_new_clients) 988 { 989 effect_state = DONE_STATE; 990 } 991 992 // it looks like we're ghosting pretty late and 993 // should just return to the inactive state. 994 else if (marks & (MARK_INTERRUPT | MARK_DEACTIVATE | MARK_SHUTDOWN)) 995 { 996 effect_state = DONE_STATE; 997 } 998 999 // it looks like we should be in the active state. 1000 else if (marks & MARK_ACTIVATE) 1001 { 1002 effect_state = ACTIVE_STATE; 1003 effect_elapsed = elapsed; 1004 enter_active_state_c(0.0); 1005 } 1006} 1007 1008//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 1009// public: 1010 1011void afxSelectron::postEvent(U8 event) 1012{ 1013 setMaskBits(StateEventMask); 1014 1015 switch (event) 1016 { 1017 case ACTIVATE_EVENT: 1018 marks_mask |= MARK_ACTIVATE; 1019 break; 1020 case SHUTDOWN_EVENT: 1021 marks_mask |= MARK_SHUTDOWN; 1022 break; 1023 case DEACTIVATE_EVENT: 1024 marks_mask |= MARK_DEACTIVATE; 1025 break; 1026 case INTERRUPT_EVENT: 1027 marks_mask |= MARK_INTERRUPT; 1028 break; 1029 } 1030} 1031 1032//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 1033 1034void afxSelectron::finish_startup() 1035{ 1036 init_constraints(); 1037 postEvent(afxSelectron::ACTIVATE_EVENT); 1038} 1039 1040// static 1041afxSelectron* 1042afxSelectron::start_selectron(SceneObject* picked, U8 subcode, SimObject* extra) 1043{ 1044 U32 picked_type = (picked) ? picked->getTypeMask() : 0; 1045 1046 afxSelectronData* datablock = arcaneFX::findSelectronData(picked_type, subcode); 1047 if (!datablock) 1048 { 1049 Con::errorf("startSelectron() -- failed to match object-type (%x/%d) to a selection-effect.", 1050 picked_type, subcode); 1051 return 0; 1052 } 1053 1054 afxSelectronData* exeblock = datablock; 1055 1056 SimObject* param_holder = new SimObject(); 1057 if (!param_holder->registerObject()) 1058 { 1059 Con::errorf("afxSelectron: failed to register parameter object."); 1060 delete param_holder; 1061 return 0; 1062 } 1063 1064 param_holder->assignDynamicFieldsFrom(datablock, arcaneFX::sParameterFieldPrefix); 1065 if (extra) 1066 { 1067 // copy dynamic fields from the extra object to the param holder 1068 param_holder->assignDynamicFieldsFrom(extra, arcaneFX::sParameterFieldPrefix); 1069 } 1070 1071 // CALL SCRIPT afxSelectronData::onPreactivate(%params, %extra) 1072 const char* result = Con::executef(datablock, "onPreactivate", 1073 Con::getIntArg(param_holder->getId()), 1074 (extra) ? Con::getIntArg(extra->getId()) : ""); 1075 if (result && result[0] != '\0' && !dAtob(result)) 1076 { 1077#if defined(TORQUE_DEBUG) 1078 Con::warnf("afxSelectron: onPreactivate() returned false, effect aborted."); 1079#endif 1080 Sim::postEvent(param_holder, new ObjectDeleteEvent, Sim::getCurrentTime()); 1081 return 0; 1082 } 1083 1084 // make a temp datablock clone if there are substitutions 1085 if (datablock->getSubstitutionCount() > 0) 1086 { 1087 datablock = new afxSelectronData(*exeblock, true); 1088 exeblock->performSubstitutions(datablock, param_holder); 1089 } 1090 1091 // create a new selectron instance 1092 afxSelectron* selectron = new afxSelectron(true); 1093 selectron->setDataBlock(datablock); 1094 selectron->exeblock = exeblock; 1095 selectron->setExtra(extra); 1096 1097 // copy dynamic fields from the param holder to the selectron 1098 selectron->assignDynamicFieldsFrom(param_holder, arcaneFX::sParameterFieldPrefix); 1099 Sim::postEvent(param_holder, new ObjectDeleteEvent, Sim::getCurrentTime()); 1100 1101 // register 1102 if (!selectron->registerObject()) 1103 { 1104 Con::errorf("afxSelectron: failed to register selectron instance."); 1105 Sim::postEvent(selectron, new ObjectDeleteEvent, Sim::getCurrentTime()); 1106 return 0; 1107 } 1108 1109 selectron->activate(); 1110 1111 return selectron; 1112} 1113 1114void afxSelectron::activate() 1115{ 1116 // separating the final part of startup allows the calling script 1117 // to make certain types of calls on the returned effectron that 1118 // need to happen prior to constraint initialization. 1119 Sim::postEvent(this, new SelectronFinishStartupEvent, Sim::getCurrentTime()); 1120 1121 // CALL SCRIPT afxEffectronData::onActivate(%eff) 1122 Con::executef(exeblock, "onActivate", getIdString()); 1123} 1124 1125//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 1126// console functions 1127 1128DefineEngineMethod(afxSelectron, setTimeFactor, void, (float factor), (1.0f), 1129 "Sets the time factor of the selectron.\n\n" 1130 "@ingroup AFX") 1131{ 1132 object->setTimeFactor(factor); 1133} 1134 1135DefineEngineMethod(afxSelectron, interrupt, void, (),, 1136 "Interrupts and deletes a running selectron.\n\n" 1137 "@ingroup AFX") 1138{ 1139 object->postEvent(afxSelectron::INTERRUPT_EVENT); 1140} 1141 1142DefineEngineMethod(afxSelectron, stopSelectron, void, (),, 1143 "Stops and deletes a running selectron.\n\n" 1144 "@ingroup AFX") 1145{ 1146 object->postEvent(afxSelectron::INTERRUPT_EVENT); 1147} 1148 1149DefineEngineFunction(startSelectron, S32, (SceneObject* selectedObj, unsigned int subcode, SimObject* extra), 1150 (nullAsType<SceneObject*>(), 0, nullAsType<SimObject*>()), 1151 "Instantiates a selectron.\n\n" 1152 "@ingroup AFX") 1153{ 1154 // 1155 // Start the Selectron 1156 // 1157 afxSelectron* selectron = afxSelectron::start_selectron(selectedObj, (U8)subcode, extra); 1158 1159 // 1160 // Return the ID (or 0 if start failed). 1161 // 1162 return (selectron) ? selectron->getId() : 0; 1163} 1164 1165//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175