Issue #17 Using xplanemp2

This commit is contained in:
Mat Sutcliffe
2020-05-27 15:33:04 +01:00
parent 926390d8f6
commit 0d52c4ca47
5 changed files with 131 additions and 187 deletions

View File

@@ -33,8 +33,6 @@ PLUGIN_API int XPluginStart(char *o_name, char *o_sig, char *o_desc)
std::strcpy(o_name, "XSwiftBus");
std::strcpy(o_sig, "org.swift-project.xswiftbus");
std::strcpy(o_desc, "Allows swift to connect to X-Plane via D-Bus IPC");
XSwiftBus::CTraffic::initLegacyData();
return 1;
}

View File

@@ -15,7 +15,6 @@
#include "traffic.h"
#include "utils.h"
#include "XPMPMultiplayer.h"
#include "XPMPPlaneRenderer.h"
#include <XPLM/XPLMGraphics.h>
#include <XPLM/XPLMProcessing.h>
#include <XPLM/XPLMUtilities.h>
@@ -38,13 +37,16 @@ namespace XSwiftBus
CTraffic::Plane::Plane(void *id_, const std::string &callsign_, const std::string &aircraftIcao_, const std::string &airlineIcao_, const std::string &livery_, const std::string &modelName_)
: id(id_), callsign(callsign_), aircraftIcao(aircraftIcao_), airlineIcao(airlineIcao_), livery(livery_), modelName(modelName_)
{
std::memset(static_cast<void *>(&position), 0, sizeof(position));
position.size = sizeof(position);
std::memset(static_cast<void *>(&surveillance), 0, sizeof(surveillance));
surveillance.size = sizeof(surveillance);
std::memset(static_cast<void *>(&surfaces), 0, sizeof(surfaces));
surfaces.size = sizeof(surfaces);
surfaces.lights.bcnLights = surfaces.lights.landLights = surfaces.lights.navLights = surfaces.lights.strbLights = 1;
surfaces.size = sizeof(surfaces);
xpdr.size = sizeof(xpdr);
std::strncpy(label, callsign.c_str(), sizeof(label));
std::srand(static_cast<unsigned int>(std::time(nullptr)));
surfaces.lights.timeOffset = static_cast<uint16_t>(std::rand() % 0xffff);
}
@@ -59,49 +61,34 @@ namespace XSwiftBus
{
assert(!s_instance);
s_instance = this;
XPLMRegisterDrawCallback(drawCallback, xplm_Phase_Airplanes, 1, this);
XPLMRegisterKeySniffer(followAircraftKeySniffer, 1, this);
}
// *INDENT-ON*
CTraffic::~CTraffic()
{
XPLMUnregisterDrawCallback(drawCallback, xplm_Phase_Airplanes, 1, this);
cleanup();
assert(s_instance == this);
s_instance = nullptr;
}
static bool s_legacyDataOK = true;
void CTraffic::setPlaneViewMenu(const CMenu &planeViewSubMenu)
{
m_followPlaneViewSubMenu = planeViewSubMenu;
}
void CTraffic::initLegacyData()
{
initXPlanePath();
auto dir = g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep + "LegacyData" + g_sep;
std::string csl = dir + "CSL";
std::string related = dir + "related.txt";
std::string doc8643 = dir + "Doc8643.txt";
std::string lights = dir + "lights.png";
auto err = XPMPMultiplayerInitLegacyData(csl.c_str(), related.c_str(), lights.c_str(), doc8643.c_str(),
"C172", preferences, preferences);
if (*err) { s_legacyDataOK = false; }
}
bool CTraffic::initialize()
{
if (! s_legacyDataOK) { return false; }
if (! m_initialized)
{
auto err = XPMPMultiplayerInit(preferences, preferences);
if (*err) { cleanup(); }
initXPlanePath();
auto dir = g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep + "LegacyData" + g_sep;
std::string related = dir + "related.txt";
std::string doc8643 = dir + "Doc8643.txt";
updateConfiguration();
auto err = XPMPMultiplayerInit(&m_configuration, related.c_str(), doc8643.c_str());
if (err && *err) { cleanup(); }
else { m_initialized = true; }
}
@@ -120,7 +107,6 @@ namespace XSwiftBus
else
{
m_enabledMultiplayer = true;
XPMPLoadPlanesIfNecessary();
}
}
@@ -234,50 +220,18 @@ namespace XSwiftBus
// static int g_maxPlanes = 100;
// static float g_drawDistance = 50.0f;
int CTraffic::preferences(const char *section, const char *name, int def)
void CTraffic::updateConfiguration()
{
if (!s_instance) { return def; }
if (strcmp(section, "planes") == 0 && strcmp(name, "max_full_count") == 0)
{
return s_instance->getSettings().getMaxPlanes(); // preferences
}
else if (strcmp(section, "debug") == 0 && strcmp(name, "allow_obj8_async_load") == 0)
{
// the setting allow_obj8_async_load (in the debug section) controls
// whether or not async loading is enabled: 1 means enabled, 0 means disabled
return 1;
}
else if (strcmp(section, "debug") == 0 && strcmp(name, "render_phases") == 0)
{
return s_instance->getConfig().getDebugMode() ? 1 : 0;
}
else if (strcmp(section, "debug") == 0 && strcmp(name, "tcas_traffic") == 0)
{
return s_instance->getConfig().getTcasEnabled() ? 1 : 0;
}
return def;
}
float CTraffic::preferences(const char *section, const char *name, float def)
{
if (!s_instance) { return def; }
if (strcmp(section, "planes") == 0 && strcmp(name, "full_distance") == 0)
{
return static_cast<float>(s_instance->getSettings().getMaxDrawDistanceNM()); // preferences
}
return def;
m_configuration.maxFullAircraftRenderingDistance = static_cast<float>(s_instance->getSettings().getMaxDrawDistanceNM());
m_configuration.enableSurfaceClamping = true;
m_configuration.debug.modelMatching = false;
}
std::string CTraffic::loadPlanesPackage(const std::string &path)
{
initXPlanePath();
auto dir = g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep + "LegacyData" + g_sep;
std::string related = dir + "related.txt";
std::string doc8643 = dir + "Doc8643.txt";
auto err = XPMPLoadCSLPackage(path.c_str(), related.c_str(), doc8643.c_str());
auto err = XPMPMultiplayerLoadCSLPackages(path.c_str());
if (*err) { return err; }
return {};
}
@@ -307,12 +261,11 @@ namespace XSwiftBus
XPMPPlaneID id = nullptr;
if (modelName.empty())
{
id = XPMPCreatePlane(aircraftIcao.c_str(), airlineIcao.c_str(), livery.c_str(), getPlaneData, planeLoaded, static_cast<void *>(this));
id = XPMPCreatePlane(aircraftIcao.c_str(), airlineIcao.c_str(), livery.c_str());
}
else
{
const std::string nt = this->getSettings().getNightTextureMode();
id = XPMPCreatePlaneWithModelName(modelName.c_str(), aircraftIcao.c_str(), airlineIcao.c_str(), livery.c_str(), nt.c_str(), getPlaneData, planeLoaded, static_cast<void *>(this));
id = XPMPCreatePlaneWithModelName(modelName.c_str(), aircraftIcao.c_str(), airlineIcao.c_str(), livery.c_str());
}
if (!id)
@@ -329,6 +282,8 @@ namespace XSwiftBus
CMenuItem planeViewMenuItem = m_followPlaneViewSubMenu.item(callsign, [this, callsign] { switchToFollowPlaneView(callsign); });
m_followPlaneViewMenuItems[callsign] = planeViewMenuItem;
m_followPlaneViewSequence.push_back(callsign);
emitPlaneAdded(callsign);
}
void CTraffic::removePlane(const std::string &callsign)
@@ -392,6 +347,8 @@ namespace XSwiftBus
plane->position.pitch = static_cast<float>(pitchesDeg.at(i));
plane->position.roll = static_cast<float>(rollsDeg.at(i));
plane->position.heading = static_cast<float>(headingsDeg.at(i));
plane->position.offsetScale = 1.0f;
plane->position.clampToGround = true;
if (setOnGround) { plane->isOnGround = onGrounds.at(i); }
}
@@ -452,11 +409,10 @@ namespace XSwiftBus
Plane *plane = planeIt->second;
if (!plane) { continue; }
plane->hasXpdr = true;
plane->xpdr.code = codes.at(i);
if (idents.at(i)) { plane->xpdr.mode = xpmpTransponderMode_ModeC_Ident; }
else if (modeCs.at(i)) { plane->xpdr.mode = xpmpTransponderMode_ModeC; }
else { plane->xpdr.mode = xpmpTransponderMode_Standby; }
plane->surveillance.code = codes.at(i);
if (idents.at(i)) { plane->surveillance.mode = xpmpTransponderMode_ModeC_Ident; }
else if (modeCs.at(i)) { plane->surveillance.mode = xpmpTransponderMode_ModeC; }
else { plane->surveillance.mode = xpmpTransponderMode_Standby; }
}
}
@@ -491,15 +447,13 @@ namespace XSwiftBus
groundElevation = plane->terrainProbe.getElevation(latDeg, lonDeg, plane->position.elevation, requestedCallsign, isWater).front();
if (std::isnan(groundElevation)) { groundElevation = 0.0; }
}
double fudgeFactor = 3.0;
bool hasOffset = XPMPGetVerticalOffset(plane->id, &fudgeFactor);
callsigns.push_back(requestedCallsign);
latitudesDeg.push_back(latDeg);
longitudesDeg.push_back(lonDeg);
elevationsM.push_back(groundElevation);
waterFlags.push_back(isWater);
verticalOffsets.push_back(hasOffset ? fudgeFactor : std::numeric_limits<decltype(fudgeFactor)>::quiet_NaN());
verticalOffsets.push_back(0); // xpmp2 adjusts the offset for us, so effectively always zero
}
}
@@ -830,6 +784,9 @@ namespace XSwiftBus
int CTraffic::process()
{
invokeQueuedDBusCalls();
doPlaneUpdates();
emitSimFrame();
m_countFrame++;
return 1;
}
@@ -842,73 +799,34 @@ namespace XSwiftBus
sizeof(*dst) - sizeof(dst->size));
}
int CTraffic::getPlaneData(void *id, int dataType, void *io_data)
void CTraffic::doPlaneUpdates()
{
const auto planeIt = m_planesById.find(id);
// assert(planeIt != m_planesById.end());
if (planeIt == m_planesById.end()) { return xpmpData_Unavailable; } // less drastic version
Plane *plane = planeIt->second;
if (!plane) { return xpmpData_Unavailable; }
switch (dataType)
m_updates.clear();
for (const auto pair : m_planesById)
{
case xpmpDataType_Position:
{
const auto io_position = static_cast<XPMPPlanePosition_t *>(io_data);
io_position->lat = plane->position.lat;
io_position->lon = plane->position.lon;
io_position->elevation = plane->position.elevation;
io_position->pitch = plane->position.pitch;
io_position->roll = plane->position.roll;
io_position->heading = plane->position.heading;
std::strncpy(io_position->label, plane->label, sizeof(plane->label)); // fixme don't need to copy on every frame
return xpmpData_NewData;
}
case xpmpDataType_Surfaces:
if (plane->hasSurfaces)
{
const auto now = std::chrono::system_clock::now();
static const float epsilon = std::numeric_limits<float>::epsilon();
const float f = plane->surfaces.gearPosition - plane->targetGearPosition;
if (std::abs(f) > epsilon)
{
// interpolate gear position
constexpr float gearMoveTimeMs = 5000;
const auto gearPositionDiffRemaining = plane->targetGearPosition - plane->surfaces.gearPosition;
const auto diffMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - plane->prevSurfacesLerpTime);
const auto gearPositionDiffThisFrame = (diffMs.count()) / gearMoveTimeMs;
plane->surfaces.gearPosition += std::copysign(gearPositionDiffThisFrame, gearPositionDiffRemaining);
plane->surfaces.gearPosition = std::max(0.0f, std::min(plane->surfaces.gearPosition, 1.0f));
}
plane->prevSurfacesLerpTime = now;
const auto io_surfaces = static_cast<XPMPPlaneSurfaces_t *>(io_data);
if (memcmpPayload(io_surfaces, &plane->surfaces))
{
std::memcpy(io_surfaces, &plane->surfaces, sizeof(*io_surfaces));
return xpmpData_NewData;
}
else { return xpmpData_Unchanged; }
}
break;
case xpmpDataType_Radar:
if (plane->hasXpdr)
{
const auto io_xpdr = static_cast<XPMPPlaneRadar_t *>(io_data);
if (memcmpPayload(io_xpdr, &plane->xpdr))
{
std::memcpy(io_xpdr, &plane->xpdr, sizeof(*io_xpdr));
return xpmpData_NewData;
}
else { return xpmpData_Unchanged; }
}
Plane *plane = pair.second;
interpolateGear(plane);
m_updates.push_back({ plane->id, &plane->position, &plane->surfaces, &plane->surveillance });
}
return xpmpData_Unavailable;
XPMPUpdatePlanes(m_updates.data(), sizeof(XPMPUpdate_t), m_updates.size());
}
void CTraffic::interpolateGear(Plane* plane)
{
const auto now = std::chrono::system_clock::now();
static const float epsilon = std::numeric_limits<float>::epsilon();
const float f = plane->surfaces.gearPosition - plane->targetGearPosition;
if (std::abs(f) > epsilon)
{
constexpr float gearMoveTimeMs = 5000;
const auto gearPositionDiffRemaining = plane->targetGearPosition - plane->surfaces.gearPosition;
const auto diffMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - plane->prevSurfacesLerpTime);
const auto gearPositionDiffThisFrame = (diffMs.count()) / gearMoveTimeMs;
plane->surfaces.gearPosition += std::copysign(gearPositionDiffThisFrame, gearPositionDiffRemaining);
plane->surfaces.gearPosition = std::max(0.0f, std::min(plane->surfaces.gearPosition, 1.0f));
}
plane->prevSurfacesLerpTime = now;
}
int CTraffic::orbitPlaneFunc(XPLMCameraPosition_t *cameraPosition, int isLosingControl, void *refcon)
@@ -1082,23 +1000,6 @@ namespace XSwiftBus
return 1;
}
int CTraffic::drawCallback(XPLMDrawingPhase phase, int isBefore, void *refcon)
{
(void)phase;
(void)isBefore;
CTraffic *traffic = static_cast<CTraffic *>(refcon);
// The draw callback is called several times per frame. We need this only once.
if (traffic->m_worldRenderType.get() == 0)
{
traffic->emitSimFrame();
}
traffic->m_countFrame++;
return 1;
}
int CTraffic::followAircraftKeySniffer(char character, XPLMKeyFlags flags, char virtualKey, void *refcon)
{
(void) character;

View File

@@ -59,9 +59,6 @@ namespace XSwiftBus
//! 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();
@@ -155,11 +152,10 @@ namespace XSwiftBus
bool containsCallsign(const std::string &callsign) const;
static CTraffic *s_instance;
static int preferences(const char *section, const char *name, int def);
static float preferences(const char *section, const char *name, float def);
XPMPConfiguration_t m_configuration = {};
void updateConfiguration();
static int orbitPlaneFunc(XPLMCameraPosition_t *cameraPosition, int isLosingControl, void *refcon);
static int drawCallback(XPLMDrawingPhase phase, int isBefore, void *refcon);
static int followAircraftKeySniffer(char character, XPLMKeyFlags flags, char virtualKey, void *refcon);
//! Remote aircraft
@@ -173,15 +169,14 @@ namespace XSwiftBus
std::string modelName;
std::string nightTextureMode;
bool hasSurfaces = false;
bool hasXpdr = false;
bool isOnGround = 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;
XPMPPlaneSurveillance_t surveillance;
Plane(void *id_, const std::string &callsign_, const std::string &aircraftIcao_, const std::string &airlineIcao_,
const std::string &livery_, const std::string &modelName_);
};
@@ -237,21 +232,9 @@ namespace XSwiftBus
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<CTraffic *>(self)->getPlaneData(id, dataType, io_data);
}
static void planeLoaded(void *id, bool succeeded, void *self)
{
auto *traffic = static_cast<CTraffic *>(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); }
}
std::vector<XPMPUpdate_t> m_updates;
void doPlaneUpdates();
void interpolateGear(Plane *);
};
} // ns

View File

@@ -14,17 +14,25 @@
#include "utils.h"
#include <XPMPMultiplayer.h>
#include <XPMPMultiplayerCSL.h>
#include <XPLM/XPLMUtilities.h>
#include <XPLM/XPLMPlugin.h>
#include <string>
#include <sstream>
#include <cassert>
#ifdef APL
#include <Carbon/Carbon.h>
#endif
namespace XSwiftBus
{
std::string g_xplanePath;
std::string g_sep;
#ifdef APL
int HFS2PosixPath(const char *path, char *result, int resultLen);
#endif
//! Init global xplane path
void initXPlanePath()
{
@@ -52,7 +60,7 @@ namespace XSwiftBus
assert(!filePath.empty());
std::ostringstream ss;
ss << XPMPTimestamp() << "xswiftbus: ";
ss << "xswiftbus: ";
#if defined(XSWIFTBUS_ENABLE_TRACE_LOG)
switch (type)
@@ -86,7 +94,7 @@ namespace XSwiftBus
ss << line;
ss << " : ";
#endif
#endif //XSWIFTBUS_ENABLE_TRACE_LOG
ss << message;
ss << "\n";
@@ -94,6 +102,47 @@ namespace XSwiftBus
const std::string buffer = ss.str();
XPLMDebugString(buffer.c_str());
}
#ifdef APL
template <typename T>
struct CFSmartPtr
{
CFSmartPtr(T p) : p_(p) {}
~CFSmartPtr() { if (p_) CFRelease(p_); }
operator T () { return p_; }
T p_;
};
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
int HFS2PosixPath(const char *path, char *result, int resultLen)
{
bool is_dir = (path[strlen(path)-1] == ':');
CFSmartPtr<CFStringRef> inStr(CFStringCreateWithCString(kCFAllocatorDefault, path ,kCFStringEncodingMacRoman));
if (inStr == nullptr) return -1;
CFSmartPtr<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, inStr, kCFURLHFSPathStyle,0));
if (url == nullptr) return -1;
CFSmartPtr<CFStringRef> outStr(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle));
if (outStr == nullptr) return -1;
if (!CFStringGetCString(outStr, result, resultLen, kCFStringEncodingMacRoman))
return -1;
if(is_dir) strcat(result, "/");
return 0;
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif //APL
}
//! \endcond

View File

@@ -37,8 +37,16 @@ HEADERS += $$files($$PWD/*.h)
# Using the $$files function so we can remove some with -= below
SOURCES += $$files(xplanemp2/src/*.cpp)
HEADERS += $$files(xplanemp2/src/*.h) $$files(xplanemp2/include/*.h)
INCLUDEPATH += ./xplanemp2 ./xplanemp2/include ./xplanemp2/src
SOURCES += $$files(xplanemp2/src/*.c)
HEADERS += $$files(xplanemp2/src/*.h)
SOURCES += $$files(xplanemp2/src/obj8/*.cpp)
HEADERS += $$files(xplanemp2/src/obj8/*.h)
HEADERS += $$files(xplanemp2/include/*.h)
INCLUDEPATH += ./xplanemp2 ./xplanemp2/include ./xplanemp2/src ./xplanemp2/obj8
!macx: SOURCES -= xplanemp2/src/AplFSUtil.cpp
unix:!macx {
INCLUDEPATH *= /usr/include/dbus-1.0
@@ -64,6 +72,10 @@ else: LIBS += -lpng -lz
msvc: DEFINES += _CRT_SECURE_NO_WARNINGS
!swiftConfig(allowNoisyWarnings) {
gcc|llvm:QMAKE_CXXFLAGS_WARN_ON *= -Wno-missing-field-initializers
}
# Required by X-Plane SDK and xplanemp2
win32:DEFINES += IBM=1
linux:DEFINES += LIN=1
@@ -71,6 +83,7 @@ macx:DEFINES += APL=1
DEFINES += XPLM200=1
DEFINES += XPLM210=1
DEFINES += XPLM300=1
DEFINES += XPLM_DEPRECATED=1
# Name will be used in xplanemp2 log messages
DEFINES += XPMP_CLIENT_NAME=\\\"xswiftbus\\\"