- 在线时间
- 1957 小时
- 最后登录
- 2024-6-29
- 注册时间
- 2004-4-26
- 听众数
- 49
- 收听数
- 0
- 能力
- 60 分
- 体力
- 40960 点
- 威望
- 6 点
- 阅读权限
- 255
- 积分
- 23863
- 相册
- 0
- 日志
- 0
- 记录
- 0
- 帖子
- 20501
- 主题
- 18182
- 精华
- 5
- 分享
- 0
- 好友
- 140
TA的每日心情 | 奋斗 2024-6-23 05:14 |
|---|
签到天数: 1043 天 [LV.10]以坛为家III
 群组: 万里江山 群组: sas讨论小组 群组: 长盛证券理财有限公司 群组: C 语言讨论组 群组: Matlab讨论组 |
<DIV class=HtmlCode>6 G4 L+ ]0 |+ n8 Q# @, T& l( N
< >// File: mazeserver.cpp
+ L$ }& i8 w H1 B s9 z; Y6 \8 m//
6 Q$ o2 ^' G% w4 `9 u, m// Desc: see main.cpp5 Z8 o, }& {2 e+ ^2 f8 B0 m
//9 F* `$ a; H9 S, i& ~' Z7 @; A
// Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.( x1 x z: l: c1 P3 P C
//-----------------------------------------------------------------------------5 g# h+ B5 y% Z9 ^
#define STRICT
2 |9 G% C: \- s! @# o! \$ R+ h- F2 O$ j#define D3D_OVERLOADS, @$ [* c1 |. I- Y+ s
#include <windows.h>
" u; P" \0 ?1 a1 ^: W/ Z#include <d3dx.h>
) Q, E2 E A5 t4 D# b#include <stdio.h>
, a. q: v q2 [+ T( b#include <math.h>
9 \: @/ [* r; z7 l$ O$ t( q6 g#include <mmsystem.h>
; a. _; R8 ^# F+ f7 I$ U8 u/ t4 u7 F#include <dplay8.h>+ F- |# G( e1 |2 _( f7 x3 _
#include <dpaddr.h>
" M! x8 s4 T I0 [5 c5 K2 ]" e v; ^#include <dxerr8.h> S9 Y1 U3 ?7 T1 m$ j1 O3 H
#include "DXUtil.h"( V( D0 V7 f/ y
#include "MazeServer.h"
0 N3 E& `- i; r3 }; q: P" V#include " ackets.h"
8 w$ S! l! c* T+ T#include "Maze.h"
2 D2 b0 J Z `$ [5 q$ s#include <malloc.h>
+ ^3 k! \7 c$ O7 t4 e3 p#include <tchar.h></P>
' v0 k; J3 ^8 E0 B
$ X/ U- X4 t* s< >//-----------------------------------------------------------------------------
b7 ^. A2 m! T7 G; ?// Name: * d0 O1 d# a' x: T
// Desc: * U0 W/ E$ A9 Y
//-----------------------------------------------------------------------------
$ K% m+ E. T; k6 g/ {CMazeServer::CMazeServer()
U! {' K2 r8 c/ @{
. z% {9 @5 l( O' }( p! Y m_dwPlayerCount = 0;
. r- G' _2 p3 @ R5 W7 z - m' z0 O, Q) j+ K: N9 X
m_wActiveThreadCount = 0;
' O) Q0 k# g- t) W m_wMaxThreadCount = 0;% }4 K: m. Z y, I t
m_fAvgThreadCount = 0;
1 j8 e" o) U1 z m_fAvgThreadTime = 0;9 B+ c% I) O1 A6 O/ }+ u
m_fMaxThreadTime = 0;</P>
5 _! q% i" ` w( |2 \; f. H< > m_dwServerReliableRate = 15;
0 s. K" J- p" l/ S$ A m_dwServerTimeout = 150;
3 m0 }8 G& {5 c3 F2 ?5 i3 t6 a2 R m_dwLogLevel = 2;/ h' w- H) N1 Q: _
m_pMaze = NULL;</P>2 |/ `3 m8 ^! T; k' ?
< > m_ClientNetConfig.ubReliableRate = 15;
; q6 F, f1 V( n m_ClientNetConfig.wUpdateRate = 150;
2 p5 t- V# D8 D1 B m_ClientNetConfig.wTimeout = 150;</P>
( @5 w7 i. S3 E! `" A- }( A' O< > m_ClientNetConfig.dwThreadWait = 0;</P>
( Z" u5 D# {: |. @3 B< > m_ClientNetConfig.ubClientPackIndex = 0;; ~2 h: m2 e) U' b) Y
m_ClientNetConfig.ubServerPackIndex = 0;( V# _: {& m' m% n
for(WORD x = 0; x < PACK_ARRAY_SIZE; x++)1 @! a: k% ?' K+ v% K
{0 d( E2 ~+ S' t
m_ClientNetConfig.wClientPackSizeArray[x] = 0;
* F8 ^9 W4 \2 ]6 X. T1 G m_ClientNetConfig.wServerPackSizeArray[x] = 0; a. W$ s1 U" s' Z- ]
}
+ a' p6 ^, u+ M' w/ m5 r}</P>8 X! X5 |& [/ C2 A* x
) o& q% _# O$ ?6 R' ?; i& h7 F" j
< >3 p) q$ I+ i- |8 y- m. D( j
//-----------------------------------------------------------------------------
( }" b$ J4 O1 f8 ?8 t// Name: ! \5 l' l; R9 l1 f- f
// Desc:
# N [4 x" ?: @! e8 `0 {. m, @: B//-----------------------------------------------------------------------------
3 V0 B8 K$ P9 ]( Y* P2 y9 ^HRESULT CMazeServer::Init( BOOL bLocalLoopback, const CMaze* pMaze )! C# [3 \+ [6 l7 r8 [' ]; T/ v; R
{
, D) [5 J( c# N3 D; x4 H m_bLocalLoopback = bLocalLoopback;
& i( J( S- p; |% W+ v) s4 c m_pMaze = pMaze;
' H% s6 n, F" Q) S4 ] if( m_pMaze == NULL )2 H+ X% k6 G4 q. c3 q+ X [
return DXTRACE_ERR( TEXT(" aram"), E_FAIL );</P>. `& J: u' g9 N2 |# D/ v0 s
< > // Grab height and width of maze6 ]! |' P* C6 q1 ?* d
m_dwWidth = m_pMaze->GetWidth();
2 v- `3 b1 D& e m_dwHeight = m_pMaze->GetHeight();</P>
5 J3 n( d7 Y2 C' \6 J1 o" V< > m_ClientNetConfig.dwMazeWidth = m_dwWidth;) b' {; h$ r7 B6 B `
m_ClientNetConfig.dwMazeHeight = m_dwHeight;</P>( ~- g# }& Q7 a1 j& ]: x, C
< > // Validate size. Must be a power-of-2 times LOCK_GRID_SIZE. Compute the shifts.0 v) E- e, m* ~( W" z% G, ^
if( m_dwWidth > SERVER_MAX_WIDTH || m_dwHeight > SERVER_MAX_HEIGHT )
/ V3 ]5 U4 c/ E& t7 v+ {! c return DXTRACE_ERR( TEXT("Maze height and width need to be less than 128"), E_INVALIDARG );9 r# \0 |/ f8 U7 c! z, N
if( (m_dwWidth % LOCK_GRID_SIZE) != 0 || (m_dwHeight % LOCK_GRID_SIZE) != 0 )
6 h2 K: a# x4 e9 N return DXTRACE_ERR( TEXT("Maze height and width need to be divisable by 16"), E_INVALIDARG );</P>
0 G c U J8 c2 u# b* @: j2 A< > DWORD scale = m_dwWidth / LOCK_GRID_SIZE;6 o4 a3 E$ C. H/ @. H3 V1 ^$ Q
m_dwMazeXShift = 0;
' y4 d; J* a y4 |( V% C+ T% S" x v while ( (scale >>= 1) )# f: J8 ~8 V9 L7 X
m_dwMazeXShift++;</P>+ q1 ~+ U; p! l( e, O. ^9 r4 l
< > scale = m_dwHeight / LOCK_GRID_SIZE;. H2 v% x; Z S4 }( j* e" x
m_dwMazeYShift = 0;' R i1 r$ Z2 B, l6 [
while ( (scale >>= 1) ): U9 P5 z! [- }* A: O
m_dwMazeYShift++;</P>
' x' x8 M4 V/ ~9 I0 I< > if( ((DWORD(LOCK_GRID_SIZE) << m_dwMazeXShift) != m_dwWidth) ||' w% r0 z4 m6 N$ D. I
((DWORD(LOCK_GRID_SIZE) << m_dwMazeYShift) != m_dwHeight) )0 p, p! d- h2 w2 x: g7 x
return DXTRACE_ERR( TEXT("Maze height and width need to be power of 2"), E_INVALIDARG );</P>
$ p) @+ `8 S4 O< > // Initialise the player list
* Z. l7 A0 k* h# R) O ZeroMemory( m_PlayerDatas, sizeof(m_PlayerDatas) );) m' f( @ n. h; ~& i
m_pFirstActivePlayerData = NULL;
3 }% T4 M* P, p* J# o/ R( X m_pFirstFreePlayerData = m_PlayerDatas;
2 ]) X: x( H/ h* C9 w5 f for( DWORD i = 1; i < MAX_PLAYER_OBJECTS-1; i++ )
1 m3 l, {; r3 ]' \% m+ z- K {, o( K' P2 |. E5 |8 K$ v
m_PlayerDatas.pNext = &m_PlayerDatas[i+1];3 d* v( b& `2 V% z3 z
m_PlayerDatas.pPrevious = &m_PlayerDatas[i-1];
6 \+ j. ~+ E4 [( G6 d }</P>( m* u0 }0 d7 \! k" P8 R6 Q. l
< > m_PlayerDatas[0].pNext = &m_PlayerDatas[1];
5 m9 i# j2 E: }; [9 A m_PlayerDatas[MAX_PLAYER_OBJECTS-1].pPrevious = &m_PlayerDatas[MAX_PLAYER_OBJECTS-2];+ y+ g$ Z n4 h# s) U
m_dwActivePlayerDataCount = 0;) B4 S7 F' _! Z6 _5 [) L. G
m_dwPlayerDataUniqueValue = 0;</P>
# D" W% J- b1 _< > // Initialise the cells
* X% T7 p- |4 u7 m& g n7 s ZeroMemory( m_Cells, sizeof(m_Cells) );4 B! r, `0 N& T8 G
ZeroMemory( &m_OffMapCell, sizeof(m_OffMapCell) );</P>6 V, Z" T+ V% g
< > return S_OK;
6 q7 i& v4 A1 A) w: _}</P>
7 G( M; z+ K! Y9 v# \% \* l5 j, K% o: E
< >
7 F# }/ j9 F0 j//-----------------------------------------------------------------------------
' g$ C2 ~& H' C1 ` d// Name: ! |9 r9 P9 Z5 f- _
// Desc:
4 A( `2 O! A3 g+ a( _) E5 i: `//-----------------------------------------------------------------------------3 S9 e; h) F* f" u+ B
void CMazeServer::Shutdown()
' Y, |3 i6 Y: e4 P{
- _; a3 ?; @5 r1 t8 C}</P>
: A: R0 Q% b+ H5 e6 V# S, Q# `2 Y& K/ u3 o
< >9 V {, O/ g9 `$ ~4 ^1 m& I
//-----------------------------------------------------------------------------# w% {5 B* }& Z4 k
// Name: 2 K' ? f. p" K$ u" R, c2 {
// Desc: " E& r: U1 O5 v( L1 P# \. e
//-----------------------------------------------------------------------------! J5 c- G0 V1 Q* p/ M) p
void CMazeServer: ockRange( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
/ J# i. j, m1 A: H8 V% w1 T{, X! O' h6 D9 r4 U8 ?5 e: y9 o
m_LockGrid.LockRange( x1>>m_dwMazeXShift, y1>>m_dwMazeYShift ,) b( O! S* B2 H
x2>>m_dwMazeXShift, y2>>m_dwMazeYShift );
5 k' Z7 ^( a1 `6 K1 D% w}</P>+ `7 H$ o/ C4 @1 v) c
9 t, Z- Q b4 p+ c) X' K1 W< >3 U0 b0 w4 m8 m$ \8 m% O
//-----------------------------------------------------------------------------
3 t$ s T3 i$ Z0 a; G. Q, ^3 R// Name: / C" i& H+ t( k; m: R5 Q4 O
// Desc: & |9 o( b8 `& p( y7 D
//-----------------------------------------------------------------------------+ ?2 k+ `$ g' r3 z) d& m
void CMazeServer::UnlockRange( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
{. Q# [* T* H{ e2 [+ L( `1 |% x: _
m_LockGrid.UnlockRange( x1>>m_dwMazeXShift, y1>>m_dwMazeYShift ,* J8 y6 N8 |# A! O4 ?7 @4 Z
x2>>m_dwMazeXShift, y2>>m_dwMazeYShift );
8 T$ S$ ~8 C) w3 a. X0 t" f0 K* o}</P>
' i* g; \# Q8 Y. I6 g F( w
" A7 i0 N! m6 ]! _2 Y3 X< >
4 Z, {: }. K1 ~: C//-----------------------------------------------------------------------------# j: j1 T* h6 }6 {
// Name: & y2 }( e) }6 O7 J( |/ v7 Q u, D% w
// Desc: ( U( S+ Q; k) Z1 G; P: d H" B
//-----------------------------------------------------------------------------2 T/ @0 L/ ?8 m! n& ?5 X
void CMazeServer: ockCell( DWORD x, DWORD y )6 u( T" K9 B6 \6 l/ Z2 |) Q
{ C& G& i1 D1 R& Q
if( x == 0xffff )
9 M5 O3 H# u: i% e m_OffMapLock.Enter();
6 _* w8 F$ Q2 t else6 P3 L* I; ^, m# z3 `0 V6 H% G( u6 ?
m_LockGrid.LockCell(x>>m_dwMazeXShift,y>>m_dwMazeYShift);9 m z v' Q: ^9 n/ w
}</P>1 h) k; _/ d# X
7 L1 [+ `& A2 p' A/ i0 a, c) j< >& E7 ~! G- S# o% _/ g+ ?7 o
//-----------------------------------------------------------------------------* |3 ]+ {. V5 Q3 | C L
// Name: + O- c2 D8 g; S' Q+ W. u5 ~5 P) D
// Desc:
R( M/ [( @/ E$ H- D. `//-----------------------------------------------------------------------------, B6 X2 Q& N+ D# A3 f. O7 b% G
void CMazeServer::UnlockCell( DWORD x, DWORD y )3 X: p& M# k6 E2 v
{
9 G# y2 ~3 _ o) ~( n( { if( x == 0xffff )
e4 N; H- b% l7 U( `0 ^. m4 C m_OffMapLock.Leave();1 v' N: u) o4 U: t) f
else. h/ M8 l7 {7 e6 q: s$ ^
m_LockGrid.UnlockCell(x>>m_dwMazeXShift,y>>m_dwMazeYShift);- h8 M& A6 W4 A5 y, S* }. R
}</P>
# m/ F2 m( |# E# o( e5 z- }3 D$ l% @4 B* t' t
< >
" `: `# M/ T. K z//-----------------------------------------------------------------------------
3 c9 m1 O2 P0 u1 `// Name:
6 e" B& d. A. f// Desc: ; q9 F% D4 y/ f+ r! S
//-----------------------------------------------------------------------------
- A6 B" h+ E( Y8 Dvoid CMazeServer: ockCellPair( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )$ c6 O3 `4 m( y3 u$ f
{
. }' d% F4 Q; a7 W' n( v if( x1 == x2 && y1 == y2 ), y3 P0 O! T# [/ C- g6 Q( i. l8 y
{5 A; n9 z p0 A8 q) g2 }" i8 t- h
if( x1 != 0xffff && y2 != 0xffff )/ U' D a$ I3 s+ Z; u q' s
LockCell( x1, y1 );
1 n% j- t$ ~! {& |' r6 @) x: A else
$ H, Y. V" t0 Z4 M* U$ j& V# `2 i- g m_OffMapLock.Enter();</P>9 q+ x' ] i$ I% V; ~2 s
< > return;
% c0 w* d" r- l- ]) a m/ H0 g }</P>
4 @5 Y; @- M% G( F. C% F< > DWORD x1shift = x1>>m_dwMazeXShift;; w. j: r$ c; Y0 s/ U# s" K% {
DWORD x2shift = x2>>m_dwMazeXShift;# X3 B. \* Q4 R7 U+ M1 H9 v
DWORD y1shift = y1>>m_dwMazeYShift;& }5 h+ Z8 @& J' c# }
DWORD y2shift = y2>>m_dwMazeYShift;</P>
! `+ W3 z/ k) C0 M' Q< > if( x1 == 0xffff ): ~+ X. G. O. L! k. l) Y8 ?
{6 R- X! M8 [+ E+ n7 N% Z7 N
m_OffMapLock.Enter();
# I# u+ G; R3 c" d+ ~( [ m_LockGrid.LockCell(x2shift,y2shift);
3 d5 {& u: X8 J, X/ i }
/ o/ b4 V( n. F' v( u3 | else if( x2 == 0xffff )
. N6 k4 K& B7 f4 n1 C2 D {* p5 A( x( X1 y1 s0 A3 Q
m_OffMapLock.Enter();" I3 J% x. Q3 M% U1 u8 R
m_LockGrid.LockCell(x1shift,y1shift);
% u2 ]6 L+ ]2 y. }0 g2 s1 }% s2 z' Z }! H: _8 @ H5 Y& o
else
' G7 W' [9 Z1 v7 y {
0 \; t5 P7 Y' A3 P5 [7 S6 i5 K, u# W m_LockGrid.LockCellPair(x1shift,y1shift,x2shift,y2shift);' a1 G; d& B$ b& t0 [" [6 m6 |9 [
}( O% q7 W7 t7 D9 H( C5 c! u; W5 E
}</P>
7 u0 s$ [% e) E( _5 @6 s. O3 y9 P; S4 y2 J! b; z
< >
' c5 ^2 a% V% w* x1 C" T//-----------------------------------------------------------------------------
1 v# T! Z) r$ \7 v// Name: & q; K8 L V: I1 Q4 ]5 k% t9 e
// Desc: 9 ^! G! W" t3 \
//-----------------------------------------------------------------------------
8 E/ b2 g7 G& Z. Q: o/ }void CMazeServer::UnlockCellPair( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )" g* H8 ~4 I: m* s- Z
{. r% D/ ]% n: V( _% O$ M
if( x1 == x2 && y1 == y2 )9 E- {3 t+ o5 x( r$ ^! [
{
' b8 K* J: ]8 @# ~: n9 S if( x1 != 0xffff && y2 != 0xffff )
. O% N: U4 x+ e. i/ O3 t P* g UnlockCell( x1, y1 );' ^) r" A& p7 R% {3 S' a' a9 d X* o
else
! H6 C' p1 w6 K0 ~* ?; { m_OffMapLock.Leave();</P>5 {8 v; L" @0 m9 [& ^4 A: s
< > return;
- g) \, z. J# g9 d }</P>
! O' j0 w1 |" y2 k/ w( x- u- L6 K<P> DWORD x1shift = x1>>m_dwMazeXShift;" f( Q1 b: f, b: E8 b1 X
DWORD x2shift = x2>>m_dwMazeXShift;( J5 K3 k& X( ~1 h3 h8 G. Y& W) l
DWORD y1shift = y1>>m_dwMazeYShift;' c- w% i+ _8 i. {) ^) x Z
DWORD y2shift = y2>>m_dwMazeYShift;</P>; g% C! a( U& e
<P> if( x1 == 0xffff )5 F' e" q0 u- ~4 U5 w9 t" b1 `
{4 B/ p3 x9 t! w: d0 ? h
m_LockGrid.UnlockCell(x2shift,y2shift);( D. F9 H; Y2 t; p6 r" m" Z- W+ p
m_OffMapLock.Leave();2 E6 M+ E1 ^0 }
}
, [7 Z* x( t" a1 R% ^* L* K else if( x2 == 0xffff )
+ \! A$ E+ P) u/ b h3 g$ q9 |$ L1 T {+ u2 u8 H2 L2 }7 R5 I
m_LockGrid.UnlockCell(x1shift,y1shift);9 C+ I1 ]" p$ n4 z1 S
m_OffMapLock.Leave();6 Y; c6 W4 M5 |7 X
}" m2 ?' ]' ]+ {5 a& ]8 z
else * u: C }( ?: O6 d# X
{
" \" j$ C _- [ m_LockGrid.UnlockCellPair(x1shift,y1shift,x2shift,y2shift);
9 n9 H* R0 ^, Q/ Q }
: B% ^+ F, U! ^2 t}</P>
9 J8 e p9 R3 j9 u) L
: @8 P, ~0 }1 a1 N<P>) {% ]# G g% c8 P Q: ? w& V5 `
//-----------------------------------------------------------------------------& _8 B8 z( A. t, \
// Name:
! @, d3 k9 @! j z// Desc: * _, ?/ X6 M* ]$ ~
//-----------------------------------------------------------------------------
1 R) ?2 q$ M1 Z8 |& P4 mvoid CMazeServer::OnAddConnection( DWORD id )
2 S/ Q) a" f& m6 O{
% Y! {7 G; b/ T4 } m_AddRemoveLock.Enter();</P>* L/ [% s/ R2 S7 Z6 ]/ n
<P> // Increment our count of players
/ u2 u6 r, q. m9 } m_dwPlayerCount++;, R" ?( O. ]5 N, p7 c; J$ }0 Z
if( m_dwLogLevel > 0 )
) E O. j. x6 B( G! n { P) n3 U6 l8 R
ConsolePrintf( SLINE_LOG, TEXT("Adding player DPNID %0.8x"), id );
- a0 n. q- J! M. O ConsolePrintf( SLINE_LOG, TEXT("Players connected = %d"), m_dwPlayerCount );
Q4 Z8 d$ |) ]2 T) G$ M3 u& u0 I }</P>
* x# h# z/ b2 B9 M- W2 e: T, z$ W<P> if( m_dwPlayerCount > m_dwPeakPlayerCount )
/ H) `- ~- s$ Q1 c m_dwPeakPlayerCount = m_dwPlayerCount;</P># g4 s! m7 F* ^3 O7 C3 N
<P> // Create a player for this client6 \* M8 }$ v7 y t
PlayerData* pPlayerData = CreatePlayerData();
& y9 ?# U: N: \$ H- L) y if( pPlayerData == NULL )
2 P0 O. _: @- d0 C1 W* _ {% {+ t9 `7 B! ]1 i2 v8 y
ConsolePrintf( SLINE_LOG, TEXT("ERROR! Unable to create new PlayerData for client!") );! \7 `+ u, ]* G' Q4 q/ n
DXTRACE_ERR( TEXT("CreatePlayerData"), E_FAIL );
5 |6 Q+ ` `1 W m_AddRemoveLock.Leave();# T; f: k( r( k, f1 Y& z: l" F, r
return;, R( \3 X. J8 M) _& n* f
}</P>3 |( O6 M; g7 `, i' K0 I
<P> // Store that pointer as local player data9 z& J5 c) s$ q
SetPlayerDataForID( id, pPlayerData );</P>2 u# J* A5 A# [; x; c
<P> // Grab net config into to send to client- B. L, n1 |4 `3 \3 ^( q' p
m_ClientNetConfigLock.Enter(); H% @' X/ G- Z& j2 R
ServerConfigPacket packet( m_ClientNetConfig );8 N1 E, w/ |2 r# f" [0 V5 }- u
m_ClientNetConfigLock.Leave();</P>; }8 r# H( K: }& ]! p
<P> // Send it
/ P3 R" ^; y: r) L$ b0 k, c" L SendPacket( id, &packet, sizeof(packet), TRUE, 0 );</P>! f4 D$ X3 z: N5 p. C Z& m u! I
<P> m_AddRemoveLock.Leave();
' y5 X+ z0 I: g4 f$ [}</P>, \' s! \* @. R5 k
# j; d5 |# Z# u; F# J! O- @
<P> q, w4 F/ m& n
//-----------------------------------------------------------------------------' c7 k$ K, Y. _: M
// Name:
% f' w9 L* ?% L% I$ \- e+ @// Desc:
( K; h9 t# T/ x. q//-----------------------------------------------------------------------------/ d0 Q4 V& K. v; F' v3 x" K
void CMazeServer::OnRemoveConnection( DWORD id ), ^$ W, u/ |$ s2 r D. Y
{
$ [/ V& ~. a( e$ O m_AddRemoveLock.Enter();</P>4 a4 h4 Y; o# ]. L8 r/ A, o
<P> // Decrement count of players4 |+ P1 Y1 ]9 u' O& |; e6 Y9 E
m_dwPlayerCount--;</P>
2 ~' h; m: q5 P3 I% Z9 X# X1 L9 B<P> if( m_dwLogLevel > 0 )
* _$ s( `3 J, ?5 w! J C: |. K- v {
! S) d" ~" y8 |: Z7 V B ConsolePrintf( SLINE_LOG, TEXT("Removing player DPNID %0.8x"), id );
% l$ S- C' z8 ~ U- h/ E/ X0 X! z ConsolePrintf( SLINE_LOG, TEXT("Players connected = %d"), m_dwPlayerCount );
. a# @$ g8 @& M; G2 b% b. o }</P># P8 O' `: }( h) {2 g' y) o
<P> // Find playerdata for this client
3 `% T' H& U% D; E% E# }+ M PlayerData* pPlayerData = GetPlayerDataForID( id );
5 y) }' V0 l9 ?; i7 J4 b% t if( pPlayerData != NULL ): m, O, g2 L4 g. F3 l) Y J0 i8 F- R
{
' K" r* n: C5 L0 M! f // Destroy it
9 L t# S4 _" P( \% N RemovePlayerDataID( pPlayerData );
, F$ P3 C; l3 @' A DestroyPlayerData( pPlayerData );9 j( {9 J9 }, x: F' o
}</P>
( \* q; B( Q5 p A<P> m_AddRemoveLock.Leave();7 ^1 a( t# m8 v1 | r7 v
}</P>
) f& X+ e# V* W0 B
3 `2 p5 B6 q2 p: P1 s/ _( d<P>
! K( D; H4 D3 {# \0 J Z//-----------------------------------------------------------------------------+ \/ v6 r9 |& l8 P6 M2 D
// Name: , R+ R8 z7 }8 Z* n
// Desc:
6 T1 K+ ~' K3 a4 d) \* f, ~//-----------------------------------------------------------------------------
. Q) h# c+ D7 z" ?( H, gHRESULT CMazeServer::OnPacket( DWORD dwFrom, void* pData, DWORD size )1 V# C% |# D7 T t8 o
{
' D7 W1 d% e& U# c, j BOOL fFoundSize = FALSE;</P>
& b+ G: C3 c; K _, h8 G% j' q<P> // Increment the number of thread we have in this process.
: [. g/ x2 y4 O% ~5 Z m_csThreadCountLock.Enter();</P>* f% F# C1 V2 ~" R/ R5 X
<P> //Get the start time of when we entered the message handler.! X! Z5 h. f' f
FLOAT fStartTime = DXUtil_Timer( TIMER_GETAPPTIME );</P>
& N8 r6 ~, Z0 L: @: ^/ x( r<P> m_wActiveThreadCount++;
. t3 a- q# E# N8 N* y% K0 s if(m_wActiveThreadCount > m_wMaxThreadCount)
! K1 \+ o) t+ \ m_wMaxThreadCount = m_wActiveThreadCount;( o+ v5 L( E- v5 t7 w" @
# d4 ], {6 D" c
// Calculate and average.* |& l- b# K2 _7 U% o, d, q
FLOAT fdiff = m_wActiveThreadCount - m_fAvgThreadCount;" G& w1 f/ A! r9 w1 B$ ]
m_fAvgThreadCount += fdiff/32;/ H$ t. O6 m, Z/ ~
6 ]/ D; w1 R1 H2 q m_csThreadCountLock.Leave();</P>9 `/ x9 D5 a* {
<P>, f: C$ }% K' z/ X, s8 v2 e
ClientPacket* pClientPack = (ClientPacket*)pData;
: o& K" t% U, ^( z# H$ C d9 I switch( pClientPack->wType )
0 m* B4 D" x# h4 i" c {; d7 [0 ^: ~" q! ?7 Z9 p
case PACKETTYPE_CLIENT_POS:) j) i6 K8 |8 X+ o( B' e0 j
f3 t* ^0 L, e2 e
// Check to see if the packet has a valid size. Including
: G& H% o% |' ~( i9 b // the custom pack size./ ]( D8 X4 K2 E! Z+ B- J4 Z
if( size < sizeof(ClientPosPacket)) k n' f' m+ e2 D( L3 P. X' n
fFoundSize = FALSE;
! U$ a( c& X/ W else if( ! IsValidPackSize(size - sizeof(ClientPosPacket)))
; @. I/ _! m1 _$ B6 c) S ` fFoundSize = FALSE;' e* F) G- f- n' w8 y9 W
else
# S. S+ {* i; R; E% P- s l fFoundSize = TRUE;</P> b$ a& s7 m7 R; Q
<P> // If valid sized packet, handle the position., B; N2 Z7 ?, S7 p# W8 Q
if(fFoundSize)) B+ h c/ z" \. t$ ^
HandleClientPosPacket( dwFrom, (ClientPosPacket*)pClientPack );/ w2 _$ }# d8 x
else6 h0 H* x& ~, t& H6 X- x- R3 B
m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );</P>. H G, X& E6 J4 q
<P> break;</P>9 f( E1 I! z0 g: P& @. z+ k8 b
<P> case PACKETTYPE_CLIENT_VERSION:% i# _% D3 y' o% B8 Q
if( size == sizeof(ClientVersionPacket) )- e% U7 X$ v3 u
HandleClientVersionPacket( dwFrom, (ClientVersionPacket*)pClientPack );
* a- M! N) s+ D" m3 \ O U/ T; { else
- v% B, k- q( k" X' Q. d" \ m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
, U& K& h; A) K, i1 \* w break;</P>' F J# h Q0 I; f4 k- i
<P> case PACKETTYPE_SERVER_CONFIG:</P>
4 p5 m; p) G: r4 ]# q4 L<P> // Server config packet sent to all users (including server). Just ignore and continue.</P>; l& B/ x6 x o6 X) q3 g* b1 Z/ P
<P> break;
2 f6 S" F6 q {! `8 v default:
, `. x$ O; X3 Y8 T; G4 Q, c HandleUnknownPacket( dwFrom, pClientPack, size );
9 ?5 `2 W G/ z$ `/ ?. t break;6 r3 I) C: @) w5 ^" e2 ?
}</P>
8 m+ k- z; e) r q<P> //If the user wants to hold the thread, Sleep for given amount of time.
! o8 B j1 _; y7 ^% d% y- p6 K& a% z if ( m_dwServerThreadWait > 0 )0 o3 A f: [1 ]
{
- v8 Z2 M9 J5 N1 A$ J) C Sleep( m_dwServerThreadWait );
9 S" I" r* s' H2 `. [ }
2 s) ^. r& J2 V, `, M! N 9 y& o, G, b, `8 D" A
// Retrieve thread data for this process.
, `, `9 `/ `) p% ~; r6 x+ @ x: M q m_csThreadCountLock.Enter();</P>1 X4 T6 ^0 S/ v c$ ^) G+ M9 ? c
<P> m_wActiveThreadCount--;</P>, R! a# D9 G. {
<P> FLOAT fDiffTime = (DXUtil_Timer( TIMER_GETAPPTIME ) - fStartTime) - m_fAvgThreadTime;
0 R2 a+ _ f: k$ L) \+ ?5 S m_fAvgThreadTime += fDiffTime/32;</P>
& ]* ]3 e, Y; }( V<P> //Get the Max time in the thread.
" Z0 e: ~5 g& f* } if ( fDiffTime > m_fMaxThreadTime )0 o! X- J" u( e
{
- ~! Q. K0 {, { m_fMaxThreadTime = fDiffTime;
2 h6 \2 m) ?; W3 {2 n* ~% n0 n }</P>
& G; t3 R8 a0 s, D4 C: W<P> m_csThreadCountLock.Leave();</P>9 @% {- G* S) m
<P> return S_OK;
) T1 D' x/ v% Z @- ]4 P$ ?! N/ |}</P> v" l7 V( @$ v& |* x `* a
& c* M$ Y4 M) ^! B! Z/ j
<P>//-----------------------------------------------------------------------------9 ~1 @3 L! n0 Q0 O+ w
// Name: r) P6 c1 W W5 x
// Desc:
/ B1 |- Q9 b+ }& d+ ~//-----------------------------------------------------------------------------8 t8 D i& w' S* E* }
BOOL CMazeServer::IsValidPackSize( DWORD dwSize )
2 R/ u1 m% q, c& ~' t3 [( S7 m{
4 m% x' [. @. b& Z- a BOOL fFoundSize = FALSE;: N' i" q- L3 {
BYTE ubPackLocation = m_ClientNetConfig.ubClientPackIndex;
; I- D% d! P9 \: A ) d, X1 H4 [+ {6 A
// Check through the array of valid pack sizes./ u6 @# S: B( ^# M
if(dwSize != m_ClientNetConfig.wClientPackSizeArray[ubPackLocation])! p# b0 x) x. Y+ P; _# o
{
% f4 l5 f/ h0 C8 R' @- x7 _ for( --ubPackLocation; ubPackLocation != m_ClientNetConfig.ubClientPackIndex; ubPackLocation--)
- c0 ~5 U Y; B, B3 F6 a% F2 T# A {8 B( C* e& N& Y3 p6 g4 b6 Q
if(dwSize == m_ClientNetConfig.wClientPackSizeArray[ubPackLocation])
. G2 U* w6 V: Q6 V/ a2 t, p {
. f l! w6 m. I! P/ \ // Found valid size in the array.
5 C2 x# l) N$ g6 i. B/ T fFoundSize = TRUE;
' ?1 d+ i8 i/ T3 e break;9 W/ F. r3 \* o1 @( R2 N8 w& p& X
}
+ G) f* _2 J& Y if(ubPackLocation >= PACK_ARRAY_SIZE) ubPackLocation = PACK_ARRAY_SIZE; //Wrap the array.1 P5 V- ~" N# p2 M+ O
}- c! [( ^# Z6 w
}
8 C; T% a6 S/ ? S% C% c: |8 O else
, r4 J. T8 O( ?2 a9 c- N' s3 H {8 m2 R$ y; p( o- j3 h% o
fFoundSize = TRUE;: J8 I) p% d! ` t8 B" s
}</P>( p0 K3 x+ H k$ g+ d* T
<P> return fFoundSize;. s0 B+ m" p5 U" N
}</P>
; ?7 I2 M( n) a. Z. n<P>9 D6 t0 c# u6 @
//-----------------------------------------------------------------------------
1 o+ q9 ?, ]: a/ v1 v) f S' W// Name: 1 j6 z% U4 q" P P' f
// Desc:
/ N3 d+ j& d/ u: C* ]5 P& z6 g//-----------------------------------------------------------------------------9 ]+ }* a/ v- ~ A5 ^! x: d! F9 s. B7 g
void CMazeServer::OnSessionLost( DWORD dwReason )
. y1 _) x7 P; \3 _! f/ [* e{
% l4 x2 \3 d4 a/ ~8 w ConsolePrintf( SLINE_LOG, TEXT("ERROR! Session was lost") );6 p8 u3 h) J6 h
}</P>. o7 n8 o! G% P% g
l. k3 f- N1 K2 S! b8 X9 Q8 ~<P>) y* S( Y$ b3 r4 X% J$ n8 E# G
//-----------------------------------------------------------------------------5 I5 A- r u) n# f/ G7 P" J
// Name:
3 U( V1 O2 B2 N/ d2 N/ G// Desc:
& H+ O/ ]- A: C' C* d//-----------------------------------------------------------------------------
7 m. ^4 W I$ w5 `. CPlayerData* CMazeServer::CreatePlayerData()
% |* [5 t0 s, J2 [8 b{7 q5 O" [ ~ R2 E4 V1 R* e3 o% Z
m_PlayerDataListLock.Enter();</P>" C6 S! s! x$ x
<P> // Grab first free player in the list
# k0 ~* Z m8 F PlayerData* pPlayerData = m_pFirstFreePlayerData;</P>4 U! L' f8 d6 h/ {+ a
<P> if( pPlayerData )
" R. j# R* _9 t7 n8 g7 _9 ]. N5 w; e {
; i# e0 S( c& n+ N' n LockPlayerData( pPlayerData );</P>
, g3 u! J" Q. i# q& M# u<P> // Got one, so remove it from the free list
" g1 Q/ h P5 Y if( pPlayerData->pPrevious )7 ?' i- }( v8 s# n
pPlayerData->pPrevious->pNext = pPlayerData->pNext;! x2 n) i. _* O5 S! S
if( pPlayerData->pNext )
2 t# V; D% g; w6 i+ `$ Z5 @5 v5 B' o pPlayerData->pNext->pPrevious = pPlayerData->pPrevious;% H& j5 ]) L3 D$ \" B3 f
m_pFirstFreePlayerData = pPlayerData->pNext;</P>. k; v; f% L, r: u7 N7 C. A
<P> // Add it to the active list7 U; \0 A: ~! x, |% W
if( m_pFirstActivePlayerData )$ B" {& `2 W5 X' u2 u/ L
m_pFirstActivePlayerData->pPrevious = pPlayerData;' i2 c9 F( B% k" w; S( j9 b
pPlayerData->pNext = m_pFirstActivePlayerData;
( @3 X P& [; ]2 V/ o pPlayerData->pPrevious = NULL;* Z ~: k4 C; Y/ e" N
m_pFirstActivePlayerData = pPlayerData;</P>
. r6 h) s2 r; [, _- B d9 [" z3 c<P> // Update count of players' p. h' [9 D( w) n- Q
m_dwActivePlayerDataCount++;</P>( v! s. d6 `9 O4 v3 u
<P> // Generate the ID for this player
. @( O# M* x+ A! t2 O3 [ m_dwPlayerDataUniqueValue++;
+ X1 w) Y3 i7 x pPlayerData->dwID = (DWORD) ((pPlayerData-m_PlayerDatas)|(m_dwPlayerDataUniqueValue<<PLAYER_OBJECT_SLOT_BITS));</P>
1 p+ T7 i+ y1 `0 S3 ?4 H<P> pPlayerData->pNextInIDHashBucket = NULL;
a) c; g% H& e. \! X D' @ pPlayerData->NetID = 0;0 {7 V. W& C4 Q# `- B
pPlayerData->dwNumNearbyPlayers = 0;</P>! T, F h! I4 \7 Y+ O( B0 M5 Y! E5 e3 Y
<P> // Insert into the "off-map" cell. N; } p+ J/ J0 G3 R4 d
pPlayerData->fPosX = pPlayerData->fPosY = -1;- x9 V# N7 q/ J3 S# F
pPlayerData->wCellX = pPlayerData->wCellY = 0xffff;
- O0 q" i# y) Y- Z4 w) _ m_OffMapLock.Enter();7 w4 L, n/ S; b) }
pPlayerData->pNextInCell = m_OffMapCell.pFirstPlayerData;
- |5 F0 a7 f# o, } m_OffMapCell.pFirstPlayerData = pPlayerData;- k; J T8 l# Y9 O9 r
m_OffMapLock.Leave();</P>. w$ W* T% a- d" B" K
<P> // Mark as active- s; e% `* v: t. U, ?% t
pPlayerData->bActive = TRUE;</P>
$ b. ?" ]. N2 i4 O0 S0 d<P> UnlockPlayerData( pPlayerData );1 a8 P. t! L0 J$ p; r( K. D, C
}</P>
) b+ q" j1 Q5 S# z% o4 D9 T* p<P> m_PlayerDataListLock.Leave();</P>
: \3 G6 c+ Q; c" P$ h- ^! R! |<P> return pPlayerData;( i* h a g% P4 ?3 i. A y8 I/ K
}</P>
' R) n' a( C5 r# [4 {
' t7 |; u, S! }3 t$ Z- Y/ {9 W- I( g<P>
. \5 w: b1 l/ W( ^//-----------------------------------------------------------------------------. p3 _ B, k! ^
// Name:
8 y% u: C" m* ~: N, k// Desc:
/ `4 s; Z+ a8 C+ a) L7 g* m//-----------------------------------------------------------------------------
2 G8 k# r% k+ M: T1 s$ V+ jvoid CMazeServer: estroyPlayerData( PlayerData* pPlayerData )
1 s V2 {- @- F! V5 |, Y8 D; ]{- O" f2 Y6 C2 |8 I& y4 u
m_PlayerDataListLock.Enter();
8 B7 h+ [$ h7 i+ ?5 }& ]5 v LockPlayerData( pPlayerData );</P>
0 ?& T6 G! e; ^4 h8 L<P> // Remove the player from its cell$ F% K+ Z s! {6 N9 e7 r
RemovePlayerDataFromCell( pPlayerData );</P>
- O: `9 |& K# t Q9 `2 }<P> // Mark as inactive1 t4 h; P+ M r4 I
pPlayerData->bActive = FALSE;</P>
( U' K' d) S: I<P> // Remove player from active list& o) `0 M8 t* y( C
if( pPlayerData->pPrevious )( @# z ^# e M5 i( c
pPlayerData->pPrevious->pNext = pPlayerData->pNext;
, r1 N1 z# i# ] f if( pPlayerData->pNext )2 \1 _* K4 z- ~% S( q
pPlayerData->pNext->pPrevious = pPlayerData->pPrevious;</P>
+ V/ O9 m; D9 i. N9 l. G<P> if( m_pFirstActivePlayerData == pPlayerData )
/ I! M0 l, f! O6 w! A" r m_pFirstActivePlayerData = pPlayerData->pNext;</P>5 O1 _3 Y) X/ B( \/ ^- `% o
<P> // Add it to the free list
" u: q6 ?2 k& e' [0 m/ ? if( m_pFirstFreePlayerData )5 V8 ]5 F$ |) `1 L
m_pFirstFreePlayerData->pPrevious = pPlayerData;
* v; u+ g! p$ `* {0 b( m$ p) [" B pPlayerData->pNext = m_pFirstFreePlayerData;
2 m, f% E. _3 r, Q0 W pPlayerData->pPrevious = NULL;
, L' b1 S, _- R% P7 Z m_pFirstFreePlayerData = pPlayerData;</P>
- V5 U/ u/ g* t<P> // Update count of players; ?# k8 ]8 {. T" U8 ?
m_dwActivePlayerDataCount--;</P># C; D5 x, r2 v2 B
<P> UnlockPlayerData( pPlayerData );& y+ \+ n* d9 h
m_PlayerDataListLock.Leave(); T/ E. k; b* E z' {. J4 ]5 g
}</P>2 g4 q* k$ g. u7 j4 t
% c L: Y# j: A* P<P>
8 a* g1 q1 x3 t7 X//-----------------------------------------------------------------------------
_0 n5 X& |& l/ Q0 l. _ C9 r$ d// Name: 3 L$ @& X& U6 O" [" w# L P/ i
// Desc:
6 H- o9 _2 s2 U! w! D//-----------------------------------------------------------------------------
, h [) p3 a9 P% Hvoid CMazeServer::RemovePlayerDataFromCell( PlayerData* pPlayerData )
5 H' O& t' V6 q" D6 p{
2 T' W) J% D. E' r7 a. K) | // Lock the player
/ L6 f7 i/ {# V6 h6 y" F LockPlayerData( pPlayerData );</P>
7 v) B4 d4 [) {( }$ U0 r6 }<P> // Lock the cell the player is in: {% e; l" K" b& s0 n$ i
ServerCell* pCell;
1 @* A! `; L' D5 D% o$ e* \3 K if( pPlayerData->wCellX == 0xffff )
1 P( F7 X A% P4 r. f9 S {3 E( k' p) o0 t, m( x6 O% s4 [
m_OffMapLock.Enter();
' S; Q* |9 m2 }1 a( c pCell = &m_OffMapCell;% s$ o. j" _2 q1 j" ^6 X
}. ]" z& g, @) ~" m2 x" f
else
0 c$ c0 }) p2 p) ?, Z( g! c {3 X0 Q" N! @! F4 e l/ ]" q
LockCell( pPlayerData->wCellX, pPlayerData->wCellY );
, m, [1 a$ B$ D* m pCell = &m_Cells[pPlayerData->wCellY][pPlayerData->wCellX];' v {2 w' x% K- O% q4 B _4 F$ ^
}</P>
, C# N9 q5 F1 `0 I& h: x<P> // Remove it from the cell4 U4 W' g# i/ \4 G% `. D- `. H$ n
PlayerData* pPt = pCell->pFirstPlayerData;8 q8 \6 `* c3 j8 N6 x, M+ `
PlayerData* pPrev = NULL;
: L1 j/ F$ |" ^4 m( V& `; d* a& i while ( pPt )
) W7 P0 l3 }5 n* ]/ G+ a {- _: w7 r9 S1 t; \; A
if( pPt == pPlayerData )
% F6 q5 [9 A% R! M i {
2 S0 U5 t/ [* K! C! w+ N# c* z! c6 g if( pPrev )! a' `- X+ J& P$ p) K; E1 z
pPrev->pNextInCell = pPlayerData->pNextInCell;
* u( z6 U9 \, J/ j. `' w else
$ a3 m3 c) y: h: s) r pCell->pFirstPlayerData = pPlayerData->pNextInCell;</P>/ b" `1 x! E: a9 b& K
<P> pPlayerData->pNextInCell = NULL;
2 n& ~0 J6 S. q# ]% U: e break;
$ Y' l$ V) m3 t4 f7 ^$ V2 X } t+ C( @9 {) W' O/ Q
pPrev = pPt;* C$ V1 k ^+ d0 \ e$ l
pPt = pPt->pNextInCell;6 M* \4 [5 i, Y/ {6 T! |* R
}</P>
X1 q: P, t# \8 U" `8 o8 V<P> // Unlock the cell
) k) {2 h! C9 V* Y4 } if( pPlayerData->wCellX == 0xffff )
( `( r7 ~ a: R8 V6 ^) F: R# _ m_OffMapLock.Leave();/ ?- v. U! M- m
else& y' ]$ m( v7 B, o
UnlockCell( pPlayerData->wCellX, pPlayerData->wCellY );</P>! V# S. { b5 ]# Q/ N8 k: j; N
<P> // Unlock the player
% E1 `4 C* g. ^! l* z+ ?; ]& \ k UnlockPlayerData( pPlayerData );
- h6 @1 v3 n3 e5 ^}</P>; b# Y6 i1 A" s/ s) O
3 k5 A& k8 [$ ?! j& `6 s<P>
$ l/ j9 `) d+ ^9 r//-----------------------------------------------------------------------------
* y; f! A/ a& S: p. x' d// Name:
! ~, m1 L ?" g$ q2 {: V9 |// Desc:
3 a$ q( _$ t1 z2 Z. q. X6 y//-----------------------------------------------------------------------------1 @& v; [0 S% r5 W) {
void CMazeServer::UnsafeRemovePlayerDataFromCell( PlayerData* pPlayerData ) M1 Y0 [, G: U
{
. Y2 ^& Y8 {8 @' ] ServerCell* pCell = GetCell( pPlayerData );
! k) n1 M c6 l6 ? PlayerData* pPt = pCell->pFirstPlayerData;
1 M `8 }- G* E9 E2 j PlayerData* pPrev = NULL;+ {: H, a0 R* z4 D( ?
while ( pPt )
- m9 w$ J5 k! O# v: z {. X# U5 q1 z4 V% S' x* S# t
if( pPt == pPlayerData )' @5 l* b6 m) n1 {. J+ _& m: h' P
{
' H& _" K2 ?$ X* w7 u; r6 D7 T# y if( pPrev )2 B t! t) V! z' ~" k' L7 k
pPrev->pNextInCell = pPlayerData->pNextInCell;% g% A# s" f- E; E: l. s1 n% c
else3 e- N( S( f j: t# H @# a9 k
pCell->pFirstPlayerData = pPlayerData->pNextInCell;3 N8 }6 p$ F, o) t
pPlayerData->pNextInCell = NULL;0 w" N' K" } c; [
break;+ H0 `6 w$ o8 K" G3 S+ x4 y4 k( T: r
}( f6 ?: U) b4 G) x9 |$ q
pPrev = pPt;7 Z1 H" G" r! x/ g+ T, q+ p$ k
pPt = pPt->pNextInCell;) |* T( o3 ?9 W' e$ |) H3 m# W) M$ I
}
/ R& B6 g0 J, I9 y- }}</P>
9 c! z& b& x( @9 ~1 x. A3 P1 j2 C: s: |* o: `$ F
<P>
% g6 l0 Z; T1 Z//-----------------------------------------------------------------------------
+ U9 A1 p& ? R! v/ r9 r// Name:
2 V. j9 i; h! r, ]) x// Desc: $ K3 C% p& `) L% D* Q9 l& g8 ~/ ~
//-----------------------------------------------------------------------------9 E. C% |* p: E
void CMazeServer::UnsafeAddPlayerDataToCell( PlayerData* pPlayerData )" l4 C, C/ c& X0 X0 D
{7 o$ G6 d) f7 s' G
ServerCell* pCell = GetCell( pPlayerData );+ e* w+ a* x' |
pPlayerData->pNextInCell = pCell->pFirstPlayerData;
, B0 d8 w! ^) z2 Y pCell->pFirstPlayerData = pPlayerData;
9 k+ x9 {6 e% t. ~) O0 z}</P>
) v2 e5 j; b: H: `, v7 C3 x4 d! O4 k8 w" L* _9 D# A
<P>
8 ?+ v, u- w8 j* b6 s//-----------------------------------------------------------------------------
" j' m' ?$ M; f6 V4 G7 |' R, g// Name:
2 `# t/ z' c0 G# `% y// Desc: 5 W+ A! f% x0 X9 G. y
//-----------------------------------------------------------------------------, o: K! K/ }/ o0 E5 s
void CMazeServer::HandleClientPosPacket( DWORD dwFrom, ClientPosPacket* pClientPosPack ), m; o# c C( N. }8 y! Z
{3 Y( @7 [4 o" Y
// Grab player for this client and lock it: b: H8 G; l" _* L6 `1 z' D" Y
PlayerData* pFromPlayer = GetPlayerDataForID( dwFrom );, |% M3 X7 p" a" }) r( W1 L
if( pFromPlayer == NULL )* K! O0 E* Y% J5 C j0 b4 Y: Y! _
{
% C4 b9 b" ~( @! }$ u( W) x if( m_dwLogLevel > 1 )
, [4 A1 Z& m+ M% o ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Could not find data structure for this player"), pFromPlayer->NetID );
2 q, O( J; x9 C return;, u9 }. @, S6 t; f) ] q
}</P>1 Q+ F) ^ `0 A; ]
<P> LockPlayerData( pFromPlayer );</P>- x" K* R( k6 F8 w1 t+ J
<P> if( FALSE == pFromPlayer->bAllow )+ F! r, G" _5 Y% x/ R
{) q0 f3 K+ ?; _$ j4 ~& a
if( m_dwLogLevel > 0 )) v+ t: g( c" J2 X0 t5 H8 }6 }
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Got position packet from bad client. Rejecting client"), pFromPlayer->NetID );</P>
; j: }& C7 g$ m9 e2 u% M7 T<P> m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
9 e8 O H' K; i X4 G5 P UnlockPlayerData( pFromPlayer );
( z Q! e' R+ x0 A return;4 j+ c0 F' g' U/ ?8 R
}</P>
$ J( y; B( t; ~2 c* `4 X: f9 I" b& N<P> // Compute the cell the player should be in now
$ _& S% H1 p) K1 }# V1 g# h8 q DWORD newcellx = int(pClientPosPack->fX);% W! L% ~, T3 |; H1 z
DWORD newcelly = int(pClientPosPack->fY);
z4 G- e+ L2 j5 B: C) z# z& E DWORD oldcellx = pFromPlayer->wCellX; c2 V+ I" j* G2 n* ~, a0 S( h
DWORD oldcelly = pFromPlayer->wCellY;</P>
$ Z7 N9 L7 d2 ^4 \7 Y<P> // Have we moved cell?
6 H# J a3 ^+ j5 P" n if( newcellx != oldcellx || newcelly != oldcelly ): Z$ ]* N/ |# L) N" y( {9 L
{
& }; V& ^& y; [8 j1 s" i* d // Yes, so lock the pair of cells in question6 T6 R/ L& m0 C7 p7 r7 o+ `$ l
LockCellPair( oldcellx, oldcelly, newcellx, newcelly );</P>
; R( `- g( y' j* j7 ~<P> // Remove from old cell and add to new cell
_2 @/ x; B2 Y+ b! ]/ R: |- z UnsafeRemovePlayerDataFromCell( pFromPlayer ); Q |1 U8 g, c7 x
pFromPlayer->wCellX = WORD(newcellx); pFromPlayer->wCellY = WORD(newcelly);5 E' q* K |4 c4 e p, E
UnsafeAddPlayerDataToCell( pFromPlayer );</P>, z- P& h* c4 ~
<P> // Unlock cells/ Y9 Q- Q$ a, s
UnlockCellPair( oldcellx, oldcelly, newcellx, newcelly );
7 j. r P' {+ V* S }</P>- F9 ? ?$ ~# H+ \2 T- V
<P> // Update player position
$ q- b! r. h8 h/ g0 c; ^) j* Q pFromPlayer->fPosX = pClientPosPack->fX;4 @: d5 k' R( ~5 g# X
pFromPlayer->fPosY = pClientPosPack->fY;
, b2 `& q; m4 n0 Z( ]1 Z! Q pFromPlayer->aCameraYaw = pClientPosPack->aCameraYaw;</P>
6 b, G/ U, N. ~" }' `5 W$ _<P> // Allocate space to build the reply packet, and fill in header
$ z8 M4 R3 [" x. A DWORD dwAllocSize;
# I$ Y, R) u& m- M ServerAckPacket* pSvrAckPack = NULL;</P>/ [6 O7 p* X$ H. z* L
<P> // Begin by allocating a buffer sized according to
- e0 f8 U* D* y9 h) K; T( U // the current number of nearby players + 4. This will give
6 w( q' O; G c" k+ L8 { // a little room for more players to come 'near' without resize
! @* s* q5 x, N9 j$ w/ D/ E! t/ ` // the buffer.
9 P: X1 [& T2 S5 a A4 Z DWORD dwMaxPlayerStatePackets = pFromPlayer->dwNumNearbyPlayers + 4;</P>% ~& h9 k9 }6 s! n% g
<P> dwAllocSize = sizeof(ServerAckPacket) + dwMaxPlayerStatePackets*sizeof(PlayerStatePacket);
& w2 U1 _1 ]0 T) a! Y' z pSvrAckPack = (ServerAckPacket*) realloc( pSvrAckPack, dwAllocSize );0 R6 V+ M1 T$ `* M1 K& M( d
if( NULL == pSvrAckPack )
2 d- d' V/ a% S" x, ] {) `& a, [+ r: m, @: L$ }0 Z& l; b1 ?
// Out of mem. Cleanup and return
" v+ F" }1 n% P n) }% S2 e UnlockPlayerData( pFromPlayer );2 q2 k- `, {0 F3 E! O+ A. \3 @
return;
& G- n4 S/ d* T }& I* i2 f# {1 ] q6 d' O# h/ J
ZeroMemory( pSvrAckPack, dwAllocSize );</P>
) Y6 \1 t! J& W6 |' e) C$ P<P> *pSvrAckPack = ServerAckPacket(m_dwPlayerCount);$ F1 d0 M9 r @, g8 S
pSvrAckPack->wPlayerStatePacketCount = 0;
0 [) `: O. O5 r7 d4 [) ~! y0 O4 _ PlayerStatePacket* pChunk = (PlayerStatePacket*)(pSvrAckPack+1);</P>
* |2 R5 U( @, r8 L/ J$ R d" u5 M<P> // Compute range of cells we're going to scan for players to send4 t1 G/ e9 c3 S4 c, t
DWORD minx = (newcellx > 7) ? (newcellx - 7) : 0;
6 O7 i3 `1 K3 i. _9 v! b3 o2 ? W DWORD miny = (newcelly > 7) ? (newcelly - 7) : 0;
( @' j n# `4 b' U* B9 B5 s5 o DWORD maxx = (newcellx+7 >= m_dwWidth) ? m_dwWidth-1 : newcellx+7;: }" @6 E. F& g/ h# l
DWORD maxy = (newcelly+7 >= m_dwHeight) ? m_dwHeight-1 : newcelly+7;</P>
* M5 @. \; m5 W8 }8 T: c<P> // Lock that range of cells
, b, c+ b# w ] v LockRange( minx, miny, maxx, maxy );</P>
7 C) I7 a( [. D<P> // Scan through the cells, tagging player data onto the end of. H& L: S- ^1 ~' N4 j2 ]1 y
// our pSvrAckPacket until we run out of room
1 ]4 n" ?, Q6 ^$ U for( DWORD y = miny; y <= maxy; y++ )
: i9 i( a4 x2 W* [' B5 @6 \) X {4 E- `5 V+ N9 p# j, @; |2 R1 @
for( DWORD x = minx; x <= maxx; x++ )
7 M0 J* S3 ]2 R1 @# e- a { [8 y" |* ~' O3 X& q
PlayerData* pCurPlayerData = m_Cells[y][x].pFirstPlayerData;5 {/ }0 i2 r1 o) E$ O
while ( pCurPlayerData ); v8 ?- \! _. p- S7 g$ H2 C; L
{4 i5 o+ }) L: o2 U8 D
if( pCurPlayerData != pFromPlayer )" b' |" x& Q( [9 z
{1 E5 v; q- ^% `, h6 s
if( pSvrAckPack->wPlayerStatePacketCount >= dwMaxPlayerStatePackets )0 O! g% A3 B$ C6 j+ S
{# O+ @# z6 S# A% z
// Make sure pChunk is where we think it is
1 j! D% a& [3 r/ B5 o assert( (BYTE*) pChunk == (BYTE*) ((BYTE*)pSvrAckPack + sizeof(ServerAckPacket) + pSvrAckPack->wPlayerStatePacketCount*sizeof(PlayerStatePacket)) );</P>
6 {, K7 p7 w1 l9 ^, ^<P> // There are more than just 4 new nearby players, so resize the
. K" g" I$ O8 z. t; A! k( W ` // buffer pSvrAckPack to allow 16 more PlayerStatePacket's./ K( |9 j; j* O
dwMaxPlayerStatePackets += 16;. ]- E0 e0 i6 i2 G
dwAllocSize = sizeof(ServerAckPacket) + dwMaxPlayerStatePackets*sizeof(PlayerStatePacket); V# }/ E( n$ d9 I, q+ U6 z" X
ServerAckPacket* pNewSvrAckPack = NULL;4 ?2 k9 u! P7 r" `; D/ A' _/ b
pNewSvrAckPack = (ServerAckPacket*) realloc( pSvrAckPack, dwAllocSize );* U4 r" d u4 j7 h# S% b0 x8 E+ V" _
if( NULL == pNewSvrAckPack )0 _ f" J( g( i' a2 H9 R) A" M0 C2 F
{% _+ p+ i/ c/ V0 s! {( M" T* e; Z; c
// Out of mem. Cleanup and return; ?( L( N* q: R* u# f% F5 p
free( pSvrAckPack );* f: n& x" m1 Q( ]
UnlockRange( minx, miny, maxx, maxy );
" ]% @' G/ c+ f/ T; N3 T UnlockPlayerData( pFromPlayer );0 V) V3 y( i2 o" H2 K# c1 Y
return; 3 R( e- u7 D. {$ Y! P
}</P>
) w* W" F4 F. N- R9 k/ `<P> pSvrAckPack = pNewSvrAckPack;" Z6 F; ?5 V4 ` T, x" m
pChunk = (PlayerStatePacket*) ((BYTE*) ((BYTE*)pSvrAckPack + sizeof(ServerAckPacket) + pSvrAckPack->wPlayerStatePacketCount*sizeof(PlayerStatePacket) ) );</P>
# F r5 ^2 e! T5 h7 J/ _<P> // Make sure pChunk is still where its supposed to be
; t% x+ ^) Z* G8 R+ x6 U& \% m& Z assert( (BYTE*) pChunk == (BYTE*) ((BYTE*)pSvrAckPack + sizeof(ServerAckPacket) + pSvrAckPack->wPlayerStatePacketCount*sizeof(PlayerStatePacket)) );4 n" \% ]5 V: @8 n8 A
}</P>
% l2 Q5 v1 \# T" {<P> pChunk->dwID = pCurPlayerData->dwID;
* S7 c+ r J( C8 J pChunk->fX = pCurPlayerData->fPosX;; @2 z" ~9 Q" `1 }7 z
pChunk->fY = pCurPlayerData->fPosY;
9 @4 a4 E, R2 |* ?5 o% R pChunk->aCameraYaw = pCurPlayerData->aCameraYaw;
# R% b Q1 g7 U7 M3 I' V6 G: L pChunk++;
/ l; ]9 I9 q+ `& j" B2 ^ pSvrAckPack->wPlayerStatePacketCount++;9 c* A* Y$ G4 q4 J+ w1 I5 u
}9 L" `8 ^1 I0 G% r) x, G; G
pCurPlayerData = pCurPlayerData->pNextInCell;+ H! v8 \) i+ K% e C7 x" l
}
3 p7 w7 T# H( l k; f8 G2 N }' H* y, q; q" e8 R
}</P>! M- j5 t. c. v+ F( K
<P> // Update the dwNumNearbyPlayers for this player+ U2 x* E+ W, r; t# E i' H+ H
pFromPlayer->dwNumNearbyPlayers = pSvrAckPack->wPlayerStatePacketCount;</P># ]& [/ c) O3 A% d$ f9 x+ q; j% h
<P> // Unlock range of cells
. r5 n( S, P5 z2 g4 I. h UnlockRange( minx, miny, maxx, maxy );</P>' z R# M3 l. n
<P> if( m_dwLogLevel > 2 )
# m* t) X$ @' {$ k+ x& e {3 V- L% q& Z3 D# i$ A
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Position is (%0.2f,%0.2f)"), pFromPlayer->NetID, pFromPlayer->fPosX, pFromPlayer->fPosY );
' p' b6 G; L6 \: \ }
& L: a' B( Z+ \: t% x else if( m_dwLogLevel == 2 )
$ F+ c' Z. O( {7 e. { {
0 P1 N# O* }* M% a" i FLOAT fTime = DXUtil_Timer( TIMER_GETAPPTIME );
* A0 i% z" k" ?" u, Q' B if( fTime - pFromPlayer->fLastDisplayTime > 60.0f )
' A4 i: s6 \4 t- R {8 H4 y' T R& h+ Z
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Position is (%0.2f,%0.2f)"), pFromPlayer->NetID, pFromPlayer->fPosX, pFromPlayer->fPosY );% e* [, L9 ]6 Z" ~* V' ~& g: Y
pFromPlayer->fLastDisplayTime = fTime;/ z' c8 y% }3 U
}
& ]; }% {6 }: v3 l. `: U: r7 o- E }</P>; t: |% m" J' g, o# U6 W
<P> // Unlock the playerdata3 t- r- w3 q- S& o9 {3 ^
UnlockPlayerData( pFromPlayer );</P>3 r7 j. A, U6 L; y( ~. B
<P> // Send acknowledgement back to client, including list of nearby players
% d( C/ C) _9 r7 O5 N/ y G DWORD acksize = sizeof(ServerAckPacket) + (pSvrAckPack->wPlayerStatePacketCount * sizeof(PlayerStatePacket));+ r, V, i" Z* }$ _ e. m
) o1 s& l7 h" \0 ~" \2 A) a // Pack the buffer with dummy data.0 z$ S1 ~0 U& G( ?9 }0 }
if(m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex] > 0)
0 w' t( V. h. U2 z( b. S( R8 U: u {! r6 O3 y3 g# ~5 C! X% A
DWORD dwBufferSize = acksize + m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex];. |4 \! A' E4 W1 n' v
VOID* pTempBuffer = 0;</P>
4 y) o3 S) _: }: M4 V1 s0 _1 d<P> pTempBuffer = malloc(dwBufferSize);
* _5 v: Q; b' i3 t2 x- U if( NULL == pTempBuffer )
% ]& W* q7 r7 j; ~. v7 K l+ J; ?6 y {
" x8 k5 S8 P) W9 J //Out of memory
- B1 N/ r4 s9 w4 S4 X DXTRACE_ERR_NOMSGBOX( TEXT("System out of Memory!"), E_OUTOFMEMORY );
/ @$ m; B/ H8 k: u( Y0 v# o free( pSvrAckPack );
, p2 e; S2 v+ R return;7 y$ D. O7 U% c& T
}</P>
0 G7 y3 ]" L8 s5 \9 R<P> FillMemory(pTempBuffer, dwBufferSize, 'Z');
7 U! o+ n& k$ k @ memcpy(pTempBuffer, pSvrAckPack, acksize);</P>
. L6 b# m' C1 z6 V$ L0 v& A<P> SendPacket( dwFrom, pTempBuffer, dwBufferSize, FALSE, m_dwServerTimeout );
0 E- h! E! Q5 s5 n% \
( j, {! t8 ]2 r free(pTempBuffer);0 e( {+ K, s+ _, m# P' `& {! y
} 7 R! L t1 ^& L* ?
else
d9 ?9 q/ y( s/ I* Z {
) z# K' l( X$ t9 Q4 f SendPacket( dwFrom, pSvrAckPack, acksize, FALSE, m_dwServerTimeout );; p+ z4 [( f, ~
}</P>
3 Y" T1 t! O7 o<P> free( pSvrAckPack );</P>
: X4 L' o6 P$ m0 a0 \<P>}</P>
) d# o3 b' d, i+ h$ \) m( a& N: K" B: d: L: g! @6 B
<P>, K( p3 ?5 m; i- @4 `' g
//-----------------------------------------------------------------------------
0 Z+ e+ e7 @" u$ m1 t: d J// Name: . K0 P0 ~9 ^7 m5 ?3 L' ~# g
// Desc:
# V2 N5 x5 P2 l v) `//-----------------------------------------------------------------------------+ a3 R& s4 d* u! Z4 @
void CMazeServer::HandleClientVersionPacket( DWORD dwFrom, ClientVersionPacket* pClientVersionPack )/ o( t- q! r1 p( n
{1 ?: S6 ]8 O" ~- _5 a. Y1 c% \4 D
// Grab playerdata for this client and lock it/ u" G1 c4 t' p4 T- `
PlayerData* pPlayerData = GetPlayerDataForID( dwFrom );
( g7 F E2 U3 e6 v0 L1 L- }; s4 g c if( pPlayerData == NULL )
" q' G* p9 [% U _* q Z return;: E3 E Y2 `" E. @) c, ^/ k
LockPlayerData( pPlayerData );</P>' G3 t/ j4 S8 p- I
<P> // Record the version number # h% K8 m& z& C0 s3 v
pPlayerData->dwVersion = pClientVersionPack->dwVersion;</P>* \ J& X) G" h. }
<P> if( m_bLocalLoopback )
0 [ _ K% Y( @' Q: [6 j% p pPlayerData->bAllow = TRUE;
2 _# P" u G% c. H' F: I% u, b else
% E$ ~# B, C; Y, V6 X( t pPlayerData->bAllow = IsClientVersionSupported( pClientVersionPack->dwVersion );</P>* |% b$ \8 y/ ^& E ?8 [7 U9 s) {4 n
<P> if( m_dwLogLevel > 0 )) ]1 m! n6 F/ b
ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Client version=%d (%s)"), pPlayerData->NetID, pPlayerData->dwVersion, pPlayerData->bAllow ? TEXT("Accepted") : TEXT("Rejected") );</P>0 a+ M, P7 h' I* ~ J
<P> if( FALSE == pPlayerData->bAllow )
" j9 }+ ]! f; K/ ]! G/ Q {
7 Z6 j" \ N) S+ `% [2 Z) U if( m_dwLogLevel > 0 )
7 S+ O% j; m* J6 P+ E, K ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Rejecting client"), pPlayerData->NetID );</P>. P! N4 M) u" c+ _3 P; _& j
<P> m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );( f8 @2 m/ r9 W1 P! g
UnlockPlayerData( pPlayerData );9 V; o5 t3 p* D9 [1 L; H6 ~2 Z
return;
& ~6 c5 y+ ^% [8 V' R }</P>
f. M# A3 g4 N H+ N! y<P> // Unlock the playerdata3 H! L# I+ G1 I2 z
UnlockPlayerData( pPlayerData );</P>
$ p, }% f8 u; t, H5 b; ?<P> // Send acknowledgement to client that the client was either accepted or rejected4 C0 T" L9 v4 f9 N8 r, W2 o/ N
ServerAckVersionPacket packet( pPlayerData->bAllow, dwFrom );3 H# m. K3 r( ]' Z0 ~8 l
SendPacket( dwFrom, &packet, sizeof(packet), TRUE, 0 ); ^" i% A; v ^8 C' v1 \* G' |8 _4 F
}</P>$ C! q9 T& O2 p5 g6 [) S" ?% Y
' E% t, L$ i: }3 l) K9 f<P>
+ J7 k5 L4 v$ G/ M8 h0 _//-----------------------------------------------------------------------------
% ^+ N; \$ h4 L8 Y// Name:
0 N0 f, Q6 p: ^1 s! ]: \// Desc: - r4 B! |- E7 R* i- F( M) x
//-----------------------------------------------------------------------------% G7 u( ]' n: w! O) v
BOOL CMazeServer::IsClientVersionSupported( DWORD dwClientVersion )
- ^/ p1 d9 q& A# R{6 [4 X, G- O# n g
switch( dwClientVersion )
$ {. g) G* @4 y) `- h+ g7 ]) L, z {
: g# _, C) O; b" u0 j7 _. P9 ]% m/ r case 107: // only v107 is supported
& j& V# x) K u( V0 J( } return TRUE;
) |, i5 ]1 T/ C; `4 e5 `8 A default:8 M( n; \6 s5 _+ p- n6 J0 c
return FALSE;
7 N7 `/ @& b6 ]9 d# V3 ^; T6 p }% ^. T+ J+ r6 D9 D: z. E5 @
}</P>3 G4 A2 m7 |: b: }- R7 g
1 B) u' R) j0 ~7 [* R# D. R
<P>
+ P5 J+ U# }1 n0 B3 u$ j& e- W//-----------------------------------------------------------------------------( y2 v% ~: U% I& B- X
// Name: $ x9 b+ a1 P0 p% x; `3 a2 f4 I; S: `& J
// Desc:
/ t$ q: x4 S" e, _3 z3 k+ `//-----------------------------------------------------------------------------. a+ }8 F6 |, Q
void CMazeServer::HandleUnknownPacket( DWORD dwFrom, ClientPacket* pClientPack, DWORD size )! z/ d3 j) H- A
{
+ z* b" J* T% ^3 t0 v) S& P if( m_dwLogLevel > 1 )3 ]7 ^! i4 [; B- r
ConsolePrintf( SLINE_LOG, TEXT("ERROR! Unknown %d byte packet from player %0.8x"), size, dwFrom );</P>
* L# P. g+ s5 l6 y<P> m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );$ A$ I Q. N( t' Q
}</P>
0 ], C+ u- F3 S8 y# { L# j
2 Z# B' _4 ^; o<P>! z+ J# s6 A5 r0 _+ ?
//-----------------------------------------------------------------------------; e S3 v j; c2 M* M
// Name: ! f# \& ^1 l: `# ^4 u' G- l
// Desc:
- s B1 r9 U, @& i& m9 R0 X//-----------------------------------------------------------------------------" P8 S; M9 d% y# t
DWORD CMazeServer::IDHash( DWORD id )
: ?( [5 m- U2 ~$ N6 A( m{
+ t* v r5 [( P- {0 b- C+ Q8 v DWORD hash = ((id) + (id>>8) + (id>>16) + (id>>24)) & (NUM_ID_HASH_BUCKETS-1);/ ?' R* C3 [/ p! f9 D
return hash;
( b" i6 o$ o2 V0 i}</P>& O2 A) K4 U( Y' w: c$ l% U. Y" s0 e
( k/ J( G: c# S5 P. Q8 s<P>
4 n. L: N. C" J0 }: y//-----------------------------------------------------------------------------) Y G! p& _4 O% ^0 T
// Name:
. }4 K6 H$ ^7 m( b6 m// Desc:
. L8 u- }# V2 x//-----------------------------------------------------------------------------
# [- L) o4 S* n. o/ Rvoid CMazeServer::RemovePlayerDataID( PlayerData* pPlayerData )
; ^( w% T0 j2 q- f- e{
" T" o$ s3 e. w& y+ ], v // Hash the ID to a bucket number
4 n2 d* [; }6 A+ |2 N- B! i7 u4 L; ~ DWORD bucket = IDHash( pPlayerData->NetID );</P>
6 X; f2 `1 Z, N7 G1 H5 I+ x4 z<P> // Lock that hash bucket
4 Y1 s$ j. w' W/ x# d const DWORD buckets_per_lock = NUM_ID_HASH_BUCKETS / NUM_ID_HASH_BUCKET_LOCKS;) q b' d, T- D* r; J
m_IDHashBucketLocks[bucket/buckets_per_lock].Enter();</P>$ t" C3 Q$ A' n% }; ]4 h
<P> // Loop though players in bucket until we find the right one0 E4 w" E1 `6 R% g* \
PlayerData* pPt = m_pstIDHashBucket[bucket];6 G/ q' V& q4 a& b* m
PlayerData* pPrev = NULL;
2 X* U' T& }: ~' S3 a' Q+ W while( pPt )1 P4 G: N8 u4 J
{) ^4 w. P! H1 l! d) T) U3 b$ ~
if( pPt == pPlayerData )
- s8 a1 ]! y) }+ |& F break;
I$ N! k3 c8 c1 N pPrev = pPt;
: P/ W' k2 D8 f) g. _- r5 e0 o pPt = pPt->pNextInIDHashBucket;
- b9 x1 |. X* F( H }</P>
$ u3 n1 v5 k7 ]+ H, n. t<P> if( pPt )" {8 ~/ f' a# A6 l q
{
0 E4 k1 y7 [; u ?7 z: p5 {8 @9 e1 B if( pPrev )
" p9 B+ y3 Q! k: M: {1 I pPrev->pNextInIDHashBucket = pPt->pNextInIDHashBucket;
5 B" p, K0 S9 ?+ v! N( g else" ~8 B& i- d" e, C6 x( O4 t
m_pstIDHashBucket[bucket] = pPt->pNextInIDHashBucket;
7 y8 h( O. @* {: i' m+ H pPt->pNextInIDHashBucket = NULL;; X3 O" ]/ T' q" }
}</P>
8 U0 z# o3 [7 U7 o5 [. r- d' a4 W<P> // Unlock the hash bucket
5 w# t+ r6 I+ ~" M" Q( A( O m_IDHashBucketLocks[bucket/buckets_per_lock].Leave();$ f3 T: a+ K$ A. n' @% U
}</P>) ]/ s C; r- c d+ m, h! t
2 P6 N% S: w" F$ [<P>* j c4 w, w8 g Q7 x% v# L
//-----------------------------------------------------------------------------
/ k% E. V2 o1 D. A. V// Name:
! b5 b3 r3 K% J" O# n// Desc: 3 h0 W) Q8 Y4 W. |
//-----------------------------------------------------------------------------
" v4 A7 u% g% ~' K6 b4 E8 Avoid CMazeServer::SetPlayerDataForID( DWORD id, PlayerData* pPlayerData )
* i7 j1 @3 O& m% t{8 \9 z" ?# i) g% J9 v: Y3 ]5 U' l
// Make sure this player isn't added twice to the m_pstIDHashBucket[]
& R+ \9 Y+ r( S; _0 u4 l // otherwise there will be a circular reference0 w) ]- C0 R$ F2 t( w; [9 s
PlayerData* pSearch = GetPlayerDataForID( id );
! O a% q+ H0 y; t, Y if( pSearch != NULL )
5 _ ]: F6 {2 r# k+ ^0 | return;</P>
* q! _" J; ^7 | m0 k K! Z<P> // Hash the ID to a bucket number' m3 A4 ^, H+ e. ]! F1 W& X
DWORD bucket = IDHash( id );</P>: w! r+ f* F) g( S) n9 ?8 o/ p4 Y
<P> // Lock that hash bucket. e2 b P) C' Q$ P- X
const DWORD buckets_per_lock = NUM_ID_HASH_BUCKETS / NUM_ID_HASH_BUCKET_LOCKS;
0 i, }/ P& H( b: x m_IDHashBucketLocks[bucket/buckets_per_lock].Enter();</P>
$ E! x2 X: j: u<P> // Add player onto hash bucket chain
) [! F* v- p& R w' |; H9 ~* ^ pPlayerData->pNextInIDHashBucket = m_pstIDHashBucket[bucket];
5 q& n* \% H$ C/ k; [: i8 ? m_pstIDHashBucket[bucket] = pPlayerData;</P>
1 d1 F) S2 E1 M: z7 J( h$ }' e<P> // Store net id in player- `. ~: Y4 }3 W. R9 X: H7 ~ d
pPlayerData->NetID = id;</P># L4 K; C. V c) }8 F; }
<P> // Unlock the hash bucket$ W, k' Q/ |# l+ z! P1 B0 |% }
m_IDHashBucketLocks[bucket/buckets_per_lock].Leave();
* V0 R& H: M" a6 J5 w5 q" l}</P>
, T! ^, D3 F3 j, A7 A7 ?* T9 a! z' r& R/ c, G
<P>
6 t S# H- a% `; O//-----------------------------------------------------------------------------# I3 e& \1 `; H3 r6 {
// Name:
1 s. h0 p& O; O3 b4 U// Desc:
6 g. h f4 d) } t% l//-----------------------------------------------------------------------------
, [% i: F1 U4 _+ C0 Y6 j5 iPlayerData* CMazeServer::GetPlayerDataForID( DWORD id )
( Q( a% e. v8 o- g, `& E; H{) P6 P! l$ |# y& S6 p
// Hash the ID to a bucket number
, W" [+ W% g6 w, ^: d DWORD bucket = IDHash( id );</P>
3 X0 L2 S. W; G$ O4 V7 j# N<P> // Lock that hash bucket
- g. |* G) s* E2 F3 } const DWORD buckets_per_lock = NUM_ID_HASH_BUCKETS / NUM_ID_HASH_BUCKET_LOCKS;
0 m4 L `+ E( {- t4 Q" W9 w m_IDHashBucketLocks[bucket/buckets_per_lock].Enter();</P>
# \" E/ p/ c" `<P> // Loop though players in bucket until we find the right one
1 C! r; x8 K5 a) U- T& W$ Y PlayerData* pPlayerData = m_pstIDHashBucket[bucket];9 s7 u$ i B9 C/ M8 k* @
while ( pPlayerData )
, d) K( D* a, S+ K- p1 Q* I {
- l8 d+ t: t% O5 U if( pPlayerData->NetID == id )
- E7 p1 F3 c; [$ B- e* f break;
2 u4 F, p! q9 t. l3 E pPlayerData = pPlayerData->pNextInIDHashBucket;
$ R! ?/ l! H$ o( H3 j }</P>6 v4 h H+ r, ^$ D
<P> // Unlock the hash bucket
, `% v* f9 `$ |: a- p9 i& Q% H m_IDHashBucketLocks[bucket/buckets_per_lock].Leave();</P>' }7 X" n! J7 h. X5 B/ Z1 z$ }3 j
<P> // Return the player we found (will be NULL if we couldn't find it)
+ f* F6 z+ k5 K# b' a+ {+ [ return pPlayerData;
( e7 Z3 W, G7 K# z; h}</P>
) ~0 B+ c* @* G" i6 d' y: g0 L; _& k7 l
<P>/ O; {8 m' I& ~; U7 U
//-----------------------------------------------------------------------------
: H4 `2 W% n) H( M; M// Name:
2 {# U+ C; |% A2 [0 E% H6 E, c7 ^// Desc: calls DisplayConnectionInfo for each connection in a round-robin manner
3 N% }3 ?- H5 j8 W3 I. G: K//-----------------------------------------------------------------------------" |1 S" ^; P b
void CMazeServer: isplayNextConnectionInfo()+ D2 U* a! u+ r: x. ^6 w3 S
{
: F: h% N' D: J if( m_pNet )& H5 c, n, t, _' b. h; ?6 M
{+ m9 q- X5 T9 B# z7 P/ k% n2 R8 }
// Find the player that was displayed the longest time ago, and display it.7 Z; g/ A9 @) `+ ]% J+ f
FLOAT fCurTime = DXUtil_Timer( TIMER_GETAPPTIME );% d- T' [+ k4 b9 i' d. l
PlayerData* pOldestPlayerData = NULL;
& y" `& o [7 A FLOAT fOldestTime = 0.0f;</P>
) v! B7 Y- z5 k5 c- c5 O9 V<P> m_PlayerDataListLock.Enter();</P>4 M2 C* c8 L$ x0 h9 r4 @* G& Q
<P> PlayerData* pPlayerData = m_pFirstActivePlayerData;+ N% `1 S# o+ X. q% b! y
while ( pPlayerData )
$ z m6 Z$ J; U+ [ {
( s+ f5 }$ k1 A( h) G* i if( fCurTime - pPlayerData->fLastCITime > fOldestTime )
( H: D( k4 D1 r( ^$ D' f7 h {! M/ y- U- P4 p$ g
fOldestTime = fCurTime - pPlayerData->fLastCITime;
6 u$ S' c. d- v) g pOldestPlayerData = pPlayerData;
9 _' v7 l9 Y2 R) l5 B }</P>
/ I5 }6 L3 @ E% u& q( O* b g<P> pPlayerData = pPlayerData->pNext;' o4 b" T) r8 a+ h* _9 h8 h
}</P>/ X, Z( _; {+ L6 [ @6 w
<P> // Display the player with the oldest CI field, and update its CI field.
+ F8 @# F1 ^. C6 L if( pOldestPlayerData )
" \- H8 J. ]% v2 t( [$ o {& C4 ?. n" O2 m
ConsolePrintf( SLINE_LOG, TEXT("Displaying connection info for next player") );
+ p v( }' D( [; ]% Y. B$ S! Y DisplayConnectionInfo( pOldestPlayerData->NetID );
$ r2 ~, B) P( r% V pOldestPlayerData->fLastCITime = fCurTime;
) S! }7 j4 ]5 G& v" H6 ~$ k% u2 s* s }& G. d4 z& h* _( d. [
else
% ~. q4 {. D/ P" w3 P, j {: K. l6 D' R9 h8 J0 i, Z
ConsolePrintf( SLINE_LOG, TEXT("No players found") );
6 z$ }$ H6 \8 {8 S& ]) i }</P>$ Q7 n8 O" _- B1 [" |
<P> m_PlayerDataListLock.Leave();
, ^% V% |4 _: y& H: P! E }
/ Y+ o a$ Y, m. d* i& @" e2 I}</P>
1 l' E+ [6 L% F" z+ Z
2 Z1 _0 { E [ Z7 l<P>: N* U; f' p9 a, m# ?, R3 V, U
//-----------------------------------------------------------------------------
/ ?2 C2 u! K$ H, i4 _* h# g! r// Name: ' e6 B/ R9 K: M% r6 o% D& r L
// Desc: % Y- s- X+ K- y3 p" |1 S* s
//-----------------------------------------------------------------------------" S% h4 Q) A6 R) Y; L' ]6 I. h% Y# b3 N
void CMazeServer: rintStats()
5 \; u- H; e8 H% p7 G{) Y% u) `9 v+ e5 e1 T3 A
ConsolePrintf( SLINE_LOG, TEXT("Thread count: Active=%d Avg=%.2f Max=%d"), # V$ S( o1 _9 ?1 C. B M
m_wActiveThreadCount, m_fAvgThreadCount, m_wMaxThreadCount );6 r @" W1 k; ?" D) ]
ConsolePrintf( SLINE_LOG, TEXT("Thread Time: Avg=%.4f Max=%.4f(s)"),5 r/ s3 I+ p0 ?' o# j* j( L& q
m_fAvgThreadTime, m_fMaxThreadTime );
( B. b5 @# g. Y+ W ConsolePrintf( SLINE_LOG, TEXT("Players online (not including server player): %d"), m_dwPlayerCount );) O- Y" h7 g7 x/ F- R( k8 g
ConsolePrintf( SLINE_LOG, TEXT("Peak player count: %d"), m_dwPeakPlayerCount );0 ~/ P) K" G* B. C
}</P>7 u0 v" Y! V: C0 J {0 J
$ Z! u! o# Z9 V( r3 _ s! E( k0 b9 ?<P>
3 `2 n( P" n; V- ^( f }//-----------------------------------------------------------------------------2 c4 T1 D6 X2 S w; A% [$ m
// Name: , N* r* a9 g( c" a4 M" o
// Desc:
8 k$ E$ y3 o8 r7 `9 @# W) s//-----------------------------------------------------------------------------
+ C# Y2 j' a7 U3 gvoid CMazeServer: isplayConnectionInfo( DWORD dwID )) Z p( w( `) N% C& O3 C
{
/ F& Q Z6 V1 A* I. k9 T( w TCHAR strInfo[5000];
. J, k% c# T) z( J9 n TCHAR* strEndOfLine;
* K) f+ A2 ]( @6 ~ TCHAR* strStartOfLine;</P>
5 A: N/ S. t: Y$ G* `1 x0 u% U<P> // Query the IOutboudNet for info about the connection to this user
+ ?6 b! r. e+ G# y m_pNet->GetConnectionInfo( dwID, strInfo );</P>/ A9 j/ [8 u5 X
<P> ConsolePrintf( SLINE_LOG, TEXT("Displaying connection info for %0.8x"), dwID );
. z1 y: B5 u' o6 f" y4 a ConsolePrintf( SLINE_LOG, TEXT("(Key: G=Guaranteed NG=Non-Guaranteed B=Bytes P=Packets)") );</P>9 R. G A# R: |
<P> // Display each line seperately
; ^( \ W( w% Z2 A9 O% N strStartOfLine = strInfo;
# s H/ t4 U% X+ b' F3 T while( TRUE )3 g1 |- q0 _5 L6 }7 p# h
{ Y p+ |- T! J2 W0 Y
strEndOfLine = _tcschr( strStartOfLine, '\n' );
( {4 M. B& W: j( }. t: ?/ ^ if( strEndOfLine == NULL ). E0 q" }7 s1 t1 u
break;</P>; O) }$ W4 D" I
<P> *strEndOfLine = 0;: ]3 D) Z3 f+ G
ConsolePrintf( SLINE_LOG, strStartOfLine );
H. [ f% Q+ o4 c" g1 I) @7 u/ W strStartOfLine = strEndOfLine + 1;
1 D# I- V. F5 t/ {0 r6 S }
+ Z* Y+ ?6 y6 Q# | k}</P>
N8 ]" R* n: ]- x* ~( q+ X& W5 \) r0 x9 o* q
<P>- _" P. j& B$ _9 z9 Z' q
//-----------------------------------------------------------------------------
! q5 C1 L( p$ ^3 W* [ q// Name: + {! e7 M' r( w6 g
// Desc: ' M5 W. i" |& [5 O8 k
//-----------------------------------------------------------------------------
4 u6 E: V, H8 r, R; xHRESULT CMazeServer::SendPacket( DWORD to, void* pData, # M. r/ ]" e& f3 \; t, w& f& V
DWORD size, BOOL reliable, DWORD dwTimeout )0 G' ~ E( t5 S. R; s, [. Z* \
{: O( l' k/ L$ s7 x! P4 z; V
// Chance of forcing any packet to be delivered reliably
4 J- @( ^% z" d5 \9 J6 f: r if( m_Rand.Get( 100 ) < m_dwServerReliableRate ); O/ L9 J; s- M
reliable = TRUE;</P>6 l" h V) }" ~- R3 l
<P> return m_pNet->SendPacket( to, pData, size, reliable, dwTimeout );# ]. i8 W6 m- M) ~7 O+ X i, A# a
}</P>3 f( P% V' ~ ?, ?. O
9 J5 ]- E9 s3 h' B" a' o2 f<P>$ v: i8 O" Z6 V( A7 W* M
//-----------------------------------------------------------------------------
( {4 X/ H) Q8 H4 m) d6 M& M1 s// Name: 2 F, C% a2 D6 @: m4 T. @% b z8 L
// Desc: 3 t, V0 R$ X1 Q% }0 s5 O- Y! b
//-----------------------------------------------------------------------------
- T" R5 m6 M+ l$ zvoid CMazeServer::SendConfigPacketToAll( ServerConfigPacket* pPacket )4 _( I; B r* q' a, g: l |
{
* d) Y& o& {$ T ^1 w // If we're up and running, then send this new information to all clients
! G2 T3 _8 a* P+ J! N- O5 h, _ if( m_pNet )& K- P) k4 } y2 @
{
: l+ q) A# R: F //Use the AllPlayers ID( m1 g2 g# x5 u9 C
SendPacket( DPNID_ALL_PLAYERS_GROUP, pPacket, sizeof(ServerConfigPacket), TRUE, 0 );' f, P9 i, z, ?- R1 c# m6 z! \6 W9 ?
}
' ^) D8 _, O2 s$ Q}</P>
7 l2 g* b0 j) u# u1 Y( |, {
6 w: [$ }4 K8 M/ t7 B; _<P> ?' z+ x# Z6 X* ~4 R
//-----------------------------------------------------------------------------: L3 A6 B8 c+ B U: z
// Name: 1 L: M0 i3 r0 o0 l
// Desc: ; P+ W1 C- I* n: [
//-----------------------------------------------------------------------------
: X! I' f2 U1 u0 _void CMazeServer::SetClientReliableRate( DWORD percent )
* J- J% e! O! y: ?{
" V0 \! |( d$ @4 L, C0 | // Update client config, and build packet containing that data/ p ~$ r0 o/ N C) n' n8 k
m_ClientNetConfigLock.Enter();
" `7 Z. \; X+ h% a$ k' y m_ClientNetConfig.ubReliableRate = BYTE(percent);
' l' D. W) x; A6 e) N ServerConfigPacket packet( m_ClientNetConfig );
6 X* Q" c. u$ u% K* o6 u m_ClientNetConfigLock.Leave();</P>
& }" I) j' q4 ~) B3 w<P> SendConfigPacketToAll( &packet );
8 Y- {5 n6 Z1 l7 L& y}</P>
# U0 L# w# A4 M4 D1 ?7 d" w0 z8 o4 R1 o8 x# D, x
<P>
3 }- X8 r: A( z: D& \' b//-----------------------------------------------------------------------------/ D9 K% h- O1 z, d0 V$ n1 p1 f# L v4 q: ]
// Name: * N: F+ X0 Z, Z2 y
// Desc:
6 ]# x- E- g1 n; k9 n& s+ O//----------------------------------------------------------------------------- ^, s# U8 r* T. [% Y
void CMazeServer::SetClientUpdateRate( DWORD rate )( m" S4 D7 T3 M& o; o' Q
{
7 S, g6 `4 B" ^6 R; |( J" ] // Update client config, and build packet containing that data
5 s# e* A% M* ~2 a m_ClientNetConfigLock.Enter();
' k" q' F( e) H% H8 n3 k2 @5 P7 c m_ClientNetConfig.wUpdateRate = WORD(rate);0 h' N6 H) t( i- T7 F
ServerConfigPacket packet( m_ClientNetConfig );$ G! A& ^1 F* Q4 m/ G
m_ClientNetConfigLock.Leave();</P>( V% H( f c1 n0 {* j6 `7 n
<P> SendConfigPacketToAll( &packet );
- P/ Y* M1 v. N' @+ M8 Y* W}</P>- m9 [$ a. C k# ?5 [# {
3 `( s8 A3 C# M6 B( }+ j/ i/ R1 w. W<P>
& C8 i) a' M9 w0 |//-----------------------------------------------------------------------------
$ d) P7 ^0 H8 j6 r& e9 Y* g// Name: : Q4 M; e3 R5 x/ T
// Desc:
) w; H: v/ G7 N6 F1 V//-----------------------------------------------------------------------------
, { i# k2 F2 ~0 T) xvoid CMazeServer::SetClientTimeout( DWORD timeout )
8 I/ @% ~8 I1 _' t, z9 r9 h{- V7 R" |- i4 j4 `" Z F/ |3 p6 j' m# h
// Update client config, and build packet containing that data4 C" r) w( J& N: _
m_ClientNetConfigLock.Enter();
; u, [; Z9 S0 h3 D% Z' E; U m_ClientNetConfig.wTimeout = WORD(timeout);# v/ {: Z# b. c- ]& u) y7 [
ServerConfigPacket packet( m_ClientNetConfig );
. ^0 e8 G$ D+ a$ E* ~ m_ClientNetConfigLock.Leave();</P>
, H- u+ k% W, P# m, {<P> SendConfigPacketToAll( &packet );; `& t) C- S3 i( S6 U
}</P>
6 W2 ]+ t) f) d, J" p* b( R+ j/ y& U! J* ?4 Q9 e# S1 X
<P>" ?/ c+ r1 o/ O+ q
//-----------------------------------------------------------------------------
l+ r) K1 c+ M: T" w- p7 `/ `// Name:
4 a% B/ e$ y% B6 k% ^" ~' v// Desc:
, v) t7 J1 C( B2 U# }//-----------------------------------------------------------------------------4 ?: X/ K, B8 ~8 O
void CMazeServer::SetClientPackSize( DWORD size )
6 o+ [1 a5 @( v7 x{
! q) b* w, e$ `2 q- E // Update client config, and build packet containing that data. t: D6 j3 Q$ y( Q8 F8 r
m_ClientNetConfigLock.Enter();
^, @; f5 x- w 5 \: n1 ]3 z; u+ J' V4 o- r
m_ClientNetConfig.ubClientPackIndex++; //Increase index and verify location in array.! b* A7 m% n% p/ i
if(m_ClientNetConfig.ubClientPackIndex >= PACK_ARRAY_SIZE) / e9 H2 A7 l9 f4 m( T' _
m_ClientNetConfig.ubClientPackIndex = 0;</P>
: c7 f M1 Z+ G2 }, ^( F<P> m_ClientNetConfig.wClientPackSizeArray[m_ClientNetConfig.ubClientPackIndex] = WORD(size);
9 g' T# s' ~, ^) w ServerConfigPacket packet( m_ClientNetConfig );" M6 Q0 l( N7 E! ~
m_ClientNetConfigLock.Leave();</P>7 l. S6 v) [/ m0 Q. D
<P> SendConfigPacketToAll( &packet );
4 w- e5 f/ Q% f9 V1 Q}</P>/ _2 E4 q& m+ A5 `7 Z1 C/ j2 k# C9 `( i
# r( B; Z( T4 l/ D$ T<P>
& }) y" N% E+ r W6 _//-----------------------------------------------------------------------------! x5 Y/ s+ U; \" P4 a0 q
// Name:
X" Q7 A' O' S, f* B1 b% [// Desc:
+ y& t+ ~. b1 S, F3 e) G) o) J# H* s//-----------------------------------------------------------------------------: B# R; G- F/ u3 Y
void CMazeServer::SetServerPackSize( DWORD size )
3 s" M1 u& m* M T{' y q4 Y+ g" M* ~2 I
// Update client config, and build packet containing that data
- a. w' P) `4 `7 R4 {$ c m_ClientNetConfigLock.Enter();+ A9 Q. x/ |+ j, ~7 Z
L" u1 Z6 X& r) M) X0 J m_ClientNetConfig.ubServerPackIndex++; //Increase index and verify location in array.- T. d% ^- b( H! |) {$ R9 e% z1 Y K
if(m_ClientNetConfig.ubServerPackIndex >= PACK_ARRAY_SIZE) . j+ A# @& U% q) ?0 s7 @% ~+ q7 n
m_ClientNetConfig.ubServerPackIndex = 0;</P>/ m9 b! B: Y$ W5 X1 V, N
<P> m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex] = WORD(size);
( G! d7 n$ ^( q ServerConfigPacket packet( m_ClientNetConfig );; U5 S( ]! B! A |5 c) z7 S1 A, s
m_ClientNetConfigLock.Leave();</P>3 Z7 R2 }' {- Z" w& r
<P> SendConfigPacketToAll( &packet );
+ w! ^6 T7 K/ e& K2 ]}</P>
( @2 G4 u9 p: D& k; u; ?1 @, |0 e2 t<P>
/ v2 f9 ~4 O" p- i: ~2 ^$ x//-----------------------------------------------------------------------------5 k" F% s% |' Z L1 Q3 e5 k
// Name:
( I& U! g5 F+ R3 j7 C// Desc: ; S' q# i2 k9 ]" r8 ^8 T5 s; O
//-----------------------------------------------------------------------------
1 M3 r8 x z2 Z4 Pvoid CMazeServer::SetClientThreadWait( DWORD dwThreadWait )
% j( f/ f! p# o) I{
6 ?# y, I4 H/ I2 |% E // Update client config, and build packet containing that data t% N1 p! c- b9 l5 M
m_ClientNetConfigLock.Enter();/ U1 M' h& s$ Z/ q+ P7 J/ z
# t" e( |2 r6 V r" U
m_ClientNetConfig.dwThreadWait = dwThreadWait;* h3 E1 ? @* {/ ?' f
ServerConfigPacket packet( m_ClientNetConfig );
: a5 u2 `8 ~) B, I0 @7 [7 a m_ClientNetConfigLock.Leave();</P>
6 x: W8 u' |- h- [+ n<P> SendConfigPacketToAll( &packet );, V& Q9 t6 p: ^' i& v1 G
}</P></DIV> |
zan
|