This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/WWOnline/PingProfile.cpp

410 lines
8.9 KiB
C++
Raw Permalink Normal View History

/*
** 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"));
}
}
}