420 lines
10 KiB
C++
420 lines
10 KiB
C++
#include "SocketServer.h"
|
|
#include <fstream>
|
|
bool SocketServer::loadMapList(char* maploc)
|
|
{
|
|
::std::string workDir;
|
|
::Utility::String::extractDirPath( workDir, maploc, '\\' );
|
|
|
|
//maploc is the filename of the list which contains all maps
|
|
//load all map file names into the server, but don't load the maps themselves.
|
|
std::ifstream file;
|
|
file.open(maploc);
|
|
if (!file.is_open())
|
|
return false;
|
|
::std::string str;
|
|
while(!file.eof())
|
|
{
|
|
::std::getline( file, str );
|
|
maps.push_back( workDir + str );
|
|
}
|
|
|
|
/*
|
|
maps.push_back("map1test.map");
|
|
maps.push_back("map2 test.map");
|
|
*/
|
|
return true;
|
|
}
|
|
bool SocketServer::LoadInitData(char* maploc)
|
|
{
|
|
std::vector<std::string> cont;
|
|
char* in=new char[100];
|
|
std::ifstream ifs;
|
|
ifs.open(maploc);
|
|
if(!ifs.is_open())
|
|
{
|
|
return false;
|
|
}
|
|
while(!ifs.eof())
|
|
{
|
|
ifs.getline(in, 100);
|
|
cont=splitString(in, '=');
|
|
if (cont.size()==2)
|
|
{
|
|
if(!strcmp("nr_players_per_session", cont[0].c_str()))
|
|
{
|
|
playersPerSessionCount=atoi(cont[1].c_str());
|
|
}
|
|
else if(!strcmp("nr_kills_to_win", cont[0].c_str()))
|
|
{
|
|
killsRequiredPerSession=atoi(cont[1].c_str());
|
|
}
|
|
else if(!strcmp("match_type", cont[0].c_str()))
|
|
{
|
|
//Isn't used
|
|
}
|
|
}
|
|
|
|
}
|
|
ifs.close();
|
|
}
|
|
SocketServer::~SocketServer()
|
|
{
|
|
serverTCPConnectionLoopActive=false;
|
|
serverUDPReceiveLoopActive=false;
|
|
serverTCPReceiveLoopActive=false;
|
|
for (int i=0; i<NR_CONNECTTHREADS; i++)
|
|
{
|
|
delete connData[i].buffer;
|
|
}
|
|
for (int i=0; i<NR_SIMULTCPCONNECTS; i++)
|
|
{
|
|
delete tcpData[i].buffer;
|
|
}
|
|
delete sendGameDataBuffer;
|
|
delete sendEffectDataBuffer;
|
|
closeConnection();
|
|
}
|
|
void SocketServer::startGameCreateLoop(int delay)
|
|
{
|
|
lobbyActive=false;
|
|
DEBUGCTR=0;
|
|
if(!serverGameCreationActive)
|
|
{
|
|
ThreadArguments tr;
|
|
tr.ptr=this;
|
|
tr.threadID=delay;
|
|
serverGameCreationActive=true;
|
|
gameCreateHandle=CreateThread(
|
|
NULL, //Choose default security
|
|
0, //Default stack size
|
|
(LPTHREAD_START_ROUTINE)&activateServerGameLoop,
|
|
//Routine to execute
|
|
(LPVOID) &tr, //Thread parameter
|
|
0, //Immediately run the thread
|
|
0 //Thread Id
|
|
);
|
|
if (gameCreateHandle == NULL)
|
|
{
|
|
printf("Game creation thread ERROR");
|
|
}
|
|
else
|
|
{
|
|
printf("Game creation thread successful\n");
|
|
Sleep(100);
|
|
}
|
|
}
|
|
}
|
|
void SocketServer::stopGameCreateLoop()
|
|
{
|
|
serverGameCreationActive=false;
|
|
WaitForSingleObject(gameCreateHandle, INFINITE);
|
|
printf("Game Creation thread ended.\n");
|
|
}
|
|
DWORD SocketServer::activateServerGameLoop(ThreadArguments* tra)
|
|
{
|
|
srand((unsigned int)(time(0)));
|
|
(tra->ptr)->serverGameCreationLoop(tra->threadID);
|
|
return 0;
|
|
}
|
|
bool SocketServer::serverGameCreationLoop(int delay)
|
|
{ // TODO: Mem access Violoation Crash 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ... delay = -858993460
|
|
//Mem access violation in a thread can also be caused by failure from something else instead of it,
|
|
//it still breaks at header even if, for example, server->load or lobby.startLobbyCountdown breaks it
|
|
//If you get an error here, make sure that isn't the problem.
|
|
int count;
|
|
while(serverGameCreationActive)
|
|
{
|
|
if (nrActiveSessions==0)
|
|
{
|
|
count=0;
|
|
for (unsigned int i=0; i<users.size(); i++)
|
|
{
|
|
if (users[i].getState()==ONLINE_QUEUEING)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
if (count>=playersPerSessionCount)
|
|
{
|
|
games.resize(1);
|
|
//lobby.resize(games.size()+1);
|
|
session =new GameLogic::Session();
|
|
lobby = Lobby();
|
|
timer.resize(1);
|
|
timeTillUpdate.resize(1);
|
|
timeTillUpdate[0]=GAME_UPDATEDELAY;
|
|
updateCount.resize(1);
|
|
updateCount[0]=0;
|
|
int curID=(int)games.size()-1;
|
|
int mapid=rand()%maps.size();
|
|
session->setNrPlayers(playersPerSessionCount);
|
|
session->setKillsRequired(killsRequiredPerSession);
|
|
session->load(maps[mapid]);
|
|
printf("Map nr %d loaded, name %s.\n",mapid, maps[mapid].c_str());
|
|
count=0;
|
|
for (unsigned int i=0; count<playersPerSessionCount && i<users.size(); i++)
|
|
{
|
|
if (users[i].getState()==ONLINE_QUEUEING)
|
|
{
|
|
//Set to INLOBBY and send lobby data, then start a lobby
|
|
lobby.addUser(users[i], i);
|
|
users[i].setState(ONLINE_INGAME);
|
|
games[curID].addUser(i);
|
|
users[i].setGame(curID);
|
|
session->accessPlayer(i).spawn();
|
|
count++;
|
|
}
|
|
}
|
|
lobbyActive=true;
|
|
sendLobbyInitData(curID);
|
|
lobby.startLobbyCountdown(LOBBY_WAIT_TIME);
|
|
sendRenderData(curID);
|
|
//return true;
|
|
}
|
|
if(lobbyActive)
|
|
{
|
|
for (int i=0; i<1; i++)
|
|
{
|
|
float ttimer=lobby.timeLeft();
|
|
if (ttimer==0)
|
|
{
|
|
printf("Starting game.\n");
|
|
games[i].initGame(users,playersPerSessionCount);
|
|
sendInitData(i);
|
|
nrActiveSessions++;
|
|
lobbyActive=false;
|
|
//serverGameCreationActive=false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Sleep(delay);
|
|
}
|
|
printf("Maximum server count reached, shutting down the sever creation thread.\n");
|
|
return false;
|
|
}
|
|
SocketServer::SocketServer()
|
|
{
|
|
UDPSocket = INVALID_SOCKET;
|
|
nrActiveSessions=0;
|
|
serverGameCreationActive=false;
|
|
serverTCPConnectionLoopActive=false;
|
|
serverTCPReceiveLoopActive=false;
|
|
serverUDPReceiveLoopActive=false;
|
|
killsRequiredPerSession=10;
|
|
playersPerSessionCount=1;
|
|
LoadInitData("../ServerData.dat");
|
|
//---------------------------------------------
|
|
// Set up the port and IP of the server
|
|
//Port starts up as a different one from when UDPSocketected, it changes once the server has exchanged some info with the client
|
|
UDPRecvAddr.sin_family = AF_INET;
|
|
UDPRecvAddr.sin_port = htons(UDPRecvPort);
|
|
UDPRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
sessionEvents=std::vector<Event::GameEvent*>(0);
|
|
sessionEffects=std::vector<Network::EffectData>(0);
|
|
TCPRecvAddr.sin_family = AF_INET;
|
|
TCPRecvAddr.sin_port = htons(TCPRecvPort);
|
|
TCPRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
addrSize=sizeof(sockaddr_in);
|
|
for (int i=0; i<NR_CONNECTTHREADS; i++)
|
|
{
|
|
connData[i].buffer=new char[256];
|
|
connData[i].bufLen=256;
|
|
ZeroMemory(connData[i].buffer,sizeof(connData[i].buffer));
|
|
connData[i].dataSize=0;
|
|
//connData[i].srcAddr
|
|
memcpy(&connData[i].srcAddr, &UDPRecvAddr,addrSize);
|
|
}
|
|
for (int i=0; i<NR_SIMULTCPCONNECTS; i++)
|
|
{
|
|
tcpData[i].buffer=new char[256];
|
|
tcpData[i].bufLen=256;
|
|
ZeroMemory(tcpData[i].buffer,sizeof(tcpData[i].buffer));
|
|
tcpData[i].dataSize=0;
|
|
memcpy(&connData[i].srcAddr, &TCPRecvAddr,addrSize);
|
|
}
|
|
sendGameDataBufferSize=SERVER_PLAYER_DATA_SIZE*playersPerSessionCount+1;
|
|
sendGameDataBuffer=new char[sendGameDataBufferSize];
|
|
sendGameDataBuffer[0]=1;
|
|
sendEffectDataBuffer=new char[sizeof(Network::EffectData)+1];
|
|
sendEffectDataBuffer[0]=7;
|
|
|
|
//----------------------
|
|
// Initialize Winsock
|
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
if (iResult != NO_ERROR) {
|
|
wprintf(L"WSAStartup failed with error: %d\n", iResult);
|
|
}
|
|
else
|
|
{
|
|
//Init sockets
|
|
setupStatus=initTCPSocket();
|
|
if(setupStatus)
|
|
setupStatus=initUDPSocket();
|
|
}
|
|
}
|
|
bool SocketServer::startThreads()
|
|
{
|
|
//ThreadArguments tra1[NR_SIMULTCPCONNECTS];
|
|
ThreadArguments tra2[NR_CONNECTTHREADS];
|
|
//for (int i=0; i< NR_SIMULTCPCONNECTS; i++)
|
|
//{
|
|
// tra1[i].ptr=this;
|
|
// tra1[i].threadID=i;
|
|
// //printf("i - %d\n",i);
|
|
//
|
|
// tcpDataHandle[i]=CreateThread(
|
|
// NULL, //Choose default security
|
|
// 0, //Default stack size
|
|
// (LPTHREAD_START_ROUTINE)&activateTCPConnectLoop,
|
|
// //Routine to execute
|
|
// (LPVOID) &tra1[i], //Thread parameter
|
|
// 0, //Immediately run the thread
|
|
// 0 //Thread Id
|
|
// );
|
|
// if (tcpDataHandle[i] == NULL)
|
|
// {
|
|
// printf("Error Creating TCP Thread#: %d\n",i);
|
|
// return(false);
|
|
// }
|
|
// else
|
|
// {
|
|
// printf("Successfully created TCP thread #: %d\n", i);
|
|
// Sleep(100);
|
|
// }
|
|
//}
|
|
for (int i=0; i< NR_CONNECTTHREADS; i++)
|
|
{
|
|
tra2[i].ptr=this;
|
|
tra2[i].threadID=i;
|
|
//printf("i - %d\n",i);
|
|
udpDataHandle[i]=CreateThread(
|
|
NULL, //Choose default security
|
|
0, //Default stack size
|
|
(LPTHREAD_START_ROUTINE)&activateUDPReceiveLoop,
|
|
//Routine to execute
|
|
(LPVOID) &tra2[i], //Thread parameter
|
|
0, //Immediately run the thread
|
|
0 //Thread Id
|
|
);
|
|
if (udpDataHandle[i] == NULL)
|
|
{
|
|
printf("Error Creating UDP Thread#: %d\n",i);
|
|
return(false);
|
|
}
|
|
else
|
|
{
|
|
printf("Successfully created UDP thread #: %d\n", i);
|
|
Sleep(100);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
bool SocketServer::sendData(int uid, const char* data, int size)
|
|
{
|
|
//---------------------------------------------
|
|
// Send a datagram to a user
|
|
//uid -1 = broadcast message
|
|
if (uid<0)
|
|
{
|
|
for (unsigned int i=0; i<users.size(); i++)
|
|
{
|
|
iResult = sendto(UDPSocket, data, size, 0, (SOCKADDR *) & users[i].getAddr(), addrSize);
|
|
if (iResult == SOCKET_ERROR)
|
|
{
|
|
wprintf(L"UDP sendData(-1) sendto failed with error: %d\n", WSAGetLastError());
|
|
closesocket(UDPSocket);
|
|
WSACleanup();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((unsigned)uid>=users.size())
|
|
{
|
|
//User doesn't exist
|
|
printf("UDP sendData(%d) sendto failed because the specified user does not exist\n", uid);
|
|
}
|
|
else
|
|
{
|
|
iResult = sendto(UDPSocket, data, size, 0, (SOCKADDR *) & users[uid].getAddr(), addrSize);
|
|
if (iResult == SOCKET_ERROR)
|
|
{
|
|
wprintf(L"UDP sendData(%d) sendto failed with error: %d\n", uid, WSAGetLastError());
|
|
closesocket(UDPSocket);
|
|
WSACleanup();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
bool SocketServer::sendKeyFrameData(int size, const char* data)
|
|
{
|
|
for (int i=0; i<playersPerSessionCount; i++)
|
|
{
|
|
iResult = sendto(UDPSocket, data, size+1, 0, (SOCKADDR *) & users[games[0].getUserID(i)].getAddr(), addrSize);
|
|
if (iResult == SOCKET_ERROR)
|
|
{
|
|
wprintf(L"UDP keyFrameData sendto failed with error: %d\n", WSAGetLastError());
|
|
closesocket(UDPSocket);
|
|
WSACleanup();
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SocketServer::checkConnection(int userID)
|
|
{
|
|
char* message="\3testmessage";
|
|
int count=
|
|
sendto(
|
|
UDPSocket,
|
|
message,
|
|
(int)strlen(message),
|
|
0,
|
|
(SOCKADDR *) & users[userID].getAddr(),
|
|
addrSize);
|
|
|
|
if (count == SOCKET_ERROR)
|
|
{
|
|
wprintf(L"recvfrom failed with error %d\n", WSAGetLastError());
|
|
return false;
|
|
}
|
|
else if (count==0)
|
|
{
|
|
wprintf(L"Disconnected.\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool SocketServer::closeConnection()
|
|
{
|
|
//---------------------------------------------
|
|
// When the application is finished sending, close the sockets.
|
|
setupStatus=false;
|
|
wprintf(L"Finished sending. Closing socket.\n");
|
|
iResult = closesocket(UDPSocket);
|
|
if (iResult == SOCKET_ERROR) {
|
|
wprintf(L"closeUDPsocket failed with error: %d\n", WSAGetLastError());
|
|
WSACleanup();
|
|
return false;
|
|
}
|
|
iResult = closesocket(TCPSocket);
|
|
if (iResult == SOCKET_ERROR) {
|
|
wprintf(L"closeTCPsocket failed with error: %d\n", WSAGetLastError());
|
|
WSACleanup();
|
|
return false;
|
|
}
|
|
//---------------------------------------------
|
|
// Clean up and quit.
|
|
wprintf(L"Exiting.\n");
|
|
WSACleanup();
|
|
return true;
|
|
} |