gameConnectionEvents.cpp
Engine/source/T3D/gameBase/gameConnectionEvents.cpp
Public Defines
define
DebugChecksum() 0xF00DBAAD
Public Variables
Public Functions
ConsoleDocClass(SetMissionCRCEvent , "@brief Use by <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> send <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 3D sound event over the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">network.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, internal use only, but does expose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GameConnection::setMissionCRC.\n\n</a> " " @internal" )
ConsoleDocClass(Sim2DAudioEvent , "@brief Use by <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> send <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 2D sound event over the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">network.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, internal use only, but does expose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GameConnection::play2D.\n\n</a> " " @internal" )
ConsoleDocClass(Sim3DAudioEvent , "@brief Use by <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> send <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 3D sound event over the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">network.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, internal use only, but does expose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GameConnection::play3D.\n\n</a> " " @internal" )
ConsoleDocClass(SimDataBlockEvent , "@brief Use by <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> process incoming <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">datablocks.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, internal use only, but does expose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">onDataBlockObjectReceived.\n\n</a> " " @internal" )
Detailed Description
Public Defines
DebugChecksum() 0xF00DBAAD
Public Variables
F32 SoundPosAccuracy
S32 SoundRotBits
Public Functions
ConsoleDocClass(SetMissionCRCEvent , "@brief Use by <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> send <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 3D sound event over the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">network.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, internal use only, but does expose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GameConnection::setMissionCRC.\n\n</a> " " @internal" )
ConsoleDocClass(Sim2DAudioEvent , "@brief Use by <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> send <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 2D sound event over the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">network.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, internal use only, but does expose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GameConnection::play2D.\n\n</a> " " @internal" )
ConsoleDocClass(Sim3DAudioEvent , "@brief Use by <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> send <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 3D sound event over the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">network.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, internal use only, but does expose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GameConnection::play3D.\n\n</a> " " @internal" )
ConsoleDocClass(SimDataBlockEvent , "@brief Use by <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> process incoming <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">datablocks.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, internal use only, but does expose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">onDataBlockObjectReceived.\n\n</a> " " @internal" )
IMPLEMENT_CO_CLIENTEVENT_V1(SetMissionCRCEvent )
IMPLEMENT_CO_CLIENTEVENT_V1(Sim2DAudioEvent )
IMPLEMENT_CO_CLIENTEVENT_V1(Sim3DAudioEvent )
IMPLEMENT_CO_CLIENTEVENT_V1(SimDataBlockEvent )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 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//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 26// Copyright (C) 2015 Faust Logic, Inc. 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 28 29#include "platform/platform.h" 30#include "core/dnet.h" 31#include "core/stream/bitStream.h" 32#include "console/consoleTypes.h" 33#include "console/simBase.h" 34#include "scene/pathManager.h" 35#include "scene/sceneManager.h" 36#include "sfx/sfxSystem.h" 37#include "sfx/sfxDescription.h" 38#include "app/game.h" 39#include "T3D/gameBase/gameConnection.h" 40#include "T3D/gameBase/gameConnectionEvents.h" 41#include "console/engineAPI.h" 42 43#define DebugChecksum 0xF00DBAAD 44 45 46//#define DEBUG_SPEW 47 48 49//-------------------------------------------------------------------------- 50IMPLEMENT_CO_CLIENTEVENT_V1(SimDataBlockEvent); 51IMPLEMENT_CO_CLIENTEVENT_V1(Sim2DAudioEvent); 52IMPLEMENT_CO_CLIENTEVENT_V1(Sim3DAudioEvent); 53IMPLEMENT_CO_CLIENTEVENT_V1(SetMissionCRCEvent); 54 55ConsoleDocClass( SimDataBlockEvent, 56 "@brief Use by GameConnection to process incoming datablocks.\n\n" 57 "Not intended for game development, internal use only, but does expose onDataBlockObjectReceived.\n\n " 58 "@internal"); 59 60ConsoleDocClass( Sim2DAudioEvent, 61 "@brief Use by GameConnection to send a 2D sound event over the network.\n\n" 62 "Not intended for game development, internal use only, but does expose GameConnection::play2D.\n\n " 63 "@internal"); 64 65ConsoleDocClass( Sim3DAudioEvent, 66 "@brief Use by GameConnection to send a 3D sound event over the network.\n\n" 67 "Not intended for game development, internal use only, but does expose GameConnection::play3D.\n\n " 68 "@internal"); 69 70ConsoleDocClass( SetMissionCRCEvent, 71 "@brief Use by GameConnection to send a 3D sound event over the network.\n\n" 72 "Not intended for game development, internal use only, but does expose GameConnection::setMissionCRC.\n\n " 73 "@internal"); 74 75//---------------------------------------------------------------------------- 76 77SimDataBlockEvent::SimDataBlockEvent(SimDataBlock* obj, U32 index, U32 total, U32 missionSequence) 78{ 79 mObj = NULL; 80 mIndex = index; 81 mTotal = total; 82 mMissionSequence = missionSequence; 83 mProcess = false; 84 85 if(obj) 86 { 87 id = obj->getId(); 88 AssertFatal(id >= DataBlockObjectIdFirst && id <= DataBlockObjectIdLast, 89 "Out of range event data block id... check simBase.h"); 90 91 #ifdef DEBUG_SPEW 92 Con::printf("queuing data block: %d", mIndex); 93 #endif 94 } 95} 96 97SimDataBlockEvent::~SimDataBlockEvent() 98{ 99 if( mObj ) 100 delete mObj; 101} 102 103#ifdef TORQUE_DEBUG_NET 104const char *SimDataBlockEvent::getDebugName() 105{ 106 SimObject *obj = Sim::findObject(id); 107 static char buffer[256]; 108 dSprintf(buffer, sizeof(buffer), "%s [%s - %s]", 109 getClassName(), 110 obj ? obj->getName() : "", 111 obj ? obj->getClassName() : "NONE"); 112 return buffer; 113} 114#endif // TORQUE_DEBUG_NET 115 116void SimDataBlockEvent::notifyDelivered(NetConnection *conn, bool ) 117{ 118 // if the modified key for this event is not the current one, 119 // we've already resorted and resent some blocks, so fall out. 120 if(conn->isRemoved()) 121 return; 122 123 GameConnection *gc = (GameConnection *) conn; 124 if(gc->getDataBlockSequence() != mMissionSequence) 125 return; 126 127 U32 nextIndex = mIndex + DataBlockQueueCount; 128 SimDataBlockGroup *g = Sim::getDataBlockGroup(); 129 130 if(mIndex == g->size() - 1) 131 { 132 gc->setDataBlockModifiedKey(gc->getMaxDataBlockModifiedKey()); 133 gc->sendConnectionMessage(GameConnection::DataBlocksDone, mMissionSequence); 134 } 135 136 if(g->size() <= nextIndex) 137 return; 138 139 SimDataBlock *blk = (SimDataBlock *) (*g)[nextIndex]; 140 gc->postNetEvent(new SimDataBlockEvent(blk, nextIndex, g->size(), mMissionSequence)); 141} 142 143void SimDataBlockEvent::pack(NetConnection *conn, BitStream *bstream) 144{ 145#ifdef AFX_CAP_DATABLOCK_CACHE 146 ((GameConnection *)conn)->tempDisableStringBuffering(bstream); 147#endif 148 SimDataBlock* obj; 149 Sim::findObject(id,obj); 150 GameConnection *gc = (GameConnection *) conn; 151 if(bstream->writeFlag(gc->getDataBlockModifiedKey() < obj->getModifiedKey())) 152 { 153 if(obj->getModifiedKey() > gc->getMaxDataBlockModifiedKey()) 154 gc->setMaxDataBlockModifiedKey(obj->getModifiedKey()); 155 156 AssertFatal(obj, 157 "SimDataBlockEvent:: Data blocks cannot be deleted"); 158 bstream->writeInt(id - DataBlockObjectIdFirst,DataBlockObjectIdBitSize); 159 160 S32 classId = obj->getClassId(conn->getNetClassGroup()); 161 bstream->writeClassId(classId, NetClassTypeDataBlock, conn->getNetClassGroup()); 162 bstream->writeInt(mIndex, DataBlockObjectIdBitSize); 163 bstream->writeInt(mTotal, DataBlockObjectIdBitSize + 1); 164 obj->packData(bstream); 165#ifdef TORQUE_DEBUG_NET 166 bstream->writeInt(classId ^ DebugChecksum, 32); 167#endif 168 } 169#ifdef AFX_CAP_DATABLOCK_CACHE 170 ((GameConnection *)conn)->restoreStringBuffering(bstream); 171#endif 172} 173 174void SimDataBlockEvent::unpack(NetConnection *cptr, BitStream *bstream) 175{ 176#ifdef AFX_CAP_DATABLOCK_CACHE 177 // stash the stream position prior to unpacking 178 S32 start_pos = bstream->getCurPos(); 179 ((GameConnection *)cptr)->tempDisableStringBuffering(bstream); 180#endif 181 if(bstream->readFlag()) 182 { 183 mProcess = true; 184 id = bstream->readInt(DataBlockObjectIdBitSize) + DataBlockObjectIdFirst; 185 S32 classId = bstream->readClassId(NetClassTypeDataBlock, cptr->getNetClassGroup()); 186 mIndex = bstream->readInt(DataBlockObjectIdBitSize); 187 mTotal = bstream->readInt(DataBlockObjectIdBitSize + 1); 188 189 SimObject* ptr; 190 if( Sim::findObject( id, ptr ) ) 191 { 192 // An object with the given ID already exists. Make sure it has the right class. 193 194 AbstractClassRep* classRep = AbstractClassRep::findClassRep( cptr->getNetClassGroup(), NetClassTypeDataBlock, classId ); 195 if( classRep && String::compare( classRep->getClassName(), ptr->getClassName() ) != 0 ) 196 { 197 Con::warnf( "A '%s' datablock with id: %d already existed. " 198 "Clobbering it with new '%s' datablock from server.", 199 ptr->getClassName(), id, classRep->getClassName() ); 200 ptr->deleteObject(); 201 ptr = NULL; 202 } 203 } 204 205 if( !ptr ) 206 ptr = ( SimObject* ) ConsoleObject::create( cptr->getNetClassGroup(), NetClassTypeDataBlock, classId ); 207 208 mObj = dynamic_cast< SimDataBlock* >( ptr ); 209 if( mObj != NULL ) 210 { 211 #ifdef DEBUG_SPEW 212 Con::printf(" - SimDataBlockEvent: unpacking event of type: %s", mObj->getClassName()); 213 #endif 214 215 mObj->unpackData( bstream ); 216 } 217 else 218 { 219 #ifdef DEBUG_SPEW 220 Con::printf(" - SimDataBlockEvent: INVALID PACKET! Could not create class with classID: %d", classId); 221 #endif 222 223 delete ptr; 224 cptr->setLastError("Invalid packet in SimDataBlockEvent::unpack()"); 225 } 226 227#ifdef TORQUE_DEBUG_NET 228 U32 checksum = bstream->readInt(32); 229 AssertISV( (checksum ^ DebugChecksum) == (U32)classId, 230 avar("unpack did not match pack for event of class %s.", 231 mObj->getClassName()) ); 232#endif 233 234 } 235#ifdef AFX_CAP_DATABLOCK_CACHE 236 // rewind to stream position and then process raw bytes for caching 237 ((GameConnection *)cptr)->repackClientDatablock(bstream, start_pos); 238 ((GameConnection *)cptr)->restoreStringBuffering(bstream); 239#endif 240} 241 242void SimDataBlockEvent::write(NetConnection *cptr, BitStream *bstream) 243{ 244 if(bstream->writeFlag(mProcess)) 245 { 246 bstream->writeInt(id - DataBlockObjectIdFirst,DataBlockObjectIdBitSize); 247 S32 classId = mObj->getClassId(cptr->getNetClassGroup()); 248 bstream->writeClassId(classId, NetClassTypeDataBlock, cptr->getNetClassGroup()); 249 bstream->writeInt(mIndex, DataBlockObjectIdBitSize); 250 bstream->writeInt(mTotal, DataBlockObjectIdBitSize + 1); 251 mObj->packData(bstream); 252 } 253} 254 255void SimDataBlockEvent::process(NetConnection *cptr) 256{ 257 if(mProcess) 258 { 259 //call the console function to set the number of blocks to be sent 260 Con::executef("onDataBlockObjectReceived", mIndex, mTotal); 261 262 String &errorBuffer = NetConnection::getErrorBuffer(); 263 264 // Register the datablock object if this is a new DB 265 // and not for a modified datablock event. 266 267 if( !mObj->isProperlyAdded() ) 268 { 269 // This is a fresh datablock object. 270 // Perform preload on datablock and register 271 // the object. 272 273 GameConnection* conn = dynamic_cast< GameConnection* >( cptr ); 274 if( conn ) 275 conn->preloadDataBlock( mObj ); 276 277 if( mObj->registerObject(id) ) 278 { 279 cptr->addObject( mObj ); 280 mObj = NULL; 281 } 282 } 283 else 284 { 285 // This is an update to an existing datablock. Preload 286 // to finish this. 287 288 mObj->preload( false, errorBuffer ); 289 mObj = NULL; 290 } 291 } 292} 293 294 295//---------------------------------------------------------------------------- 296 297 298Sim2DAudioEvent::Sim2DAudioEvent(SFXProfile *profile) 299{ 300 mProfile = profile; 301} 302 303void Sim2DAudioEvent::pack(NetConnection *, BitStream *bstream) 304{ 305 bstream->writeInt( mProfile->getId() - DataBlockObjectIdFirst, DataBlockObjectIdBitSize); 306} 307 308void Sim2DAudioEvent::write(NetConnection *, BitStream *bstream) 309{ 310 bstream->writeInt( mProfile->getId() - DataBlockObjectIdFirst, DataBlockObjectIdBitSize); 311} 312 313void Sim2DAudioEvent::unpack(NetConnection *, BitStream *bstream) 314{ 315 SimObjectId id = bstream->readInt(DataBlockObjectIdBitSize) + DataBlockObjectIdFirst; 316 Sim::findObject(id, mProfile); 317} 318 319void Sim2DAudioEvent::process(NetConnection *) 320{ 321 if (mProfile) 322 SFX->playOnce( mProfile ); 323} 324 325//---------------------------------------------------------------------------- 326 327static F32 SoundPosAccuracy = 0.5; 328static S32 SoundRotBits = 8; 329 330Sim3DAudioEvent::Sim3DAudioEvent(SFXProfile *profile,const MatrixF* mat) 331{ 332 mProfile = profile; 333 if (mat) 334 mTransform = *mat; 335} 336 337void Sim3DAudioEvent::pack(NetConnection *con, BitStream *bstream) 338{ 339 bstream->writeInt(mProfile->getId() - DataBlockObjectIdFirst, DataBlockObjectIdBitSize); 340 341 // If the sound has cone parameters, the orientation is 342 // transmitted as well. 343 SFXDescription* ad = mProfile->getDescription(); 344 if ( bstream->writeFlag( ad->mConeInsideAngle || ad->mConeOutsideAngle ) ) 345 { 346 QuatF q(mTransform); 347 q.normalize(); 348 349 // LH - we can get a valid quat that's very slightly over 1 in and so 350 // this fails (barely) check against zero. So use some error- 351 AssertFatal((1.0 - ((q.x * q.x) + (q.y * q.y) + (q.z * q.z))) >= (0.0 - 0.001), 352 "QuatF::normalize() is broken in Sim3DAudioEvent"); 353 354 bstream->writeSignedFloat(q.x,SoundRotBits); 355 bstream->writeSignedFloat(q.y,SoundRotBits); 356 bstream->writeSignedFloat(q.z,SoundRotBits); 357 bstream->writeFlag(q.w < 0.0); 358 } 359 360 Point3F pos; 361 mTransform.getColumn(3,&pos); 362 bstream->writeCompressedPoint(pos,SoundPosAccuracy); 363} 364 365void Sim3DAudioEvent::write(NetConnection *con, BitStream *bstream) 366{ 367 // Just do the normal pack... 368 pack(con,bstream); 369} 370 371void Sim3DAudioEvent::unpack(NetConnection *con, BitStream *bstream) 372{ 373 SimObjectId id = bstream->readInt(DataBlockObjectIdBitSize) + DataBlockObjectIdFirst; 374 Sim::findObject(id, mProfile); 375 376 if (bstream->readFlag()) { 377 QuatF q; 378 q.x = bstream->readSignedFloat(SoundRotBits); 379 q.y = bstream->readSignedFloat(SoundRotBits); 380 q.z = bstream->readSignedFloat(SoundRotBits); 381 F32 value = ((q.x * q.x) + (q.y * q.y) + (q.z * q.z)); 382// #ifdef __linux 383 // Hmm, this should never happen, but it does... 384 if ( value > 1.f ) 385 value = 1.f; 386// #endif 387 q.w = mSqrt(1.f - value); 388 if (bstream->readFlag()) 389 q.w = -q.w; 390 q.setMatrix(&mTransform); 391 } 392 else 393 mTransform.identity(); 394 395 Point3F pos; 396 bstream->readCompressedPoint(&pos,SoundPosAccuracy); 397 mTransform.setColumn(3, pos); 398} 399 400void Sim3DAudioEvent::process(NetConnection *) 401{ 402 if (mProfile) 403 SFX->playOnce( mProfile, &mTransform ); 404} 405 406