Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarSystemWorldServerThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/game/StarSystemWorldServerThread.cpp')
-rw-r--r--source/game/StarSystemWorldServerThread.cpp175
1 files changed, 175 insertions, 0 deletions
diff --git a/source/game/StarSystemWorldServerThread.cpp b/source/game/StarSystemWorldServerThread.cpp
new file mode 100644
index 0000000..af9c065
--- /dev/null
+++ b/source/game/StarSystemWorldServerThread.cpp
@@ -0,0 +1,175 @@
+#include "StarSystemWorldServerThread.hpp"
+#include "StarTickRateMonitor.hpp"
+#include "StarNetPackets.hpp"
+
+namespace Star {
+
+SystemWorldServerThread::SystemWorldServerThread(Vec3I const& location, SystemWorldServerPtr systemWorld, String storageFile)
+ : Thread(strf("SystemWorldServer: %s", location)), m_stop(false), m_storageFile(storageFile) {
+ m_systemLocation = location;
+ m_systemWorld = move(systemWorld);
+}
+
+SystemWorldServerThread::~SystemWorldServerThread() {
+ m_stop = true;
+ join();
+}
+
+Vec3I SystemWorldServerThread::location() const {
+ return m_systemLocation;
+}
+
+List<ConnectionId> SystemWorldServerThread::clients() {
+ return m_clients.values();
+}
+
+void SystemWorldServerThread::addClient(ConnectionId clientId, Uuid const& uuid, float shipSpeed, SystemLocation const& location) {
+ WriteLocker locker(m_mutex);
+ m_clients.add(clientId);
+ m_outgoingPacketQueue.set(clientId, List<PacketPtr>());
+
+ m_systemWorld->addClientShip(clientId, uuid, shipSpeed, location);
+
+ m_clientShipLocations.set(clientId, {m_systemWorld->clientShipLocation(clientId), m_systemWorld->clientSkyParameters(clientId)});
+ if (auto warpAction = m_systemWorld->clientWarpAction(clientId))
+ m_clientWarpActions.set(clientId, *warpAction);
+}
+
+void SystemWorldServerThread::removeClient(ConnectionId clientId) {
+ WriteLocker locker(m_mutex);
+ m_systemWorld->removeClientShip(clientId);
+ m_clients.remove(clientId);
+ m_clientShipDestinations.remove(clientId);
+ m_clientShipLocations.remove(clientId);
+ m_outgoingPacketQueue.remove(clientId);
+}
+
+void SystemWorldServerThread::setPause(shared_ptr<const atomic<bool>> pause) {
+ m_pause = move(pause);
+}
+
+void SystemWorldServerThread::run() {
+ TickRateApproacher tickApproacher(1.0 / SystemWorldTimestep, 0.5);
+
+ while (!m_stop) {
+ LogMap::set(strf("system_%s_update_fps", m_systemLocation), tickApproacher.rate());
+
+ update();
+
+ m_periodicStorage -= 1.0 / tickApproacher.rate();
+ if (m_triggerStorage || m_periodicStorage <= 0.0) {
+ m_triggerStorage = false;
+ m_periodicStorage = 300.0; // store every 5 minutes
+ store();
+ }
+
+ tickApproacher.tick();
+
+ double spareTime = tickApproacher.spareTime();
+ uint64_t millis = floor(spareTime * 1000);
+ if (spareTime > 0)
+ sleepPrecise(millis);
+ }
+
+ store();
+}
+
+void SystemWorldServerThread::stop() {
+ m_stop = true;
+}
+
+void SystemWorldServerThread::update() {
+ WriteLocker queueLocker(m_queueMutex);
+ WriteLocker locker(m_mutex);
+
+ for (auto p : take(m_incomingPacketQueue))
+ m_systemWorld->handleIncomingPacket(p.first, p.second);
+
+ for (auto p : take(m_clientShipActions))
+ p.second(m_systemWorld->clientShip(p.first).get());
+
+ if (!m_pause || *m_pause == false)
+ m_systemWorld->update();
+ m_triggerStorage = m_systemWorld->triggeredStorage();
+
+ // important to set destinations before getting locations
+ // setting a destination nullifies the current location
+ for (auto p : take(m_clientShipDestinations))
+ m_systemWorld->setClientDestination(p.first, p.second);
+
+ m_activeInstanceWorlds = m_systemWorld->activeInstanceWorlds();
+
+ for (auto clientId : m_clients) {
+ m_outgoingPacketQueue[clientId].appendAll(m_systemWorld->pullOutgoingPackets(clientId));
+ m_clientShipLocations.set(clientId, {m_systemWorld->clientShipLocation(clientId), m_systemWorld->clientSkyParameters(clientId)});
+ if (auto warpAction = m_systemWorld->clientWarpAction(clientId))
+ m_clientWarpActions.set(clientId, *warpAction);
+ else if (m_clientWarpActions.contains(clientId))
+ m_clientWarpActions.remove(clientId);
+ }
+ queueLocker.unlock();
+
+ if (m_updateAction)
+ m_updateAction(this);
+}
+
+void SystemWorldServerThread::setClientDestination(ConnectionId clientId, SystemLocation const& destination) {
+ WriteLocker locker(m_queueMutex);
+ m_clientShipDestinations.set(clientId, destination);
+}
+
+void SystemWorldServerThread::executeClientShipAction(ConnectionId clientId, ClientShipAction action) {
+ WriteLocker locker(m_queueMutex);
+ m_clientShipActions.append({clientId, move(action)});
+}
+
+SystemLocation SystemWorldServerThread::clientShipLocation(ConnectionId clientId) {
+ ReadLocker locker(m_queueMutex);
+ // while a ship destination is pending the ship is assumed to be flying
+ if (m_clientShipDestinations.contains(clientId))
+ return {};
+ return m_clientShipLocations.get(clientId).first;
+}
+
+Maybe<pair<WarpAction, WarpMode>> SystemWorldServerThread::clientWarpAction(ConnectionId clientId) {
+ ReadLocker locker(m_queueMutex);
+ if (m_clientShipDestinations.contains(clientId))
+ return {};
+ return m_clientWarpActions.maybe(clientId);
+}
+
+SkyParameters SystemWorldServerThread::clientSkyParameters(ConnectionId clientId) {
+ ReadLocker locker(m_queueMutex);
+ return m_clientShipLocations.get(clientId).second;
+}
+
+List<InstanceWorldId> SystemWorldServerThread::activeInstanceWorlds() const {
+ return m_activeInstanceWorlds;
+}
+
+void SystemWorldServerThread::setUpdateAction(function<void(SystemWorldServerThread*)> updateAction) {
+ m_updateAction = updateAction;
+}
+
+void SystemWorldServerThread::pushIncomingPacket(ConnectionId clientId, PacketPtr packet) {
+ WriteLocker locker(m_queueMutex);
+ m_incomingPacketQueue.append({move(clientId), move(packet)});
+}
+
+List<PacketPtr> SystemWorldServerThread::pullOutgoingPackets(ConnectionId clientId) {
+ WriteLocker locker(m_queueMutex);
+ return take(m_outgoingPacketQueue[clientId]);
+}
+
+void SystemWorldServerThread::store() {
+ ReadLocker locker(m_mutex);
+ Json store = m_systemWorld->diskStore();
+ locker.unlock();
+
+ Logger::debug("Trigger disk storage for system world %s:%s:%s", m_systemLocation.x(), m_systemLocation.y(), m_systemLocation.z());
+ auto versioningDatabase = Root::singleton().versioningDatabase();
+ auto versionedStore = versioningDatabase->makeCurrentVersionedJson("System", store);
+ VersionedJson::writeFile(versionedStore, m_storageFile);
+}
+
+}