//---------------------------------------------------------------------------- // File: mazeserver.h // // Desc: see main.cpp // // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved. //----------------------------------------------------------------------------- #ifndef _MAZESERVER_H #define _MAZESERVER_H //----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- #include "NetAbstract.h" #include "SyncObjects.h" #include "Maze.h" #include "Random.h" #include "Packets.h" #include "Trig.h" class CMaze; struct ClientPosPacket; #define SERVER_MAX_WIDTH 128 #define SERVER_MAX_HEIGHT 128 #define DEFAULT_MAZE_WIDTH 16 #define DEFAULT_MAZE_HEIGHT 16 #define DEFAULT_SEED 314159 #define LOCK_GRID_SIZE 16 //----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- struct PlayerData { DWORD dwID; // Client ID DWORD NetID; // NetID for owning player (0 if none) DWORD dwVersion; // Version of the owning player BOOL bAllow; // If FALSE, then we should drop this player // Links for the various lists PlayerData* pNext; // Free/active PlayerData list (double link) PlayerData* pPrevious; PlayerData* pNextInCell; // Cell list (single link) PlayerData* pNextInIDHashBucket; // ID hash bucket (single link) FLOAT fLastDisplayTime; FLOAT fLastCITime; BOOL bActive; float fPosX; // Floating point position float fPosY; WORD wCellX; // Coordinates of the cell this player is in WORD wCellY; // or (0xffff,0xffff) for off-map ANGLE aCameraYaw; DWORD dwNumNearbyPlayers; // Number of nearby players DWORD pad[4]; }; //----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- struct ServerCell { PlayerData* pFirstPlayerData; }; //----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- class CMazeServer : public INetServer { public: CMazeServer(); // From INetServer void OnAddConnection( DWORD dwID ); HRESULT OnPacket( DWORD from, void* pData, DWORD dwSize ); void OnRemoveConnection( DWORD dwID ); void OnSessionLost( DWORD dwReason ); // Hook up to the network service void SetOutboundServer( IOutboundServer* poutnet ) { m_pNet = poutnet; }; // Initialisation - need to hook up a maze object HRESULT Init( BOOL bLocalLoopback, const CMaze* pmaze ); void Shutdown(); // Chance of server sending packets via reliable transport void SetServerReliableRate( DWORD percent ) { m_dwServerReliableRate = percent; }; DWORD GetServerReliableRate() const { return m_dwServerReliableRate; }; // Timeout of server's packets void SetServerTimeout( DWORD timeout ) { m_dwServerTimeout = timeout; }; DWORD GetServerTimeout() const { return m_dwServerTimeout; }; // Change of client sending packets via reliable transport. Setting this causes the server // to propagate this setting to all currently connected clients void SetClientReliableRate( DWORD percent ); DWORD GetClientReliableRate() const { return DWORD(m_ClientNetConfig.ubReliableRate); }; // Change client update rate. Setting this causes the server to propagate this setting to all // currently connected clients void SetClientUpdateRate( DWORD rate ); DWORD GetClientUpdateRate() const { return DWORD(m_ClientNetConfig.wUpdateRate); }; // Change client timeout. Setting this causes the server to propagate this setting to all // currently connected clients void SetClientTimeout( DWORD timeout ); DWORD GetClientTimeout() const { return DWORD(m_ClientNetConfig.wTimeout); }; // Change Client position pack size. Setting this causes the server to propagate this setting to all // currently connected clients void SetClientPackSize( DWORD size ); DWORD GetClientPackSize() const { return DWORD(m_ClientNetConfig.wClientPackSizeArray[m_ClientNetConfig.ubClientPackIndex]); }; // Change Server position pack size. void SetServerPackSize( DWORD size ); DWORD GetServerPackSize() const { return DWORD(m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex]); }; // How long the user wants to hold the Server's Dplay Threads void SetServerThreadWait( DWORD threadwait ) { m_dwServerThreadWait = threadwait; }; DWORD GetServerThreadWait() const { return m_dwServerThreadWait; }; // How long the user wants to hold the Server's Dplay Threads void SetClientThreadWait( DWORD threadwait ); DWORD GetClientThreadWait() const { return DWORD(m_ClientNetConfig.dwThreadWait); }; // Various commands void DisplayConnectionInfo( DWORD dwID ); void DisplayNextConnectionInfo(); void PrintStats(); void SetLogLevel( DWORD dwLogLevel ) { m_dwLogLevel = dwLogLevel; } DWORD GetLogLevel() { return m_dwLogLevel; } DWORD GetNumPlayers() { return m_dwPlayerCount; } protected: BOOL m_bLocalLoopback; IOutboundServer* m_pNet; const CMaze* m_pMaze; DWORD m_dwLogLevel; DWORD m_dwWidth; DWORD m_dwHeight; CCriticalSection m_AddRemoveLock; // A fixed sized grid of locks which we lay over the maze to control access to it // We demand that the maze dimensions are a power-of-2 times the dimensions of this // grid, and pre-store that power to allow fast translation CLockArray m_LockGrid; DWORD m_dwMazeXShift; DWORD m_dwMazeYShift; void LockCell( DWORD x , DWORD y ); void UnlockCell( DWORD x , DWORD y ); void LockRange( DWORD x1 , DWORD y1 , DWORD x2 , DWORD y2 ); void UnlockRange( DWORD x1 , DWORD y1 , DWORD x2 , DWORD y2 ); void LockCellPair( DWORD x1 , DWORD y1 , DWORD x2 , DWORD y2 ); void UnlockCellPair( DWORD x1 , DWORD y1 , DWORD x2 , DWORD y2 ); CCriticalSection m_OffMapLock; // The PlayerData lists PlayerData m_PlayerDatas[MAX_PLAYER_OBJECTS]; PlayerData* m_pFirstActivePlayerData; PlayerData* m_pFirstFreePlayerData; DWORD m_dwActivePlayerDataCount; DWORD m_dwPlayerDataUniqueValue; CCriticalSection m_PlayerDataListLock; // The player object locks enum { NUM_PLAYER_OBJECT_LOCKS = 16 }; CCriticalSection m_PlayerDataLocks[NUM_PLAYER_OBJECT_LOCKS]; void LockPlayerData( PlayerData* pPlayerData ) { m_PlayerDataLocks[((pPlayerData-m_PlayerDatas) & (NUM_PLAYER_OBJECT_LOCKS-1))].Enter(); }; void UnlockPlayerData( PlayerData* pPlayerData ) { m_PlayerDataLocks[((pPlayerData-m_PlayerDatas) & (NUM_PLAYER_OBJECT_LOCKS-1))].Leave(); }; PlayerData* CreatePlayerData(); void DestroyPlayerData( PlayerData* pPlayerData ); // The cell array and the "off-map" cell. ServerCell m_OffMapCell; ServerCell m_Cells[SERVER_MAX_WIDTH][SERVER_MAX_HEIGHT]; // Remove playerdata from its cell void RemovePlayerDataFromCell( PlayerData* pPlayerData ); // Unsafe versions of add/remove. Must have playerdata and cell locked when you call this void UnsafeRemovePlayerDataFromCell( PlayerData* pPlayerData ); void UnsafeAddPlayerDataToCell( PlayerData* pPlayerData ); ServerCell* GetCell( PlayerData* pPlayerData ) { if ( pPlayerData->wCellX == 0xffff ) return &m_OffMapCell; else return &m_Cells[pPlayerData->wCellY][pPlayerData->wCellX]; }; void HandleClientPosPacket( DWORD dwFrom, ClientPosPacket* pPacket ); void HandleClientVersionPacket( DWORD dwFrom, ClientVersionPacket* pClientVersionPack ); void HandleUnknownPacket( DWORD dwFrom, ClientPacket* pClientPack, DWORD size ); BOOL IsValidPackSize( DWORD wSize ); BOOL IsClientVersionSupported( DWORD dwClientVersion ); DWORD m_dwPlayerCount; CCriticalSection m_csThreadCountLock; WORD m_wActiveThreadCount; WORD m_wMaxThreadCount; FLOAT m_fAvgThreadCount; FLOAT m_fAvgThreadTime; FLOAT m_fMaxThreadTime; DWORD m_dwPeakPlayerCount; // Hashing DPIDs to PlayerData pointers void SetPlayerDataForID( DWORD dwID, PlayerData* pPlayerData ); PlayerData* GetPlayerDataForID( DWORD dwID ); void RemovePlayerDataID( PlayerData* pPlayerData ); DWORD IDHash( DWORD dwID ); enum { NUM_ID_HASH_BUCKETS = 1024 }; enum { NUM_ID_HASH_BUCKET_LOCKS = 16 }; PlayerData* m_pstIDHashBucket[NUM_ID_HASH_BUCKETS]; CCriticalSection m_IDHashBucketLocks[NUM_ID_HASH_BUCKET_LOCKS]; // Random number generator CRandom m_Rand; // Send packet wrapper HRESULT SendPacket( DWORD dwTo, void* pData, DWORD dwSize, BOOL bReliable, DWORD dwTimeout ); void SendConfigPacketToAll( ServerConfigPacket* pPacket ); // Network configuration parameters DWORD m_dwServerReliableRate; DWORD m_dwServerTimeout; DWORD m_dwServerThreadWait; ClientNetConfig m_ClientNetConfig; CCriticalSection m_ClientNetConfigLock; }; //----------------------------------------------------------------------------- // Name: // Desc: This function is called by the server to output informational text. // In the client it should probably just be a dummy function, in the server // it should probably just spew out to the console //----------------------------------------------------------------------------- enum ServerBufferType { SLINE_PROMPT, SLINE_INPUT, SLINE_LOG, SLINE_CMD }; void ConsolePrintf( ServerBufferType enumLineType, const TCHAR* fmt , ... ); #endif