Torque3D Documentation / _generateds / pathManager.cpp

pathManager.cpp

Engine/source/scene/pathManager.cpp

More...

Classes:

Public Functions

ConsoleDocClass(PathManagerEvent , "@brief Class responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the registration, transmission , and management " "of paths on client and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n\n</a>" "For internal use only, not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> use in TorqueScript or game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">development\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">internal\n</a>" )
DefineConsoleFunction(clearClientPaths , void , () , "" )
DefineConsoleFunction(clearServerPaths , void , () , "" )

Detailed Description

Public Variables

 gClientPathManager 
bool gEditingMission 

For frame signal.

 gServerPathManager 
 MODULE_END 
 MODULE_INIT 
 MODULE_SHUTDOWN 

Public Functions

ConsoleDocClass(PathManagerEvent , "@brief Class responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the registration, transmission , and management " "of paths on client and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n\n</a>" "For internal use only, not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> use in TorqueScript or game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">development\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">internal\n</a>" )

DefineConsoleFunction(clearClientPaths , void , () , "" )

DefineConsoleFunction(clearServerPaths , void , () , "" )

IMPLEMENT_CO_NETEVENT_V1(PathManagerEvent )

  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#include "gfx/gfxDevice.h"
 25#include "scene/pathManager.h"
 26#include "sim/netConnection.h"
 27#include "core/stream/bitStream.h"
 28#include "scene/simPath.h"
 29#include "math/mathIO.h"
 30#include "scene/sceneRenderState.h"
 31#include "scene/sceneManager.h"
 32#include "platform/profiler.h"
 33#include "core/module.h"
 34#include "console/engineAPI.h"
 35
 36extern bool gEditingMission;
 37
 38
 39namespace {
 40
 41U32 countNumBits(U32 n)
 42{
 43   U32 count = 0;
 44   while (n != 0) {
 45      n >>= 1;
 46      count++;
 47   }
 48
 49   return count ? count : 1;
 50}
 51
 52} // namespace {}
 53
 54
 55MODULE_BEGIN( PathManager )
 56
 57   MODULE_INIT
 58   {
 59      AssertFatal(gClientPathManager == NULL && gServerPathManager == NULL, "Error, already initialized the path manager!");
 60
 61      gClientPathManager = new PathManager(false);
 62      gServerPathManager = new PathManager(true);
 63   }
 64
 65   MODULE_SHUTDOWN
 66   {
 67      AssertFatal(gClientPathManager != NULL && gServerPathManager != NULL, "Error, path manager not initialized!");
 68
 69      delete gClientPathManager;
 70      gClientPathManager = NULL;
 71      delete gServerPathManager;
 72      gServerPathManager = NULL;
 73   }
 74
 75MODULE_END;
 76
 77
 78//--------------------------------------------------------------------------
 79//-------------------------------------- PathManagerEvent
 80//
 81class PathManagerEvent : public NetEvent
 82{
 83  public:
 84   U32  modifiedPath;
 85   bool clearPaths;
 86   PathManager::PathEntry path;
 87
 88  public:
 89   typedef NetEvent Parent;
 90   PathManagerEvent() : modifiedPath(0), clearPaths(false) { }
 91
 92   void pack(NetConnection*, BitStream*);
 93   void write(NetConnection*, BitStream*);
 94   void unpack(NetConnection*, BitStream*);
 95   void process(NetConnection*);
 96
 97   DECLARE_CONOBJECT(PathManagerEvent);
 98};
 99
100void PathManagerEvent::pack(NetConnection*, BitStream* stream)
101{
102   // Write out the modified path...
103   stream->write(modifiedPath);
104   stream->writeFlag(clearPaths);
105   stream->write(path.totalTime);
106   stream->write(path.positions.size());
107
108
109   // This is here for safety. You can remove it if you want to try your luck at bigger sizes. -- BJG
110   AssertWarn(path.positions.size() < 1500/40, "Warning! Path size is pretty big - may cause packet overrun!");
111
112   // Each one of these is about 8 floats and 2 ints
113   // so we'll say it's about 40 bytes in size, which is where the 40 in the above calc comes from.
114   for (U32 j = 0; j < path.positions.size(); j++)
115   {
116      mathWrite(*stream, path.positions[j]);
117      mathWrite(*stream, path.rotations[j]);
118      stream->write(path.msToNext[j]);
119      stream->write(path.smoothingType[j]);
120   }
121}
122
123void PathManagerEvent::write(NetConnection*nc, BitStream *stream)
124{
125   pack(nc, stream);
126}
127
128void PathManagerEvent::unpack(NetConnection*, BitStream* stream)
129{
130   // Read in the modified path...
131
132   stream->read(&modifiedPath);
133   clearPaths = stream->readFlag();
134   stream->read(&path.totalTime);
135
136   U32 numPoints;
137   stream->read(&numPoints);
138   path.positions.setSize(numPoints);
139   path.rotations.setSize(numPoints);
140   path.msToNext.setSize(numPoints);
141   path.smoothingType.setSize(numPoints);
142   for (U32 j = 0; j < path.positions.size(); j++)
143   {
144      mathRead(*stream, &path.positions[j]);
145      mathRead(*stream, &path.rotations[j]);
146      stream->read(&path.msToNext[j]);
147      stream->read(&path.smoothingType[j]);
148   }
149}
150
151void PathManagerEvent::process(NetConnection*)
152{
153   if (clearPaths)
154   {
155      // Clear out all the client's paths...
156      gClientPathManager->clearPaths();
157   }
158   AssertFatal(modifiedPath <= gClientPathManager->mPaths.size(), "Error out of bounds path!");
159   if (modifiedPath == gClientPathManager->mPaths.size()) {
160      PathManager::PathEntry *pe = new PathManager::PathEntry;
161      *pe = path;
162      gClientPathManager->mPaths.push_back(pe);
163   }
164   else
165      *(gClientPathManager->mPaths[modifiedPath]) = path;
166}
167
168IMPLEMENT_CO_NETEVENT_V1(PathManagerEvent);
169
170// Will be internalized once the @internal tag is working
171ConsoleDocClass( PathManagerEvent,
172   "@brief Class responsible for the registration, transmission, and management "
173   "of paths on client and server.\n\n"
174
175   "For internal use only, not intended for use in TorqueScript or game development\n\n"
176
177   "@internal\n"
178);
179
180//--------------------------------------------------------------------------
181//-------------------------------------- PathManager Implementation
182//
183PathManager* gClientPathManager = NULL;
184PathManager* gServerPathManager = NULL;
185
186//--------------------------------------------------------------------------
187PathManager::PathManager(const bool isServer)
188{
189   VECTOR_SET_ASSOCIATION(mPaths);
190
191   mIsServer  = isServer;
192}
193
194PathManager::~PathManager()
195{
196   clearPaths();
197}
198
199void PathManager::clearPaths()
200{
201   for (U32 i = 0; i < mPaths.size(); i++)
202      delete mPaths[i];
203   mPaths.setSize(0);
204#ifdef TORQUE_DEBUG
205   // This gets rid of the memory used by the vector.
206   // Prevents it from showing up in memory leak logs.
207   mPaths.compact();
208#endif
209}
210
211DefineConsoleFunction( clearServerPaths, void, ( ), , "")
212{
213   gServerPathManager->clearPaths();
214}
215
216DefineConsoleFunction( clearClientPaths, void, ( ), , "")
217{
218   gClientPathManager->clearPaths();
219}
220
221//--------------------------------------------------------------------------
222U32 PathManager::allocatePathId()
223{
224   mPaths.increment();
225   mPaths.last() = new PathEntry;
226
227   return (mPaths.size() - 1);
228}
229
230
231void PathManager::updatePath(const U32              id,
232                             const Vector<Point3F>& positions,
233                             const Vector<QuatF>&   rotations,
234                             const Vector<U32>&     times,
235                             const Vector<U32>&     smoothingTypes)
236{
237   AssertFatal(mIsServer == true, "PathManager::updatePath: Error, must be called on the server side");
238   AssertFatal(id < mPaths.size(), "PathManager::updatePath: error, id out of range");
239   AssertFatal(positions.size() == times.size() && positions.size() == smoothingTypes.size(), "Error, times and positions must match!");
240
241   PathEntry& rEntry = *mPaths[id];
242
243   rEntry.positions = positions;
244   rEntry.rotations = rotations;
245   rEntry.msToNext  = times;
246   rEntry.smoothingType = smoothingTypes;
247
248   rEntry.totalTime = 0;
249   for (S32 i = 0; i < S32(rEntry.msToNext.size()); i++)
250      rEntry.totalTime += rEntry.msToNext[i];
251
252   transmitPath(id);
253}
254
255
256//--------------------------------------------------------------------------
257void PathManager::transmitPaths(NetConnection* nc)
258{
259   AssertFatal(mIsServer, "Error, cannot call transmitPaths on client path manager!");
260
261   // Send over paths
262   for(S32 i = 0; i < mPaths.size(); i++)
263   {
264      PathManagerEvent* event = new PathManagerEvent;
265      event->clearPaths       = (i == 0);
266      event->modifiedPath = i;
267      event->path = *(mPaths[i]);
268      nc->postNetEvent(event);
269   }
270}
271
272void PathManager::transmitPath(const U32 id)
273{
274   AssertFatal(mIsServer, "Error, cannot call transmitNewPath on client path manager!");
275
276   // Post to all active clients that have already received their paths...
277   //
278   SimGroup* pClientGroup = Sim::getClientGroup();
279   for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++) {
280      NetConnection* nc = dynamic_cast<NetConnection*>(*itr);
281      if (nc && nc->missionPathsSent())
282      {
283         // Transmit the updated path...
284         PathManagerEvent* event = new PathManagerEvent;
285         event->modifiedPath     = id;
286         event->clearPaths       = false;
287         event->path             = *(mPaths[id]);
288         nc->postNetEvent(event);
289      }
290   }
291}
292
293void PathManager::getPathPosition(const U32 id,
294                                  const F64 msPosition,
295                                  Point3F&  rPosition,
296                                  QuatF &rotation)
297{
298   AssertFatal(isValidPath(id), "Error, this is not a valid path!");
299   PROFILE_START(PathManGetPos);
300
301   // Ok, query holds our path information...
302   F64 ms = msPosition;
303   if (ms > mPaths[id]->totalTime)
304      ms = mPaths[id]->totalTime;
305
306   S32 startNode = 0;
307   while (ms > mPaths[id]->msToNext[startNode]) {
308      ms -= mPaths[id]->msToNext[startNode];
309      startNode++;
310   }
311   S32 endNode = (startNode + 1) % mPaths[id]->positions.size();
312
313   Point3F& rStart = mPaths[id]->positions[startNode];
314   Point3F& rEnd   = mPaths[id]->positions[endNode];
315
316   F64 interp = ms / F32(mPaths[id]->msToNext[startNode]);
317   if(mPaths[id]->smoothingType[startNode] == Marker::SmoothingTypeLinear)
318   {
319      rPosition = (rStart * (1.0 - interp)) + (rEnd * interp);
320   }
321   else if(mPaths[id]->smoothingType[startNode] == Marker::SmoothingTypeAccelerate)
322   {
323      interp = mSin(interp * M_PI - (M_PI / 2)) * 0.5 + 0.5;
324      rPosition = (rStart * (1.0 - interp)) + (rEnd * interp);
325   }
326   else if(mPaths[id]->smoothingType[startNode] == Marker::SmoothingTypeSpline)
327   {
328      S32 preStart = startNode - 1;
329      S32 postEnd = endNode + 1;
330      if(postEnd >= mPaths[id]->positions.size())
331         postEnd = 0;
332      if(preStart < 0)
333         preStart = mPaths[id]->positions.size() - 1;
334      Point3F p0 = mPaths[id]->positions[preStart];
335      Point3F p1 = rStart;
336      Point3F p2 = rEnd;
337      Point3F p3 = mPaths[id]->positions[postEnd];
338      rPosition.x = mCatmullrom(interp, p0.x, p1.x, p2.x, p3.x);
339      rPosition.y = mCatmullrom(interp, p0.y, p1.y, p2.y, p3.y);
340      rPosition.z = mCatmullrom(interp, p0.z, p1.z, p2.z, p3.z);
341   }
342   rotation.interpolate( mPaths[id]->rotations[startNode], mPaths[id]->rotations[endNode], interp );
343   PROFILE_END();
344}
345
346U32 PathManager::getPathTotalTime(const U32 id) const
347{
348   AssertFatal(isValidPath(id), "Error, this is not a valid path!");
349
350   return mPaths[id]->totalTime;
351}
352
353U32 PathManager::getPathNumWaypoints(const U32 id) const
354{
355   AssertFatal(isValidPath(id), "Error, this is not a valid path!");
356
357   return mPaths[id]->positions.size();
358}
359
360U32 PathManager::getWaypointTime(const U32 id, const U32 wayPoint) const
361{
362   AssertFatal(isValidPath(id), "Error, this is not a valid path!");
363   AssertFatal(wayPoint < getPathNumWaypoints(id), "Invalid waypoint!");
364
365   U32 time = 0;
366   for (U32 i = 0; i < wayPoint; i++)
367      time += mPaths[id]->msToNext[i];
368
369   return time;
370}
371
372U32 PathManager::getPathTimeBits(const U32 id)
373{
374   AssertFatal(isValidPath(id), "Error, this is not a valid path!");
375
376   return countNumBits(mPaths[id]->totalTime);
377}
378
379U32 PathManager::getPathWaypointBits(const U32 id)
380{
381   AssertFatal(isValidPath(id), "Error, this is not a valid path!");
382
383   return countNumBits(mPaths[id]->positions.size());
384}
385
386
387bool PathManager::dumpState(BitStream* stream) const
388{
389   stream->write(mPaths.size());
390
391   for (U32 i = 0; i < mPaths.size(); i++) {
392      const PathEntry& rEntry = *mPaths[i];
393      stream->write(rEntry.totalTime);
394
395      stream->write(rEntry.positions.size());
396      for (U32 j = 0; j < rEntry.positions.size(); j++) {
397         mathWrite(*stream, rEntry.positions[j]);
398         stream->write(rEntry.msToNext[j]);
399      }
400   }
401
402   return stream->getStatus() == Stream::Ok;
403}
404
405bool PathManager::readState(BitStream* stream)
406{
407   U32 i;
408   for (i = 0; i < mPaths.size(); i++)
409      delete mPaths[i];
410
411   U32 numPaths;
412   stream->read(&numPaths);
413   mPaths.setSize(numPaths);
414
415   for (i = 0; i < mPaths.size(); i++) {
416      mPaths[i] = new PathEntry;
417      PathEntry& rEntry = *mPaths[i];
418
419      stream->read(&rEntry.totalTime);
420
421      U32 numPositions;
422      stream->read(&numPositions);
423      rEntry.positions.setSize(numPositions);
424      rEntry.msToNext.setSize(numPositions);
425      for (U32 j = 0; j < rEntry.positions.size(); j++) {
426         mathRead(*stream, &rEntry.positions[j]);
427         stream->read(&rEntry.msToNext[j]);
428      }
429   }
430
431   return stream->getStatus() == Stream::Ok;
432}
433
434
435
436