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/WOLNetUtilObserver.cpp

648 lines
14 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/WOLNetUtilObserver.cpp $
*
* DESCRIPTION
*
* PROGRAMMER
* $Author: Denzil_l $
*
* VERSION INFO
* $Revision: 25 $
* $Modtime: 2/21/02 5:36p $
*
******************************************************************************/
#include <atlbase.h>
#include "WOLNetUtilObserver.h"
#include "WOLSession.h"
#include "WOLLadder.h"
#include "WOLServer.h"
#include "WOLErrorUtil.h"
namespace WWOnline {
/******************************************************************************
*
* NAME
* NetUtilObserver::NetUtilObserver
*
* DESCRIPTION
* Constructor
*
* INPUTS
* NONE
*
* RESULT
* NONE
*
******************************************************************************/
NetUtilObserver::NetUtilObserver() :
mRefCount(1),
mOuter(NULL)
{
WWDEBUG_SAY(("WOL: NetUtilObserver Instantiated\n"));
}
/******************************************************************************
*
* NAME
* NetUtilObserver::~NetUtilObserver
*
* DESCRIPTION
* Destructor
*
* INPUTS
* NONE
*
* RESULT
* NONE
*
******************************************************************************/
NetUtilObserver::~NetUtilObserver()
{
WWDEBUG_SAY(("WOL: NetUtilObserver Destroyed\n"));
}
/******************************************************************************
*
* NAME
* NetUtilObserver::Init
*
* DESCRIPTION
* Initialize Net utility observer
*
* INPUTS
* WOLSession - Outer session
*
* RESULT
* NONE
*
******************************************************************************/
void NetUtilObserver::Init(Session& outer)
{
mOuter = &outer;
}
/****************************************************************************
*
* NAME
* IUnknown::QueryInterface
*
* DESCRIPTION
*
* INPUTS
*
* RESULT
*
****************************************************************************/
STDMETHODIMP NetUtilObserver::QueryInterface(const IID& iid, void** ppv)
{
if ((iid == IID_IUnknown) || (iid == WOL::IID_INetUtilEvent))
{
*ppv = static_cast<WOL::INetUtilEvent*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
static_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
/****************************************************************************
*
* NAME
* IUnknown::AddRef
*
* DESCRIPTION
*
* INPUTS
* NONE
*
* RESULT
*
****************************************************************************/
ULONG STDMETHODCALLTYPE NetUtilObserver::AddRef(void)
{
InterlockedIncrement((LPLONG)&mRefCount);
return mRefCount;
}
/****************************************************************************
*
* NAME
* IUnknown::Release
*
* DESCRIPTION
*
* INPUTS
* NONE
*
* RESULT
*
****************************************************************************/
ULONG STDMETHODCALLTYPE NetUtilObserver::Release(void)
{
InterlockedDecrement((LPLONG)&mRefCount);
if (mRefCount == 0)
{
delete this;
return 0;
}
return mRefCount;
}
/******************************************************************************
*
* NAME
* NetUtilObserver::OnPing
*
* DESCRIPTION
* Handle ping result response to a ping request
*
* INPUTS
* Result - Error / Status code
* Time - Ping time
* IP - IP Address
* Handle - Ping request handle
*
* RESULT
*
******************************************************************************/
STDMETHODIMP NetUtilObserver::OnPing(HRESULT result, int time, unsigned long ip, int handle)
{
if (mOuter == NULL)
{
WWDEBUG_SAY(("WOLERROR: Session not initialized\n"));
WWASSERT(mOuter && "Session not initialized");
return S_OK;
}
if (FAILED(result))
{
WWDEBUG_SAY(("WOLERROR: OnPing '%s'\n", GetNetUtilErrorString(result)));
return S_OK;
}
// Find the ping request
int pingIndex = -1;
for (unsigned int index = 0; index < mOuter->mPingRequests.size(); index++)
{
if (mOuter->mPingRequests[index].GetHandle() == handle)
{
pingIndex = index;
break;
}
}
if ((pingIndex >= 0) && ((unsigned)pingIndex < mOuter->mPingRequests.size()))
{
RawPing* ping = &mOuter->mPingRequests[pingIndex];
ping->SetTime(time);
ping->SetIPAddress(ip);
WWDEBUG_SAY(("WOL: OnPing %s = %d\n", ping->GetHostAddress(), time));
// Automatically update ping time for ping servers.
mOuter->UpdatePingServerTime(ping->GetHostAddress(), time);
// Notify others about the ping result.
mOuter->NotifyObservers(*ping);
// Remove ping from request list.
std::vector<RawPing>::iterator iter = mOuter->mPingRequests.begin();
while (iter != mOuter->mPingRequests.end())
{
if (iter == ping)
{
mOuter->mPingRequests.erase(iter);
mOuter->mPingsPending--;
break;
}
iter++;
}
}
return S_OK;
}
/******************************************************************************
*
* NAME
* NetUtilObserver::OnLadderList
*
* DESCRIPTION
*
* INPUTS
*
* RESULT
*
******************************************************************************/
STDMETHODIMP NetUtilObserver::OnLadderList(HRESULT result, WOL::Ladder* list,
int rungCount, long timeStamp, int keyRung)
{
if (mOuter == NULL)
{
WWDEBUG_SAY(("WOLERROR: Session not initialized\n"));
WWASSERT(mOuter && "Session not initialized");
return S_OK;
}
if (FAILED(result) || (list == NULL))
{
WWDEBUG_SAY(("WOLERROR: OnLadderList '%s'\n", GetNetUtilErrorString(result)));
// Clear the ladder type we requested (in order)
if (mOuter->mLadderPending & LadderType_Individual)
{
mOuter->mLadderPending &= ~LadderType_Individual;
}
else if (mOuter->mLadderPending & LadderType_Team)
{
mOuter->mLadderPending &= ~LadderType_Team;
}
else if (mOuter->mLadderPending & LadderType_Clan)
{
mOuter->mLadderPending &= ~LadderType_Clan;
}
else
{
mOuter->mLadderPending &= ~LADDERTYPE_MASK;
}
// If there are no pending ladders then remove the satisfied requests
if ((mOuter->mLadderPending & LADDERTYPE_MASK) == 0)
{
for (unsigned int count = 0; count < mOuter->mLadderPending; count++)
{
mOuter->mLadderRequests.pop_front();
}
mOuter->mLadderPending = 0;
}
return S_OK;
}
//---------------------------------------------------------------------------
// Handle ladder information for individual users.
//---------------------------------------------------------------------------
if (keyRung == -1)
{
ProcessLadderListResults(list, timeStamp);
return S_OK;
}
//---------------------------------------------------------------------------
// Handle ladder search results
//---------------------------------------------------------------------------
LadderList ladders;
WOL::Ladder* wolLadder = list;
while (wolLadder)
{
RefPtr<LadderData> data = LadderData::Create(*wolLadder, timeStamp);
if (data.IsValid())
{
ladders.push_back(data);
}
wolLadder = wolLadder->next;
}
mOuter->NotifyObservers(ladders);
return S_OK;
}
/******************************************************************************
*
* NAME
* NetUtilObserver::ProcessLadderListResults
*
* DESCRIPTION
*
* INPUTS
*
* RESULT
* NONE
*
******************************************************************************/
void NetUtilObserver::ProcessLadderListResults(WOL::Ladder* list, long timeStamp)
{
if (mOuter->mLadderPending)
{
// Within a given request, ladder results are guaranteed to be in order.
WOL::Ladder* wolLadder = list;
// Extract the ladder request type from the hiword of the SKU
LadderType type = (LadderType)(wolLadder->sku & LADDERTYPE_MASK);
if (type == 0)
{
type = LadderType_Individual;
}
Session::LadderRequestList::iterator request = mOuter->mLadderRequests.begin();
unsigned int ladderCount = 0;
while (wolLadder)
{
// Get the name of the user we requested information for.
const WCHAR* requestName = wcschr(*request, L':');
WWASSERT(requestName != NULL && "Invalid ladder request");
requestName++;
wchar_t ladderName[64];
mbstowcs(ladderName, (const char*)wolLadder->login_name, sizeof(wolLadder->login_name));
WWDEBUG_SAY(("WOL: LadderInfo [%08lX] Requested '%S', Received '%S'\n", type, requestName, ladderName));
// If the ladder name matches the requested name then there is ladder info available.
bool hasLadderData = (wcsicmp(requestName, ladderName) == 0);
if (type == LadderType_Clan)
{
RefPtr<SquadData> squad = SquadData::FindByAbbr(requestName);
if (squad.IsValid())
{
// Update / create ladder information for this clan
RefPtr<LadderData> ladderData = squad->GetLadder();
if (ladderData.IsValid())
{
ladderData->UpdateData(*wolLadder, timeStamp);
}
else if (hasLadderData)
{
ladderData = LadderData::Create(*wolLadder, timeStamp);
WWASSERT(ladderData.IsValid());
squad->SetLadder(ladderData);
}
// Notify others about updated clan ladder information
NotifyClanLadderUpdate(mOuter->mUsers, squad);
NotifyClanLadderUpdate(mOuter->mBuddies, squad);
}
}
else
{
RefPtr<UserData> user = mOuter->GetUserOrBuddy(requestName);
// Update users with new ladder information.
if (user.IsValid())
{
RefPtr<LadderData> ladderData = user->GetLadderFromType(type);
if (ladderData.IsValid())
{
ladderData->UpdateData(*wolLadder, timeStamp);
}
else if (hasLadderData)
{
ladderData = LadderData::Create(*wolLadder, timeStamp);
WWASSERT(ladderData.IsValid());
if (ladderData.IsValid())
{
user->SetLadderFromType(ladderData, type);
}
}
// Notify others that the ladder information for this user has changed.
UserEvent event(UserEvent::LadderInfo, user);
mOuter->NotifyObservers(event);
}
}
// Notify others about the raw ladder information
LadderInfoEvent ladderEvent(ladderName, *wolLadder, timeStamp);
mOuter->NotifyObservers(ladderEvent);
request++;
ladderCount++;
wolLadder = wolLadder->next;
}
// Clear the ladder type we received
mOuter->mLadderPending &= ~type;
// If there are no pending ladders then remove the satisfied requests
if ((mOuter->mLadderPending & LADDERTYPE_MASK) == 0)
{
WWASSERT(ladderCount == mOuter->mLadderPending && "LadderInfo received doesn't match number requested");
for (unsigned int count = 0; count < mOuter->mLadderPending; ++count)
{
mOuter->mLadderRequests.pop_front();
}
mOuter->mLadderPending = 0;
}
}
}
void NetUtilObserver::NotifyClanLadderUpdate(const UserList& users, const RefPtr<SquadData>& squad)
{
const unsigned int userCount = users.size();
for (unsigned int index = 0; index < userCount; ++index)
{
const RefPtr<UserData>& user = users[index];
if (user.IsValid() && (user->GetSquadID() == squad->GetID()))
{
// Notify others that this user received squad information
UserEvent event(UserEvent::LadderInfo, user);
mOuter->NotifyObservers(event);
}
}
}
/******************************************************************************
*
* NAME
* NetUtilObserver::OnGameresSent
*
* DESCRIPTION
*
* INPUTS
*
* RESULT
*
******************************************************************************/
STDMETHODIMP NetUtilObserver::OnGameresSent(HRESULT)
{
WWDEBUG_SAY(("WOLWARNING: OnGameresSent() not implemented\n"));
return S_OK;
}
/******************************************************************************
*
* NAME
* NetUtilObserver::OnNewNick
*
* DESCRIPTION
*
* INPUTS
*
* RESULT
*
******************************************************************************/
STDMETHODIMP NetUtilObserver::OnNewNick(HRESULT result, LPCSTR message, LPCSTR nickname, LPCSTR password)
{
if (mOuter == NULL)
{
WWDEBUG_SAY(("WOLERROR: Session not initialized\n"));
WWASSERT(mOuter && "Session not initialized");
return S_OK;
}
if (FAILED(result))
{
WWDEBUG_SAY(("WOLERROR: OnNewNick '%s'\n", GetNetUtilErrorString(result)));
return S_OK;
}
RefPtr<LoginInfo> login;
if (result == S_OK)
{
login = LoginInfo::Create(nickname, password, true);
}
NewLoginInfoEvent event(login, message);
mOuter->NotifyObservers(event);
return S_OK;
}
/******************************************************************************
*
* NAME
* NetUtilObserver::OnAgeCheck
*
* DESCRIPTION
*
* INPUTS
*
* RESULT
*
******************************************************************************/
STDMETHODIMP NetUtilObserver::OnAgeCheck(HRESULT result, int years, int consent)
{
if (mOuter == NULL)
{
WWDEBUG_SAY(("WOLERROR: Session not initialized\n"));
WWASSERT(mOuter && "Session not initialized");
return S_OK;
}
if (FAILED(result))
{
WWDEBUG_SAY(("WOLERROR: OnAgeCheck '%s'\n", GetNetUtilErrorString(result)));
return S_OK;
}
AgeCheckEvent event(years, consent != 0);
mOuter->NotifyObservers(event);
return S_OK;
}
/******************************************************************************
*
* NAME
* NetUtilObserver::OnWDTState
*
* DESCRIPTION
*
* INPUTS
*
* RESULT
*
******************************************************************************/
STDMETHODIMP NetUtilObserver::OnWDTState(HRESULT result, unsigned char* , int )
{
WWDEBUG_SAY(("WOLWARNING: OnWDTState not implemented\n"));
return S_OK;
}
/******************************************************************************
*
* NAME
* NetUtilObserver::OnHighscore
*
* DESCRIPTION
*
* INPUTS
*
* RESULT
*
******************************************************************************/
STDMETHODIMP NetUtilObserver::OnHighscore(HRESULT result, WOL::Highscore* list,
int count, long time, int keyRung)
{
WWDEBUG_SAY(("WOLWARNING: OnHighscore not implemented\n"));
return S_OK;
}
} // namespace WWOnline