504 lines
14 KiB
C++
504 lines
14 KiB
C++
//
|
|
// sample_datasync/app.h
|
|
//
|
|
// Copyright (C) 1999-2008 Rockstar Games. All Rights Reserved.
|
|
//
|
|
|
|
#include "app.h"
|
|
|
|
#include "bank/bkmgr.h"
|
|
#include "devcam/polarcam.h"
|
|
#include "datasync/synchmsg.h"
|
|
#include "devcam/polarcam.h"
|
|
#include "grcore/im.h"
|
|
#include "grcore/viewport.h"
|
|
#include "net/timesync.h"
|
|
#include "input/pad.h"
|
|
#include "system/timer.h"
|
|
|
|
#include "sample_snet/livemanager.h"
|
|
#include "sample_snet/peermanager.h"
|
|
|
|
#define BROADCAST_WORLD 1 // otherwise, simulate the world locally
|
|
|
|
namespace
|
|
{
|
|
dcamPolarCam g_PolarCam;
|
|
float g_ForceFalloff = 1.0f;
|
|
float g_ForceScale = 2.0f;
|
|
float g_WorldCubeScale = 0.95f;
|
|
float g_CamZoomSpeed = 2.0f;
|
|
float g_ObjectSpeed = 5.0f;
|
|
float g_WorldSphereSize = 0.5f;
|
|
int g_WorldSphereNumFaces = 4;
|
|
bool g_Lock2dPlane = true;
|
|
|
|
// bool g_JustJoined = false;
|
|
|
|
PeerManager *s_PeerManager = NULL;
|
|
|
|
static Vector3 calcforce(Vector3::Vector3Param attractor, Vector3::Vector3Param point)
|
|
{
|
|
Vector3 dif;
|
|
dif.Subtract(attractor,point);
|
|
float mag = dif.Mag();
|
|
dif.Normalize();
|
|
if(mag > g_ForceFalloff)
|
|
{
|
|
mag -= square(((mag-g_ForceFalloff)/g_ForceScale));
|
|
mag = Max(mag,0.0f);
|
|
}
|
|
dif.Scale(mag);
|
|
return dif;
|
|
}
|
|
|
|
static float deadzone(float val)
|
|
{
|
|
const float DEAD = 0.2f;
|
|
const float factor = 1.0f / (1.0f-DEAD);
|
|
|
|
float neg = val<0.0f?-1.0f:1.0f;
|
|
val = Max((fabsf(val)-DEAD)*factor,0.0f) * neg;
|
|
return val;
|
|
}
|
|
|
|
}
|
|
|
|
using namespace rage;
|
|
|
|
// statics
|
|
template<typename T> rage::NSOType TemplateNetSyncObject<T>::sm_AutoSyncData;
|
|
template<typename T> T& TemplateNetSyncObject<T>::sm_OffsetFromZero = *(T*)0;
|
|
|
|
NSOInstance *SampleAppDataSyncMsg::OnGetReciever(u32 net_id) const
|
|
{
|
|
SampleApp3dWorld::nsoinst_node* pNode = SampleApp3dWorld::sm_Instance->GetRemoteObject(net_id);
|
|
if(pNode)
|
|
return pNode->mp_Data;
|
|
return NULL;
|
|
}
|
|
|
|
NET_MESSAGE_IMPL( SampleAppDataSyncMsg );
|
|
//NET_MESSAGE_IMPL( NetSyncDataMsg );
|
|
|
|
void SampleApp3dWorld::AddRemoteViewOfLocalAvatar(int cxnid)
|
|
{
|
|
SampleNetSyncObject &rObj = *mp_LocalAvatar;
|
|
// check for dups
|
|
for(nsoinst_node* node=m_RemoteViewsOfLocalObjects;node;node=node->mp_Next)
|
|
{
|
|
if(node->mp_Object==mp_LocalAvatar && node->m_CxnId==cxnid)
|
|
return;
|
|
}
|
|
|
|
// u64 peerId = 0;
|
|
// Peer* peers[PeerManager::MAX_PEERS];
|
|
// const unsigned numPeers = s_PeerManager->GetPeers(peers, COUNTOF(peers));
|
|
// for(unsigned i=0;i<numPeers;i++)
|
|
// {
|
|
// if( peers[i]->GetCxnId() == cxnid )
|
|
// {
|
|
// peerId = peers[i]->g;
|
|
// }
|
|
// }
|
|
|
|
nsoinst_node *tmp = m_RemoteViewsOfLocalObjects;
|
|
m_RemoteViewsOfLocalObjects = rage_new nsoinst_node;
|
|
m_RemoteViewsOfLocalObjects->mp_Data = SampleNetSyncObject::CreateTransmitter(rObj, 0 /*not used??*/);
|
|
m_RemoteViewsOfLocalObjects->m_CxnId = cxnid;
|
|
m_RemoteViewsOfLocalObjects->mp_Object = mp_LocalAvatar;
|
|
m_RemoteViewsOfLocalObjects->mp_Next = tmp;
|
|
}
|
|
|
|
void SampleApp3dWorld::Disconnect()
|
|
{
|
|
if(!m_RemoteViewsOfLocalObjects && !m_RemoteObjects)
|
|
return;
|
|
|
|
nsoinst_node* o = m_RemoteViewsOfLocalObjects;
|
|
m_RemoteViewsOfLocalObjects = NULL;
|
|
while(o)
|
|
{
|
|
// free mp_Data only for these nodes
|
|
nsoinst_node* tmp = o->mp_Next;
|
|
delete o->mp_Data;
|
|
delete o;
|
|
o = tmp;
|
|
}
|
|
|
|
o = m_RemoteObjects;
|
|
m_RemoteObjects = NULL;
|
|
while(o)
|
|
{
|
|
// free cur->mp_Object && cur->mp_Data
|
|
nsoinst_node* tmp = o->mp_Next;
|
|
delete o->mp_Data;
|
|
delete o->mp_Object;
|
|
delete o;
|
|
o = tmp;
|
|
}
|
|
}
|
|
|
|
SampleApp3dWorld::nsoinst_node* SampleApp3dWorld::GetRemoteObject(int net_id)
|
|
{
|
|
nsoinst_node* cur = m_RemoteObjects;
|
|
|
|
while(cur)
|
|
{
|
|
if(cur->mp_Object->m_ObjectId==net_id)
|
|
return cur;
|
|
cur=cur->mp_Next;
|
|
}
|
|
|
|
cur = rage_new nsoinst_node;
|
|
|
|
cur->m_CxnId = 0; // doesn't matter for remotes
|
|
cur->mp_Object = rage_new SampleNetSyncObject(net_id, 0.0f,0.0f,0.0f);
|
|
cur->mp_Data = SampleNetSyncObject::CreateReceiver(*cur->mp_Object);
|
|
cur->mp_Next = m_RemoteObjects;
|
|
m_RemoteObjects = cur;
|
|
|
|
return cur;
|
|
}
|
|
|
|
void SampleApp3dWorld::UpdateNet(netConnectionManager &rMgr, PeerManager &rPeerMgr)
|
|
{
|
|
float fNetTime = ((float)m_TimeSync->GetTime()) * 0.001f; // rMgr.GetNetTime();
|
|
|
|
static unsigned lastpeercount = 0;
|
|
unsigned peercount = s_PeerManager->GetPeerCount();
|
|
if(peercount != lastpeercount)
|
|
{
|
|
// brute force, add all peers (AddRemoteViewOfLocalAvatar takes care of the duplicates)
|
|
Peer* peers[PeerManager::MAX_PEERS];
|
|
const unsigned numPeers = s_PeerManager->GetPeers(peers, COUNTOF(peers));
|
|
for(unsigned i=0;i<numPeers;i++)
|
|
{
|
|
// g_JustJoined = false; // don't clear this until we've actually got peers
|
|
AddRemoteViewOfLocalAvatar( peers[i]->GetCxnId() ); // add a remote viewer for every connected peer
|
|
}
|
|
}
|
|
|
|
for(nsoinst_node* node=m_RemoteViewsOfLocalObjects;node;node=node->mp_Next)
|
|
{
|
|
node->mp_Data->Update(*node->mp_Object, fNetTime);
|
|
if (node->mp_Data->IsDirty())
|
|
{
|
|
SampleAppDataSyncMsg::NetSessionTransport trans(rMgr, rPeerMgr);
|
|
SampleAppDataSyncMsg syncMsg(trans, node->m_CxnId, node->mp_Object->m_ObjectId, fNetTime);
|
|
syncMsg.SendMessage(*node->mp_Data);
|
|
}
|
|
}
|
|
|
|
|
|
for(nsoinst_node* node=m_RemoteObjects;node;node=node->mp_Next)
|
|
{
|
|
node->mp_Data->Update(*node->mp_Object, fNetTime);
|
|
}
|
|
}
|
|
|
|
void SampleApp3dWorld::UpdateObjects()
|
|
{
|
|
unsigned curTime = sysTimer::GetSystemMsTime();
|
|
unsigned deltaMs = 0;
|
|
|
|
if(m_LastTime)
|
|
{
|
|
deltaMs = curTime - m_LastTime;
|
|
}
|
|
m_LastTime = curTime;
|
|
float deltaSeconds = float(deltaMs)/1000.0f;
|
|
|
|
// polar cam and viewport update
|
|
float azi = deadzone(ioPad::GetPad(0).GetNormRightX()) * deltaSeconds;
|
|
float inc = deadzone(ioPad::GetPad(0).GetNormRightY()) * deltaSeconds;
|
|
float zoomin = (ioPad::GetPad(0).GetButtons()&ioPad::R1)?deltaSeconds*g_CamZoomSpeed:0.0f;
|
|
float zoomout = (ioPad::GetPad(0).GetButtons()&ioPad::L1)?deltaSeconds*g_CamZoomSpeed:0.0f;
|
|
g_PolarCam.SetAzimuth(g_PolarCam.GetAzimuth()+azi);
|
|
g_PolarCam.SetIncline(Wrap(g_PolarCam.GetIncline()-inc,-PI,PI));
|
|
g_PolarCam.SetDistance(g_PolarCam.GetDistance()+zoomin-zoomout);
|
|
#if __CONSOLE
|
|
g_PolarCam.SetEnableInput(false);
|
|
#endif
|
|
g_PolarCam.Update(deltaSeconds);
|
|
Matrix44 world;
|
|
world.FromMatrix34(g_PolarCam.GetWorldMtx());
|
|
grcViewport::GetCurrent()->SetCameraMtx(world, g_PolarCam.GetViewMtx());
|
|
|
|
Vector3 deltapos(0.0f,0.0f,0.0f);
|
|
|
|
if (g_Lock2dPlane) // 2d plane locked
|
|
{
|
|
deltapos.x = deadzone(ioPad::GetPad(0).GetNormLeftX());
|
|
deltapos.z = deadzone(ioPad::GetPad(0).GetNormLeftY());
|
|
if (g_PolarCam.GetIncline()<0.0f) // below the groundplane
|
|
deltapos.z*=-1.0f;
|
|
deltapos.RotateY(g_PolarCam.GetAzimuth());
|
|
}
|
|
else
|
|
{
|
|
deltapos.x = deadzone(ioPad::GetPad(0).GetNormLeftX());
|
|
deltapos.y = -deadzone(ioPad::GetPad(0).GetNormLeftY());
|
|
Vector3 newPos;
|
|
Matrix34 m;
|
|
g_PolarCam.GetViewMtx().ToMatrix34(m);
|
|
m.Inverse();
|
|
m.Transform3x3(deltapos, newPos);
|
|
deltapos = newPos;
|
|
}
|
|
|
|
deltapos.Scale(deltaSeconds*g_ObjectSpeed);
|
|
|
|
mp_LocalAvatar->m_vPos+=deltapos;
|
|
|
|
if(m_UseLocalWorldObjects)
|
|
{
|
|
int numavatars = 1;
|
|
for(nsoinst_node *node = m_RemoteObjects;node;node=node->mp_Next)
|
|
numavatars++;
|
|
|
|
// update these objects if you are the host...
|
|
int curIndex = 0;
|
|
float inv_numavatars = 1.0f / float(numavatars); // multiplier for attraction weight
|
|
for(float i=-5;i<5;i++)
|
|
for(float j=-5;j<5;j++)
|
|
for(float k=-5;k<5;k++)
|
|
{
|
|
Assert(curIndex<NUM_WORLD_OBJECTS);
|
|
Vector3 curpos(i,j,k);
|
|
curpos.Scale(g_WorldCubeScale);
|
|
Vector3 force = calcforce(mp_LocalAvatar->m_vPos, curpos) * inv_numavatars;
|
|
|
|
for(nsoinst_node *node = m_RemoteObjects;node;node=node->mp_Next)
|
|
{
|
|
force += calcforce(node->mp_Object->m_vPos, curpos) * inv_numavatars;
|
|
}
|
|
|
|
curpos += force;
|
|
|
|
float red = (i+5.0f)/10.0f;
|
|
float green = (j+5.0f)/10.0f;
|
|
float blue = (k+5.0f)/10.0f;
|
|
m_LocalWorldObjects[curIndex].m_cColor = Color32(red, green, blue);
|
|
m_LocalWorldObjects[curIndex].m_vPos = curpos;
|
|
m_LocalWorldObjects[curIndex].m_ObjectId = (0xBEEF << 16) | curIndex;
|
|
curIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SampleApp3dWorld::Draw()
|
|
{
|
|
rage::grcColor(Color32(1.0f,1.0f,1.0f));
|
|
rage::grcDrawSphere(0.5f, mp_LocalAvatar->m_vPos, 8, true);
|
|
|
|
for(nsoinst_node *node = m_RemoteObjects;node;node=node->mp_Next)
|
|
{
|
|
if(node->mp_Object->m_cColor==Color32(0))
|
|
{
|
|
// m_cColor 0 is the indicator that its a
|
|
rage::grcColor(Color32(1.0f,1.0f,0.0f));
|
|
rage::grcDrawSphere(0.5f, node->mp_Object->m_vPos, 8, true);
|
|
}
|
|
else
|
|
{
|
|
rage::grcColor(node->mp_Object->m_cColor);
|
|
rage::grcDrawSphere(g_WorldSphereSize, node->mp_Object->m_vPos, g_WorldSphereNumFaces,false,true);
|
|
}
|
|
}
|
|
|
|
if (m_UseLocalWorldObjects)
|
|
{
|
|
for(int i=0;i<NUM_WORLD_OBJECTS;i++)
|
|
{
|
|
rage::grcColor(m_LocalWorldObjects[i].m_cColor);
|
|
rage::grcDrawSphere(g_WorldSphereSize, m_LocalWorldObjects[i].m_vPos, g_WorldSphereNumFaces,false,true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
void SampleApp3dWorld::AddWidgets()
|
|
{
|
|
#if __BANK
|
|
bkBank &bk = BANKMGR.CreateBank("World");
|
|
bk.AddSlider("Force Falloff",&g_ForceFalloff,0.0f,10.0f,0.1f);
|
|
bk.AddSlider("Force Scale",&g_ForceScale,0.0f,10.0f,0.1f);
|
|
bk.AddSlider("Size",&g_WorldCubeScale,0.0f,100.0f,1.0f);
|
|
bk.AddSlider("Cam Zoom Spd", &g_CamZoomSpeed,0.1f,10.0f,1.0f);
|
|
bk.AddToggle("Lock Movement to 2d Plane", &g_Lock2dPlane);
|
|
bk.AddSlider("Object Spd", &g_ObjectSpeed,0.1f,10.0f,1.0f);
|
|
/*bkBank &bk2 = */bk.PushGroup("Sphere Properties");
|
|
bk.AddSlider("Sphere Size", &g_WorldSphereSize, 0.01f, 50.0f, 0.5f);
|
|
bk.AddSlider("Sphere Faces", &g_WorldSphereNumFaces, 4, 12, 1);
|
|
bk.PopGroup();
|
|
|
|
bkBank &bk2 = BANKMGR.CreateBank("Net Objects");
|
|
SampleNetSyncObject::AddWidgets(bk2);
|
|
#endif // __BANK
|
|
}
|
|
#endif
|
|
|
|
bool SampleApp3dWorld::HandleMessages(unsigned msgId, const netEventFrameReceived* fr)
|
|
{
|
|
if(SampleAppDataSyncMsg::MSG_ID() == msgId)
|
|
{
|
|
SampleAppDataSyncMsg msg;
|
|
msg.Import(fr->m_Payload, fr->m_SizeofPayload);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
SampleApp3dWorld::SampleApp3dWorld()
|
|
{
|
|
m_UseLocalWorldObjects = false;
|
|
m_RemoteViewsOfLocalObjects = NULL;
|
|
m_RemoteObjects = NULL;
|
|
mp_LocalAvatar = NULL;
|
|
m_LastTime = 0;
|
|
SampleNetSyncObject::CreateAutoSyncData();
|
|
mp_LocalAvatar = rage_new SampleNetSyncObject(1, 0.0f,0.0f,0.0f); // change this id when we connect
|
|
#if __BANK
|
|
AddWidgets();
|
|
#endif
|
|
g_PolarCam.SetIncline(PI*0.5f);
|
|
g_PolarCam.SetDistance(20.0f);
|
|
grcViewport::SetCurrent(rage_new grcViewport());
|
|
m_TimeSync = rage_new netTimeSync;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------
|
|
//Time
|
|
//------------------------------------------------------------
|
|
void SampleApp3dWorld::UpdateTimeSync(LiveManager *livemgr)
|
|
{
|
|
//TODO: Time synch per session
|
|
if (!livemgr->GetSession()->Exists())
|
|
{
|
|
if (m_TimeSync->HasStarted())
|
|
m_TimeSync->Stop(); //?
|
|
return;
|
|
}
|
|
|
|
//TMS: NEED TO RESTART THE TIME SYNC ON HOST MIGRATION
|
|
//is it time to begin time synchronization?
|
|
if( !m_TimeSync->HasStarted() )
|
|
{
|
|
if( livemgr->GetSession()->IsHost() )
|
|
{
|
|
m_TimeSync->Start(
|
|
livemgr->GetCxnMgr(),
|
|
rage::netTimeSync::FLAG_SERVER,
|
|
NULL, // Hosts manage their own time
|
|
NULL, // MIGRATE TODO: needs a real "initialServerTime"
|
|
TIME_SYNC_CHANNEL_ID,
|
|
netTimeSync::DEFAULT_INITIAL_PING_INTERVAL,
|
|
netTimeSync::DEFAULT_FINAL_PING_INTERVAL
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//if we are in a session and have a host address, request a sync
|
|
if (livemgr->GetSession()->Exists())
|
|
{
|
|
snSession* session = livemgr->GetSession();
|
|
netAddress hostAddr ;
|
|
|
|
if( session && session->Exists() &&
|
|
livemgr->GetSession()->GetHostNetAddress(&hostAddr))
|
|
{
|
|
m_TimeSync->Start(
|
|
livemgr->GetCxnMgr(),
|
|
rage::netTimeSync::FLAG_CLIENT,
|
|
&hostAddr, // For clients the time server address is the host address
|
|
NULL, // MIGRATE TODO: needs a real "initialServerTime"
|
|
TIME_SYNC_CHANNEL_ID,
|
|
netTimeSync::DEFAULT_INITIAL_PING_INTERVAL,
|
|
netTimeSync::DEFAULT_FINAL_PING_INTERVAL
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_TimeSync->Update();
|
|
}
|
|
|
|
}
|
|
|
|
void SampleApp3dWorld::Update(LiveManager *livemgr, PeerManager &peermgr)
|
|
{
|
|
s_PeerManager = &peermgr;
|
|
UpdateTimeSync(livemgr);
|
|
if(!livemgr->GetSession()->Exists())
|
|
{
|
|
Disconnect();
|
|
}
|
|
|
|
UpdateNet(*livemgr->GetCxnMgr(), peermgr);
|
|
UpdateObjects();
|
|
}
|
|
|
|
void SampleApp3dWorld::JoinedSession(snSession *session)
|
|
{
|
|
m_UseLocalWorldObjects=session->IsHost() || !BROADCAST_WORLD;
|
|
if(!session->IsHost())
|
|
{
|
|
// g_JustJoined = true;
|
|
mp_LocalAvatar->m_ObjectId = (int)session->GetLocalPeerId(); // HACK! This may not be unique (although the odds are quite good)
|
|
}
|
|
}
|
|
|
|
void SampleApp3dWorld::AddRemoteViewOfWorld(int cxnId)
|
|
{
|
|
if (BROADCAST_WORLD && m_UseLocalWorldObjects)
|
|
{
|
|
for(int i=0;i<NUM_WORLD_OBJECTS;i++)
|
|
{
|
|
nsoinst_node *tmp = m_RemoteViewsOfLocalObjects;
|
|
m_RemoteViewsOfLocalObjects = rage_new nsoinst_node;
|
|
m_RemoteViewsOfLocalObjects->mp_Data = SampleNetSyncObject::CreateTransmitter(m_LocalWorldObjects[i], 0 /*HACK: peerId not used right now?*/);
|
|
m_RemoteViewsOfLocalObjects->m_CxnId = cxnId;
|
|
m_RemoteViewsOfLocalObjects->mp_Object = &m_LocalWorldObjects[i];
|
|
m_RemoteViewsOfLocalObjects->mp_Next = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SampleApp3dWorld::AddGamer(Gamer *gamer)
|
|
{
|
|
Assert(s_PeerManager);
|
|
|
|
Peer *p = s_PeerManager->GetPeer(gamer->GetPeerInfo().GetPeerId());
|
|
if(p)
|
|
{
|
|
AddRemoteViewOfLocalAvatar(p->GetCxnId());
|
|
AddRemoteViewOfWorld(p->GetCxnId());
|
|
}
|
|
}
|
|
|
|
//SampleApp3dWorld g_world;
|
|
SampleApp3dWorld* SampleApp3dWorld::sm_Instance = NULL; // &g_world;
|
|
SampleSessionPlugin SampleApp3dWorld::sm_Plugin = {
|
|
SampleApp3dWorld::PluginUpdate,
|
|
SampleApp3dWorld::PluginDraw,
|
|
SampleApp3dWorld::PluginJoinedSession,
|
|
SampleApp3dWorld::PluginHandleMessages,
|
|
SampleApp3dWorld::PluginAddGamer,
|
|
SampleApp3dWorld::PluginInit
|
|
};
|
|
|
|
struct Sample3dAppBootstrap
|
|
{
|
|
Sample3dAppBootstrap()
|
|
{
|
|
App::sm_Plugin = SampleApp3dWorld::sm_Plugin;
|
|
}
|
|
} dummy;
|
|
|