summaryrefslogtreecommitdiffstats
path: root/source/cPlayer.cpp
diff options
context:
space:
mode:
authorfaketruth <faketruth@0a769ca7-a7f5-676a-18bf-c427514a06d6>2011-10-03 20:41:19 +0200
committerfaketruth <faketruth@0a769ca7-a7f5-676a-18bf-c427514a06d6>2011-10-03 20:41:19 +0200
commit386d58b5862d8b76925c6523721594887606e82a (patch)
treeef073e7a843f4b75a4008d4b7383f7cdf08ceee5 /source/cPlayer.cpp
parentVisual Studio 2010 solution and project files (diff)
downloadcuberite-386d58b5862d8b76925c6523721594887606e82a.tar
cuberite-386d58b5862d8b76925c6523721594887606e82a.tar.gz
cuberite-386d58b5862d8b76925c6523721594887606e82a.tar.bz2
cuberite-386d58b5862d8b76925c6523721594887606e82a.tar.lz
cuberite-386d58b5862d8b76925c6523721594887606e82a.tar.xz
cuberite-386d58b5862d8b76925c6523721594887606e82a.tar.zst
cuberite-386d58b5862d8b76925c6523721594887606e82a.zip
Diffstat (limited to 'source/cPlayer.cpp')
-rw-r--r--source/cPlayer.cpp713
1 files changed, 713 insertions, 0 deletions
diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp
new file mode 100644
index 000000000..8552abd3e
--- /dev/null
+++ b/source/cPlayer.cpp
@@ -0,0 +1,713 @@
+#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>
+#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;
+} \ No newline at end of file