2011-10-03 14:41:19 -04:00
# include "cPlayer.h"
# include "cServer.h"
# include "cInventory.h"
# include "cClientHandle.h"
# include "cWorld.h"
# include "cPickup.h"
# include "cPluginManager.h"
# include "cChunk.h"
# include "cMCLogger.h"
# include "cWindow.h"
# include "cBlockEntity.h"
# include "cGroupManager.h"
# include "cGroup.h"
# include "cChatColor.h"
# include "cItem.h"
# include "cTracer.h"
# include "cRoot.h"
# include "packets/cPacket_NamedEntitySpawn.h"
# include "packets/cPacket_EntityLook.h"
# include "packets/cPacket_TeleportEntity.h"
# include "packets/cPacket_RelativeEntityMove.h"
# include "packets/cPacket_RelativeEntityMoveLook.h"
# include "packets/cPacket_UpdateHealth.h"
# include "packets/cPacket_Respawn.h"
# include "packets/cPacket_PlayerPosition.h"
# include "packets/cPacket_DestroyEntity.h"
# include "packets/cPacket_Metadata.h"
# include "packets/cPacket_Chat.h"
# include "Vector3d.h"
# include "Vector3f.h"
# include "../iniFile/iniFile.h"
# ifndef _WIN32 // for mkdir
# include <sys/stat.h>
# include <sys/types.h>
2011-10-21 17:25:29 -04:00
# define sprintf_s(dst, size, format, ...) sprintf(dst, format, __VA_ARGS__ )
2011-10-03 14:41:19 -04:00
# endif
extern std : : vector < std : : string > StringSplit ( std : : string str , std : : string delim ) ;
CLASS_DEFINITION ( cPlayer , cPawn ) ;
typedef std : : map < std : : string , bool > PermissionMap ;
struct cPlayer : : sPlayerState
{
PermissionMap ResolvedPermissions ;
PermissionMap Permissions ;
cPlayer : : GroupList ResolvedGroups ;
cPlayer : : GroupList Groups ;
std : : string PlayerName ;
} ;
cPlayer : : cPlayer ( cClientHandle * a_Client , const char * a_PlayerName )
: m_bBurnable ( true )
, e_EPMetaState ( NORMAL )
, m_bVisible ( true )
, m_LastGroundHeight ( 0 )
, m_bTouchGround ( false )
, m_Stance ( 0.0 )
, m_Inventory ( 0 )
, m_CurrentWindow ( 0 )
, m_TimeLastPickupCheck ( 0.f )
, m_Color ( ' - ' )
, m_FireDamageInterval ( 0 )
, m_BurnPeriod ( 0 )
, m_ClientHandle ( a_Client )
, m_pState ( new sPlayerState )
{
m_EntityType = E_PLAYER ;
m_Inventory = new cInventory ( this ) ;
m_TimeLastTeleportPacket = cWorld : : GetTime ( ) ;
m_TimeLastPickupCheck = cWorld : : GetTime ( ) ;
m_pState - > PlayerName = a_PlayerName ;
m_bDirtyPosition = true ; // So chunks are streamed to player at spawn
if ( ! LoadFromDisk ( ) )
{
m_Inventory - > Clear ( ) ;
SetPosX ( cRoot : : Get ( ) - > GetWorld ( ) - > GetSpawnX ( ) ) ;
SetPosY ( cRoot : : Get ( ) - > GetWorld ( ) - > GetSpawnY ( ) ) ;
SetPosZ ( cRoot : : Get ( ) - > GetWorld ( ) - > GetSpawnZ ( ) ) ;
}
MoveToCorrectChunk ( ) ;
cRoot : : Get ( ) - > GetWorld ( ) - > AddPlayer ( this ) ;
}
cPlayer : : ~ cPlayer ( void )
{
SaveToDisk ( ) ;
m_ClientHandle = 0 ;
CloseWindow ( ) ;
if ( m_Inventory )
{
delete m_Inventory ;
m_Inventory = 0 ;
}
delete m_pState ;
cRoot : : Get ( ) - > GetWorld ( ) - > RemovePlayer ( this ) ;
}
void cPlayer : : SpawnOn ( cClientHandle * a_Target )
{
if ( a_Target = = m_ClientHandle | | ! m_bVisible ) return ;
LOG ( " cPlayer::SpawnOn -> Sending %s to %s " , m_pState - > PlayerName . c_str ( ) , ( a_Target ) ? a_Target - > GetUsername ( ) : " Everybody " ) ;
cPacket_NamedEntitySpawn SpawnPacket ;
SpawnPacket . m_UniqueID = m_UniqueID ;
SpawnPacket . m_PlayerName = m_pState - > PlayerName ;
SpawnPacket . m_PosX = ( int ) ( m_Pos - > x * 32 ) ;
SpawnPacket . m_PosY = ( int ) ( m_Pos - > y * 32 ) ;
SpawnPacket . m_PosZ = ( int ) ( m_Pos - > z * 32 ) ;
SpawnPacket . m_Rotation = ( char ) ( ( m_Rot - > x / 360.f ) * 256 ) ;
SpawnPacket . m_Pitch = ( char ) ( ( m_Rot - > y / 360.f ) * 256 ) ;
SpawnPacket . m_CurrentItem = ( short ) m_Inventory - > GetEquippedItem ( ) . m_ItemID ;
if ( a_Target = = 0 )
{
cChunk * Chunk = cRoot : : Get ( ) - > GetWorld ( ) - > GetChunk ( m_ChunkX , m_ChunkY , m_ChunkZ ) ;
Chunk - > Broadcast ( SpawnPacket , m_ClientHandle ) ;
}
else
{
a_Target - > Send ( SpawnPacket ) ;
}
}
void cPlayer : : Tick ( float a_Dt )
{
cChunk * InChunk = cRoot : : Get ( ) - > GetWorld ( ) - > GetChunk ( m_ChunkX , m_ChunkY , m_ChunkZ ) ;
if ( m_bDirtyOrientation & & ! m_bDirtyPosition )
{
cPacket_EntityLook EntityLook ( this ) ;
InChunk - > Broadcast ( EntityLook , m_ClientHandle ) ;
m_bDirtyOrientation = false ;
}
if ( m_bDirtyPosition )
{
cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHook ( cPluginManager : : E_PLUGIN_PLAYER_MOVE , 1 , this ) ;
float DiffX = ( float ) ( GetPosX ( ) - m_LastPosX ) ;
float DiffY = ( float ) ( GetPosY ( ) - m_LastPosY ) ;
float DiffZ = ( float ) ( GetPosZ ( ) - m_LastPosZ ) ;
float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ ;
if ( SqrDist > 4 * 4 // 4 blocks is max Relative Move
| | cWorld : : GetTime ( ) - m_TimeLastTeleportPacket > 2 ) // Send an absolute position every 2 seconds
{
//LOG("Teleported %f", sqrtf(SqrDist) );
cPacket_TeleportEntity TeleportEntity ( this ) ;
InChunk - > Broadcast ( TeleportEntity , m_ClientHandle ) ;
m_TimeLastTeleportPacket = cWorld : : GetTime ( ) ;
}
else
{ // Relative move sucks balls! It's always wrong wtf!
if ( m_bDirtyOrientation )
{
cPacket_RelativeEntityMoveLook RelativeEntityMoveLook ;
RelativeEntityMoveLook . m_UniqueID = GetUniqueID ( ) ;
RelativeEntityMoveLook . m_MoveX = ( char ) ( DiffX * 32 ) ;
RelativeEntityMoveLook . m_MoveY = ( char ) ( DiffY * 32 ) ;
RelativeEntityMoveLook . m_MoveZ = ( char ) ( DiffZ * 32 ) ;
RelativeEntityMoveLook . m_Yaw = ( char ) ( ( GetRotation ( ) / 360.f ) * 256 ) ;
RelativeEntityMoveLook . m_Pitch = ( char ) ( ( GetPitch ( ) / 360.f ) * 256 ) ;
InChunk - > Broadcast ( RelativeEntityMoveLook , m_ClientHandle ) ;
}
else
{
cPacket_RelativeEntityMove RelativeEntityMove ;
RelativeEntityMove . m_UniqueID = GetUniqueID ( ) ;
RelativeEntityMove . m_MoveX = ( char ) ( DiffX * 32 ) ;
RelativeEntityMove . m_MoveY = ( char ) ( DiffY * 32 ) ;
RelativeEntityMove . m_MoveZ = ( char ) ( DiffZ * 32 ) ;
InChunk - > Broadcast ( RelativeEntityMove , m_ClientHandle ) ;
}
}
m_LastPosX = GetPosX ( ) ;
m_LastPosY = GetPosY ( ) ;
m_LastPosZ = GetPosZ ( ) ;
m_bDirtyPosition = false ;
m_ClientHandle - > StreamChunks ( ) ;
}
if ( m_Health > 0 ) // make sure player is alive
{
if ( cWorld : : GetTime ( ) - m_TimeLastPickupCheck > 0.5f ) // Each 0.5 second, check for pickups
{
m_TimeLastPickupCheck = cWorld : : GetTime ( ) ;
// and also check if near a pickup
// TODO: Don't only check in current chunks, but also close chunks (chunks within range)
cChunk * Chunk = cRoot : : Get ( ) - > GetWorld ( ) - > GetChunk ( m_ChunkX , m_ChunkY , m_ChunkZ ) ;
Chunk - > LockEntities ( ) ;
cWorld : : EntityList Entities = Chunk - > GetEntities ( ) ;
for ( cWorld : : EntityList : : iterator itr = Entities . begin ( ) ; itr ! = Entities . end ( ) ; + + itr )
{
if ( ( * itr ) - > GetEntityType ( ) ! = cEntity : : E_PICKUP ) continue ; // Only pickups
float DiffX = ( float ) ( ( * itr ) - > GetPosX ( ) - GetPosX ( ) ) ;
float DiffY = ( float ) ( ( * itr ) - > GetPosY ( ) - GetPosY ( ) ) ;
float DiffZ = ( float ) ( ( * itr ) - > GetPosZ ( ) - GetPosZ ( ) ) ;
float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ ;
if ( SqrDist < 1.5f * 1.5f ) // 1.5 block
{
cPickup * Pickup = reinterpret_cast < cPickup * > ( * itr ) ;
Pickup - > CollectedBy ( this ) ;
}
}
Chunk - > UnlockEntities ( ) ;
}
}
CheckMetaDataBurn ( ) ;
if ( e_EPMetaState = = BURNING ) {
InStateBurning ( a_Dt ) ;
}
}
void cPlayer : : InStateBurning ( float a_Dt ) {
m_FireDamageInterval + = a_Dt ;
char block = cRoot : : Get ( ) - > GetWorld ( ) - > GetBlock ( ( int ) m_Pos - > x , ( int ) m_Pos - > y , ( int ) m_Pos - > z ) ;
char bblock = cRoot : : Get ( ) - > GetWorld ( ) - > GetBlock ( ( int ) m_Pos - > x , ( int ) m_Pos - > y - 1 , ( int ) m_Pos - > z ) ;
if ( m_FireDamageInterval > 1000 ) {
m_FireDamageInterval = 0 ;
int rem = rand ( ) % 3 + 1 ; //Burn most of the time
if ( rem > = 2 ) {
//printf("OUCH burning!!!\n");
TakeDamage ( 1 , this ) ;
}
m_BurnPeriod + + ;
if ( block = = E_BLOCK_LAVA | | block = = E_BLOCK_STATIONARY_LAVA | | block = = E_BLOCK_FIRE
| | bblock = = E_BLOCK_LAVA | | bblock = = E_BLOCK_STATIONARY_LAVA | | bblock = = E_BLOCK_FIRE )
m_BurnPeriod = 0 ;
if ( m_BurnPeriod > 5 ) {
cChunk * InChunk = cRoot : : Get ( ) - > GetWorld ( ) - > GetChunkUnreliable ( m_ChunkX , m_ChunkY , m_ChunkZ ) ;
e_EPMetaState = NORMAL ;
cPacket_Metadata md ( NORMAL , GetUniqueID ( ) ) ;
//md.m_UniqueID = GetUniqueID();
InChunk - > Broadcast ( md ) ;
m_BurnPeriod = 0 ;
}
}
}
//----Change Entity MetaData
void cPlayer : : CheckMetaDataBurn ( ) {
char block = cRoot : : Get ( ) - > GetWorld ( ) - > GetBlock ( ( int ) m_Pos - > x , ( int ) m_Pos - > y , ( int ) m_Pos - > z ) ;
char bblock = cRoot : : Get ( ) - > GetWorld ( ) - > GetBlock ( ( int ) m_Pos - > x , ( int ) m_Pos - > y - 1 , ( int ) m_Pos - > z ) ;
if ( m_bBurnable & & e_EPMetaState ! = BURNING & & ( block = = E_BLOCK_LAVA | | block = = E_BLOCK_STATIONARY_LAVA | | block = = E_BLOCK_FIRE
| | bblock = = E_BLOCK_LAVA | | bblock = = E_BLOCK_STATIONARY_LAVA | | bblock = = E_BLOCK_FIRE ) ) {
cChunk * InChunk = cRoot : : Get ( ) - > GetWorld ( ) - > GetChunkUnreliable ( m_ChunkX , m_ChunkY , m_ChunkZ ) ;
if ( ! InChunk )
return ;
printf ( " I should burn " ) ;
e_EPMetaState = BURNING ;
cPacket_Metadata md ( BURNING , GetUniqueID ( ) ) ;
InChunk - > Broadcast ( md ) ;
}
}
void cPlayer : : SetTouchGround ( bool a_bTouchGround )
{
m_bTouchGround = a_bTouchGround ;
if ( ! m_bTouchGround )
{
cWorld * World = cRoot : : Get ( ) - > GetWorld ( ) ;
char BlockID = World - > GetBlock ( ( int ) m_Pos - > x , ( int ) m_Pos - > y , ( int ) m_Pos - > z ) ;
if ( BlockID ! = E_BLOCK_AIR )
{
m_bTouchGround = true ;
}
if ( BlockID = = E_BLOCK_WATER | | BlockID = = E_BLOCK_STATIONARY_WATER | | BlockID = = E_BLOCK_LADDER | | BlockID = = E_BLOCK_TORCH )
{
m_LastGroundHeight = ( float ) m_Pos - > y ;
}
}
if ( m_bTouchGround )
{
float Dist = ( float ) ( m_LastGroundHeight - m_Pos - > y ) ;
if ( Dist > 4.f ) // Player dropped
{
int Damage = ( int ) ( Dist - 4.f ) ;
if ( Damage > 0 )
{
TakeDamage ( Damage , 0 ) ;
}
}
m_LastGroundHeight = ( float ) m_Pos - > y ;
}
}
void cPlayer : : Heal ( int a_Health )
{
if ( m_Health < 20 )
{
m_Health + = ( short ) a_Health ;
if ( m_Health > 20 )
{
m_Health = 20 ;
}
cPacket_UpdateHealth Health ;
Health . m_Health = m_Health ;
m_ClientHandle - > Send ( Health ) ;
}
}
void cPlayer : : TakeDamage ( int a_Damage , cEntity * a_Instigator )
{
cPawn : : TakeDamage ( a_Damage , a_Instigator ) ;
cPacket_UpdateHealth Health ;
Health . m_Health = m_Health ;
m_ClientHandle - > Send ( Health ) ;
}
void cPlayer : : KilledBy ( cEntity * a_Killer )
{
cPawn : : KilledBy ( a_Killer ) ;
if ( m_Health > 0 ) return ; // not dead yet =]
m_bVisible = false ; // So new clients don't see the player
// Puke out all the items
cItem * Items = m_Inventory - > GetSlots ( ) ;
for ( unsigned int i = 1 ; i < m_Inventory - > c_NumSlots ; + + i )
{
if ( ! Items [ i ] . IsEmpty ( ) )
{
float SpeedX = ( ( rand ( ) % 1000 ) - 500 ) / 100.f ;
float SpeedY = ( ( rand ( ) % 1000 ) ) / 100.f ;
float SpeedZ = ( ( rand ( ) % 1000 ) - 500 ) / 100.f ;
cPickup * Pickup = new cPickup ( ( int ) ( m_Pos - > x * 32 ) , ( int ) ( m_Pos - > y * 32 ) , ( int ) ( m_Pos - > z * 32 ) , Items [ i ] , SpeedX , SpeedY , SpeedZ ) ;
Pickup - > Initialize ( ) ;
}
Items [ i ] . Empty ( ) ;
}
SaveToDisk ( ) ; // Save it, yeah the world is a tough place !
}
void cPlayer : : Respawn ( )
{
m_Health = 20 ;
cWorld * World = cRoot : : Get ( ) - > GetWorld ( ) ;
m_ClientHandle - > Send ( cPacket_Respawn ( ) ) ;
TeleportTo ( World - > GetSpawnX ( ) , World - > GetSpawnY ( ) , World - > GetSpawnZ ( ) ) ;
SetVisible ( true ) ;
}
double cPlayer : : GetEyeHeight ( )
{
return m_Stance ;
}
Vector3d cPlayer : : GetEyePosition ( )
{
return Vector3d ( m_Pos - > x , m_Stance , m_Pos - > z ) ;
}
void cPlayer : : OpenWindow ( cWindow * a_Window )
{
CloseWindow ( ) ;
a_Window - > Open ( * this ) ;
m_CurrentWindow = a_Window ;
}
void cPlayer : : CloseWindow ( )
{
if ( m_CurrentWindow ) m_CurrentWindow - > Close ( * this ) ;
m_CurrentWindow = 0 ;
}
# ifdef SendMessage // Cause stupid windows.h defines SendMessage as SendMessageA
# undef SendMessage
# endif
void cPlayer : : SendMessage ( const char * a_Message )
{
m_ClientHandle - > Send ( cPacket_Chat ( a_Message ) ) ;
}
void cPlayer : : TeleportTo ( cEntity * a_Entity )
{
cPawn : : TeleportTo ( a_Entity ) ;
cPacket_PlayerPosition PlayerPosition ( this ) ;
m_ClientHandle - > Send ( PlayerPosition ) ;
}
void cPlayer : : TeleportTo ( const double & a_PosX , const double & a_PosY , const double & a_PosZ )
{
cPawn : : TeleportTo ( a_PosX , a_PosY , a_PosZ ) ;
cPacket_PlayerPosition PlayerPosition ( this ) ;
m_ClientHandle - > Send ( PlayerPosition ) ;
}
void cPlayer : : MoveTo ( const Vector3d & a_NewPos )
{
// TODO: should do some checks to see if player is not moving through terrain
SetPosition ( a_NewPos ) ;
}
void cPlayer : : SetVisible ( bool a_bVisible )
{
if ( a_bVisible = = true & & m_bVisible = = false ) // Make visible
{
m_bVisible = true ;
SpawnOn ( 0 ) ; // Spawn on everybody
}
if ( a_bVisible = = false & & m_bVisible = = true )
{
m_bVisible = false ;
cPacket_DestroyEntity DestroyEntity ( this ) ;
cChunk * Chunk = cRoot : : Get ( ) - > GetWorld ( ) - > GetChunkUnreliable ( m_ChunkX , m_ChunkY , m_ChunkZ ) ;
if ( Chunk )
{
Chunk - > Broadcast ( DestroyEntity ) ; // Destroy on all clients
}
}
}
void cPlayer : : AddToGroup ( const char * a_GroupName )
{
cGroup * Group = cRoot : : Get ( ) - > GetGroupManager ( ) - > GetGroup ( a_GroupName ) ;
m_pState - > Groups . push_back ( Group ) ;
LOG ( " Added %s to group %s " , m_pState - > PlayerName . c_str ( ) , a_GroupName ) ;
ResolveGroups ( ) ;
ResolvePermissions ( ) ;
}
bool cPlayer : : CanUseCommand ( const char * a_Command )
{
for ( GroupList : : iterator itr = m_pState - > Groups . begin ( ) ; itr ! = m_pState - > Groups . end ( ) ; + + itr )
{
if ( ( * itr ) - > HasCommand ( a_Command ) ) return true ;
}
return false ;
}
bool cPlayer : : HasPermission ( const char * a_Permission )
{
std : : vector < std : : string > Split = StringSplit ( a_Permission , " . " ) ;
PermissionMap Possibilities = m_pState - > ResolvedPermissions ;
// Now search the namespaces
while ( Possibilities . begin ( ) ! = Possibilities . end ( ) )
{
PermissionMap : : iterator itr = Possibilities . begin ( ) ;
if ( itr - > second )
{
std : : vector < std : : string > OtherSplit = StringSplit ( itr - > first , " . " ) ;
if ( OtherSplit . size ( ) < = Split . size ( ) )
{
unsigned int i ;
for ( i = 0 ; i < OtherSplit . size ( ) ; + + i )
{
if ( OtherSplit [ i ] . compare ( Split [ i ] ) ! = 0 )
{
if ( OtherSplit [ i ] . compare ( " * " ) = = 0 ) return true ; // WildCard man!! WildCard!
break ;
}
}
if ( i = = Split . size ( ) ) return true ;
}
}
Possibilities . erase ( itr ) ;
}
// Nothing that matched :(
return false ;
}
bool cPlayer : : IsInGroup ( const char * a_Group )
{
for ( GroupList : : iterator itr = m_pState - > ResolvedGroups . begin ( ) ; itr ! = m_pState - > ResolvedGroups . end ( ) ; + + itr )
{
if ( strcmp ( a_Group , ( * itr ) - > GetName ( ) . c_str ( ) ) = = 0 )
return true ;
}
return false ;
}
void cPlayer : : ResolvePermissions ( )
{
m_pState - > ResolvedPermissions . clear ( ) ; // Start with an empty map yo~
// Copy all player specific permissions into the resolved permissions map
for ( PermissionMap : : iterator itr = m_pState - > Permissions . begin ( ) ; itr ! = m_pState - > Permissions . end ( ) ; + + itr )
{
m_pState - > ResolvedPermissions [ itr - > first ] = itr - > second ;
}
for ( GroupList : : iterator GroupItr = m_pState - > ResolvedGroups . begin ( ) ; GroupItr ! = m_pState - > ResolvedGroups . end ( ) ; + + GroupItr )
{
const cGroup : : PermissionMap & Permissions = ( * GroupItr ) - > GetPermissions ( ) ;
for ( cGroup : : PermissionMap : : const_iterator itr = Permissions . begin ( ) ; itr ! = Permissions . end ( ) ; + + itr )
{
m_pState - > ResolvedPermissions [ itr - > first ] = itr - > second ;
}
}
}
void cPlayer : : ResolveGroups ( )
{
// Clear resolved groups first
m_pState - > ResolvedGroups . clear ( ) ;
// Get a complete resolved list of all groups the player is in
std : : map < cGroup * , bool > AllGroups ; // Use a map, because it's faster than iterating through a list to find duplicates
GroupList ToIterate ;
for ( GroupList : : iterator GroupItr = m_pState - > Groups . begin ( ) ; GroupItr ! = m_pState - > Groups . end ( ) ; + + GroupItr )
{
ToIterate . push_back ( * GroupItr ) ;
}
while ( ToIterate . begin ( ) ! = ToIterate . end ( ) )
{
cGroup * CurrentGroup = * ToIterate . begin ( ) ;
if ( AllGroups . find ( CurrentGroup ) ! = AllGroups . end ( ) )
{
LOGERROR ( " ERROR: Player %s is in the same group multiple times (%s). FIX IT! " , m_pState - > PlayerName . c_str ( ) , CurrentGroup - > GetName ( ) . c_str ( ) ) ;
}
else
{
AllGroups [ CurrentGroup ] = true ;
m_pState - > ResolvedGroups . push_back ( CurrentGroup ) ; // Add group to resolved list
const cGroup : : GroupList & Inherits = CurrentGroup - > GetInherits ( ) ;
for ( cGroup : : GroupList : : const_iterator itr = Inherits . begin ( ) ; itr ! = Inherits . end ( ) ; + + itr )
{
if ( AllGroups . find ( * itr ) ! = AllGroups . end ( ) )
{
LOGERROR ( " ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT! " , m_pState - > PlayerName . c_str ( ) , ( * itr ) - > GetName ( ) . c_str ( ) ) ;
continue ;
}
ToIterate . push_back ( * itr ) ;
}
}
ToIterate . erase ( ToIterate . begin ( ) ) ;
}
}
std : : string cPlayer : : GetColor ( )
{
if ( m_Color ! = ' - ' )
return cChatColor : : MakeColor ( m_Color ) ;
if ( m_pState - > Groups . size ( ) < 1 )
return cChatColor : : White ;
return ( * m_pState - > Groups . begin ( ) ) - > GetColor ( ) ;
}
void cPlayer : : TossItem ( bool a_bDraggingItem , int a_Amount /* = 1 */ )
{
if ( a_bDraggingItem )
{
cItem * Item = GetInventory ( ) . GetWindow ( ) - > GetDraggingItem ( ) ;
if ( Item - > m_ItemID > 0 & & Item - > m_ItemCount > = a_Amount )
{
float vX = 0 , vY = 0 , vZ = 0 ;
EulerToVector ( - GetRotation ( ) , GetPitch ( ) , vZ , vX , vY ) ;
vY = - vY * 2 + 1.f ;
cPickup * Pickup = new cPickup ( ( int ) ( GetPosX ( ) * 32 ) , ( int ) ( GetPosY ( ) * 32 ) + ( int ) ( 1.6f * 32 ) , ( int ) ( GetPosZ ( ) * 32 ) , cItem ( Item - > m_ItemID , ( char ) a_Amount , Item - > m_ItemHealth ) , vX * 2 , vY * 2 , vZ * 2 ) ;
Pickup - > Initialize ( ) ;
if ( Item - > m_ItemCount > a_Amount )
Item - > m_ItemCount - = ( char ) a_Amount ;
else
Item - > Empty ( ) ;
}
return ;
}
// Else drop equipped item
cItem DroppedItem = GetInventory ( ) . GetEquippedItem ( ) ;
if ( DroppedItem . m_ItemID > 0 & & DroppedItem . m_ItemCount > 0 )
{
DroppedItem . m_ItemCount = 1 ;
if ( GetInventory ( ) . RemoveItem ( DroppedItem ) )
{
DroppedItem . m_ItemCount = 1 ; // RemoveItem decreases the count, so set it to 1 again
float vX = 0 , vY = 0 , vZ = 0 ;
EulerToVector ( - GetRotation ( ) , GetPitch ( ) , vZ , vX , vY ) ;
vY = - vY * 2 + 1.f ;
cPickup * Pickup = new cPickup ( ( int ) ( GetPosX ( ) * 32 ) , ( int ) ( GetPosY ( ) * 32 ) + ( int ) ( 1.6f * 32 ) , ( int ) ( GetPosZ ( ) * 32 ) , DroppedItem , vX * 2 , vY * 2 , vZ * 2 ) ;
Pickup - > Initialize ( ) ;
}
}
}
bool cPlayer : : LoadFromDisk ( )
{
cIniFile IniFile ( " users.ini " ) ;
if ( IniFile . ReadFile ( ) )
{
std : : string Groups = IniFile . GetValue ( m_pState - > PlayerName , " Groups " , " " ) ;
if ( Groups . size ( ) > 0 )
{
std : : vector < std : : string > Split = StringSplit ( Groups , " , " ) ;
for ( unsigned int i = 0 ; i < Split . size ( ) ; i + + )
{
AddToGroup ( Split [ i ] . c_str ( ) ) ;
}
}
else
{
AddToGroup ( " Default " ) ;
}
m_Color = IniFile . GetValue ( m_pState - > PlayerName , " Color " , " - " ) [ 0 ] ;
}
else
{
AddToGroup ( " Default " ) ;
}
ResolvePermissions ( ) ;
// Log player permissions, cause it's what the cool kids do
LOGINFO ( " Player %s has permissions: " , m_pState - > PlayerName . c_str ( ) ) ;
for ( PermissionMap : : iterator itr = m_pState - > ResolvedPermissions . begin ( ) ; itr ! = m_pState - > ResolvedPermissions . end ( ) ; + + itr )
{
if ( itr - > second ) LOGINFO ( " %s " , itr - > first . c_str ( ) ) ;
}
char SourceFile [ 128 ] ;
sprintf_s ( SourceFile , 128 , " world/player/%s.bin " , m_pState - > PlayerName . c_str ( ) ) ;
FILE * f ;
# ifdef _WIN32
if ( fopen_s ( & f , SourceFile , " rb " ) = = 0 ) // no error
# else
if ( ( f = fopen ( SourceFile , " rb " ) ) ! = 0 ) // no error
# endif
{
if ( fread ( & m_Pos - > x , sizeof ( double ) , 1 , f ) ! = 1 ) { LOGERROR ( " ERROR READING FROM FILE %s " , SourceFile ) ; fclose ( f ) ; return false ; }
if ( fread ( & m_Pos - > y , sizeof ( double ) , 1 , f ) ! = 1 ) { LOGERROR ( " ERROR READING FROM FILE %s " , SourceFile ) ; fclose ( f ) ; return false ; }
if ( fread ( & m_Pos - > z , sizeof ( double ) , 1 , f ) ! = 1 ) { LOGERROR ( " ERROR READING FROM FILE %s " , SourceFile ) ; fclose ( f ) ; return false ; }
if ( fread ( & m_Rot - > x , sizeof ( float ) , 1 , f ) ! = 1 ) { LOGERROR ( " ERROR READING FROM FILE %s " , SourceFile ) ; fclose ( f ) ; return false ; }
if ( fread ( & m_Rot - > y , sizeof ( float ) , 1 , f ) ! = 1 ) { LOGERROR ( " ERROR READING FROM FILE %s " , SourceFile ) ; fclose ( f ) ; return false ; }
if ( fread ( & m_Rot - > z , sizeof ( float ) , 1 , f ) ! = 1 ) { LOGERROR ( " ERROR READING FROM FILE %s " , SourceFile ) ; fclose ( f ) ; return false ; }
if ( fread ( & m_Health , sizeof ( m_Health ) , 1 , f ) ! = 1 ) { LOGERROR ( " ERROR READING FROM FILE %s " , SourceFile ) ; fclose ( f ) ; return false ; }
if ( ! m_Inventory - > LoadFromFile ( f ) ) { LOGERROR ( " ERROR READING INVENTORY FROM FILE %s " , SourceFile ) ; fclose ( f ) ; return false ; }
fclose ( f ) ;
return true ;
}
return false ;
}
bool cPlayer : : SaveToDisk ( )
{
# ifdef _WIN32
{ // Make sure some folders exist
SECURITY_ATTRIBUTES Attrib ;
Attrib . nLength = sizeof ( SECURITY_ATTRIBUTES ) ;
Attrib . lpSecurityDescriptor = NULL ;
Attrib . bInheritHandle = false ;
: : CreateDirectory ( " world " , & Attrib ) ;
: : CreateDirectory ( " world/player " , & Attrib ) ;
}
# else
{
mkdir ( " world " , S_IRWXU | S_IRWXG | S_IRWXO ) ;
mkdir ( " world/player " , S_IRWXU | S_IRWXG | S_IRWXO ) ;
}
# endif
char SourceFile [ 128 ] ;
sprintf_s ( SourceFile , 128 , " world/player/%s.bin " , m_pState - > PlayerName . c_str ( ) ) ;
FILE * f ;
# ifdef _WIN32
if ( fopen_s ( & f , SourceFile , " wb " ) = = 0 ) // no error
# else
if ( ( f = fopen ( SourceFile , " wb " ) ) ! = 0 ) // no error
# endif
{
fwrite ( & m_Pos - > x , sizeof ( double ) , 1 , f ) ;
fwrite ( & m_Pos - > y , sizeof ( double ) , 1 , f ) ;
fwrite ( & m_Pos - > z , sizeof ( double ) , 1 , f ) ;
fwrite ( & m_Rot - > x , sizeof ( float ) , 1 , f ) ;
fwrite ( & m_Rot - > y , sizeof ( float ) , 1 , f ) ;
fwrite ( & m_Rot - > z , sizeof ( float ) , 1 , f ) ;
fwrite ( & m_Health , sizeof ( m_Health ) , 1 , f ) ;
m_Inventory - > WriteToFile ( f ) ;
fclose ( f ) ;
return true ;
}
LOGERROR ( " ERROR WRITING PLAYER %s TO FILE %s " , m_pState - > PlayerName . c_str ( ) , SourceFile ) ;
return false ;
}
const char * cPlayer : : GetName ( )
{
return m_pState - > PlayerName . c_str ( ) ;
}
void cPlayer : : SetName ( const char * a_Name )
{
m_pState - > PlayerName = a_Name ;
}
const cPlayer : : GroupList & cPlayer : : GetGroups ( )
{
return m_pState - > Groups ;
}