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