Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/flightgear into next
This commit is contained in:
commit
b0d707c3f4
15 changed files with 569 additions and 120 deletions
|
@ -24,10 +24,8 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
|
|||
set( OSG_MSVC ${OSG_MSVC}140 )
|
||||
elseif (${MSVC_VERSION} EQUAL 1800)
|
||||
set( OSG_MSVC ${OSG_MSVC}120 )
|
||||
elseif (${MSVC_VERSION} EQUAL 1700)
|
||||
set( OSG_MSVC ${OSG_MSVC}110 )
|
||||
elseif (${MSVC_VERSION} EQUAL 1600)
|
||||
set( OSG_MSVC ${OSG_MSVC}100 )
|
||||
else ()
|
||||
message(FATAL_ERROR "Visual Studio 2013/2015 is required now")
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CL_64)
|
||||
|
@ -39,24 +37,18 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
|
|||
set( BOOST_LIB lib )
|
||||
endif (CMAKE_CL_64)
|
||||
|
||||
GET_FILENAME_COMPONENT(MSVC_ROOT_PARENT_DIR ${MSVC_3RDPARTY_ROOT} PATH)
|
||||
set (CMAKE_LIBRARY_PATH ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib ${MSVC_3RDPARTY_ROOT}/install/${OSG_MSVC}/OpenScenegraph/lib ${MSVC_3RDPARTY_ROOT}/install/${OSG_MSVC}/OpenRTI/lib ${MSVC_3RDPARTY_ROOT}/install/${OSG_MSVC}/SimGear/lib $(BOOST_ROOT)/$(BOOST_LIB) )
|
||||
set (CMAKE_LIBRARY_PATH ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib ${MSVC_3RDPARTY_ROOT}/install/${OSG_MSVC}/OpenScenegraph/lib ${MSVC_3RDPARTY_ROOT}/install/${OSG_MSVC}/OpenRTI/lib ${MSVC_3RDPARTY_ROOT}/install/${OSG_MSVC}/SimGear/lib )
|
||||
set (CMAKE_INCLUDE_PATH ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include ${MSVC_3RDPARTY_ROOT}/install/${OSG_MSVC}/OpenScenegraph/include ${MSVC_3RDPARTY_ROOT}/install/${OSG_MSVC}/OpenRTI/include ${MSVC_3RDPARTY_ROOT}/install/${OSG_MSVC}/SimGear/include)
|
||||
find_path(BOOST_ROOT boost/version.hpp
|
||||
${MSVC_ROOT_PARENT_DIR}
|
||||
${MSVC_3RDPARTY_ROOT}/boost
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_52_0
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_51_0
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_50_0
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_49_0
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_48_0
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_47_0
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_46_1
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_46_0
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_45_0
|
||||
${MSVC_3RDPARTY_ROOT}/boost_1_44_0
|
||||
)
|
||||
message(STATUS "BOOST_ROOT is ${BOOST_ROOT}")
|
||||
|
||||
if(NOT BOOST_INCLUDEDIR)
|
||||
# if this variable was not set by the user, set it to 3rdparty root's
|
||||
# parent dir, which is the normal location for people using our
|
||||
# windows-3rd-party repo
|
||||
GET_FILENAME_COMPONENT(MSVC_ROOT_PARENT_DIR ${MSVC_3RDPARTY_ROOT} PATH)
|
||||
set(BOOST_INCLUDEDIR ${MSVC_ROOT_PARENT_DIR})
|
||||
message(STATUS "BOOST_INCLUDEDIR is ${BOOST_INCLUDEDIR}")
|
||||
endif()
|
||||
|
||||
if (USE_AEONWAVE)
|
||||
find_package(AAX COMPONENTS aax REQUIRED)
|
||||
else()
|
||||
|
|
|
@ -127,7 +127,9 @@ void FGFDM::init()
|
|||
_turb_magnitude_norm = fgGetNode("/environment/turbulence/magnitude-norm", true);
|
||||
_turb_rate_hz = fgGetNode("/environment/turbulence/rate-hz", true);
|
||||
_gross_weight_lbs = fgGetNode("/yasim/gross-weight-lbs", true);
|
||||
|
||||
_cg_x = fgGetNode("/yasim/cg-x-m", true);
|
||||
_cg_y = fgGetNode("/yasim/cg-y-m", true);
|
||||
_cg_z = fgGetNode("/yasim/cg-z-m", true);
|
||||
// Allows the user to start with something other than full fuel
|
||||
_airplane.setFuelFraction(fgGetFloat("/sim/fuel-fraction", 1));
|
||||
|
||||
|
@ -610,6 +612,12 @@ void FGFDM::setOutputProperties(float dt)
|
|||
float grossWgt = _airplane.getModel()->getBody()->getTotalMass() * KG2LBS;
|
||||
_gross_weight_lbs->setFloatValue(grossWgt);
|
||||
|
||||
float cg[3];
|
||||
_airplane.getModel()->getBody()->getCG(cg);
|
||||
_cg_x->setFloatValue(cg[0]);
|
||||
_cg_y->setFloatValue(cg[1]);
|
||||
_cg_z->setFloatValue(cg[2]);
|
||||
|
||||
ControlMap* cm = _airplane.getControlMap();
|
||||
for(int i=0; i<_controlProps.size(); i++) {
|
||||
PropOut* p = (PropOut*)_controlProps.get(i);
|
||||
|
|
|
@ -104,6 +104,9 @@ private:
|
|||
|
||||
SGPropertyNode_ptr _turb_magnitude_norm, _turb_rate_hz;
|
||||
SGPropertyNode_ptr _gross_weight_lbs;
|
||||
SGPropertyNode_ptr _cg_x;
|
||||
SGPropertyNode_ptr _cg_y;
|
||||
SGPropertyNode_ptr _cg_z;
|
||||
std::vector<SGPropertyNode_ptr> _tank_level_lbs;
|
||||
std::vector<ThrusterProps> _thrust_props;
|
||||
std::vector<FuelProps> _fuel_props;
|
||||
|
|
|
@ -144,9 +144,9 @@ void AircraftItem::toDataStream(QDataStream& ds) const
|
|||
for (int i=0; i<4; ++i) ds << ratings[i];
|
||||
}
|
||||
|
||||
QPixmap AircraftItem::thumbnail() const
|
||||
QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
||||
{
|
||||
if (m_thumbnail.isNull()) {
|
||||
if (m_thumbnail.isNull() && loadIfRequired) {
|
||||
QFileInfo info(path);
|
||||
QDir dir = info.dir();
|
||||
if (dir.exists("thumbnail.jpg")) {
|
||||
|
@ -346,7 +346,7 @@ protected:
|
|||
virtual void catalogRefreshed(CatalogRef aCatalog, StatusCode aReason)
|
||||
{
|
||||
if (aReason == STATUS_IN_PROGRESS) {
|
||||
qDebug() << "doing refresh of" << QString::fromStdString(aCatalog->url());
|
||||
// nothing to do
|
||||
} else if ((aReason == STATUS_REFRESHED) || (aReason == STATUS_SUCCESS)) {
|
||||
m_model->refreshPackages();
|
||||
} else {
|
||||
|
@ -402,19 +402,15 @@ protected:
|
|||
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT);
|
||||
}
|
||||
m_model->m_thumbnailPixmapCache.insert(QString::fromStdString(aThumbnailUrl),
|
||||
pix);
|
||||
m_model->m_thumbnailPixmapCache.insert(QString::fromStdString(aThumbnailUrl), pix);
|
||||
|
||||
// notify any affected items. Linear scan here avoids another map/dict
|
||||
// structure.
|
||||
PackageList::const_iterator it;
|
||||
int i = 0;
|
||||
|
||||
for (it=m_model->m_packages.begin(); it != m_model->m_packages.end(); ++it, ++i) {
|
||||
const string_list& urls((*it)->thumbnailUrls());
|
||||
string_list::const_iterator cit = std::find(urls.begin(), urls.end(), aThumbnailUrl);
|
||||
for (auto pkg : m_model->m_packages) {
|
||||
const string_list& urls(pkg->thumbnailUrls());
|
||||
auto cit = std::find(urls.begin(), urls.end(), aThumbnailUrl);
|
||||
if (cit != urls.end()) {
|
||||
QModelIndex mi(m_model->index(i + m_model->m_items.size()));
|
||||
QModelIndex mi = indexForPackage(pkg);
|
||||
m_model->dataChanged(mi, mi);
|
||||
}
|
||||
} // of packages iteration
|
||||
|
@ -423,9 +419,8 @@ protected:
|
|||
private:
|
||||
QModelIndex indexForPackage(const PackageRef& ref) const
|
||||
{
|
||||
PackageList::const_iterator it = std::find(m_model->m_packages.begin(),
|
||||
m_model->m_packages.end(),
|
||||
ref);
|
||||
auto it = std::find(m_model->m_packages.begin(),
|
||||
m_model->m_packages.end(), ref);
|
||||
if (it == m_model->m_packages.end()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
@ -480,12 +475,12 @@ void AircraftItemModel::setMessageWidgetVisible(bool vis)
|
|||
if (vis) {
|
||||
beginInsertRows(QModelIndex(), 0, 0);
|
||||
m_items.prepend(AircraftItemPtr(new AircraftItem));
|
||||
m_activeVariant.prepend(0);
|
||||
m_delegateStates.prepend(DelegateState());
|
||||
endInsertRows();
|
||||
} else {
|
||||
beginRemoveRows(QModelIndex(), 0, 0);
|
||||
m_items.removeAt(0);
|
||||
m_activeVariant.removeAt(0);
|
||||
m_delegateStates.removeAt(0);
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
@ -510,7 +505,7 @@ void AircraftItemModel::scanDirs()
|
|||
|
||||
beginRemoveRows(QModelIndex(), firstRow, lastRow);
|
||||
m_items.remove(firstRow, numToRemove);
|
||||
m_activeVariant.remove(firstRow, numToRemove);
|
||||
m_delegateStates.remove(firstRow, numToRemove);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
|
@ -545,8 +540,9 @@ void AircraftItemModel::abandonCurrentScan()
|
|||
void AircraftItemModel::refreshPackages()
|
||||
{
|
||||
simgear::pkg::PackageList newPkgs = m_packageRoot->allPackages();
|
||||
int firstRow = m_items.size();
|
||||
int newSize = newPkgs.size();
|
||||
const int firstRow = m_items.size();
|
||||
const int newSize = newPkgs.size();
|
||||
const int newTotalSize = firstRow + newSize;
|
||||
|
||||
if (m_packages.size() != newPkgs.size()) {
|
||||
int oldSize = m_packages.size();
|
||||
|
@ -556,7 +552,7 @@ void AircraftItemModel::refreshPackages()
|
|||
int lastNewRow = firstRow + newSize - 1;
|
||||
beginInsertRows(QModelIndex(), firstNewRow, lastNewRow);
|
||||
m_packages = newPkgs;
|
||||
m_packageVariant.resize(newSize);
|
||||
m_delegateStates.resize(newTotalSize);
|
||||
endInsertRows();
|
||||
} else {
|
||||
// shrinking
|
||||
|
@ -564,7 +560,7 @@ void AircraftItemModel::refreshPackages()
|
|||
int lastOldRow = firstRow + oldSize - 1;
|
||||
beginRemoveRows(QModelIndex(), firstOldRow, lastOldRow);
|
||||
m_packages = newPkgs;
|
||||
m_packageVariant.resize(newSize);
|
||||
m_delegateStates.resize(newTotalSize);
|
||||
endRemoveRows();
|
||||
}
|
||||
} else {
|
||||
|
@ -593,13 +589,16 @@ QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
|
|||
}
|
||||
}
|
||||
|
||||
if (row >= m_items.size()) {
|
||||
quint32 packageIndex = row - m_items.size();
|
||||
|
||||
if (role == AircraftVariantRole) {
|
||||
return m_packageVariant.at(packageIndex);
|
||||
return m_delegateStates.at(row).variant;
|
||||
}
|
||||
|
||||
if (role == AircraftCurrentThumbnailRole) {
|
||||
return m_delegateStates.at(row).thumbnail;
|
||||
}
|
||||
|
||||
if (row >= m_items.size()) {
|
||||
quint32 packageIndex = row - m_items.size();
|
||||
const PackageRef& pkg(m_packages[packageIndex]);
|
||||
InstallRef ex = pkg->existingInstall();
|
||||
|
||||
|
@ -609,20 +608,14 @@ QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
|
|||
return static_cast<quint64>(ex.valid() ? ex->downloadedBytes() : 0);
|
||||
}
|
||||
|
||||
quint32 variantIndex = m_packageVariant.at(packageIndex);
|
||||
return dataFromPackage(pkg, variantIndex, role);
|
||||
return dataFromPackage(pkg, m_delegateStates.at(row), role);
|
||||
} else {
|
||||
if (role == AircraftVariantRole) {
|
||||
return m_activeVariant.at(row);
|
||||
}
|
||||
|
||||
quint32 variantIndex = m_activeVariant.at(row);
|
||||
const AircraftItemPtr item(m_items.at(row));
|
||||
return dataFromItem(item, variantIndex, role);
|
||||
return dataFromItem(item, m_delegateStates.at(row), role);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, quint32 variantIndex, int role) const
|
||||
QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateState& state, int role) const
|
||||
{
|
||||
if (role == AircraftVariantCountRole) {
|
||||
return item->variants.count();
|
||||
|
@ -634,7 +627,7 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, quint32 variantIn
|
|||
}
|
||||
|
||||
if (role == AircraftThumbnailSizeRole) {
|
||||
return item->thumbnail().size();
|
||||
return item->thumbnail(false).size();
|
||||
}
|
||||
|
||||
if ((role >= AircraftVariantDescriptionRole) && (role < AircraftThumbnailRole)) {
|
||||
|
@ -642,10 +635,10 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, quint32 variantIn
|
|||
return item->variants.at(variantIndex)->description;
|
||||
}
|
||||
|
||||
if (variantIndex) {
|
||||
if (variantIndex <= static_cast<quint32>(item->variants.count())) {
|
||||
if (state.variant) {
|
||||
if (state.variant <= static_cast<quint32>(item->variants.count())) {
|
||||
// show the selected variant
|
||||
item = item->variants.at(variantIndex - 1);
|
||||
item = item->variants.at(state.variant - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -690,7 +683,7 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, quint32 variantIn
|
|||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, quint32 variantIndex, int role) const
|
||||
QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const DelegateState& state, int role) const
|
||||
{
|
||||
if (role == Qt::DecorationRole) {
|
||||
role = AircraftThumbnailRole; // use first thumbnail
|
||||
|
@ -706,7 +699,7 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, quint32 vari
|
|||
}
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
QString desc = QString::fromStdString(item->nameForVariant(variantIndex));
|
||||
QString desc = QString::fromStdString(item->nameForVariant(state.variant));
|
||||
if (desc.isEmpty()) {
|
||||
desc = tr("Missing description for: %1").arg(QString::fromStdString(item->id()));
|
||||
}
|
||||
|
@ -717,7 +710,7 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, quint32 vari
|
|||
return QString::fromStdString(i->primarySetPath().utf8Str());
|
||||
}
|
||||
} else if (role == AircraftPackageIdRole) {
|
||||
return QString::fromStdString(item->variants()[variantIndex]);
|
||||
return QString::fromStdString(item->variants()[state.variant]);
|
||||
} else if (role == AircraftPackageStatusRole) {
|
||||
InstallRef i = item->existingInstall();
|
||||
if (i.valid()) {
|
||||
|
@ -740,12 +733,15 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, quint32 vari
|
|||
// including the primary. Hence the -1 term.
|
||||
return static_cast<quint32>(item->variants().size() - 1);
|
||||
} else if (role == AircraftThumbnailSizeRole) {
|
||||
QPixmap pm = packageThumbnail(item, 0, false).value<QPixmap>();
|
||||
QPixmap pm = packageThumbnail(item, state, false).value<QPixmap>();
|
||||
if (pm.isNull())
|
||||
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
|
||||
return pm.size();
|
||||
} else if (role >= AircraftThumbnailRole) {
|
||||
return packageThumbnail(item , role - AircraftThumbnailRole);
|
||||
DelegateState changedState(state);
|
||||
// override the current thumbnail as required
|
||||
changedState.thumbnail = (role - AircraftThumbnailRole);
|
||||
return packageThumbnail(item, changedState);
|
||||
} else if (role == AircraftAuthorsRole) {
|
||||
SGPropertyNode* authors = item->properties()->getChild("author");
|
||||
if (authors) {
|
||||
|
@ -756,7 +752,7 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, quint32 vari
|
|||
} else if (role == AircraftPackageSizeRole) {
|
||||
return static_cast<int>(item->fileSizeBytes());
|
||||
} else if (role == AircraftURIRole) {
|
||||
return QUrl("package:" + QString::fromStdString(item->qualifiedVariantId(variantIndex)));
|
||||
return QUrl("package:" + QString::fromStdString(item->qualifiedVariantId(state.variant)));
|
||||
} else if (role == AircraftHasRatingsRole) {
|
||||
return item->properties()->hasChild("rating");
|
||||
} else if ((role >= AircraftRatingRole) && (role < AircraftVariantDescriptionRole)) {
|
||||
|
@ -771,14 +767,14 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, quint32 vari
|
|||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant AircraftItemModel::packageThumbnail(PackageRef p, int index, bool download) const
|
||||
QVariant AircraftItemModel::packageThumbnail(PackageRef p, const DelegateState& ds, bool download) const
|
||||
{
|
||||
const string_list& thumbnails(p->thumbnailUrls());
|
||||
if (index >= static_cast<int>(thumbnails.size())) {
|
||||
if (ds.thumbnail >= static_cast<int>(thumbnails.size())) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
std::string thumbnailUrl = thumbnails.at(index);
|
||||
std::string thumbnailUrl = thumbnails.at(ds.thumbnail);
|
||||
QString urlQString(QString::fromStdString(thumbnailUrl));
|
||||
if (m_thumbnailPixmapCache.contains(urlQString)) {
|
||||
// cache hit, easy
|
||||
|
@ -792,7 +788,7 @@ QVariant AircraftItemModel::packageThumbnail(PackageRef p, int index, bool downl
|
|||
const string_list& thumbNames(p->thumbnails());
|
||||
if (!thumbNames.empty()) {
|
||||
SGPath path(ex->path());
|
||||
path.append(p->thumbnails()[index]);
|
||||
path.append(p->thumbnails()[ds.thumbnail]);
|
||||
if (path.exists()) {
|
||||
QPixmap pix;
|
||||
pix.load(QString::fromStdString(path.utf8Str()));
|
||||
|
@ -809,20 +805,31 @@ QVariant AircraftItemModel::packageThumbnail(PackageRef p, int index, bool downl
|
|||
if (download) {
|
||||
m_packageRoot->requestThumbnailData(thumbnailUrl);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
int row = index.row();
|
||||
int newValue = value.toInt();
|
||||
|
||||
if (role == AircraftVariantRole) {
|
||||
if (row >= m_activeVariant.size()) {
|
||||
row -= m_activeVariant.size();
|
||||
m_packageVariant[row] = value.toInt();
|
||||
} else {
|
||||
m_activeVariant[row] = value.toInt();
|
||||
if (m_delegateStates[row].variant == newValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
m_delegateStates[row].variant = newValue;
|
||||
emit dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (role == AircraftCurrentThumbnailRole) {
|
||||
if (m_delegateStates[row].thumbnail == newValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
m_delegateStates[row].thumbnail = newValue;
|
||||
emit dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
|
@ -885,8 +892,9 @@ void AircraftItemModel::onScanResults()
|
|||
|
||||
// default variants in all cases
|
||||
for (int i=0; i< newItems.count(); ++i) {
|
||||
m_activeVariant.append(0);
|
||||
m_delegateStates.insert(firstRow + i, DelegateState());
|
||||
}
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ const int AircraftURIRole = Qt::UserRole + 14;
|
|||
const int AircraftThumbnailSizeRole = Qt::UserRole + 15;
|
||||
const int AircraftIsHelicopterRole = Qt::UserRole + 16;
|
||||
const int AircraftIsSeaplaneRole = Qt::UserRole + 17;
|
||||
const int AircraftCurrentThumbnailRole = Qt::UserRole + 18;
|
||||
|
||||
const int AircraftRatingRole = Qt::UserRole + 100;
|
||||
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
|
||||
|
@ -73,7 +74,7 @@ struct AircraftItem
|
|||
|
||||
void toDataStream(QDataStream& ds) const;
|
||||
|
||||
QPixmap thumbnail() const;
|
||||
QPixmap thumbnail(bool loadIfRequired = true) const;
|
||||
|
||||
bool excluded;
|
||||
QString path;
|
||||
|
@ -163,12 +164,23 @@ private slots:
|
|||
private:
|
||||
friend class PackageDelegate;
|
||||
|
||||
QVariant dataFromItem(AircraftItemPtr item, quint32 variantIndex, int role) const;
|
||||
/**
|
||||
* struct to record persistent state from the item-delegate, about the
|
||||
* currently visible variant, thumbnail and similar.
|
||||
*/
|
||||
struct DelegateState
|
||||
{
|
||||
quint32 variant = 0;
|
||||
quint32 thumbnail = 0;
|
||||
};
|
||||
|
||||
QVariant dataFromItem(AircraftItemPtr item, const DelegateState& state, int role) const;
|
||||
|
||||
QVariant dataFromPackage(const simgear::pkg::PackageRef& item,
|
||||
quint32 variantIndex, int role) const;
|
||||
const DelegateState& state, int role) const;
|
||||
|
||||
QVariant packageThumbnail(simgear::pkg::PackageRef p, int index, bool download = true) const;
|
||||
QVariant packageThumbnail(simgear::pkg::PackageRef p,
|
||||
const DelegateState& state, bool download = true) const;
|
||||
|
||||
void abandonCurrentScan();
|
||||
void refreshPackages();
|
||||
|
@ -182,8 +194,8 @@ private:
|
|||
PackageDelegate* m_delegate = nullptr;
|
||||
bool m_showMessageWidget = false;
|
||||
|
||||
QVector<quint32> m_activeVariant;
|
||||
QVector<quint32> m_packageVariant;
|
||||
|
||||
QVector<DelegateState> m_delegateStates;
|
||||
|
||||
simgear::pkg::RootRef m_packageRoot;
|
||||
simgear::pkg::PackageList m_packages;
|
||||
|
|
|
@ -131,6 +131,7 @@
|
|||
#include <Instrumentation/HUD/HUD.hxx>
|
||||
#include <Cockpit/cockpitDisplayManager.hxx>
|
||||
#include <Network/HTTPClient.hxx>
|
||||
#include <Network/DNSClient.hxx>
|
||||
#include <Network/fgcom.hxx>
|
||||
#include <Network/http/httpd.hxx>
|
||||
#include <Include/version.h>
|
||||
|
@ -735,6 +736,7 @@ void fgCreateSubsystems(bool duringReset) {
|
|||
if (!globals->get_subsystem<FGHTTPClient>()) {
|
||||
globals->add_new_subsystem<FGHTTPClient>();
|
||||
}
|
||||
globals->add_new_subsystem<FGDNSClient>();
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Initialize the flight model subsystem.
|
||||
|
|
|
@ -3,11 +3,13 @@ include(FlightGearComponent)
|
|||
set(SOURCES
|
||||
multiplaymgr.cxx
|
||||
tiny_xdr.cxx
|
||||
MPServerResolver.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
multiplaymgr.hxx
|
||||
tiny_xdr.hxx
|
||||
MPServerResolver.hxx
|
||||
)
|
||||
|
||||
flightgear_component(MultiPlayer "${SOURCES}" "${HEADERS}")
|
194
src/MultiPlayer/MPServerResolver.cxx
Normal file
194
src/MultiPlayer/MPServerResolver.cxx
Normal file
|
@ -0,0 +1,194 @@
|
|||
|
||||
/*
|
||||
MPServerResolver.cxx - mpserver names lookup via DNS
|
||||
Written and copyright by Torsten Dreyer - November 2016
|
||||
|
||||
This file is part of FlightGear.
|
||||
|
||||
FlightGear is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FlightGear is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FlightGear. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/#include "MPServerResolver.hxx"
|
||||
|
||||
#include <Network/DNSClient.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <3rdparty/cjson/cJSON.h>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace simgear;
|
||||
|
||||
/**
|
||||
* Build a name=value map from base64 encoded JSON string
|
||||
*/
|
||||
class MPServerProperties : public std::map<string, string> {
|
||||
public:
|
||||
MPServerProperties (string b64)
|
||||
{
|
||||
std::vector<unsigned char> b64dec;
|
||||
simgear::strutils::decodeBase64 (b64, b64dec);
|
||||
auto jsonString = string ((char*) b64dec.data (), b64dec.size ());
|
||||
cJSON * json = ::cJSON_Parse (jsonString.c_str ());
|
||||
if (json) {
|
||||
for (int i = 0; i < ::cJSON_GetArraySize (json); i++) {
|
||||
cJSON * cj = ::cJSON_GetArrayItem (json, i);
|
||||
if (cj->string && cj->valuestring)
|
||||
emplace (cj->string, cj->valuestring);
|
||||
}
|
||||
::cJSON_Delete (json);
|
||||
} else {
|
||||
SG_LOG(SG_NETWORK,SG_WARN, "MPServerResolver: Can't parse JSON string '" << jsonString << "'" );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MPServerResolver::MPServerResolver_priv {
|
||||
public:
|
||||
enum {
|
||||
INIT, LOADING_SRV_RECORDS, LOAD_NEXT_TXT_RECORD, LOADING_TXT_RECORDS, DONE,
|
||||
} _state = INIT;
|
||||
|
||||
FGDNSClient * _dnsClient = globals->get_subsystem<FGDNSClient> ();
|
||||
DNS::Request_ptr _dnsRequest;
|
||||
PropertyList _serverNodes;
|
||||
PropertyList::const_iterator _serverNodes_it;
|
||||
};
|
||||
|
||||
MPServerResolver::~MPServerResolver ()
|
||||
{
|
||||
delete _priv;
|
||||
}
|
||||
|
||||
MPServerResolver::MPServerResolver () :
|
||||
_priv (new MPServerResolver_priv ())
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MPServerResolver::run ()
|
||||
{
|
||||
//SG_LOG(SG_NETWORK, SG_DEBUG, "MPServerResolver::run() with state=" << _priv->_state );
|
||||
switch (_priv->_state) {
|
||||
// First call - fire DNS lookup for SRV records
|
||||
case MPServerResolver_priv::INIT:
|
||||
if (!_priv->_dnsClient) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "MPServerResolver: DNS subsystem not available.");
|
||||
onFailure ();
|
||||
return;
|
||||
}
|
||||
|
||||
_priv->_dnsRequest = new DNS::SRVRequest (_dnsName, _service, _protocol);
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "MPServerResolver: sending DNS request for " << _priv->_dnsRequest->getDn());
|
||||
_priv->_dnsClient->makeRequest (_priv->_dnsRequest);
|
||||
_priv->_state = MPServerResolver_priv::LOADING_SRV_RECORDS;
|
||||
break;
|
||||
|
||||
// Check if response from SRV Query
|
||||
case MPServerResolver_priv::LOADING_SRV_RECORDS:
|
||||
if (_priv->_dnsRequest->isTimeout ()) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Timeout waiting for DNS response. Query was: " << _priv->_dnsRequest->getDn());
|
||||
onFailure ();
|
||||
return;
|
||||
}
|
||||
if (_priv->_dnsRequest->isComplete ()) {
|
||||
// Create a child node under _targetNode for each SRV entry of the response
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "MPServerResolver: got DNS response for " << _priv->_dnsRequest->getDn());
|
||||
int idx = 0;
|
||||
for (DNS::SRVRequest::SRV_ptr entry : dynamic_cast<DNS::SRVRequest*> (_priv->_dnsRequest.get ())->entries) {
|
||||
SG_LOG(SG_NETWORK, SG_DEBUG,
|
||||
"MPServerResolver: SRV " << entry->priority << " " << entry->weight << " " << entry->port << " " << entry->target);
|
||||
if( 0 == entry->port ) {
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "MPServerResolver: Skipping offline host " << entry->target );
|
||||
continue;
|
||||
}
|
||||
SGPropertyNode * serverNode = _targetNode->getNode ("server", idx++, true);
|
||||
serverNode->getNode ("hostname", true)->setStringValue (entry->target);
|
||||
serverNode->getNode ("priority", true)->setIntValue (entry->priority);
|
||||
serverNode->getNode ("weight", true)->setIntValue (entry->weight);
|
||||
serverNode->getNode ("port", true)->setIntValue (entry->port);
|
||||
}
|
||||
|
||||
// prepare an iterator over the server-nodes to be used later when loading the TXT records
|
||||
_priv->_serverNodes = _targetNode->getChildren ("server");
|
||||
_priv->_serverNodes_it = _priv->_serverNodes.begin ();
|
||||
if (_priv->_serverNodes_it == _priv->_serverNodes.end ()) {
|
||||
// No SRV records found - flag failure
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "MPServerResolver: no multiplayer servers defined via DNS");
|
||||
onFailure ();
|
||||
return;
|
||||
}
|
||||
_priv->_state = MPServerResolver_priv::LOAD_NEXT_TXT_RECORD;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// get the next TXT record
|
||||
case MPServerResolver_priv::LOAD_NEXT_TXT_RECORD:
|
||||
if (_priv->_serverNodes_it == _priv->_serverNodes.end ()) {
|
||||
// we are done with all servers
|
||||
_priv->_state = MPServerResolver_priv::DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
// send the DNS query for the hostnames TXT record
|
||||
_priv->_dnsRequest = new DNS::TXTRequest ((*_priv->_serverNodes_it)->getStringValue ("hostname"));
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "MPServerResolver: sending DNS request for " << _priv->_dnsRequest->getDn());
|
||||
_priv->_dnsClient->makeRequest (_priv->_dnsRequest);
|
||||
_priv->_state = MPServerResolver_priv::LOADING_TXT_RECORDS;
|
||||
break;
|
||||
|
||||
// check if response for TXT query
|
||||
case MPServerResolver_priv::LOADING_TXT_RECORDS:
|
||||
if (_priv->_dnsRequest->isTimeout ()) {
|
||||
// on timeout, try proceeding with next server
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Timeout waiting for DNS response. Query was: " << _priv->_dnsRequest->getDn());
|
||||
_priv->_state = MPServerResolver_priv::LOAD_NEXT_TXT_RECORD;
|
||||
++_priv->_serverNodes_it;
|
||||
break;
|
||||
}
|
||||
if (_priv->_dnsRequest->isComplete ()) {
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "MPServerResolver: got DNS response for " << _priv->_dnsRequest->getDn());
|
||||
// DNS::TXTRequest automatically extracts name=value entries for us, lets retrieve them
|
||||
auto attributes = dynamic_cast<DNS::TXTRequest*> (_priv->_dnsRequest.get ())->attributes;
|
||||
auto mpserverAttribute = attributes["flightgear-mpserver"];
|
||||
if (!mpserverAttribute.empty ()) {
|
||||
// we are only interested in the 'flightgear-mpserver=something' entry, this is a base64 encoded
|
||||
// JSON string, convert this into a map<string,string>
|
||||
MPServerProperties mpserverProperties (mpserverAttribute);
|
||||
for (auto prop : mpserverProperties) {
|
||||
// and store each as a node under our servers node.
|
||||
SG_LOG(SG_NETWORK, SG_DEBUG, "MPServerResolver: TXT record attribute " << prop.first << "=" << prop.second);
|
||||
// sanitize property name, don't allow dots or forward slash
|
||||
auto propertyName = prop.first;
|
||||
std::replace( propertyName.begin(), propertyName.end(), '.', '_');
|
||||
std::replace( propertyName.begin(), propertyName.end(), '/', '_');
|
||||
(*_priv->_serverNodes_it)->setStringValue (propertyName, prop.second);
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "MPServerResolver: TXT record attributes empty");
|
||||
}
|
||||
|
||||
// procede with the net node
|
||||
++_priv->_serverNodes_it;
|
||||
_priv->_state = MPServerResolver_priv::LOAD_NEXT_TXT_RECORD;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case MPServerResolver_priv::DONE:
|
||||
onSuccess ();
|
||||
return;
|
||||
}
|
||||
|
||||
// Relinguish control, call me back on the next frame
|
||||
globals->get_event_mgr ()->addEvent ("MPServerResolver_update", this, &MPServerResolver::run, .0);
|
||||
}
|
||||
|
83
src/MultiPlayer/MPServerResolver.hxx
Normal file
83
src/MultiPlayer/MPServerResolver.hxx
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
MPServerResolver.hxx - mpserver names lookup via DNS
|
||||
Written and copyright by Torsten Dreyer - November 2016
|
||||
|
||||
This file is part of FlightGear.
|
||||
|
||||
FlightGear is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FlightGear is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FlightGear. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __FG_MPSERVERRESOLVER_HXX
|
||||
#define __FG_MPSERVERRESOLVER_HXX
|
||||
|
||||
#include <string>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
class MPServerResolver {
|
||||
public:
|
||||
MPServerResolver();
|
||||
virtual ~MPServerResolver();
|
||||
void run();
|
||||
|
||||
/**
|
||||
* Set the target property where the server-list gets stored
|
||||
*
|
||||
* \param value the property node to use as a target
|
||||
*/
|
||||
void setTarget( SGPropertyNode_ptr value ) { _targetNode = value; }
|
||||
|
||||
/**
|
||||
* Set the dns domain name to query. This could be either a full qualified name including the
|
||||
* service and the protocol like _fgms._udp.flightgear.org or just the domain name like
|
||||
* flightgear.org. Use setService() and setProtocol() in the latter case.
|
||||
*
|
||||
* \param value the dnsname to use for the query.
|
||||
*/
|
||||
void setDnsName( const std::string & value ) { _dnsName = value; }
|
||||
|
||||
/** Set the service name to use for the query. Don't add the underscore, this gets added
|
||||
* automatically. This builds the fully qualified DNS name to query, together with
|
||||
* setProtocol() and setDnsName().
|
||||
*
|
||||
* \param value the service name to use for the query sans the leading underscore
|
||||
*/
|
||||
void setService( const std::string & value ) { _service = value; }
|
||||
|
||||
/** Set the protocol name to use for the query. Don't add the underscore, this gets added
|
||||
* automatically. This builds the fully qualified DNS name to query, together with
|
||||
* setService() and setDnsName().
|
||||
*
|
||||
* \param value the protocol name to use for the query sans the leading underscore
|
||||
*/
|
||||
void setProtocol( const std::string & value ) { _protocol = value; }
|
||||
|
||||
/** Handler to be called if the resolver process finishes with success. Does nothing by
|
||||
* default and should be overridden be the user.
|
||||
*/
|
||||
virtual void onSuccess() {};
|
||||
|
||||
/** Handler to be called if the resolver process terminates with an error. Does nothing by
|
||||
* default and should be overridden be the user.
|
||||
*/
|
||||
virtual void onFailure() {};
|
||||
|
||||
private:
|
||||
class MPServerResolver_priv;
|
||||
std::string _dnsName;
|
||||
std::string _service;
|
||||
std::string _protocol;
|
||||
SGPropertyNode_ptr _targetNode;
|
||||
MPServerResolver_priv * _priv;
|
||||
};
|
||||
|
||||
#endif // __FG_MPSERVERRESOLVER_HXX
|
|
@ -41,14 +41,14 @@
|
|||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/commands.hxx>
|
||||
#include <simgear/structure/event_mgr.hxx>
|
||||
|
||||
#include <AIModel/AIManager.hxx>
|
||||
#include <AIModel/AIMultiplayer.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Network/RemoteXMLRequest.hxx>
|
||||
#include <Network/HTTPClient.hxx>
|
||||
#include "multiplaymgr.hxx"
|
||||
#include "mpmessages.hxx"
|
||||
#include "MPServerResolver.hxx"
|
||||
#include <FDM/flightProperties.hxx>
|
||||
|
||||
using namespace std;
|
||||
|
@ -428,39 +428,59 @@ static bool do_multiplayer_disconnect(const SGPropertyNode * arg) {
|
|||
// none
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
static bool do_multiplayer_refreshserverlist(const SGPropertyNode * arg) {
|
||||
|
||||
static bool
|
||||
do_multiplayer_refreshserverlist (const SGPropertyNode * arg)
|
||||
{
|
||||
using namespace simgear;
|
||||
|
||||
FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem ("mp");
|
||||
if (!self) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
|
||||
if (!http) {
|
||||
SG_LOG(SG_IO, SG_ALERT,
|
||||
"do_multiplayer.refreshserverlist: HTTP client not running");
|
||||
return false;
|
||||
// MPServerResolver implementation to fill the mp server list
|
||||
// deletes itself when done
|
||||
class MyMPServerResolver : public MPServerResolver {
|
||||
public:
|
||||
MyMPServerResolver () :
|
||||
MPServerResolver ()
|
||||
{
|
||||
setTarget (fgGetNode ("/sim/multiplay/server-list", true));
|
||||
setDnsName (fgGetString ("/sim/multiplay/dns/query-dn", "flightgear.org"));
|
||||
setService (fgGetString ("/sim/multiplay/dns/query-srv-service", "fgms"));
|
||||
setProtocol (fgGetString ("/sim/multiplay/dns/query-srv-protocol", "udp"));
|
||||
_completeNode->setBoolValue (false);
|
||||
_failureNode->setBoolValue (false);
|
||||
}
|
||||
|
||||
string url(
|
||||
fgGetString("/sim/multiplay/serverlist-url",
|
||||
"http://liveries.flightgear.org/mpstatus/mpservers.xml"));
|
||||
|
||||
if (url.empty()) {
|
||||
SG_LOG(SG_IO, SG_ALERT,
|
||||
"do_multiplayer.refreshserverlist: no URL given");
|
||||
return false;
|
||||
~MyMPServerResolver ()
|
||||
{
|
||||
}
|
||||
|
||||
SGPropertyNode *targetnode = fgGetNode("/sim/multiplay/server-list", true);
|
||||
SGPropertyNode *completeNode = fgGetNode("/sim/multiplay/got-servers", true);
|
||||
SGPropertyNode *failureNode = fgGetNode("/sim/multiplay/get-servers-failure", true);
|
||||
RemoteXMLRequest* req = new RemoteXMLRequest(url, targetnode);
|
||||
req->setCompletionProp(completeNode);
|
||||
req->setFailedProp(failureNode);
|
||||
completeNode->setBoolValue(false);
|
||||
failureNode->setBoolValue(false);
|
||||
http->makeRequest(req);
|
||||
virtual void
|
||||
onSuccess ()
|
||||
{
|
||||
SG_LOG(SG_NETWORK, SG_DEBUG, "MyMPServerResolver: trigger success");
|
||||
_completeNode->setBoolValue (true);
|
||||
delete this;
|
||||
}
|
||||
virtual void
|
||||
onFailure ()
|
||||
{
|
||||
SG_LOG(SG_NETWORK, SG_DEBUG, "MyMPServerResolver: trigger failure");
|
||||
_failureNode->setBoolValue (true);
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
SGPropertyNode *_completeNode = fgGetNode ("/sim/multiplay/got-servers", true);
|
||||
SGPropertyNode *_failureNode = fgGetNode ("/sim/multiplay/get-servers-failure", true);
|
||||
};
|
||||
|
||||
MyMPServerResolver * mpServerResolver = new MyMPServerResolver ();
|
||||
mpServerResolver->run ();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ set(SOURCES
|
|||
garmin.cxx
|
||||
generic.cxx
|
||||
HTTPClient.cxx
|
||||
DNSClient.cxx
|
||||
igc.cxx
|
||||
joyclient.cxx
|
||||
jsclient.cxx
|
||||
|
@ -39,6 +40,7 @@ set(HEADERS
|
|||
garmin.hxx
|
||||
generic.hxx
|
||||
HTTPClient.hxx
|
||||
DNSClient.hxx
|
||||
igc.hxx
|
||||
joyclient.hxx
|
||||
jsclient.hxx
|
||||
|
|
71
src/Network/DNSClient.cxx
Normal file
71
src/Network/DNSClient.cxx
Normal file
|
@ -0,0 +1,71 @@
|
|||
// HDNSClient.cxx -- Singleton DNS client object
|
||||
//
|
||||
// Written by James Turner, started April 2012.
|
||||
// Based on HTTPClient from James Turner
|
||||
// Copyright (C) 2012 James Turner
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include "DNSClient.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Include/version.h>
|
||||
|
||||
#include <simgear/sg_inlines.h>
|
||||
|
||||
|
||||
using namespace simgear;
|
||||
|
||||
FGDNSClient::FGDNSClient() :
|
||||
_inited(false)
|
||||
{
|
||||
}
|
||||
|
||||
FGDNSClient::~FGDNSClient()
|
||||
{
|
||||
}
|
||||
|
||||
void FGDNSClient::init()
|
||||
{
|
||||
if (_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dns.reset( new simgear::DNS::Client() );
|
||||
|
||||
_inited = true;
|
||||
}
|
||||
|
||||
void FGDNSClient::postinit()
|
||||
{
|
||||
}
|
||||
|
||||
void FGDNSClient::shutdown()
|
||||
{
|
||||
_dns.reset();
|
||||
_inited = false;
|
||||
}
|
||||
|
||||
void FGDNSClient::update(double)
|
||||
{
|
||||
_dns->update();
|
||||
}
|
||||
|
||||
void FGDNSClient::makeRequest(const simgear::DNS::Request_ptr& req)
|
||||
{
|
||||
_dns->makeRequest(req);
|
||||
}
|
52
src/Network/DNSClient.hxx
Normal file
52
src/Network/DNSClient.hxx
Normal file
|
@ -0,0 +1,52 @@
|
|||
// DNSClient.hxx -- Singleton DNS client object
|
||||
//
|
||||
// Written by Torsten Dreyer, started November 2016.
|
||||
// Based on HTTPClient from James Turner
|
||||
// Copyright (C) 2012 James Turner
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef FG_DNS_CLIENT_HXX
|
||||
#define FG_DNS_CLIENT_HXX
|
||||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/io/DNSClient.hxx>
|
||||
#include <memory>
|
||||
|
||||
class FGDNSClient : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
FGDNSClient();
|
||||
virtual ~FGDNSClient();
|
||||
|
||||
void makeRequest(const simgear::DNS::Request_ptr& req);
|
||||
|
||||
// simgear::HTTP::Client* client() { return _http.get(); }
|
||||
// simgear::HTTP::Client const* client() const { return _http.get(); }
|
||||
|
||||
virtual void init();
|
||||
virtual void postinit();
|
||||
virtual void shutdown();
|
||||
virtual void update(double);
|
||||
|
||||
static const char* subsystemName() { return "dns"; }
|
||||
private:
|
||||
bool _inited;
|
||||
std::unique_ptr<simgear::DNS::Client> _dns;
|
||||
};
|
||||
|
||||
#endif // FG_DNS_CLIENT_HXX
|
||||
|
||||
|
2
version
2
version
|
@ -1 +1 @@
|
|||
2016.4.0
|
||||
2017.1.0
|
||||
|
|
Loading…
Reference in a new issue