Skip to content

Commit

Permalink
feat(skymp5-server): add id to timers (#1622)
Browse files Browse the repository at this point in the history
  • Loading branch information
barkinlove authored Sep 29, 2023
1 parent fd6790d commit 4dcacc7
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 60 deletions.
1 change: 1 addition & 0 deletions skymp5-server/cpp/server_guest_lib/ActiveMagicEffectsMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ActiveMagicEffectsMap
public:
struct Entry
{
uint32_t timerId = -1;
espm::Effects::Effect data;
std::chrono::system_clock::time_point endTime;
};
Expand Down
22 changes: 11 additions & 11 deletions skymp5-server/cpp/server_guest_lib/MpActor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -835,10 +835,8 @@ void MpActor::ApplyMagicEffect(espm::Effects::Effect& effect, bool hasSweetpie,
}

if (isRate || isMult) {
if (hasSweetpie) {
if (!CanActorValueBeRestored(av)) {
return;
}
if (hasSweetpie && !CanActorValueBeRestored(av)) {
return;
}
MpChangeForm changeForm = GetChangeForm();
BaseActorValues baseValues =
Expand Down Expand Up @@ -868,11 +866,18 @@ void MpActor::ApplyMagicEffect(espm::Effects::Effect& effect, bool hasSweetpie,
duration =
Viet::TimeUtils::To<std::chrono::milliseconds>(effect.duration);
}
ActiveMagicEffectsMap::Entry entry{ effect, endTime };
uint32_t timerId;
worldState->SetEffectTimer(duration, &timerId)
.Then([formId, actorValue = av, worldState](Viet::Void) {
auto& actor = worldState->GetFormAt<MpActor>(formId);
actor.RemoveMagicEffect(actorValue);
});

ActiveMagicEffectsMap::Entry entry{ timerId, effect, endTime };
if (activeEffects.Has(av)) {
const ActiveMagicEffectsMap::Entry& entry =
activeEffects.Get(av).value().get();
worldState->RemoveEffectTimer(entry.endTime);
worldState->RemoveEffectTimer(entry.timerId);
}
EditChangeForm([av, pEntry = &entry](MpChangeForm& changeForm) {
changeForm.activeMagicEffects.Add(av, *pEntry);
Expand All @@ -898,11 +903,6 @@ void MpActor::ApplyMagicEffect(espm::Effects::Effect& effect, bool hasSweetpie,
mult, baseValue * mult);
SetActorValue(av, baseValue * mult);
}
worldState->SetEffectTimer(std::cref(endTime))
.Then([formId, actorValue = av, worldState](Viet::Void) {
auto& actor = worldState->GetFormAt<MpActor>(formId);
actor.RemoveMagicEffect(actorValue);
});
}
}

Expand Down
22 changes: 7 additions & 15 deletions skymp5-server/cpp/server_guest_lib/WorldState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,18 +219,6 @@ void WorldState::RequestSave(MpObjectReference& ref)
}
}

Viet::Promise<Viet::Void> WorldState::SetTimer(
std::reference_wrapper<const std::chrono::system_clock::time_point> wrapper)
{
return timerRegular.SetTimer(wrapper.get());
}

Viet::Promise<Viet::Void> WorldState::SetEffectTimer(
std::reference_wrapper<const std::chrono::system_clock::time_point> wrapper)
{
return timerEffects.SetTimer(wrapper.get());
}

const std::shared_ptr<MpForm>& WorldState::LookupFormById(uint32_t formId)
{
static const std::shared_ptr<MpForm> kNullForm;
Expand Down Expand Up @@ -810,10 +798,14 @@ void WorldState::SetNpcSettings(
npcSettings = settings;
}

bool WorldState::RemoveEffectTimer(
const std::chrono::system_clock::time_point& endTime)
bool WorldState::RemoveTimer(uint32_t timerId)
{
return timerRegular.RemoveTimer(timerId);
}

bool WorldState::RemoveEffectTimer(uint32_t timerId)
{
return timerEffects.RemoveTimer(endTime);
return timerEffects.RemoveTimer(timerId);
}

void WorldState::SetForbiddenRelootTypes(const std::set<std::string>& types)
Expand Down
13 changes: 8 additions & 5 deletions skymp5-server/cpp/server_guest_lib/WorldState.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,17 @@ class WorldState
bool HasEspmFile(std::string_view filename) const noexcept;

template <typename T>
Viet::Promise<Viet::Void> SetTimer(T&& duration)
Viet::Promise<Viet::Void> SetTimer(T&& duration,
uint32_t* outTimerId = nullptr)
{
return timerRegular.SetTimer(std::forward<T>(duration));
return timerRegular.SetTimer(std::forward<T>(duration), outTimerId);
}

template <typename T>
Viet::Promise<Viet::Void> SetEffectTimer(T&& duration)
Viet::Promise<Viet::Void> SetEffectTimer(T&& duration,
uint32_t* outTimerId = nullptr)
{
return timerEffects.SetTimer(std::forward<T>(duration));
return timerEffects.SetTimer(std::forward<T>(duration), outTimerId);
}

template <typename T>
Expand All @@ -97,13 +99,14 @@ class WorldState
});
}

bool RemoveTimer(uint32_t timerId);
Viet::Promise<Viet::Void> SetTimer(
std::reference_wrapper<const std::chrono::system_clock::time_point>
wrapper);
Viet::Promise<Viet::Void> SetEffectTimer(
std::reference_wrapper<const std::chrono::system_clock::time_point>
wrapper);
bool RemoveEffectTimer(const std::chrono::system_clock::time_point& endTime);
bool RemoveEffectTimer(uint32_t timerId);

const std::shared_ptr<MpForm>& LookupFormById(uint32_t formId);

Expand Down
2 changes: 2 additions & 0 deletions viet/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
include(${CMAKE_SOURCE_DIR}/cmake/apply_default_settings.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/link_vcpkg_dependencies.cmake)

file(GLOB_RECURSE viet_sources "${CMAKE_CURRENT_SOURCE_DIR}/src/*" "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
add_library(viet STATIC ${viet_sources})
target_include_directories(viet PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_include_directories(viet PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
apply_default_settings(TARGETS viet)
link_vcpkg_dependencies(TARGETS viet)
15 changes: 7 additions & 8 deletions viet/include/Timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,29 @@
#include <chrono>

namespace Viet {

class Timer
{
public:
Timer();

template <typename T>
Viet::Promise<Viet::Void> SetTimer(T&& duration)
Promise<Void> SetTimer(T&& duration, uint32_t* outTimerId)
{
auto endTime = std::chrono::system_clock::now() + duration;
return Set(endTime);
return Set(endTime, outTimerId);
};

Viet::Promise<Viet::Void> SetTimer(
const std::chrono::system_clock::time_point& endTime);
[[maybe_unused]] bool RemoveTimer(
const std::chrono::system_clock::time_point& endTime);
[[maybe_unused]] bool RemoveTimer(uint32_t timerId);
void TickTimers();

private:
Viet::Promise<Viet::Void> Set(
const std::chrono::system_clock::time_point& endTime);
Promise<Void> Set(const std::chrono::system_clock::time_point& endTime,
uint32_t* outTimerId);

private:
struct Impl;
std::shared_ptr<Impl> pImpl;
};

}
60 changes: 39 additions & 21 deletions viet/src/Timer.cpp
Original file line number Diff line number Diff line change
@@ -1,70 +1,86 @@
#include "Timer.h"
#include <MakeID.h-1.0.2>
#include <algorithm>
#include <chrono>
#include <deque>
#include <limits>
#include <memory>
#include <spdlog/spdlog.h>
#include <utility>

namespace Viet {

namespace {
struct TimerEntry
{
Viet::Promise<Viet::Void> promise;
uint32_t id;
Promise<Void> promise;
std::chrono::system_clock::time_point finish;
};
}

struct Viet::Timer::Impl
struct Timer::Impl
{
std::deque<TimerEntry> timers;
const std::unique_ptr<MakeID> idGenerator =
std::make_unique<MakeID>(std::numeric_limits<uint32_t>::max());

void DestroyID(const TimerEntry& entry);
};

Viet::Timer::Timer()
void Timer::Impl::DestroyID(const TimerEntry& entry)
{
pImpl = std::make_shared<Impl>();
idGenerator->DestroyID(entry.id);
}

Viet::Promise<Viet::Void> Viet::Timer::SetTimer(
const std::chrono::system_clock::time_point& endTime)
Timer::Timer()
{
return Set(endTime);
pImpl = std::make_shared<Impl>();
}

void Viet::Timer::TickTimers()
void Timer::TickTimers()
{
auto now = std::chrono::system_clock::now();

auto& timers = pImpl->timers;
while (!timers.empty() && now >= timers.front().finish) {
auto front = std::move(timers.front());
timers.pop_front();
front.promise.Resolve(Viet::Void());
front.promise.Resolve(Void());
pImpl->DestroyID(front);
}
}

bool Viet::Timer::RemoveTimer(
const std::chrono::system_clock::time_point& endTime)
bool Timer::RemoveTimer(const uint32_t timerId)
{
auto& timers = pImpl->timers;
auto it =
std::lower_bound(timers.begin(), timers.end(), endTime,
[](const TimerEntry& entry,
const std::chrono::system_clock::time_point& target) {
return entry.finish < target;
});
auto it = std::find_if(
timers.begin(), timers.end(),
[timerId](const TimerEntry& entry) { return entry.id == timerId; });
if (it != timers.end()) {
timers.erase(it);
return true;
}
return false;
}

Viet::Promise<Viet::Void> Viet::Timer::Set(
const std::chrono::system_clock::time_point& endTime)
Promise<Void> Timer::Set(const std::chrono::system_clock::time_point& endTime,
uint32_t* outTimerId)
{
Viet::Promise<Viet::Void> promise;
Promise<Void> promise;
bool sortRequired =
!pImpl->timers.empty() && endTime > pImpl->timers.front().finish;

pImpl->timers.push_front({ promise, endTime });
uint32_t timerId;
bool created = pImpl->idGenerator->CreateID(timerId);
if (!created) {
spdlog::critical("MakeID was not able to Create Id for a timer");
std::terminate();
}
pImpl->timers.push_front({ timerId, promise, endTime });
if (outTimerId) {
*outTimerId = timerId;
}

if (sortRequired) {
std::sort(pImpl->timers.begin(), pImpl->timers.end(),
Expand All @@ -74,3 +90,5 @@ Viet::Promise<Viet::Void> Viet::Timer::Set(
}
return promise;
}

}

0 comments on commit 4dcacc7

Please sign in to comment.