Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1320 lines
40 KiB
C++
1320 lines
40 KiB
C++
//----------------------------------------------------------------------------
|
|
// File: mazeserver.cpp
|
|
//
|
|
// Desc: see main.cpp
|
|
//
|
|
// Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
#define STRICT
|
|
#define D3D_OVERLOADS
|
|
#include <windows.h>
|
|
#include <d3dx.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <mmsystem.h>
|
|
#include <dplay8.h>
|
|
#include <dpaddr.h>
|
|
#include <dxerr8.h>
|
|
#include "DXUtil.h"
|
|
#include "MazeServer.h"
|
|
#include "Packets.h"
|
|
#include "Maze.h"
|
|
#include <malloc.h>
|
|
#include <tchar.h>
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
CMazeServer::CMazeServer()
|
|
{
|
|
m_dwPlayerCount = 0;
|
|
|
|
m_wActiveThreadCount = 0;
|
|
m_wMaxThreadCount = 0;
|
|
m_fAvgThreadCount = 0;
|
|
m_fAvgThreadTime = 0;
|
|
m_fMaxThreadTime = 0;
|
|
|
|
m_dwServerReliableRate = 15;
|
|
m_dwServerTimeout = 150;
|
|
m_dwLogLevel = 2;
|
|
m_pMaze = NULL;
|
|
|
|
m_ClientNetConfig.ubReliableRate = 15;
|
|
m_ClientNetConfig.wUpdateRate = 150;
|
|
m_ClientNetConfig.wTimeout = 150;
|
|
|
|
m_ClientNetConfig.dwThreadWait = 0;
|
|
|
|
m_ClientNetConfig.ubClientPackIndex = 0;
|
|
m_ClientNetConfig.ubServerPackIndex = 0;
|
|
for(WORD x = 0; x < PACK_ARRAY_SIZE; x++)
|
|
{
|
|
m_ClientNetConfig.wClientPackSizeArray[x] = 0;
|
|
m_ClientNetConfig.wServerPackSizeArray[x] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMazeServer::Init( BOOL bLocalLoopback, const CMaze* pMaze )
|
|
{
|
|
m_bLocalLoopback = bLocalLoopback;
|
|
m_pMaze = pMaze;
|
|
if( m_pMaze == NULL )
|
|
return DXTRACE_ERR( TEXT("Param"), E_FAIL );
|
|
|
|
// Grab height and width of maze
|
|
m_dwWidth = m_pMaze->GetWidth();
|
|
m_dwHeight = m_pMaze->GetHeight();
|
|
|
|
m_ClientNetConfig.dwMazeWidth = m_dwWidth;
|
|
m_ClientNetConfig.dwMazeHeight = m_dwHeight;
|
|
|
|
// Validate size. Must be a power-of-2 times LOCK_GRID_SIZE. Compute the shifts.
|
|
if( m_dwWidth > SERVER_MAX_WIDTH || m_dwHeight > SERVER_MAX_HEIGHT )
|
|
return DXTRACE_ERR( TEXT("Maze height and width need to be less than 128"), E_INVALIDARG );
|
|
if( (m_dwWidth % LOCK_GRID_SIZE) != 0 || (m_dwHeight % LOCK_GRID_SIZE) != 0 )
|
|
return DXTRACE_ERR( TEXT("Maze height and width need to be divisable by 16"), E_INVALIDARG );
|
|
|
|
DWORD scale = m_dwWidth / LOCK_GRID_SIZE;
|
|
m_dwMazeXShift = 0;
|
|
while ( (scale >>= 1) )
|
|
m_dwMazeXShift++;
|
|
|
|
scale = m_dwHeight / LOCK_GRID_SIZE;
|
|
m_dwMazeYShift = 0;
|
|
while ( (scale >>= 1) )
|
|
m_dwMazeYShift++;
|
|
|
|
if( ((DWORD(LOCK_GRID_SIZE) << m_dwMazeXShift) != m_dwWidth) ||
|
|
((DWORD(LOCK_GRID_SIZE) << m_dwMazeYShift) != m_dwHeight) )
|
|
return DXTRACE_ERR( TEXT("Maze height and width need to be power of 2"), E_INVALIDARG );
|
|
|
|
// Initialise the player list
|
|
ZeroMemory( m_PlayerDatas, sizeof(m_PlayerDatas) );
|
|
m_pFirstActivePlayerData = NULL;
|
|
m_pFirstFreePlayerData = m_PlayerDatas;
|
|
for( DWORD i = 1; i < MAX_PLAYER_OBJECTS-1; i++ )
|
|
{
|
|
m_PlayerDatas[i].pNext = &m_PlayerDatas[i+1];
|
|
m_PlayerDatas[i].pPrevious = &m_PlayerDatas[i-1];
|
|
}
|
|
|
|
m_PlayerDatas[0].pNext = &m_PlayerDatas[1];
|
|
m_PlayerDatas[MAX_PLAYER_OBJECTS-1].pPrevious = &m_PlayerDatas[MAX_PLAYER_OBJECTS-2];
|
|
m_dwActivePlayerDataCount = 0;
|
|
m_dwPlayerDataUniqueValue = 0;
|
|
|
|
// Initialise the cells
|
|
ZeroMemory( m_Cells, sizeof(m_Cells) );
|
|
ZeroMemory( &m_OffMapCell, sizeof(m_OffMapCell) );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::Shutdown()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::LockRange( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
|
|
{
|
|
m_LockGrid.LockRange( x1>>m_dwMazeXShift, y1>>m_dwMazeYShift ,
|
|
x2>>m_dwMazeXShift, y2>>m_dwMazeYShift );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::UnlockRange( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
|
|
{
|
|
m_LockGrid.UnlockRange( x1>>m_dwMazeXShift, y1>>m_dwMazeYShift ,
|
|
x2>>m_dwMazeXShift, y2>>m_dwMazeYShift );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::LockCell( DWORD x, DWORD y )
|
|
{
|
|
if( x == 0xffff )
|
|
m_OffMapLock.Enter();
|
|
else
|
|
m_LockGrid.LockCell(x>>m_dwMazeXShift,y>>m_dwMazeYShift);
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::UnlockCell( DWORD x, DWORD y )
|
|
{
|
|
if( x == 0xffff )
|
|
m_OffMapLock.Leave();
|
|
else
|
|
m_LockGrid.UnlockCell(x>>m_dwMazeXShift,y>>m_dwMazeYShift);
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::LockCellPair( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
|
|
{
|
|
if( x1 == x2 && y1 == y2 )
|
|
{
|
|
if( x1 != 0xffff && y2 != 0xffff )
|
|
LockCell( x1, y1 );
|
|
else
|
|
m_OffMapLock.Enter();
|
|
|
|
return;
|
|
}
|
|
|
|
DWORD x1shift = x1>>m_dwMazeXShift;
|
|
DWORD x2shift = x2>>m_dwMazeXShift;
|
|
DWORD y1shift = y1>>m_dwMazeYShift;
|
|
DWORD y2shift = y2>>m_dwMazeYShift;
|
|
|
|
if( x1 == 0xffff )
|
|
{
|
|
m_OffMapLock.Enter();
|
|
m_LockGrid.LockCell(x2shift,y2shift);
|
|
}
|
|
else if( x2 == 0xffff )
|
|
{
|
|
m_OffMapLock.Enter();
|
|
m_LockGrid.LockCell(x1shift,y1shift);
|
|
}
|
|
else
|
|
{
|
|
m_LockGrid.LockCellPair(x1shift,y1shift,x2shift,y2shift);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::UnlockCellPair( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
|
|
{
|
|
if( x1 == x2 && y1 == y2 )
|
|
{
|
|
if( x1 != 0xffff && y2 != 0xffff )
|
|
UnlockCell( x1, y1 );
|
|
else
|
|
m_OffMapLock.Leave();
|
|
|
|
return;
|
|
}
|
|
|
|
DWORD x1shift = x1>>m_dwMazeXShift;
|
|
DWORD x2shift = x2>>m_dwMazeXShift;
|
|
DWORD y1shift = y1>>m_dwMazeYShift;
|
|
DWORD y2shift = y2>>m_dwMazeYShift;
|
|
|
|
if( x1 == 0xffff )
|
|
{
|
|
m_LockGrid.UnlockCell(x2shift,y2shift);
|
|
m_OffMapLock.Leave();
|
|
}
|
|
else if( x2 == 0xffff )
|
|
{
|
|
m_LockGrid.UnlockCell(x1shift,y1shift);
|
|
m_OffMapLock.Leave();
|
|
}
|
|
else
|
|
{
|
|
m_LockGrid.UnlockCellPair(x1shift,y1shift,x2shift,y2shift);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::OnAddConnection( DWORD id )
|
|
{
|
|
m_AddRemoveLock.Enter();
|
|
|
|
// Increment our count of players
|
|
m_dwPlayerCount++;
|
|
if( m_dwLogLevel > 0 )
|
|
{
|
|
ConsolePrintf( SLINE_LOG, TEXT("Adding player DPNID %0.8x"), id );
|
|
ConsolePrintf( SLINE_LOG, TEXT("Players connected = %d"), m_dwPlayerCount );
|
|
}
|
|
|
|
if( m_dwPlayerCount > m_dwPeakPlayerCount )
|
|
m_dwPeakPlayerCount = m_dwPlayerCount;
|
|
|
|
// Create a player for this client
|
|
PlayerData* pPlayerData = CreatePlayerData();
|
|
if( pPlayerData == NULL )
|
|
{
|
|
ConsolePrintf( SLINE_LOG, TEXT("ERROR! Unable to create new PlayerData for client!") );
|
|
DXTRACE_ERR( TEXT("CreatePlayerData"), E_FAIL );
|
|
m_AddRemoveLock.Leave();
|
|
return;
|
|
}
|
|
|
|
// Store that pointer as local player data
|
|
SetPlayerDataForID( id, pPlayerData );
|
|
|
|
// Grab net config into to send to client
|
|
m_ClientNetConfigLock.Enter();
|
|
ServerConfigPacket packet( m_ClientNetConfig );
|
|
m_ClientNetConfigLock.Leave();
|
|
|
|
// Send it
|
|
SendPacket( id, &packet, sizeof(packet), TRUE, 0 );
|
|
|
|
m_AddRemoveLock.Leave();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::OnRemoveConnection( DWORD id )
|
|
{
|
|
m_AddRemoveLock.Enter();
|
|
|
|
// Decrement count of players
|
|
m_dwPlayerCount--;
|
|
|
|
if( m_dwLogLevel > 0 )
|
|
{
|
|
ConsolePrintf( SLINE_LOG, TEXT("Removing player DPNID %0.8x"), id );
|
|
ConsolePrintf( SLINE_LOG, TEXT("Players connected = %d"), m_dwPlayerCount );
|
|
}
|
|
|
|
// Find playerdata for this client
|
|
PlayerData* pPlayerData = GetPlayerDataForID( id );
|
|
if( pPlayerData != NULL )
|
|
{
|
|
// Destroy it
|
|
RemovePlayerDataID( pPlayerData );
|
|
DestroyPlayerData( pPlayerData );
|
|
}
|
|
|
|
m_AddRemoveLock.Leave();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMazeServer::OnPacket( DWORD dwFrom, void* pData, DWORD size )
|
|
{
|
|
BOOL fFoundSize = FALSE;
|
|
|
|
// Increment the number of thread we have in this process.
|
|
m_csThreadCountLock.Enter();
|
|
|
|
//Get the start time of when we entered the message handler.
|
|
FLOAT fStartTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
|
|
|
m_wActiveThreadCount++;
|
|
if(m_wActiveThreadCount > m_wMaxThreadCount)
|
|
m_wMaxThreadCount = m_wActiveThreadCount;
|
|
|
|
// Calculate and average.
|
|
FLOAT fdiff = m_wActiveThreadCount - m_fAvgThreadCount;
|
|
m_fAvgThreadCount += fdiff/32;
|
|
|
|
m_csThreadCountLock.Leave();
|
|
|
|
|
|
ClientPacket* pClientPack = (ClientPacket*)pData;
|
|
switch( pClientPack->wType )
|
|
{
|
|
case PACKETTYPE_CLIENT_POS:
|
|
|
|
// Check to see if the packet has a valid size. Including
|
|
// the custom pack size.
|
|
if( size < sizeof(ClientPosPacket))
|
|
fFoundSize = FALSE;
|
|
else if( ! IsValidPackSize(size - sizeof(ClientPosPacket)))
|
|
fFoundSize = FALSE;
|
|
else
|
|
fFoundSize = TRUE;
|
|
|
|
// If valid sized packet, handle the position.
|
|
if(fFoundSize)
|
|
HandleClientPosPacket( dwFrom, (ClientPosPacket*)pClientPack );
|
|
else
|
|
m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
|
|
|
|
break;
|
|
|
|
case PACKETTYPE_CLIENT_VERSION:
|
|
if( size == sizeof(ClientVersionPacket) )
|
|
HandleClientVersionPacket( dwFrom, (ClientVersionPacket*)pClientPack );
|
|
else
|
|
m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
|
|
break;
|
|
|
|
case PACKETTYPE_SERVER_CONFIG:
|
|
|
|
// Server config packet sent to all users (including server). Just ignore and continue.
|
|
|
|
break;
|
|
default:
|
|
HandleUnknownPacket( dwFrom, pClientPack, size );
|
|
break;
|
|
}
|
|
|
|
//If the user wants to hold the thread, Sleep for given amount of time.
|
|
if ( m_dwServerThreadWait > 0 )
|
|
{
|
|
Sleep( m_dwServerThreadWait );
|
|
}
|
|
|
|
// Retrieve thread data for this process.
|
|
m_csThreadCountLock.Enter();
|
|
|
|
m_wActiveThreadCount--;
|
|
|
|
FLOAT fDiffTime = (DXUtil_Timer( TIMER_GETAPPTIME ) - fStartTime) - m_fAvgThreadTime;
|
|
m_fAvgThreadTime += fDiffTime/32;
|
|
|
|
//Get the Max time in the thread.
|
|
if ( fDiffTime > m_fMaxThreadTime )
|
|
{
|
|
m_fMaxThreadTime = fDiffTime;
|
|
}
|
|
|
|
m_csThreadCountLock.Leave();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CMazeServer::IsValidPackSize( DWORD dwSize )
|
|
{
|
|
BOOL fFoundSize = FALSE;
|
|
BYTE ubPackLocation = m_ClientNetConfig.ubClientPackIndex;
|
|
|
|
// Check through the array of valid pack sizes.
|
|
if(dwSize != m_ClientNetConfig.wClientPackSizeArray[ubPackLocation])
|
|
{
|
|
for( --ubPackLocation; ubPackLocation != m_ClientNetConfig.ubClientPackIndex; ubPackLocation--)
|
|
{
|
|
if(dwSize == m_ClientNetConfig.wClientPackSizeArray[ubPackLocation])
|
|
{
|
|
// Found valid size in the array.
|
|
fFoundSize = TRUE;
|
|
break;
|
|
}
|
|
if(ubPackLocation >= PACK_ARRAY_SIZE) ubPackLocation = PACK_ARRAY_SIZE; //Wrap the array.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fFoundSize = TRUE;
|
|
}
|
|
|
|
return fFoundSize;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::OnSessionLost( DWORD dwReason )
|
|
{
|
|
ConsolePrintf( SLINE_LOG, TEXT("ERROR! Session was lost") );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
PlayerData* CMazeServer::CreatePlayerData()
|
|
{
|
|
m_PlayerDataListLock.Enter();
|
|
|
|
// Grab first free player in the list
|
|
PlayerData* pPlayerData = m_pFirstFreePlayerData;
|
|
|
|
if( pPlayerData )
|
|
{
|
|
LockPlayerData( pPlayerData );
|
|
|
|
// Got one, so remove it from the free list
|
|
if( pPlayerData->pPrevious )
|
|
pPlayerData->pPrevious->pNext = pPlayerData->pNext;
|
|
if( pPlayerData->pNext )
|
|
pPlayerData->pNext->pPrevious = pPlayerData->pPrevious;
|
|
m_pFirstFreePlayerData = pPlayerData->pNext;
|
|
|
|
// Add it to the active list
|
|
if( m_pFirstActivePlayerData )
|
|
m_pFirstActivePlayerData->pPrevious = pPlayerData;
|
|
pPlayerData->pNext = m_pFirstActivePlayerData;
|
|
pPlayerData->pPrevious = NULL;
|
|
m_pFirstActivePlayerData = pPlayerData;
|
|
|
|
// Update count of players
|
|
m_dwActivePlayerDataCount++;
|
|
|
|
// Generate the ID for this player
|
|
m_dwPlayerDataUniqueValue++;
|
|
pPlayerData->dwID = (DWORD) ((pPlayerData-m_PlayerDatas)|(m_dwPlayerDataUniqueValue<<PLAYER_OBJECT_SLOT_BITS));
|
|
|
|
pPlayerData->pNextInIDHashBucket = NULL;
|
|
pPlayerData->NetID = 0;
|
|
pPlayerData->dwNumNearbyPlayers = 0;
|
|
|
|
// Insert into the "off-map" cell
|
|
pPlayerData->fPosX = pPlayerData->fPosY = -1;
|
|
pPlayerData->wCellX = pPlayerData->wCellY = 0xffff;
|
|
m_OffMapLock.Enter();
|
|
pPlayerData->pNextInCell = m_OffMapCell.pFirstPlayerData;
|
|
m_OffMapCell.pFirstPlayerData = pPlayerData;
|
|
m_OffMapLock.Leave();
|
|
|
|
// Mark as active
|
|
pPlayerData->bActive = TRUE;
|
|
|
|
UnlockPlayerData( pPlayerData );
|
|
}
|
|
|
|
m_PlayerDataListLock.Leave();
|
|
|
|
return pPlayerData;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::DestroyPlayerData( PlayerData* pPlayerData )
|
|
{
|
|
m_PlayerDataListLock.Enter();
|
|
LockPlayerData( pPlayerData );
|
|
|
|
// Remove the player from its cell
|
|
RemovePlayerDataFromCell( pPlayerData );
|
|
|
|
// Mark as inactive
|
|
pPlayerData->bActive = FALSE;
|
|
|
|
// Remove player from active list
|
|
if( pPlayerData->pPrevious )
|
|
pPlayerData->pPrevious->pNext = pPlayerData->pNext;
|
|
if( pPlayerData->pNext )
|
|
pPlayerData->pNext->pPrevious = pPlayerData->pPrevious;
|
|
|
|
if( m_pFirstActivePlayerData == pPlayerData )
|
|
m_pFirstActivePlayerData = pPlayerData->pNext;
|
|
|
|
// Add it to the free list
|
|
if( m_pFirstFreePlayerData )
|
|
m_pFirstFreePlayerData->pPrevious = pPlayerData;
|
|
pPlayerData->pNext = m_pFirstFreePlayerData;
|
|
pPlayerData->pPrevious = NULL;
|
|
m_pFirstFreePlayerData = pPlayerData;
|
|
|
|
// Update count of players
|
|
m_dwActivePlayerDataCount--;
|
|
|
|
UnlockPlayerData( pPlayerData );
|
|
m_PlayerDataListLock.Leave();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::RemovePlayerDataFromCell( PlayerData* pPlayerData )
|
|
{
|
|
// Lock the player
|
|
LockPlayerData( pPlayerData );
|
|
|
|
// Lock the cell the player is in
|
|
ServerCell* pCell;
|
|
if( pPlayerData->wCellX == 0xffff )
|
|
{
|
|
m_OffMapLock.Enter();
|
|
pCell = &m_OffMapCell;
|
|
}
|
|
else
|
|
{
|
|
LockCell( pPlayerData->wCellX, pPlayerData->wCellY );
|
|
pCell = &m_Cells[pPlayerData->wCellY][pPlayerData->wCellX];
|
|
}
|
|
|
|
// Remove it from the cell
|
|
PlayerData* pPt = pCell->pFirstPlayerData;
|
|
PlayerData* pPrev = NULL;
|
|
while ( pPt )
|
|
{
|
|
if( pPt == pPlayerData )
|
|
{
|
|
if( pPrev )
|
|
pPrev->pNextInCell = pPlayerData->pNextInCell;
|
|
else
|
|
pCell->pFirstPlayerData = pPlayerData->pNextInCell;
|
|
|
|
pPlayerData->pNextInCell = NULL;
|
|
break;
|
|
}
|
|
pPrev = pPt;
|
|
pPt = pPt->pNextInCell;
|
|
}
|
|
|
|
// Unlock the cell
|
|
if( pPlayerData->wCellX == 0xffff )
|
|
m_OffMapLock.Leave();
|
|
else
|
|
UnlockCell( pPlayerData->wCellX, pPlayerData->wCellY );
|
|
|
|
// Unlock the player
|
|
UnlockPlayerData( pPlayerData );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::UnsafeRemovePlayerDataFromCell( PlayerData* pPlayerData )
|
|
{
|
|
ServerCell* pCell = GetCell( pPlayerData );
|
|
PlayerData* pPt = pCell->pFirstPlayerData;
|
|
PlayerData* pPrev = NULL;
|
|
while ( pPt )
|
|
{
|
|
if( pPt == pPlayerData )
|
|
{
|
|
if( pPrev )
|
|
pPrev->pNextInCell = pPlayerData->pNextInCell;
|
|
else
|
|
pCell->pFirstPlayerData = pPlayerData->pNextInCell;
|
|
pPlayerData->pNextInCell = NULL;
|
|
break;
|
|
}
|
|
pPrev = pPt;
|
|
pPt = pPt->pNextInCell;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::UnsafeAddPlayerDataToCell( PlayerData* pPlayerData )
|
|
{
|
|
ServerCell* pCell = GetCell( pPlayerData );
|
|
pPlayerData->pNextInCell = pCell->pFirstPlayerData;
|
|
pCell->pFirstPlayerData = pPlayerData;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::HandleClientPosPacket( DWORD dwFrom, ClientPosPacket* pClientPosPack )
|
|
{
|
|
// Grab player for this client and lock it
|
|
PlayerData* pFromPlayer = GetPlayerDataForID( dwFrom );
|
|
if( pFromPlayer == NULL )
|
|
{
|
|
if( m_dwLogLevel > 1 )
|
|
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Could not find data structure for this player"), pFromPlayer->NetID );
|
|
return;
|
|
}
|
|
|
|
LockPlayerData( pFromPlayer );
|
|
|
|
if( FALSE == pFromPlayer->bAllow )
|
|
{
|
|
if( m_dwLogLevel > 0 )
|
|
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Got position packet from bad client. Rejecting client"), pFromPlayer->NetID );
|
|
|
|
m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
|
|
UnlockPlayerData( pFromPlayer );
|
|
return;
|
|
}
|
|
|
|
// Compute the cell the player should be in now
|
|
DWORD newcellx = int(pClientPosPack->fX);
|
|
DWORD newcelly = int(pClientPosPack->fY);
|
|
DWORD oldcellx = pFromPlayer->wCellX;
|
|
DWORD oldcelly = pFromPlayer->wCellY;
|
|
|
|
// Have we moved cell?
|
|
if( newcellx != oldcellx || newcelly != oldcelly )
|
|
{
|
|
// Yes, so lock the pair of cells in question
|
|
LockCellPair( oldcellx, oldcelly, newcellx, newcelly );
|
|
|
|
// Remove from old cell and add to new cell
|
|
UnsafeRemovePlayerDataFromCell( pFromPlayer );
|
|
pFromPlayer->wCellX = WORD(newcellx); pFromPlayer->wCellY = WORD(newcelly);
|
|
UnsafeAddPlayerDataToCell( pFromPlayer );
|
|
|
|
// Unlock cells
|
|
UnlockCellPair( oldcellx, oldcelly, newcellx, newcelly );
|
|
}
|
|
|
|
// Update player position
|
|
pFromPlayer->fPosX = pClientPosPack->fX;
|
|
pFromPlayer->fPosY = pClientPosPack->fY;
|
|
pFromPlayer->aCameraYaw = pClientPosPack->aCameraYaw;
|
|
|
|
// Allocate space to build the reply packet, and fill in header
|
|
DWORD dwAllocSize;
|
|
ServerAckPacket* pSvrAckPack = NULL;
|
|
|
|
// Begin by allocating a buffer sized according to
|
|
// the current number of nearby players + 4. This will give
|
|
// a little room for more players to come 'near' without resize
|
|
// the buffer.
|
|
DWORD dwMaxPlayerStatePackets = pFromPlayer->dwNumNearbyPlayers + 4;
|
|
|
|
dwAllocSize = sizeof(ServerAckPacket) + dwMaxPlayerStatePackets*sizeof(PlayerStatePacket);
|
|
pSvrAckPack = (ServerAckPacket*) realloc( pSvrAckPack, dwAllocSize );
|
|
if( NULL == pSvrAckPack )
|
|
{
|
|
// Out of mem. Cleanup and return
|
|
UnlockPlayerData( pFromPlayer );
|
|
return;
|
|
}
|
|
ZeroMemory( pSvrAckPack, dwAllocSize );
|
|
|
|
*pSvrAckPack = ServerAckPacket(m_dwPlayerCount);
|
|
pSvrAckPack->wPlayerStatePacketCount = 0;
|
|
PlayerStatePacket* pChunk = (PlayerStatePacket*)(pSvrAckPack+1);
|
|
|
|
// Compute range of cells we're going to scan for players to send
|
|
DWORD minx = (newcellx > 7) ? (newcellx - 7) : 0;
|
|
DWORD miny = (newcelly > 7) ? (newcelly - 7) : 0;
|
|
DWORD maxx = (newcellx+7 >= m_dwWidth) ? m_dwWidth-1 : newcellx+7;
|
|
DWORD maxy = (newcelly+7 >= m_dwHeight) ? m_dwHeight-1 : newcelly+7;
|
|
|
|
// Lock that range of cells
|
|
LockRange( minx, miny, maxx, maxy );
|
|
|
|
// Scan through the cells, tagging player data onto the end of
|
|
// our pSvrAckPacket until we run out of room
|
|
for( DWORD y = miny; y <= maxy; y++ )
|
|
{
|
|
for( DWORD x = minx; x <= maxx; x++ )
|
|
{
|
|
PlayerData* pCurPlayerData = m_Cells[y][x].pFirstPlayerData;
|
|
while ( pCurPlayerData )
|
|
{
|
|
if( pCurPlayerData != pFromPlayer )
|
|
{
|
|
if( pSvrAckPack->wPlayerStatePacketCount >= dwMaxPlayerStatePackets )
|
|
{
|
|
// Make sure pChunk is where we think it is
|
|
assert( (BYTE*) pChunk == (BYTE*) ((BYTE*)pSvrAckPack + sizeof(ServerAckPacket) + pSvrAckPack->wPlayerStatePacketCount*sizeof(PlayerStatePacket)) );
|
|
|
|
// There are more than just 4 new nearby players, so resize the
|
|
// buffer pSvrAckPack to allow 16 more PlayerStatePacket's.
|
|
dwMaxPlayerStatePackets += 16;
|
|
dwAllocSize = sizeof(ServerAckPacket) + dwMaxPlayerStatePackets*sizeof(PlayerStatePacket);
|
|
ServerAckPacket* pNewSvrAckPack = NULL;
|
|
pNewSvrAckPack = (ServerAckPacket*) realloc( pSvrAckPack, dwAllocSize );
|
|
if( NULL == pNewSvrAckPack )
|
|
{
|
|
// Out of mem. Cleanup and return
|
|
free( pSvrAckPack );
|
|
UnlockRange( minx, miny, maxx, maxy );
|
|
UnlockPlayerData( pFromPlayer );
|
|
return;
|
|
}
|
|
|
|
pSvrAckPack = pNewSvrAckPack;
|
|
pChunk = (PlayerStatePacket*) ((BYTE*) ((BYTE*)pSvrAckPack + sizeof(ServerAckPacket) + pSvrAckPack->wPlayerStatePacketCount*sizeof(PlayerStatePacket) ) );
|
|
|
|
// Make sure pChunk is still where its supposed to be
|
|
assert( (BYTE*) pChunk == (BYTE*) ((BYTE*)pSvrAckPack + sizeof(ServerAckPacket) + pSvrAckPack->wPlayerStatePacketCount*sizeof(PlayerStatePacket)) );
|
|
}
|
|
|
|
pChunk->dwID = pCurPlayerData->dwID;
|
|
pChunk->fX = pCurPlayerData->fPosX;
|
|
pChunk->fY = pCurPlayerData->fPosY;
|
|
pChunk->aCameraYaw = pCurPlayerData->aCameraYaw;
|
|
pChunk++;
|
|
pSvrAckPack->wPlayerStatePacketCount++;
|
|
}
|
|
pCurPlayerData = pCurPlayerData->pNextInCell;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the dwNumNearbyPlayers for this player
|
|
pFromPlayer->dwNumNearbyPlayers = pSvrAckPack->wPlayerStatePacketCount;
|
|
|
|
// Unlock range of cells
|
|
UnlockRange( minx, miny, maxx, maxy );
|
|
|
|
if( m_dwLogLevel > 2 )
|
|
{
|
|
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Position is (%0.2f,%0.2f)"), pFromPlayer->NetID, pFromPlayer->fPosX, pFromPlayer->fPosY );
|
|
}
|
|
else if( m_dwLogLevel == 2 )
|
|
{
|
|
FLOAT fTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
|
if( fTime - pFromPlayer->fLastDisplayTime > 60.0f )
|
|
{
|
|
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Position is (%0.2f,%0.2f)"), pFromPlayer->NetID, pFromPlayer->fPosX, pFromPlayer->fPosY );
|
|
pFromPlayer->fLastDisplayTime = fTime;
|
|
}
|
|
}
|
|
|
|
// Unlock the playerdata
|
|
UnlockPlayerData( pFromPlayer );
|
|
|
|
// Send acknowledgement back to client, including list of nearby players
|
|
DWORD acksize = sizeof(ServerAckPacket) + (pSvrAckPack->wPlayerStatePacketCount * sizeof(PlayerStatePacket));
|
|
|
|
// Pack the buffer with dummy data.
|
|
if(m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex] > 0)
|
|
{
|
|
DWORD dwBufferSize = acksize + m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex];
|
|
VOID* pTempBuffer = 0;
|
|
|
|
pTempBuffer = malloc(dwBufferSize);
|
|
if( NULL == pTempBuffer )
|
|
{
|
|
//Out of memory
|
|
DXTRACE_ERR_NOMSGBOX( TEXT("System out of Memory!"), E_OUTOFMEMORY );
|
|
free( pSvrAckPack );
|
|
return;
|
|
}
|
|
|
|
FillMemory(pTempBuffer, dwBufferSize, 'Z');
|
|
memcpy(pTempBuffer, pSvrAckPack, acksize);
|
|
|
|
SendPacket( dwFrom, pTempBuffer, dwBufferSize, FALSE, m_dwServerTimeout );
|
|
|
|
free(pTempBuffer);
|
|
}
|
|
else
|
|
{
|
|
SendPacket( dwFrom, pSvrAckPack, acksize, FALSE, m_dwServerTimeout );
|
|
}
|
|
|
|
free( pSvrAckPack );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::HandleClientVersionPacket( DWORD dwFrom, ClientVersionPacket* pClientVersionPack )
|
|
{
|
|
// Grab playerdata for this client and lock it
|
|
PlayerData* pPlayerData = GetPlayerDataForID( dwFrom );
|
|
if( pPlayerData == NULL )
|
|
return;
|
|
LockPlayerData( pPlayerData );
|
|
|
|
// Record the version number
|
|
pPlayerData->dwVersion = pClientVersionPack->dwVersion;
|
|
|
|
if( m_bLocalLoopback )
|
|
pPlayerData->bAllow = TRUE;
|
|
else
|
|
pPlayerData->bAllow = IsClientVersionSupported( pClientVersionPack->dwVersion );
|
|
|
|
if( m_dwLogLevel > 0 )
|
|
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Client version=%d (%s)"), pPlayerData->NetID, pPlayerData->dwVersion, pPlayerData->bAllow ? TEXT("Accepted") : TEXT("Rejected") );
|
|
|
|
if( FALSE == pPlayerData->bAllow )
|
|
{
|
|
if( m_dwLogLevel > 0 )
|
|
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Rejecting client"), pPlayerData->NetID );
|
|
|
|
m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
|
|
UnlockPlayerData( pPlayerData );
|
|
return;
|
|
}
|
|
|
|
// Unlock the playerdata
|
|
UnlockPlayerData( pPlayerData );
|
|
|
|
// Send acknowledgement to client that the client was either accepted or rejected
|
|
ServerAckVersionPacket packet( pPlayerData->bAllow, dwFrom );
|
|
SendPacket( dwFrom, &packet, sizeof(packet), TRUE, 0 );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CMazeServer::IsClientVersionSupported( DWORD dwClientVersion )
|
|
{
|
|
switch( dwClientVersion )
|
|
{
|
|
case 107: // only v107 is supported
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::HandleUnknownPacket( DWORD dwFrom, ClientPacket* pClientPack, DWORD size )
|
|
{
|
|
if( m_dwLogLevel > 1 )
|
|
ConsolePrintf( SLINE_LOG, TEXT("ERROR! Unknown %d byte packet from player %0.8x"), size, dwFrom );
|
|
|
|
m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CMazeServer::IDHash( DWORD id )
|
|
{
|
|
DWORD hash = ((id) + (id>>8) + (id>>16) + (id>>24)) & (NUM_ID_HASH_BUCKETS-1);
|
|
return hash;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::RemovePlayerDataID( PlayerData* pPlayerData )
|
|
{
|
|
// Hash the ID to a bucket number
|
|
DWORD bucket = IDHash( pPlayerData->NetID );
|
|
|
|
// Lock that hash bucket
|
|
const DWORD buckets_per_lock = NUM_ID_HASH_BUCKETS / NUM_ID_HASH_BUCKET_LOCKS;
|
|
m_IDHashBucketLocks[bucket/buckets_per_lock].Enter();
|
|
|
|
// Loop though players in bucket until we find the right one
|
|
PlayerData* pPt = m_pstIDHashBucket[bucket];
|
|
PlayerData* pPrev = NULL;
|
|
while( pPt )
|
|
{
|
|
if( pPt == pPlayerData )
|
|
break;
|
|
pPrev = pPt;
|
|
pPt = pPt->pNextInIDHashBucket;
|
|
}
|
|
|
|
if( pPt )
|
|
{
|
|
if( pPrev )
|
|
pPrev->pNextInIDHashBucket = pPt->pNextInIDHashBucket;
|
|
else
|
|
m_pstIDHashBucket[bucket] = pPt->pNextInIDHashBucket;
|
|
pPt->pNextInIDHashBucket = NULL;
|
|
}
|
|
|
|
// Unlock the hash bucket
|
|
m_IDHashBucketLocks[bucket/buckets_per_lock].Leave();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::SetPlayerDataForID( DWORD id, PlayerData* pPlayerData )
|
|
{
|
|
// Make sure this player isn't added twice to the m_pstIDHashBucket[]
|
|
// otherwise there will be a circular reference
|
|
PlayerData* pSearch = GetPlayerDataForID( id );
|
|
if( pSearch != NULL )
|
|
return;
|
|
|
|
// Hash the ID to a bucket number
|
|
DWORD bucket = IDHash( id );
|
|
|
|
// Lock that hash bucket
|
|
const DWORD buckets_per_lock = NUM_ID_HASH_BUCKETS / NUM_ID_HASH_BUCKET_LOCKS;
|
|
m_IDHashBucketLocks[bucket/buckets_per_lock].Enter();
|
|
|
|
// Add player onto hash bucket chain
|
|
pPlayerData->pNextInIDHashBucket = m_pstIDHashBucket[bucket];
|
|
m_pstIDHashBucket[bucket] = pPlayerData;
|
|
|
|
// Store net id in player
|
|
pPlayerData->NetID = id;
|
|
|
|
// Unlock the hash bucket
|
|
m_IDHashBucketLocks[bucket/buckets_per_lock].Leave();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
PlayerData* CMazeServer::GetPlayerDataForID( DWORD id )
|
|
{
|
|
// Hash the ID to a bucket number
|
|
DWORD bucket = IDHash( id );
|
|
|
|
// Lock that hash bucket
|
|
const DWORD buckets_per_lock = NUM_ID_HASH_BUCKETS / NUM_ID_HASH_BUCKET_LOCKS;
|
|
m_IDHashBucketLocks[bucket/buckets_per_lock].Enter();
|
|
|
|
// Loop though players in bucket until we find the right one
|
|
PlayerData* pPlayerData = m_pstIDHashBucket[bucket];
|
|
while ( pPlayerData )
|
|
{
|
|
if( pPlayerData->NetID == id )
|
|
break;
|
|
pPlayerData = pPlayerData->pNextInIDHashBucket;
|
|
}
|
|
|
|
// Unlock the hash bucket
|
|
m_IDHashBucketLocks[bucket/buckets_per_lock].Leave();
|
|
|
|
// Return the player we found (will be NULL if we couldn't find it)
|
|
return pPlayerData;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc: calls DisplayConnectionInfo for each connection in a round-robin manner
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::DisplayNextConnectionInfo()
|
|
{
|
|
if( m_pNet )
|
|
{
|
|
// Find the player that was displayed the longest time ago, and display it.
|
|
FLOAT fCurTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
|
PlayerData* pOldestPlayerData = NULL;
|
|
FLOAT fOldestTime = 0.0f;
|
|
|
|
m_PlayerDataListLock.Enter();
|
|
|
|
PlayerData* pPlayerData = m_pFirstActivePlayerData;
|
|
while ( pPlayerData )
|
|
{
|
|
if( fCurTime - pPlayerData->fLastCITime > fOldestTime )
|
|
{
|
|
fOldestTime = fCurTime - pPlayerData->fLastCITime;
|
|
pOldestPlayerData = pPlayerData;
|
|
}
|
|
|
|
pPlayerData = pPlayerData->pNext;
|
|
}
|
|
|
|
// Display the player with the oldest CI field, and update its CI field.
|
|
if( pOldestPlayerData )
|
|
{
|
|
ConsolePrintf( SLINE_LOG, TEXT("Displaying connection info for next player") );
|
|
DisplayConnectionInfo( pOldestPlayerData->NetID );
|
|
pOldestPlayerData->fLastCITime = fCurTime;
|
|
}
|
|
else
|
|
{
|
|
ConsolePrintf( SLINE_LOG, TEXT("No players found") );
|
|
}
|
|
|
|
m_PlayerDataListLock.Leave();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::PrintStats()
|
|
{
|
|
ConsolePrintf( SLINE_LOG, TEXT("Thread count: Active=%d Avg=%.2f Max=%d"),
|
|
m_wActiveThreadCount, m_fAvgThreadCount, m_wMaxThreadCount );
|
|
ConsolePrintf( SLINE_LOG, TEXT("Thread Time: Avg=%.4f Max=%.4f(s)"),
|
|
m_fAvgThreadTime, m_fMaxThreadTime );
|
|
ConsolePrintf( SLINE_LOG, TEXT("Players online (not including server player): %d"), m_dwPlayerCount );
|
|
ConsolePrintf( SLINE_LOG, TEXT("Peak player count: %d"), m_dwPeakPlayerCount );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::DisplayConnectionInfo( DWORD dwID )
|
|
{
|
|
TCHAR strInfo[5000];
|
|
TCHAR* strEndOfLine;
|
|
TCHAR* strStartOfLine;
|
|
|
|
// Query the IOutboudNet for info about the connection to this user
|
|
m_pNet->GetConnectionInfo( dwID, strInfo );
|
|
|
|
ConsolePrintf( SLINE_LOG, TEXT("Displaying connection info for %0.8x"), dwID );
|
|
ConsolePrintf( SLINE_LOG, TEXT("(Key: G=Guaranteed NG=Non-Guaranteed B=Bytes P=Packets)") );
|
|
|
|
// Display each line seperately
|
|
strStartOfLine = strInfo;
|
|
while( TRUE )
|
|
{
|
|
strEndOfLine = _tcschr( strStartOfLine, '\n' );
|
|
if( strEndOfLine == NULL )
|
|
break;
|
|
|
|
*strEndOfLine = 0;
|
|
ConsolePrintf( SLINE_LOG, strStartOfLine );
|
|
strStartOfLine = strEndOfLine + 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMazeServer::SendPacket( DWORD to, void* pData,
|
|
DWORD size, BOOL reliable, DWORD dwTimeout )
|
|
{
|
|
// Chance of forcing any packet to be delivered reliably
|
|
if( m_Rand.Get( 100 ) < m_dwServerReliableRate )
|
|
reliable = TRUE;
|
|
|
|
return m_pNet->SendPacket( to, pData, size, reliable, dwTimeout );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::SendConfigPacketToAll( ServerConfigPacket* pPacket )
|
|
{
|
|
// If we're up and running, then send this new information to all clients
|
|
if( m_pNet )
|
|
{
|
|
//Use the AllPlayers ID
|
|
SendPacket( DPNID_ALL_PLAYERS_GROUP, pPacket, sizeof(ServerConfigPacket), TRUE, 0 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::SetClientReliableRate( DWORD percent )
|
|
{
|
|
// Update client config, and build packet containing that data
|
|
m_ClientNetConfigLock.Enter();
|
|
m_ClientNetConfig.ubReliableRate = BYTE(percent);
|
|
ServerConfigPacket packet( m_ClientNetConfig );
|
|
m_ClientNetConfigLock.Leave();
|
|
|
|
SendConfigPacketToAll( &packet );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::SetClientUpdateRate( DWORD rate )
|
|
{
|
|
// Update client config, and build packet containing that data
|
|
m_ClientNetConfigLock.Enter();
|
|
m_ClientNetConfig.wUpdateRate = WORD(rate);
|
|
ServerConfigPacket packet( m_ClientNetConfig );
|
|
m_ClientNetConfigLock.Leave();
|
|
|
|
SendConfigPacketToAll( &packet );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::SetClientTimeout( DWORD timeout )
|
|
{
|
|
// Update client config, and build packet containing that data
|
|
m_ClientNetConfigLock.Enter();
|
|
m_ClientNetConfig.wTimeout = WORD(timeout);
|
|
ServerConfigPacket packet( m_ClientNetConfig );
|
|
m_ClientNetConfigLock.Leave();
|
|
|
|
SendConfigPacketToAll( &packet );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::SetClientPackSize( DWORD size )
|
|
{
|
|
// Update client config, and build packet containing that data
|
|
m_ClientNetConfigLock.Enter();
|
|
|
|
m_ClientNetConfig.ubClientPackIndex++; //Increase index and verify location in array.
|
|
if(m_ClientNetConfig.ubClientPackIndex >= PACK_ARRAY_SIZE)
|
|
m_ClientNetConfig.ubClientPackIndex = 0;
|
|
|
|
m_ClientNetConfig.wClientPackSizeArray[m_ClientNetConfig.ubClientPackIndex] = WORD(size);
|
|
ServerConfigPacket packet( m_ClientNetConfig );
|
|
m_ClientNetConfigLock.Leave();
|
|
|
|
SendConfigPacketToAll( &packet );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::SetServerPackSize( DWORD size )
|
|
{
|
|
// Update client config, and build packet containing that data
|
|
m_ClientNetConfigLock.Enter();
|
|
|
|
m_ClientNetConfig.ubServerPackIndex++; //Increase index and verify location in array.
|
|
if(m_ClientNetConfig.ubServerPackIndex >= PACK_ARRAY_SIZE)
|
|
m_ClientNetConfig.ubServerPackIndex = 0;
|
|
|
|
m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex] = WORD(size);
|
|
ServerConfigPacket packet( m_ClientNetConfig );
|
|
m_ClientNetConfigLock.Leave();
|
|
|
|
SendConfigPacketToAll( &packet );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
void CMazeServer::SetClientThreadWait( DWORD dwThreadWait )
|
|
{
|
|
// Update client config, and build packet containing that data
|
|
m_ClientNetConfigLock.Enter();
|
|
|
|
m_ClientNetConfig.dwThreadWait = dwThreadWait;
|
|
ServerConfigPacket packet( m_ClientNetConfig );
|
|
m_ClientNetConfigLock.Leave();
|
|
|
|
SendConfigPacketToAll( &packet );
|
|
}
|