410 lines
No EOL
8.9 KiB
C++
410 lines
No EOL
8.9 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FILE
|
|
* $Archive: /Commando/Code/WWOnline/PingProfile.cpp $
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* PROGRAMMER
|
|
* $Author: Denzil_l $
|
|
*
|
|
* VERSION INFO
|
|
* $Revision: 8 $
|
|
* $Modtime: 1/11/02 5:45p $
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "always.h"
|
|
#include "PingProfile.h"
|
|
#include <WWOnline\WOLSession.h>
|
|
#include <WWOnline\WOLServer.h>
|
|
#include <WWOnline\WOLString.h>
|
|
#include <WWLib\WideString.h>
|
|
#include <WWDebug\WWDebug.h>
|
|
#include <limits.h>
|
|
#include <math.h>
|
|
|
|
using namespace WWOnline;
|
|
|
|
static PingProfile gPingProfile;
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* RecalculatePingProfile
|
|
*
|
|
* DESCRIPTION
|
|
* Calculate ping profile based on the current session ping times.
|
|
*
|
|
* INPUTS
|
|
* Session - WWOnline session
|
|
*
|
|
* RESULT
|
|
* True if ping times are valid
|
|
*
|
|
******************************************************************************/
|
|
|
|
bool RecalculatePingProfile(const RefPtr<Session>& session)
|
|
{
|
|
memset(gPingProfile.Pings, 0xFF, sizeof(gPingProfile.Pings));
|
|
|
|
if (session.IsValid())
|
|
{
|
|
const PingServerList& pingers = session->GetPingServerList();
|
|
|
|
// The ping profile holds up to eight pings.
|
|
unsigned int count = min<unsigned int>(8, pingers.size());
|
|
|
|
// If there aren't any ping servers then fail.
|
|
if (count > 0)
|
|
{
|
|
for (unsigned int index = 0; index < count; index++)
|
|
{
|
|
int pingTime = pingers[index]->GetPingTime();
|
|
|
|
// If a ping time is invalid then fail.
|
|
if (pingTime < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Clamp pings time to a maximum of 1000 ms
|
|
pingTime = min<int>(pingTime, 1000);
|
|
|
|
// Scale ping time to from 0-1000 to 0-255
|
|
gPingProfile.Pings[index] = (((unsigned long)pingTime * 255) / 1000);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* GetLocalPingProfile
|
|
*
|
|
* DESCRIPTION
|
|
* Get the ping profile for this client.
|
|
*
|
|
* INPUTS
|
|
* NONE
|
|
*
|
|
* RESULT
|
|
* Profile - Ping profile to for current session.
|
|
*
|
|
******************************************************************************/
|
|
|
|
const PingProfile& GetLocalPingProfile(void)
|
|
{
|
|
return gPingProfile;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* ComparePingProfile
|
|
*
|
|
* DESCRIPTION
|
|
* Calcualte the best time between two ping profiles.
|
|
*
|
|
* INPUTS
|
|
* Profile1 - Ping profile
|
|
* Profile2 - Ping profile
|
|
*
|
|
* RESULT
|
|
* Weight - Smallest time between two profiles.
|
|
*
|
|
******************************************************************************/
|
|
|
|
long ComparePingProfile(const PingProfile& ping1, const PingProfile& ping2)
|
|
{
|
|
long minWeight = LONG_MAX;
|
|
|
|
for (int index = 0; index < 8; index++)
|
|
{
|
|
long a = ping1.Pings[index];
|
|
long b = ping2.Pings[index];
|
|
long weight = (a * a) + (b * b);
|
|
|
|
minWeight = min<long>(weight, minWeight);
|
|
}
|
|
|
|
return minWeight;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* EncodePingProfile
|
|
*
|
|
* DESCRIPTION
|
|
* Encode the ping profile into a clear text string that can be transmited
|
|
* via chat.
|
|
*
|
|
* INPUTS
|
|
* Pings - Ping profile to encode.
|
|
* Buffer - Buffer to encode pings into.
|
|
*
|
|
* RESULT
|
|
* Length - Number of characters used to encode the profile.
|
|
*
|
|
******************************************************************************/
|
|
|
|
int EncodePingProfile(const PingProfile& pings, char* buffer)
|
|
{
|
|
assert(buffer != NULL);
|
|
|
|
if (buffer == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
char temp[18];
|
|
int count = sprintf(temp, "%02X%02X%02X%02X%02X%02X%02X%02X",
|
|
pings.Pings[0], pings.Pings[1], pings.Pings[2], pings.Pings[3],
|
|
pings.Pings[4], pings.Pings[5], pings.Pings[6], pings.Pings[7]);
|
|
|
|
strcat(buffer, temp);
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* DecodePingProfile
|
|
*
|
|
* DESCRIPTION
|
|
* Decode the ping profile from clear text string.
|
|
*
|
|
* INPUTS
|
|
* String - Encode ping profile.
|
|
* Pings - Ping profile structure.
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
******************************************************************************/
|
|
|
|
void DecodePingProfile(const char* buffer, PingProfile& pings)
|
|
{
|
|
if (buffer)
|
|
{
|
|
unsigned long ping[8];
|
|
|
|
sscanf(buffer, "%02X%02X%02X%02X%02X%02X%02X%02X",
|
|
&ping[0], &ping[1], &ping[2], &ping[3], &ping[4], &ping[5], &ping[6], &ping[7]);
|
|
|
|
pings.Pings[0] = ping[0];
|
|
pings.Pings[1] = ping[1];
|
|
pings.Pings[2] = ping[2];
|
|
pings.Pings[3] = ping[3];
|
|
pings.Pings[4] = ping[4];
|
|
pings.Pings[5] = ping[5];
|
|
pings.Pings[6] = ping[6];
|
|
pings.Pings[7] = ping[7];
|
|
}
|
|
else
|
|
{
|
|
memset(&pings, 0xFF, sizeof(pings));
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* PingProfileWait::Create
|
|
*
|
|
* DESCRIPTION
|
|
* Create a wait condition to obtain an update ping profile.
|
|
*
|
|
* INPUTS
|
|
* Session - WWOnline session
|
|
*
|
|
* RESULT
|
|
* Wait - Wait condition to process.
|
|
*
|
|
******************************************************************************/
|
|
|
|
RefPtr<PingProfileWait> PingProfileWait::Create(void)
|
|
{
|
|
return new PingProfileWait;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* PingProfileWait::PingProfileWait
|
|
*
|
|
* DESCRIPTION
|
|
* Constructor
|
|
*
|
|
* INPUTS
|
|
*
|
|
* RESULT
|
|
*
|
|
******************************************************************************/
|
|
|
|
PingProfileWait::PingProfileWait() :
|
|
SingleWait(WOLSTRING("WOL_PINGPROFILEREQUEST")),
|
|
mCount(0)
|
|
{
|
|
WWDEBUG_SAY(("WOL: PingProfileWait Instantiated\n"));
|
|
mWOLSession = Session::GetInstance(false);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* PingProfileWait::~PingProfileWait
|
|
*
|
|
* DESCRIPTION
|
|
* Destructor
|
|
*
|
|
* INPUTS
|
|
* NONE
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
******************************************************************************/
|
|
|
|
PingProfileWait::~PingProfileWait()
|
|
{
|
|
WWDEBUG_SAY(("WOL: PingProfileWait Destroyed\n"));
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* PingProfileWait::WaitBeginning
|
|
*
|
|
* DESCRIPTION
|
|
* Begin wait condition
|
|
*
|
|
* INPUTS
|
|
* NONE
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
******************************************************************************/
|
|
|
|
void PingProfileWait::WaitBeginning(void)
|
|
{
|
|
WWDEBUG_SAY(("WOL: PingProfileWait Beginning\n"));
|
|
|
|
if (mWOLSession.IsValid() == false)
|
|
{
|
|
EndWait(Error, WOLSTRING("WOL_NOTINITIALIZED"));
|
|
return;
|
|
}
|
|
|
|
const PingServerList& pingers = mWOLSession->GetPingServerList();
|
|
|
|
// Handle up to eight servers
|
|
mCount = min<unsigned int>(8, pingers.size());
|
|
|
|
if (mCount == 0)
|
|
{
|
|
EndWait(Error, WOLSTRING("WOL_NOPINGSERVER"));
|
|
return;
|
|
}
|
|
|
|
Observer<RawPing>::NotifyMe(*mWOLSession);
|
|
|
|
bool pingsValid = true;
|
|
|
|
for (unsigned int index = 0; index < mCount; index++)
|
|
{
|
|
int pingTime = pingers[index]->GetPingTime();
|
|
|
|
// If a ping time is invalid then request it.
|
|
if (pingTime == -1)
|
|
{
|
|
pingsValid = false;
|
|
|
|
const char* address = pingers[index]->GetHostAddress();
|
|
mWOLSession->RequestPing(address);
|
|
}
|
|
}
|
|
|
|
if (pingsValid)
|
|
{
|
|
RecalculatePingProfile(mWOLSession);
|
|
EndWait(ConditionMet, WOLSTRING("WOL_PINGPROFILERECEIVED"));
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* NAME
|
|
* PingProfileWait::HandleNotification(RawPing)
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* INPUTS
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
******************************************************************************/
|
|
|
|
void PingProfileWait::HandleNotification(RawPing& ping)
|
|
{
|
|
if ((mEndResult == Waiting) && (mCount > 0))
|
|
{
|
|
const char* address = ping.GetHostAddress();
|
|
|
|
const PingServerList& pingers = mWOLSession->GetPingServerList();
|
|
|
|
for (unsigned int index = 0; index < pingers.size(); index++)
|
|
{
|
|
const char* pinger = pingers[index]->GetHostAddress();
|
|
|
|
if (stricmp(address, pinger) == 0)
|
|
{
|
|
WWDEBUG_SAY(("WOL: PingProfileWait received ping for '%s'\n", pingers[index]->GetData().name));
|
|
mCount--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (mCount == 0)
|
|
{
|
|
RecalculatePingProfile(mWOLSession);
|
|
EndWait(ConditionMet, WOLSTRING("WOL_PINGPROFILERECEIVED"));
|
|
}
|
|
}
|
|
} |