299 lines
8.2 KiB
C++
299 lines
8.2 KiB
C++
//
|
|
// sample_datasync/app.h
|
|
//
|
|
// Copyright (C) 1999-2008 Rockstar Games. All Rights Reserved.
|
|
//
|
|
|
|
#ifndef SAMPLE_DATASYNC_APP_H
|
|
#define SAMPLE_DATASYNC_APP_H
|
|
|
|
#include "datasync/synchobject.h"
|
|
#include "datasync/synchmsg.h"
|
|
#include "datasync/netpresent.h"
|
|
#include "net/timesync.h"
|
|
#include "sample_snet/app.h"
|
|
#include "vector/vector3.h"
|
|
|
|
namespace rage
|
|
{
|
|
class bkBank;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// TemplateNetSyncObject - THIS BASE CLASS IS GENERICALLY USEFUL
|
|
template <typename T> class TemplateNetSyncObject : public rage::NSOObjectBase //Currently all objects derive from NSOObjectBase, an empty class with a virtual interface. This can be designed out if needed.
|
|
{
|
|
public:
|
|
virtual rage::NSOType *GetNSOType() const
|
|
{
|
|
return &sm_AutoSyncData;
|
|
}
|
|
|
|
TemplateNetSyncObject() : m_ObjectId(0) { }
|
|
|
|
TemplateNetSyncObject(int objectid) : m_ObjectId(objectid) { }
|
|
#if __BANK
|
|
static void AddWidgets(rage::bkBank &bk) { sm_AutoSyncData.AddWidgets(bk); }
|
|
#endif
|
|
|
|
static rage::NSOInstance* CreateTransmitter(T& rObj, u64 iRemoteTarget)
|
|
{
|
|
return rage::NSOInstance::CreateTransmitter(*rObj.GetNSOType(), rObj, iRemoteTarget);
|
|
}
|
|
|
|
static rage::NSOInstance* CreateReceiver(T& obj)
|
|
{
|
|
return rage::NSOInstance::CreateReceiver(*obj.GetNSOType(), obj);
|
|
}
|
|
|
|
int m_ObjectId;
|
|
|
|
protected:
|
|
static rage::NSOType sm_AutoSyncData;
|
|
static T &sm_OffsetFromZero;
|
|
};
|
|
// TemplateNetSyncObject
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GenericTransportableNSDMsg - this is where the SNU interface would live
|
|
class GenericTransportableNSDMsg : public NetSyncDataMsg
|
|
{
|
|
public:
|
|
struct NetSessionTransport
|
|
{
|
|
NetSessionTransport() : mp_Cxn(0), mp_PeerMgr(0)
|
|
{
|
|
|
|
}
|
|
NetSessionTransport(rage::netConnectionManager &cxn, rage::PeerManager &pmgr) : mp_Cxn(&cxn), mp_PeerMgr(&pmgr)
|
|
{
|
|
|
|
}
|
|
rage::netConnectionManager* mp_Cxn;
|
|
rage::PeerManager* mp_PeerMgr;
|
|
};
|
|
|
|
NetSessionTransport m_Transport;
|
|
int m_CxnId;
|
|
|
|
GenericTransportableNSDMsg(): m_CxnId(0)
|
|
{}
|
|
|
|
GenericTransportableNSDMsg(NetSessionTransport trans, int cxnId, u32 iObjectId, float fNetTime): NetSyncDataMsg(iObjectId, fNetTime)
|
|
, m_Transport(trans)
|
|
, m_CxnId(cxnId)
|
|
{
|
|
|
|
}
|
|
|
|
template<typename T>
|
|
bool SendToCxn( const int cxnId,
|
|
const T& msg,
|
|
const unsigned flags,
|
|
rage::netSequence* frameSeq = 0 )
|
|
{
|
|
if( AssertVerify( cxnId >= 0 ) )
|
|
{
|
|
if (m_Transport.mp_Cxn->IsOpen(cxnId) || m_Transport.mp_Cxn->IsPendingOpen(cxnId))
|
|
{
|
|
return m_Transport.mp_Cxn->Send( cxnId, msg, flags, frameSeq ); // can't put this in a base class because the "this" is a template of the type passed in, could have msg as a param
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template<typename T>
|
|
bool SendToAllPeers(
|
|
const T& msg,
|
|
const unsigned flags,
|
|
rage::netSequence* frameSeq = 0 )
|
|
{
|
|
// just send to all other peers for now
|
|
bool b = false;
|
|
Peer* peers[PeerManager::MAX_PEERS];
|
|
const unsigned numPeers = m_Transport.mp_PeerMgr->GetPeers(peers, COUNTOF(peers));
|
|
for(unsigned i = 0; i < numPeers; ++i)
|
|
{
|
|
if(!peers[i]->IsLocal())
|
|
{
|
|
b |= SendToCxn( peers[i]->GetCxnId(), msg, flags, frameSeq );
|
|
}
|
|
}
|
|
return b;
|
|
}
|
|
};
|
|
// GenericTransportableNSDMsg
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SampleNetSyncObject - Primary sync-able object for this tester
|
|
class SampleNetSyncObject : public TemplateNetSyncObject<SampleNetSyncObject>
|
|
{
|
|
public:
|
|
rage::Vector3 m_vPos;
|
|
Color32 m_cColor;
|
|
|
|
SampleNetSyncObject()
|
|
:m_vPos(rage::Vector3::ZeroType)
|
|
{
|
|
m_cColor.Set(0);
|
|
}
|
|
|
|
SampleNetSyncObject(rage::u32 objectid, float x, float y, float z)
|
|
: TemplateNetSyncObject<SampleNetSyncObject>(objectid)
|
|
, m_vPos(x,y,z)
|
|
, m_cColor(0)
|
|
{
|
|
}
|
|
|
|
//sm_AutoSyncData holds information for synchronising the NetGOHActor class. It also provided us with an API to create and destroy per client view data.
|
|
//When we create views we need to create an NSOInstance to go with this type. Also each remote object is currently required to have an NSOInstance to receive data.
|
|
static void CreateAutoSyncData()
|
|
{
|
|
//The NetPresenter is an object used to gather information about the data structure. It has a load of
|
|
//helper functions wrapping templated functionality in NSEPresenter to simplify common rules.
|
|
rage::NetPresenter presenter;
|
|
|
|
//Groups are handy for visualisation and stats tracking. They also add a guard flag to the data.
|
|
//If nothing in the group or its children gets serialized then the flag isn't set and the section
|
|
//is skipped. We'll see a variation on the theme a little later.
|
|
if (presenter.StartGroup("ContainedData"))
|
|
{
|
|
//We store data as offsets from 0 so we can reapply to different instances of the class
|
|
presenter.HeartbeatAndChange("AnyChangeVector3", sm_OffsetFromZero.m_vPos, 10.0f);
|
|
presenter.OnChange("AnyChangeColor32", *(int*)(void*)&sm_OffsetFromZero.m_cColor);
|
|
//All StartGroup calls require an EndGroup.
|
|
presenter.EndGroup();
|
|
}
|
|
|
|
//Now we give the data to the NSOType. This is used later to create instance data (NSOInstance) for each view)
|
|
sm_AutoSyncData.SetupFromPresenter(presenter);
|
|
}
|
|
};
|
|
|
|
// SampleNetSyncObject
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SampleAppDataSyncMsg - message for syncing NSOInstances (using a globally unique net_id system - (only rudimentarily supplied)
|
|
class SampleAppDataSyncMsg : public GenericTransportableNSDMsg
|
|
{
|
|
NSOInstance *OnGetReciever(u32 net_id) const;
|
|
|
|
public:
|
|
virtual void OnSendMsg()
|
|
{
|
|
SendToCxn( m_CxnId, *this, 0); //TMS: This used to be reliable or not but these days we handle that under the hood
|
|
}
|
|
|
|
|
|
SampleAppDataSyncMsg() {}
|
|
SampleAppDataSyncMsg(NetSessionTransport trans, int cxnId, u32 iObjectId, float fNetTime)
|
|
: GenericTransportableNSDMsg(trans, cxnId, iObjectId, fNetTime)
|
|
{}
|
|
NET_MESSAGE_DECL( SampleAppDataSyncMsg );
|
|
NET_MESSAGE_SER( bb, msg )
|
|
{
|
|
return NetSyncDataMsg::SerMsgPayload( bb, msg );
|
|
}
|
|
};
|
|
// SampleAppDataSyncMsg
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// main tester plugin
|
|
class SampleApp3dWorld {
|
|
public:
|
|
|
|
SampleApp3dWorld();
|
|
|
|
static SampleSessionPlugin sm_Plugin;
|
|
static SampleApp3dWorld* sm_Instance;
|
|
|
|
enum Channels
|
|
{
|
|
TIME_SYNC_CHANNEL_ID = 0,
|
|
};
|
|
|
|
struct nsoinst_node
|
|
{
|
|
nsoinst_node() : mp_Data(NULL), mp_Next(NULL), m_CxnId(0)
|
|
{
|
|
}
|
|
|
|
int m_CxnId;
|
|
SampleNetSyncObject* mp_Object;
|
|
NSOInstance* mp_Data;
|
|
nsoinst_node* mp_Next;
|
|
};
|
|
|
|
void AddRemoteViewOfLocalAvatar(int cxnid);
|
|
nsoinst_node* GetRemoteObject(int net_id); // will create if not found
|
|
|
|
#if __BANK
|
|
void AddWidgets();
|
|
#endif
|
|
void UpdateTimeSync(LiveManager *livemgr);
|
|
void JoinedSession(snSession *session);
|
|
void AddRemoteViewOfWorld(int cxnId);
|
|
bool HandleMessages(unsigned msgId, const netEventFrameReceived* fr);
|
|
void AddGamer(Gamer *gamer);
|
|
|
|
void Update(LiveManager *livemgr, PeerManager &peermgr); // top level update function
|
|
void UpdateObjects();
|
|
void UpdateNet(netConnectionManager &rMgr, PeerManager &rPeerMgr);
|
|
void Draw();
|
|
void Disconnect();
|
|
|
|
// sample_session plugin delegates
|
|
static void PluginUpdate(LiveManager *livemgr, PeerManager &peermgr)
|
|
{
|
|
sm_Instance->Update(livemgr, peermgr);
|
|
}
|
|
|
|
static void PluginDraw()
|
|
{
|
|
sm_Instance->Draw();
|
|
}
|
|
|
|
static void PluginJoinedSession(snSession *session)
|
|
{
|
|
sm_Instance->JoinedSession(session);
|
|
}
|
|
|
|
static bool PluginHandleMessages(unsigned msgId, const netEventFrameReceived* fr)
|
|
{
|
|
return sm_Instance->HandleMessages(msgId, fr);
|
|
}
|
|
|
|
static void PluginAddGamer(Gamer *gamer)
|
|
{
|
|
sm_Instance->AddGamer(gamer);
|
|
}
|
|
|
|
static void PluginInit()
|
|
{
|
|
sm_Instance = rage_new SampleApp3dWorld;
|
|
}
|
|
|
|
protected:
|
|
|
|
enum {
|
|
MIN_X=-5, MAX_X=5,
|
|
MIN_Y=-5, MAX_Y=5,
|
|
MIN_Z=-5, MAX_Z=5,
|
|
NUM_WORLD_OBJECTS = (MAX_X-MIN_X)*(MAX_Y-MIN_Y)*(MAX_Z-MIN_Z)
|
|
};
|
|
|
|
SampleNetSyncObject* mp_LocalAvatar;
|
|
unsigned m_LastTime;
|
|
rage::netTimeSync* m_TimeSync;
|
|
nsoinst_node* m_RemoteViewsOfLocalObjects;
|
|
nsoinst_node* m_RemoteObjects;
|
|
bool m_UseLocalWorldObjects;
|
|
SampleNetSyncObject m_LocalWorldObjects[NUM_WORLD_OBJECTS];
|
|
};
|
|
|
|
|
|
#endif // SAMPLE_DATASYNC_APP_H
|