Files
GTASource/rage/contrib/samples/sample_datasync/app.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

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;