mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-23 23:45:35 +08:00
360 lines
21 KiB
C++
360 lines
21 KiB
C++
/* 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 and at http://www.swift-project.org/license.html. 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.
|
|
*/
|
|
|
|
#include "simulatorfsxcommon.h"
|
|
#include "blackcore/application.h"
|
|
#include "simconnectdatadefinition.h"
|
|
#include "blackmisc/simulation/fscommon/bcdconversions.h"
|
|
#include "blackmisc/simulation/fsx/simconnectutilities.h"
|
|
#include "blackmisc/simulation/simulatorplugininfo.h"
|
|
#include "blackmisc/aviation/airportlist.h"
|
|
#include "blackmisc/logmessage.h"
|
|
|
|
using namespace BlackCore;
|
|
using namespace BlackMisc;
|
|
using namespace BlackMisc::Simulation;
|
|
using namespace BlackMisc::Aviation;
|
|
using namespace BlackMisc::PhysicalQuantities;
|
|
using namespace BlackMisc::Geo;
|
|
using namespace BlackMisc::Network;
|
|
using namespace BlackMisc::Simulation;
|
|
using namespace BlackMisc::Simulation::FsCommon;
|
|
using namespace BlackMisc::Simulation::Fsx;
|
|
|
|
namespace BlackSimPlugin
|
|
{
|
|
namespace FsxCommon
|
|
{
|
|
void CALLBACK CSimulatorFsxCommon::SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext)
|
|
{
|
|
// IMPORTANT:
|
|
// all tasks called in this function (ie all called functions) must perform fast or shall be called asynchronously
|
|
|
|
CSimulatorFsxCommon *simulatorFsxP3D = static_cast<CSimulatorFsxCommon *>(pContext);
|
|
const SIMCONNECT_RECV_ID recvId = static_cast<SIMCONNECT_RECV_ID>(pData->dwID);
|
|
simulatorFsxP3D->m_dispatchLastReceiveId = recvId;
|
|
switch (recvId)
|
|
{
|
|
case SIMCONNECT_RECV_ID_OPEN:
|
|
{
|
|
SIMCONNECT_RECV_OPEN *event = (SIMCONNECT_RECV_OPEN *)pData;
|
|
simulatorFsxP3D->m_simulatorVersion = QString("%1.%2.%3.%4").arg(event->dwApplicationVersionMajor).arg(event->dwApplicationVersionMinor).arg(event->dwApplicationBuildMajor).arg(event->dwApplicationBuildMinor);
|
|
simulatorFsxP3D->m_simConnectVersion = QString("%1.%2.%3.%4").arg(event->dwSimConnectVersionMajor).arg(event->dwSimConnectVersionMinor).arg(event->dwSimConnectBuildMajor).arg(event->dwSimConnectBuildMinor);
|
|
simulatorFsxP3D->m_simulatorName = CSimulatorFsxCommon::fsxCharToQString(event->szApplicationName);
|
|
simulatorFsxP3D->m_simulatorDetails = QString("Name: '%1' Version: %2 SimConnect: %3").arg(simulatorFsxP3D->m_simulatorName, simulatorFsxP3D->m_simulatorVersion, simulatorFsxP3D->m_simConnectVersion);
|
|
CLogMessage(static_cast<CSimulatorFsxCommon *>(nullptr)).info("Connected to %1: '%2'") << simulatorFsxP3D->getSimulatorPluginInfo().getIdentifier() << simulatorFsxP3D->m_simulatorDetails;
|
|
simulatorFsxP3D->setSimConnected();
|
|
break; // SIMCONNECT_RECV_ID_OPEN
|
|
}
|
|
case SIMCONNECT_RECV_ID_EXCEPTION:
|
|
{
|
|
if (!simulatorFsxP3D->stillDisplayReceiveExceptions()) { break; }
|
|
SIMCONNECT_RECV_EXCEPTION *exception = (SIMCONNECT_RECV_EXCEPTION *)pData;
|
|
const DWORD exceptionId = exception->dwException;
|
|
const DWORD sendId = exception->dwSendID;
|
|
const DWORD index = exception->dwIndex;
|
|
const DWORD data = cbData;
|
|
switch (exceptionId)
|
|
{
|
|
case SIMCONNECT_EXCEPTION_OPERATION_INVALID_FOR_OBJECT_TYPE: break;
|
|
case SIMCONNECT_EXCEPTION_UNRECOGNIZED_ID: break;
|
|
case SIMCONNECT_EXCEPTION_CREATE_OBJECT_FAILED: break;
|
|
default: break;
|
|
}
|
|
QString ex;
|
|
ex.sprintf("Exception=%lu | SendID=%lu | Index=%lu | cbData=%lu", exceptionId, sendId, index, data);
|
|
const QString exceptionString(CSimConnectUtilities::simConnectExceptionToString((SIMCONNECT_EXCEPTION)exception->dwException));
|
|
const QString sendIdDetails = simulatorFsxP3D->getSendIdTraceDetails(sendId);
|
|
CLogMessage(simulatorFsxP3D).warning("Caught simConnect exception: '%1' '%2' | send details: '%3'")
|
|
<< exceptionString << ex
|
|
<< (sendIdDetails.isEmpty() ? "N/A" : sendIdDetails);
|
|
simulatorFsxP3D->triggerAutoTraceSendId();
|
|
break; // SIMCONNECT_RECV_ID_EXCEPTION
|
|
}
|
|
case SIMCONNECT_RECV_ID_QUIT:
|
|
{
|
|
simulatorFsxP3D->onSimExit();
|
|
break;
|
|
}
|
|
case SIMCONNECT_RECV_ID_EVENT:
|
|
{
|
|
const SIMCONNECT_RECV_EVENT *event = static_cast<SIMCONNECT_RECV_EVENT *>(pData);
|
|
switch (event->uEventID)
|
|
{
|
|
case SystemEventSimStatus:
|
|
{
|
|
const bool running = event->dwData ? true : false;
|
|
if (running)
|
|
{
|
|
simulatorFsxP3D->onSimRunning();
|
|
}
|
|
else
|
|
{
|
|
simulatorFsxP3D->onSimStopped();
|
|
}
|
|
break;
|
|
}
|
|
case SystemEventPause:
|
|
{
|
|
const bool p = event->dwData ? true : false;
|
|
if (simulatorFsxP3D->m_simPaused != p)
|
|
{
|
|
simulatorFsxP3D->m_simPaused = p;
|
|
simulatorFsxP3D->emitSimulatorCombinedStatus();
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break; // SIMCONNECT_RECV_ID_EVENT
|
|
}
|
|
case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE:
|
|
{
|
|
const SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *event = static_cast<SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *>(pData);
|
|
const DWORD objectId = event->dwData;
|
|
const SIMCONNECT_SIMOBJECT_TYPE objectType = event->eObjType;
|
|
if (objectType != SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT && objectType != SIMCONNECT_SIMOBJECT_TYPE_HELICOPTER)
|
|
{
|
|
break; // SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE
|
|
}
|
|
|
|
// such an object is not necessarily one of ours
|
|
// for instance, I always see object "5" when I start the simulator
|
|
if (simulatorFsxP3D->getSimConnectObjects().isKnownSimObjectId(objectId))
|
|
{
|
|
switch (event->uEventID)
|
|
{
|
|
case SystemEventObjectRemoved:
|
|
simulatorFsxP3D->simulatorReportedObjectRemoved(objectId);
|
|
break;
|
|
case SystemEventObjectAdded: // added in SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if (simulatorFsxP3D->getSimConnectProbes().isKnownSimObjectId(objectId))
|
|
{
|
|
switch (event->uEventID)
|
|
{
|
|
case SystemEventObjectRemoved:
|
|
CLogMessage(simulatorFsxP3D).info("Removed probe id: %2") << objectId;
|
|
simulatorFsxP3D->m_simConnectProbes.removeByObjectId(objectId);
|
|
break;
|
|
case SystemEventObjectAdded: // added in SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break; // SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE
|
|
}
|
|
case SIMCONNECT_RECV_ID_EVENT_FRAME:
|
|
{
|
|
const SIMCONNECT_RECV_EVENT_FRAME *event = (SIMCONNECT_RECV_EVENT_FRAME *) pData;
|
|
switch (event->uEventID)
|
|
{
|
|
case SystemEventFrame:
|
|
// doing interpolation
|
|
simulatorFsxP3D->onSimFrame();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break; // SIMCONNECT_RECV_ID_EVENT_FRAME
|
|
}
|
|
case SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID:
|
|
{
|
|
const SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast<SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *>(pData);
|
|
const DWORD requestId = event->dwRequestID;
|
|
const DWORD objectId = event->dwObjectID;
|
|
|
|
bool success = false;
|
|
if (CSimulatorFsxCommon::isRequestForProbe(requestId))
|
|
{
|
|
success = simulatorFsxP3D->setSimConnectProbeId(requestId, objectId);
|
|
if (!success) { break; } // not an request ID of ours
|
|
success = simulatorFsxP3D->simulatorReportedProbeAdded(objectId);
|
|
const CSimConnectObject simObject = simulatorFsxP3D->getSimConnectProbes().getSimObjectForObjectId(objectId);
|
|
if (success)
|
|
{
|
|
CLogMessage(simulatorFsxP3D).info("Added probe '%1' id: %2") << simObject.getCallsign() << objectId;
|
|
}
|
|
else
|
|
{
|
|
CLogMessage(simulatorFsxP3D).error("Cannot add probe '%1' id: %2") << simObject.getCallsign() << objectId;
|
|
}
|
|
}
|
|
else if (CSimulatorFsxCommon::isRequestForSimData(requestId))
|
|
{
|
|
success = simulatorFsxP3D->setSimConnectObjectId(requestId, objectId);
|
|
if (!success) { break; } // not an request ID of ours
|
|
success = simulatorFsxP3D->simulatorReportedObjectAdded(objectId); // trigger follow up actions
|
|
if (!success)
|
|
{
|
|
const CSimConnectObject simObj = simulatorFsxP3D->getSimConnectObjects().getSimObjectForObjectId(objectId);
|
|
const CSimulatedAircraft remoteAircraft(simObj.getAircraft());
|
|
const CStatusMessage msg = CStatusMessage(simulatorFsxP3D).error("Cannot add object %1, cs: '%2' model: '%3'") << objectId << remoteAircraft.getCallsignAsString() << remoteAircraft.getModelString();
|
|
CLogMessage::preformatted(msg);
|
|
emit simulatorFsxP3D->physicallyAddingRemoteModelFailed(remoteAircraft, msg);
|
|
}
|
|
}
|
|
break; // SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID
|
|
}
|
|
case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE:
|
|
{
|
|
// SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *)pData;
|
|
break;
|
|
}
|
|
case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
|
|
{
|
|
const SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA *) pData;
|
|
const DWORD requestId = pObjData->dwRequestID;
|
|
|
|
switch (requestId)
|
|
{
|
|
case CSimConnectDefinitions::RequestOwnAircraft:
|
|
{
|
|
static_assert(sizeof(DataDefinitionOwnAircraft) == 31 * sizeof(double), "DataDefinitionOwnAircraft has an incorrect size.");
|
|
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestOwnAircraft;
|
|
const DataDefinitionOwnAircraft *ownAircaft = (DataDefinitionOwnAircraft *)&pObjData->dwData;
|
|
simulatorFsxP3D->updateOwnAircraftFromSimulator(*ownAircaft);
|
|
break;
|
|
}
|
|
case CSimConnectDefinitions::RequestOwnAircraftTitle:
|
|
{
|
|
const DataDefinitionOwnAircraftModel *dataDefinitionModel = (DataDefinitionOwnAircraftModel *) &pObjData->dwData;
|
|
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestOwnAircraftTitle;
|
|
const CAircraftModel model(dataDefinitionModel->title, CAircraftModel::TypeOwnSimulatorModel);
|
|
simulatorFsxP3D->reverseLookupAndUpdateOwnAircraftModel(model);
|
|
break;
|
|
}
|
|
case CSimConnectDefinitions::RequestSimEnvironment:
|
|
{
|
|
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestSimEnvironment;
|
|
const DataDefinitionSimEnvironment *simEnv = (DataDefinitionSimEnvironment *) &pObjData->dwData;
|
|
if (simulatorFsxP3D->isTimeSynchronized())
|
|
{
|
|
const int zh = simEnv->zuluTimeSeconds / 3600;
|
|
const int zm = (simEnv->zuluTimeSeconds - (zh * 3600)) / 60;
|
|
const CTime zulu(zh, zm);
|
|
const int lh = simEnv->localTimeSeconds / 3600;
|
|
const int lm = (simEnv->localTimeSeconds - (lh * 3600)) / 60;
|
|
const CTime local(lh, lm);
|
|
simulatorFsxP3D->synchronizeTime(zulu, local);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
const DWORD objectId = pObjData->dwObjectID;
|
|
if (CSimulatorFsxCommon::isRequestForSimData(requestId))
|
|
{
|
|
static_assert(sizeof(DataDefinitionRemoteAircraftSimData) == 5 * sizeof(double), "DataDefinitionRemoteAircraftSimData has an incorrect size.");
|
|
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestRangeForSimData;
|
|
const CSimConnectObject simObject = simulatorFsxP3D->getSimObjectForObjectId(objectId);
|
|
if (!simObject.hasValidRequestAndObjectId()) { break; }
|
|
const DataDefinitionRemoteAircraftSimData *remoteAircraftSimData = (DataDefinitionRemoteAircraftSimData *)&pObjData->dwData;
|
|
// extra check, but ids should be the same
|
|
if (objectId == simObject.getObjectId())
|
|
{
|
|
simulatorFsxP3D->updateRemoteAircraftFromSimulator(simObj, *remoteAircraftSimData);
|
|
}
|
|
}
|
|
else if (CSimulatorFsxCommon::isRequestForProbe(requestId))
|
|
{
|
|
static_assert(sizeof(DataDefinitionRemoteAircraftSimData) == 5 * sizeof(double), "DataDefinitionRemoteAircraftSimData has an incorrect size.");
|
|
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestRangeForProbe;
|
|
const CSimConnectObject probeObj = simulatorFsxP3D->getSimConnectProbes().getSimObjectForObjectId(objectId);
|
|
if (!probeObj.hasValidRequestAndObjectId()) { break; }
|
|
const DataDefinitionRemoteAircraftSimData *probeSimData = (DataDefinitionRemoteAircraftSimData *)&pObjData->dwData;
|
|
// extra check, but ids should be the same
|
|
if (objectId == probeObj.getObjectId())
|
|
{
|
|
const CCallsign cs = simulatorFsxP3D->m_pendingProbeRequests.value(requestId);
|
|
if (cs.isEmpty()) { break; }
|
|
simulatorFsxP3D->updateProbeFromSimulator(cs, *probeSimData);
|
|
}
|
|
}
|
|
else if (CSimulatorFsxCommon::isRequestForLights(requestId))
|
|
{
|
|
static_assert(sizeof(DataDefinitionRemoteAircraftLights) == 8 * sizeof(double), "DataDefinitionRemoteAircraftLights has an incorrect size.");
|
|
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestRangeForLights;
|
|
const CSimConnectObject simObj = simulatorFsxP3D->getSimConnectObjects().getSimObjectForObjectId(objectId);
|
|
if (!simObj.hasValidRequestAndObjectId()) break;
|
|
const DataDefinitionRemoteAircraftLights *remoteAircraftLights = (DataDefinitionRemoteAircraftLights *)&pObjData->dwData;
|
|
// extra check, but ids should be the same
|
|
if (objectId == simObj.getObjectId())
|
|
{
|
|
const CCallsign callsign(simObj.getCallsign());
|
|
const CAircraftLights lights(remoteAircraftLights->toLights()); // as in simulator
|
|
simulatorFsxP3D->setCurrentLights(callsign, lights);
|
|
if (simObj.getLightsAsSent().isNull())
|
|
{
|
|
// allows to compare for toggle
|
|
simulatorFsxP3D->setLightsAsSent(callsign, lights);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break; // SIMCONNECT_RECV_ID_SIMOBJECT_DATA
|
|
}
|
|
case SIMCONNECT_RECV_ID_AIRPORT_LIST:
|
|
{
|
|
const SIMCONNECT_RECV_AIRPORT_LIST *pAirportList = (SIMCONNECT_RECV_AIRPORT_LIST *) pData;
|
|
CAirportList simAirports;
|
|
for (unsigned i = 0; i < pAirportList->dwArraySize; ++i)
|
|
{
|
|
const SIMCONNECT_DATA_FACILITY_AIRPORT *pFacilityAirport = pAirportList->rgData + i;
|
|
if (!pFacilityAirport) { break; }
|
|
const QString icao(pFacilityAirport->Icao);
|
|
if (icao.isEmpty()) { continue; } // airfield without ICAO code
|
|
if (!CAirportIcaoCode::isValidIcaoDesignator(icao)) { continue; } // tiny airfields/strips in simulator
|
|
if (CAirportIcaoCode::containsNumbers(icao)) { continue; } // tiny airfields/strips in simulator
|
|
const CCoordinateGeodetic pos(pFacilityAirport->Latitude, pFacilityAirport->Longitude, pFacilityAirport->Altitude);
|
|
const CAirport airport(CAirportIcaoCode(icao), pos);
|
|
simAirports.push_back(airport);
|
|
}
|
|
if (!simAirports.isEmpty())
|
|
{
|
|
simulatorFsxP3D->triggerUpdateAirports(simAirports); // real "work" outside SimConnectProc
|
|
}
|
|
break; // SIMCONNECT_RECV_ID_AIRPORT_LIST
|
|
}
|
|
case SIMCONNECT_RECV_ID_CLIENT_DATA:
|
|
{
|
|
if (!simulatorFsxP3D->m_useSbOffsets) { break; }
|
|
const SIMCONNECT_RECV_CLIENT_DATA *clientData = (SIMCONNECT_RECV_CLIENT_DATA *)pData;
|
|
if (simulatorFsxP3D->m_useSbOffsets && clientData->dwRequestID == CSimConnectDefinitions::RequestSbData)
|
|
{
|
|
//! \fixme FSUIPC vs SimConnect why is offset 19 ident 2/0? In FSUIPC it is 0/1, according to documentation it is 0/1 but I receive 2/0 here. Whoever knows, add comment or fix if wrong
|
|
DataDefinitionClientAreaSb *sbData = (DataDefinitionClientAreaSb *) &clientData->dwData;
|
|
simulatorFsxP3D->updateOwnAircraftFromSimulator(*sbData);
|
|
}
|
|
break; // SIMCONNECT_RECV_ID_CLIENT_DATA
|
|
}
|
|
case SIMCONNECT_RECV_ID_EVENT_FILENAME:
|
|
{
|
|
const SIMCONNECT_RECV_EVENT_FILENAME *event = static_cast<SIMCONNECT_RECV_EVENT_FILENAME *>(pData);
|
|
switch (event->uEventID)
|
|
{
|
|
case SystemEventFlightLoaded: break;
|
|
default: break;
|
|
}
|
|
break; // SIMCONNECT_RECV_ID_EVENT_FILENAME
|
|
}
|
|
default:
|
|
break;
|
|
} // main switch
|
|
} // method
|
|
} // namespace
|
|
} // namespace
|