openmohaa/code/gamespy/Peer/peerMain.c
2023-02-04 21:00:01 +01:00

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);
}
}