Redline/source/network_NT.cpp
2016-04-04 17:08:13 +02:00

924 lines
24 KiB
C++

//network.cpp
//basic game hosting/joining and message sending code based on Network_Tool
#include <AmbrosiaTools/network_tool.h>
#include <stdio.h>
#include <string.h>
#include "gametime.h"
#include "config.h"
#include "network.h"
#include "error.h"
#include "gameframe.h"
#include "controls.h"
#include "gamesound.h"
#include "carphysics.h"
#include "interfaceutil.h"
#include "gamemem.h"
#include <AmbrosiaTools/Reggie.h>
#include "gamesystem.h"
#include "interfacemultiplayer.h"
#include "initexit.h"
extern ReggieRef gReggieRef;
extern int gReggieConnected;
int gAllowCompression=true;
#define kGameName "Redline"
#define kConnectionTimeOut 5.0
#define kCompressionSize 32
#define kCompressionFlag 0x80
NT_SessionRef gSessionRef=nil;
typedef struct{
QStub qstub;
tNetworkPacket packet;
}tQueuedPacket;
Queue gPacketQueue;
int gInternetAvailable=true;
int gTerminateSession=false;
float gLastPingReceived=0,gLastRTT=0;
char gHistoryBuffer[1024*500]="";
int gHistoryDumps=0;
void NetworkLockOutNewPlayers()
{
// HandleError(NT_SetSessionLock(gSessionRef,true));
int err=NT_SetSessionLock(gSessionRef,true);
//PrintConsoleString("Locking session. returns %d",err);
}
void NetworkUnlockOutNewPlayers()
{
// HandleError(NT_SetSessionLock(gSessionRef,false));
int err=NT_SetSessionLock(gSessionRef,false);
//PrintConsoleString("Unlocking session. returns %d",err);
}
int NetworkGetLocalNetID()
{
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
return info.member;
}
void NetworkClearPacketQueue()
{
int temp=gTerminateSession;
gTerminateSession=false;
tNetworkPacket packet;
while(NetworkReceivePacket(&packet))
if(packet.data)
MemoryFreeBlock(packet.data);
gTerminateSession=temp;
}
Result32 CompressPacket(void *buffer, long *length) {
Result32 error = eCommonErrorNone;
void ** indirect = NULL;
qThrowIfNull(indirect = IndirectInitialize(buffer, *length),
eCommonErrorOutOfMem, kCommonErrorOutOfMemStr);
qThrowIfError(IndirectCompress(indirect,
kIndirectCompressorZLib, NULL), 0);
MemoryCopy(buffer, *indirect, *length = IndirectGetSize(indirect));
CLEANUP:
if (indirect) IndirectDeallocate(indirect);
return(error);
}
Result32 DecompressPacket(void *buffer, long *length) {
Result32 error = eCommonErrorNone;
void ** indirect = NULL;
qThrowIfNull(indirect = IndirectInitialize(buffer, *length),
eCommonErrorOutOfMem, kCommonErrorOutOfMemStr);
qThrowIfError(IndirectDecompress(indirect,
kIndirectCompressorZLib, NULL), 0);
MemoryCopy(buffer, *indirect, *length = IndirectGetSize(indirect));
CLEANUP:
if (indirect) IndirectDeallocate(indirect);
return(error);
}
void NetworkGetStatusString(char *str)
{
NT_ProblemInfo prob;
if(NT_GetProblemInfo(gSessionRef,0,&prob))
{
if(prob.timeout<10)
str[0]='.';
else if(prob.timeout<50)
str[0]='t';
else
str[0]='T';
if(prob.latency<10)
str[1]='.';
else if(prob.latency<50)
str[1]='l';
else
str[1]='L';
if(prob.stalled<10)
str[2]='.';
else if(prob.stalled<50)
str[2]='s';
else
str[2]='S';
if(prob.backlog<10)
str[3]='.';
else if(prob.backlog<50)
str[3]='b';
else
str[3]='B';
if(prob.failure<10)
str[4]='.';
else if(prob.failure<50)
str[4]='f';
else
str[4]='F';
if(prob.errors<10)
str[5]='.';
else if(prob.errors<50)
str[5]='e';
else
str[5]='E';
str[6]='\0';
}
}
void NetworkGetBandwidth(float *rcv,float *snd)
{
NT_LatencyInfo lat;
NT_GetTotalLatencyInfo(gSessionRef,&lat);
*rcv=lat.recvPackets10Sec*0.1;
*snd=lat.sendPackets10Sec*0.1;
}
void NetworkQueuePacket(tNetworkPacket *insert)
{
tQueuedPacket *q=(tQueuedPacket*)MemoryAllocateZeroedBlock(sizeof(tQueuedPacket));
q->packet=*insert;
QueueInsert(&gPacketQueue,(QStubPtr)q);
}
//#define PACKET_DUMP
#ifdef PACKET_DUMP
void DumpPacket(tNetworkPacket *packet)
{
char st[256];
sprintf(st,"what: %d",packet->what);
PrintConsoleString(st);
sprintf(st,"from: %d",packet->from);
PrintConsoleString(st);
sprintf(st,"size: 0x%x",packet->size);
PrintConsoleString(st);
int line=0;
while(line<=packet->size/16)
{
char dataStr[256];
sprintf(dataStr,"%04x ",line*16);
for(int pos=line*16;pos<line*16+16;pos++)
if(pos<packet->size)
sprintf(dataStr,"%s%02x",dataStr,*((UInt8*)packet->data+pos));
else
sprintf(dataStr,"%s ",dataStr);
sprintf(dataStr,"%s ",dataStr);
for(int pos=line*16;pos<line*16+16;pos++)
if(pos<packet->size)
if(*((UInt8*)packet->data+pos)>=32)
sprintf(dataStr,"%s%c",dataStr,*((UInt8*)packet->data+pos));
else
sprintf(dataStr,"%s.",dataStr);
else
sprintf(dataStr,"%s ",dataStr);
PrintConsoleString(dataStr);
line++;
}
PrintConsoleString("");
}
#endif
void NTEventHandler(NT_SessionRef sessionRef,void *refcon,NT_SessionEventType event,NT_MemberIDType member)
{
gAllowCompression=false;
switch(event)
{
case eSessionEventSessionStart:{
//PrintConsoleString("eSessionEventSessionStart");
tNetworkPacket packet;
packet.what=kMessageTypePlayerJoined;
packet.from=0;
packet.size=0;
packet.data=NULL;
NetworkQueuePacket(&packet);
}
break;
case eSessionEventMemberJoin:{
//PrintConsoleString("eSessionEventMemberJoin, member=%d",member);
tNetworkPacket packet;
packet.what=kMessageTypePlayerJoined;
packet.from=member;
packet.size=0;
packet.data=NULL;
NetworkQueuePacket(&packet);
/*NT_ToleranceInfo tolerance;
NT_GetToleranceInfo(gSessionRef,&tolerance);
PrintConsoleString("Tolerance info:");
PrintConsoleString("avgPackets %d.",tolerance.avgPackets);
PrintConsoleString("avgRequests %d.",tolerance.avgRequests);
PrintConsoleString("maxRequests %d.",tolerance.maxRequests);
PrintConsoleString("minHeartbeat %d.",tolerance.minHeartbeat);
PrintConsoleString("avgHeartbeat %d.",tolerance.avgHeartbeat);
PrintConsoleString("maxHeartbeat %d.",tolerance.maxHeartbeat);
PrintConsoleString("maxTimeout %d.",tolerance.maxTimeout);
PrintConsoleString("maxFailures %d.",tolerance.maxFailures);
PrintConsoleString("maxErrors %d.",tolerance.maxErrors);
PrintConsoleString("minLinger %d.",tolerance.minLinger);*/
}
break;
case eSessionEventMemberLeave:{
//PrintConsoleString("eSessionEventMemberLeave, member=%d",member);
tNetworkPacket packet;
if(member==0)
{
if(*gDisconnectString=='\0')
sprintf(gDisconnectString,"Network Failure (Failure on Host side).");
packet.what=kMessageTypeGameTerminated;
}
else
packet.what=kMessageTypePlayerLeft;
packet.from=member;
packet.size=0;
packet.data=NULL;
NetworkQueuePacket(&packet);
NT_LatencyInfo latency;
if(NT_GetLatencyInfo(gSessionRef,member,&latency))
{
PrintConsoleString("Latency info for dropped member:");
PrintConsoleString("minLinkRTT %d.",latency.minLinkRTT);
PrintConsoleString("avgLinkRTT %d.",latency.avgLinkRTT);
PrintConsoleString("p80LinkRTT %d.",latency.p80LinkRTT);
PrintConsoleString("devLinkRTT %d.",latency.devLinkRTT);
PrintConsoleString("wAvgLinkRTT %d.",latency.wAvgLinkRTT);
PrintConsoleString("wDevLinkRTT %d.",latency.wDevLinkRTT);
PrintConsoleString("minTranRTT %d.",latency.minTranRTT);
PrintConsoleString("avgTranRTT %d.",latency.avgTranRTT);
PrintConsoleString("p80TranRTT %d.",latency.p80TranRTT);
PrintConsoleString("maxTranRTT %d.",latency.maxTranRTT);
PrintConsoleString("devTranRTT %d.",latency.devTranRTT);
PrintConsoleString("wAvgTranRTT %d.",latency.wAvgTranRTT);
PrintConsoleString("wDevTranRTT %d.",latency.wDevTranRTT);
}
NT_ProblemInfo prob;
if(NT_GetProblemInfo(gSessionRef,member,&prob))
{
PrintConsoleString("Problem info for dropped member:");
PrintConsoleString("timeout %d.",prob.timeout);
PrintConsoleString("latency %d.",prob.latency);
PrintConsoleString("stalled %d.",prob.stalled);
PrintConsoleString("backlog %d.",prob.backlog);
PrintConsoleString("failure %d.",prob.failure);
PrintConsoleString("errors %d.",prob.errors);
}
NT_PacketHistory(gSessionRef,gHistoryBuffer,1024*500);
}
break;
case eSessionEventSessionEnd:{
//PrintConsoleString("eSessionEventSessionEnd");
/* tNetworkPacket packet;
packet.what=kMessageTypeGameTerminated;
packet.from=member;
packet.size=0;
packet.data=NULL;
NetworkQueuePacket(&packet);*/
}
break;
case eSessionEventRecvPacket:{
UInt8 data[kNetworkToolPacketSize];
UInt16 len;
if(NT_RecvPacket(gSessionRef,&member,(char*)data,kNetworkToolPacketSize,&len))
{
tNetworkPacket packet;
packet.data=MemoryAllocateBlock(kNetworkToolPacketSize);
MemoryMove(packet.data,data+1,len-1);
packet.size=len-1;
packet.from=member;
packet.what=*data;
if(packet.what==kMessageTypeGameTerminated)
gTerminateSession=true;
/*#ifdef PACKET_DUMP
PrintConsoleString("Packet Received:");
DumpPacket(&packet);
#endif
*/
//got a Ping request?
if(packet.what==kMessageTypePing)
//send out a reply packet with the original ping packets time stamp.
NetworkSendPacket(kMessageTypePong,packet.data,sizeof(float),kMessagePriorityLow,packet.from);
else if(packet.what==kMessageTypePong)
{
gLastPingReceived=TimeGetSeconds();
gLastRTT=gLastPingReceived-*(float*)packet.data;
}
else
NetworkQueuePacket(&packet);
}
}
break;
case eSessionEventRecvRequest:{
UInt8 data[kNetworkToolPacketSize];
UInt16 len;
if(NT_RecvRequest(gSessionRef,&member,(char*)data,kNetworkToolPacketSize,&len))
{
NT_SendResponse(gSessionRef,NULL,0);
tNetworkPacket packet;
packet.data=MemoryAllocateBlock(kNetworkToolPacketSize);
MemoryMove(packet.data,data+1,len-1);
packet.size=len-1;
packet.from=member;
packet.what=*data;
if(packet.what==kMessageTypeGameTerminated)
gTerminateSession=true;
#ifdef PACKET_DUMP
PrintConsoleString("Request Packet Received:");
DumpPacket(&packet);
#endif
NetworkQueuePacket(&packet);
}
}
break;
case eSessionEventRecvResponse:{
UInt8 data[kNetworkToolPacketSize];
UInt16 len;
NT_RecvResponse(gSessionRef,&member,(char*)data,kNetworkToolPacketSize,&len);
}
break;
}
gAllowCompression=true;
}
void NTErrorHandler(NT_SessionRef sessionRef,void *refcon,NT_SessionProblemType problem,NT_SessionSeverityType severity,NT_MemberIDType member,Bool8 *disconnectSelf,Bool8 *disconnectMember)
{
gAllowCompression=false;
if(severity>=100)
{
PrintConsoleString("NT Error %d",problem);
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
if(info.member==0)
{
if(member!=0)
{
*disconnectMember=true;
tChatMessage m;
m.flags=kChatFlagSystem;
switch(problem)
{
case eSessionProblemTimeout:
sprintf(m.str,"### Player %d is disconnecting (Connection timed out).",member+1);
break;
case eSessionProblemLatency:
sprintf(m.str,"### Player %d is disconnecting (Latency too high).",member+1);
break;
case eSessionProblemStalled:
sprintf(m.str,"### Player %d is disconnecting (Stalled).",member+1);
break;
case eSessionProblemBacklog:
sprintf(m.str,"### Player %d is disconnecting (Backlog).",member+1);
break;
case eSessionProblemFailure:
sprintf(m.str,"### Player %d is disconnecting (Failure).",member+1);
break;
case eSessionProblemErrors:
sprintf(m.str,"### Player %d is disconnecting (Too many errors).",member+1);
break;
default:
sprintf(m.str,"### Player %d is disconnecting (Unknown error).",member+1);
break;
}
printf("%s\n",m.str);
//NetworkSendPacket(kMessageTypeChat,&m,sizeof(m),kMessagePriorityHigh,kMessageSendToAll);
}
}
else if(member==0)
{
*disconnectMember=false;
*disconnectSelf=true;
tNetworkPacket packet;
packet.data=NULL;
packet.size=0;
packet.from=member;
packet.what=kMessageTypeGameTerminated;
NetworkQueuePacket(&packet);
switch(problem)
{
case eSessionProblemTimeout:
sprintf(gDisconnectString,"Network Failure (Connection timed out).");
break;
case eSessionProblemLatency:
sprintf(gDisconnectString,"Network Failure (Latency too high).");
break;
case eSessionProblemStalled:
sprintf(gDisconnectString,"Network Failure (Stalled).");
break;
case eSessionProblemBacklog:
sprintf(gDisconnectString,"Network Failure (Backlog).");
break;
case eSessionProblemFailure:
sprintf(gDisconnectString,"Network Failure (Failure).");
break;
case eSessionProblemErrors:
sprintf(gDisconnectString,"Network Failure (Too many errors).");
break;
default:
sprintf(gDisconnectString,"Network Failure (unknown error).");
break;
}
}
}
gAllowCompression=true;
}
void NetworkPreSession()
{
if(gSessionRef==NULL)
HandleError(NT_SessionStartParam(&gSessionRef,NTEventHandler,NTErrorHandler,NULL,NULL,6,kGameName,""));
else
HandleError(NT_SessionRestart(gSessionRef,6,kGameName,""));
}
float NetworkGetPlayerPing(int netID)
{
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
if(netID==info.member||netID==kMessageNoRecipients)
return 0;
NT_LatencyInfo latency;
if(NT_GetLatencyInfo(gSessionRef,netID,&latency));
{
/* PrintConsoleString("Player %d latency.",netID);
PrintConsoleString("minLinkRTT %d.",latency.minLinkRTT);
PrintConsoleString("avgLinkRTT %d.",latency.avgLinkRTT);
PrintConsoleString("p80LinkRTT %d.",latency.p80LinkRTT);
PrintConsoleString("devLinkRTT %d.",latency.devLinkRTT);
PrintConsoleString("wAvgLinkRTT %d.",latency.wAvgLinkRTT);
PrintConsoleString("wDevLinkRTT %d.",latency.wDevLinkRTT);
PrintConsoleString("minTranRTT %d.",latency.minTranRTT);
PrintConsoleString("avgTranRTT %d.",latency.avgTranRTT);
PrintConsoleString("p80TranRTT %d.",latency.p80TranRTT);
PrintConsoleString("maxTranRTT %d.",latency.maxTranRTT);
PrintConsoleString("devTranRTT %d.",latency.devTranRTT);
PrintConsoleString("wAvgTranRTT %d.",latency.wAvgTranRTT);
PrintConsoleString("wDevTranRTT %d.",latency.wDevTranRTT);*/
return latency.avgLinkRTT*0.001;
}
return 0;
}
//Host a new Network Game
void HostNetGame(int maxPlayers,char *pass)
{
HandleError(NT_SessionRestart(gSessionRef,maxPlayers,kGameName,pass));
gTerminateSession=false;
}
void NetworkDisconnectPlayer(int netID,UInt8 type)
{
NT_MemberInfo info;
if(NT_GetMemberInfo(gSessionRef,netID,&info))
{
if(type!=kNetworkDisconnectLicenseCopies)
HandleError(NT_SessionBan(gSessionRef,&info.address,false,NULL));
NetworkSendPacket(kMessageTypeKicked,&type,sizeof(UInt8),kMessagePriorityHigh,netID);
}
}
void NetworkChangePassword(char *pass)
{
HandleError(NT_SetSessionPassword(gSessionRef,pass));
}
//join a network game at the ip address given in the string address.
//returns an error code or 0. passes the player's id in id.
int JoinNetGame(char *address,char *errorString)
{
if(!*address)
{
sprintf(errorString,"No Address Entered.");
return false;
}
//PrintConsoleString(address);
NetworkAddress addy;
Result32 err=SimpleResolve(eNetworkStackTCPIP,address,&addy);
if(err)
{
sprintf(errorString,"Can't resolve host. (%d)",err);
return false;
}
gTerminateSession=false;
NetworkClearPacketQueue();
HandleError(NT_SessionRejoin(gSessionRef,&addy,kGameName,NULL,&err));
if(err==eNetworkToolErrorBadPass)
{
err=0;
char password[256];
if(InterfaceGetUserInputString("Please enter Game Password",password,256,true,true))
{
NetworkClearPacketQueue();
HandleError(NT_SessionRejoin(gSessionRef,&addy,kGameName,password,&err));
}
else
return false;
}
if(err)
{
switch(err)
{
case eNetworkToolErrorNoServer:
sprintf(errorString,"No Server Running on that Machine",err);
break;
case eNetworkToolErrorTimeout:
sprintf(errorString,"Network_Tool Timeout",err);
break;
case eNetworkToolErrorLatency:
sprintf(errorString,"Latency is too high.",err);
break;
case eNetworkToolErrorBanned:
sprintf(errorString,"You are banned from this host.",err);
break;
case eNetworkToolErrorTooMany:
sprintf(errorString,"The game is full.",err);
break;
case eNetworkToolErrorBadPass:
sprintf(errorString,"Wrong Password",err);
break;
case eNetworkToolErrorLocked:
sprintf(errorString,"Can't join in the middle of a game.",err);
break;
default:
sprintf(errorString,"Connection Error. (%d)",err);
}
return false;
}
float startTime=TimeGetSeconds();
while(TimeGetSeconds()<startTime+kConnectionTimeOut)
{
tNetworkPacket message;
while(NetworkReceivePacket(&message))
{
//wait for servers response
if(message.what==kMessageTypeID)
{
NetworkQueuePacket(&message);
return true;
}
if(message.what==kMessageTypeVersion)
{
UInt32 reply=kVersion;
U32Swap(reply);
NetworkSendPacket(kMessageTypeVersion,&reply,sizeof(UInt32),kMessagePriorityHigh,message.from);
}
if(message.what==kMessageTypeJoinDenied)
{
if(*((UInt8*)message.data)==kJoinDeniedInProgress)
sprintf(errorString,"Can't join in the middle of a game.",err);
else if(*((UInt8*)message.data)==kJoinDeniedVersion)
sprintf(errorString,"Version Mismatch.",err);
else
sprintf(errorString,"Host rejected connection.",err);
//PrintConsoleString("Rejected. Exiting.");
return false;
}
if(message.what==kMessageTypeGameTerminated)
{
sprintf(errorString,"Game Terminated.",err);
return false;
}
NetworkDisposePacket(&message);
}
}
sprintf(errorString,"Connection Timed out.",err);
return false;
}
//exits a network game
void ExitNetGame()
{
if(gSessionRef)
{
// HandleError(NT_SessionLeave(gSessionRef));
// gSessionRef=nil;
}
}
//sends the data in *message to other players on the network
void NetworkSendPacket(char messageType,void *message,long size,int priority,int to,int notTo)
{
if(messageType==kMessageTypeGameTerminated)
gTerminateSession=true;
if(to==kMessageNoRecipients)
return;
if(size>kNetworkToolPacketSize-1)
FailWithErrorString("Packet too large.");
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
NT_MemberListType self=0x00000001<<info.member;
UInt8 data[kNetworkToolPacketSize];
MemoryMove(data+1,message,size);
*data=messageType;
if(size>kCompressionSize&&gAllowCompression)
{
int oldsize=size;
if(CompressPacket(data+1,&size)==eCommonErrorNone)
if(oldsize<size)
*data|=kCompressionFlag;
else
{
size=oldsize;
MemoryMove(data+1,message,size);
}
}
// U32Swap(*data);
NT_MemberListType members;
switch(to)
{
case kMessageSendToAll: members=eMemberListAll; break;
case kMessageSendToAllButSelf: members=eMemberListAll^self; break;
case kMessageSendToHostOnly: members=0x00000001; break;
default: members=0x00000001<<to;
}
if(notTo)
members&=~(0x00000001<<notTo);
if(members&self)
{
tNetworkPacket packet;
packet.data=MemoryAllocateBlock(size);
MemoryMove(packet.data,message,size);
packet.size=size;
packet.from=info.member;
packet.what=messageType;
NetworkQueuePacket(&packet);
}
Result32 err=0;
if(priority<=kMessagePriorityNormal)
err=NT_SendPacket(gSessionRef,members,(char*)data,size+4);
else
{
NT_SessionInfo sessInfo;
NT_MemberInfo member;
NT_GetSessionInfo(gSessionRef,&sessInfo);
for(int i=0;i<32;i++)
if((members&(0x00000001<<i))&&(i!=info.member))
if(NT_GetMemberInfo(gSessionRef,i,&member))
err=NT_SendRequest(gSessionRef,i,(char*)data,size+4);
}
if(err)
{
PrintConsoleString("Error Sending Packet (%d)",err);
gTerminateSession=true;
}
}
void NetworkSendPacket(char messageType,void *message,long size,int priority,int to)
{
NetworkSendPacket(messageType,message,size,priority,to,0);
}
int NetworkReceivePacket(tNetworkPacket* packet)
{
if(*gHistoryBuffer)
{
time_t t;
time(&t);
char ct[26];
ctime_r(&t,ct);
PrintConsoleString("Dumping Packet History %d. (%s)",gHistoryDumps,ct);
FILE *f=fopen("/tmp/packethistory.log","a");
fprintf(f,"Dump %d (%s)\n\n",gHistoryDumps++,ct);
char *ch=gHistoryBuffer;
while(*ch)
fwrite(ch++,1,1,f);
strcpy(gHistoryBuffer,"");
fprintf(f,"Debug Snapshot:");
NT_MemberListType mt=0xffff;
char buffer[64*1024];
NT_DebugSnapshot(gSessionRef,mt,buffer,32*1024);
ch=buffer;
while(*ch)
fwrite(ch++,1,1,f);
fclose(f);
}
if(gTerminateSession)
{
packet->what=kMessageTypeGameTerminated;
packet->data=NULL;
return true;
}
else if(QStubPtr rcv=QueueRemove(&gPacketQueue))
{
*packet=((tQueuedPacket*)rcv)->packet;
if(packet->what&kCompressionFlag)
{
DecompressPacket(packet->data,&packet->size);
packet->what^=kCompressionFlag;
}
MemoryFreeBlock(rcv);
return true;
}
if(gReggieConnected)
ReggieMessageCheck(gReggieRef);
return false;
}
void NetworkDisposePacket(tNetworkPacket* packet)
{
if(packet->data)
MemoryFreeBlock(packet->data);
}
void NetworkInit()
{
HandleError(NT_Open());
QueueCreate(&gPacketQueue);
}
void NetworkIdle()
{
static float lastStatus=0;
NT_Idle();
if(gSessionRef)
{
/* if(TimeGetSeconds()-lastStatus<0.5)
return;
lastStatus=TimeGetSeconds();
char str[16];
NetworkGetStatusString(str);
// printf("%s\n",str);
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
if(info.member)
{
if(gLastRTT<0)
printf("No Ping Response since %f seconds.\n",lastStatus-gLastPingReceived);
else
{
//printf("Last RTT: %f\n",gLastRTT);
gLastRTT=-1;
}
NetworkSendPacket(kMessageTypePing,&lastStatus,sizeof(float),kMessagePriorityLow,kMessageSendToHostOnly);
}*/
}
}
void NetworkExit()
{
if(gSessionRef)
NetworkSendPacket(kMessageTypeBye,0,NULL,kMessagePriorityHigh,kMessageSendToAll);
if(gReggieConnected)
ReggieDispose(gReggieRef,true);
NT_Close();
while(QStubPtr rcv=QueueRemove(&gPacketQueue))
MemoryFreeBlock(rcv);
QueueEmpty(&gPacketQueue);
}
//wait for a response from all players, to synchronize the start of the game.
int NetworkSynch(int numPlayers)
{
//PrintConsoleString("Synching %d...",numPlayers);
NetworkSendPacket(kMessageTypeSynch,nil,0,kMessagePriorityHigh,kMessageSendToAll);
UInt32 lastSynch=0;
UInt32 startClock;
int start=false;
tNetworkPacket leftMessage[kMaxPlayers];
int numLeftMessages=0;
int synchMessagesReceived=0;
while(synchMessagesReceived<numPlayers&&!start)
{
tNetworkPacket message;
if(NetworkReceivePacket(&message))
{
int cancel=false;
if(message.what==kMessageTypeSynch)
{
synchMessagesReceived++;
//PrintConsoleString("Received Synch packet from player %d",message.from);
}
else if(message.what==kMessageTypeEndGame||message.what==kMessageTypeGameTerminated)
{
cancel=true;
PrintConsoleString("Received Termination Packet. Aborting");
}
else if(message.what==kMessageTypePlayerLeft)
{
//cancel=true;
leftMessage[numLeftMessages++]=message;
numPlayers--;
PrintConsoleString("A Player Left.");
}
else if(message.what==kMessageTypeSynchStart)
{
//PrintConsoleString("Received Start Signal.");
startClock=*(UInt32*)message.data;
U32Swap(startClock);
start=true;
}
else
PrintConsoleString("Unexpected Packet");
NetworkDisposePacket(&message);
if(cancel)
return false;
}
SystemPoll(true);
}
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
if(info.member==0)
{
//PrintConsoleString("Sent Start Signal.");
startClock=NT_GetSessionClock(gSessionRef)+500;
U32Swap(startClock);
NetworkSendPacket(kMessageTypeSynchStart,&startClock,sizeof(UInt32),kMessagePriorityHigh,kMessageSendToAll);
U32Swap(startClock);
}
else
{
float startTime=TimeGetSeconds();
tNetworkPacket message;
while(TimeGetSeconds()<startTime+kConnectionTimeOut&&!start)
{
if(NetworkReceivePacket(&message))
{
if(message.what==kMessageTypeSynchStart)
{
//PrintConsoleString("Received Start Signal.");
startClock=*(UInt32*)message.data;
U32Swap(startClock);
start=true;
}
else if(message.what==kMessageTypePlayerLeft)
{
leftMessage[numLeftMessages++]=message;
}
else
PrintConsoleString("Unexpected Packet");
NetworkDisposePacket(&message);
}
SystemPoll(false);
}
if(!start)
return false;
}
for(int i=0;i<numLeftMessages;i++)
NetworkQueuePacket(leftMessage+i);
while(NT_GetSessionClock(gSessionRef)<startClock);
return true;
}