mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
1082 lines
22 KiB
C
1082 lines
22 KiB
C
![]() |
/*
|
||
|
GameSpy Peer SDK
|
||
|
Dan "Mr. Pants" Schoenblum
|
||
|
dan@gamespy.com
|
||
|
|
||
|
Copyright 1999-2007 GameSpy Industries, Inc
|
||
|
|
||
|
devsupport@gamespy.com
|
||
|
*/
|
||
|
|
||
|
/*************
|
||
|
** INCLUDES **
|
||
|
*************/
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include "peer.h"
|
||
|
#include "peerAscii.h"
|
||
|
#include "peerMain.h"
|
||
|
#include "peerGlobalCallbacks.h"
|
||
|
#include "peerRooms.h"
|
||
|
#include "peerPlayers.h"
|
||
|
#include "peerCallbacks.h"
|
||
|
#include "peerOperations.h"
|
||
|
#include "peerPing.h"
|
||
|
#include "peerMangle.h"
|
||
|
#include "peerKeys.h"
|
||
|
#include "peerAutoMatch.h"
|
||
|
|
||
|
/************
|
||
|
** DEFINES **
|
||
|
************/
|
||
|
#define PI_UTM_MATCH(utm) (strncmp(piUTMCommand, utm, strlen(utm) - 1) == 0)
|
||
|
|
||
|
#define PI_UTM_COMMAND_LEN 8
|
||
|
#define PI_UTM_PARAMATERS_LEN 512
|
||
|
|
||
|
/************
|
||
|
** GLOBALS **
|
||
|
************/
|
||
|
static char piUTMCommand[PI_UTM_COMMAND_LEN];
|
||
|
static char piUTMParameters[PI_UTM_PARAMATERS_LEN];
|
||
|
|
||
|
/**************
|
||
|
** FUNCTIONS **
|
||
|
**************/
|
||
|
// Prototype the ASCII versions that are needed even in unicode mode
|
||
|
void peerMessagePlayerA(PEER peer, const char * nick, const char * message, MessageType messageType);
|
||
|
|
||
|
|
||
|
/* Chat.
|
||
|
*******/
|
||
|
static PEERBool piIsOldUTM
|
||
|
(
|
||
|
const char * message
|
||
|
)
|
||
|
{
|
||
|
// Check for no message.
|
||
|
////////////////////////
|
||
|
assert(message);
|
||
|
if(!message)
|
||
|
return PEERFalse;
|
||
|
|
||
|
// Check for too short for prefix + 1 char.
|
||
|
///////////////////////////////////////////
|
||
|
if(strlen(message) < 4)
|
||
|
return PEERFalse;
|
||
|
|
||
|
// Check for no prefix.
|
||
|
///////////////////////
|
||
|
if((message[0] != '@') ||
|
||
|
(message[1] != '@') ||
|
||
|
(message[2] != '@') ||
|
||
|
(message[3] == ' '))
|
||
|
{
|
||
|
return PEERFalse;
|
||
|
}
|
||
|
|
||
|
return PEERTrue;
|
||
|
}
|
||
|
|
||
|
// Returns PEERTrue if a UTM.
|
||
|
/////////////////////////////
|
||
|
static PEERBool piParseUTM
|
||
|
(
|
||
|
const char * message
|
||
|
)
|
||
|
{
|
||
|
int len;
|
||
|
|
||
|
// Check for no message.
|
||
|
////////////////////////
|
||
|
assert(message);
|
||
|
if(!message)
|
||
|
return PEERFalse;
|
||
|
|
||
|
// Find the end of the command.
|
||
|
///////////////////////////////
|
||
|
len = (int)strcspn(message, "/ ");
|
||
|
if(len >= PI_UTM_COMMAND_LEN)
|
||
|
return PEERFalse;
|
||
|
memcpy(piUTMCommand, message, (unsigned int)len);
|
||
|
piUTMCommand[len] = '\0';
|
||
|
|
||
|
// Copy off the parameters.
|
||
|
///////////////////////////
|
||
|
message += len;
|
||
|
if(message[0])
|
||
|
{
|
||
|
message++;
|
||
|
if(strlen(message) >= PI_UTM_PARAMATERS_LEN)
|
||
|
return PEERFalse;
|
||
|
strcpy(piUTMParameters, message);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
piUTMParameters[0] = '\0';
|
||
|
}
|
||
|
|
||
|
return PEERTrue;
|
||
|
}
|
||
|
|
||
|
static void piProcessUTM
|
||
|
(
|
||
|
PEER peer,
|
||
|
piPlayer * player,
|
||
|
PEERBool inRoom,
|
||
|
RoomType roomType
|
||
|
)
|
||
|
{
|
||
|
char * params = piUTMParameters;
|
||
|
|
||
|
PEER_CONNECTION;
|
||
|
|
||
|
assert(piUTMCommand[0]);
|
||
|
assert(player);
|
||
|
|
||
|
if(PI_UTM_MATCH(PI_UTM_LAUNCH))
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
assert(connection->inRoom[StagingRoom]);
|
||
|
if(inRoom)
|
||
|
assert(roomType == StagingRoom);
|
||
|
else
|
||
|
assert(player->inRoom[StagingRoom]);
|
||
|
#endif
|
||
|
if(!connection->inRoom[StagingRoom])
|
||
|
return;
|
||
|
if(inRoom && (roomType != StagingRoom))
|
||
|
return;
|
||
|
if(!inRoom && !player->inRoom[StagingRoom])
|
||
|
return;
|
||
|
|
||
|
// Ignore if we're hosting.
|
||
|
///////////////////////////
|
||
|
if(connection->hosting)
|
||
|
return;
|
||
|
|
||
|
// Only accept launch from ops.
|
||
|
///////////////////////////////
|
||
|
if(!piIsPlayerOp(player))
|
||
|
return;
|
||
|
|
||
|
// We're playing.
|
||
|
/////////////////
|
||
|
connection->playing = PEERTrue;
|
||
|
|
||
|
// Set the flags.
|
||
|
/////////////////
|
||
|
piSetLocalFlags(peer);
|
||
|
|
||
|
// Add the callback.
|
||
|
////////////////////
|
||
|
piAddGameStartedCallback(peer, connection->hostServer, params);
|
||
|
|
||
|
// If we're AutoMatching, we're now done.
|
||
|
/////////////////////////////////////////
|
||
|
if(peerIsAutoMatching(peer))
|
||
|
piSetAutoMatchStatus(peer, PEERComplete);
|
||
|
}
|
||
|
else if(PI_UTM_MATCH(PI_UTM_XPING))
|
||
|
{
|
||
|
piPlayer * other;
|
||
|
int ping;
|
||
|
unsigned int IP;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
// if(inRoom)
|
||
|
// assert(connection->xpingRoom[roomType]);
|
||
|
#endif
|
||
|
if(inRoom && !connection->xpingRoom[roomType])
|
||
|
return;
|
||
|
|
||
|
// Check for no params.
|
||
|
///////////////////////
|
||
|
if(!params[0])
|
||
|
return;
|
||
|
|
||
|
// Get the IP.
|
||
|
//////////////
|
||
|
IP = piDemangleIP(params);
|
||
|
|
||
|
// Get the ping.
|
||
|
////////////////
|
||
|
params += 11;
|
||
|
ping = atoi(params);
|
||
|
|
||
|
// Figure out who this ping is to.
|
||
|
//////////////////////////////////
|
||
|
other = piFindPlayerByIP(peer, IP);
|
||
|
if(!other)
|
||
|
return;
|
||
|
if(strcasecmp(player->nick, other->nick) == 0)
|
||
|
return;
|
||
|
if(inRoom && !player->inRoom[roomType])
|
||
|
return;
|
||
|
if(!inRoom)
|
||
|
{
|
||
|
int i;
|
||
|
PEERBool success = PEERFalse;
|
||
|
|
||
|
// Check that the three of us are in a room with xping enabled.
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
for(i = 0 ; i < NumRooms ; i++)
|
||
|
{
|
||
|
if(connection->xpingRoom[i] && connection->inRoom[i] && player->inRoom[i] && other->inRoom[i])
|
||
|
success = PEERTrue;
|
||
|
}
|
||
|
if(!success)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Update.
|
||
|
//////////
|
||
|
piUpdateXping(peer, player->nick, other->nick, ping);
|
||
|
|
||
|
// Add a xping callback.
|
||
|
////////////////////////
|
||
|
piAddCrossPingCallback(peer, player->nick, other->nick, ping);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void piChatDisconnectedA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * reason,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
PEER_CONNECTION;
|
||
|
|
||
|
// We're disconnected.
|
||
|
//////////////////////
|
||
|
connection->disconnect = PEERTrue;
|
||
|
|
||
|
// Add the disconnected callback.
|
||
|
/////////////////////////////////
|
||
|
piAddDisconnectedCallback(peer, reason);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
void piChatDisconnectedW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * reason,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* reason_A = UCS2ToUTF8StringAlloc(reason);
|
||
|
piChatDisconnectedA(chat, reason_A, peer);
|
||
|
gsifree(reason_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piHandleOldNFO
|
||
|
(
|
||
|
PEER peer,
|
||
|
piPlayer * player,
|
||
|
const char * message
|
||
|
)
|
||
|
{
|
||
|
// Ignore old NFOs from new clients.
|
||
|
////////////////////////////////////
|
||
|
if(strncmp(message + strlen(message) - 2, "X\\", 2) != 0)
|
||
|
{
|
||
|
const char * str;
|
||
|
|
||
|
if(!player->inRoom[StagingRoom])
|
||
|
return;
|
||
|
|
||
|
str = strstr(message, "\\$flags$\\");
|
||
|
if(str)
|
||
|
{
|
||
|
PEERBool ready = PEERFalse;
|
||
|
str += 9;
|
||
|
while(*str && (*str != '\\'))
|
||
|
{
|
||
|
if(*str++ == 'r')
|
||
|
{
|
||
|
ready = PEERTrue;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(ready)
|
||
|
player->flags[StagingRoom] |= PEER_FLAG_READY;
|
||
|
else
|
||
|
player->flags[StagingRoom] &= ~PEER_FLAG_READY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GSI_UNUSED(peer);
|
||
|
}
|
||
|
|
||
|
void piChatPrivateMessageA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * user,
|
||
|
const char * message,
|
||
|
int type,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
assert(message);
|
||
|
|
||
|
if(!user || !user[0])
|
||
|
return;
|
||
|
|
||
|
// Check for old-style UTMs.
|
||
|
////////////////////////////
|
||
|
if(piIsOldUTM(message))
|
||
|
{
|
||
|
// Check for ready.
|
||
|
///////////////////
|
||
|
if(strncasecmp(message, "@@@NFO", 6) == 0)
|
||
|
{
|
||
|
piPlayer * player;
|
||
|
|
||
|
player = piGetPlayer(peer, user);
|
||
|
if(player)
|
||
|
piHandleOldNFO(peer, player, message);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Check if it's a UTM.
|
||
|
///////////////////////
|
||
|
if((type == CHAT_UTM) || (type == CHAT_ATM))
|
||
|
{
|
||
|
if(piParseUTM(message))
|
||
|
{
|
||
|
piPlayer * player;
|
||
|
|
||
|
// Get the player it's from.
|
||
|
////////////////////////////
|
||
|
player = piGetPlayer(peer, user);
|
||
|
if(player)
|
||
|
{
|
||
|
// Process it.
|
||
|
//////////////
|
||
|
piProcessUTM(peer, player, PEERFalse, (RoomType)0);
|
||
|
}
|
||
|
|
||
|
// Pass it along.
|
||
|
/////////////////
|
||
|
piAddPlayerUTMCallback(peer, user, piUTMCommand, piUTMParameters, (PEERBool)(type == CHAT_ATM));
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// It's a regular message, deliver it.
|
||
|
//////////////////////////////////////
|
||
|
piAddPlayerMessageCallback(peer, user, message, (MessageType)type);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
void piChatPrivateMessageW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * user,
|
||
|
const unsigned short * message,
|
||
|
int type,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
||
|
char* message_A = UCS2ToUTF8StringAlloc(message);
|
||
|
piChatPrivateMessageA(chat, user_A, message_A, type, peer);
|
||
|
gsifree(user_A);
|
||
|
gsifree(message_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piChannelMessageA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
const char * user,
|
||
|
const char * message,
|
||
|
int type,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
piPlayer * player;
|
||
|
RoomType roomType;
|
||
|
|
||
|
//PEER_CONNECTION;
|
||
|
|
||
|
assert(message);
|
||
|
|
||
|
// Check the room type.
|
||
|
///////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Get the player.
|
||
|
//////////////////
|
||
|
player = piGetPlayer(peer, user);
|
||
|
|
||
|
// Check for old-style UTMs.
|
||
|
////////////////////////////
|
||
|
if(player && piIsOldUTM(message))
|
||
|
{
|
||
|
// Only take stuff in staging rooms.
|
||
|
////////////////////////////////////
|
||
|
if(roomType != StagingRoom)
|
||
|
return;
|
||
|
|
||
|
// Check for a launch.
|
||
|
//////////////////////
|
||
|
if(strncasecmp(message, "@@@GML", 6) == 0)
|
||
|
{
|
||
|
// Ignore old launches from new clients.
|
||
|
////////////////////////////////////////
|
||
|
if(strncmp(message + strlen(message) - 4, "/OLD", 4) == 0)
|
||
|
return;
|
||
|
|
||
|
// Convert this into its modern equivalent.
|
||
|
///////////////////////////////////////////
|
||
|
type = CHAT_UTM;
|
||
|
message = "GML";
|
||
|
}
|
||
|
// Check for ready.
|
||
|
///////////////////
|
||
|
else if(strncasecmp(message, "@@@NFO", 6) == 0)
|
||
|
{
|
||
|
piHandleOldNFO(peer, player, message);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if it's a UTM.
|
||
|
///////////////////////
|
||
|
if((type == CHAT_UTM) || (type == CHAT_ATM))
|
||
|
{
|
||
|
if(piParseUTM(message))
|
||
|
{
|
||
|
// Process it.
|
||
|
//////////////
|
||
|
if(player)
|
||
|
piProcessUTM(peer, player, PEERTrue, roomType);
|
||
|
|
||
|
// Pass it along.
|
||
|
/////////////////
|
||
|
piAddRoomUTMCallback(peer, roomType, user, piUTMCommand, piUTMParameters, (type == CHAT_ATM)?PEERTrue:PEERFalse);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Add the callback.
|
||
|
////////////////////
|
||
|
piAddRoomMessageCallback(peer, roomType, user, message, (MessageType)type);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piChannelMessageW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
const unsigned short * user,
|
||
|
const unsigned short * message,
|
||
|
int type,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
||
|
char* message_A = UCS2ToUTF8StringAlloc(message);
|
||
|
piChannelMessageA(chat, channel_A, user_A, message_A, type, peer);
|
||
|
gsifree(channel_A);
|
||
|
gsifree(user_A);
|
||
|
gsifree(message_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piChannelKickedA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
const char * user,
|
||
|
const char * reason,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
RoomType roomType;
|
||
|
|
||
|
//PEER_CONNECTION;
|
||
|
|
||
|
// Figure out the room type.
|
||
|
////////////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Leave the room.
|
||
|
//////////////////
|
||
|
piLeaveRoom(peer, roomType, NULL);
|
||
|
|
||
|
// Add the callback.
|
||
|
////////////////////
|
||
|
piAddKickedCallback(peer, roomType, user, reason);
|
||
|
|
||
|
// If we were kicked from an AutoMatch room, start searching.
|
||
|
/////////////////////////////////////////////////////////////
|
||
|
if((roomType == StagingRoom) && peerIsAutoMatching(peer))
|
||
|
piSetAutoMatchStatus(peer, PEERSearching);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piChannelKickedW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
const unsigned short * user,
|
||
|
const unsigned short * reason,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
||
|
char* reason_A = UCS2ToUTF8StringAlloc(reason);
|
||
|
piChannelKickedA(chat, channel_A, user_A, reason_A, peer);
|
||
|
gsifree(channel_A);
|
||
|
gsifree(user_A);
|
||
|
gsifree(reason_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piChannelUserJoinedA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
const char * user,
|
||
|
int mode,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
RoomType roomType;
|
||
|
piPlayer * player;
|
||
|
|
||
|
PEER_CONNECTION;
|
||
|
|
||
|
// Figure out the room type.
|
||
|
////////////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Add this player to the room.
|
||
|
///////////////////////////////
|
||
|
player = piPlayerJoinedRoom(peer, user, roomType, mode);
|
||
|
if(!player)
|
||
|
return;
|
||
|
|
||
|
// Get IP and profile ID if we don't already have it.
|
||
|
/////////////////////////////////////////////////////
|
||
|
if(!player->gotIPAndProfileID)
|
||
|
{
|
||
|
const char * info;
|
||
|
unsigned int IP;
|
||
|
int profileID;
|
||
|
|
||
|
if(chatGetBasicUserInfoNoWaitA(connection->chat, user, &info, NULL) && piDemangleUser(info, &IP, &profileID))
|
||
|
{
|
||
|
piSetPlayerIPAndProfileID(peer, user, IP, profileID);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Refresh this player's watch keys.
|
||
|
////////////////////////////////////
|
||
|
piKeyCacheRefreshPlayer(peer, roomType, user);
|
||
|
|
||
|
// Add the callback.
|
||
|
////////////////////
|
||
|
piAddPlayerJoinedCallback(peer, roomType, user);
|
||
|
|
||
|
#if 1
|
||
|
// If this is the staging room, send our ready state.
|
||
|
/////////////////////////////////////////////////////
|
||
|
if((roomType == StagingRoom) && connection->ready)
|
||
|
peerMessagePlayerA(peer, user, "@@@NFO \\$flags$\\rX\\", NormalMessage);
|
||
|
#endif
|
||
|
|
||
|
// Check if this is an AutoMatch room.
|
||
|
//////////////////////////////////////
|
||
|
if((roomType == StagingRoom) && peerIsAutoMatching(peer))
|
||
|
{
|
||
|
// If we are Waiting, we're now Staging.
|
||
|
////////////////////////////////////////
|
||
|
if(connection->autoMatchStatus == PEERWaiting)
|
||
|
piSetAutoMatchStatus(peer, PEERStaging);
|
||
|
|
||
|
// If we've got maxplayers, we're now Ready.
|
||
|
////////////////////////////////////////////
|
||
|
if((connection->autoMatchStatus == PEERStaging) && (connection->numPlayers[StagingRoom] >= connection->maxPlayers))
|
||
|
piSetAutoMatchStatus(peer, PEERReady);
|
||
|
}
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piChannelUserJoinedW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
const unsigned short * user,
|
||
|
int mode,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
||
|
piChannelUserJoinedA(chat, channel_A, user_A, mode, peer);
|
||
|
gsifree(channel_A);
|
||
|
gsifree(user_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piChannelUserPartedA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
const char * user,
|
||
|
int why,
|
||
|
const char * reason,
|
||
|
const char * kicker,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
RoomType roomType;
|
||
|
PEERAutoMatchStatus status = PEERFailed;
|
||
|
PEERBool newStatus = PEERFalse;
|
||
|
PEERBool autoMatchRoom;
|
||
|
|
||
|
PEER_CONNECTION;
|
||
|
|
||
|
// Figure out the room type.
|
||
|
////////////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Check if this is an AutoMatch room.
|
||
|
//////////////////////////////////////
|
||
|
autoMatchRoom = ((roomType == StagingRoom) && peerIsAutoMatching(peer))?PEERTrue:PEERFalse;
|
||
|
if(autoMatchRoom)
|
||
|
{
|
||
|
piPlayer * player;
|
||
|
|
||
|
// Get the players.
|
||
|
///////////////////
|
||
|
player = piGetPlayer(peer, user);
|
||
|
|
||
|
// Check if he was the last op.
|
||
|
///////////////////////////////
|
||
|
if(!connection->hosting && piIsPlayerHost(player))
|
||
|
{
|
||
|
status = PEERSearching;
|
||
|
newStatus = PEERTrue;
|
||
|
}
|
||
|
// Check for host and everyone left.
|
||
|
////////////////////////////////////
|
||
|
else if(connection->hosting && connection->numPlayers[StagingRoom] == 2)
|
||
|
{
|
||
|
status = PEERWaiting;
|
||
|
newStatus = PEERTrue;
|
||
|
}
|
||
|
// Check for no longer at maxplayers.
|
||
|
/////////////////////////////////////
|
||
|
else if(connection->numPlayers[StagingRoom] == connection->maxPlayers)
|
||
|
{
|
||
|
status = PEERStaging;
|
||
|
newStatus = PEERTrue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove this player from the room.
|
||
|
////////////////////////////////////
|
||
|
piPlayerLeftRoom(peer, user, roomType);
|
||
|
|
||
|
// Figure out the reason.
|
||
|
/////////////////////////
|
||
|
if((why == CHAT_KICKED) || (why == CHAT_KILLED))
|
||
|
reason = "Kicked";
|
||
|
else if(!reason)
|
||
|
reason = "";
|
||
|
|
||
|
// Add the callback.
|
||
|
////////////////////
|
||
|
piAddPlayerLeftCallback(peer, roomType, user, reason);
|
||
|
|
||
|
// Set status if needed.
|
||
|
////////////////////////
|
||
|
if(newStatus)
|
||
|
piSetAutoMatchStatus(peer, status);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
GSI_UNUSED(kicker);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piChannelUserPartedW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
const unsigned short * user,
|
||
|
int why,
|
||
|
const unsigned short * reason,
|
||
|
const unsigned short * kicker,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
||
|
char* reason_A = UCS2ToUTF8StringAlloc(reason);
|
||
|
char* kicker_A = UCS2ToUTF8StringAlloc(kicker);
|
||
|
piChannelUserPartedA(chat, channel_A, user_A, why, reason_A, kicker_A, peer);
|
||
|
gsifree(channel_A);
|
||
|
gsifree(user_A);
|
||
|
gsifree(reason_A);
|
||
|
gsifree(kicker_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piChannelUserChangedNickA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
const char * oldNick,
|
||
|
const char * newNick,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
RoomType roomType;
|
||
|
|
||
|
// Figure out the room type.
|
||
|
////////////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Change the nick locally.
|
||
|
///////////////////////////
|
||
|
piPlayerChangedNick(peer, oldNick, newNick);
|
||
|
|
||
|
// Add the callback.
|
||
|
////////////////////
|
||
|
piAddPlayerChangedNickCallback(peer, roomType, oldNick, newNick);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piChannelUserChangedNickW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
const unsigned short * oldNick,
|
||
|
const unsigned short * newNick,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
char* oldNick_A = UCS2ToUTF8StringAlloc(oldNick);
|
||
|
char* newNick_A = UCS2ToUTF8StringAlloc(newNick);
|
||
|
piChannelUserChangedNickA(chat, channel_A, oldNick_A, newNick_A, peer);
|
||
|
gsifree(channel_A);
|
||
|
gsifree(oldNick_A);
|
||
|
gsifree(newNick_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piChannelTopicChangedA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
const char * topic,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
RoomType roomType;
|
||
|
|
||
|
PEER_CONNECTION;
|
||
|
|
||
|
// Figure out the room type.
|
||
|
////////////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Don't allow blank names.
|
||
|
///////////////////////////
|
||
|
if(!topic[0])
|
||
|
return;
|
||
|
|
||
|
// Is it the same as the old name?
|
||
|
//////////////////////////////////
|
||
|
//if(strcmp(NAME, topic) == 0)
|
||
|
// return;
|
||
|
|
||
|
// Copy the new name.
|
||
|
/////////////////////
|
||
|
strzcpy(NAME, topic, PI_NAME_MAX_LEN);
|
||
|
|
||
|
// Add a callback.
|
||
|
//////////////////
|
||
|
if(IN_ROOM)
|
||
|
piAddRoomNameChangedCallback(peer, roomType);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piChannelTopicChangedW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
const unsigned short * topic,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
char* topic_A = UCS2ToUTF8StringAlloc(topic);
|
||
|
piChannelTopicChangedA(chat, channel_A, topic_A, peer);
|
||
|
gsifree(channel_A);
|
||
|
gsifree(topic_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piChannelNewUserListA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
int num,
|
||
|
const char ** users,
|
||
|
int * modes,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
int i;
|
||
|
RoomType roomType;
|
||
|
|
||
|
//PEER_CONNECTION;
|
||
|
|
||
|
// Figure out the room type.
|
||
|
////////////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Clear all the players out of this room.
|
||
|
//////////////////////////////////////////
|
||
|
piClearRoomPlayers(peer, roomType);
|
||
|
|
||
|
// Add all the new ones.
|
||
|
////////////////////////
|
||
|
for(i = 0 ; i < num ; i++)
|
||
|
piPlayerJoinedRoom(peer, users[i], roomType, modes[i]);
|
||
|
|
||
|
// Refresh keys.
|
||
|
////////////////
|
||
|
piKeyCacheRefreshRoom(peer, roomType);
|
||
|
|
||
|
// Call the callback.
|
||
|
/////////////////////
|
||
|
piAddNewPlayerListCallback(peer, roomType);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piChannelNewUserListW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
int num,
|
||
|
const unsigned short ** users,
|
||
|
int * modes,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
char** users_A = UCS2ToUTF8StringArrayAlloc(users, num);
|
||
|
int i;
|
||
|
piChannelNewUserListA(chat, channel_A, num, (const char**)users_A, modes, peer);
|
||
|
gsifree(channel_A);
|
||
|
for (i=0; i<num; i++)
|
||
|
gsifree(users_A[i]);
|
||
|
gsifree(users_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piBroadcastKeyChangedA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
const char * user,
|
||
|
const char * key,
|
||
|
const char * value,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
RoomType roomType;
|
||
|
|
||
|
//PEER_CONNECTION;
|
||
|
|
||
|
// Figure out the room type.
|
||
|
////////////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Update the watch keys.
|
||
|
/////////////////////////
|
||
|
piRoomKeyChanged(peer, roomType, user, key, value);
|
||
|
|
||
|
// Add the callback.
|
||
|
////////////////////
|
||
|
// Removed by Bill 11/20/2003
|
||
|
// piRoomKeyChanged does this automatically for broadcast keys
|
||
|
// piAddRoomKeyChangedCallback(peer, roomType, user, key, value);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piBroadcastKeyChangedW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
const unsigned short * user,
|
||
|
const unsigned short * key,
|
||
|
const unsigned short * value,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
||
|
char* key_A = UCS2ToUTF8StringAlloc(key);
|
||
|
char* value_A = UCS2ToUTF8StringAlloc(value);
|
||
|
piBroadcastKeyChangedA(chat, channel_A, user_A, key_A, value_A, peer);
|
||
|
gsifree(channel_A);
|
||
|
gsifree(user_A);
|
||
|
gsifree(key_A);
|
||
|
gsifree(value_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piUserModeChangedA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
const char * user,
|
||
|
int mode,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
RoomType roomType;
|
||
|
|
||
|
//PEER_CONNECTION;
|
||
|
|
||
|
// Figure out the room type.
|
||
|
////////////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Set the user mode.
|
||
|
/////////////////////
|
||
|
piSetPlayerModeFlags(peer, user, roomType, mode);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piUserModeChangedW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
const unsigned short * user,
|
||
|
int mode,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
||
|
piUserModeChangedA(chat, channel_A, user_A, mode, peer);
|
||
|
gsifree(channel_A);
|
||
|
gsifree(user_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void piChannelModeChangedA
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const char * channel,
|
||
|
CHATChannelMode * mode,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
RoomType roomType;
|
||
|
|
||
|
//PEER_CONNECTION;
|
||
|
|
||
|
// Figure out the room type.
|
||
|
////////////////////////////
|
||
|
if(!piRoomToType(peer, channel, &roomType))
|
||
|
return;
|
||
|
|
||
|
// Add the callback.
|
||
|
////////////////////
|
||
|
piAddRoomModeChangedCallback(peer, roomType, mode);
|
||
|
|
||
|
GSI_UNUSED(chat);
|
||
|
}
|
||
|
#ifdef GSI_UNICODE
|
||
|
static void piChannelModeChangedW
|
||
|
(
|
||
|
CHAT chat,
|
||
|
const unsigned short * channel,
|
||
|
CHATChannelMode * mode,
|
||
|
PEER peer
|
||
|
)
|
||
|
{
|
||
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
||
|
piChannelModeChangedA(chat, channel_A, mode, peer);
|
||
|
gsifree(channel_A);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void piSetChannelCallbacks
|
||
|
(
|
||
|
PEER peer,
|
||
|
chatChannelCallbacks * channelCallbacks
|
||
|
)
|
||
|
{
|
||
|
memset(channelCallbacks, 0, sizeof(chatChannelCallbacks));
|
||
|
channelCallbacks->param = peer;
|
||
|
#ifndef GSI_UNICODE // NOT GSI_PEER_UNICODE
|
||
|
channelCallbacks->channelMessage = piChannelMessageA;
|
||
|
channelCallbacks->kicked = piChannelKickedA;
|
||
|
channelCallbacks->userJoined = piChannelUserJoinedA;
|
||
|
channelCallbacks->userParted = piChannelUserPartedA;
|
||
|
channelCallbacks->userChangedNick = piChannelUserChangedNickA;
|
||
|
channelCallbacks->topicChanged = piChannelTopicChangedA;
|
||
|
channelCallbacks->newUserList = piChannelNewUserListA;
|
||
|
channelCallbacks->broadcastKeyChanged = piBroadcastKeyChangedA;
|
||
|
channelCallbacks->userModeChanged = piUserModeChangedA;
|
||
|
channelCallbacks->channelModeChanged = piChannelModeChangedA;
|
||
|
#else
|
||
|
channelCallbacks->channelMessage = piChannelMessageW;
|
||
|
channelCallbacks->kicked = piChannelKickedW;
|
||
|
channelCallbacks->userJoined = piChannelUserJoinedW;
|
||
|
channelCallbacks->userParted = piChannelUserPartedW;
|
||
|
channelCallbacks->userChangedNick = piChannelUserChangedNickW;
|
||
|
channelCallbacks->topicChanged = piChannelTopicChangedW;
|
||
|
channelCallbacks->newUserList = piChannelNewUserListW;
|
||
|
channelCallbacks->broadcastKeyChanged = piBroadcastKeyChangedW;
|
||
|
channelCallbacks->userModeChanged = piUserModeChangedW;
|
||
|
channelCallbacks->channelModeChanged = piChannelModeChangedW;
|
||
|
#endif
|
||
|
}
|
||
|
|