//========= Copyright © 1996-2008, Valve LLC, All rights reserved. ============
//
// Purpose: Shared definitions for the communication between the server/client
//
// $NoKeywords: $
//=============================================================================

#ifndef SPACEWAR_H
#define SPACEWAR_H


// The Steamworks API's are modular, you can use some subsystems without using others
// When USE_GS_AUTH_API is defined you get the following Steam features:
// - Strong user authentication and authorization
// - Game server matchmaking
// - VAC cheat protection
// - Access to achievement/community API's
// - P2P networking capability

// Remove this define to disable using the native Steam authentication and matchmaking system
// You can use this as a sample of how to integrate your game without replacing an existing matchmaking system
// When you un-define USE_GS_AUTH_API you get:
// - Access to achievement/community API's
// - P2P networking capability
// You CANNOT use:
// - VAC cheat protection
// - Game server matchmaking
// as these function depend on using Steam authentication
#define USE_GS_AUTH_API 


// Current game server version
#define SPACEWAR_SERVER_VERSION "1.0.0.0"

// UDP port for the spacewar server to do authentication on (ie, talk to Steam on)
#define SPACEWAR_AUTHENTICATION_PORT 8766

// UDP port for the spacewar server to listen on
#define SPACEWAR_SERVER_PORT 27015

// UDP port for the master server updater to listen on
#define SPACEWAR_MASTER_SERVER_UPDATER_PORT 27016

// How long to wait for a response from the server before resending our connection attempt
#define SERVER_CONNECTION_RETRY_MILLISECONDS 350

// How long to wait for a client to send an update before we drop its connection server side
#define SERVER_TIMEOUT_MILLISECONDS 5000

// Maximum packet size in bytes
#define MAX_SPACEWAR_PACKET_SIZE 1024*512

// Maximum number of players who can join a server and play simultaneously
#define MAX_PLAYERS_PER_SERVER 4

// Time to pause wait after a round ends before starting a new one
#define MILLISECONDS_BETWEEN_ROUNDS 4000

// How long photon beams live before expiring
#define PHOTON_BEAM_LIFETIME_IN_TICKS 1750

// How fast can photon beams be fired?
#define PHOTON_BEAM_FIRE_INTERVAL_TICKS 250

// Amount of space needed for beams per ship
#define MAX_PHOTON_BEAMS_PER_SHIP (PHOTON_BEAM_LIFETIME_IN_TICKS/PHOTON_BEAM_FIRE_INTERVAL_TICKS)

// Time to timeout a connection attempt in
#define MILLISECONDS_CONNECTION_TIMEOUT 30000

// How many times a second does the server send world updates to clients
#define SERVER_UPDATE_SEND_RATE 60

// How many times a second do we send our updated client state to the server
#define CLIENT_UPDATE_SEND_RATE 30

// How fast does the server internally run at?
#define MAX_CLIENT_AND_SERVER_FPS 86


template <typename T>
inline T WordSwap( T w )
{
	uint16 temp;

	temp  = ((*((uint16 *)&w) & 0xff00) >> 8);
	temp |= ((*((uint16 *)&w) & 0x00ff) << 8);

	return *((T*)&temp);
}

template <typename T>
inline T DWordSwap( T dw )
{
	uint32 temp;

	temp  =   *((uint32 *)&dw) 				>> 24;
	temp |= ((*((uint32 *)&dw) & 0x00FF0000) >> 8);
	temp |= ((*((uint32 *)&dw) & 0x0000FF00) << 8);
	temp |= ((*((uint32 *)&dw) & 0x000000FF) << 24);

	return *((T*)&temp);
}

template <typename T>
inline T QWordSwap( T dw )
{
	uint64 temp;

	temp  =   *((uint64 *)&dw) 				         >> 56;
	temp |= ((*((uint64 *)&dw) & 0x00FF000000000000ull) >> 40);
	temp |= ((*((uint64 *)&dw) & 0x0000FF0000000000ull) >> 24);
	temp |= ((*((uint64 *)&dw) & 0x000000FF00000000ull) >> 8);
	temp |= ((*((uint64 *)&dw) & 0x00000000FF000000ull) << 8);
	temp |= ((*((uint64 *)&dw) & 0x0000000000FF0000ull) << 24);
	temp |= ((*((uint64 *)&dw) & 0x000000000000FF00ull) << 40);
	temp |= ((*((uint64 *)&dw) & 0x00000000000000FFull) << 56);

	return *((T*)&temp);
}

#ifndef _PS3

#define LittleInt16( val )	( val )
#define LittleWord( val )	( val )
#define LittleInt32( val )	( val )
#define LittleDWord( val )	( val )
#define LittleQWord( val )	( val )
#define LittleFloat( val )	( val )

#else

#define LittleInt16( val )	WordSwap( val )
#define LittleWord( val )	WordSwap( val )
#define LittleInt32( val )	DWordSwap( val )
#define LittleDWord( val )	DWordSwap( val )
#define LittleQWord( val )	QWordSwap( val )
#define LittleFloat( val )	DWordSwap( val )

#endif


// Leaderboard names
#define LEADERBOARD_QUICKEST_WIN "Quickest Win"
#define LEADERBOARD_FEET_TRAVELED "Feet Traveled"


// Player colors
DWORD const g_rgPlayerColors[ MAX_PLAYERS_PER_SERVER ] = 
{ 
	D3DCOLOR_ARGB( 255, 255, 150, 150 ), // red 
	D3DCOLOR_ARGB( 255, 200, 200, 255 ), // blue
	D3DCOLOR_ARGB( 255, 255, 204, 102 ), // orange
	D3DCOLOR_ARGB( 255, 153, 255, 153 ), // green
};


// Enum for possible game states on the client
enum EClientGameState
{
	k_EClientGameStartServer,
	k_EClientGameActive,
	k_EClientGameWaitingForPlayers,
	k_EClientGameMenu,
	k_EClientGameQuitMenu,
	k_EClientGameExiting,
	k_EClientGameInstructions,
	k_EClientGameDraw,
	k_EClientGameWinner,
	k_EClientGameConnecting,
	k_EClientGameConnectionFailure,
	k_EClientFindInternetServers,
	k_EClientStatsAchievements,
	k_EClientCreatingLobby,
	k_EClientInLobby,
	k_EClientFindLobby,
	k_EClientJoiningLobby,
	k_EClientFindLANServers,
	k_EClientRemoteStorage,
	k_EClientLeaderboards,
	k_EClientFriendsList,
	k_EClientMinidump,
	k_EClientConnectingToSteam,
	k_EClientLinkSteamAccount,
	k_EClientAutoCreateAccount,
	k_EClientRetrySteamConnection,
	k_EClientClanChatRoom,
	k_EClientWebCallback,
	k_EClientMusic,
	k_EClientWorkshop,
	k_EClientHTMLSurface,
	k_EClientInGameStore,
};


// Enum for possible game states on the server
enum EServerGameState
{
	k_EServerWaitingForPlayers,
	k_EServerActive,
	k_EServerDraw,
	k_EServerWinner,
	k_EServerExiting,
};

#pragma pack( push, 1 )

// Data sent per photon beam from the server to update clients photon beam positions
struct ServerPhotonBeamUpdateData_t
{
	void SetActive( bool bIsActive ) { m_bIsActive = bIsActive; }
	bool GetActive() { return m_bIsActive; }

	void SetRotation( float flRotation ) { m_flCurrentRotation = LittleFloat( flRotation ); }
	float GetRotation() { return LittleFloat( m_flCurrentRotation ); }

	void SetXVelocity( float flVelocity ) { m_flXVelocity = LittleFloat( flVelocity ); }
	float GetXVelocity() { return LittleFloat( m_flXVelocity ); }

	void SetYVelocity( float flVelocity ) { m_flYVelocity = LittleFloat( flVelocity ); }
	float GetYVelocity() { return LittleFloat( m_flYVelocity ); }

	void SetXPosition( float flPosition ) { m_flXPosition = LittleFloat( flPosition ); }
	float GetXPosition() { return LittleFloat( m_flXPosition ); }

	void SetYPosition( float flPosition ) { m_flYPosition = LittleFloat( flPosition ); }
	float GetYPosition() { return LittleFloat( m_flYPosition ); }


private:
	// Does the photon beam exist right now?
	bool m_bIsActive; 

	// The current rotation 
	float m_flCurrentRotation;

	// The current velocity
	float m_flXVelocity;
	float m_flYVelocity;

	// The current position
	float m_flXPosition;
	float m_flYPosition;
};


// This is the data that gets sent per ship in each update, see below for the full update data
struct ServerShipUpdateData_t
{
	void SetRotation( float flRotation ) { m_flCurrentRotation = LittleFloat( flRotation ); }
	float GetRotation() { return LittleFloat( m_flCurrentRotation ); }

	void SetRotationDeltaLastFrame( float flDelta ) { m_flRotationDeltaLastFrame = LittleFloat( flDelta ); }
	float GetRotationDeltaLastFrame() { return LittleFloat( m_flRotationDeltaLastFrame ); }

	void SetXAcceleration( float flAcceleration ) { m_flXAcceleration = LittleFloat( flAcceleration ); }
	float GetXAcceleration() { return LittleFloat( m_flXAcceleration ); }

	void SetYAcceleration( float flAcceleration ) { m_flYAcceleration = LittleFloat( flAcceleration ); }
	float GetYAcceleration() { return LittleFloat( m_flYAcceleration ); }

	void SetXVelocity( float flVelocity ) { m_flXVelocity = LittleFloat( flVelocity ); }
	float GetXVelocity() { return LittleFloat( m_flXVelocity ); }

	void SetYVelocity( float flVelocity ) { m_flYVelocity = LittleFloat( flVelocity ); }
	float GetYVelocity() { return LittleFloat( m_flYVelocity ); }

	void SetXPosition( float flPosition ) { m_flXPosition = LittleFloat( flPosition ); }
	float GetXPosition() { return LittleFloat( m_flXPosition ); }

	void SetYPosition( float flPosition ) { m_flYPosition = LittleFloat( flPosition ); }
	float GetYPosition() { return LittleFloat( m_flYPosition ); }

	void SetExploding( bool bIsExploding ) { m_bExploding = bIsExploding; }
	bool GetExploding() { return m_bExploding; }

	void SetDisabled( bool bIsDisabled ) { m_bDisabled = bIsDisabled; }
	bool GetDisabled() { return m_bDisabled; }

	void SetForwardThrustersActive( bool bActive ) { m_bForwardThrustersActive = bActive; }
	bool GetForwardThrustersActive() { return m_bForwardThrustersActive; }

	void SetReverseThrustersActive( bool bActive ) { m_bReverseThrustersActive = bActive; }
	bool GetReverseThrustersActive() { return m_bReverseThrustersActive; }

	void SetDecoration( int nDecoration ) { m_nShipDecoration = nDecoration;  }
	int GetDecoration() { return m_nShipDecoration; }

	void SetWeapon( int nWeapon ) { m_nShipWeapon = nWeapon;  }
	int GetWeapon() { return m_nShipWeapon; }

	void SetPower( int nPower ) { m_nShipPower = nPower;  }
	int GetPower() { return m_nShipPower; }

	void SetShieldStrength( int nShieldStrength ) { m_nShieldStrength = nShieldStrength;  }
	int GetShieldStrength() { return m_nShieldStrength; }

	void SetThrustersLevel( float fLevel ) { m_fThrusterLevel = fLevel; }
	float GetThrustersLevel( ) { return m_fThrusterLevel; }

	void SetTurnSpeed( float fSpeed ) { m_fTurnSpeed = fSpeed; }
	float GetTurnSpeed( ) { return m_fTurnSpeed; }

	ServerPhotonBeamUpdateData_t *AccessPhotonBeamData( int iIndex ) { return &m_PhotonBeamData[iIndex]; }

private:
	// The current rotation of the ship
	float m_flCurrentRotation;

	// The delta in rotation for the last frame (client side interpolation will use this)
	float m_flRotationDeltaLastFrame;

	// The current thrust for the ship
	float m_flXAcceleration;
	float m_flYAcceleration;

	// The current velocity for the ship
	float m_flXVelocity;
	float m_flYVelocity;

	// The current position for the ship
	float m_flXPosition;
	float m_flYPosition;

	// Is the ship exploding?
	bool m_bExploding;

	// Is the ship disabled?
	bool m_bDisabled;

	// Are the thrusters to be drawn?
	bool m_bForwardThrustersActive;
	bool m_bReverseThrustersActive;

	// Decoration for this ship
	int m_nShipDecoration;

	// Weapon for this ship
	int m_nShipWeapon;

	// Power for this ship
	int m_nShipPower;
	int m_nShieldStrength;

	// Photon beam positions and data
	ServerPhotonBeamUpdateData_t m_PhotonBeamData[MAX_PHOTON_BEAMS_PER_SHIP];

	// Thrust and rotation speed can be anlog when using a Steam Controller
	float m_fThrusterLevel;
	float m_fTurnSpeed;
};


// This is the data that gets sent from the server to each client for each update
struct ServerSpaceWarUpdateData_t
{
	void SetServerGameState( EServerGameState eState ) { m_eCurrentGameState = LittleDWord( (uint32)eState ); }
	EServerGameState GetServerGameState() { return (EServerGameState)LittleDWord( m_eCurrentGameState ); }

	void SetPlayerWhoWon( uint32 iIndex ) { m_uPlayerWhoWonGame = LittleDWord( iIndex ); }
	uint32 GetPlayerWhoWon() { return LittleDWord( m_uPlayerWhoWonGame ); }

	void SetPlayerActive( uint32 iIndex, bool bIsActive ) { m_rgPlayersActive[iIndex] = bIsActive; }
	bool GetPlayerActive( uint32 iIndex ) { return m_rgPlayersActive[iIndex]; }

	void SetPlayerScore( uint32 iIndex, uint32 unScore ) { m_rgPlayerScores[iIndex] = LittleDWord(unScore); }
	uint32 GetPlayerScore( uint32 iIndex ) { return LittleDWord(m_rgPlayerScores[iIndex]); }

	void SetPlayerSteamID( uint32 iIndex, uint64 ulSteamID ) { m_rgPlayerSteamIDs[iIndex] = LittleQWord(ulSteamID); }
	uint64 GetPlayerSteamID( uint32 iIndex ) { return LittleQWord(m_rgPlayerSteamIDs[iIndex]); }

	ServerShipUpdateData_t *AccessShipUpdateData( uint32 iIndex ) { return &m_rgShipData[iIndex];}

private:
	// What state the game is in
	uint32 m_eCurrentGameState;

	// Who just won the game? -- only valid when m_eCurrentGameState == k_EGameWinner
	uint32 m_uPlayerWhoWonGame;

	// which player slots are in use
	bool m_rgPlayersActive[MAX_PLAYERS_PER_SERVER];

	// what are the scores for each player?
	uint32 m_rgPlayerScores[MAX_PLAYERS_PER_SERVER];

	// array of ship data
	ServerShipUpdateData_t m_rgShipData[MAX_PLAYERS_PER_SERVER];

	// array of players steamids for each slot, serialized to uint64
	uint64 m_rgPlayerSteamIDs[MAX_PLAYERS_PER_SERVER];
};


// This is the data that gets sent from each client to the server for each update
struct ClientSpaceWarUpdateData_t
{
	void SetPlayerName( const char *pchName ) { strncpy( m_rgchPlayerName, pchName, sizeof( m_rgchPlayerName ) ); }
	const char *GetPlayerName() { return m_rgchPlayerName; }

	void SetFirePressed( bool bIsPressed ) { m_bFirePressed = bIsPressed; }
	bool GetFirePressed() { return m_bFirePressed; }

	void SetTurnLeftPressed( bool bIsPressed ) { m_bTurnLeftPressed = bIsPressed; }
	bool GetTurnLeftPressed() { return m_bTurnLeftPressed; }

	void SetTurnRightPressed( bool bIsPressed ) { m_bTurnRightPressed = bIsPressed; }
	bool GetTurnRightPressed() { return m_bTurnRightPressed; }

	void SetForwardThrustersPressed( bool bIsPressed ) { m_bForwardThrustersPressed = bIsPressed; }
	bool GetForwardThrustersPressed() { return m_bForwardThrustersPressed; }

	void SetReverseThrustersPressed( bool bIsPressed ) { m_bReverseThrustersPressed = bIsPressed; }
	bool GetReverseThrustersPressed() { return m_bReverseThrustersPressed; }

	void SetDecoration( int nDecoration ) { m_nShipDecoration = nDecoration;  }
	int GetDecoration() { return m_nShipDecoration; }

	void SetWeapon( int nWeapon ) { m_nShipWeapon = nWeapon;  }
	int GetWeapon() { return m_nShipWeapon; }

	void SetPower( int nPower ) { m_nShipPower = nPower;  }
	int GetPower() { return m_nShipPower; }

	void SetShieldStrength( int nShieldPower ) { m_nShieldStrength = nShieldPower;  }
	int GetShieldStrength() { return m_nShieldStrength; }

	void SetThrustersLevel( float fLevel ) { m_fThrusterLevel = fLevel; }
	float GetThrustersLevel( ) { return m_fThrusterLevel; }

	void SetTurnSpeed( float fSpeed ) { m_fTurnSpeed = fSpeed; }
	float GetTurnSpeed( ) { return m_fTurnSpeed; }

private:
	// Key's which are done
	bool m_bFirePressed;
	bool m_bTurnLeftPressed;
	bool m_bTurnRightPressed;
	bool m_bForwardThrustersPressed;
	bool m_bReverseThrustersPressed;

	// Decoration for this ship
	int m_nShipDecoration;

	// Weapon for this ship
	int m_nShipWeapon;

	// Power for this ship
	int m_nShipPower;

	int m_nShieldStrength;

	// Name of the player (needed server side to tell master server about)
	// bugbug jmccaskey - Really lame to send this every update instead of event driven...
	char m_rgchPlayerName[64];

	// Thrust and rotation speed can be anlog when using a Steam Controller
	float m_fThrusterLevel;
	float m_fTurnSpeed;
};

#pragma pack( pop )

#endif // SPACEWAR_H