mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-29 22:27:57 +03:00
4409 lines
86 KiB
C
4409 lines
86 KiB
C
/*
|
|
GameSpy Peer SDK
|
|
Dan "Mr. Pants" Schoenblum
|
|
dan@gamespy.com
|
|
|
|
Copyright 1999-2007 GameSpy Industries, Inc
|
|
|
|
devsupport@gamespy.com
|
|
*/
|
|
|
|
/*************
|
|
** INCLUDES **
|
|
*************/
|
|
#include <limits.h>
|
|
#include "peer.h"
|
|
#include "peerAscii.h"
|
|
#include "peerMain.h"
|
|
#include "peerCallbacks.h"
|
|
#include "peerGlobalCallbacks.h"
|
|
#include "peerOperations.h"
|
|
#include "peerPlayers.h"
|
|
#include "peerRooms.h"
|
|
#include "peerPing.h"
|
|
#include "peerSB.h"
|
|
#include "peerMangle.h"
|
|
#include "peerKeys.h"
|
|
#include "peerQR.h"
|
|
#include "peerHost.h"
|
|
#include "peerAutoMatch.h"
|
|
#include "../common/gsAvailable.h"
|
|
|
|
/************
|
|
** DEFINES **
|
|
************/
|
|
#define PEER_CONNECTED assert(connection->connected);
|
|
|
|
#define PI_CHECK_SHUTDOWN if(connection->shutdown && (connection->callbackDepth == 0))\
|
|
{\
|
|
peerShutdown(peer);\
|
|
}
|
|
|
|
#define PI_INIT_FAILED {\
|
|
piShutdownCleanup(peer);\
|
|
return NULL;\
|
|
}
|
|
|
|
#define PI_DO_BLOCKING if(blocking)\
|
|
{\
|
|
do\
|
|
{\
|
|
msleep(1);\
|
|
piThink(peer, opID);\
|
|
}\
|
|
while(!piCheckBlockingID(peer, opID));\
|
|
PI_CHECK_SHUTDOWN\
|
|
}
|
|
|
|
#define PI_OP_ID int opID = piGetNextID(peer)
|
|
#if 0
|
|
int opID; // for visual assist
|
|
#endif
|
|
|
|
/***************
|
|
** PROTOTYPES **
|
|
***************/
|
|
static void piShutdownCleanup(PEER peer);
|
|
static void piDisconnectCleanup(PEER peer);
|
|
static void piThink(PEER peer,int ID);
|
|
|
|
void peerCreateStagingRoomWithSocketA(PEER peer, const char * name, int maxPlayers, const char password[PEER_PASSWORD_LEN], SOCKET socket, unsigned short port, peerJoinRoomCallback callback, void * param, PEERBool blocking);
|
|
void peerStartAutoMatchWithSocketA(PEER peer, int maxPlayers, const char * filter, SOCKET socket, unsigned short port, peerAutoMatchStatusCallback statusCallback, peerAutoMatchRateCallback rateCallback, void * param, PEERBool blocking);
|
|
|
|
/************
|
|
** GENERAL **
|
|
************/
|
|
static PEERBool piCheckBlockingID
|
|
(
|
|
PEER peer,
|
|
int ID
|
|
)
|
|
{
|
|
return (PEERBool)(piIsOperationFinished(peer, ID) && piIsCallbackFinished(peer, ID));
|
|
}
|
|
|
|
static unsigned int piGetPrivateIP(void)
|
|
{
|
|
HOSTENT * host;
|
|
IN_ADDR * addr;
|
|
int i;
|
|
|
|
host = getlocalhost();
|
|
if(!host)
|
|
return 0;
|
|
|
|
for(i = 0 ; host->h_addr_list[i] ; i++)
|
|
{
|
|
addr = (IN_ADDR *)host->h_addr_list[i];
|
|
if(IsPrivateIP(addr))
|
|
return addr->s_addr;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
PEER peerInitialize
|
|
(
|
|
PEERCallbacks * callbacks
|
|
)
|
|
{
|
|
PEER peer;
|
|
piConnection * connection;
|
|
|
|
assert(callbacks);
|
|
|
|
// Check if the backend is available.
|
|
/////////////////////////////////////
|
|
if(__GSIACResult != GSIACAvailable)
|
|
return NULL;
|
|
|
|
// Init sockets.
|
|
////////////////
|
|
SocketStartUp();
|
|
|
|
// Create an object.
|
|
////////////////////
|
|
connection = (piConnection *)gsimalloc(sizeof(piConnection));
|
|
if(!connection)
|
|
return NULL;
|
|
memset(connection, 0, sizeof(piConnection));
|
|
peer = (PEER)connection;
|
|
|
|
// Chat.
|
|
////////
|
|
connection->chat = NULL;
|
|
connection->nick[0] = '\0';
|
|
connection->connecting = PEERFalse;
|
|
connection->connected = PEERFalse;
|
|
|
|
// Game.
|
|
////////
|
|
connection->privateIP = piGetPrivateIP();
|
|
connection->title[0] = '\0';
|
|
|
|
#ifdef GSI_UNICODE
|
|
connection->title_W[0] = '\0';
|
|
connection->nick_W[0] = '\0';
|
|
#endif
|
|
|
|
// ID.
|
|
//////
|
|
connection->nextID = 0;
|
|
|
|
// Operations.
|
|
//////////////
|
|
if(!piOperationsInit(peer))
|
|
PI_INIT_FAILED
|
|
|
|
// Callbacks.
|
|
/////////////
|
|
connection->callbacks = *callbacks;
|
|
if(!piCallbacksInit(peer))
|
|
PI_INIT_FAILED
|
|
|
|
// Keys.
|
|
////////
|
|
if(!piKeysInit(peer))
|
|
PI_INIT_FAILED
|
|
|
|
// Misc.
|
|
////////
|
|
connection->shutdown = PEERFalse;
|
|
|
|
return peer;
|
|
}
|
|
|
|
void peerConnectA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
int profileID,
|
|
peerNickErrorCallback nickErrorCallback,
|
|
peerConnectCallback connectCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
assert(profileID >= 0);
|
|
assert(connectCallback);
|
|
assert(strlen(nick) < PI_NICK_MAX_LEN);
|
|
|
|
// Are we already connecting or connected?
|
|
//////////////////////////////////////////
|
|
if(connection->connected || connection->connecting)
|
|
success = PEERFalse;
|
|
|
|
// We must have a title set to connect.
|
|
///////////////////////////////////////
|
|
if(success && !connection->title[0])
|
|
success = PEERFalse;
|
|
|
|
if(success)
|
|
{
|
|
// Chat.
|
|
////////
|
|
connection->chat = NULL;
|
|
strzcpy(connection->nick, nick, PI_NICK_MAX_LEN);
|
|
connection->connected = PEERFalse;
|
|
connection->connecting = PEERTrue;
|
|
connection->nickErrorCallback = nickErrorCallback;
|
|
|
|
#ifdef GSI_UNICODE
|
|
UTF8ToUCS2String(connection->nick, connection->nick_W);
|
|
#endif
|
|
// Misc.
|
|
////////
|
|
connection->profileID = profileID;
|
|
connection->disconnect = PEERFalse;
|
|
|
|
// Start connecting.
|
|
////////////////////
|
|
if(!piNewConnectOperation(peer, PI_CONNECT, nick, 0, NULL, NULL, NULL, NULL, NULL, NULL, connectCallback, param, opID))
|
|
{
|
|
success = PEERFalse;
|
|
piDisconnectCleanup(peer);
|
|
}
|
|
}
|
|
|
|
if(!success)
|
|
piAddConnectCallback(peer, PEERFalse, PEER_DISCONNECTED, connectCallback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerConnectW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
int profileID,
|
|
peerNickErrorCallback nickErrorCallback,
|
|
peerConnectCallback connectCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
peerConnectA(peer, nick_A, profileID, nickErrorCallback, connectCallback, param, blocking);
|
|
gsifree(nick_A);
|
|
}
|
|
#endif
|
|
|
|
void peerConnectLoginA
|
|
(
|
|
PEER peer,
|
|
int namespaceID,
|
|
const char * email,
|
|
const char * profilenick,
|
|
const char * uniquenick,
|
|
const char * password,
|
|
peerNickErrorCallback nickErrorCallback,
|
|
peerConnectCallback connectCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
|
|
assert(connectCallback);
|
|
|
|
// Are we already connecting or connected?
|
|
//////////////////////////////////////////
|
|
if(connection->connected || connection->connecting)
|
|
success = PEERFalse;
|
|
|
|
// We must have a title set to connect.
|
|
///////////////////////////////////////
|
|
if(success && !connection->title[0])
|
|
success = PEERFalse;
|
|
|
|
if(success)
|
|
{
|
|
// Chat.
|
|
////////
|
|
connection->chat = NULL;
|
|
connection->nick[0] = '\0';
|
|
connection->connected = PEERFalse;
|
|
connection->connecting = PEERTrue;
|
|
connection->nickErrorCallback = nickErrorCallback;
|
|
|
|
#ifdef GSI_UNICODE
|
|
UTF8ToUCS2String(connection->nick, connection->nick_W);
|
|
#endif
|
|
// Misc.
|
|
////////
|
|
connection->profileID = 0;
|
|
connection->disconnect = PEERFalse;
|
|
|
|
// Start connecting.
|
|
////////////////////
|
|
if(!piNewConnectOperation(peer, (uniquenick && uniquenick[0])?PI_CONNECT_UNIQUENICK_LOGIN:PI_CONNECT_PROFILENICK_LOGIN, NULL, namespaceID, email, profilenick, uniquenick, password, NULL, NULL, connectCallback, param, opID))
|
|
{
|
|
success = PEERFalse;
|
|
piDisconnectCleanup(peer);
|
|
}
|
|
}
|
|
|
|
if(!success)
|
|
piAddConnectCallback(peer, PEERFalse, PEER_DISCONNECTED, connectCallback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerConnectLoginW
|
|
(
|
|
PEER peer,
|
|
int namespaceID,
|
|
const unsigned short * email,
|
|
const unsigned short * profilenick,
|
|
const unsigned short * uniquenick,
|
|
const unsigned short * password,
|
|
peerNickErrorCallback nickErrorCallback,
|
|
peerConnectCallback connectCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* email_A = UCS2ToUTF8StringAlloc(email);
|
|
char* profilenick_A = UCS2ToUTF8StringAlloc(profilenick);
|
|
char* uniquenick_A = UCS2ToUTF8StringAlloc(uniquenick);
|
|
char* password_A = UCS2ToUTF8StringAlloc(password);
|
|
peerConnectLoginA(peer, namespaceID, email_A, profilenick_A, uniquenick_A, password_A, nickErrorCallback, connectCallback, param, blocking);
|
|
gsifree(email_A);
|
|
gsifree(profilenick_A);
|
|
gsifree(uniquenick_A);
|
|
gsifree(password_A);
|
|
}
|
|
#endif
|
|
|
|
void peerConnectPreAuthA
|
|
(
|
|
PEER peer,
|
|
const char * authtoken,
|
|
const char * partnerchallenge,
|
|
peerNickErrorCallback nickErrorCallback,
|
|
peerConnectCallback connectCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
|
|
assert(authtoken && authtoken[0]);
|
|
assert(partnerchallenge && partnerchallenge[0]);
|
|
assert(connectCallback);
|
|
|
|
// Are we already connecting or connected?
|
|
//////////////////////////////////////////
|
|
if(connection->connected || connection->connecting)
|
|
success = PEERFalse;
|
|
|
|
// We must have a title set to connect.
|
|
///////////////////////////////////////
|
|
if(success && !connection->title[0])
|
|
success = PEERFalse;
|
|
|
|
if(success)
|
|
{
|
|
// Chat.
|
|
////////
|
|
connection->chat = NULL;
|
|
connection->nick[0] = '\0';
|
|
connection->connected = PEERFalse;
|
|
connection->connecting = PEERTrue;
|
|
connection->nickErrorCallback = nickErrorCallback;
|
|
|
|
#ifdef GSI_UNICODE
|
|
UTF8ToUCS2String(connection->nick, connection->nick_W);
|
|
#endif
|
|
// Misc.
|
|
////////
|
|
connection->profileID = 0;
|
|
connection->disconnect = PEERFalse;
|
|
|
|
// Start connecting.
|
|
////////////////////
|
|
if(!piNewConnectOperation(peer, PI_CONNECT_PREAUTH, NULL, 0, NULL, NULL, NULL, NULL, authtoken, partnerchallenge, connectCallback, param, opID))
|
|
{
|
|
success = PEERFalse;
|
|
piDisconnectCleanup(peer);
|
|
}
|
|
}
|
|
|
|
if(!success)
|
|
piAddConnectCallback(peer, PEERFalse, PEER_DISCONNECTED, connectCallback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerConnectPreAuthW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * authtoken,
|
|
const unsigned short * partnerchallenge,
|
|
peerNickErrorCallback nickErrorCallback,
|
|
peerConnectCallback connectCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* authtoken_A = UCS2ToUTF8StringAlloc(authtoken);
|
|
char* partnerchallenge_A = UCS2ToUTF8StringAlloc(partnerchallenge);
|
|
peerConnectPreAuthA(peer, authtoken_A, partnerchallenge_A, nickErrorCallback, connectCallback, param, blocking);
|
|
gsifree(authtoken_A);
|
|
gsifree(partnerchallenge_A);
|
|
}
|
|
#endif
|
|
|
|
void peerRetryWithNickA
|
|
(
|
|
PEER peer,
|
|
const char * nick
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Check that we're connecting.
|
|
///////////////////////////////
|
|
assert(connection->connecting);
|
|
if(!connection->connecting)
|
|
return;
|
|
|
|
// Set the new nick we're using.
|
|
////////////////////////////////
|
|
if(nick && nick[0])
|
|
{
|
|
strzcpy(connection->nick, nick, PI_NICK_MAX_LEN);
|
|
|
|
#ifdef GSI_UNICODE
|
|
UTF8ToUCS2String(connection->nick, connection->nick_W);
|
|
#endif
|
|
}
|
|
|
|
// Retry with the new nick.
|
|
///////////////////////////
|
|
chatRetryWithNickA(connection->chat, nick);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerRetryWithNickW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
peerRetryWithNickA(peer, nick_A);
|
|
gsifree(nick_A);
|
|
}
|
|
#endif
|
|
|
|
void peerRegisterUniqueNickA
|
|
(
|
|
PEER peer,
|
|
int namespaceID,
|
|
const char * uniquenick,
|
|
const char * cdkey)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Check that we're connecting.
|
|
///////////////////////////////
|
|
assert(connection->connecting);
|
|
if(!connection->connecting)
|
|
return;
|
|
|
|
// Register the nick.
|
|
/////////////////////
|
|
chatRegisterUniqueNickA(connection->chat, namespaceID, uniquenick, cdkey);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerRegisterUniqueNickW
|
|
(
|
|
PEER peer,
|
|
int namespaceID,
|
|
const unsigned short * uniquenick,
|
|
const unsigned short * cdkey
|
|
)
|
|
{
|
|
char* uniquenick_A = UCS2ToUTF8StringAlloc(uniquenick);
|
|
char* cdkey_A = UCS2ToUTF8StringAlloc(cdkey);
|
|
peerRegisterUniqueNickA(peer, namespaceID, uniquenick_A, cdkey_A);
|
|
gsifree(uniquenick_A);
|
|
gsifree(cdkey_A);
|
|
}
|
|
#endif
|
|
|
|
PEERBool peerIsConnected(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
return connection->connected;
|
|
}
|
|
|
|
PEERBool piConnectTitle(PEER peer)
|
|
{
|
|
// Rooms.
|
|
/////////
|
|
if(!piRoomsInit(peer))
|
|
return PEERFalse;
|
|
|
|
// Players.
|
|
///////////
|
|
if(!piPlayersInit(peer))
|
|
return PEERFalse;
|
|
|
|
// Ping.
|
|
// If it fails, keep going.
|
|
///////////////////////////
|
|
piPingInit(peer);
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
void piDisconnectTitle(PEER peer)
|
|
{
|
|
// Rooms.
|
|
/////////
|
|
piRoomsCleanup(peer);
|
|
|
|
// Players.
|
|
///////////
|
|
piPlayersCleanup(peer);
|
|
|
|
// Ping.
|
|
////////
|
|
piPingCleanup(peer);
|
|
|
|
// AutoMatch.
|
|
/////////////
|
|
piStopAutoMatch(peer);
|
|
}
|
|
|
|
PEERBool peerSetTitleA
|
|
(
|
|
PEER peer,
|
|
const char * title,
|
|
const char * qrSecretKey,
|
|
const char * sbName,
|
|
const char * sbSecretKey,
|
|
int sbGameVersion,
|
|
int sbMaxUpdates,
|
|
PEERBool natNegotiate,
|
|
PEERBool pingRooms[NumRooms],
|
|
PEERBool crossPingRooms[NumRooms]
|
|
)
|
|
{
|
|
static PEERBool noPings[NumRooms];
|
|
PEERBool pingTitleRoom = PEERFalse;
|
|
PEERBool xpingTitleRoom = PEERFalse;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(title);
|
|
assert(title[0]);
|
|
assert(strlen(title) < PI_TITLE_MAX_LEN);
|
|
assert(qrSecretKey);
|
|
assert(sbName);
|
|
assert(sbName[0]);
|
|
assert(sbSecretKey);
|
|
|
|
// Check if a title is set.
|
|
///////////////////////////
|
|
if(connection->title[0])
|
|
peerClearTitle(peer);
|
|
|
|
// Game.
|
|
////////
|
|
strcpy(connection->title, title);
|
|
|
|
#ifdef GSI_UNICODE
|
|
AsciiToUCS2String(title, connection->title_W);
|
|
#endif
|
|
|
|
// Null pings means don't do pings.
|
|
///////////////////////////////////
|
|
if(!pingRooms)
|
|
pingRooms = noPings;
|
|
if(!crossPingRooms)
|
|
crossPingRooms = noPings;
|
|
|
|
// If staying in the title room, leave the room's ping setting alone.
|
|
/////////////////////////////////////////////////////////////////////
|
|
if(connection->stayInTitleRoom)
|
|
{
|
|
pingTitleRoom = connection->pingRoom[TitleRoom];
|
|
xpingTitleRoom = connection->xpingRoom[TitleRoom];
|
|
}
|
|
|
|
// Save our ping settings.
|
|
//////////////////////////
|
|
memcpy(connection->pingRoom, pingRooms, sizeof(PEERBool) * NumRooms);
|
|
memcpy(connection->xpingRoom, crossPingRooms, sizeof(PEERBool) * NumRooms);
|
|
|
|
// If staying in the title room, leave the room's ping setting alone.
|
|
/////////////////////////////////////////////////////////////////////
|
|
if(connection->stayInTitleRoom)
|
|
{
|
|
connection->pingRoom[TitleRoom] = pingTitleRoom;
|
|
connection->xpingRoom[TitleRoom] = xpingTitleRoom;
|
|
}
|
|
|
|
// Save SB settings.
|
|
////////////////////
|
|
strzcpy(connection->sbName, sbName, PI_SB_LEN);
|
|
strzcpy(connection->sbSecretKey, sbSecretKey, PI_SB_LEN);
|
|
connection->sbGameVersion = sbGameVersion;
|
|
connection->sbMaxUpdates = sbMaxUpdates;
|
|
|
|
// Init SB.
|
|
///////////
|
|
if(!piSBInit(peer))
|
|
return PEERFalse;
|
|
|
|
// If we're already connected, do the connect stuff.
|
|
////////////////////////////////////////////////////
|
|
if(connection->connected)
|
|
{
|
|
if(!piConnectTitle(peer))
|
|
{
|
|
peerClearTitle(peer);
|
|
return PEERFalse;
|
|
}
|
|
}
|
|
|
|
// Hosting.
|
|
///////////
|
|
strcpy(connection->qrSecretKey, qrSecretKey);
|
|
piStopHosting(peer, PEERTrue);
|
|
connection->hosting = PEERFalse;
|
|
connection->playing = PEERFalse;
|
|
connection->natNegotiate = natNegotiate;
|
|
|
|
// Game states.
|
|
///////////////
|
|
connection->ready = PEERFalse;
|
|
|
|
// Make sure the "stay in title room" setting is cleared.
|
|
/////////////////////////////////////////////////////////
|
|
connection->stayInTitleRoom = PEERFalse;
|
|
|
|
return PEERTrue;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
PEERBool peerSetTitleW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * title,
|
|
const unsigned short * qrSecretKey,
|
|
const unsigned short * sbName,
|
|
const unsigned short * sbSecretKey,
|
|
int sbGameVersion,
|
|
int sbMaxUpdates,
|
|
PEERBool natNegotiate,
|
|
PEERBool pingRooms[NumRooms],
|
|
PEERBool crossPingRooms[NumRooms]
|
|
)
|
|
{
|
|
char* title_A = UCS2ToUTF8StringAlloc(title);
|
|
char* qrSecretKey_A = UCS2ToUTF8StringAlloc(qrSecretKey);
|
|
char* sbName_A = UCS2ToUTF8StringAlloc(sbName);
|
|
char* sbSecretKey_A = UCS2ToUTF8StringAlloc(sbSecretKey);
|
|
PEERBool result = peerSetTitleA(peer, title_A, qrSecretKey_A, sbName_A, sbSecretKey_A, sbGameVersion, sbMaxUpdates, natNegotiate, pingRooms, crossPingRooms);
|
|
gsifree(title_A);
|
|
gsifree(qrSecretKey_A);
|
|
gsifree(sbName_A);
|
|
gsifree(sbSecretKey_A);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
void peerClearTitle(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Stop hosting if we are.
|
|
//////////////////////////
|
|
piStopHosting(peer, PEERTrue);
|
|
|
|
// Cleanup SB.
|
|
//////////////
|
|
piSBCleanup(peer);
|
|
|
|
// Cleanup title stuff.
|
|
///////////////////////
|
|
piDisconnectTitle(peer);
|
|
|
|
// Cleanup game.
|
|
////////////////
|
|
connection->title[0] = '\0';
|
|
|
|
#ifdef GSI_UNICODE
|
|
connection->title_W[0] = '\0';
|
|
#endif
|
|
|
|
// Cleanup qr secret key.
|
|
/////////////////////////
|
|
connection->qrSecretKey[0] = '\0';
|
|
}
|
|
|
|
const char* peerGetTitleA(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
if(!connection->title[0])
|
|
return NULL;
|
|
|
|
return connection->title;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
const unsigned short* peerGetTitleW(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
if(!connection->title_W[0])
|
|
return NULL;
|
|
|
|
return connection->title_W;
|
|
}
|
|
#endif
|
|
|
|
static void piDisconnectCleanup(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Chat.
|
|
////////
|
|
if(connection->chat)
|
|
chatDisconnect(connection->chat);
|
|
connection->chat = NULL;
|
|
connection->nick[0] = '\0';
|
|
connection->connecting = PEERFalse;
|
|
connection->connected = PEERFalse;
|
|
|
|
#ifdef GSI_UNICODE
|
|
connection->nick_W[0] = '\0';
|
|
#endif
|
|
|
|
// Operations.
|
|
//////////////
|
|
piOperationsReset(peer);
|
|
|
|
// Title.
|
|
/////////
|
|
piDisconnectTitle(peer);
|
|
|
|
// Away.
|
|
////////
|
|
connection->away = PEERFalse;
|
|
connection->awayReason[0] = '\0';
|
|
|
|
// We're not trying to disconnect.
|
|
//////////////////////////////////
|
|
connection->disconnect = PEERFalse;
|
|
}
|
|
|
|
static void piDisconnect(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Are we within a callback?
|
|
////////////////////////////
|
|
if(connection->callbackDepth > 0)
|
|
{
|
|
// Flag for disconnect later.
|
|
/////////////////////////////
|
|
connection->disconnect = PEERTrue;
|
|
|
|
return;
|
|
}
|
|
|
|
// Can't stay in the title room if we're disconnecting.
|
|
///////////////////////////////////////////////////////
|
|
connection->stayInTitleRoom = PEERFalse;
|
|
|
|
// Cleanup the connection.
|
|
//////////////////////////
|
|
piDisconnectCleanup(peer);
|
|
|
|
// Think to make sure the disconnected callback gets called.
|
|
////////////////////////////////////////////////////////////
|
|
piThink(peer, -1);
|
|
}
|
|
|
|
void peerDisconnect(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Do the disconnect.
|
|
/////////////////////
|
|
piDisconnect(peer);
|
|
|
|
// Check if we got shutdown in the disconnect callback.
|
|
///////////////////////////////////////////////////////
|
|
PI_CHECK_SHUTDOWN
|
|
}
|
|
|
|
static void piShutdownCleanup(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Operations.
|
|
//////////////
|
|
piOperationsCleanup(peer);
|
|
|
|
// Callbacks.
|
|
/////////////
|
|
piCallbacksCleanup(peer);
|
|
|
|
// Shut down sockets.
|
|
/////////////////////
|
|
SocketShutDown();
|
|
|
|
// Keys.
|
|
////////
|
|
piKeysCleanup(peer);
|
|
|
|
// gsifree the connection.
|
|
///////////////////////
|
|
gsifree(connection);
|
|
}
|
|
|
|
void peerShutdown(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Cleanup the connection?
|
|
//////////////////////////
|
|
if(connection->connected || connection->connecting)
|
|
{
|
|
peerDisconnectedCallback callback;
|
|
|
|
// We don't want the disconnected callback
|
|
// called if we're being explicitly shutdown.
|
|
/////////////////////////////////////////////
|
|
callback = connection->callbacks.disconnected;
|
|
connection->callbacks.disconnected = NULL;
|
|
piDisconnect(peer);
|
|
connection->callbacks.disconnected = callback;
|
|
}
|
|
|
|
// Cleanup title if needed.
|
|
///////////////////////////
|
|
if(connection->title[0])
|
|
peerClearTitle(peer);
|
|
|
|
// Are we within a callback?
|
|
////////////////////////////
|
|
if(connection->callbackDepth > 0)
|
|
{
|
|
// Flag for shutdown later.
|
|
///////////////////////////
|
|
connection->shutdown = PEERTrue;
|
|
|
|
return;
|
|
}
|
|
|
|
// Cleanup.
|
|
///////////
|
|
piShutdownCleanup(peer);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
static void piNumPlayersConsistencyCheckMap
|
|
(
|
|
piPlayer * player,
|
|
int count[NumRooms]
|
|
)
|
|
{
|
|
int i;
|
|
|
|
assert(player);
|
|
assert(count);
|
|
|
|
for(i = 0 ; i < NumRooms ; i++)
|
|
{
|
|
if(player->inRoom[i])
|
|
count[i]++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void piThink
|
|
(
|
|
PEER peer,
|
|
int opID
|
|
)
|
|
{
|
|
gsi_time now;
|
|
PEER_CONNECTION;
|
|
|
|
#ifdef _DEBUG
|
|
if(connection->players)
|
|
{
|
|
// Consistency check number of players in each room.
|
|
////////////////////////////////////////////////////
|
|
{
|
|
int count[NumRooms];
|
|
int i;
|
|
|
|
// Init the counts to 0.
|
|
////////////////////////
|
|
for(i = 0 ; i < NumRooms ; i++)
|
|
count[i] = 0;
|
|
|
|
// Map through the players checking the count.
|
|
//////////////////////////////////////////////
|
|
TableMap(connection->players, (TableMapFn)piNumPlayersConsistencyCheckMap, count);
|
|
|
|
// Check the counts.
|
|
////////////////////
|
|
for(i = 0 ; i < NumRooms ; i++)
|
|
assert(count[i] == connection->numPlayers[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
// Show info.
|
|
/////////////
|
|
{
|
|
char buffer[1024];
|
|
static int counter = -1;
|
|
|
|
counter++;
|
|
counter %= 20;
|
|
if(counter == 0)
|
|
{
|
|
sprintf(buffer,
|
|
"---------------------\n"
|
|
"operationsStarted: %d\n"
|
|
"operationsFinished: %d\n"
|
|
"callbacksQueued: %d\n"
|
|
"callbacksCalled: %d\n"
|
|
"callbackDepth: %d\n"
|
|
"titleRoomPlayers: %d\n"
|
|
"groupRoomPlayers: %d\n"
|
|
"stagingRoomPlayers: %d\n",
|
|
connection->operationsStarted,
|
|
connection->operationsFinished,
|
|
connection->callbacksQueued,
|
|
connection->callbacksCalled,
|
|
connection->callbackDepth,
|
|
connection->numPlayers[TitleRoom],
|
|
connection->numPlayers[GroupRoom],
|
|
connection->numPlayers[StagingRoom]);
|
|
OutputDebugString(buffer);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Let chat think.
|
|
//////////////////
|
|
if(connection->connected || connection->connecting)
|
|
{
|
|
chatThink(connection->chat);
|
|
|
|
// Only do this if we weren't disconnected.
|
|
///////////////////////////////////////////
|
|
if(!connection->disconnect)
|
|
{
|
|
// Is a title set?
|
|
//////////////////
|
|
if(connection->title[0])
|
|
{
|
|
// Do ping stuff.
|
|
/////////////////
|
|
piPingThink(peer);
|
|
}
|
|
|
|
// Are we connected?
|
|
////////////////////
|
|
if(connection->connected)
|
|
{
|
|
// Ge the current time.
|
|
///////////////////////
|
|
now = current_time();
|
|
|
|
// Check if we need to ping the chat server.
|
|
////////////////////////////////////////////
|
|
if((now - connection->lastChatPing) > PI_CHAT_PING_TIME)
|
|
{
|
|
// Send the ping.
|
|
/////////////////
|
|
chatSendRawA(connection->chat, "PING");
|
|
|
|
// Store the current time.
|
|
//////////////////////////
|
|
connection->lastChatPing = now;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Let SB think.
|
|
////////////////
|
|
piSBThink(peer);
|
|
|
|
// Let query-reporting think.
|
|
/////////////////////////////
|
|
piQRThink(peer);
|
|
|
|
// If we got disconnected from chat, do the cleanup before calling the callback.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
if(connection->disconnect && (connection->callbackDepth == 0))
|
|
piDisconnect(peer);
|
|
|
|
// Let the callbacks think.
|
|
///////////////////////////
|
|
piCallbacksThink(peer, opID);
|
|
}
|
|
|
|
void peerThink(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Think.
|
|
/////////
|
|
piThink(peer, -1);
|
|
|
|
PI_CHECK_SHUTDOWN
|
|
}
|
|
|
|
CHAT peerGetChat(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Return it.
|
|
/////////////
|
|
return connection->chat;
|
|
}
|
|
|
|
const char * peerGetNickA(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check if connected.
|
|
//////////////////////
|
|
if(!connection->connected)
|
|
return NULL;
|
|
|
|
// Return it.
|
|
/////////////
|
|
return connection->nick;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
const unsigned short * peerGetNickW(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
if (!connection->connected)
|
|
return NULL;
|
|
return connection->nick_W;
|
|
}
|
|
#endif
|
|
|
|
#ifndef GSI_UNICODE
|
|
void peerFixNickA
|
|
(
|
|
char * newNick,
|
|
const char * oldNick
|
|
)
|
|
{
|
|
chatFixNickA(newNick, oldNick);
|
|
}
|
|
const char * peerTranslateNickA
|
|
(
|
|
char * nick,
|
|
const char * extension
|
|
)
|
|
{
|
|
return chatTranslateNickA(nick, extension);
|
|
}
|
|
#else
|
|
void peerFixNickW
|
|
(
|
|
unsigned short * newNick,
|
|
const unsigned short * oldNick
|
|
)
|
|
{
|
|
chatFixNickW(newNick, oldNick);
|
|
}
|
|
const unsigned short * peerTranslateNickW
|
|
(
|
|
unsigned short * nick,
|
|
const unsigned short * extension
|
|
)
|
|
{
|
|
return chatTranslateNickW(nick, extension);
|
|
}
|
|
#endif
|
|
|
|
unsigned int peerGetPublicIP(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Return it.
|
|
/////////////
|
|
return connection->publicIP;
|
|
}
|
|
|
|
unsigned int peerGetPrivateIP(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Return it.
|
|
/////////////
|
|
return connection->privateIP;
|
|
}
|
|
|
|
int peerGetUserID(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
if(!connection->connected)
|
|
return 0;
|
|
|
|
return chatGetUserID(connection->chat);
|
|
}
|
|
|
|
int peerGetProfileID(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
if(!connection->connected)
|
|
return 0;
|
|
|
|
return chatGetProfileID(connection->chat);
|
|
}
|
|
|
|
void peerChangeNickA
|
|
(
|
|
PEER peer,
|
|
const char * newNick,
|
|
peerChangeNickCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(callback);
|
|
|
|
// Start the operation.
|
|
///////////////////////
|
|
if(!piNewChangeNickOperation(peer, newNick, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// Check for failure.
|
|
/////////////////////
|
|
if(!success)
|
|
piAddChangeNickCallback(peer, PEERFalse, connection->nick, newNick, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerChangeNickW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * newNick,
|
|
peerChangeNickCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* newNick_A = UCS2ToUTF8StringAlloc(newNick);
|
|
peerChangeNickA(peer, newNick_A, callback, param, blocking);
|
|
gsifree(newNick_A);
|
|
}
|
|
#endif
|
|
|
|
void peerStayInRoom
|
|
(
|
|
PEER peer,
|
|
RoomType roomType
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(roomType == TitleRoom);
|
|
if(roomType != TitleRoom)
|
|
return;
|
|
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
connection->stayInTitleRoom = PEERTrue;
|
|
}
|
|
|
|
void peerSetQuietMode
|
|
(
|
|
PEER peer,
|
|
PEERBool quiet
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
chatSetQuietMode(connection->chat, (CHATBool)quiet);
|
|
}
|
|
|
|
void peerSetAwayModeA
|
|
(
|
|
PEER peer,
|
|
const char * reason
|
|
)
|
|
{
|
|
char buffer[PI_AWAY_MAX_LEN + 6];
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
if(!reason)
|
|
reason = "";
|
|
|
|
// Store the setting.
|
|
/////////////////////
|
|
connection->away = (PEERBool)(reason[0] != '\0');
|
|
strzcpy(connection->awayReason, reason, PI_AWAY_MAX_LEN);
|
|
|
|
// Set the flags.
|
|
/////////////////
|
|
piSetLocalFlags(peer);
|
|
|
|
// Send the chat command.
|
|
/////////////////////////
|
|
sprintf(buffer, "AWAY :%s", connection->awayReason);
|
|
chatSendRawA(connection->chat, buffer);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerSetAwayModeW
|
|
(
|
|
PEER peer,
|
|
const unsigned short* reason
|
|
)
|
|
{
|
|
char* reason_A = UCS2ToUTF8StringAlloc(reason);
|
|
peerSetAwayModeA(peer, reason_A);
|
|
gsifree(reason_A);
|
|
}
|
|
#endif
|
|
|
|
void peerParseQueryA
|
|
(
|
|
PEER peer,
|
|
char * query,
|
|
int len,
|
|
struct sockaddr * sender
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
assert(query);
|
|
assert(sender);
|
|
|
|
// Handle the query based on what type of reporting we're doing.
|
|
////////////////////////////////////////////////////////////////
|
|
if(connection->queryReporting)
|
|
qr2_parse_queryA(connection->queryReporting, query, len, sender);
|
|
else if(connection->autoMatchReporting)
|
|
qr2_parse_queryA(connection->autoMatchReporting, query, len, sender);
|
|
}
|
|
/* NOT necessary since qr2_parse_query uses char not unsigned short
|
|
#ifdef GSI_UNICODE
|
|
void peerParseQueryW
|
|
(
|
|
PEER peer,
|
|
unsigned short * query,
|
|
int len,
|
|
struct sockaddr * sender
|
|
)
|
|
{
|
|
char* query_A = UCS2ToUTF8StringAlloc(query);
|
|
peerParseQueryA(peer, query_A, len, sender);
|
|
gsifree(query_A);
|
|
}
|
|
#endif
|
|
*/
|
|
void peerAuthenticateCDKeyA
|
|
(
|
|
PEER peer,
|
|
const char * cdkey,
|
|
peerAuthenticateCDKeyCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(callback);
|
|
|
|
// Start the operation.
|
|
///////////////////////
|
|
if(!piNewAuthenticateCDKeyOperation(peer, cdkey, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// Check for failure.
|
|
/////////////////////
|
|
if(!success)
|
|
piAddAuthenticateCDKeyCallback(peer, 0, "Error starting CD Key check", callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerAuthenticateCDKeyW
|
|
(
|
|
PEER peer,
|
|
const unsigned short* cdkey,
|
|
peerAuthenticateCDKeyCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* cdkey_A = UCS2ToUTF8StringAlloc(cdkey);
|
|
peerAuthenticateCDKeyA(peer, cdkey_A, callback, param, blocking);
|
|
gsifree(cdkey_A);
|
|
}
|
|
#endif
|
|
|
|
void peerSendNatNegotiateCookie
|
|
(
|
|
PEER peer,
|
|
unsigned int ip,
|
|
unsigned short port,
|
|
int cookie
|
|
)
|
|
{
|
|
piSendNatNegotiateCookie(peer, ip, port, cookie);
|
|
}
|
|
|
|
void peerSendMessageToServer
|
|
(
|
|
PEER peer,
|
|
unsigned int ip,
|
|
unsigned short port,
|
|
const char * data,
|
|
int len
|
|
)
|
|
{
|
|
piSendMessageToServer(peer, ip, port, data, len);
|
|
}
|
|
|
|
void peerAlwaysGetPlayerInfo
|
|
(
|
|
PEER peer,
|
|
PEERBool always
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
connection->alwaysRequestPlayerInfo = always;
|
|
}
|
|
|
|
/**********
|
|
** ROOMS **
|
|
**********/
|
|
void peerJoinTitleRoomA
|
|
(
|
|
PEER peer,
|
|
const char password[PEER_PASSWORD_LEN],
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
PEERJoinResult result = PEERJoinFailed;
|
|
char buffer[PI_ROOM_MAX_LEN];
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(callback);
|
|
|
|
// NULL password is the same as empty password.
|
|
///////////////////////////////////////////////
|
|
if(!password)
|
|
password = "";
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERNoTitleSet;
|
|
}
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(success && !connection->connected)
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERNoConnection;
|
|
}
|
|
|
|
// Check if we're in the title room.
|
|
////////////////////////////////////
|
|
assert(!connection->enteringRoom[TitleRoom] && !connection->inRoom[TitleRoom]);
|
|
if((success && connection->enteringRoom[TitleRoom]) || connection->inRoom[TitleRoom])
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERAlreadyInRoom;
|
|
}
|
|
|
|
// Check if we're AutoMatching.
|
|
///////////////////////////////
|
|
assert(!peerIsAutoMatching(peer));
|
|
if(success && peerIsAutoMatching(peer))
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERAutoMatching;
|
|
}
|
|
|
|
// Get the room name.
|
|
/////////////////////
|
|
if(success)
|
|
{
|
|
if(connection->titleRoomChannel[0])
|
|
strcpy(buffer, connection->titleRoomChannel);
|
|
else
|
|
piMangleTitleRoom(buffer, connection->title);
|
|
}
|
|
|
|
// Start the operation.
|
|
///////////////////////
|
|
if(success && !piNewJoinRoomOperation(peer, TitleRoom, buffer, password, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// Check for failure.
|
|
/////////////////////
|
|
if(!success)
|
|
piAddJoinRoomCallback(peer, PEERFalse, result, TitleRoom, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerJoinTitleRoomW
|
|
(
|
|
PEER peer,
|
|
const unsigned short password[PEER_PASSWORD_LEN],
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* password_A = NULL;
|
|
if (password != NULL)
|
|
password_A = UCS2ToUTF8StringAlloc(password);
|
|
peerJoinTitleRoomA(peer, password_A, callback, param, blocking);
|
|
gsifree(password_A);
|
|
}
|
|
#endif
|
|
|
|
void peerJoinGroupRoom
|
|
(
|
|
PEER peer,
|
|
int groupID,
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
PEERJoinResult result = PEERJoinFailed;
|
|
char room[PI_ROOM_MAX_LEN];
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(callback);
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERNoTitleSet;
|
|
}
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(success && !connection->connected)
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERNoConnection;
|
|
}
|
|
|
|
// Check if we're AutoMatching.
|
|
///////////////////////////////
|
|
assert(!peerIsAutoMatching(peer));
|
|
if(success && peerIsAutoMatching(peer))
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERAutoMatching;
|
|
}
|
|
|
|
// Check the ID.
|
|
////////////////
|
|
assert(groupID);
|
|
if(success && !groupID)
|
|
success = PEERFalse;
|
|
|
|
// Check if we're in a group room.
|
|
//////////////////////////////////
|
|
if(success && (connection->enteringRoom[GroupRoom] || connection->inRoom[GroupRoom]))
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERAlreadyInRoom;
|
|
}
|
|
|
|
// Create the name.
|
|
///////////////////
|
|
piMangleGroupRoom(room, groupID);
|
|
|
|
// Save off the group id.
|
|
/////////////////////////
|
|
connection->groupID = groupID;
|
|
|
|
// Start the operation.
|
|
///////////////////////
|
|
if(success && !piNewJoinRoomOperation(peer, GroupRoom, room, NULL, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// Check for failure.
|
|
/////////////////////
|
|
if(!success)
|
|
piAddJoinRoomCallback(peer, PEERFalse, result, GroupRoom, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
|
|
void peerSetGroupID
|
|
(
|
|
PEER peer,
|
|
int groupID
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Save off the group id.
|
|
/////////////////////////
|
|
connection->groupID = groupID;
|
|
}
|
|
|
|
int peerGetGroupID
|
|
(
|
|
PEER peer
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return 0;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return 0;
|
|
|
|
// Get the group id.
|
|
////////////////////
|
|
return connection->groupID;
|
|
}
|
|
|
|
static void piJoinStagingRoom
|
|
(
|
|
PEER peer,
|
|
SBServer server,
|
|
const char * channel,
|
|
const char password[PEER_PASSWORD_LEN],
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
unsigned int publicIP = 0;
|
|
unsigned int privateIP = 0;
|
|
unsigned short privatePort = 0;
|
|
char room[PI_ROOM_MAX_LEN];
|
|
PEERBool success = PEERTrue;
|
|
PEERJoinResult result = PEERJoinFailed;
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(callback);
|
|
|
|
// NULL password is the same as empty password.
|
|
///////////////////////////////////////////////
|
|
if(!password)
|
|
password = "";
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERNoTitleSet;
|
|
}
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(success && !connection->connected)
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERNoConnection;
|
|
}
|
|
|
|
// Check if we're in a staging room.
|
|
////////////////////////////////////
|
|
if(success && (connection->enteringRoom[StagingRoom] || connection->inRoom[StagingRoom]))
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERAlreadyInRoom;
|
|
}
|
|
|
|
// Check if we're AutoMatching.
|
|
///////////////////////////////
|
|
assert(!peerIsAutoMatching(peer));
|
|
if(success && peerIsAutoMatching(peer))
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERAutoMatching;
|
|
}
|
|
|
|
// If we have a server, get the public and private IPs and ports.
|
|
/////////////////////////////////////////////////////////////////
|
|
if(success && server)
|
|
{
|
|
publicIP = SBServerGetPublicInetAddress(server);
|
|
privateIP = SBServerGetPrivateInetAddress(server);
|
|
if(SBServerHasPrivateAddress(server))
|
|
privatePort = SBServerGetPrivateQueryPort(server);
|
|
else
|
|
privatePort = SBServerGetPublicQueryPort(server);
|
|
|
|
if(!publicIP)
|
|
success = PEERFalse;
|
|
}
|
|
|
|
// If we have a channel, check it.
|
|
//////////////////////////////////
|
|
if(success && !server)
|
|
{
|
|
assert(channel);
|
|
assert(channel[0]);
|
|
if(!channel || !channel[0])
|
|
success = PEERFalse;
|
|
}
|
|
|
|
// Stop hosting.
|
|
////////////////
|
|
if(success)
|
|
piStopHosting(peer, PEERTrue);
|
|
|
|
// If we have a server, get the staging room.
|
|
/////////////////////////////////////////////
|
|
if(success && server)
|
|
piMangleStagingRoom(room, connection->title, publicIP, privateIP, privatePort);
|
|
|
|
// Start the operation.
|
|
///////////////////////
|
|
if(success && !piNewJoinRoomOperation(peer, StagingRoom, server?room:channel, password, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// If we have a server, clone it.
|
|
/////////////////////////////////
|
|
if(success && server)
|
|
connection->hostServer = piSBCloneServer(server);
|
|
|
|
// Check for failure.
|
|
/////////////////////
|
|
if(!success)
|
|
piAddJoinRoomCallback(peer, PEERFalse, result, StagingRoom, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
|
|
void peerJoinStagingRoomA
|
|
(
|
|
PEER peer,
|
|
SBServer server,
|
|
const char password[PEER_PASSWORD_LEN],
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
piJoinStagingRoom(peer, server, NULL, password, callback, param, blocking);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerJoinStagingRoomW
|
|
(
|
|
PEER peer,
|
|
SBServer server,
|
|
const unsigned short password[PEER_PASSWORD_LEN],
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* password_A = UCS2ToUTF8StringAlloc(password);
|
|
peerJoinStagingRoomA(peer, server, password_A, callback, param, blocking);
|
|
gsifree(password_A);
|
|
}
|
|
#endif
|
|
|
|
void peerJoinStagingRoomByChannelA
|
|
(
|
|
PEER peer,
|
|
const char * channel,
|
|
const char password[PEER_PASSWORD_LEN],
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
piJoinStagingRoom(peer, NULL, channel, password, callback, param, blocking);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerJoinStagingRoomByChannelW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * channel,
|
|
const unsigned short password[PEER_PASSWORD_LEN],
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
|
char* password_A = UCS2ToUTF8StringAlloc(password);
|
|
peerJoinStagingRoomByChannelA(peer, channel_A, password_A, callback, param, blocking);
|
|
gsifree(password_A);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
void peerCreateStagingRoomA
|
|
(
|
|
PEER peer,
|
|
const char * name,
|
|
int maxPlayers,
|
|
const char password[PEER_PASSWORD_LEN],
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
peerCreateStagingRoomWithSocketA(peer, name, maxPlayers, password, INVALID_SOCKET, 0, callback, param, blocking);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerCreateStagingRoomW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * name,
|
|
int maxPlayers,
|
|
const unsigned short password[PEER_PASSWORD_LEN],
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* name_A = UCS2ToUTF8StringAlloc(name);
|
|
char* password_A = UCS2ToUTF8StringAlloc(password);
|
|
peerCreateStagingRoomA(peer, name_A, maxPlayers, password_A, callback, param, blocking);
|
|
gsifree(password_A);
|
|
gsifree(name_A);
|
|
}
|
|
#endif
|
|
|
|
void peerCreateStagingRoomWithSocketA
|
|
(
|
|
PEER peer,
|
|
const char * name,
|
|
int maxPlayers,
|
|
const char password[PEER_PASSWORD_LEN],
|
|
SOCKET socket,
|
|
unsigned short port,
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
PEERJoinResult result = PEERJoinFailed;
|
|
PI_OP_ID;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(name);
|
|
assert(connection->title[0]);
|
|
assert(callback);
|
|
assert(maxPlayers >= 0);
|
|
|
|
// NULL password is the same as empty password.
|
|
///////////////////////////////////////////////
|
|
if(!password)
|
|
password = "";
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERNoTitleSet;
|
|
}
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(success && !connection->connected)
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERNoConnection;
|
|
}
|
|
|
|
// Check if we're in a staging room.
|
|
////////////////////////////////////
|
|
if(success && (connection->enteringRoom[StagingRoom] || connection->inRoom[StagingRoom]))
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERAlreadyInRoom;
|
|
}
|
|
|
|
// Check if we're AutoMatching.
|
|
///////////////////////////////
|
|
assert(!peerIsAutoMatching(peer));
|
|
if(success && peerIsAutoMatching(peer))
|
|
{
|
|
success = PEERFalse;
|
|
result = PEERAutoMatching;
|
|
}
|
|
|
|
// Stop hosting.
|
|
////////////////
|
|
if(success)
|
|
piStopHosting(peer, PEERTrue);
|
|
|
|
// Start the operation.
|
|
///////////////////////
|
|
if(success && !piNewCreateStagingRoomOperation(peer, name, password, maxPlayers, socket, port, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// Add callback if error.
|
|
/////////////////////////
|
|
if(!success)
|
|
piAddJoinRoomCallback(peer, PEERFalse, result, StagingRoom, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerCreateStagingRoomWithSocketW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * name,
|
|
int maxPlayers,
|
|
const unsigned short password[PEER_PASSWORD_LEN],
|
|
SOCKET socket,
|
|
unsigned short port,
|
|
peerJoinRoomCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* name_A = UCS2ToUTF8StringAlloc(name);
|
|
char* password_A = UCS2ToUTF8StringAlloc(password);
|
|
peerCreateStagingRoomWithSocketA(peer, name_A, maxPlayers, password_A, socket, port, callback, param, blocking);
|
|
gsifree(password_A);
|
|
gsifree(name_A);
|
|
}
|
|
#endif
|
|
|
|
// Should only be called when a game report is already in progress
|
|
// Always call after creating staging room, starting reporting,
|
|
// starting automatch
|
|
//////////////////////////////////////////////////////////////////////////
|
|
/*
|
|
qr2_t peerGetReportingRecord(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
if (!connection->title[0])
|
|
return NULL;
|
|
|
|
if (!connection->connected)
|
|
return NULL;
|
|
|
|
assert(connection->queryReporting || connection->autoMatchReporting);
|
|
// When we are reporting normal games, the normal qr2 record
|
|
// is returned.
|
|
if (connection->queryReporting)
|
|
{
|
|
return connection->queryReporting;
|
|
}
|
|
|
|
|
|
// When we are reporting automatch games, the automatch qr2 record
|
|
// is returned.
|
|
if (peerIsAutoMatching(peer) && connection->autoMatchReporting)
|
|
{
|
|
return connection->autoMatchReporting;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
*/
|
|
|
|
void peerLeaveRoomA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * reason
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Check if we're in or entering.
|
|
/////////////////////////////////
|
|
if(!ENTERING_ROOM && !IN_ROOM)
|
|
return;
|
|
|
|
// Leave.
|
|
/////////
|
|
piLeaveRoom(peer, roomType, reason);
|
|
|
|
// Is this an AutoMatch room?
|
|
/////////////////////////////
|
|
if((roomType == StagingRoom) && peerIsAutoMatching(peer))
|
|
{
|
|
// Go back to searching.
|
|
////////////////////////
|
|
piSetAutoMatchStatus(peer, PEERSearching);
|
|
}
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerLeaveRoomW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const unsigned short* reason
|
|
)
|
|
{
|
|
if (reason != NULL)
|
|
{
|
|
char* reason_A = UCS2ToUTF8StringAlloc(reason);
|
|
peerLeaveRoomA(peer, roomType, reason_A);
|
|
gsifree(reason_A);
|
|
}
|
|
else
|
|
peerLeaveRoomA(peer, roomType, NULL);
|
|
}
|
|
#endif
|
|
|
|
void peerListGroupRoomsA
|
|
(
|
|
PEER peer,
|
|
const char * fields,
|
|
peerListGroupRoomsCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
|
|
assert(callback);
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
success = PEERFalse;
|
|
|
|
// Can't have a NULL fields.
|
|
////////////////////////////
|
|
if(!fields)
|
|
fields = "";
|
|
|
|
// Start the listing.
|
|
/////////////////////
|
|
if(success && !piNewListGroupRoomsOperation(peer, fields, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// Call the callback if failed.
|
|
///////////////////////////////
|
|
if(!success)
|
|
piAddListGroupRoomsCallback(peer, PEERFalse, 0, NULL, NULL, 0, 0, 0, 0, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerListGroupRoomsW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * fields,
|
|
peerListGroupRoomsCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* fields_A = UCS2ToUTF8StringAlloc(fields);
|
|
peerListGroupRoomsA(peer, fields_A, callback, param, blocking);
|
|
gsifree(fields_A);
|
|
}
|
|
#endif
|
|
|
|
void peerStartListingGamesA
|
|
(
|
|
PEER peer,
|
|
const unsigned char * fields,
|
|
int numFields,
|
|
const char * filter,
|
|
peerListingGamesCallback callback,
|
|
void * param
|
|
)
|
|
{
|
|
PEERBool success;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(callback);
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Can't have an empty filter.
|
|
//////////////////////////////
|
|
if(filter && !filter[0])
|
|
filter = NULL;
|
|
|
|
// Check the fields.
|
|
////////////////////
|
|
if(!fields || (numFields <= 0))
|
|
numFields = 0;
|
|
|
|
// Save the callback info.
|
|
//////////////////////////
|
|
connection->gameListCallback = callback;
|
|
connection->gameListParam = param;
|
|
|
|
// Start the listing.
|
|
/////////////////////
|
|
success = piSBStartListingGames(peer, fields, numFields, filter);
|
|
|
|
// Call the callback if failed.
|
|
///////////////////////////////
|
|
if(!success)
|
|
piAddListingGamesCallback(peer, PEERFalse, NULL, 0);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerStartListingGamesW
|
|
(
|
|
PEER peer,
|
|
const unsigned char * fields,
|
|
int numFields,
|
|
const unsigned short * filter,
|
|
peerListingGamesCallback callback,
|
|
void * param
|
|
)
|
|
{
|
|
char* filter_A = UCS2ToUTF8StringAlloc(filter);
|
|
peerStartListingGamesA(peer, fields, numFields, filter_A, callback, param);
|
|
gsifree(filter_A);
|
|
}
|
|
#endif
|
|
|
|
void peerStopListingGames
|
|
(
|
|
PEER peer
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Stop the listing.
|
|
////////////////////
|
|
piSBStopListingGames(peer);
|
|
}
|
|
|
|
void peerUpdateGame
|
|
(
|
|
PEER peer,
|
|
SBServer server,
|
|
PEERBool fullUpdate
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
assert(server);
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Update the server.
|
|
// Changed 08-26-2004
|
|
// Saad Nader
|
|
// Added force update by master server parameter
|
|
// for internal update function
|
|
/////////////////////
|
|
piSBUpdateGame(peer, server, fullUpdate, PEERFalse, PEERFalse);
|
|
}
|
|
|
|
// Added 08-26-2004
|
|
// By Saad Nader
|
|
// per request of developer
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void peerUpdateGameByMaster(PEER peer, SBServer server, PEERBool fullUpdate)
|
|
{
|
|
// obtain and check the peer connection object
|
|
PEER_CONNECTION;
|
|
|
|
// validate server for sanity check
|
|
assert(server);
|
|
|
|
// Check that we have set a title
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Let internal update take place via the master server
|
|
piSBUpdateGame(peer, server, fullUpdate, PEERTrue, PEERFalse);
|
|
}
|
|
|
|
void peerUpdateGamePing(PEER peer, SBServer server)
|
|
{
|
|
// obtain and check the peer connection object
|
|
PEER_CONNECTION;
|
|
|
|
// validate server for sanity check
|
|
assert(server);
|
|
|
|
// Check that we have set a title
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Let internal update take place via the master server
|
|
piSBUpdateGame(peer, server, PEERFalse, PEERFalse, PEERTrue);
|
|
}
|
|
|
|
void peerMessageRoomA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * message,
|
|
MessageType messageType
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
ASSERT_MESSAGETYPE(messageType);
|
|
|
|
// Check for no message.
|
|
////////////////////////
|
|
if(!message || !message[0])
|
|
return;
|
|
|
|
// Check that we're in this room.
|
|
/////////////////////////////////
|
|
assert(IN_ROOM);
|
|
if(!IN_ROOM)
|
|
return;
|
|
|
|
// Send the message.
|
|
////////////////////
|
|
chatSendChannelMessageA(connection->chat, ROOM, message, (int)messageType);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerMessageRoomW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const unsigned short * message,
|
|
MessageType messageType
|
|
)
|
|
{
|
|
char* message_A = UCS2ToUTF8StringAlloc(message);
|
|
peerMessageRoomA(peer, roomType, message_A, messageType);
|
|
gsifree(message_A);
|
|
}
|
|
#endif
|
|
|
|
void peerUTMRoomA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * command,
|
|
const char * parameters,
|
|
PEERBool authenticate
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
|
|
// Check that we're in this room.
|
|
/////////////////////////////////
|
|
assert(IN_ROOM);
|
|
if(!IN_ROOM)
|
|
return;
|
|
|
|
// Send it.
|
|
///////////
|
|
piSendChannelUTM(peer, ROOM, command, parameters, authenticate);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerUTMRoomW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const unsigned short * command,
|
|
const unsigned short * parameters,
|
|
PEERBool authenticate
|
|
)
|
|
{
|
|
char* command_A = UCS2ToUTF8StringAlloc(command);
|
|
char* parameters_A = UCS2ToUTF8StringAlloc(parameters);
|
|
peerUTMRoomA(peer, roomType, command_A, parameters_A, authenticate);
|
|
gsifree(parameters_A);
|
|
gsifree(command_A);
|
|
}
|
|
#endif
|
|
|
|
void peerSetPasswordA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char password[PEER_PASSWORD_LEN]
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
|
|
// Check room type.
|
|
////////////////////
|
|
assert(roomType == StagingRoom);
|
|
if(roomType != StagingRoom)
|
|
return;
|
|
|
|
// NULL password is the same as empty password.
|
|
///////////////////////////////////////////////
|
|
if(!password)
|
|
password = "";
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Check if we're in or entering.
|
|
/////////////////////////////////
|
|
if(!ENTERING_ROOM && !IN_ROOM)
|
|
return;
|
|
|
|
// Make sure we're hosting.
|
|
///////////////////////////
|
|
assert(connection->hosting);
|
|
if(!connection->hosting)
|
|
return;
|
|
|
|
// Set/clear the password.
|
|
//////////////////////////
|
|
if(password[0])
|
|
chatSetChannelPasswordA(connection->chat, ROOM, CHATTrue, password);
|
|
else
|
|
chatSetChannelPasswordA(connection->chat, ROOM, CHATFalse, "x");
|
|
|
|
// Set the passworded flag.
|
|
///////////////////////////
|
|
connection->passwordedRoom = password[0]?PEERTrue:PEERFalse;
|
|
|
|
// Send a state-changed.
|
|
////////////////////////
|
|
piSendStateChanged(peer);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerSetPasswordW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const unsigned short password[PEER_PASSWORD_LEN]
|
|
)
|
|
{
|
|
char* password_A = UCS2ToUTF8StringAlloc(password);
|
|
peerSetPasswordA(peer, roomType, password_A);
|
|
gsifree(password_A);
|
|
}
|
|
#endif
|
|
|
|
void peerSetRoomNameA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * name
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
|
|
assert(roomType == StagingRoom);
|
|
|
|
// NULL name is the same as empty name.
|
|
///////////////////////////////////////
|
|
if(!name)
|
|
name = "";
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Check if we're in or entering.
|
|
/////////////////////////////////
|
|
if(!ENTERING_ROOM && !IN_ROOM)
|
|
return;
|
|
|
|
// Make sure we're hosting.
|
|
///////////////////////////
|
|
assert(connection->hosting);
|
|
if(!connection->hosting)
|
|
return;
|
|
|
|
// Set it.
|
|
//////////
|
|
chatSetChannelTopicA(connection->chat, ROOM, name);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerSetRoomNameW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const unsigned short * name
|
|
)
|
|
{
|
|
char* name_A = UCS2ToUTF8StringAlloc(name);
|
|
peerSetRoomNameA(peer, roomType, name_A);
|
|
gsifree(name_A);
|
|
}
|
|
#endif
|
|
|
|
const char * peerGetRoomNameA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
assert(IN_ROOM);
|
|
if(!IN_ROOM)
|
|
return NULL;
|
|
|
|
return NAME;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
const unsigned short * peerGetRoomNameW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
assert(IN_ROOM);
|
|
if(!IN_ROOM)
|
|
return NULL;
|
|
|
|
return NAME_W;
|
|
}
|
|
#endif
|
|
|
|
const char * peerGetRoomChannelA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
assert(IN_ROOM || ENTERING_ROOM);
|
|
if(!IN_ROOM && ! ENTERING_ROOM)
|
|
return NULL;
|
|
|
|
return ROOM;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
const unsigned short * peerGetRoomChannelW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
assert(IN_ROOM || ENTERING_ROOM);
|
|
if(!IN_ROOM && ! ENTERING_ROOM)
|
|
return NULL;
|
|
|
|
return ROOM_W;
|
|
}
|
|
#endif
|
|
|
|
PEERBool peerInRoom
|
|
(
|
|
PEER peer,
|
|
RoomType roomType
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
|
|
return IN_ROOM;
|
|
}
|
|
|
|
void peerSetTitleRoomChannelA
|
|
(
|
|
PEER peer,
|
|
const char * channel
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Check for no channel.
|
|
////////////////////////
|
|
if(!channel)
|
|
channel = "";
|
|
|
|
// Copy it.
|
|
///////////
|
|
strzcpy(connection->titleRoomChannel, channel, PI_ROOM_MAX_LEN);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerSetTitleRoomChannelW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * channel
|
|
)
|
|
{
|
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
|
peerSetTitleRoomChannelA(peer, channel_A);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
SBServer peerGetHostServer(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
return connection->hostServer;
|
|
}
|
|
|
|
/************
|
|
** PLAYERS **
|
|
************/
|
|
typedef struct piEnumPlayersData
|
|
{
|
|
peerEnumPlayersCallback callback;
|
|
void * param;
|
|
} piEnumPlayersData;
|
|
|
|
static void piEnumPlayersEnumRoomPlayersCallback
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
piPlayer * player,
|
|
int index,
|
|
void *param
|
|
)
|
|
{
|
|
piEnumPlayersData * data = (piEnumPlayersData *)param;
|
|
const char * nick;
|
|
|
|
int flags;
|
|
|
|
if(player)
|
|
{
|
|
nick = player->nick;
|
|
flags = player->flags[roomType];
|
|
}
|
|
else
|
|
{
|
|
nick = NULL;
|
|
flags = 0;
|
|
}
|
|
|
|
// Call the callback.
|
|
/////////////////////
|
|
#ifndef GSI_UNICODE
|
|
data->callback(peer, PEERTrue, roomType, index, nick, flags, data->param);
|
|
#else
|
|
if (nick == NULL)
|
|
data->callback(peer, PEERTrue, roomType, index, NULL, flags, data->param);
|
|
else
|
|
{
|
|
unsigned short nick_W[512];
|
|
UTF8ToUCS2String(nick, nick_W);
|
|
data->callback(peer, PEERTrue, roomType, index, nick_W, flags, data->param);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void peerEnumPlayers
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
peerEnumPlayersCallback callback,
|
|
void * param
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
piEnumPlayersData data;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(callback);
|
|
ASSERT_ROOMTYPE(roomType);
|
|
|
|
// Check that we're in this room.
|
|
/////////////////////////////////
|
|
assert(IN_ROOM);
|
|
if(success && !IN_ROOM)
|
|
success = PEERFalse;
|
|
|
|
// Check for failure.
|
|
/////////////////////
|
|
if(!success)
|
|
{
|
|
// Call the callback.
|
|
/////////////////////
|
|
callback(peer, PEERFalse, roomType, -1, NULL, PEERFalse, param);
|
|
return;
|
|
}
|
|
|
|
// Enumerate through the players, using a local copy.
|
|
/////////////////////////////////////////////////////
|
|
data.callback = callback;
|
|
data.param = param;
|
|
piEnumRoomPlayers(peer, roomType, piEnumPlayersEnumRoomPlayersCallback, &data);
|
|
}
|
|
|
|
void peerMessagePlayerA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
const char * message,
|
|
MessageType messageType
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_MESSAGETYPE(messageType);
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
|
|
// Check for connection succeeded.
|
|
//////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Check for no message.
|
|
////////////////////////
|
|
if(!message || !message[0])
|
|
return;
|
|
|
|
// Send the message to this player.
|
|
///////////////////////////////////
|
|
chatSendUserMessageA(connection->chat, nick, message, (int)messageType);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerMessagePlayerW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
const unsigned short * message,
|
|
MessageType messageType
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
char* message_A = UCS2ToUTF8StringAlloc(message);
|
|
peerMessagePlayerA(peer, nick_A, message_A, messageType);
|
|
gsifree(nick_A);
|
|
gsifree(message_A);
|
|
}
|
|
#endif
|
|
|
|
void peerUTMPlayerA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
const char * command,
|
|
const char * parameters,
|
|
PEERBool authenticate
|
|
)
|
|
{
|
|
// Send it.
|
|
///////////
|
|
piSendPlayerUTM(peer, nick, command, parameters, authenticate);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerUTMPlayerW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
const unsigned short * command,
|
|
const unsigned short * parameters,
|
|
PEERBool authenticate
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
char* command_A = UCS2ToUTF8StringAlloc(command);
|
|
char* parameters_A = UCS2ToUTF8StringAlloc(parameters);
|
|
peerUTMPlayerA(peer, nick_A, command_A, parameters_A, authenticate);
|
|
gsifree(parameters_A);
|
|
gsifree(command_A);
|
|
gsifree(nick_A);
|
|
}
|
|
#endif
|
|
|
|
void peerKickPlayerA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * nick,
|
|
const char * reason
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
assert(IN_ROOM || ENTERING_ROOM);
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
|
|
// Check for connection succeeded.
|
|
//////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Kick the player.
|
|
///////////////////
|
|
chatKickUserA(connection->chat, ROOM, nick, reason);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerKickPlayerW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const unsigned short * nick,
|
|
const unsigned short * reason
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
char* reason_A = UCS2ToUTF8StringAlloc(reason);
|
|
peerKickPlayerA(peer, roomType, nick_A, reason_A);
|
|
gsifree(reason_A);
|
|
gsifree(nick_A);
|
|
}
|
|
#endif
|
|
|
|
PEERBool peerGetPlayerPingA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
int * ping
|
|
)
|
|
{
|
|
piPlayer * player;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
assert(ping);
|
|
|
|
// Get the player.
|
|
//////////////////
|
|
player = piGetPlayer(peer, nick);
|
|
if(!player)
|
|
return PEERFalse;
|
|
|
|
// Is it the local player?
|
|
//////////////////////////
|
|
if(player->local)
|
|
{
|
|
*ping = 0;
|
|
}
|
|
else
|
|
{
|
|
// Check if there's a ping.
|
|
///////////////////////////
|
|
if(!player->numPings)
|
|
return PEERFalse;
|
|
|
|
*ping = player->pingAverage;
|
|
}
|
|
|
|
return PEERTrue;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
PEERBool peerGetPlayerPingW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
int * ping
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
PEERBool result = peerGetPlayerPingA(peer, nick_A, ping);
|
|
gsifree(nick_A);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
PEERBool peerGetPlayersCrossPingA
|
|
(
|
|
PEER peer,
|
|
const char * nick1,
|
|
const char * nick2,
|
|
int * crossPing
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(nick1);
|
|
assert(nick1[0]);
|
|
assert(nick2);
|
|
assert(nick2[0]);
|
|
assert(crossPing);
|
|
|
|
// Do it.
|
|
/////////
|
|
return piGetXping(peer, nick1, nick2, crossPing);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
PEERBool peerGetPlayersCrossPingW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick1,
|
|
const unsigned short * nick2,
|
|
int * crossPing
|
|
)
|
|
{
|
|
char* nick1_A = UCS2ToUTF8StringAlloc(nick1);
|
|
char* nick2_A = UCS2ToUTF8StringAlloc(nick2);
|
|
PEERBool result = peerGetPlayersCrossPingA(peer, nick1_A, nick2_A, crossPing);
|
|
gsifree(nick2_A);
|
|
gsifree(nick1_A);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
PEERBool peerPingPlayerA
|
|
(
|
|
PEER peer,
|
|
const char * nick
|
|
)
|
|
{
|
|
piPlayer * player;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
|
|
// Get the player.
|
|
//////////////////
|
|
player = piGetPlayer(peer, nick);
|
|
if(!player)
|
|
return PEERFalse;
|
|
|
|
// Is it the local player?
|
|
//////////////////////////
|
|
if(player->local)
|
|
return PEERFalse;
|
|
|
|
// Do we have the IP?
|
|
/////////////////////
|
|
if(!player->gotIPAndProfileID)
|
|
return PEERFalse;
|
|
|
|
// Is the player already being pinged?
|
|
//////////////////////////////////////
|
|
if(player->waitingForPing)
|
|
return PEERTrue;
|
|
|
|
// Set this player as a must ping.
|
|
//////////////////////////////////
|
|
player->mustPing = PEERTrue;
|
|
|
|
// Set this player as a one-time ping.
|
|
//////////////////////////////////////
|
|
if(!player->inPingRoom)
|
|
player->pingOnce = PEERTrue;
|
|
|
|
return PEERTrue;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
PEERBool peerPingPlayerW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
PEERBool result = peerPingPlayerA(peer, nick_A);
|
|
gsifree(nick_A);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
PEERBool peerGetPlayerInfoNoWaitA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
unsigned int * IP,
|
|
int * profileID
|
|
)
|
|
{
|
|
piPlayer * player;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(nick);
|
|
|
|
player = piGetPlayer(peer, nick);
|
|
if(!player || !player->gotIPAndProfileID)
|
|
{
|
|
const char * info;
|
|
unsigned int locIP;
|
|
int locProfileID;
|
|
|
|
// Can we get it from chat?
|
|
///////////////////////////
|
|
if(chatGetBasicUserInfoNoWaitA(connection->chat, nick, &info, NULL) && piDemangleUser(info, &locIP, &locProfileID))
|
|
{
|
|
if(player)
|
|
piSetPlayerIPAndProfileID(peer, nick, locIP, locProfileID);
|
|
|
|
if(IP)
|
|
*IP = locIP;
|
|
if(profileID)
|
|
*profileID = locProfileID;
|
|
|
|
return PEERTrue;
|
|
}
|
|
return PEERFalse;
|
|
}
|
|
|
|
if(IP)
|
|
*IP = player->IP;
|
|
if(profileID)
|
|
*profileID = player->profileID;
|
|
|
|
return PEERTrue;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
PEERBool peerGetPlayerInfoNoWaitW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
unsigned int * IP,
|
|
int * profileID
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
PEERBool result = peerGetPlayerInfoNoWaitA(peer, nick_A, IP, profileID);
|
|
gsifree(nick_A);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
void peerGetPlayerInfoA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
peerGetPlayerInfoCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
piPlayer * player;
|
|
PI_OP_ID;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(callback);
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
assert(callback);
|
|
|
|
// Find the player.
|
|
///////////////////
|
|
player = piGetPlayer(peer, nick);
|
|
|
|
// Check if chat has it.
|
|
////////////////////////
|
|
if(player && !player->gotIPAndProfileID)
|
|
{
|
|
const char * info;
|
|
unsigned int IP;
|
|
int profileID;
|
|
|
|
if(chatGetBasicUserInfoNoWaitA(connection->chat, nick, &info, NULL) && piDemangleUser(info, &IP, &profileID))
|
|
{
|
|
piSetPlayerIPAndProfileID(peer, nick, IP, profileID);
|
|
}
|
|
}
|
|
|
|
// See if we already have it.
|
|
/////////////////////////////
|
|
if(player && player->gotIPAndProfileID)
|
|
{
|
|
piAddGetPlayerInfoCallback(peer, PEERTrue, nick, player->IP, player->profileID, callback, param, opID);
|
|
}
|
|
else
|
|
{
|
|
// Start an op to get it.
|
|
/////////////////////////
|
|
if(!piNewGetPlayerInfoOperation(peer, nick, callback, param, opID))
|
|
success = PEERFalse;
|
|
}
|
|
|
|
// If failed, add the callback.
|
|
///////////////////////////////
|
|
if(!success)
|
|
piAddGetPlayerInfoCallback(peer, PEERFalse, nick, 0, 0, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerGetPlayerInfoW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
peerGetPlayerInfoCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
peerGetPlayerInfoA(peer, nick_A, callback, param, blocking);
|
|
gsifree(nick_A);
|
|
}
|
|
#endif
|
|
|
|
void peerGetPlayerProfileIDA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
peerGetPlayerProfileIDCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
piPlayer * player;
|
|
PI_OP_ID;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(callback);
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
assert(callback);
|
|
|
|
// Find the player.
|
|
///////////////////
|
|
player = piGetPlayer(peer, nick);
|
|
|
|
// Check if chat has it.
|
|
////////////////////////
|
|
if(player && !player->gotIPAndProfileID)
|
|
{
|
|
const char * info;
|
|
unsigned int IP;
|
|
int profileID;
|
|
|
|
if(chatGetBasicUserInfoNoWaitA(connection->chat, nick, &info, NULL) && piDemangleUser(info, &IP, &profileID))
|
|
{
|
|
piSetPlayerIPAndProfileID(peer, nick, IP, profileID);
|
|
}
|
|
}
|
|
|
|
// See if we already have it.
|
|
/////////////////////////////
|
|
if(player && player->gotIPAndProfileID)
|
|
{
|
|
piAddGetPlayerProfileIDCallback(peer, PEERTrue, nick, player->profileID, callback, param, opID);
|
|
}
|
|
else
|
|
{
|
|
// Start an op to get it.
|
|
/////////////////////////
|
|
if(!piNewGetProfileIDOperation(peer, nick, callback, param, opID))
|
|
success = PEERFalse;
|
|
}
|
|
|
|
// If failed, add the callback.
|
|
///////////////////////////////
|
|
if(!success)
|
|
piAddGetPlayerProfileIDCallback(peer, PEERFalse, nick, 0, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerGetPlayerProfileIDW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
peerGetPlayerProfileIDCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
peerGetPlayerProfileIDA(peer, nick_A, callback, param, blocking);
|
|
gsifree(nick_A);
|
|
}
|
|
#endif
|
|
|
|
void peerGetPlayerIPA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
peerGetPlayerIPCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
piPlayer * player;
|
|
PI_OP_ID;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(callback);
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
assert(callback);
|
|
|
|
// Find the player.
|
|
///////////////////
|
|
player = piGetPlayer(peer, nick);
|
|
|
|
// Check if chat has it.
|
|
////////////////////////
|
|
if(player && !player->gotIPAndProfileID)
|
|
{
|
|
const char * info;
|
|
unsigned int IP;
|
|
int profileID;
|
|
|
|
if(chatGetBasicUserInfoNoWaitA(connection->chat, nick, &info, NULL) && piDemangleUser(info, &IP, &profileID))
|
|
{
|
|
piSetPlayerIPAndProfileID(peer, nick, IP, profileID);
|
|
}
|
|
}
|
|
|
|
// Check if we already have it.
|
|
///////////////////////////////
|
|
if(player && player->gotIPAndProfileID)
|
|
{
|
|
piAddGetPlayerIPCallback(peer, PEERTrue, nick, player->IP, callback, param, opID);
|
|
}
|
|
else
|
|
{
|
|
// Start an op to get it.
|
|
/////////////////////////
|
|
if(!piNewGetIPOperation(peer, nick, callback, param, opID))
|
|
success = PEERFalse;
|
|
}
|
|
|
|
// If failed, add the callback.
|
|
///////////////////////////////
|
|
if(!success)
|
|
piAddGetPlayerIPCallback(peer, PEERFalse, nick, 0, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerGetPlayerIPW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
peerGetPlayerIPCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
peerGetPlayerIPA(peer, nick_A, callback, param, blocking);
|
|
gsifree(nick_A);
|
|
}
|
|
#endif
|
|
|
|
PEERBool peerIsPlayerHostA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
RoomType roomType
|
|
)
|
|
{
|
|
piPlayer * player;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Are we in this type of room?
|
|
///////////////////////////////
|
|
assert(IN_ROOM);
|
|
if(!IN_ROOM)
|
|
return PEERFalse;
|
|
|
|
// Get the player.
|
|
//////////////////
|
|
player = piGetPlayer(peer, nick);
|
|
if(!player)
|
|
return PEERFalse;
|
|
|
|
// If it's the local player, return the value we store.
|
|
///////////////////////////////////////////////////////
|
|
if(player->local)
|
|
return connection->hosting;
|
|
|
|
// Is he host?
|
|
//////////////
|
|
return piIsPlayerHost(player);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
PEERBool peerIsPlayerHostW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
RoomType roomType
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
PEERBool result = peerIsPlayerHostA(peer, nick_A, roomType);
|
|
gsifree(nick_A);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
PEERBool peerGetPlayerFlagsA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
RoomType roomType,
|
|
int * flags
|
|
)
|
|
{
|
|
piPlayer * player;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(flags);
|
|
if(!flags)
|
|
return PEERFalse;
|
|
|
|
// Are we in this type of room?
|
|
///////////////////////////////
|
|
assert(IN_ROOM);
|
|
if(!IN_ROOM)
|
|
return PEERFalse;
|
|
|
|
// Get the player.
|
|
//////////////////
|
|
player = piGetPlayer(peer, nick);
|
|
if(!player)
|
|
return PEERFalse;
|
|
|
|
// Is he in?
|
|
////////////
|
|
if(!player->inRoom[roomType])
|
|
return PEERFalse;
|
|
|
|
// Get the flags.
|
|
/////////////////
|
|
*flags = player->flags[roomType];
|
|
|
|
return PEERTrue;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
PEERBool peerGetPlayerFlagsW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
RoomType roomType,
|
|
int * flags
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
PEERBool result = peerGetPlayerFlagsA(peer, nick_A, roomType, flags);
|
|
gsifree(nick_A);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
/*********
|
|
** GAME **
|
|
*********/
|
|
void peerSetReady
|
|
(
|
|
PEER peer,
|
|
PEERBool ready
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Are we in a staging room?
|
|
////////////////////////////
|
|
assert(connection->inRoom[StagingRoom]);
|
|
if(!connection->inRoom[StagingRoom])
|
|
return;
|
|
|
|
// Don't do anything if the state isn't changing.
|
|
/////////////////////////////////////////////////
|
|
if(connection->ready == ready)
|
|
return;
|
|
|
|
// Set it.
|
|
//////////
|
|
connection->ready = ready;
|
|
|
|
// Set the flags.
|
|
/////////////////
|
|
piSetLocalFlags(peer);
|
|
|
|
#if 1
|
|
// Send an old-style ready notice.
|
|
// THIS IS ONLY NEEDED FOR BACKWARDS COMPATIBILITY AND SHOULD BE REMOVED AT SOME POINT IN THE FUTURE.
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
char buffer[32];
|
|
//IN_ADDR addr;
|
|
//addr.s_addr = connection->publicIP;
|
|
strcpy(buffer, "@@@NFO \\$flags$\\");
|
|
if(ready)
|
|
strcat(buffer, "r");
|
|
strcat(buffer, "X\\"); // Flag to indicate this was sent by a new client.
|
|
peerMessageRoomA(peer, StagingRoom, buffer, NormalMessage);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
PEERBool peerGetReadyA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
PEERBool * ready
|
|
)
|
|
{
|
|
piPlayer * player;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
assert(ready);
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return PEERFalse;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return PEERFalse;
|
|
|
|
// Are we in a staging room?
|
|
////////////////////////////
|
|
assert(connection->inRoom[StagingRoom]);
|
|
if(!connection->inRoom[StagingRoom])
|
|
return PEERFalse;
|
|
|
|
// Get the player.
|
|
//////////////////
|
|
player = piGetPlayer(peer, nick);
|
|
if(!player || !player->inRoom[StagingRoom])
|
|
return PEERFalse;
|
|
|
|
*ready = (PEERBool)((player->flags[StagingRoom] & PEER_FLAG_READY) != 0);
|
|
|
|
return PEERTrue;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
PEERBool peerGetReadyW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
PEERBool * ready
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
PEERBool result = peerGetReadyA(peer, nick_A, ready);
|
|
gsifree(nick_A);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
static void piAreAllReadyEnumRoomPlayersCallback
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
piPlayer * player,
|
|
int index,
|
|
void *param
|
|
)
|
|
{
|
|
if(player)
|
|
{
|
|
PEERBool * allReadyPtr = (PEERBool *)param;
|
|
|
|
// If this player's not ready, set the flag.
|
|
////////////////////////////////////////////
|
|
if(!(player->flags[StagingRoom] & PEER_FLAG_READY))
|
|
*allReadyPtr = PEERFalse;
|
|
}
|
|
|
|
GSI_UNUSED(peer);
|
|
GSI_UNUSED(roomType);
|
|
GSI_UNUSED(index);
|
|
}
|
|
|
|
PEERBool peerAreAllReady
|
|
(
|
|
PEER peer
|
|
)
|
|
{
|
|
PEERBool allReady;
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return PEERFalse;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return PEERFalse;
|
|
|
|
// Are we in a staging room?
|
|
////////////////////////////
|
|
assert(connection->inRoom[StagingRoom]);
|
|
if(!connection->inRoom[StagingRoom])
|
|
return PEERFalse;
|
|
|
|
// Enum through all the room's players.
|
|
///////////////////////////////////////
|
|
allReady = PEERTrue;
|
|
piEnumRoomPlayers(peer, StagingRoom, piAreAllReadyEnumRoomPlayersCallback, &allReady);
|
|
|
|
return allReady;
|
|
}
|
|
|
|
void peerStartGameA
|
|
(
|
|
PEER peer,
|
|
const char * message,
|
|
int reportingOptions
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Check that we're in a staging room.
|
|
//////////////////////////////////////
|
|
assert(connection->inRoom[StagingRoom]);
|
|
if(!connection->inRoom[StagingRoom])
|
|
return;
|
|
|
|
// Make sure we're the host.
|
|
////////////////////////////
|
|
assert(connection->hosting);
|
|
if(!connection->hosting)
|
|
return;
|
|
|
|
// Change NULL messages to empty messages.
|
|
//////////////////////////////////////////
|
|
if(!message)
|
|
message = "";
|
|
|
|
// Send the launch UTM.
|
|
///////////////////////
|
|
piSendChannelUTM(peer, connection->rooms[StagingRoom], PI_UTM_LAUNCH, message, PEERFalse);
|
|
|
|
#if 1
|
|
// Send an old-style launch command.
|
|
// THIS IS ONLY NEEDED FOR BACKWARDS COMPATIBILITY AND SHOULD BE REMOVED AT SOME POINT IN THE FUTURE.
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
char buffer[32];
|
|
IN_ADDR addr;
|
|
addr.s_addr = connection->publicIP;
|
|
sprintf(buffer, "@@@GML %s/OLD", inet_ntoa(addr));
|
|
peerMessageRoomA(peer, StagingRoom, buffer, NormalMessage);
|
|
}
|
|
#endif
|
|
|
|
// We're playing.
|
|
/////////////////
|
|
connection->playing = PEERTrue;
|
|
|
|
// Set the flags.
|
|
/////////////////
|
|
piSetLocalFlags(peer);
|
|
|
|
// If we're AutoMatching, we're now done.
|
|
/////////////////////////////////////////
|
|
if(peerIsAutoMatching(peer))
|
|
{
|
|
piSetAutoMatchStatus(peer, PEERComplete);
|
|
}
|
|
else if(connection->queryReporting)
|
|
{
|
|
// Check if we should stop GOA reporting.
|
|
/////////////////////////////////////////
|
|
if(reportingOptions & PEER_STOP_REPORTING)
|
|
{
|
|
// Stop.
|
|
////////
|
|
piStopReporting(peer);
|
|
}
|
|
else
|
|
{
|
|
// Set the options.
|
|
///////////////////
|
|
connection->reportingOptions = reportingOptions;
|
|
|
|
// Send a state-changed.
|
|
////////////////////////
|
|
piSendStateChanged(peer);
|
|
}
|
|
}
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerStartGameW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * message,
|
|
int reportingOptions
|
|
)
|
|
{
|
|
char* message_A = UCS2ToUTF8StringAlloc(message);
|
|
peerStartGameA(peer, message_A, reportingOptions);
|
|
gsifree(message_A);
|
|
}
|
|
#endif
|
|
|
|
PEERBool peerStartReporting
|
|
(
|
|
PEER peer
|
|
)
|
|
{
|
|
return peerStartReportingWithSocket(peer, INVALID_SOCKET, 0);
|
|
}
|
|
|
|
PEERBool peerStartReportingWithSocket
|
|
(
|
|
PEER peer,
|
|
SOCKET socket,
|
|
unsigned short port
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return PEERFalse;
|
|
|
|
// Start.
|
|
/////////
|
|
if(!piStartReporting(peer, socket, port))
|
|
return PEERFalse;
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
void peerStartPlaying
|
|
(
|
|
PEER peer
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Mark us as playing.
|
|
//////////////////////
|
|
connection->playing = PEERTrue;
|
|
|
|
// Set the flags.
|
|
/////////////////
|
|
piSetLocalFlags(peer);
|
|
}
|
|
|
|
PEERBool peerIsPlaying
|
|
(
|
|
PEER peer
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return PEERFalse;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return PEERFalse;
|
|
|
|
return connection->playing;
|
|
}
|
|
|
|
void peerStopGame
|
|
(
|
|
PEER peer
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// We're done playing.
|
|
//////////////////////
|
|
connection->playing = PEERFalse;
|
|
|
|
// Set the flags.
|
|
/////////////////
|
|
piSetLocalFlags(peer);
|
|
|
|
// Are we reporting?
|
|
////////////////////
|
|
if(connection->queryReporting)
|
|
{
|
|
// Are we still in the staging room?
|
|
////////////////////////////////////
|
|
if(connection->inRoom[StagingRoom])
|
|
piSendStateChanged(peer);
|
|
else
|
|
piStopReporting(peer);
|
|
}
|
|
}
|
|
|
|
void peerStateChanged
|
|
(
|
|
PEER peer
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// We should be reporting.
|
|
//////////////////////////
|
|
assert(connection->queryReporting);
|
|
|
|
// Send a state-changed.
|
|
////////////////////////
|
|
piSendStateChanged(peer);
|
|
}
|
|
|
|
void piSendChannelUTM
|
|
(
|
|
PEER peer,
|
|
const char * channel,
|
|
const char * command,
|
|
const char * parameters,
|
|
PEERBool authenticate
|
|
)
|
|
{
|
|
char buffer[512];
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(channel && channel[0]);
|
|
assert(command && command[0]);
|
|
assert(parameters);
|
|
|
|
// Check for connection succeeded.
|
|
//////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Check for no channel.
|
|
////////////////////////
|
|
if(!channel || !channel[0])
|
|
return;
|
|
|
|
// Check for no command.
|
|
////////////////////////
|
|
if(!command || !command[0])
|
|
return;
|
|
|
|
// Check for no parameters.
|
|
///////////////////////////
|
|
if(!parameters)
|
|
parameters = "";
|
|
|
|
// Make sure this UTM isn't too long.
|
|
/////////////////////////////////////
|
|
if((strlen(command) + strlen(parameters) + 5) > sizeof(buffer))
|
|
return;
|
|
|
|
// Form the message.
|
|
////////////////////
|
|
sprintf(buffer, "%s %s", command, parameters);
|
|
|
|
// Send it.
|
|
///////////
|
|
chatSendChannelMessageA(connection->chat, channel, buffer, authenticate?CHAT_ATM:CHAT_UTM);
|
|
}
|
|
|
|
void piSendPlayerUTM
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
const char * command,
|
|
const char * parameters,
|
|
PEERBool authenticate
|
|
)
|
|
{
|
|
char buffer[512];
|
|
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(nick && nick[0]);
|
|
assert(command && command[0]);
|
|
assert(parameters);
|
|
|
|
// Check for connection succeeded.
|
|
//////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Check for no nick.
|
|
/////////////////////
|
|
if(!nick || !nick[0])
|
|
return;
|
|
|
|
// Check for no command.
|
|
////////////////////////
|
|
if(!command || !command[0])
|
|
return;
|
|
|
|
// Check for no parameters.
|
|
///////////////////////////
|
|
if(!parameters)
|
|
parameters = "";
|
|
|
|
// Make sure this UTM isn't too long.
|
|
/////////////////////////////////////
|
|
if((strlen(command) + strlen(parameters) + 5) > sizeof(buffer))
|
|
return;
|
|
|
|
// Form the message.
|
|
////////////////////
|
|
sprintf(buffer, "%s %s", command, parameters);
|
|
|
|
// Send it.
|
|
///////////
|
|
chatSendUserMessageA(connection->chat, nick, buffer, authenticate?CHAT_ATM:CHAT_UTM);
|
|
}
|
|
|
|
/*********
|
|
** KEYS **
|
|
*********/
|
|
void peerSetGlobalKeysA
|
|
(
|
|
PEER peer,
|
|
int num,
|
|
const char ** keys,
|
|
const char ** values
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(keys);
|
|
assert(values);
|
|
assert(num > 0);
|
|
|
|
// Check for connection succeeded.
|
|
//////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Set the keys.
|
|
////////////////
|
|
chatSetGlobalKeysA(connection->chat, num, keys, values);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerSetGlobalKeysW
|
|
(
|
|
PEER peer,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
const unsigned short ** values
|
|
)
|
|
{
|
|
char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
char** values_A = UCS2ToUTF8StringArrayAlloc(values, num);
|
|
int i;
|
|
peerSetGlobalKeysA(peer, num, (const char**)keys_A, (const char**)values_A);
|
|
for (i=0; i<num; i++)
|
|
{
|
|
gsifree(keys_A[i]);
|
|
gsifree(values_A[i]);
|
|
}
|
|
gsifree(keys_A);
|
|
gsifree(values_A);
|
|
}
|
|
#endif
|
|
|
|
void peerGetPlayerGlobalKeysA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
int num,
|
|
const char ** keys,
|
|
peerGetGlobalKeysCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for connection succeeded.
|
|
//////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
if(!nick || !nick[0])
|
|
nick = connection->nick;
|
|
|
|
assert(callback);
|
|
|
|
// Start the operation.
|
|
///////////////////////
|
|
if(!piNewGetGlobalKeysOperation(peer, nick, num, keys, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// Check for failure.
|
|
/////////////////////
|
|
if(!success)
|
|
piAddGetGlobalKeysCallback(peer, PEERFalse, nick, 0, NULL, NULL, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerGetPlayerGlobalKeysW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
peerGetGlobalKeysCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
int i;
|
|
peerGetPlayerGlobalKeysA(peer, nick_A, num, (const char**)keys_A, callback, param, blocking);
|
|
gsifree(nick_A);
|
|
for (i=0; i<num; i++)
|
|
gsifree(keys_A[i]);
|
|
gsifree(keys_A);
|
|
}
|
|
#endif
|
|
|
|
void peerGetRoomGlobalKeysA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
int num,
|
|
const char ** keys,
|
|
peerGetGlobalKeysCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for connection succeeded.
|
|
//////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
assert(callback);
|
|
|
|
// Check that we're in or entering this room.
|
|
/////////////////////////////////////////////
|
|
if(!ENTERING_ROOM && !IN_ROOM)
|
|
return;
|
|
|
|
// Start the operation.
|
|
///////////////////////
|
|
if(!piNewGetGlobalKeysOperation(peer, ROOM, num, keys, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// Check for failure.
|
|
/////////////////////
|
|
if(!success)
|
|
piAddGetGlobalKeysCallback(peer, PEERFalse, "", 0, NULL, NULL, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerGetRoomGlobalKeysW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
peerGetGlobalKeysCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
int i;
|
|
peerGetRoomGlobalKeysA(peer, roomType, num, (const char**)keys_A, callback, param, blocking);
|
|
for (i=0; i<num; i++)
|
|
gsifree(keys_A[i]);
|
|
gsifree(keys_A);
|
|
}
|
|
#endif
|
|
|
|
void peerSetRoomKeysA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * nick,
|
|
int num,
|
|
const char ** keys,
|
|
const char ** values
|
|
)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(keys);
|
|
assert(values);
|
|
assert(num > 0);
|
|
ASSERT_ROOMTYPE(roomType);
|
|
|
|
// Check for connection succeeded.
|
|
//////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Check that we're in or entering this room.
|
|
/////////////////////////////////////////////
|
|
if(!ENTERING_ROOM && !IN_ROOM)
|
|
return;
|
|
|
|
// Set the keys.
|
|
////////////////
|
|
chatSetChannelKeysA(connection->chat, ROOM, nick, num, keys, values);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerSetRoomKeysW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const unsigned short * nick,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
const unsigned short ** values
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
char** values_A = UCS2ToUTF8StringArrayAlloc(values, num);
|
|
int i;
|
|
peerSetRoomKeysA(peer, roomType, nick_A, num, (const char**)keys_A, (const char**)values_A);
|
|
gsifree(nick_A);
|
|
for (i=0; i<num; i++)
|
|
{
|
|
gsifree(keys_A[i]);
|
|
gsifree(values_A[i]);
|
|
}
|
|
gsifree(keys_A);
|
|
gsifree(values_A);
|
|
}
|
|
#endif
|
|
|
|
void peerGetRoomKeysA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * nick,
|
|
int num,
|
|
const char ** keys,
|
|
peerGetRoomKeysCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PEERBool success = PEERTrue;
|
|
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for connection succeeded.
|
|
//////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
assert(callback);
|
|
|
|
// Check that we're in or entering this room.
|
|
/////////////////////////////////////////////
|
|
if(!ENTERING_ROOM && !IN_ROOM)
|
|
return;
|
|
|
|
// Start the operation.
|
|
///////////////////////
|
|
if(!piNewGetRoomKeysOperation(peer, roomType, nick, num, keys, callback, param, opID))
|
|
success = PEERFalse;
|
|
|
|
// Check for failure.
|
|
/////////////////////
|
|
if(!success)
|
|
piAddGetRoomKeysCallback(peer, PEERFalse, roomType, nick, 0, NULL, NULL, callback, param, opID);
|
|
|
|
PI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerGetRoomKeysW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const unsigned short * nick,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
peerGetRoomKeysCallback callback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
int i;
|
|
peerGetRoomKeysA(peer, roomType, nick_A, num, (const char**)keys_A, callback, param, blocking);
|
|
gsifree(nick_A);
|
|
for (i=0; i<num; i++)
|
|
gsifree(keys_A[i]);
|
|
gsifree(keys_A);
|
|
}
|
|
#endif
|
|
|
|
void peerSetGlobalWatchKeysA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
int num,
|
|
const char ** keys,
|
|
PEERBool addKeys
|
|
)
|
|
{
|
|
piSetGlobalWatchKeys(peer, roomType, num, keys, addKeys);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerSetGlobalWatchKeysW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
PEERBool addKeys
|
|
)
|
|
{
|
|
char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
int i;
|
|
peerSetGlobalWatchKeysA(peer, roomType, num, (const char**)keys_A, addKeys);
|
|
for (i=0; i<num; i++)
|
|
gsifree(keys_A[i]);
|
|
gsifree(keys_A);
|
|
}
|
|
#endif
|
|
|
|
void peerSetRoomWatchKeysA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
int num,
|
|
const char ** keys,
|
|
PEERBool addKeys
|
|
)
|
|
{
|
|
piSetRoomWatchKeys(peer, roomType, num, keys, addKeys);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerSetRoomWatchKeysW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
PEERBool addKeys
|
|
)
|
|
{
|
|
char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
int i;
|
|
peerSetGlobalWatchKeysA(peer, roomType, num, (const char**)keys_A, addKeys);
|
|
for (i=0; i<num; i++)
|
|
gsifree(keys_A[i]);
|
|
gsifree(keys_A);
|
|
}
|
|
#endif
|
|
|
|
const char * peerGetGlobalWatchKeyA
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
const char * key
|
|
)
|
|
{
|
|
return piGetGlobalWatchKeyA(peer, nick, key);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
const unsigned short * peerGetGlobalWatchKeyW
|
|
(
|
|
PEER peer,
|
|
const unsigned short * nick,
|
|
const unsigned short * key
|
|
)
|
|
{
|
|
return piGetGlobalWatchKeyW(peer, nick, key);
|
|
}
|
|
#endif
|
|
|
|
const char * peerGetRoomWatchKeyA
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * nick,
|
|
const char * key
|
|
)
|
|
{
|
|
return piGetRoomWatchKeyA(peer, roomType, nick, key);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
const unsigned short * peerGetRoomWatchKeyW
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const unsigned short * nick,
|
|
const unsigned short * key
|
|
)
|
|
{
|
|
return piGetRoomWatchKeyW(peer, roomType, nick, key);
|
|
}
|
|
#endif
|
|
|
|
void peerStartAutoMatchA
|
|
(
|
|
PEER peer,
|
|
int maxPlayers,
|
|
const char * filter,
|
|
peerAutoMatchStatusCallback statusCallback,
|
|
peerAutoMatchRateCallback rateCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
peerStartAutoMatchWithSocketA(peer, maxPlayers, filter, INVALID_SOCKET, 0, statusCallback, rateCallback, param, blocking);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerStartAutoMatchW
|
|
(
|
|
PEER peer,
|
|
int maxPlayers,
|
|
const unsigned short * filter,
|
|
peerAutoMatchStatusCallback statusCallback,
|
|
peerAutoMatchRateCallback rateCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* filter_A = UCS2ToUTF8StringAlloc(filter);
|
|
peerStartAutoMatchA(peer, maxPlayers, filter_A, statusCallback, rateCallback, param, blocking);
|
|
gsifree(filter_A);
|
|
}
|
|
#endif
|
|
|
|
void peerStartAutoMatchWithSocketA
|
|
(
|
|
PEER peer,
|
|
int maxPlayers,
|
|
const char * filter,
|
|
SOCKET socket,
|
|
unsigned short port,
|
|
peerAutoMatchStatusCallback statusCallback,
|
|
peerAutoMatchRateCallback rateCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
PI_OP_ID;
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
assert(maxPlayers >= 2);
|
|
|
|
// Check the params.
|
|
////////////////////
|
|
if(!filter)
|
|
filter = "";
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
goto failed;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
goto failed;
|
|
|
|
// Check for an AutoMatch in progress.
|
|
//////////////////////////////////////
|
|
assert(!peerIsAutoMatching(peer));
|
|
if(peerIsAutoMatching(peer))
|
|
goto failed;
|
|
|
|
// If entering a staging room, leave.
|
|
/////////////////////////////////////
|
|
if(connection->enteringRoom[StagingRoom])
|
|
piLeaveRoom(peer, StagingRoom, "");
|
|
|
|
// Stop any reporting.
|
|
//////////////////////
|
|
piStopReporting(peer);
|
|
|
|
// Stop any game listing.
|
|
/////////////////////////
|
|
piSBStopListingGames(peer);
|
|
|
|
// Store some parameters.
|
|
/////////////////////////
|
|
connection->maxPlayers = maxPlayers;
|
|
connection->autoMatchFilter = goastrdup(filter);
|
|
if(!connection->autoMatchFilter)
|
|
goto failed;
|
|
|
|
// Initialize the AutoMatch status.
|
|
///////////////////////////////////
|
|
connection->autoMatchStatus = PEERFailed;
|
|
|
|
// Clear the SB and QR failed flags.
|
|
////////////////////////////////////
|
|
connection->autoMatchSBFailed = PEERFalse;
|
|
connection->autoMatchQRFailed = PEERFalse;
|
|
|
|
// Start the AutoMatch.
|
|
///////////////////////
|
|
if(!piNewAutoMatchOperation(peer, socket, port, statusCallback, rateCallback, param, opID))
|
|
{
|
|
gsifree(connection->autoMatchFilter);
|
|
goto failed;
|
|
}
|
|
|
|
PI_DO_BLOCKING;
|
|
|
|
return;
|
|
|
|
failed:
|
|
// Failed to start the attempt.
|
|
///////////////////////////////
|
|
connection->autoMatchStatus = PEERFailed;
|
|
piAddAutoMatchStatusCallback(peer);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void peerStartAutoMatchWithSocketW
|
|
(
|
|
PEER peer,
|
|
int maxPlayers,
|
|
const unsigned short * filter,
|
|
SOCKET socket,
|
|
unsigned short port,
|
|
peerAutoMatchStatusCallback statusCallback,
|
|
peerAutoMatchRateCallback rateCallback,
|
|
void * param,
|
|
PEERBool blocking
|
|
)
|
|
{
|
|
char* filter_A = UCS2ToUTF8StringAlloc(filter);
|
|
peerStartAutoMatchWithSocketA(peer, maxPlayers, filter_A, socket, port, statusCallback, rateCallback, param, blocking);
|
|
gsifree(filter_A);
|
|
}
|
|
#endif
|
|
|
|
void peerStopAutoMatch(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
PEER_CONNECTED;
|
|
|
|
// Check for a title.
|
|
/////////////////////
|
|
if(!connection->title[0])
|
|
return;
|
|
|
|
// Check for a connection.
|
|
//////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// Stop the AutoMatch.
|
|
//////////////////////
|
|
piStopAutoMatch(peer);
|
|
}
|
|
|
|
PEERBool peerIsAutoMatching(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// If the status is Failed or Done, then we're not matching.
|
|
////////////////////////////////////////////////////////////
|
|
if(connection->autoMatchStatus == PEERFailed)
|
|
return PEERFalse;
|
|
if(connection->autoMatchStatus == PEERComplete)
|
|
return PEERFalse;
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
PEERAutoMatchStatus peerGetAutoMatchStatus(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
return connection->autoMatchStatus;
|
|
}
|
|
|
|
void peerSetStagingRoomMaxPlayers(PEER peer, int maxPlayers)
|
|
{
|
|
PEER_CONNECTION;
|
|
GS_ASSERT(connection->inRoom[StagingRoom]);
|
|
if (connection->inRoom[StagingRoom])
|
|
{
|
|
// Let QR2 report the new max players, and set the new chat channel limit
|
|
connection->maxPlayers = maxPlayers;
|
|
piSendStateChanged(peer);
|
|
|
|
chatSetChannelLimitA(connection->chat, connection->rooms[StagingRoom], maxPlayers);
|
|
}
|
|
}
|