mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
feat(stats): send UpdatePlayerStatistic to the player as live did
Live sent UpdatePlayerStatistic (1481) server -> client for every statistic the server counted (59,933 messages in the captures, none client -> server); DLU only counted them, so the passport stayed stale until the next login. CharacterComponent::UpdatePlayerStatistic now tells the player's client what it counts (not what a client reported), with the amount left out when it is 1, byte for byte as the live samples. MetersTraveled: whole meters now count (each position update's distance was cut to a whole number before, so short steps never counted) and go to the client once 25 have gathered (live's values were nearly all 25-33 while moving) and the rest, 0 included, when the player is taken down on leaving the world (live sent one more after TRANSFER_TO_WORLD). DistanceDriven goes out every 10 seconds of racing (inferred: live sent it every few hundred packets, about 1300 units at race speed). Check in game: open the passport's statistics page, walk around, collect a power-up, complete a mission; the numbers go up without relogging. Walk 25+ meters; Meters Traveled matches what the passport shows after relogging. Change worlds and relog: the meters were kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,9 @@
|
||||
#include "ZoneInstanceManager.h"
|
||||
#include "ClientPackets.h"
|
||||
#include "MessageType/Game.h"
|
||||
#include "PlayerMessages.h"
|
||||
#include <ctime>
|
||||
#include <cmath>
|
||||
#include <ranges>
|
||||
|
||||
CharacterComponent::CharacterComponent(Entity* parent, const int32_t componentID, Character* character, const SystemAddress& systemAddress) : Component(parent, componentID) {
|
||||
@@ -619,14 +621,52 @@ void CharacterComponent::TrackRaceCompleted(bool won) {
|
||||
|
||||
void CharacterComponent::TrackPositionUpdate(const NiPoint3& newPosition) {
|
||||
const auto distance = NiPoint3::Distance(newPosition, m_Parent->GetPosition());
|
||||
if (!std::isfinite(distance)) return;
|
||||
|
||||
// Whole meters count at once; the parts of a meter add up
|
||||
auto& remainder = m_IsRacing ? m_DrivenRemainder : m_MetersRemainder;
|
||||
remainder += distance;
|
||||
const auto meters = static_cast<uint64_t>(remainder);
|
||||
remainder -= static_cast<float>(meters);
|
||||
|
||||
if (m_IsRacing) {
|
||||
UpdatePlayerStatistic(DistanceDriven, static_cast<uint64_t>(distance));
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if (m_LastDrivenUpdate != std::chrono::steady_clock::time_point{}) m_DrivenSinceSend += std::chrono::duration<float>(now - m_LastDrivenUpdate).count();
|
||||
m_LastDrivenUpdate = now;
|
||||
if (meters > 0) UpdatePlayerStatistic(DistanceDriven, meters);
|
||||
m_UnsentDriven += meters;
|
||||
if (m_DrivenSinceSend >= DISTANCE_DRIVEN_INTERVAL) {
|
||||
SendPlayerStatistic(DistanceDriven, m_UnsentDriven);
|
||||
m_UnsentDriven = 0;
|
||||
m_DrivenSinceSend = 0.0f;
|
||||
}
|
||||
} else {
|
||||
UpdatePlayerStatistic(MetersTraveled, static_cast<uint64_t>(distance));
|
||||
if (meters > 0) UpdatePlayerStatistic(MetersTraveled, meters);
|
||||
m_UnsentMeters += meters;
|
||||
if (m_UnsentMeters >= METERS_TRAVELED_BATCH) {
|
||||
SendPlayerStatistic(MetersTraveled, m_UnsentMeters);
|
||||
m_UnsentMeters = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterComponent::FlushMovementStatistics() {
|
||||
if (m_UnsentDriven > 0) SendPlayerStatistic(DistanceDriven, m_UnsentDriven);
|
||||
SendPlayerStatistic(MetersTraveled, m_UnsentMeters);
|
||||
m_UnsentDriven = 0;
|
||||
m_UnsentMeters = 0;
|
||||
m_DrivenSinceSend = 0.0f;
|
||||
}
|
||||
|
||||
void CharacterComponent::SendPlayerStatistic(StatisticID updateID, uint64_t updateValue) const {
|
||||
if (m_SystemAddress == UNASSIGNED_SYSTEM_ADDRESS) return;
|
||||
GameMessages::UpdatePlayerStatistic statistic;
|
||||
statistic.target = m_Parent->GetObjectID();
|
||||
statistic.updateID = static_cast<int32_t>(updateID);
|
||||
statistic.updateValue = static_cast<int64_t>(updateValue);
|
||||
statistic.SendToClient(m_SystemAddress);
|
||||
}
|
||||
|
||||
void CharacterComponent::HandleZoneStatisticsUpdate(LWOMAPID zoneID, const std::u16string& name, int32_t value) {
|
||||
auto zoneStatistics = &GetZoneStatisticsForMap(zoneID);
|
||||
|
||||
@@ -730,6 +770,9 @@ void CharacterComponent::UpdatePlayerStatistic(StatisticID updateID, uint64_t up
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Live told the client at once; the meters go out in batches (TrackPositionUpdate)
|
||||
if (!fromClient && updateID != MetersTraveled && updateID != DistanceDriven) SendPlayerStatistic(updateID, updateValue);
|
||||
}
|
||||
|
||||
void CharacterComponent::InitializeStatisticsFromString(const std::string& statisticsString) {
|
||||
|
||||
Reference in New Issue
Block a user