/* Copyright (C) 2013 * swift Project Community / Contributors * * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, * or distributed except according to the terms contained in the LICENSE file. */ #ifndef BLACKSIM_XSWIFTBUS_TRAFFIC_H #define BLACKSIM_XSWIFTBUS_TRAFFIC_H //! \file #include "dbusobject.h" #include "settings.h" #include "command.h" #include "datarefs.h" #include "terrainprobe.h" #include "menus.h" #include "XPMPMultiplayer.h" #include "XPLMCamera.h" #include #include #include //! \cond PRIVATE #define XSWIFTBUS_TRAFFIC_INTERFACENAME "org.swift_project.xswiftbus.traffic" #define XSWIFTBUS_TRAFFIC_OBJECTPATH "/xswiftbus/traffic" //! \endcond namespace XSwiftBus { /*! * XSwiftBus service object for traffic aircraft which is accessible through DBus */ class CTraffic : public CDBusObject { public: //! Constructor CTraffic(ISettingsProvider *settingsProvider); //! Destructor virtual ~CTraffic() override; //! DBus interface name static const std::string &InterfaceName() { static std::string s(XSWIFTBUS_TRAFFIC_INTERFACENAME); return s; } //! DBus object path static const std::string &ObjectPath() { static std::string s(XSWIFTBUS_TRAFFIC_OBJECTPATH); return s; } //! Set plane view submenu void setPlaneViewMenu(const CMenu &planeViewSubMenu); //! Called by XPluginStart static void initLegacyData(); //! Initialize the multiplayer planes rendering and return true if successful bool initialize(); //! Returns whether multiplayer planes have been acquired. If not, owner will be set to the plugin that acquired it. bool acquireMultiplayerPlanes(std::string *owner = nullptr); //! Reverse the actions of initialize(). void cleanup(); //! Load a collection of planes from the given directory and return error message if unsuccessful std::string loadPlanesPackage(const std::string &path); //! Set the ICAO code to use for aircraft without a model match void setDefaultIcao(const std::string &defaultIcao); //! Set whether the plugin draws type and callsign labels above aircraft void setDrawingLabels(bool drawing); //! Get whether the plugin draws type and callsign labels above aircraft bool isDrawingLabels() const; //! Set the maximum number of aircraft. void setMaxPlanes(int planes); //! Set the maximum distance at which to draw aircraft (nautical miles). void setMaxDrawDistance(double nauticalMiles); //! Introduce a new traffic aircraft void addPlane(const std::string &callsign, const std::string &modelName, const std::string &aircraftIcao, const std::string &airlineIcao, const std::string &livery); //! Remove a traffic aircraft void removePlane(const std::string &callsign); //! Remove all traffic aircraft void removeAllPlanes(); //! Set the position of multiple traffic aircrafts void setPlanesPositions(const std::vector &callsigns, std::vector latitudesDeg, std::vector longitudesDeg, std::vector altitudesFt, std::vector pitchesDeg, std::vector rollsDeg, std::vector headingsDeg, const std::vector &onGrounds); //! Set the flight control surfaces and lights of multiple traffic aircrafts void setPlanesSurfaces(const std::vector &callsigns, const std::vector &gears, const std::vector &flaps, const std::vector &spoilers, const std::vector &speedBrakes, const std::vector &slats, const std::vector &wingSweeps, const std::vector &thrusts, const std::vector &elevators, const std::vector &rudders, const std::vector &ailerons, const std::vector &landLights, const std::vector &beaconLights, const std::vector &strobeLights, const std::vector &navLights, const std::vector &lightPatterns); //! Set the transponder of multiple traffic aircraft void setPlanesTransponders(const std::vector &callsigns, const std::vector &codes, const std::vector &modeCs, const std::vector &idents); //! Get remote aircrafts data (lat, lon, elevation and CG) void getRemoteAircraftData(std::vector &callsigns, std::vector &latitudesDeg, std::vector &longitudesDeg, std::vector &elevationsM, std::vector &verticalOffsets) const; //! Get the ground elevation at an arbitrary position double getElevationAtPosition(const std::string &callsign, double latitudeDeg, double longitudeDeg, double altitudeMeters) const; //! Sets the aircraft with callsign to be followed in plane view void setFollowedAircraft(const std::string &callsign); //! Perform generic processing int process(); //! Returns the own aircraft string to be used as callsign for setFollowedAircraft() static const std::string &ownAircraftString() { static const std::string o = "ownAircraft"; return o; } protected: //! Handler virtual void dbusDisconnectedHandler() override; //! Handler DBusHandlerResult dbusMessageHandler(const CDBusMessage &message) override; private: //! Camera struct DeltaCameraPosition { double dx = 0.0; double dy = 0.0; double dz = 0.0; double headingDeg = 0.0; double pitchDeg = 0.0; bool isInitialized = false; }; bool m_initialized = false; bool m_enabledMultiplayer = false; CTerrainProbe m_terrainProbe; void emitSimFrame(); void emitPlaneAdded(const std::string &callsign); void emitPlaneAddingFailed(const std::string &callsign); void switchToFollowPlaneView(const std::string &callsign); void followNextPlane(); void followPreviousPlane(); bool containsCallsign(const std::string &callsign) const; static int preferences(const char *section, const char *name, int def); static float preferences(const char *section, const char *name, float def); static int orbitOwnAircraftFunc(XPLMCameraPosition_t *cameraPosition, int isLosingControl, void *refcon); static int orbitPlaneFunc(XPLMCameraPosition_t *cameraPosition, int isLosingControl, void *refcon); static int drawCallback(XPLMDrawingPhase phase, int isBefore, void *refcon); static int spaceKeySniffer(char character, XPLMKeyFlags flags, char virtualKey, void *refcon); //! Remote aircraft struct Plane { void *id = nullptr; std::string callsign; std::string aircraftIcao; std::string airlineIcao; std::string livery; std::string modelName; std::string nightTextureMode; bool hasSurfaces = false; bool hasXpdr = false; char label[32] {}; CTerrainProbe terrainProbe; XPMPPlaneSurfaces_t surfaces; float targetGearPosition = 0; std::chrono::system_clock::time_point prevSurfacesLerpTime; XPMPPlaneRadar_t xpdr; XPMPPlanePosition_t position; Plane(void *id_, const std::string &callsign_, const std::string &aircraftIcao_, const std::string &airlineIcao_, const std::string &livery_, const std::string &modelName_); }; //! Check functions @{ static bool isPlusMinusOne(float v); static bool isPlusMinus180(float v); static bool isPlusMinus180(double v); static bool isZeroTo360(double v); //! @} //! Normalize to (-180, 180] or [0, 360) degrees @{ static float normalizeToPlusMinus180DegF(float v); static double normalizeToPlusMinus180DegD(double v); static float normalizeToZero360DegF(float v); static double normalizeToZero360DegD(double v); //! @} //! Check the position if values are valid @{ static bool isValidPosition(const XPMPPlanePosition_t &position); static bool isValidPosition(const XPLMCameraPosition_t *camPos); //! @} //! Pos as string @{ static std::string pos2String(const XPMPPlanePosition_t &position); static std::string pos2String(const XPLMCameraPosition_t *camPos); //! @} std::unordered_map m_planesByCallsign; std::unordered_map m_planesById; std::vector m_followPlaneViewSequence; // std::chrono::system_clock::time_point m_timestampLastSimFrame = std::chrono::system_clock::now(); CMenu m_followPlaneViewSubMenu; std::unordered_map m_followPlaneViewMenuItems; std::string m_followPlaneViewCallsign; CCommand m_followPlaneViewNextCommand; CCommand m_followPlaneViewPreviousCommand; DataRef m_worldRenderType; DataRef m_ownAircraftPositionX; DataRef m_ownAircraftPositionY; DataRef m_ownAircraftPositionZ; bool m_isSpacePressed = false; DeltaCameraPosition m_deltaCameraPosition; bool m_emitSimFrame = true; int m_countFrame = 0; //!< allows to do something every n-th frame int getPlaneData(void *id, int dataType, void *io_data); static int getPlaneData(void *id, int dataType, void *io_data, void *self) { 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); } } }; } // ns #endif // guard