/** * @file dthread.cpp * * Implementation of functions for updating game state from network commands. */ #include #include #include "nthread.h" #include "utils/sdl_cond.h" #include "utils/sdl_thread.h" namespace devilution { struct DThreadPkt { int pnum; _cmd_id cmd; std::unique_ptr data; uint32_t len; DThreadPkt(int pnum, _cmd_id(cmd), std::unique_ptr data, uint32_t len) : pnum(pnum) , cmd(cmd) , data(std::move(data)) , len(len) { } }; namespace { std::optional DthreadMutex; std::list InfoList; bool DthreadRunning; std::optional WorkToDo; /* rdata */ SdlThread Thread; void DthreadHandler() { std::lock_guard lock(*DthreadMutex); while (true) { while (!InfoList.empty()) { DThreadPkt pkt = std::move(InfoList.front()); InfoList.pop_front(); DthreadMutex->unlock(); multi_send_zero_packet(pkt.pnum, pkt.cmd, pkt.data.get(), pkt.len); DthreadMutex->lock(); } if (!DthreadRunning) return; WorkToDo->wait(*DthreadMutex); } } } // namespace void dthread_remove_player(uint8_t pnum) { std::lock_guard lock(*DthreadMutex); InfoList.remove_if([&](auto &pkt) { return pkt.pnum == pnum; }); } void dthread_send_delta(int pnum, _cmd_id cmd, std::unique_ptr data, uint32_t len) { if (!gbIsMultiplayer) return; DThreadPkt pkt { pnum, cmd, std::move(data), len }; std::lock_guard lock(*DthreadMutex); InfoList.push_back(std::move(pkt)); WorkToDo->signal(); } void dthread_start() { if (!gbIsMultiplayer) return; DthreadRunning = true; DthreadMutex.emplace(); WorkToDo.emplace(); Thread = SdlThread { DthreadHandler }; } void DThreadCleanup() { if (!DthreadRunning) return; { std::lock_guard lock(*DthreadMutex); DthreadRunning = false; InfoList.clear(); WorkToDo->signal(); } Thread.join(); DthreadMutex = std::nullopt; WorkToDo = std::nullopt; } } // namespace devilution