📄 ghostconnection.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "core/dnet.h"
#include "console/simBase.h"
#include "core/bitStream.h"
#include "sim/netObject.h"
#include "core/resManager.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "server/conn/GhostConnection.h"
//namespace CS
//{
#define DebugChecksum 0xF00DBAAD
extern U32 gGhostUpdates;
GhostConnection::GhostConnection()
{
// ghost management data:
mScopeObject = NULL;
mGhostingSequence = 0;
mGhosting = false;
mScoping = false;
mGhostArray = NULL;
mGhostRefs = NULL;
mGhostLookupTable = NULL;
mLocalGhosts = NULL;
mGhostsActive = 0;
}
GhostConnection::~GhostConnection()
{
delete[] mLocalGhosts;
delete[] mGhostLookupTable;
delete[] mGhostRefs;
delete[] mGhostArray;
}
///////////////////////////////////////////////////////////////////////////////
//GhostAlwaysObjectEvent
class GhostAlwaysObjectEvent : public NetEvent
{
SimObjectId objectId;
U32 ghostIndex;
NetObject *object;
bool validObject;
public:
GhostAlwaysObjectEvent(NetObject *obj = NULL, U32 index = 0)
{
if(obj)
{
objectId = obj->getId();
ghostIndex = index;
}
object = NULL;
}
~GhostAlwaysObjectEvent()
{ delete object; }
void pack(NetConnection *ps, BitStream *bstream)
{
bstream->writeInt(ghostIndex, GhostConnection::GhostIdBitSize);
NetObject *obj = (NetObject *) Sim::findObject(objectId);
if(bstream->writeFlag(obj != NULL))
{
S32 classId = obj->getClassId(ps->getNetClassGroup());
bstream->writeClassId(classId, NetClassTypeObject, ps->getNetClassGroup());
obj->packUpdate(ps, 0xFFFFFFFF, bstream);
}
}
void write(NetConnection *ps, BitStream *bstream)
{
bstream->writeInt(ghostIndex, GhostConnection::GhostIdBitSize);
if(bstream->writeFlag(validObject))
{
S32 classId = object->getClassId(ps->getNetClassGroup());
bstream->writeClassId(classId, NetClassTypeObject, ps->getNetClassGroup());
object->packUpdate(ps, 0xFFFFFFFF, bstream);
}
}
void unpack(NetConnection *ps, BitStream *bstream)
{
ghostIndex = bstream->readInt(GhostConnection::GhostIdBitSize);
if(bstream->readFlag())
{
S32 classId = bstream->readClassId(NetClassTypeObject, ps->getNetClassGroup());
if(classId == -1)
{
ps->setLastError("Invalid packet.");
return;
}
object = (NetObject *) ConsoleObject::create(ps->getNetClassGroup(), NetClassTypeObject, classId);
if(!object)
{
ps->setLastError("Invalid packet.");
return;
}
object->mNetFlags = NetObject::IsGhost;
object->mNetIndex = ghostIndex;
object->unpackUpdate(ps, bstream);
validObject = true;
}
else
{
object = new NetObject;
validObject = false;
}
}
void process(NetConnection *ps)
{
Con::executef(1, "onGhostAlwaysObjectReceived");
GhostConnection* gc = static_cast<GhostConnection*> (ps);
if(gc)
gc->setGhostAlwaysObject(object, ghostIndex);
object = NULL;
}
DECLARE_CONOBJECT(GhostAlwaysObjectEvent);
};
IMPLEMENT_CO_NETEVENT_V1(GhostAlwaysObjectEvent);
ConsoleMethod( GhostConnection, getGhostsActive, S32, 2, 2, "()"
"Returns number of ghosts active.")
{
return object->getGhostsActive();
}
void GhostConnection::setGhostTo(bool ghostTo)
{
if(mLocalGhosts) // if ghosting to this is already enabled, silently return
return;
if(ghostTo)
{
mLocalGhosts = new NetObject *[MaxGhostCount];
for(S32 i = 0; i < MaxGhostCount; i++)
mLocalGhosts[i] = NULL;
}
}
void GhostConnection::setGhostFrom(bool ghostFrom)
{
if(mGhostArray)
return;
if(ghostFrom)
{
mGhostFreeIndex = mGhostZeroUpdateIndex = 0;
mGhostArray = new GhostInfo *[MaxGhostCount];
mGhostRefs = new GhostInfo[MaxGhostCount];
S32 i;
for(i = 0; i < MaxGhostCount; i++)
{
mGhostRefs[i].obj = NULL;
mGhostRefs[i].index = i;
mGhostRefs[i].updateMask = 0;
}
mGhostLookupTable = new GhostInfo *[GhostLookupTableSize];
for(i = 0; i < GhostLookupTableSize; i++)
mGhostLookupTable[i] = 0;
}
}
void GhostConnection::onRemove()
{
ghostOnRemove();
Parent::onRemove();
}
void GhostConnection::ghostOnRemove()
{
if(mGhostArray)
clearGhostInfo();
}
void GhostConnection::ghostPacketDropped(PacketNotify *notify)
{
GhostRef *packRef = notify->ghostList;
// loop through all the packRefs in the packet
while(packRef)
{
GhostRef *temp = packRef->nextRef;
U32 orFlags = 0;
AssertFatal(packRef->nextUpdateChain == NULL, "Out of order notify!!");
// clear out the ref for this object, plus or together all
// flags from updates after this
GhostRef **walk = &(packRef->ghost->updateChain);
while(*walk != packRef)
{
orFlags |= (*walk)->mask;
walk = &((*walk)->nextUpdateChain);
}
*walk = 0;
// for any flags we haven't updated since this (dropped) packet
// or them into the mask so they'll get updated soon
orFlags = packRef->mask & ~orFlags;
if(orFlags)
{
if(!packRef->ghost->updateMask)
{
packRef->ghost->updateMask = orFlags;
ghostPushNonZero(packRef->ghost);
}
else
packRef->ghost->updateMask |= orFlags;
}
// if this packet was ghosting an object, set it
// to re ghost at it's earliest convenience
if(packRef->ghostInfoFlags & GhostInfo::Ghosting)
{
packRef->ghost->flags |= GhostInfo::NotYetGhosted;
packRef->ghost->flags &= ~GhostInfo::Ghosting;
}
// otherwise, if it was being deleted,
// set it to re-delete
else if(packRef->ghostInfoFlags & GhostInfo::KillingGhost)
{
packRef->ghost->flags |= GhostInfo::KillGhost;
packRef->ghost->flags &= ~GhostInfo::KillingGhost;
}
delete packRef;
packRef = temp;
}
}
bool GhostConnection::readDemoStartBlock(BitStream* stream)
{
ghostReadStartBlock(stream);
return Parent::readDemoStartBlock(stream);
}
void GhostConnection::writeDemoStartBlock(ResizeBitStream* stream)
{
ghostWriteStartBlock(stream);
Parent::writeDemoStartBlock(stream);
}
void GhostConnection::readPacket(BitStream *bstream)
{
ghostReadPacket(bstream);
Parent::readPacket(bstream);
}
void GhostConnection::writePacket(BitStream *bstream, PacketNotify *note)
{
ghostWritePacket(bstream, note);
Parent::writePacket(bstream, note);
}
void GhostConnection::packetReceived(PacketNotify *note)
{
ghostPacketReceived(note);
Parent::packetReceived(note);
}
void GhostConnection::packetDropped(PacketNotify *note)
{
ghostPacketDropped(note);
Parent::packetDropped(note);
}
void GhostConnection::ghostPacketReceived(PacketNotify *notify)
{
GhostRef *packRef = notify->ghostList;
// loop through all the notifies in this packet
while(packRef)
{
GhostRef *temp = packRef->nextRef;
AssertFatal(packRef->nextUpdateChain == NULL, "Out of order notify!!");
// clear this notify from the end of the object's notify
// chain
GhostRef **walk = &(packRef->ghost->updateChain);
while(*walk != packRef)
walk = &((*walk)->nextUpdateChain);
*walk = 0;
// if this object was ghosting , it is now ghosted
if(packRef->ghostInfoFlags & GhostInfo::Ghosting)
packRef->ghost->flags &= ~GhostInfo::Ghosting;
// otherwise, if it was dieing, free the ghost
else if(packRef->ghostInfoFlags & GhostInfo::KillingGhost)
freeGhostInfo(packRef->ghost);
delete packRef;
packRef = temp;
}
}
struct UpdateQueueEntry
{
F32 priority;
GhostInfo *obj;
UpdateQueueEntry(F32 in_priority, GhostInfo *in_obj)
{ priority = in_priority; obj = in_obj; }
};
static S32 QSORT_CALLBACK UQECompare(const void *a,const void *b)
{
GhostInfo *ga = *((GhostInfo **) a);
GhostInfo *gb = *((GhostInfo **) b);
F32 ret = ga->priority - gb->priority;
return (ret < 0) ? -1 : ((ret > 0) ? 1 : 0);
}
void GhostConnection::ghostWritePacket(BitStream *bstream, PacketNotify *notify)
{
#ifdef TORQUE_DEBUG_NET
bstream->writeInt(DebugChecksum, 32);
#endif
notify->ghostList = NULL;
if(!isGhostingFrom())
return;
if(!bstream->writeFlag(mGhosting))
return;
// fill a packet (or two) with ghosting data
// first step is to check all our polled ghosts:
// 1. Scope query - find if any new objects have come into
// scope and if any have gone out.
// 2. call scoped objects' priority functions if the flag set is nonzero
// A removed ghost is assumed to have a high priority
// 3. call updates based on sorted priority until the packet is
// full. set flags to zero for all updated objects
CameraScopeQuery camInfo;
camInfo.camera = NULL;
camInfo.pos.set(0,0,0);
camInfo.orientation.set(0,1,0);
camInfo.visibleDistance = 1;
camInfo.fov = (F32)(3.1415f / 4.0f);
camInfo.sinFov = 0.7071f;
camInfo.cosFov = 0.7071f;
GhostInfo *walk;
// only need to worry about the ghosts that have update masks set...
S32 maxIndex = 0;
S32 i;
for(i = 0; i < mGhostZeroUpdateIndex; i++)
{
// increment the updateSkip for everyone... it's all good
walk = mGhostArray[i];
walk->updateSkipCount++;
if(!(walk->flags & (GhostInfo::ScopeAlways | GhostInfo::ScopeLocalAlways)))
walk->flags &= ~GhostInfo::InScope;
}
//#ifdef _RPG_NOCOMMENT
if(mScopeObject)
mScopeObject->onCameraScopeQuery(this, &camInfo);
//#endif
for(i = mGhostZeroUpdateIndex - 1; i >= 0; i--)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -