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