diff --git a/src/ll/api/chrono/GameChrono.cpp b/src/ll/api/chrono/GameChrono.cpp index 22b0d9b425..e05d0f4a28 100644 --- a/src/ll/api/chrono/GameChrono.cpp +++ b/src/ll/api/chrono/GameChrono.cpp @@ -3,7 +3,6 @@ #include "ll/api/service/GlobalService.h" #include "mc/server/ServerLevel.h" -#include "mc/world/level/Level.h" #include "mc/world/level/Tick.h" namespace ll::chrono::game_chrono { diff --git a/src/ll/api/chrono/TickSyncSleep.cpp b/src/ll/api/chrono/TickSyncSleep.cpp index 814fbf4382..797383f00b 100644 --- a/src/ll/api/chrono/TickSyncSleep.cpp +++ b/src/ll/api/chrono/TickSyncSleep.cpp @@ -2,14 +2,14 @@ #include "ll/api/memory/Hook.h" #include "mc/server/ServerLevel.h" -namespace ll::chrono { -namespace detail { -std::mutex listMutex; +namespace ll::chrono::detail { +std::mutex listMutex; +std::atomic_size_t tickListSize{}; +std::atomic_bool hooked{}; std::vector>, std::reference_wrapper>>> tickList; -} // namespace detail LL_AUTO_TYPED_INSTANCE_HOOK( TickSyncSleepInterrruptHook, HookPriority::Normal, @@ -17,9 +17,8 @@ LL_AUTO_TYPED_INSTANCE_HOOK( &ServerLevel::_subTick, void ) { - origin(); using namespace detail; - if (!tickList.empty()) { + if (tickListSize > 0) { std::lock_guard lock(listMutex); for (auto& e : tickList) { std::visit( @@ -45,7 +44,13 @@ LL_AUTO_TYPED_INSTANCE_HOOK( e ); } + } else { + unhook(); + hooked = false; } + origin(); } - -} // namespace ll::chrono +void notify() { + if (!hooked) TickSyncSleepInterrruptHook::hook(); +} +} // namespace ll::chrono::detail diff --git a/src/ll/api/chrono/TickSyncSleep.h b/src/ll/api/chrono/TickSyncSleep.h index 08f938a154..1a6ad3cff6 100644 --- a/src/ll/api/chrono/TickSyncSleep.h +++ b/src/ll/api/chrono/TickSyncSleep.h @@ -13,10 +13,12 @@ template class TickSyncSleep; namespace detail { LLETAPI std::mutex listMutex; -LLETAPI std::vector>, std::reference_wrapper>>> - tickList; + tickList; +LLAPI void notify(); }; // namespace detail template @@ -48,6 +50,8 @@ class TickSyncSleep { std::lock_guard lock(listMutex); id = tickList.size(); tickList.emplace_back(std::ref(*this)); + ++tickListSize; + notify(); } ~TickSyncSleep() { @@ -56,6 +60,7 @@ class TickSyncSleep { state = State::None; std::swap(tickList[id], tickList.back()); tickList.pop_back(); + --tickListSize; } void sleepFor(Clock::duration duration) { diff --git a/src/ll/api/schedule/Scheduler.h b/src/ll/api/schedule/Scheduler.h index ee097c8827..8fecd7c9e1 100644 --- a/src/ll/api/schedule/Scheduler.h +++ b/src/ll/api/schedule/Scheduler.h @@ -8,6 +8,7 @@ #include "ll/api/schedule/Task.h" #include "ll/api/thread/InterruptableSleep.h" #include "ll/api/thread/ThreadPool.h" +#include "ll/api/thread/TickSyncTaskPool.h" namespace ll::schedule { @@ -26,15 +27,17 @@ struct SleeperType { using Type = ll::chrono::TickSyncSleep; }; -template ::Type, class Pool = ll::thread::ThreadPool> +template ::Type> class Scheduler; using GameTickScheduler = Scheduler; using GameTimeScheduler = Scheduler; - using SystemTimeScheduler = Scheduler; -template +using GameSyncTickScheduler = Scheduler; +using GameSyncTimeScheduler = Scheduler; + +template class Scheduler { private: using TimePoint = typename Clock::time_point; @@ -46,7 +49,8 @@ class Scheduler { std::atomic done; std::mutex mutex; Sleeper sleeper; - Pool threads; + Pool workers; + std::thread manager; std::weak_ptr> addTask(TaskPtr t) { std::weak_ptr> res = t; @@ -80,7 +84,7 @@ class Scheduler { continue; } if (task->interval) { - threads.addTask([this, task] { + workers.addTask([this, task] { try { task->f(); } catch (...) { @@ -89,7 +93,7 @@ class Scheduler { addTask(task); }); } else { - threads.addTask([task] { + workers.addTask([task] { try { task->f(); } catch (...) { @@ -116,8 +120,8 @@ class Scheduler { Scheduler& operator=(Scheduler const&) = delete; Scheduler& operator=(Scheduler&&) noexcept = delete; - explicit Scheduler(int maxThreads = 1) : done(false), threads(std::max(1, maxThreads) + 1) { - threads.addTask([this] { + explicit Scheduler(int maxThreads = 1) : done(false), workers(std::max(1, maxThreads)) { + manager = std::thread([this] { while (!done) { if (tasks.empty()) { sleeper.sleep(); @@ -132,6 +136,7 @@ class Scheduler { ~Scheduler() { done = true; sleeper.interrupt(); + manager.join(); } template