#include "StarSystemWorldClient.hpp" #include "StarRoot.hpp" #include "StarCelestialDatabase.hpp" #include "StarClientContext.hpp" #include "StarPlayerUniverseMap.hpp" namespace Star { SystemWorldClient::SystemWorldClient(ClockConstPtr universeClock, CelestialDatabasePtr celestialDatabase, PlayerUniverseMapPtr universeMap) : SystemWorld(universeClock, celestialDatabase), m_universeMap(std::move(universeMap)) {} CelestialCoordinate SystemWorldClient::currentSystem() const { return CelestialCoordinate(m_location); } Maybe SystemWorldClient::shipPosition() const { if (m_ship) return m_ship->position(); else return {}; } SystemLocation SystemWorldClient::shipLocation() const { if (m_ship) return m_ship->systemLocation(); else return {}; } SystemLocation SystemWorldClient::shipDestination() const { if (m_ship) return m_ship->destination(); else return {}; } // ship is flying if the system world is uninitialized or the ship doesn't have a location bool SystemWorldClient::flying() const { if (m_ship) return m_ship->systemLocation().empty(); return true; } void SystemWorldClient::update(float dt) { if (!m_ship) return; m_ship->clientUpdate(dt); auto location = m_ship->systemLocation(); if (auto uuid = location.maybe()) { if (auto object = getObject(*uuid)) { Maybe orbit; if (object->permanent()) m_universeMap->addMappedObject(CelestialCoordinate(m_location), *uuid, object->name(), object->orbit(), object->parameters()); else m_universeMap->addMappedObject(CelestialCoordinate(m_location), *uuid, object->name()); } } else if (auto coordinate = location.maybe()) { if (coordinate->isPlanetaryBody() || coordinate->isSatelliteBody()) m_universeMap->addMappedCoordinate(coordinate->planet()); } else if (auto orbit = location.maybe()) { if (orbit->target.isPlanetaryBody() || orbit->target.isSatelliteBody()) m_universeMap->addMappedCoordinate(orbit->target.planet()); } for (auto p : m_clientShips) p.second->clientUpdate(dt); for (auto p : m_objects) p.second->clientUpdate(dt); if (currentSystem().isNull()) { m_objects.clear(); m_clientShips.clear(); m_ship = {}; m_location = Vec3I(); } else if (auto celestialSlave = as(m_celestialDatabase)) celestialSlave->signalSystem(currentSystem()); // keeps the celestial chunk for our current system alive } List SystemWorldClient::objects() const { return m_objects.values(); } List SystemWorldClient::objectKeys() const { return m_objects.keys(); } SystemObjectPtr SystemWorldClient::getObject(Uuid const& uuid) const { return m_objects.maybe(uuid).value({}); } List SystemWorldClient::ships() const { return m_clientShips.values(); } SystemClientShipPtr SystemWorldClient::getShip(Uuid const & uuid) const { return m_clientShips.maybe(uuid).value({}); } Uuid SystemWorldClient::spawnObject(String typeName, Maybe position, Maybe const& uuid, JsonObject overrides) { Uuid objectUuid = uuid.value(Uuid()); m_outgoingPackets.append(make_shared(std::move(typeName), objectUuid, std::move(position), std::move(overrides))); return objectUuid; } bool SystemWorldClient::handleIncomingPacket(PacketPtr packet) { if (auto updatePacket = as(packet)) { auto location = m_ship->systemLocation(); for (auto p : updatePacket->shipUpdates) { if (m_ship && p.first == m_ship->uuid()) m_ship->readNetState(p.second, SystemWorldTimestep); else m_clientShips[p.first]->readNetState(p.second, SystemWorldTimestep); } for (auto p : updatePacket->objectUpdates) { auto object = getObject(p.first); object->readNetState(p.second, SystemWorldTimestep); } } else if (auto createPacket = as(packet)) { auto object = netLoadObject(createPacket->objectStore); m_objects.set(object->uuid(), object); } else if (auto destroyPacket = as(packet)) { m_objects.remove(destroyPacket->objectUuid); m_universeMap->removeMappedObject(CelestialCoordinate(m_location), destroyPacket->objectUuid); } else if (auto shipCreatePacket = as(packet)) { auto ship = netLoadShip(shipCreatePacket->shipStore); m_clientShips.set(ship->uuid(), ship); } else if (auto shipDestroyPacket = as(packet)) { m_clientShips.remove(shipDestroyPacket->shipUuid); } else if (auto startPacket = as(packet)) { m_objects.clear(); m_clientShips.clear(); m_location = startPacket->location; for (auto netStore: startPacket->objectStores) { auto object = netLoadObject(netStore); m_objects.set(object->uuid(), object); } for (auto netStore : startPacket->shipStores) { auto ship = netLoadShip(netStore); m_clientShips.set(ship->uuid(), ship); } m_ship = make_shared(this, startPacket->clientShip.first, startPacket->clientShip.second); m_universeMap->addMappedCoordinate(CelestialCoordinate(m_location)); m_universeMap->filterMappedObjects(CelestialCoordinate(m_location), m_objects.keys()); } else { // packet type not handled by system world client return false; } // packet was handled return true; } List SystemWorldClient::pullOutgoingPackets() { return take(m_outgoingPackets); } SystemObjectPtr SystemWorldClient::netLoadObject(ByteArray netStore) { DataStreamBuffer ds(std::move(netStore)); Uuid uuid = ds.read(); String name = ds.read(); auto objectConfig = systemObjectConfig(name, uuid); Vec2F position = ds.read(); JsonObject parameters = ds.read(); return make_shared(objectConfig, uuid, position, parameters); } SystemClientShipPtr SystemWorldClient::netLoadShip(ByteArray netStore) { DataStreamBuffer ds(std::move(netStore)); Uuid uuid = ds.read(); SystemLocation location = ds.read(); return make_shared(this, uuid, location); } }