Files
itgmania212121/stepmania/src/NetworkSyncServer.cpp
T

1023 lines
26 KiB
C++
Raw Normal View History

2004-09-06 23:36:38 +00:00
#include "global.h"
2004-08-28 05:30:23 +00:00
#include "NetworkSyncServer.h"
#include "RageLog.h"
#include "PrefsManager.h"
2004-09-06 23:36:38 +00:00
#include <time.h>
2004-08-28 05:30:23 +00:00
2004-09-10 23:21:56 +00:00
#if defined(WITHOUT_NETWORKING)
bool StepManiaLanServer::ServerStart() { return false; }
void StepManiaLanServer::ServerStop() { }
void StepManiaLanServer::ServerUpdate() { }
StepManiaLanServer::StepManiaLanServer() { }
StepManiaLanServer::~StepManiaLanServer() { }
#else
static Preference<float> g_fStartWait( Options, "ServerWaitSeconds", 2 );
2004-09-06 23:36:38 +00:00
LanPlayer::LanPlayer()
{
2004-08-28 05:30:23 +00:00
score = 0;
health = 0;
feet = 0;
projgrade = 0;
combo = 0;
2004-09-01 19:50:30 +00:00
currstep = 0;
2004-08-28 05:30:23 +00:00
maxCombo = 0;
Grade = 0;
offset = 0;
2004-09-06 04:24:51 +00:00
options = "";
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
StepManiaLanServer::StepManiaLanServer()
{
stop = true;
SecondSameSelect = false;
AssignPlayerIDs();
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
StepManiaLanServer::~StepManiaLanServer()
{
2004-08-28 05:30:23 +00:00
ServerStop();
}
2004-09-06 23:36:38 +00:00
bool StepManiaLanServer::ServerStart()
{
2004-08-28 05:30:23 +00:00
server.blocking = 0; /* Turn off blocking */
if (server.create())
if (server.bind(8765))
2004-09-06 23:36:38 +00:00
if (server.listen())
{
2004-08-28 05:30:23 +00:00
stop = false;
statsTime = time(NULL);
return true;
2004-08-28 05:30:23 +00:00
}
2004-09-06 18:20:16 +00:00
else
lastError = "Failed to make socket listen.";
else
lastError = "Failed to bind socket";
else
lastError = "Failed to create socket";
2004-08-28 05:30:23 +00:00
2004-09-06 18:20:16 +00:00
lastErrorCode = server.lastCode;
//Hopefully we will not get here. If we did, something went wrong above.
return false;
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::ServerStop()
{
2004-09-18 05:48:40 +00:00
for (unsigned int x = 0; x < Client.size(); ++x)
2004-10-30 04:13:45 +00:00
{
2004-09-18 05:48:40 +00:00
delete Client[x];
2004-10-30 04:13:45 +00:00
Client[x] = NULL;
}
2004-09-18 05:48:40 +00:00
Client.clear();
2004-08-28 05:30:23 +00:00
server.close();
stop = true;
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::ServerUpdate()
{
if (!stop)
{
2004-08-28 05:30:23 +00:00
NewClientCheck(); /* See if there is another client wanting to play */
UpdateClients();
2004-09-06 23:36:38 +00:00
if (time(NULL) > statsTime)
{
2004-08-28 05:30:23 +00:00
SendStatsToClients();
statsTime = time(NULL);
}
}
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::UpdateClients()
{
//Go through all the clients and check to see if it is being used.
//If so then try to get a backet and parse the data.
for (unsigned int x = 0; x < Client.size(); ++x)
2004-10-30 04:13:45 +00:00
if (CheckConnection(x) && (Client[x]->GetData(Packet) >= 0))
ParseData(Packet, x);
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
GameClient::GameClient()
{
GotStartRequest = 0;
2004-08-28 05:30:23 +00:00
clientSocket.blocking = 0;
twoPlayers = false;
version = 0;
startPosition = 0;
InGame = 0;
hasSong = forceHas = false;
inNetMusicSelect = false;
isStarting = false; //Used for after ScreenNetMusicSelect but before InGame
2004-09-06 16:29:23 +00:00
wasIngame = false;
lowerJudge = false;
2004-10-29 01:58:56 +00:00
NetScreenInfo = NS_NOWHERE;
2004-08-28 05:30:23 +00:00
}
void StepManiaLanServer::Disconnect(const unsigned int clientNum)
2004-09-11 17:18:50 +00:00
{
if (clientNum == (Client.size()-1))
2004-09-18 05:48:40 +00:00
{
2004-09-19 03:36:28 +00:00
delete Client[Client.size()-1];
2004-10-30 04:13:45 +00:00
Client[Client.size()-1] = NULL;
Client.pop_back();
2004-09-18 05:48:40 +00:00
}
else
2004-09-19 03:36:28 +00:00
{
vector<GameClient*>::iterator Iterator;
Iterator = Client.begin();
for (unsigned int x = 0; x < Client.size(); ++x)
{
if (x == clientNum)
2004-09-18 05:48:40 +00:00
{
delete Client[x];
2004-10-30 04:13:45 +00:00
Client[x] = NULL;
Client.erase(Iterator);
2004-09-18 05:48:40 +00:00
}
2004-09-19 03:36:28 +00:00
++Iterator;
}
2004-09-19 03:36:28 +00:00
}
2004-10-30 04:13:45 +00:00
SendUserList();
2004-09-11 17:18:50 +00:00
}
2004-09-06 23:36:38 +00:00
int GameClient::GetData(PacketFunctions& Packet)
{
2004-08-28 05:30:23 +00:00
int length = -1;
Packet.ClearPacket();
length = clientSocket.ReadPack((char*)Packet.Data, NETMAXBUFFERSIZE);
return length;
}
void StepManiaLanServer::ParseData(PacketFunctions& Packet, const unsigned int clientNum)
2004-09-06 23:36:38 +00:00
{
2004-08-28 05:30:23 +00:00
int command = Packet.Read1();
2004-09-06 23:36:38 +00:00
switch (command)
{
case NSCPing:
2004-09-02 16:39:45 +00:00
// No Operation
SendValue(NSServerOffset + NSCPingR, clientNum);
2004-08-28 05:30:23 +00:00
break;
case NSCPingR:
2004-09-02 16:39:45 +00:00
// No Operation response
2004-08-28 05:30:23 +00:00
break;
case NSCHello:
2004-09-02 16:39:45 +00:00
// Hello
2004-08-28 05:30:23 +00:00
Hello(Packet, clientNum);
break;
case NSCGSR:
2004-09-02 16:39:45 +00:00
// Start Request
Client[clientNum]->StartRequest(Packet);
2004-10-17 14:46:00 +00:00
CheckReady(); //This is what ACTUALLY starts the games
2004-08-28 05:30:23 +00:00
break;
case NSCGON:
2004-09-02 16:39:45 +00:00
// GameOver
2004-09-01 19:50:30 +00:00
GameOver(Packet, clientNum);
2004-08-28 05:30:23 +00:00
break;
case NSCGSU:
2004-09-02 16:39:45 +00:00
// StatsUpdate
Client[clientNum]->UpdateStats(Packet);
2004-09-17 22:22:39 +00:00
if (!Client[clientNum]->lowerJudge)
CheckLowerJudge(clientNum);
2004-08-28 05:30:23 +00:00
break;
case NSCSU:
2004-09-02 16:39:45 +00:00
// Style Update
Client[clientNum]->StyleUpdate(Packet);
SendUserList();
2004-08-28 05:30:23 +00:00
break;
case NSCCM:
2004-09-02 16:39:45 +00:00
// Chat message
2004-09-11 17:18:50 +00:00
AnalizeChat(Packet, clientNum);
2004-08-28 05:30:23 +00:00
break;
case NSCRSG:
2004-08-28 05:30:23 +00:00
SelectSong(Packet, clientNum);
break;
case NSCSMS:
ScreenNetMusicSelectStatus(Packet, clientNum);
break;
case NSCUPOpts:
Client[clientNum]->Player[0].options = Packet.ReadNT();
Client[clientNum]->Player[1].options = Packet.ReadNT();
2004-09-06 04:24:51 +00:00
break;
2004-08-28 05:30:23 +00:00
default:
break;
}
}
void StepManiaLanServer::Hello(PacketFunctions& Packet, const unsigned int clientNum)
2004-09-06 23:36:38 +00:00
{
2004-08-28 05:30:23 +00:00
int ClientVersion = Packet.Read1();
CString build = Packet.ReadNT();
Client[clientNum]->SetClientVersion(ClientVersion, build);
2004-08-28 05:30:23 +00:00
2004-09-02 16:39:45 +00:00
Reply.ClearPacket();
Reply.Write1( NSCHello + NSServerOffset );
2004-08-28 05:30:23 +00:00
Reply.Write1(1);
Reply.WriteNT(servername);
SendNetPacket(clientNum, Reply);
2004-08-28 05:30:23 +00:00
if (ClientHost == -1)
ClientHost = clientNum;
}
2004-09-06 23:36:38 +00:00
void GameClient::StyleUpdate(PacketFunctions& Packet)
{
2004-08-28 05:30:23 +00:00
int playernumber = 0;
Player[0].name = Player[1].name = "";
2004-08-28 05:30:23 +00:00
twoPlayers = Packet.Read1()-1;
2004-09-11 17:18:50 +00:00
for (int x = 0; x < twoPlayers+1; ++x)
2004-09-06 23:36:38 +00:00
{
2004-08-28 05:30:23 +00:00
playernumber = Packet.Read1();
Player[playernumber].name = Packet.ReadNT();
}
}
2004-09-06 23:36:38 +00:00
void GameClient::SetClientVersion(int ver, const CString& b)
{
2004-08-28 05:30:23 +00:00
version = ver;
build = b;
}
2004-09-06 23:36:38 +00:00
void GameClient::StartRequest(PacketFunctions& Packet)
{
2004-08-28 05:30:23 +00:00
int firstbyte = Packet.Read1();
int secondbyte = Packet.Read1();
2004-09-01 19:50:30 +00:00
int thirdbyte = Packet.Read1();
2004-08-28 05:30:23 +00:00
Player[0].feet = firstbyte/16;
Player[1].feet = firstbyte%16;
if ((Player[0].feet > 0)&&(Player[1].feet > 0))
twoPlayers = true;
2004-09-01 19:50:30 +00:00
Player[0].diff = secondbyte/16;
Player[1].diff = secondbyte%16;
startPosition = thirdbyte/16;
2004-08-28 05:30:23 +00:00
gameInfo.title = Packet.ReadNT();
gameInfo.subtitle = Packet.ReadNT();
gameInfo.artist = Packet.ReadNT();
gameInfo.course = Packet.ReadNT();
2004-09-06 23:36:38 +00:00
for (int x = 0; x < 2; ++x)
{
2004-09-02 16:39:45 +00:00
Player[x].score = 0;
Player[x].combo = 0;
Player[x].projgrade = 0;
Player[x].maxCombo = 0;
2004-09-06 23:36:38 +00:00
memset(Player[x].steps, 0, sizeof(int)*9);
}
GotStartRequest = true;
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::CheckReady()
{
bool canStart = true;
unsigned int x;
//Only check clients that are starting (after ScreenNetMusicSelect before InGame).
2004-10-30 04:13:45 +00:00
for (x = 0; (x < Client.size()) && canStart; ++x)
2004-10-17 14:46:00 +00:00
{
2004-10-30 04:13:45 +00:00
if (Client[x]->isStarting && !Client[x]->GotStartRequest)
canStart = false;
2004-10-17 14:46:00 +00:00
2004-10-30 04:13:45 +00:00
//Start for courses
if (!Client[x]->inNetMusicSelect && !Client[x]->hasSong && Client[x]->GotStartRequest)
canStart = true;
2004-10-17 14:46:00 +00:00
}
2004-08-28 05:30:23 +00:00
2004-09-06 23:36:38 +00:00
if (canStart)
{
2004-09-06 07:21:53 +00:00
//(Test this)
//For whatever reason we need to pause in a way
//that will not use a lot of CPU.
//When you try playing the music as soon as it's loaded
//it will not always play ... immediately
usleep( int( g_fStartWait * 1000000.0 ) );
2004-09-06 07:21:53 +00:00
//The next three loops are seperate because we want to minimize what is done
//during the actual loop that starts the clients. This is in an atempt
//to start all the clients as close together as possible.
for (x = 0; x < Client.size(); ++x)
2004-10-17 14:46:00 +00:00
{
if (Client[x]->isStarting)
{
Client[x]->clientSocket.blocking = true;
Client[x]->GotStartRequest = false;
}
2004-10-17 14:46:00 +00:00
//For Start for courses
2004-10-30 04:13:45 +00:00
if (!Client[x]->inNetMusicSelect && !Client[x]->hasSong && Client[x]->GotStartRequest)
{
Client[x]->clientSocket.blocking = true;
Client[x]->GotStartRequest = false;
}
2004-10-17 14:46:00 +00:00
}
//Start clients waiting for a start between ScreenNetMusicSelect and the game.
for (x = 0; x < Client.size(); ++x)
2004-10-17 14:46:00 +00:00
{
if (Client[x]->isStarting)
SendValue(NSCGSR + NSServerOffset, x);
2004-10-17 14:46:00 +00:00
//For Start for courses
2004-10-30 04:13:45 +00:00
if (!Client[x]->inNetMusicSelect && !Client[x]->hasSong)
SendValue(NSCGSR + NSServerOffset, x);
2004-10-17 14:46:00 +00:00
}
for (x = 0; x < Client.size(); ++x)
2004-10-17 14:46:00 +00:00
{
if (Client[x]->isStarting)
{
if (Client[x]->startPosition == 1)
2004-09-06 23:36:38 +00:00
{
Client[x]->isStarting = false;
Client[x]->InGame = true;
Client[x]->lowerJudge = false;
//After we start the clients, clear each client's hasSong.
Client[x]->hasSong = false;
}
Client[x]->clientSocket.blocking = false;
}
2004-10-17 14:46:00 +00:00
//For Start for courses
2004-10-30 04:13:45 +00:00
if (!Client[x]->inNetMusicSelect && !Client[x]->hasSong)
{
if (Client[x]->startPosition == 1)
2004-10-17 14:46:00 +00:00
{
2004-10-30 04:13:45 +00:00
Client[x]->isStarting = false;
Client[x]->InGame = true;
Client[x]->lowerJudge = false;
//After we start the clients, clear each client's hasSong.
Client[x]->hasSong = false;
2004-10-17 14:46:00 +00:00
}
2004-10-30 04:13:45 +00:00
Client[x]->clientSocket.blocking = false;
}
2004-10-17 14:46:00 +00:00
}
2004-09-02 21:42:33 +00:00
}
2004-08-28 05:30:23 +00:00
}
void StepManiaLanServer::GameOver(PacketFunctions& Packet, const unsigned int clientNum)
2004-09-06 23:36:38 +00:00
{
2004-09-01 19:50:30 +00:00
bool allOver = true;
unsigned int x;
unsigned int numPlayers = playersPtr.size();
2004-09-01 19:50:30 +00:00
Client[clientNum]->hasSong = Client[clientNum]->forceHas = 0;
Client[clientNum]->GotStartRequest = false;
Client[clientNum]->InGame = false;
Client[clientNum]->wasIngame = true;
for (x = 0; (x < Client.size())&&allOver ; ++x)
if (Client[x]->InGame)
allOver = false;
2004-09-01 19:50:30 +00:00
//Wait until everyone is done before sending
2004-09-06 23:36:38 +00:00
if (allOver)
{
for (x = 0; x < Client.size(); ++x)
2004-10-30 04:13:45 +00:00
if (Client[x]->wasIngame && Client[x]->lowerJudge)
for (int y = 0; y < 2; ++y)
Client[x]->Player[y].options = "TIMING " + playersPtr[x]->options;
SortStats(playersPtr);
2004-09-01 19:50:30 +00:00
Reply.ClearPacket();
Reply.Write1( NSCGON + NSServerOffset );
2004-09-02 21:05:57 +00:00
Reply.Write1( (uint8_t) numPlayers );
2004-09-06 23:36:38 +00:00
for (x = 0; x < numPlayers; ++x)
2004-09-02 23:47:02 +00:00
Reply.Write1((uint8_t)playersPtr[x]->PlayerID);
2004-09-06 23:36:38 +00:00
for (x = 0; x < numPlayers; ++x)
2004-09-01 19:50:30 +00:00
Reply.Write4(playersPtr[x]->score);
2004-09-06 23:36:38 +00:00
for (x = 0; x < numPlayers; ++x)
2004-09-02 21:05:57 +00:00
Reply.Write1( (uint8_t) playersPtr[x]->projgrade );
2004-09-06 23:36:38 +00:00
for (x = 0; x < numPlayers; ++x)
2004-09-02 21:05:57 +00:00
Reply.Write1( (uint8_t) playersPtr[x]->diff );
2004-09-06 23:36:38 +00:00
for (int y = 6; y >= 1; --y)
for (x = 0; x < numPlayers; ++x)
2004-09-02 21:05:57 +00:00
Reply.Write2( (uint16_t) playersPtr[x]->steps[y] );
2004-09-06 23:36:38 +00:00
for (x = 0; x < numPlayers; ++x)
2004-09-02 21:05:57 +00:00
Reply.Write2( (uint16_t) playersPtr[x]->steps[8] ); //Tack on OK
2004-09-06 23:36:38 +00:00
for (x = 0; x < numPlayers; ++x)
2004-09-02 21:05:57 +00:00
Reply.Write2( (uint16_t) playersPtr[x]->maxCombo );
2004-09-06 23:36:38 +00:00
for (x = 0; x < numPlayers; ++x)
2004-09-06 16:29:23 +00:00
Reply.WriteNT( playersPtr[x]->options );
for (x = 0; x < Client.size(); ++x)
if(Client[x]->wasIngame)
2004-09-06 23:36:38 +00:00
{
SendNetPacket(x, Reply);
Client[x]->wasIngame = false;
2004-09-06 17:07:50 +00:00
}
2004-09-01 19:50:30 +00:00
}
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::AssignPlayerIDs()
{
unsigned int counter = 0;
//Future: Figure out how to do dynamic numbering.
for (unsigned int x = 0; x < Client.size(); ++x)
2004-09-06 23:36:38 +00:00
for(int y = 0; y < 2; ++y)
Client[x]->Player[y].PlayerID = counter++;
}
void StepManiaLanServer::PopulatePlayersPtr(vector<LanPlayer*> &playersPtr) {
2004-09-18 06:42:39 +00:00
2004-10-30 04:13:45 +00:00
for (unsigned int x = 0; x < playersPtr.size(); ++x)
playersPtr[x] = NULL;
2004-09-18 06:42:39 +00:00
playersPtr.clear();
//Populate with in game players only
for (unsigned int x = 0; x < Client.size(); ++x)
if (Client[x]->InGame||Client[x]->wasIngame)
for (int y = 0; y < 2; ++y)
if (Client[x]->IsPlaying(y))
2004-09-18 06:42:39 +00:00
playersPtr.push_back(&Client[x]->Player[y]);
}
int StepManiaLanServer::SortStats(vector<LanPlayer*> &playersPtr)
2004-09-06 23:36:38 +00:00
{
2004-08-28 05:30:23 +00:00
LanPlayer *tmp;
2004-09-17 22:22:39 +00:00
bool isChanged;
2004-08-28 05:30:23 +00:00
PopulatePlayersPtr(playersPtr);
2004-08-28 05:30:23 +00:00
2004-09-17 22:22:39 +00:00
do
{
isChanged = false;
for (int x = 0; x < int(playersPtr.size())-1; ++x)
2004-09-06 23:36:38 +00:00
if ((playersPtr[x]->score) < (playersPtr[x+1]->score))
{
2004-08-28 05:30:23 +00:00
tmp = playersPtr[x];
playersPtr[x] = playersPtr[x+1];
playersPtr[x+1] = tmp;
2004-09-17 22:22:39 +00:00
isChanged = true;
2004-08-28 05:30:23 +00:00
}
2004-09-17 22:22:39 +00:00
} while (isChanged);
2004-08-28 05:30:23 +00:00
return playersPtr.size();
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::SendStatsToClients()
{
unsigned int x;
2004-08-28 05:30:23 +00:00
SortStats(playersPtr); //Return number of players
2004-08-28 05:30:23 +00:00
2004-09-17 22:22:39 +00:00
/* Write and Send name packet */
Reply.ClearPacket();
Reply.Write1(NSCGSU + NSServerOffset);
Reply.Write1(0);
Reply.Write1( (uint8_t) playersPtr.size());
StatsNameColumn(Reply, playersPtr);
2004-08-28 05:30:23 +00:00
2004-09-17 22:22:39 +00:00
//Send to in game clients only.
for (x = 0; x < Client.size(); ++x)
if (Client[x]->InGame)
SendNetPacket(x, Reply);
2004-08-28 05:30:23 +00:00
/* Write and send Combo packet */
Reply.ClearPacket();
Reply.Write1(NSCGSU + NSServerOffset);
2004-08-28 05:30:23 +00:00
Reply.Write1(1);
Reply.Write1( (uint8_t) playersPtr.size() );
StatsComboColumn(Reply, playersPtr);
2004-08-28 05:30:23 +00:00
//Send to in game clients only.
for (x = 0; x < Client.size(); ++x)
if (Client[x]->InGame)
SendNetPacket(x, Reply);
2004-08-28 05:30:23 +00:00
/* Write and send projgrade packet*/
//Is it worth the programing troube to save a small amount of bandwidth here?
//Probably not. Sends all everytime unless developer feelings change.
Reply.ClearPacket();
Reply.Write1(NSCGSU + NSServerOffset);
2004-08-28 05:30:23 +00:00
Reply.Write1(2);
Reply.Write1( (uint8_t) playersPtr.size());
StatsProjgradeColumn(Reply, playersPtr);
2004-08-28 05:30:23 +00:00
//Send to in game clients only.
for (x = 0; x < Client.size(); ++x)
if (Client[x]->InGame)
SendNetPacket(x, Reply);
2004-08-28 05:30:23 +00:00
}
void StepManiaLanServer::SendNetPacket(const unsigned int client, PacketFunctions& Packet)
2004-09-06 23:36:38 +00:00
{
if ( client < Client.size() )
Client[client]->clientSocket.SendPack((char*)Packet.Data, Packet.Position);
2004-08-28 05:30:23 +00:00
}
void StepManiaLanServer::StatsNameColumn(PacketFunctions &data, vector<LanPlayer*> &playresPtr)
2004-09-06 23:36:38 +00:00
{
for (unsigned int x = 0; x < playersPtr.size(); ++x)
2004-09-02 21:05:57 +00:00
data.Write1( (uint8_t) playersPtr[x]->PlayerID );
2004-08-28 05:30:23 +00:00
}
void StepManiaLanServer::StatsComboColumn(PacketFunctions &data, vector<LanPlayer*> &playresPtr)
2004-09-06 23:36:38 +00:00
{
for(unsigned int x = 0; x < playersPtr.size(); ++x )
2004-09-01 14:58:59 +00:00
data.Write2( (uint16_t) playersPtr[x]->combo);
2004-08-28 05:30:23 +00:00
}
void StepManiaLanServer::StatsProjgradeColumn(PacketFunctions& data, vector<LanPlayer*> &playresPtr)
2004-09-06 23:36:38 +00:00
{
for(unsigned int x = 0; x < playersPtr.size(); ++x )
2004-08-29 01:51:41 +00:00
data.Write1( (uint8_t) playersPtr[x]->projgrade );
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
bool GameClient::IsPlaying(int x)
{
//If the feet setting is above 0, there must be a player.
2004-08-28 05:30:23 +00:00
if (Player[x].feet > 0)
return true;
return false;
}
2004-09-06 23:36:38 +00:00
void GameClient::UpdateStats(PacketFunctions& Packet)
{
//Get the Stats from a packet
2004-08-28 05:30:23 +00:00
char firstbyte = Packet.Read1();
char secondbyte = Packet.Read1();
int pID = int(firstbyte/16); /* MSN */
2004-09-02 16:39:45 +00:00
Player[pID].currstep = int(firstbyte%16); /* LSN */
Player[pID].projgrade = int(secondbyte/16);
Player[pID].score = Packet.Read4();
Player[pID].combo = Packet.Read2();
if (Player[pID].combo > Player[pID].maxCombo)
Player[pID].maxCombo = Player[pID].combo;
2004-09-02 16:39:45 +00:00
Player[pID].health = Packet.Read2();
Player[pID].offset = ((double)abs(int(Packet.Read2())-32767)/2000);
Player[pID].steps[Player[pID].currstep]++;
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::NewClientCheck()
{
//Make a new client and accept a connection to it.
2004-09-19 03:36:28 +00:00
//If no connection is accepted, delete the client.
2004-09-02 16:39:45 +00:00
2004-09-19 03:36:28 +00:00
GameClient *tmp = new GameClient;
2004-08-28 05:30:23 +00:00
2004-09-19 03:36:28 +00:00
if (server.accept(tmp->clientSocket) == 1)
if (!IsBanned(tmp->clientSocket.address))
{
2004-09-19 03:36:28 +00:00
Client.push_back(tmp);
AssignPlayerIDs();
}
2004-09-19 03:36:28 +00:00
else
2004-10-30 04:13:45 +00:00
{
2004-09-19 03:36:28 +00:00
delete tmp;
2004-10-30 04:13:45 +00:00
tmp = NULL;
}
else
2004-10-30 04:13:45 +00:00
{
2004-09-19 03:36:28 +00:00
delete tmp;
2004-10-30 04:13:45 +00:00
tmp = NULL;
}
2004-08-28 05:30:23 +00:00
}
void StepManiaLanServer::SendValue(uint8_t value, const unsigned int clientNum)
2004-09-06 23:36:38 +00:00
{
if ( clientNum < Client.size() )
Client[clientNum]->clientSocket.SendPack((char*)&value, sizeof(uint8_t));
2004-08-28 05:30:23 +00:00
}
void StepManiaLanServer::AnalizeChat(PacketFunctions &Packet, const unsigned int clientNum)
2004-09-11 17:18:50 +00:00
{
CString message = Packet.ReadNT();
if (message.at(0) == '/')
{
CString command = message.substr(1, message.find(" ")-1);
if ((command.compare("list") == 0)||(command.compare("have") == 0))
2004-10-30 04:13:45 +00:00
{
2004-09-11 17:18:50 +00:00
if (command.compare("list") == 0)
{
Reply.ClearPacket();
Reply.Write1(NSCCM + NSServerOffset);
Reply.WriteNT(ListPlayers());
SendNetPacket(clientNum, Reply);
}
else
{
message = "";
message += Client[clientNum]->Player[0].name;
if (Client[clientNum]->twoPlayers)
message += "&";
message += Client[clientNum]->Player[1].name;
message += " forces has song.";
Client[clientNum]->forceHas = true;
ServerChat(message);
}
2004-10-30 04:13:45 +00:00
}
2004-09-11 17:18:50 +00:00
else
2004-10-30 04:13:45 +00:00
{
2004-09-11 17:18:50 +00:00
if (clientNum == 0)
{
if (command.compare("force_start") == 0)
ForceStart();
if (command.compare("kick") == 0)
{
CString name = message.substr(message.find(" ")+1);
Kick(name);
}
if (command.compare("ban") == 0)
{
CString name = message.substr(message.find(" ")+1);
Ban(name);
}
}
else
{
Reply.ClearPacket();
Reply.Write1(NSCCM + NSServerOffset);
Reply.WriteNT("You do not have permission to use server commands.");
SendNetPacket(clientNum, Reply);
}
2004-10-30 04:13:45 +00:00
}
2004-09-11 17:18:50 +00:00
}
else
RelayChat(message, clientNum);
2004-09-11 17:18:50 +00:00
}
void StepManiaLanServer::RelayChat(CString &passedmessage, const unsigned int clientNum)
2004-09-06 23:36:38 +00:00
{
2004-08-28 05:30:23 +00:00
Reply.ClearPacket();
CString message = "";
message += Client[clientNum]->Player[0].name;
2004-08-28 05:30:23 +00:00
if (Client[clientNum]->twoPlayers)
message += "&";
message += Client[clientNum]->Player[1].name;
2004-08-28 05:30:23 +00:00
message += ": ";
2004-09-11 17:18:50 +00:00
message += passedmessage;
Reply.Write1(NSCCM + NSServerOffset);
2004-08-28 05:30:23 +00:00
Reply.WriteNT(message);
SendToAllClients(Reply);
}
void StepManiaLanServer::SelectSong(PacketFunctions& Packet, unsigned int clientNum)
2004-09-06 23:36:38 +00:00
{
2004-08-28 05:30:23 +00:00
int use = Packet.Read1();
CString message;
2004-09-06 23:36:38 +00:00
if (use == 2)
{
if (clientNum == 0)
{
SecondSameSelect = false;
CurrentSongInfo.title = Packet.ReadNT();
CurrentSongInfo.artist = Packet.ReadNT();
CurrentSongInfo.subtitle = Packet.ReadNT();
2004-08-28 05:30:23 +00:00
Reply.ClearPacket();
Reply.Write1(NSCRSG + NSServerOffset);
2004-08-28 05:30:23 +00:00
Reply.Write1(1);
Reply.WriteNT(CurrentSongInfo.title);
Reply.WriteNT(CurrentSongInfo.artist);
2004-09-02 16:39:45 +00:00
Reply.WriteNT(CurrentSongInfo.subtitle);
2004-08-28 05:30:23 +00:00
//Only send data to clients currently in ScreenNetMusicSelect
for (unsigned int x = 0; x < Client.size(); ++x)
if (Client[x]->inNetMusicSelect)
SendNetPacket(x, Reply);
//The following code forces the host to select the same song twice in order to play it.
2004-10-30 04:13:45 +00:00
if ((strcmp(CurrentSongInfo.title, LastSongInfo.title) == 0) &&
(strcmp(CurrentSongInfo.artist, LastSongInfo.artist) == 0) &&
(strcmp(CurrentSongInfo.subtitle, LastSongInfo.subtitle) == 0))
SecondSameSelect = true;
2004-09-02 16:39:45 +00:00
2004-09-06 23:36:38 +00:00
if (!SecondSameSelect)
{
LastSongInfo.title = CurrentSongInfo.title;
LastSongInfo.artist = CurrentSongInfo.artist;
LastSongInfo.subtitle = CurrentSongInfo.subtitle;
2004-09-11 17:18:50 +00:00
message = "Play \"";
message += CurrentSongInfo.title + " " + CurrentSongInfo.subtitle;
message += "\"?";
ServerChat(message);
}
2004-09-06 23:36:38 +00:00
}
else
{
2004-08-28 05:30:23 +00:00
message = servername;
message += ": You do not have permission to pick a song.";
Reply.ClearPacket();
Reply.Write1(NSCCM + NSServerOffset);
2004-08-28 05:30:23 +00:00
Reply.WriteNT(message);
SendNetPacket(clientNum, Reply);
2004-08-28 05:30:23 +00:00
}
}
2004-09-06 23:36:38 +00:00
if (use == 1)
{
2004-08-28 05:30:23 +00:00
//If user dosn't have song
Client[clientNum]->hasSong = false;
message = Client[clientNum]->Player[0].name;
2004-08-28 05:30:23 +00:00
if (Client[clientNum]->twoPlayers)
2004-09-06 23:36:38 +00:00
{
2004-08-28 05:30:23 +00:00
message += "&";
message += Client[clientNum]->Player[1].name;
2004-08-28 05:30:23 +00:00
}
message += " lacks song \"";
message += CurrentSongInfo.title;
2004-08-28 05:30:23 +00:00
message += "\"";
ServerChat(message);
}
//If client has song
if (use == 0)
Client[clientNum]->hasSong = true;
2004-08-28 05:30:23 +00:00
//Only play if everyone has the same song and the host has select the same song twice.
2004-09-06 23:36:38 +00:00
if ( CheckHasSongState() && SecondSameSelect && (clientNum == 0) )
{
ClientsSongSelectStart();
2004-09-02 16:39:45 +00:00
//Reset last song in case host picks same song again (otherwise dual select is bypassed)
ResetLastSongInfo();
}
}
void StepManiaLanServer::ClientsSongSelectStart()
{
Reply.ClearPacket();
Reply.Write1(NSCRSG + NSServerOffset);
Reply.Write1(2);
Reply.WriteNT(CurrentSongInfo.title);
Reply.WriteNT(CurrentSongInfo.artist);
Reply.WriteNT(CurrentSongInfo.subtitle);
//Only send data to clients currently in ScreenNetMusicSelect that use hasSong
for (unsigned int x = 0; x < Client.size(); ++x)
2004-10-30 04:13:45 +00:00
if (Client[x]->inNetMusicSelect && Client[x]->hasSong)
{
SendNetPacket(x, Reply);
//Designate the client is starting,
//after ScreenNetMusicSelect but before game play (InGame).
Client[x]->isStarting = true;
}
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
bool StepManiaLanServer::CheckHasSongState()
{
for (unsigned int x = 0; x < Client.size(); ++x)
2004-10-30 04:13:45 +00:00
if (Client[x]->inNetMusicSelect && !Client[x]->hasSong)
return false;
2004-08-28 05:30:23 +00:00
return true;
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::ClearHasSong()
{
for (unsigned int x = 0; x < Client.size(); ++x)
Client[x]->hasSong = false;
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::SendToAllClients(PacketFunctions& Packet)
{
for (unsigned int x = 0; x < Client.size(); ++x)
SendNetPacket(x, Packet);
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::ServerChat(const CString& message)
{
2004-09-11 17:18:50 +00:00
CString x = servername + ": " + message;
2004-08-28 05:30:23 +00:00
Reply.ClearPacket();
Reply.Write1(NSCCM + NSServerOffset);
2004-09-11 17:18:50 +00:00
Reply.WriteNT(x);
2004-08-28 05:30:23 +00:00
SendToAllClients(Reply);
}
bool StepManiaLanServer::CheckConnection(const unsigned int clientNum)
2004-09-06 23:36:38 +00:00
{
2004-09-02 16:39:45 +00:00
//If there is an error close the socket.
2004-12-07 06:06:01 +00:00
if ( clientNum >= Client.size() )
return false;
if (Client[clientNum]->clientSocket.IsError())
{
Disconnect(clientNum);
return false;
}
return true;
2004-08-28 05:30:23 +00:00
}
2004-09-06 23:36:38 +00:00
void StepManiaLanServer::SendUserList()
{
Reply.ClearPacket();
Reply.Write1(NSCUUL + NSServerOffset);
2004-09-16 22:07:45 +00:00
Reply.Write1( (uint8_t) Client.size()*2 );
Reply.Write1( (uint8_t) Client.size()*2 );
2004-09-02 16:39:45 +00:00
for (unsigned int x = 0; x < Client.size(); ++x)
2004-09-06 23:36:38 +00:00
for (int y = 0; y < 2; ++y)
{
if (Client[x]->Player[y].name.length() == 0)
2004-09-02 16:39:45 +00:00
Reply.Write1(0);
2004-09-06 23:36:38 +00:00
else
2004-11-07 06:41:53 +00:00
Reply.Write1( (int8_t)Client[x]->NetScreenInfo + 1);
Reply.WriteNT(Client[x]->Player[y].name);
}
2004-09-02 16:39:45 +00:00
SendToAllClients(Reply);
}
void StepManiaLanServer::ScreenNetMusicSelectStatus(PacketFunctions& Packet, unsigned int clientNum)
2004-09-06 23:36:38 +00:00
{
2004-09-11 17:18:50 +00:00
CString message = "";
2004-09-06 23:54:04 +00:00
int EntExitCode = Packet.Read1();
message += Client[clientNum]->Player[0].name;
if (Client[clientNum]->twoPlayers)
2004-09-06 23:54:04 +00:00
message += "&";
message += Client[clientNum]->Player[1].name;
2004-09-06 23:54:04 +00:00
if (EntExitCode % 2 == 1)
Client[clientNum]->inNetMusicSelect = true;
2004-09-06 23:36:38 +00:00
else
Client[clientNum]->inNetMusicSelect = false;
2004-09-06 23:54:04 +00:00
2004-10-29 01:58:56 +00:00
GameClient::LastNetScreen LastScreenInfo = GameClient::NS_NOWHERE;
2004-09-06 23:54:04 +00:00
switch (EntExitCode)
{
case 0:
message += " left the song selection.";
break;
case 1:
message += " entered the song selection.";
2004-10-29 01:58:56 +00:00
LastScreenInfo = GameClient::NS_SELECTSCREEN;
2004-09-06 23:54:04 +00:00
break;
case 2:
2004-10-29 01:58:56 +00:00
message += " exited options.";
2004-09-06 23:54:04 +00:00
break;
case 3:
2004-10-29 01:58:56 +00:00
message += " went into options.";
LastScreenInfo = GameClient::NS_OPTIONS;
break;
case 4:
//no need to mention exiting of options
break;
case 5:
message += " finished the game.";
LastScreenInfo = GameClient::NS_EVALUATION;
2004-09-06 23:54:04 +00:00
break;
}
ServerChat(message);
2004-10-29 01:58:56 +00:00
Client[clientNum]->NetScreenInfo = LastScreenInfo;
SendUserList ();
}
2004-09-11 17:18:50 +00:00
CString StepManiaLanServer::ListPlayers()
{
CString list= "Player List:\n";
for (unsigned int x = 0; x < Client.size(); ++x)
if (Client[x]->inNetMusicSelect)
2004-09-11 17:18:50 +00:00
for (int y = 0; y < 2; ++y)
if (Client[x]->Player[y].name.length() > 0)
list += Client[x]->Player[y].name + "\n";
2004-09-11 17:18:50 +00:00
return list;
}
void StepManiaLanServer::Kick(CString &name)
{
2004-10-30 04:13:45 +00:00
bool kicked = false;
for (unsigned int x = 0; x < Client.size(); ++x)
2004-10-10 04:45:57 +00:00
for (int y = 0; (y < 2)&&(kicked == false); ++y)
if (name == Client[x]->Player[y].name)
{
ServerChat("Kicked " + name + ".");
Disconnect(x);
2004-10-10 04:45:57 +00:00
kicked = true;
}
2004-09-11 17:18:50 +00:00
}
void StepManiaLanServer::Ban(CString &name)
{
2004-10-30 04:13:45 +00:00
bool kicked = false;
for (unsigned int x = 0; x < Client.size(); ++x)
2004-10-10 04:45:57 +00:00
for (int y = 0; (y < 2)&&(kicked == false); ++y)
if (name == Client[x]->Player[y].name)
{
ServerChat("Banned " + name + ".");
bannedIPs.push_back(Client[x]->clientSocket.address);
Disconnect(x);
2004-10-10 04:45:57 +00:00
kicked = true;
}
2004-09-11 17:18:50 +00:00
}
2004-09-12 15:23:34 +00:00
bool StepManiaLanServer::IsBanned(CString &ip)
2004-09-11 17:18:50 +00:00
{
for (unsigned int x = 0; x < bannedIPs.size(); ++x)
2004-09-12 15:23:34 +00:00
if (ip == bannedIPs[x])
2004-09-11 17:18:50 +00:00
return true;
return false;
}
void StepManiaLanServer::ForceStart()
{
//Send the normal stat to clients using hasSong.
ClientsSongSelectStart();
2004-09-11 17:18:50 +00:00
//Reset last song in case host picks same song again (otherwise dual select is bypassed)
ResetLastSongInfo();
2004-09-11 17:18:50 +00:00
//Prepate force_start packet
Reply.ClearPacket();
Reply.Write1(NSCRSG + NSServerOffset);
Reply.Write1(3);
//Only send force_start data to clients currently in ScreenNetMusicSelect using forceHas
for (unsigned int x = 0; x < Client.size(); ++x)
2004-10-30 04:13:45 +00:00
if (Client[x]->inNetMusicSelect && Client[x]->forceHas)
{
SendNetPacket(x, Reply);
//Designate the client is starting,
//after ScreenNetMusicSelect but before game play (InGame).
Client[x]->isStarting = true;
}
}
void StepManiaLanServer::ResetLastSongInfo()
{
LastSongInfo.title = "";
LastSongInfo.artist = "";
LastSongInfo.subtitle = "";
2004-09-11 17:18:50 +00:00
}
void StepManiaLanServer::CheckLowerJudge(const unsigned int clientNum)
{
for (int x = 0; x < 2; ++x)
if (Client[clientNum]->IsPlaying(x))
{
if ((Client[clientNum]->Player[x].currstep == 2)&&
(PREFSMAN->m_fJudgeWindowSecondsBoo < Client[clientNum]->Player[x].offset))
Client[clientNum]->lowerJudge = true;
if ((Client[clientNum]->Player[x].currstep == 3)&&
(PREFSMAN->m_fJudgeWindowSecondsGood < Client[clientNum]->Player[x].offset))
Client[clientNum]->lowerJudge = true;
if ((Client[clientNum]->Player[x].currstep == 4)&&
(PREFSMAN->m_fJudgeWindowSecondsGreat < Client[clientNum]->Player[x].offset))
Client[clientNum]->lowerJudge = true;
if ((Client[clientNum]->Player[x].currstep == 5)&&
(PREFSMAN->m_fJudgeWindowSecondsPerfect < Client[clientNum]->Player[x].offset))
Client[clientNum]->lowerJudge = true;
if ((Client[clientNum]->Player[x].currstep == 6)&&
(PREFSMAN->m_fJudgeWindowSecondsMarvelous < Client[clientNum]->Player[x].offset))
Client[clientNum]->lowerJudge = true;
}
}
2004-09-11 17:18:50 +00:00
#endif
2004-08-28 05:30:23 +00:00
/*
* (c) 2003-2004 Joshua Allen
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/