diff options
Diffstat (limited to 'source/Player.cpp')
-rw-r--r-- | source/Player.cpp | 1019 |
1 files changed, 1019 insertions, 0 deletions
diff --git a/source/Player.cpp b/source/Player.cpp new file mode 100644 index 000000000..b20287750 --- /dev/null +++ b/source/Player.cpp @@ -0,0 +1,1019 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Player.h" +#include "Server.h" +#include "ClientHandle.h" +#include "UI/Window.h" +#include "UI/WindowOwner.h" +#include "World.h" +#include "Pickup.h" +#include "PluginManager.h" +#include "BlockEntity.h" +#include "GroupManager.h" +#include "Group.h" +#include "ChatColor.h" +#include "Item.h" +#include "Tracer.h" +#include "Root.h" +#include "OSSupport/MakeDir.h" +#include "OSSupport/Timer.h" +#include "MersenneTwister.h" + +#include "Vector3d.h" +#include "Vector3f.h" + +#include "../iniFile/iniFile.h" +#include <json/json.h> + +#define float2int(x) ((x)<0 ? ((int)(x))-1 : (int)(x)) + + + + + +CLASS_DEFINITION( cPlayer, cPawn ); + + + + + +cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) + : m_GameMode(eGameMode_NotSet) + , m_IP("") + , m_LastBlockActionTime( 0 ) + , m_LastBlockActionCnt( 0 ) + , m_bVisible( true ) + , m_LastGroundHeight( 0 ) + , m_bTouchGround( false ) + , m_Stance( 0.0 ) + , m_Inventory(*this) + , m_CurrentWindow(NULL) + , m_InventoryWindow(NULL) + , m_TimeLastPickupCheck( 0.f ) + , m_Color('-') + , m_ClientHandle( a_Client ) + , m_FoodExhaustionLevel(0.f) + , m_FoodTickTimer(0) +{ + LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", + a_PlayerName.c_str(), a_Client->GetIPString().c_str(), + this, GetUniqueID() + ); + m_EntityType = eEntityType_Player; + + m_InventoryWindow = new cInventoryWindow(*this); + m_CurrentWindow = m_InventoryWindow; + m_InventoryWindow->OpenedByPlayer(*this); + + SetMaxHealth(20); + m_MaxFoodLevel = 20; + m_MaxFoodSaturationLevel = 20.f; + + m_FoodLevel = m_MaxFoodLevel; + m_FoodSaturationLevel = 5.f; + + cTimer t1; + m_LastPlayerListTime = t1.GetNowTime(); + + m_TimeLastTeleportPacket = cWorld::GetTime(); + m_TimeLastPickupCheck = cWorld::GetTime(); + + m_PlayerName = a_PlayerName; + m_bDirtyPosition = true; // So chunks are streamed to player at spawn + + if (!LoadFromDisk()) + { + m_Inventory.Clear(); + m_Pos.x = cRoot::Get()->GetDefaultWorld()->GetSpawnX(); + m_Pos.y = cRoot::Get()->GetDefaultWorld()->GetSpawnY(); + m_Pos.z = cRoot::Get()->GetDefaultWorld()->GetSpawnZ(); + + LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}", + a_PlayerName.c_str(), m_Pos.x, m_Pos.y, m_Pos.z + ); + } + m_LastGroundHeight = (float)(m_Pos.y); + m_Stance = m_Pos.y + 1.62; +} + + + + + +cPlayer::~cPlayer(void) +{ + LOG("Deleting cPlayer \"%s\" at %p, ID %d", m_PlayerName.c_str(), this, GetUniqueID()); + + SaveToDisk(); + + m_World->RemovePlayer( this ); + + m_ClientHandle = NULL; + + delete m_InventoryWindow; + + LOG("Player %p deleted", this); +} + + + + + +void cPlayer::Initialize( cWorld* a_World ) +{ + cPawn::Initialize( a_World ); + GetWorld()->AddPlayer( this ); +} + + + + + +void cPlayer::Destroyed() +{ + CloseWindow(-1); + m_ClientHandle = NULL; +} + + + + + +void cPlayer::SpawnOn(cClientHandle & a_Client) +{ + /* + LOGD("cPlayer::SpawnOn(%s) for \"%s\" at pos {%.2f, %.2f, %.2f}", + a_Client.GetUsername().c_str(), m_PlayerName.c_str(), m_Pos.x, m_Pos.y, m_Pos.z + ); + */ + + if (m_bVisible) + { + a_Client.SendPlayerSpawn(*this); + } +} + + + + + +void cPlayer::Tick(float a_Dt) +{ + if (!m_ClientHandle->IsPlaying()) + { + // We're not yet in the game, ignore everything + return; + } + + cPawn::Tick(a_Dt); + + if (m_bDirtyOrientation && !m_bDirtyPosition) + { + m_World->BroadcastEntLook(*this, m_ClientHandle); + m_World->BroadcastEntHeadLook(*this, m_ClientHandle); + m_bDirtyOrientation = false; + } + else 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) ); + m_World->BroadcastTeleportEntity(*this, m_ClientHandle); + m_TimeLastTeleportPacket = cWorld::GetTime(); + } + else + { + // Relative move sucks balls! It's always wrong wtf! + if (m_bDirtyOrientation) + { + m_World->BroadcastEntRelMoveLook(*this, (char)(DiffX * 32), (char)(DiffY * 32), (char)(DiffZ * 32), m_ClientHandle); + m_bDirtyOrientation = false; + } + else + { + m_World->BroadcastEntRelMove(*this, (char)(DiffX * 32), (char)(DiffY * 32), (char)(DiffZ * 32), 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 + { + m_World->CollectPickupsByPlayer(this); + + //Handle Health: + m_FoodTickTimer++; + if(m_FoodTickTimer >= 80) + { + m_FoodTickTimer = 0; + + if(m_FoodLevel >= 17) + { + Heal(1); + }else if(m_FoodLevel == 0) + { + TakeDamage(1, NULL); + } + } + + // TODO: Increase Exhaustion level http://www.minecraftwiki.net/wiki/Hunger#Exhaustion_level_increase + if (m_FoodExhaustionLevel >= 4.f) + { + m_FoodExhaustionLevel -= 4.f; + + if (m_FoodSaturationLevel >= 1.f) + { + m_FoodSaturationLevel--; + } + else + { + m_FoodLevel = MAX(m_FoodLevel -1, 0); + } + + SendHealth(); + } + } + + cTimer t1; + // Send Player List (Once per m_LastPlayerListTime/1000 ms) + if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime()) + { + m_World->SendPlayerList(this); + m_LastPlayerListTime = t1.GetNowTime(); + } +} + + + + + +void cPlayer::SetTouchGround(bool a_bTouchGround) +{ + m_bTouchGround = a_bTouchGround; + + if (!m_bTouchGround) + { + cWorld* World = GetWorld(); + char BlockID = World->GetBlock( float2int(m_Pos.x), float2int(m_Pos.y), float2int(m_Pos.z) ); + if( BlockID != E_BLOCK_AIR ) + { + // LOGD("TouchGround set to true by server"); + m_bTouchGround = true; + } + if( BlockID == E_BLOCK_WATER || BlockID == E_BLOCK_STATIONARY_WATER || BlockID == E_BLOCK_LADDER || BlockID == E_BLOCK_TORCH ) + { + // LOGD("Water / Ladder / Torch"); + m_LastGroundHeight = (float)m_Pos.y; + } + } + + if (m_bTouchGround) + { + float Dist = (float)(m_LastGroundHeight - m_Pos.y); + 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 < GetMaxHealth() ) + { + m_Health = (short) MIN(a_Health + m_Health, GetMaxHealth()); + + + SendHealth(); + } +} + + + + + +bool cPlayer::Feed(short a_Food, float a_Saturation) +{ + if (m_FoodLevel >= GetMaxFoodLevel()) + { + return false; + } + + m_FoodLevel = MIN(a_Food + m_FoodLevel, GetMaxFoodLevel()); + m_FoodSaturationLevel = MIN(m_FoodSaturationLevel + a_Saturation, GetMaxFoodSaturationLevel()); + + SendHealth(); + return true; +} + + + + + +void cPlayer::SendHealth() +{ + if (m_ClientHandle != NULL) + { + m_ClientHandle->SendHealth(); + } +} + + + + + +void cPlayer::TakeDamage( int a_Damage, cEntity* a_Instigator ) +{ + if (m_GameMode != eGameMode_Creative) + { + cPawn::TakeDamage( a_Damage, a_Instigator ); + + AddFoodExhaustion(0.3f); + + SendHealth(); + } +} + + + + + +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(); + cItems Pickups; + for (unsigned int i = 1; i < m_Inventory.c_NumSlots; ++i) + { + if( !Items[i].IsEmpty() ) + { + Pickups.push_back(Items[i]); + } + Items[i].Empty(); + } + m_World->SpawnItemPickups(Pickups, m_Pos.x, m_Pos.y, m_Pos.z, 10); + SaveToDisk(); // Save it, yeah the world is a tough place ! +} + + + + + +void cPlayer::Respawn() +{ + m_Health = GetMaxHealth(); + + m_ClientHandle->SendRespawn(); + + // Set non Burning + SetMetaData(NORMAL); + + TeleportTo(GetWorld()->GetSpawnX(), GetWorld()->GetSpawnY(), GetWorld()->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(m_CurrentWindow ? (char)m_CurrentWindow->GetWindowType() : 0); + a_Window->OpenedByPlayer(*this); + m_CurrentWindow = a_Window; +} + + + + + +void cPlayer::CloseWindow(char a_WindowType) +{ + if (m_CurrentWindow == m_InventoryWindow) + { + // The inventory window must not be closed and must not be even sent a close packet + return; + } + + if (m_CurrentWindow != NULL) + { + // TODO: This code should be in cChestWindow instead + if ((a_WindowType == 1) && (m_CurrentWindow->GetWindowType() == cWindow::Chest)) + { + int x, y, z; + m_CurrentWindow->GetOwner()->GetBlockPos(x, y, z); + m_World->BroadcastBlockAction(x, y, z, 1, 0, E_BLOCK_CHEST); + } + + m_CurrentWindow->ClosedByPlayer(*this); + } + m_CurrentWindow = m_InventoryWindow; +} + + + + + +void cPlayer::SetLastBlockActionTime() +{ + if (m_World != NULL) + { + m_LastBlockActionTime = m_World->GetTime(); + } +} + + + + + +void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt ) +{ + m_LastBlockActionCnt = a_LastBlockActionCnt; +} + + + + + +void cPlayer::SetGameMode(eGameMode a_GameMode) +{ + if ((a_GameMode >= 2) || (a_GameMode < 0)) + { + LOGWARNING("%s: Setting invalid gamemode: %d", GetName().c_str(), a_GameMode); + return; + } + + if (m_GameMode == a_GameMode) + { + // Gamemode already set + return; + } + + m_GameMode = a_GameMode; + m_ClientHandle->SendGameMode(a_GameMode); +} + + + + + +void cPlayer::LoginSetGameMode( eGameMode a_GameMode ) +{ + m_GameMode = a_GameMode; +} + + + + + +void cPlayer::SetIP(const AString & a_IP) +{ + m_IP = a_IP; +} + + + + + +void cPlayer::SendMessage(const AString & a_Message) +{ + m_ClientHandle->SendChat(a_Message); +} + + + + + +void cPlayer::TeleportTo(const double & a_PosX, const double & a_PosY, const double & a_PosZ) +{ + SetPosition( a_PosX, a_PosY, a_PosZ ); + + m_World->BroadcastTeleportEntity(*this, GetClientHandle()); + m_ClientHandle->SendPlayerMoveLook(); +} + + + + + +void cPlayer::MoveTo( const Vector3d & a_NewPos ) +{ + // TODO: should do some checks to see if player is not moving through terrain + // TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too + + SetPosition( a_NewPos ); + SetStance(a_NewPos.y + 1.62); +} + + + + + +void cPlayer::SetVisible(bool a_bVisible) +{ + if (a_bVisible && !m_bVisible) // Make visible + { + m_bVisible = true; + m_World->BroadcastSpawn(*this); + } + if (!a_bVisible && m_bVisible) + { + m_bVisible = false; + m_World->BroadcastDestroyEntity(*this, m_ClientHandle); // Destroy on all clients + } +} + + + + + +void cPlayer::AddToGroup( const char* a_GroupName ) +{ + cGroup* Group = cRoot::Get()->GetGroupManager()->GetGroup( a_GroupName ); + m_Groups.push_back( Group ); + LOGD("Added %s to group %s", m_PlayerName.c_str(), a_GroupName ); + ResolveGroups(); + ResolvePermissions(); +} + + + + + +bool cPlayer::CanUseCommand( const char* a_Command ) +{ + for( GroupList::iterator itr = m_Groups.begin(); itr != m_Groups.end(); ++itr ) + { + if( (*itr)->HasCommand( a_Command ) ) return true; + } + return false; +} + + + + + +bool cPlayer::HasPermission( const char* a_Permission ) +{ + AStringVector Split = StringSplit( a_Permission, "." ); + PermissionMap Possibilities = m_ResolvedPermissions; + // Now search the namespaces + while( Possibilities.begin() != Possibilities.end() ) + { + PermissionMap::iterator itr = Possibilities.begin(); + if( itr->second ) + { + AStringVector 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_ResolvedGroups.begin(); itr != m_ResolvedGroups.end(); ++itr ) + { + if( strcmp( a_Group, (*itr)->GetName().c_str() ) == 0 ) + return true; + } + return false; +} + + + + + +void cPlayer::ResolvePermissions() +{ + m_ResolvedPermissions.clear(); // Start with an empty map yo~ + + // Copy all player specific permissions into the resolved permissions map + for( PermissionMap::iterator itr = m_Permissions.begin(); itr != m_Permissions.end(); ++itr ) + { + m_ResolvedPermissions[ itr->first ] = itr->second; + } + + for( GroupList::iterator GroupItr = m_ResolvedGroups.begin(); GroupItr != m_ResolvedGroups.end(); ++GroupItr ) + { + const cGroup::PermissionMap & Permissions = (*GroupItr)->GetPermissions(); + for( cGroup::PermissionMap::const_iterator itr = Permissions.begin(); itr != Permissions.end(); ++itr ) + { + m_ResolvedPermissions[ itr->first ] = itr->second; + } + } +} + + + + + +void cPlayer::ResolveGroups() +{ + // Clear resolved groups first + m_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_Groups.begin(); GroupItr != m_Groups.end(); ++GroupItr ) + { + ToIterate.push_back( *GroupItr ); + } + while( ToIterate.begin() != ToIterate.end() ) + { + cGroup* CurrentGroup = *ToIterate.begin(); + if( AllGroups.find( CurrentGroup ) != AllGroups.end() ) + { + LOGWARNING("ERROR: Player \"%s\" is in the group multiple times (\"%s\"). Please fix your settings in users.ini!", + m_PlayerName.c_str(), CurrentGroup->GetName().c_str() + ); + } + else + { + AllGroups[ CurrentGroup ] = true; + m_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_PlayerName.c_str(), (*itr)->GetName().c_str() ); + continue; + } + ToIterate.push_back( *itr ); + } + } + ToIterate.erase( ToIterate.begin() ); + } +} + + + + + +AString cPlayer::GetColor(void) const +{ + if ( m_Color != '-' ) + { + return cChatColor::MakeColor( m_Color ); + } + + if ( m_Groups.size() < 1 ) + { + return cChatColor::White; + } + + return (*m_Groups.begin())->GetColor(); +} + + + + + +void cPlayer::TossItem( + bool a_bDraggingItem, + char a_Amount /* = 1 */, + short a_CreateType /* = 0 */, + short a_CreateHealth /* = 0 */ +) +{ + cItems Drops; + if (a_CreateType) + { + // Just create item without touching the inventory (used in creative mode) + Drops.push_back(cItem(a_CreateType, a_Amount, a_CreateHealth)); + } + else + { + // Drop an item from the inventory: + if (a_bDraggingItem) + { + cItem & Item = GetDraggingItem(); + if (!Item.IsEmpty()) + { + Drops.push_back(Item); + if (Item.m_ItemCount > a_Amount) + { + Item.m_ItemCount -= (char)a_Amount; + } + else + { + Item.Empty(); + } + } + } + else + { + // Else drop equipped item + cItem DroppedItem = GetInventory().GetEquippedItem(); + if (!DroppedItem.IsEmpty()) + { + DroppedItem.m_ItemCount = 1; + if (GetInventory().RemoveItem(DroppedItem)) + { + DroppedItem.m_ItemCount = 1; // RemoveItem decreases the count, so set it to 1 again + Drops.push_back(DroppedItem); + } + } + } + } + float vX = 0, vY = 0, vZ = 0; + EulerToVector(-GetRotation(), GetPitch(), vZ, vX, vY); + vY = -vY * 2 + 1.f; + m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY() + 1.6f, GetPosZ(), vX * 2, vY * 2, vZ * 2); +} + + + + + +bool cPlayer::MoveToWorld( const char* a_WorldName ) +{ + cWorld * World = cRoot::Get()->GetWorld( a_WorldName ); + if ( World ) + { + /* Remove all links to the old world */ + m_World->RemovePlayer( this ); + m_ClientHandle->RemoveFromAllChunks(); + m_World->RemoveEntityFromChunk(this, m_ChunkX, m_ChunkY, m_ChunkZ); + + /* Add player to all the necessary parts of the new world */ + SetWorld( World ); + GetWorld()->AddPlayer( this ); + MoveToCorrectChunk(true); + GetClientHandle()->StreamChunks(); + + return true; + } + + return false; +} + + + + + +void cPlayer::LoadPermissionsFromDisk() +{ + m_Groups.clear(); + m_Permissions.clear(); + + cIniFile IniFile("users.ini"); + if( IniFile.ReadFile() ) + { + std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", ""); + if( Groups.size() > 0 ) + { + AStringVector 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_PlayerName, "Color", "-")[0]; + } + else + { + LOGWARN("WARNING: Failed to read ini file users.ini"); + AddToGroup("Default"); + } + ResolvePermissions(); +} + + + + +bool cPlayer::LoadFromDisk() +{ + LoadPermissionsFromDisk(); + + // Log player permissions, cause it's what the cool kids do + LOGINFO("Player %s has permissions:", m_PlayerName.c_str() ); + for( PermissionMap::iterator itr = m_ResolvedPermissions.begin(); itr != m_ResolvedPermissions.end(); ++itr ) + { + if( itr->second ) LOGINFO("%s", itr->first.c_str() ); + } + + AString SourceFile; + Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() ); + + cFile f; + if (!f.Open(SourceFile, cFile::fmRead)) + { + return false; + } + + AString buffer; + if (f.ReadRestOfFile(buffer) != f.GetSize()) + { + LOGERROR("ERROR READING FROM FILE \"%s\"", SourceFile.c_str()); + return false; + } + f.Close(); + + Json::Value root; + Json::Reader reader; + if (!reader.parse(buffer, root, false)) + { + LOGERROR("ERROR WHILE PARSING JSON FROM FILE %s", SourceFile.c_str()); + } + + Json::Value & JSON_PlayerPosition = root["position"]; + if (JSON_PlayerPosition.size() == 3) + { + m_Pos.x = JSON_PlayerPosition[(unsigned int)0].asDouble(); + m_Pos.y = JSON_PlayerPosition[(unsigned int)1].asDouble(); + m_Pos.z = JSON_PlayerPosition[(unsigned int)2].asDouble(); + } + + Json::Value & JSON_PlayerRotation = root["rotation"]; + if (JSON_PlayerRotation.size() == 3) + { + m_Rot.x = (float)JSON_PlayerRotation[(unsigned int)0].asDouble(); + m_Rot.y = (float)JSON_PlayerRotation[(unsigned int)1].asDouble(); + m_Rot.z = (float)JSON_PlayerRotation[(unsigned int)2].asDouble(); + } + + m_Health = (short)root.get("health", 0 ).asInt(); + m_FoodLevel = (short)root.get("food", m_MaxFoodLevel ).asInt(); + m_FoodSaturationLevel = (float)root.get("foodSaturation", m_MaxFoodSaturationLevel ).asDouble(); + + m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt(); + + m_Inventory.LoadFromJson(root["inventory"]); + + m_LoadedWorldName = root.get("world", "world").asString(); + + LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"", + m_PlayerName.c_str(), m_Pos.x, m_Pos.y, m_Pos.z, m_LoadedWorldName.c_str() + ); + + return true; +} + + + + + +bool cPlayer::SaveToDisk() +{ + cMakeDir::MakeDir("players"); + + // create the JSON data + Json::Value JSON_PlayerPosition; + JSON_PlayerPosition.append( Json::Value( m_Pos.x ) ); + JSON_PlayerPosition.append( Json::Value( m_Pos.y ) ); + JSON_PlayerPosition.append( Json::Value( m_Pos.z ) ); + + Json::Value JSON_PlayerRotation; + JSON_PlayerRotation.append( Json::Value( m_Rot.x ) ); + JSON_PlayerRotation.append( Json::Value( m_Rot.y ) ); + JSON_PlayerRotation.append( Json::Value( m_Rot.z ) ); + + Json::Value JSON_Inventory; + m_Inventory.SaveToJson( JSON_Inventory ); + + Json::Value root; + root["position"] = JSON_PlayerPosition; + root["rotation"] = JSON_PlayerRotation; + root["inventory"] = JSON_Inventory; + root["health"] = m_Health; + root["food"] = m_FoodLevel; + root["foodSaturation"] = m_FoodSaturationLevel; + root["world"] = GetWorld()->GetName(); + + if (m_GameMode == GetWorld()->GetGameMode()) + { + root["gamemode"] = (int) eGameMode_NotSet; + } + else + { + root["gamemode"] = (int) m_GameMode; + } + + Json::StyledWriter writer; + std::string JsonData = writer.write( root ); + + AString SourceFile; + Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() ); + + cFile f; + if (!f.Open(SourceFile, cFile::fmWrite)) + { + LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", m_PlayerName.c_str(), SourceFile.c_str()); + return false; + } + if (f.Write(JsonData.c_str(), JsonData.size()) != (int)JsonData.size()) + { + LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str()); + return false; + } + return true; +} + + + + + +cPlayer::StringList cPlayer::GetResolvedPermissions() +{ + StringList Permissions; + + const PermissionMap& ResolvedPermissions = m_ResolvedPermissions; + for( PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr ) + { + if( itr->second ) Permissions.push_back( itr->first ); + } + + return Permissions; +} + + + + + +void cPlayer::UseEquippedItem() +{ + if(GetGameMode() != 1) //No damage in creative + { + if (GetInventory().GetEquippedItem().DamageItem()) + { + LOG("Player %s Broke ID: %i", GetClientHandle()->GetUsername().c_str(), GetInventory().GetEquippedItem().m_ItemID); + GetInventory().RemoveItem( GetInventory().GetEquippedItem()); + } + } +} + + + + |