Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
493 lines
13 KiB
C++
493 lines
13 KiB
C++
#include "stdafx.h"
|
||
#include "UserStatistics.h"
|
||
|
||
#include <Network/Packet/WrapPacket.h>
|
||
#include <Network/Packet/ManagePacketCmd.h>
|
||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||
#include <Log/ServerLog.h>
|
||
#include <Utility/Setup/ServerSetup.h>
|
||
#include <Network/Dispatch/SingleDispatchStorage.h>
|
||
#include <Network/Dispatch/ManageServer/StatServerMultiDispatch.h>
|
||
#include <atlTime.h>
|
||
|
||
|
||
const TCHAR* g_szAppName = _T("HANGAME_SEND_USER_INFO");
|
||
|
||
|
||
CUserStatistics& CUserStatistics::GetInstance()
|
||
{
|
||
static CUserStatistics userStatistics;
|
||
return userStatistics;
|
||
}
|
||
|
||
CUserStatistics::CUserStatistics()
|
||
{
|
||
SetSetupFileName(_T("./RylSetupServerGroup.ini"));
|
||
Load();
|
||
}
|
||
|
||
CUserStatistics::~CUserStatistics()
|
||
{
|
||
|
||
}
|
||
|
||
|
||
void CUserStatistics::SetSetupFileName(const TCHAR* szFileName)
|
||
{
|
||
if(0 != szFileName)
|
||
{
|
||
_sntprintf(m_szSetupFileName, MAX_PATH - 1, "%s", szFileName);
|
||
m_szSetupFileName[MAX_PATH - 1] = 0;
|
||
}
|
||
}
|
||
|
||
bool CUserStatistics::Load()
|
||
{
|
||
StatisticsLock::Syncronize sync(m_Lock);
|
||
|
||
TCHAR szKeyName[MAX_PATH];
|
||
TCHAR szValue[MAX_PATH];
|
||
|
||
m_ServerGroupNames.clear();
|
||
|
||
unsigned long dwMaxServerGroup = GetPrivateProfileInt(g_szAppName, "MAX_GROUP_NAME", 0, m_szSetupFileName);
|
||
|
||
for(unsigned long dwCount = 0; dwCount < dwMaxServerGroup; ++dwCount)
|
||
{
|
||
_sntprintf(szKeyName, MAX_PATH - 1, "GROUP_KEY%u", dwCount);
|
||
szKeyName[MAX_PATH - 1] = 0;
|
||
|
||
unsigned long dwKey = GetPrivateProfileInt(g_szAppName, szKeyName, 0xFFFFFFFF, m_szSetupFileName);
|
||
|
||
if(dwKey != 0xFFFFFFFF)
|
||
{
|
||
_sntprintf(szKeyName, MAX_PATH - 1, "GROUP_NAME%u", dwCount);
|
||
szKeyName[MAX_PATH - 1] = 0;
|
||
|
||
GetPrivateProfileString(g_szAppName, szKeyName, 0, szValue, MAX_PATH, m_szSetupFileName);
|
||
|
||
m_ServerGroupNames.insert(ServerGroupNames::value_type(dwKey, szValue));
|
||
}
|
||
}
|
||
|
||
GetPrivateProfileString(g_szAppName, "HANGAME_SERVER_DOMAIN", 0, szValue, MAX_PATH, m_szSetupFileName);
|
||
unsigned short usPort = static_cast<unsigned short>(
|
||
GetPrivateProfileInt(g_szAppName, "HANGAME_SERVER_PORT", 0, m_szSetupFileName));
|
||
|
||
hostent* lphost = gethostbyname(szValue);
|
||
if (0 != lphost)
|
||
{
|
||
for (int nCount = 0; 0 != lphost->h_addr_list[nCount]; ++nCount )
|
||
{
|
||
m_HangameAddress.push_back(
|
||
INET_Addr(*(in_addr*)lphost->h_addr_list[nCount], usPort));
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
void CUserStatistics::InternalSetUserNum(unsigned long dwRunID, unsigned long dwServerID, int nCurrentUserNum)
|
||
{
|
||
// ServerID <20><>Ģ üũ dwServerID
|
||
|
||
SERVER_ID serverID;
|
||
serverID.dwID = dwServerID;
|
||
|
||
if(0 <= serverID.GetChannel() && 0 <= serverID.GetGroup() && 0 <= serverID.GetZone())
|
||
{
|
||
UserNumTable::iterator pos = m_CurrentUsers.find(dwServerID);
|
||
if(pos != m_CurrentUsers.end())
|
||
{
|
||
// <20><> <20><><EFBFBD><EFBFBD>
|
||
pos->second = nCurrentUserNum;
|
||
}
|
||
else
|
||
{
|
||
// <20><> <20><><EFBFBD><EFBFBD>
|
||
pos = m_CurrentUsers.insert(pos, UserNumTable::value_type(dwServerID, nCurrentUserNum));
|
||
m_RunIDTable.insert(RunIDTable::value_type(dwRunID, pos));
|
||
}
|
||
}
|
||
}
|
||
|
||
int CUserStatistics::GetUserNum(unsigned long dwServerID)
|
||
{
|
||
StatisticsLock::Syncronize sync(m_Lock);
|
||
UserNumTable::iterator find = m_CurrentUsers.find(dwServerID);
|
||
return (find != m_CurrentUsers.end()) ? find->second : 0;
|
||
}
|
||
|
||
int CUserStatistics::GetTotalUserNum()
|
||
{
|
||
StatisticsLock::Syncronize sync(m_Lock);
|
||
|
||
UserNumTable::iterator pos = m_CurrentUsers.begin();
|
||
UserNumTable::iterator end = m_CurrentUsers.end();
|
||
|
||
int nTotalUser = 0;
|
||
|
||
for(; pos != end; ++pos)
|
||
{
|
||
int nCurrentUser = pos->second;
|
||
|
||
if(0 < nCurrentUser)
|
||
{
|
||
nTotalUser += pos->second;
|
||
}
|
||
}
|
||
|
||
return nTotalUser;
|
||
}
|
||
|
||
int CUserStatistics::GetGroupUserNum(char cGroupNum)
|
||
{
|
||
StatisticsLock::Syncronize sync(m_Lock);
|
||
|
||
UserNumTable::iterator pos = m_CurrentUsers.begin();
|
||
UserNumTable::iterator end = m_CurrentUsers.end();
|
||
|
||
int nTotalUser = 0;
|
||
|
||
SERVER_ID serverID;
|
||
|
||
for(; pos != end; ++pos)
|
||
{
|
||
serverID.dwID = pos->first;
|
||
|
||
if(cGroupNum == serverID.GetGroup())
|
||
{
|
||
int nCurrentUser = pos->second;
|
||
|
||
if(0 < nCurrentUser)
|
||
{
|
||
nTotalUser += pos->second;
|
||
}
|
||
}
|
||
}
|
||
|
||
return nTotalUser;
|
||
}
|
||
|
||
void CUserStatistics::InternalClearRunID_UserNum(unsigned long dwRunID)
|
||
{
|
||
std::pair<RunIDTable::iterator, RunIDTable::iterator>
|
||
resultPair = m_RunIDTable.equal_range(dwRunID);
|
||
|
||
RunIDTable::iterator pos = resultPair.first;
|
||
|
||
for(; pos != resultPair.second; ++pos)
|
||
{
|
||
if(0 != pos->second->second)
|
||
{
|
||
pos->second->second = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CUserStatistics::InternalClearGroupUserNum(unsigned char cGroupNum)
|
||
{
|
||
UserNumTable::iterator pos = m_CurrentUsers.begin();
|
||
UserNumTable::iterator end = m_CurrentUsers.end();
|
||
|
||
SERVER_ID serverID;
|
||
|
||
for(; pos != end; ++pos)
|
||
{
|
||
serverID.dwID = pos->first;
|
||
|
||
if(cGroupNum == serverID.GetGroup())
|
||
{
|
||
pos->second = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CUserStatistics::SerializeIn(unsigned long dwRunID,
|
||
ServerManage::UserNumPair* lpUserNumPair, unsigned long dwPairNum)
|
||
{
|
||
if(0 != lpUserNumPair)
|
||
{
|
||
StatisticsLock::Syncronize sync(m_Lock);
|
||
|
||
ServerManage::UserNumPair* lpUserNumPairEnd = lpUserNumPair + dwPairNum;
|
||
|
||
for(; lpUserNumPair != lpUserNumPairEnd; ++lpUserNumPair)
|
||
{
|
||
InternalSetUserNum(dwRunID, lpUserNumPair->m_dwServerID,
|
||
lpUserNumPair->m_nUserNum);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void CUserStatistics::SendStatisticsToHanGame()
|
||
{
|
||
if(0 == GetPrivateProfileInt(g_szAppName, "SEND_HANGAME_INFO", 0, m_szSetupFileName))
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
|
||
return;
|
||
}
|
||
|
||
char szGameID[256];
|
||
GetPrivateProfileString(g_szAppName, "SEND_GAME_ID", _T("RYL"), szGameID, 256, m_szSetupFileName);
|
||
|
||
UserNumTable CurrentUsers;
|
||
|
||
{
|
||
StatisticsLock::Syncronize sync(m_Lock);
|
||
CurrentUsers = m_CurrentUsers;
|
||
}
|
||
|
||
const int MAX_BUFFER = 3192;
|
||
char szBuffer[MAX_BUFFER];
|
||
|
||
SERVER_ID ServerID;
|
||
int nUserNum = 0;
|
||
int nLength = 0;
|
||
|
||
size_t nMaxGroupName = m_ServerGroupNames.size();
|
||
|
||
SOCKADDR_IN ServerAddr;
|
||
memset(&ServerAddr, 0, sizeof(SOCKADDR_IN));
|
||
|
||
UserNumTable::iterator pos = CurrentUsers.begin();
|
||
UserNumTable::iterator end = CurrentUsers.end();
|
||
|
||
for(; pos != end; ++pos)
|
||
{
|
||
ServerID.dwID = pos->first;
|
||
nUserNum = pos->second;
|
||
|
||
if(ServerID.GetZone() - 1 < 0 || ServerID.GetChannel() < 0)
|
||
{
|
||
|
||
|
||
}
|
||
else if(0 < nUserNum)
|
||
{
|
||
ServerGroupNames::iterator pos = m_ServerGroupNames.find(ServerID.GetGroup());
|
||
|
||
if(pos != m_ServerGroupNames.end())
|
||
{
|
||
// TODO : Sparrowhawk.
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>Ȳ<EFBFBD><C8B2>.. ù <20><><EFBFBD><EFBFBD> GrandCost<73><74> <20><> <20><>ȣ<EFBFBD><C8A3> 1<>̴<EFBFBD>.
|
||
// <20><EFBFBD><D7B7><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><>ȣ<EFBFBD><C8A3> 0<><30><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
// GetServerSession<6F><6E><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̴<EFBFBD>.
|
||
|
||
nLength = _snprintf(szBuffer, MAX_BUFFER,
|
||
"GET /gamestatic/gameconn.nhn?m=gameconn&gameid=%s&servername=%s-%d-%d&conncount=%d\n\n",
|
||
szGameID,
|
||
pos->second.c_str(),
|
||
ServerID.GetZone() - 1,
|
||
ServerID.GetChannel(),
|
||
nUserNum);
|
||
|
||
// <20><><EFBFBD><EFBFBD>
|
||
AddressList::iterator pos = m_HangameAddress.begin();
|
||
AddressList::iterator end = m_HangameAddress.end();
|
||
|
||
bool bSucceeded = false;
|
||
|
||
for (; pos != end && !bSucceeded; ++pos)
|
||
{
|
||
INET_Addr& address = *pos;
|
||
|
||
SOCKET hSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED);
|
||
if (INVALID_SOCKET == hSocket)
|
||
{
|
||
ERRLOG1(g_Log, "Hangame user send failed : socket create failed - %d", WSAGetLastError());
|
||
}
|
||
else if (SOCKET_ERROR == connect(hSocket, &address.get_addr(), address.get_size()))
|
||
{
|
||
ERRLOG1(g_Log, "Hangame user send failed : connect failed - %d", WSAGetLastError());
|
||
}
|
||
else if (SOCKET_ERROR == send(hSocket, szBuffer, nLength, 0))
|
||
{
|
||
ERRLOG1(g_Log, "Hangame user send failed : send failed - %d", WSAGetLastError());
|
||
}
|
||
else
|
||
{
|
||
INFLOG2(g_Log, "'%s':%d bytes send complete", szBuffer, nLength);
|
||
bSucceeded = true;
|
||
}
|
||
|
||
shutdown(hSocket, SD_SEND);
|
||
closesocket(hSocket);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CUserStatistics::SendStatisticsToStatServer()
|
||
{
|
||
int nSendGlobal =
|
||
GetPrivateProfileInt("STATSERVER_INFO", "SEND_STAT_SERVER_1ST", 0, m_szSetupFileName);
|
||
|
||
int nSendLocal =
|
||
GetPrivateProfileInt("STATSERVER_INFO", "SEND_STAT_SERVER_2ND", 0, m_szSetupFileName);
|
||
|
||
int nNation =
|
||
GetPrivateProfileInt("GENERAL", "NATION_INDEX", 0, m_szSetupFileName);
|
||
|
||
if((0 == nSendGlobal) && (0 == nSendLocal))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if(UCHAR_MAX < nNation)
|
||
{
|
||
ERRLOG1(g_Log, "Nation index is invalid: NationIndex-%d", nNation);
|
||
return;
|
||
}
|
||
|
||
SERVER_ID ServerID;
|
||
int nUserNum = 0;
|
||
|
||
UserNumTable CurrentUsers;
|
||
{
|
||
StatisticsLock::Syncronize sync(m_Lock);
|
||
CurrentUsers = m_CurrentUsers;
|
||
}
|
||
|
||
const int MAX_USER_STAT = 1000;
|
||
const int BUFFER_SIZE = sizeof(ServerManage::PktUserStat) +
|
||
sizeof(ServerManage::UserStatData) * MAX_USER_STAT;
|
||
|
||
char szBuffer[BUFFER_SIZE];
|
||
|
||
ServerManage::PktUserStat* lpPktUserStat =
|
||
reinterpret_cast<ServerManage::PktUserStat*>(szBuffer);
|
||
|
||
ServerManage::UserStatData* lpUserStatData =
|
||
reinterpret_cast<ServerManage::UserStatData*>(lpPktUserStat + 1);
|
||
|
||
unsigned short nUserStatData = 0;
|
||
|
||
SYSTEMTIME stCurrentTime;
|
||
GetLocalTime(&stCurrentTime);
|
||
|
||
_snprintf(lpPktUserStat->m_szSendingTime, ServerManage::PktUserStat::MAX_DATE,
|
||
"%04d-%02d-%02d %02d:%02d:%02d",
|
||
stCurrentTime.wYear, stCurrentTime.wMonth, stCurrentTime.wDay,
|
||
stCurrentTime.wHour, stCurrentTime.wMinute, stCurrentTime.wSecond);
|
||
|
||
UserNumTable::iterator pos = CurrentUsers.begin();
|
||
UserNumTable::iterator end = CurrentUsers.end();
|
||
|
||
const int MAX_BUFFER = 256;
|
||
char szGlobalStatServerIP[MAX_BUFFER], szLocalStatServerIP[MAX_BUFFER];
|
||
|
||
GetPrivateProfileString("STATSERVER_INFO", "STAT_SERVER_1ST_IP", 0,
|
||
szGlobalStatServerIP, MAX_BUFFER, m_szSetupFileName);
|
||
GetPrivateProfileString("STATSERVER_INFO", "STAT_SERVER_2ND_IP", 0,
|
||
szLocalStatServerIP, MAX_BUFFER, m_szSetupFileName);
|
||
|
||
GET_MULTI_DISPATCH(lpGlobalStatDispatch, inet_addr(szGlobalStatServerIP),
|
||
CStatServerMultiDispatch, CStatServerMultiDispatch::GetDispatchTable());
|
||
GET_MULTI_DISPATCH(lpLocalStatDispatch, inet_addr(szLocalStatServerIP),
|
||
CStatServerMultiDispatch, CStatServerMultiDispatch::GetDispatchTable());
|
||
|
||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
for(; pos != end; ++pos)
|
||
{
|
||
ServerID.dwID = pos->first;
|
||
nUserNum = pos->second;
|
||
|
||
if(nUserNum < 0)
|
||
{
|
||
nUserNum = 0;
|
||
}
|
||
|
||
if(ServerID.GetZone() - 1 < 0 || ServerID.GetChannel() < 0)
|
||
{
|
||
ERRLOG1(g_Log, "Invalid serverID: %u", ServerID.dwID);
|
||
}
|
||
else if(CServerSetup::GameServer == ServerID.GetType())
|
||
{
|
||
lpUserStatData->m_dwServerID = ServerID.dwID;
|
||
lpUserStatData->m_nNation = nNation;
|
||
lpUserStatData->m_nUserNum = nUserNum;
|
||
|
||
INFLOG3(g_Log, "[UserStat Sended] NationCode: %d/ServerID: 0x%08x/UserNum: %d",
|
||
nNation, ServerID.dwID, nUserNum);
|
||
|
||
++lpUserStatData;
|
||
++nUserStatData;
|
||
}
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
if(nUserStatData == MAX_USER_STAT - 1)
|
||
{
|
||
lpPktUserStat->m_usUserStatDataNum = nUserStatData;
|
||
|
||
if((NULL != lpGlobalStatDispatch) && (1 == nSendGlobal))
|
||
{
|
||
lpGlobalStatDispatch->GetSendStream().WrapCompress(szBuffer,
|
||
sizeof(ServerManage::PktUserStat) + sizeof(ServerManage::UserStatData) * nUserStatData,
|
||
ServerManage::CMD::UPDATE_USER_STATUS, 0, 0);
|
||
}
|
||
|
||
if((NULL != lpLocalStatDispatch) && (1 == nSendLocal))
|
||
{
|
||
lpLocalStatDispatch->GetSendStream().WrapCompress(szBuffer,
|
||
sizeof(ServerManage::PktUserStat) + sizeof(ServerManage::UserStatData) * nUserStatData,
|
||
ServerManage::CMD::UPDATE_USER_STATUS, 0, 0);
|
||
}
|
||
|
||
lpUserStatData = reinterpret_cast<ServerManage::UserStatData*>(lpPktUserStat + 1);
|
||
nUserStatData = 0;
|
||
}
|
||
|
||
if(0 < nUserStatData)
|
||
{
|
||
lpPktUserStat->m_usUserStatDataNum = nUserStatData;
|
||
|
||
if((NULL != lpGlobalStatDispatch) && (1 == nSendGlobal))
|
||
{
|
||
lpGlobalStatDispatch->GetSendStream().WrapCompress(szBuffer,
|
||
sizeof(ServerManage::PktUserStat) + sizeof(ServerManage::UserStatData) * nUserStatData,
|
||
ServerManage::CMD::UPDATE_USER_STATUS, 0, 0);
|
||
}
|
||
|
||
if((NULL != lpLocalStatDispatch) && (1 == nSendLocal))
|
||
{
|
||
lpLocalStatDispatch->GetSendStream().WrapCompress(szBuffer,
|
||
sizeof(ServerManage::PktUserStat) + sizeof(ServerManage::UserStatData) * nUserStatData,
|
||
ServerManage::CMD::UPDATE_USER_STATUS, 0, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
void CUserStatistics::CheckClearUser(PktBase* lpPktBase)
|
||
{
|
||
StatisticsLock::Syncronize sync(m_Lock);
|
||
|
||
if(sizeof(ServerManage::ManageCommand) <= lpPktBase->GetLen())
|
||
{
|
||
ServerManage::ManageCommand* lpManageCommand =
|
||
reinterpret_cast<ServerManage::ManageCommand*>(lpPktBase);
|
||
|
||
int nProcessStatusNum = int(lpManageCommand->usDataLen / sizeof(ServerManage::ProcessStatus));
|
||
|
||
if(sizeof(ServerManage::ManageCommand) + lpManageCommand->usDataLen == lpPktBase->GetLen()
|
||
&& lpManageCommand->usDataLen == nProcessStatusNum * sizeof(ServerManage::ProcessStatus))
|
||
{
|
||
ServerManage::ProcessStatus* lpProcessStatus =
|
||
reinterpret_cast<ServerManage::ProcessStatus*>(lpManageCommand + 1);
|
||
|
||
ServerManage::ProcessStatus* lpProcessStatusEnd = lpProcessStatus + nProcessStatusNum;
|
||
|
||
for(; lpProcessStatus != lpProcessStatusEnd; ++lpProcessStatus)
|
||
{
|
||
if(0 == (ServerManage::PROCESS_RUNNING & lpProcessStatus->m_dwStatusFlags))
|
||
{
|
||
InternalClearRunID_UserNum(lpProcessStatus->m_dwRunID);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|