diff --git a/src/plugins/simulator/xplane/simulatorxplane.cpp b/src/plugins/simulator/xplane/simulatorxplane.cpp index 4a0e70e54..02afd2385 100644 --- a/src/plugins/simulator/xplane/simulatorxplane.cpp +++ b/src/plugins/simulator/xplane/simulatorxplane.cpp @@ -96,9 +96,11 @@ namespace BlackSimPlugin m_fastTimer.setObjectName(this->objectName().append(":m_fastTimer")); m_slowTimer.setObjectName(this->objectName().append(":m_slowTimer")); + m_pendingAddedTimer.setObjectName(this->objectName().append(":m_pendingAddedTimer")); connect(&m_fastTimer, &QTimer::timeout, this, &CSimulatorXPlane::fastTimerTimeout); connect(&m_slowTimer, &QTimer::timeout, this, &CSimulatorXPlane::slowTimerTimeout); connect(&m_airportUpdater, &QTimer::timeout, this, &CSimulatorXPlane::updateAirportsInRange); + connect(&m_pendingAddedTimer, &QTimer::timeout, this, &CSimulatorXPlane::remoteAircraftAddingTimeout); m_fastTimer.start(100); m_slowTimer.start(1000); m_airportUpdater.start(60000); @@ -260,6 +262,8 @@ namespace BlackSimPlugin m_serviceProxy->updateAirportsInRange(); connect(m_trafficProxy, &CXSwiftBusTrafficProxy::simFrame, this, &CSimulatorXPlane::updateRemoteAircraft); connect(m_trafficProxy, &CXSwiftBusTrafficProxy::remoteAircraftData, this, &CSimulatorXPlane::updateRemoteAircraftFromSimulator); + connect(m_trafficProxy, &CXSwiftBusTrafficProxy::remoteAircraftAdded, this, &CSimulatorXPlane::remoteAircraftAdded); + connect(m_trafficProxy, &CXSwiftBusTrafficProxy::remoteAircraftAddingFailed, this, &CSimulatorXPlane::remoteAircraftAddingFailed); if (m_watcher) { m_watcher->setConnection(m_conn); } m_trafficProxy->removeAllPlanes(); this->loadCslPackages(); @@ -491,22 +495,19 @@ namespace BlackSimPlugin Q_ASSERT_X(!newRemoteAircraft.getCallsign().isEmpty(), Q_FUNC_INFO, "empty callsign"); Q_ASSERT_X(newRemoteAircraft.hasModelString(), Q_FUNC_INFO, "missing model string"); - m_xplaneAircraftObjects.insert(newRemoteAircraft.getCallsign(), CXPlaneMPAircraft(newRemoteAircraft, this, &m_interpolationLogger)); - CAircraftModel aircraftModel = newRemoteAircraft.getModel(); - QString livery = aircraftModel.getLivery().getCombinedCode(); //! \todo livery resolution for XP - m_trafficProxy->addPlane(newRemoteAircraft.getCallsign().asString(), aircraftModel.getModelString(), - newRemoteAircraft.getAircraftIcaoCode().getDesignator(), - newRemoteAircraft.getAirlineIcaoCode().getDesignator(), - livery); + QString callsign = newRemoteAircraft.getCallsign().asString(); + m_pendingAddedAircrafts.push_back(newRemoteAircraft); - CLogMessage(this).info("XP: Added aircraft %1") << newRemoteAircraft.getCallsign().toQString(); - - bool rendered = true; - updateAircraftRendered(newRemoteAircraft.getCallsign(), rendered); - - CSimulatedAircraft remoteAircraftCopy(newRemoteAircraft); - remoteAircraftCopy.setRendered(rendered); - emit this->aircraftRenderingChanged(remoteAircraftCopy); + if (m_pendingAddedAircrafts.size() == 1) + { + CAircraftModel aircraftModel = newRemoteAircraft.getModel(); + QString livery = aircraftModel.getLivery().getCombinedCode(); //! \todo livery resolution for XP + m_trafficProxy->addPlane(callsign, aircraftModel.getModelString(), + newRemoteAircraft.getAircraftIcaoCode().getDesignator(), + newRemoteAircraft.getAirlineIcaoCode().getDesignator(), + livery); + m_pendingAddedTimer.start(5000); + } return true; } @@ -519,21 +520,36 @@ namespace BlackSimPlugin if (callsign.isEmpty()) { return false; } // can happen if an object is not an aircraft // really remove from simulator - if (!m_xplaneAircraftObjects.contains(callsign)) { return false; } // already fully removed or not yet added + if (!m_xplaneAircraftObjects.contains(callsign) && !m_pendingAddedAircrafts.containsCallsign(callsign)) { return false; } // already fully removed or not yet added // mark in provider const bool updated = this->updateAircraftRendered(callsign, false); if (updated) { - Q_ASSERT_X(m_xplaneAircraftObjects.contains(callsign), Q_FUNC_INFO, "Aircraft removed"); - const CXPlaneMPAircraft &xplaneAircraft = m_xplaneAircraftObjects[callsign]; - CSimulatedAircraft aircraft(xplaneAircraft.getAircraft()); - aircraft.setRendered(false); - emit this->aircraftRenderingChanged(aircraft); + if (m_xplaneAircraftObjects.contains(callsign)) + { + const CXPlaneMPAircraft &xplaneAircraft = m_xplaneAircraftObjects[callsign]; + CSimulatedAircraft aircraft(xplaneAircraft.getAircraft()); + aircraft.setRendered(false); + emit this->aircraftRenderingChanged(aircraft); + } + if (m_pendingAddedAircrafts.containsCallsign(callsign)) + { + CSimulatedAircraft aircraft = m_pendingAddedAircrafts.findFirstByCallsign(callsign); + aircraft.setRendered(false); + emit this->aircraftRenderingChanged(aircraft); + } } m_trafficProxy->removePlane(callsign.asString()); m_xplaneAircraftObjects.remove(callsign); + m_pendingAddedAircrafts.removeByCallsign(callsign); + + // Stop the timer if there is nothing left + if (m_pendingAddedAircrafts.empty()) + { + m_pendingAddedTimer.stop(); + } // bye return true; @@ -809,6 +825,81 @@ namespace BlackSimPlugin if (this->isConnected()) { m_serviceProxy->updateAirportsInRange(); } } + void CSimulatorXPlane::remoteAircraftAdded(const QString &callsign) + { + if (m_pendingAddedAircrafts.containsCallsign(callsign)) + { + CSimulatedAircraft addedRemoteAircraft = m_pendingAddedAircrafts.findFirstByCallsign(callsign); + m_pendingAddedAircrafts.removeByCallsign(callsign); + m_xplaneAircraftObjects.insert(addedRemoteAircraft.getCallsign(), CXPlaneMPAircraft(addedRemoteAircraft, this, &m_interpolationLogger)); + + CLogMessage(this).info("XP: Added aircraft %1") << addedRemoteAircraft.getCallsign().toQString(); + + bool rendered = true; + updateAircraftRendered(addedRemoteAircraft.getCallsign(), rendered); + addedRemoteAircraft.setRendered(rendered); + emit this->aircraftRenderingChanged(addedRemoteAircraft); + } + + if (m_pendingAddedAircrafts.size() > 0) + { + CSimulatedAircraft newRemoteAircraft = m_pendingAddedAircrafts.front(); + CAircraftModel aircraftModel = newRemoteAircraft.getModel(); + QString livery = aircraftModel.getLivery().getCombinedCode(); //! \todo livery resolution for XP + m_trafficProxy->addPlane(newRemoteAircraft.getCallsign().toQString(), aircraftModel.getModelString(), + newRemoteAircraft.getAircraftIcaoCode().getDesignator(), + newRemoteAircraft.getAirlineIcaoCode().getDesignator(), + livery); + m_pendingAddedTimer.start(5000); + } + else + { + m_pendingAddedTimer.stop(); + } + } + + void CSimulatorXPlane::remoteAircraftAddingFailed(const QString &callsign) + { + CLogMessage(this).info("XP: Adding aircraft failed: %1") << callsign; + m_pendingAddedAircrafts.removeByCallsign(callsign); + + if (m_pendingAddedAircrafts.size() > 0) + { + CSimulatedAircraft newRemoteAircraft = m_pendingAddedAircrafts.front(); + CAircraftModel aircraftModel = newRemoteAircraft.getModel(); + QString livery = aircraftModel.getLivery().getCombinedCode(); //! \todo livery resolution for XP + m_trafficProxy->addPlane(newRemoteAircraft.getCallsign().toQString(), aircraftModel.getModelString(), + newRemoteAircraft.getAircraftIcaoCode().getDesignator(), + newRemoteAircraft.getAirlineIcaoCode().getDesignator(), + livery); + m_pendingAddedTimer.start(5000); + } + else + { + m_pendingAddedTimer.stop(); + } + } + + void CSimulatorXPlane::remoteAircraftAddingTimeout() + { + Q_ASSERT(m_pendingAddedAircrafts.size() > 0); + + CSimulatedAircraft newRemoteAircraft = m_pendingAddedAircrafts.front(); + QString callsign = newRemoteAircraft.getCallsign().toQString(); + + CLogMessage(this).warning("XP: Adding aircraft timed out: %1. Trying again.") << callsign; + + m_trafficProxy->removePlane(callsign); + + CAircraftModel aircraftModel = newRemoteAircraft.getModel(); + QString livery = aircraftModel.getLivery().getCombinedCode(); //! \todo livery resolution for XP + m_trafficProxy->addPlane(callsign, aircraftModel.getModelString(), + newRemoteAircraft.getAircraftIcaoCode().getDesignator(), + newRemoteAircraft.getAirlineIcaoCode().getDesignator(), + livery); + m_pendingAddedTimer.start(5000); + } + BlackCore::ISimulator *CSimulatorXPlaneFactory::create(const CSimulatorPluginInfo &info, IOwnAircraftProvider *ownAircraftProvider, IRemoteAircraftProvider *remoteAircraftProvider, diff --git a/src/plugins/simulator/xplane/simulatorxplane.h b/src/plugins/simulator/xplane/simulatorxplane.h index 9cbf1eda2..adb99b79c 100644 --- a/src/plugins/simulator/xplane/simulatorxplane.h +++ b/src/plugins/simulator/xplane/simulatorxplane.h @@ -25,6 +25,7 @@ #include "blackmisc/simulation/data/modelcaches.h" #include "blackmisc/simulation/settings/simulatorsettings.h" #include "blackmisc/simulation/settings/xswiftbussettings.h" +#include "blackmisc/simulation/simulatedaircraftlist.h" #include "blackmisc/weather/weathergrid.h" #include "blackmisc/settingscache.h" #include "blackmisc/statusmessage.h" @@ -180,6 +181,9 @@ namespace BlackSimPlugin void requestRemoteAircraftDataFromXPlane(); void updateRemoteAircraftFromSimulator(const QString &callsign, double latitudeDeg, double longitudeDeg, double elevationMeters, double modelVerticalOffsetMeters); void updateAirportsInRange(); + void remoteAircraftAdded(const QString &callsign); + void remoteAircraftAddingFailed(const QString &callsign); + void remoteAircraftAddingTimeout(); static constexpr int GuessRemoteAircraftPartsCycle = 20; //!< guess every n-th cycle @@ -196,8 +200,10 @@ namespace BlackSimPlugin BlackMisc::CData m_modelSet { this }; // Driver Interpolation + BlackMisc::Simulation::CSimulatedAircraftList m_pendingAddedAircrafts; CXPlaneMPAircraftObjects m_xplaneAircraftObjects; //!< XPlane multiplayer aircraft int m_interpolationRequest = 0; //!< current interpolation request + QTimer m_pendingAddedTimer; XPlaneData m_xplaneData; diff --git a/src/plugins/simulator/xplane/xswiftbustrafficproxy.h b/src/plugins/simulator/xplane/xswiftbustrafficproxy.h index 12df0be8d..b15c813cb 100644 --- a/src/plugins/simulator/xplane/xswiftbustrafficproxy.h +++ b/src/plugins/simulator/xplane/xswiftbustrafficproxy.h @@ -70,6 +70,12 @@ namespace BlackSimPlugin //! \remark from simulator to driver for elevation and CG void remoteAircraftData(const QString &callsign, double latitudeDeg, double longitudeDeg, double elevationMeters, double modelVerticalOffsetMeters); + //! Remote aircraft successfully added + void remoteAircraftAdded(const QString &callsign); + + //! Remote aircraft adding failed + void remoteAircraftAddingFailed(const QString &callsign); + public slots: //! \copydoc XSwiftBus::CTraffic::initialize bool initialize(); diff --git a/src/xswiftbus/traffic.cpp b/src/xswiftbus/traffic.cpp index 9312b2a2a..447e884cf 100644 --- a/src/xswiftbus/traffic.cpp +++ b/src/xswiftbus/traffic.cpp @@ -76,8 +76,7 @@ namespace XSwiftBus { if (! s_legacyDataOK) { return false; } - auto dir = g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep; - auto err = XPMPMultiplayerInit(preferences, preferences, dir.c_str()); + auto err = XPMPMultiplayerInit(preferences, preferences); if (*err) { cleanup(); return false; } m_initialized = true; @@ -124,6 +123,22 @@ namespace XSwiftBus sendDBusMessage(signalRemoteAircraftData); } + void CTraffic::emitPlaneAdded(const std::string &callsign) + { + CDBusMessage signalPlaneAdded = CDBusMessage::createSignal(XSWIFTBUS_TRAFFIC_OBJECTPATH, XSWIFTBUS_TRAFFIC_INTERFACENAME, "remoteAircraftAdded"); + signalPlaneAdded.beginArgumentWrite(); + signalPlaneAdded.appendArgument(callsign); + sendDBusMessage(signalPlaneAdded); + } + + void CTraffic::emitPlaneAddingFailed(const std::string &callsign) + { + CDBusMessage signalPlaneAddingFailed = CDBusMessage::createSignal(XSWIFTBUS_TRAFFIC_OBJECTPATH, XSWIFTBUS_TRAFFIC_INTERFACENAME, "remoteAircraftAddingFailed"); + signalPlaneAddingFailed.beginArgumentWrite(); + signalPlaneAddingFailed.appendArgument(callsign); + sendDBusMessage(signalPlaneAddingFailed); + } + void CTraffic::orbitRemotePlane(const std::string &callsign) { m_planeViewCallsign = callsign; @@ -216,7 +231,7 @@ namespace XSwiftBus } else { - id = XPMPCreatePlaneWithModelName(modelName.c_str(), aircraftIcao.c_str(), airlineIcao.c_str(), livery.c_str(), getPlaneData, static_cast(this)); + id = XPMPCreatePlaneWithModelName(modelName.c_str(), aircraftIcao.c_str(), airlineIcao.c_str(), livery.c_str(), getPlaneData, planeLoaded, static_cast(this)); } if (id) diff --git a/src/xswiftbus/traffic.h b/src/xswiftbus/traffic.h index bbf4a8847..f7537f4a3 100644 --- a/src/xswiftbus/traffic.h +++ b/src/xswiftbus/traffic.h @@ -125,6 +125,8 @@ namespace XSwiftBus void emitSimFrame(); void emitRemoteAircraftData(const std::string &callsign, double latitude, double longitude, double elevation, double modelVerticalOffset); + void emitPlaneAdded(const std::string &callsign); + void emitPlaneAddingFailed(const std::string &callsign); void orbitRemotePlane(const std::string &callsign); static int preferences(const char *section, const char *name, int def); @@ -169,6 +171,16 @@ namespace XSwiftBus { return static_cast(self)->getPlaneData(id, dataType, io_data); } + + static void planeLoaded(void *id, bool succeeded, void *self) + { + auto *traffic = static_cast(self); + auto planeIt = traffic->m_planesById.find(id); + if (planeIt == traffic->m_planesById.end()) { return; } + + if (succeeded) { traffic->emitPlaneAdded(planeIt->second->callsign); } + else { traffic->emitPlaneAddingFailed(planeIt->second->callsign); } + } }; }