/* GameSpy Peer SDK Dan "Mr. Pants" Schoenblum dan@gamespy.com Copyright 1999-2007 GameSpy Industries, Inc devsupport@gamespy.com */ /************* ** INCLUDES ** *************/ #include #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; iconnected) 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; iconnected) 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 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; iconnected) 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= 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); } }