mirror of
https://github.com/tribes2/engine.git
synced 2026-01-19 19:24:45 +00:00
407 lines
12 KiB
C++
407 lines
12 KiB
C++
//-----------------------------------------------------------------------------
|
|
// V12 Engine
|
|
//
|
|
// Copyright (c) 2001 GarageGames.Com
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "Sim/pathManager.h"
|
|
#include "Sim/netConnection.h"
|
|
#include "Core/bitStream.h"
|
|
#include "interior/interiorInstance.h"
|
|
#include "Math/mathIO.h"
|
|
|
|
namespace {
|
|
|
|
U32 countNumBits(U32 n)
|
|
{
|
|
U32 count = 0;
|
|
while (n != 0) {
|
|
n >>= 1;
|
|
count++;
|
|
}
|
|
|
|
return count ? count : 1;
|
|
}
|
|
|
|
} // namespace {}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//-------------------------------------- PathManagerEvent
|
|
//
|
|
class PathManagerEvent : public NetEvent
|
|
{
|
|
public:
|
|
enum MessageType {
|
|
NewPaths,
|
|
ModifyPath
|
|
};
|
|
|
|
MessageType message;
|
|
U32 modifiedPath;
|
|
|
|
Vector<PathManager::PathEntry*> mPaths;
|
|
|
|
public:
|
|
PathManagerEvent() {
|
|
VECTOR_SET_ASSOCIATION(mPaths);
|
|
}
|
|
|
|
void pack(NetConnection*, BitStream*);
|
|
void write(NetConnection*, BitStream*);
|
|
void unpack(NetConnection*, BitStream*);
|
|
void process(NetConnection*);
|
|
|
|
DECLARE_CONOBJECT(PathManagerEvent);
|
|
};
|
|
|
|
void PathManagerEvent::pack(NetConnection*, BitStream* stream)
|
|
{
|
|
AssertFatal(mPaths.size() == 0, "Hm, bad");
|
|
|
|
if (stream->writeFlag(message == NewPaths) == true) {
|
|
// Write out all the new paths...
|
|
stream->write(gServerPathManager->mPaths.size());
|
|
for (U32 i = 0; i < gServerPathManager->mPaths.size(); i++) {
|
|
stream->write(gServerPathManager->mPaths[i]->totalTime);
|
|
|
|
stream->write(gServerPathManager->mPaths[i]->positions.size());
|
|
for (U32 j = 0; j < gServerPathManager->mPaths[i]->positions.size(); j++) {
|
|
mathWrite(*stream, gServerPathManager->mPaths[i]->positions[j]);
|
|
stream->write(gServerPathManager->mPaths[i]->msToNext[j]);
|
|
}
|
|
}
|
|
} else {
|
|
// Write out the modified path...
|
|
stream->write(modifiedPath);
|
|
stream->write(gServerPathManager->mPaths[modifiedPath]->totalTime);
|
|
stream->write(gServerPathManager->mPaths[modifiedPath]->positions.size());
|
|
for (U32 j = 0; j < gServerPathManager->mPaths[modifiedPath]->positions.size(); j++) {
|
|
mathWrite(*stream, gServerPathManager->mPaths[modifiedPath]->positions[j]);
|
|
stream->write(gServerPathManager->mPaths[modifiedPath]->msToNext[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PathManagerEvent::write(NetConnection*, BitStream *stream)
|
|
{
|
|
if (stream->writeFlag(message == NewPaths) == true) {
|
|
// Write out all the new paths...
|
|
stream->write(mPaths.size());
|
|
for (U32 i = 0; i < mPaths.size(); i++) {
|
|
stream->write(mPaths[i]->totalTime);
|
|
|
|
stream->write(mPaths[i]->positions.size());
|
|
for (U32 j = 0; j < mPaths[i]->positions.size(); j++) {
|
|
mathWrite(*stream, mPaths[i]->positions[j]);
|
|
stream->write(mPaths[i]->msToNext[j]);
|
|
}
|
|
}
|
|
} else {
|
|
// Write out the modified path...
|
|
stream->write(modifiedPath);
|
|
stream->write(mPaths[0]->totalTime);
|
|
stream->write(mPaths[0]->positions.size());
|
|
for (U32 j = 0; j < mPaths[0]->positions.size(); j++) {
|
|
mathWrite(*stream, mPaths[0]->positions[j]);
|
|
stream->write(mPaths[0]->msToNext[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PathManagerEvent::unpack(NetConnection*, BitStream* stream)
|
|
{
|
|
AssertFatal(mPaths.size() == 0, "Hm, bad");
|
|
|
|
message = stream->readFlag() ? NewPaths : ModifyPath;
|
|
|
|
if (message == NewPaths) {
|
|
// Read in all the paths
|
|
U32 numPaths, i;
|
|
stream->read(&numPaths);
|
|
mPaths.setSize(numPaths);
|
|
for (i = 0; i < mPaths.size(); i++)
|
|
mPaths[i] = new PathManager::PathEntry;
|
|
|
|
for (i = 0; i < mPaths.size(); i++) {
|
|
PathManager::PathEntry& rEntry = *(mPaths[i]);
|
|
|
|
stream->read(&rEntry.totalTime);
|
|
|
|
U32 numPoints;
|
|
stream->read(&numPoints);
|
|
rEntry.positions.setSize(numPoints);
|
|
rEntry.msToNext.setSize(numPoints);
|
|
for (U32 j = 0; j < rEntry.positions.size(); j++) {
|
|
mathRead(*stream, &rEntry.positions[j]);
|
|
stream->read(&rEntry.msToNext[j]);
|
|
}
|
|
}
|
|
} else {
|
|
// Read in the modified path...
|
|
stream->read(&modifiedPath);
|
|
AssertFatal(modifiedPath <= gClientPathManager->mPaths.size(), "Error out of bounds path!");
|
|
|
|
mPaths.push_back(new PathManager::PathEntry);
|
|
PathManager::PathEntry& rEntry = *(mPaths[0]);
|
|
|
|
stream->read(&rEntry.totalTime);
|
|
|
|
U32 numPoints;
|
|
stream->read(&numPoints);
|
|
rEntry.positions.setSize(numPoints);
|
|
rEntry.msToNext.setSize(numPoints);
|
|
for (U32 j = 0; j < rEntry.positions.size(); j++) {
|
|
mathRead(*stream, &rEntry.positions[j]);
|
|
stream->read(&rEntry.msToNext[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PathManagerEvent::process(NetConnection*)
|
|
{
|
|
if (message == NewPaths) {
|
|
// Destroy all previous paths...
|
|
U32 i;
|
|
for (i = 0; i < gClientPathManager->mPaths.size(); i++)
|
|
delete gClientPathManager->mPaths[i];
|
|
|
|
gClientPathManager->mPaths.setSize(mPaths.size());
|
|
for (i = 0; i < mPaths.size(); i++) {
|
|
gClientPathManager->mPaths[i] = mPaths[i];
|
|
mPaths[i] = NULL;
|
|
}
|
|
} else {
|
|
if (modifiedPath == gClientPathManager->mPaths.size()) {
|
|
gClientPathManager->mPaths.push_back(mPaths[0]);
|
|
mPaths[0] = NULL;
|
|
} else {
|
|
delete gClientPathManager->mPaths[modifiedPath];
|
|
gClientPathManager->mPaths[modifiedPath] = mPaths[0];
|
|
mPaths[0] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
IMPLEMENT_CO_NETEVENT_V1(PathManagerEvent);
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//-------------------------------------- PathManager Implementation
|
|
//
|
|
PathManager* gClientPathManager = NULL;
|
|
PathManager* gServerPathManager = NULL;
|
|
|
|
//--------------------------------------------------------------------------
|
|
PathManager::PathManager(const bool isServer)
|
|
{
|
|
VECTOR_SET_ASSOCIATION(mPaths);
|
|
|
|
mIsServer = isServer;
|
|
}
|
|
|
|
PathManager::~PathManager()
|
|
{
|
|
for (U32 i = 0; i < mPaths.size(); i++)
|
|
delete mPaths[i];
|
|
}
|
|
|
|
void PathManager::init()
|
|
{
|
|
AssertFatal(gClientPathManager == NULL && gServerPathManager == NULL, "Error, already initialized the path manager!");
|
|
|
|
gClientPathManager = new PathManager(false);
|
|
gServerPathManager = new PathManager(true);
|
|
}
|
|
|
|
void PathManager::destroy()
|
|
{
|
|
AssertFatal(gClientPathManager != NULL && gServerPathManager != NULL, "Error, path manager not initialized!");
|
|
|
|
delete gClientPathManager;
|
|
gClientPathManager = NULL;
|
|
delete gServerPathManager;
|
|
gServerPathManager = NULL;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
U32 PathManager::allocatePathId()
|
|
{
|
|
mPaths.increment();
|
|
mPaths.last() = new PathEntry;
|
|
|
|
return (mPaths.size() - 1);
|
|
}
|
|
|
|
|
|
void PathManager::updatePath(const U32 id,
|
|
const Vector<Point3F>& positions,
|
|
const Vector<U32>& times)
|
|
{
|
|
AssertFatal(mIsServer == true, "PathManager::updatePath: Error, must be called on the server side");
|
|
AssertFatal(id < mPaths.size(), "PathManager::updatePath: error, id out of range");
|
|
AssertFatal(positions.size() == times.size(), "Error, times and positions must match!");
|
|
|
|
PathEntry& rEntry = *mPaths[id];
|
|
|
|
rEntry.positions = positions;
|
|
rEntry.msToNext = times;
|
|
|
|
rEntry.totalTime = 0;
|
|
for (S32 i = 0; i < S32(rEntry.msToNext.size()) - 1; i++)
|
|
rEntry.totalTime += rEntry.msToNext[i];
|
|
|
|
transmitPath(id);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
void PathManager::transmitPaths(NetConnection* nc)
|
|
{
|
|
AssertFatal(mIsServer, "Error, cannot call transmitPaths on client path manager!");
|
|
|
|
// Send over paths
|
|
PathManagerEvent* event = new PathManagerEvent;
|
|
event->message = PathManagerEvent::NewPaths;
|
|
|
|
nc->postNetEvent(event);
|
|
}
|
|
|
|
void PathManager::transmitPath(const U32 id)
|
|
{
|
|
AssertFatal(mIsServer, "Error, cannot call transmitNewPath on client path manager!");
|
|
|
|
// Post to all active clients that have already received their paths...
|
|
//
|
|
SimGroup* pClientGroup = Sim::getClientGroup();
|
|
for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++) {
|
|
NetConnection* nc = dynamic_cast<NetConnection*>(*itr);
|
|
if (nc && nc->missionPathsSent()) {
|
|
// Transmit the updated path...
|
|
PathManagerEvent* event = new PathManagerEvent;
|
|
event->message = PathManagerEvent::ModifyPath;
|
|
event->modifiedPath = id;
|
|
nc->postNetEvent(event);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PathManager::getPathPosition(const U32 id,
|
|
const U32 msPosition,
|
|
Point3F& rPosition)
|
|
{
|
|
AssertFatal(isValidPath(id), "Error, this is not a valid path!");
|
|
|
|
// Ok, query holds our path information...
|
|
U32 ms = msPosition;
|
|
if (ms > mPaths[id]->totalTime)
|
|
ms = mPaths[id]->totalTime;
|
|
|
|
U32 startNode = 0;
|
|
while (ms > mPaths[id]->msToNext[startNode]) {
|
|
ms -= mPaths[id]->msToNext[startNode];
|
|
startNode++;
|
|
}
|
|
U32 endNode = (startNode + 1) % mPaths[id]->positions.size();
|
|
|
|
Point3F& rStart = mPaths[id]->positions[startNode];
|
|
Point3F& rEnd = mPaths[id]->positions[endNode];
|
|
|
|
F32 interp = F32(ms) / F32(mPaths[id]->msToNext[startNode]);
|
|
|
|
rPosition = (rStart * (1.0 - interp)) + (rEnd * interp);
|
|
}
|
|
|
|
|
|
U32 PathManager::getPathTotalTime(const U32 id) const
|
|
{
|
|
AssertFatal(isValidPath(id), "Error, this is not a valid path!");
|
|
|
|
return mPaths[id]->totalTime;
|
|
}
|
|
|
|
U32 PathManager::getPathNumWaypoints(const U32 id) const
|
|
{
|
|
AssertFatal(isValidPath(id), "Error, this is not a valid path!");
|
|
|
|
return mPaths[id]->positions.size();
|
|
}
|
|
|
|
U32 PathManager::getWaypointTime(const U32 id, const U32 wayPoint) const
|
|
{
|
|
AssertFatal(isValidPath(id), "Error, this is not a valid path!");
|
|
AssertFatal(wayPoint < getPathNumWaypoints(id), "Invalid waypoint!");
|
|
|
|
U32 time = 0;
|
|
for (U32 i = 0; i < wayPoint; i++)
|
|
time += mPaths[id]->msToNext[i];
|
|
|
|
return time;
|
|
}
|
|
|
|
U32 PathManager::getPathTimeBits(const U32 id)
|
|
{
|
|
AssertFatal(isValidPath(id), "Error, this is not a valid path!");
|
|
|
|
return countNumBits(mPaths[id]->totalTime);
|
|
}
|
|
|
|
U32 PathManager::getPathWaypointBits(const U32 id)
|
|
{
|
|
AssertFatal(isValidPath(id), "Error, this is not a valid path!");
|
|
|
|
return countNumBits(mPaths[id]->positions.size());
|
|
}
|
|
|
|
|
|
bool PathManager::dumpState(BitStream* stream) const
|
|
{
|
|
stream->write(mPaths.size());
|
|
|
|
for (U32 i = 0; i < mPaths.size(); i++) {
|
|
const PathEntry& rEntry = *mPaths[i];
|
|
stream->write(rEntry.totalTime);
|
|
|
|
stream->write(rEntry.positions.size());
|
|
for (U32 j = 0; j < rEntry.positions.size(); j++) {
|
|
mathWrite(*stream, rEntry.positions[j]);
|
|
stream->write(rEntry.msToNext[j]);
|
|
}
|
|
}
|
|
|
|
return stream->getStatus() == Stream::Ok;
|
|
}
|
|
|
|
bool PathManager::readState(BitStream* stream)
|
|
{
|
|
U32 i;
|
|
for (i = 0; i < mPaths.size(); i++)
|
|
delete mPaths[i];
|
|
|
|
U32 numPaths;
|
|
stream->read(&numPaths);
|
|
mPaths.setSize(numPaths);
|
|
|
|
for (i = 0; i < mPaths.size(); i++) {
|
|
mPaths[i] = new PathEntry;
|
|
PathEntry& rEntry = *mPaths[i];
|
|
|
|
stream->read(&rEntry.totalTime);
|
|
|
|
U32 numPositions;
|
|
stream->read(&numPositions);
|
|
rEntry.positions.setSize(numPositions);
|
|
rEntry.msToNext.setSize(numPositions);
|
|
for (U32 j = 0; j < rEntry.positions.size(); j++) {
|
|
mathRead(*stream, &rEntry.positions[j]);
|
|
stream->read(&rEntry.msToNext[j]);
|
|
}
|
|
}
|
|
|
|
return stream->getStatus() == Stream::Ok;
|
|
}
|
|
|