diff options
Diffstat (limited to 'src/Entities')
-rw-r--r-- | src/Entities/ArrowEntity.cpp | 24 | ||||
-rw-r--r-- | src/Entities/Pickup.cpp | 2 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 216 | ||||
-rw-r--r-- | src/Entities/Player.h | 43 |
4 files changed, 177 insertions, 108 deletions
diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 47a0876fc..d59088e72 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -106,14 +106,7 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); // Broadcast successful hit sound - m_World->BroadcastSoundEffect( - "random.successful_hit", - (int)std::floor(GetPosX() * 8.0), - (int)std::floor(GetPosY() * 8.0), - (int)std::floor(GetPosZ() * 8.0), - 0.5f, - 0.75f + ((float)((GetUniqueID() * 23) % 32)) / 64.0f - ); + GetWorld()->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); Destroy(); } @@ -136,21 +129,10 @@ void cArrowEntity::CollectedBy(cPlayer * a_Dest) return; } } - - // TODO: BroadcastCollectPickup needs a cPickup, which we don't have - // m_World->BroadcastCollectPickup(*this, *a_Dest); + GetWorld()->BroadcastCollectEntity(*this, *a_Dest); + GetWorld()->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); m_bIsCollected = true; - - cFastRandom Random; - m_World->BroadcastSoundEffect( - "random.pop", - (int)std::floor(GetPosX() * 8.0), - (int)std::floor(GetPosY() * 8), - (int)std::floor(GetPosZ() * 8), - 0.2F, - ((Random.NextFloat(1.0F) - Random.NextFloat(1.0F)) * 0.7F + 1.0F) * 2.0F - ); } } diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index 10b6bbd5c..24fa591da 100644 --- a/src/Entities/Pickup.cpp +++ b/src/Entities/Pickup.cpp @@ -224,7 +224,7 @@ bool cPickup::CollectedBy(cPlayer * a_Dest) } m_Item.m_ItemCount -= NumAdded; - m_World->BroadcastCollectPickup(*this, *a_Dest); + m_World->BroadcastCollectEntity(*this, *a_Dest); // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) m_World->BroadcastSoundEffect("random.pop",(int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); if (m_Item.m_ItemCount <= 0) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index dbb8cd26c..944ed643e 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -34,52 +34,48 @@ -cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) - : super(etPlayer, 0.6, 1.8) - , m_bVisible(true) - , m_FoodLevel(MAX_FOOD_LEVEL) - , m_FoodSaturationLevel(5.0) - , m_FoodTickTimer(0) - , m_FoodExhaustionLevel(0.0) - , m_FoodPoisonedTicksRemaining(0) - , m_LastJumpHeight(0) - , m_LastGroundHeight(0) - , m_bTouchGround(false) - , m_Stance(0.0) - , m_Inventory(*this) - , m_EnderChestContents(9, 3) - , m_CurrentWindow(NULL) - , m_InventoryWindow(NULL) - , m_Color('-') - , m_GameMode(eGameMode_NotSet) - , m_IP("") - , m_ClientHandle(a_Client) - , m_NormalMaxSpeed(1.0) - , m_SprintingMaxSpeed(1.3) - , m_FlyingMaxSpeed(1.0) - , m_IsCrouched(false) - , m_IsSprinting(false) - , m_IsFlying(false) - , m_IsSwimming(false) - , m_IsSubmerged(false) - , m_IsFishing(false) - , m_CanFly(false) - , m_EatingFinishTick(-1) - , m_LifetimeTotalXp(0) - , m_CurrentXp(0) - , m_bDirtyExperience(false) - , m_IsChargingBow(false) - , m_BowCharge(0) - , m_FloaterID(-1) - , m_Team(NULL) - , m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL) - , m_bIsTeleporting(false) -{ - LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", - a_PlayerName.c_str(), a_Client->GetIPString().c_str(), - this, GetUniqueID() - ); - +cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : + super(etPlayer, 0.6, 1.8), + m_bVisible(true), + m_FoodLevel(MAX_FOOD_LEVEL), + m_FoodSaturationLevel(5.0), + m_FoodTickTimer(0), + m_FoodExhaustionLevel(0.0), + m_FoodPoisonedTicksRemaining(0), + m_LastJumpHeight(0), + m_LastGroundHeight(0), + m_bTouchGround(false), + m_Stance(0.0), + m_Inventory(*this), + m_EnderChestContents(9, 3), + m_CurrentWindow(NULL), + m_InventoryWindow(NULL), + m_Color('-'), + m_GameMode(eGameMode_NotSet), + m_IP(""), + m_ClientHandle(a_Client), + m_NormalMaxSpeed(1.0), + m_SprintingMaxSpeed(1.3), + m_FlyingMaxSpeed(1.0), + m_IsCrouched(false), + m_IsSprinting(false), + m_IsFlying(false), + m_IsSwimming(false), + m_IsSubmerged(false), + m_IsFishing(false), + m_CanFly(false), + m_EatingFinishTick(-1), + m_LifetimeTotalXp(0), + m_CurrentXp(0), + m_bDirtyExperience(false), + m_IsChargingBow(false), + m_BowCharge(0), + m_FloaterID(-1), + m_Team(NULL), + m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL), + m_bIsTeleporting(false), + m_UUID((a_Client != NULL) ? a_Client->GetUUID() : "") +{ m_InventoryWindow = new cInventoryWindow(*this); m_CurrentWindow = m_InventoryWindow; m_InventoryWindow->OpenedByPlayer(*this); @@ -1690,53 +1686,98 @@ void cPlayer::LoadPermissionsFromDisk() -bool cPlayer::LoadFromDisk() + +bool cPlayer::LoadFromDisk(void) { LoadPermissionsFromDisk(); - AString SourceFile; - Printf(SourceFile, "players/%s.json", GetName().c_str() ); + // Load from the UUID file: + if (LoadFromFile(GetUUIDFileName(m_UUID))) + { + return true; + } + + // Load from the offline UUID file, if allowed: + AString OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName()); + if (cRoot::Get()->GetServer()->ShouldLoadOfflinePlayerData()) + { + if (LoadFromFile(GetUUIDFileName(OfflineUUID))) + { + return true; + } + } + + // Load from the old-style name-based file, if allowed: + if (cRoot::Get()->GetServer()->ShouldLoadNamedPlayerData()) + { + AString OldStyleFileName = Printf("players/%s.json", GetName().c_str()); + if (LoadFromFile(OldStyleFileName)) + { + // Save in new format and remove the old file + if (SaveToDisk()) + { + cFile::Delete(OldStyleFileName); + } + return true; + } + } + + // None of the files loaded successfully + LOG("Player data file not found for %s (%s, offline %s), will be reset to defaults.", + GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str() + ); + return false; +} + + + + +bool cPlayer::LoadFromFile(const AString & a_FileName) +{ + // Load the data from the file: cFile f; - if (!f.Open(SourceFile, cFile::fmRead)) + if (!f.Open(a_FileName, cFile::fmRead)) { // This is a new player whom we haven't seen yet, bail out, let them have the defaults return false; } - AString buffer; if (f.ReadRestOfFile(buffer) != f.GetSize()) { - LOGWARNING("Cannot read player data from file \"%s\"", SourceFile.c_str()); + LOGWARNING("Cannot read player data from file \"%s\"", a_FileName.c_str()); return false; } - f.Close(); //cool kids play nice + f.Close(); + // Parse the JSON format: Json::Value root; Json::Reader reader; if (!reader.parse(buffer, root, false)) { - LOGWARNING("Cannot parse player data in file \"%s\", player will be reset", SourceFile.c_str()); + LOGWARNING("Cannot parse player data in file \"%s\"", a_FileName.c_str()); + return false; } + // Load the player data: Json::Value & JSON_PlayerPosition = root["position"]; if (JSON_PlayerPosition.size() == 3) { - SetPosX(JSON_PlayerPosition[(unsigned int)0].asDouble()); - SetPosY(JSON_PlayerPosition[(unsigned int)1].asDouble()); - SetPosZ(JSON_PlayerPosition[(unsigned int)2].asDouble()); + SetPosX(JSON_PlayerPosition[(unsigned)0].asDouble()); + SetPosY(JSON_PlayerPosition[(unsigned)1].asDouble()); + SetPosZ(JSON_PlayerPosition[(unsigned)2].asDouble()); m_LastPos = GetPosition(); } Json::Value & JSON_PlayerRotation = root["rotation"]; if (JSON_PlayerRotation.size() == 3) { - SetYaw ((float)JSON_PlayerRotation[(unsigned int)0].asDouble()); - SetPitch ((float)JSON_PlayerRotation[(unsigned int)1].asDouble()); - SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble()); + SetYaw ((float)JSON_PlayerRotation[(unsigned)0].asDouble()); + SetPitch ((float)JSON_PlayerRotation[(unsigned)1].asDouble()); + SetRoll ((float)JSON_PlayerRotation[(unsigned)2].asDouble()); } - m_Health = root.get("health", 0).asInt(); + m_Health = root.get("health", 0).asInt(); m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt(); m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt(); m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); @@ -1763,8 +1804,8 @@ bool cPlayer::LoadFromDisk() cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); StatSerializer.Load(); - LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"", - GetName().c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() + LOGD("Player \"%s\" was read from file \"%s\", spawning at {%.2f, %.2f, %.2f} in world \"%s\"", + GetName().c_str(), a_FileName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() ); return true; @@ -1777,6 +1818,7 @@ bool cPlayer::LoadFromDisk() bool cPlayer::SaveToDisk() { cFile::CreateFolder(FILE_IO_PREFIX + AString("players")); + cFile::CreateFolder(FILE_IO_PREFIX + AString("players/") + m_UUID.substr(0, 2)); // create the JSON data Json::Value JSON_PlayerPosition; @@ -1808,33 +1850,45 @@ bool cPlayer::SaveToDisk() root["foodSaturation"] = m_FoodSaturationLevel; root["foodTickTimer"] = m_FoodTickTimer; root["foodExhaustion"] = m_FoodExhaustionLevel; - root["world"] = GetWorld()->GetName(); root["isflying"] = IsFlying(); - - if (m_GameMode == GetWorld()->GetGameMode()) + root["lastknownname"] = GetName(); + if (m_World != NULL) { - root["gamemode"] = (int) eGameMode_NotSet; + root["world"] = m_World->GetName(); + if (m_GameMode == m_World->GetGameMode()) + { + root["gamemode"] = (int) eGameMode_NotSet; + } + else + { + root["gamemode"] = (int) m_GameMode; + } } else { - root["gamemode"] = (int) m_GameMode; + // This happens if the player is saved to new format after loading from the old format + root["world"] = m_LoadedWorldName; + root["gamemode"] = (int) eGameMode_NotSet; } Json::StyledWriter writer; std::string JsonData = writer.write(root); - AString SourceFile; - Printf(SourceFile, "players/%s.json", GetName().c_str() ); + AString SourceFile = GetUUIDFileName(m_UUID); cFile f; if (!f.Open(SourceFile, cFile::fmWrite)) { - LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", GetName().c_str(), SourceFile.c_str()); + LOGWARNING("Error writing player \"%s\" to file \"%s\" - cannot open file. Player will lose their progress.", + GetName().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()); + LOGWARNING("Error writing player \"%s\" to file \"%s\" - cannot save data. Player will lose their progress. ", + GetName().c_str(), SourceFile.c_str() + ); return false; } @@ -1843,7 +1897,7 @@ bool cPlayer::SaveToDisk() cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); if (!StatSerializer.Save()) { - LOGERROR("Could not save stats for player %s", GetName().c_str()); + LOGWARNING("Could not save stats for player %s", GetName().c_str()); return false; } @@ -2156,3 +2210,19 @@ void cPlayer::Detach() + +AString cPlayer::GetUUIDFileName(const AString & a_UUID) +{ + ASSERT(a_UUID.size() == 36); + + AString res("players/"); + res.append(a_UUID, 0, 2); + res.push_back('/'); + res.append(a_UUID, 2, AString::npos); + res.append(".json"); + return res; +} + + + + diff --git a/src/Entities/Player.h b/src/Entities/Player.h index f247ac2f9..8f9b46e0f 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -41,6 +41,7 @@ public: cPlayer(cClientHandle * a_Client, const AString & a_PlayerName); + virtual ~cPlayer(); virtual void SpawnOn(cClientHandle & a_Client) override; @@ -337,7 +338,15 @@ public: bool MoveToWorld(const char * a_WorldName); // tolua_export bool SaveToDisk(void); + + /** Loads the player data from the disk file. + Returns true on success, false on failure. */ bool LoadFromDisk(void); + + /** Loads the player data from the specified file. + Returns true on success, false on failure. */ + bool LoadFromFile(const AString & a_FileName); + void LoadPermissionsFromDisk(void); // tolua_export const AString & GetLoadedWorldName() { return m_LoadedWorldName; } @@ -519,6 +528,24 @@ protected: cStatManager m_Stats; + /** Flag representing whether the player is currently in a bed + Set by a right click on unoccupied bed, unset by a time fast forward or teleport */ + bool m_bIsInBed; + + /** How long till the player's inventory will be saved + Default save interval is #defined in PLAYER_INVENTORY_SAVE_INTERVAL */ + unsigned int m_TicksUntilNextSave; + + /** Flag used by food handling system to determine whether a teleport has just happened + Will not apply food penalties if found to be true; will set to false after processing + */ + bool m_bIsTeleporting; + + /** The UUID of the player, as read from the ClientHandle. + If no ClientHandle is given, the UUID is initialized to empty. */ + AString m_UUID; + + /** Sets the speed and sends it to the client, so that they are forced to move so. */ virtual void DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) override; @@ -545,19 +572,9 @@ protected: /** Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) */ void ApplyFoodExhaustionFromMovement(); - /** Flag representing whether the player is currently in a bed - Set by a right click on unoccupied bed, unset by a time fast forward or teleport */ - bool m_bIsInBed; - - /** How long till the player's inventory will be saved - Default save interval is #defined in PLAYER_INVENTORY_SAVE_INTERVAL */ - unsigned int m_TicksUntilNextSave; - - /** Flag used by food handling system to determine whether a teleport has just happened - Will not apply food penalties if found to be true; will set to false after processing - */ - bool m_bIsTeleporting; - + /** Returns the filename for the player data based on the UUID given. + This can be used both for online and offline UUIDs. */ + AString GetUUIDFileName(const AString & a_UUID); } ; // tolua_export |