1
0
Fork 0

Fallback AI model implementation

Aircraft can now set a /sim/model/fallback-model-index property that is transmitted over the MP network.

Receiving clients use this as an index into AI/Aircraft/fallback_models.xml to determine a model to use if the model path (/sim/model/path) cannot be found under Aircraft or AI/Aircraft.  This allows aircraft developers to identify a suitable fallback model to be used for those who do not have their aircraft installed.
This commit is contained in:
Stuart Buchanan 2018-07-27 19:51:37 +01:00
parent 23196184cc
commit e43fe82094
7 changed files with 149 additions and 105 deletions

View file

@ -244,6 +244,8 @@ void FGAIBase::readFromScenario(SGPropertyNode* scFileNode)
setPath(scFileNode->getStringValue("model", setPath(scFileNode->getStringValue("model",
fgGetString("/sim/multiplay/default-model", default_model))); fgGetString("/sim/multiplay/default-model", default_model)));
setFallbackModelIndex(scFileNode->getIntValue("fallback-model-index", 0));
setHeading(scFileNode->getDoubleValue("heading", 0.0)); setHeading(scFileNode->getDoubleValue("heading", 0.0));
setSpeed(scFileNode->getDoubleValue("speed", 0.0)); setSpeed(scFileNode->getDoubleValue("speed", 0.0));
setAltitude(scFileNode->getDoubleValue("altitude", 0.0)); setAltitude(scFileNode->getDoubleValue("altitude", 0.0));
@ -446,24 +448,51 @@ std::vector<std::string> FGAIBase::resolveModelPath(ModelSearchOrder searchOrder
std::vector<std::string> path_list; std::vector<std::string> path_list;
if (searchOrder == DATA_ONLY) { if (searchOrder == DATA_ONLY) {
SG_LOG(SG_AI, SG_DEBUG, "Resolving model path: DATA only");
auto p = simgear::SGModelLib::findDataFile(model_path); auto p = simgear::SGModelLib::findDataFile(model_path);
if (!p.empty()) { if (!p.empty()) {
// We've got a model, use it // We've got a model, use it
_installed = true; _installed = true;
SG_LOG(SG_AI, SG_DEBUG, "Found model " << p);
path_list.push_back(p); path_list.push_back(p);
} else { } else {
// No model, so fall back to the default // No model, so fall back to the default
path_list.push_back(fgGetString("/sim/multiplay/default-model", default_model)); path_list.push_back(fgGetString("/sim/multiplay/default-model", default_model));
} }
} else { } else {
SG_LOG(SG_AI, SG_DEBUG, "Resolving model path: PREFER_AI/PREFER_DATA");
// We're either PREFER_AI or PREFER_DATA. Find an AI model first. // We're either PREFER_AI or PREFER_DATA. Find an AI model first.
for (SGPath p : globals->get_data_paths("AI")) { for (SGPath p : globals->get_data_paths("AI")) {
p.append(model_path); p.append(model_path);
if (p.exists()) { if (p.exists()) {
SG_LOG(SG_AI, SG_DEBUG, "Found AI model: " << p.local8BitStr());
path_list.push_back(p.local8BitStr()); path_list.push_back(p.local8BitStr());
break; break;
} }
} // of AI data paths iteration }
if (path_list.empty()) {
// Fall back on the fallback-model-index which is a lookup into
// /sim/multiplay/fallback-models/model[]
std::string fallback_path;
const SGPropertyNode* fallbackNode =
globals->get_props()->getNode("/sim/multiplay/fallback-models/model", _getFallbackModelIndex(), false);
if (fallbackNode != NULL) {
fallback_path = fallbackNode->getStringValue();
} else {
fallback_path = globals->get_props()->getNode("/sim/multiplay/fallback-models/model", 0, true)->getStringValue();
}
for (SGPath p : globals->get_data_paths()) {
p.append(fallback_path);
if (p.exists()) {
SG_LOG(SG_AI, SG_DEBUG, "Found fallback model path for index " << _fallback_model_index << ": " << p.local8BitStr());
path_list.push_back(p.local8BitStr());
break;
}
}
}
if ((searchOrder == PREFER_AI) && !path_list.empty()) { if ((searchOrder == PREFER_AI) && !path_list.empty()) {
// if we prefer AI, and we've got a valid AI path from above, then use it, we're done // if we prefer AI, and we've got a valid AI path from above, then use it, we're done
@ -471,18 +500,13 @@ std::vector<std::string> FGAIBase::resolveModelPath(ModelSearchOrder searchOrder
return path_list; return path_list;
} }
// At this point we've either still to find a valid path, or we're // At this point we're looking for a regular model to display at closer range.
// looking for a regular model to display at closer range.
auto p = simgear::SGModelLib::findDataFile(model_path); auto p = simgear::SGModelLib::findDataFile(model_path);
if (!p.empty()) { if (!p.empty()) {
_installed = true; _installed = true;
SG_LOG(SG_AI, SG_DEBUG, "Found DATA model " << p);
path_list.insert(path_list.begin(), p); path_list.insert(path_list.begin(), p);
} }
if (path_list.empty()) {
// No model found at all, so fall back to the default
path_list.push_back(fgGetString("/sim/multiplay/default-model", default_model));
}
} }
/* /*
@ -503,10 +527,10 @@ bool FGAIBase::init(ModelSearchOrder searchOrder)
return false; return false;
} }
vector<string> model_list = resolveModelPath(searchOrder);
props->addChild("type")->setStringValue("AI"); props->addChild("type")->setStringValue("AI");
_modeldata = new FGAIModelData(props); _modeldata = new FGAIModelData(props);
vector<string> model_list = resolveModelPath(searchOrder);
_model= SGModelLib::loadPagedModel(model_list, props, _modeldata); _model= SGModelLib::loadPagedModel(model_list, props, _modeldata);
_model->setName("AI-model range animation node"); _model->setName("AI-model range animation node");
@ -982,6 +1006,10 @@ const char* FGAIBase::_getSubmodel() const {
return _submodel.c_str(); return _submodel.c_str();
} }
const int FGAIBase::_getFallbackModelIndex() const {
return _fallback_model_index;
}
void FGAIBase::CalculateMach() { void FGAIBase::CalculateMach() {
// Calculate rho at altitude, using standard atmosphere // Calculate rho at altitude, using standard atmosphere
// For the temperature T and the pressure p, // For the temperature T and the pressure p,

View file

@ -74,6 +74,7 @@ public:
void updateInterior(); void updateInterior();
void setManager(FGAIManager* mgr, SGPropertyNode* p); void setManager(FGAIManager* mgr, SGPropertyNode* p);
void setPath( const char* model ); void setPath( const char* model );
void setFallbackModelIndex(const int i );
void setSMPath( const std::string& p ); void setSMPath( const std::string& p );
void setCallSign(const std::string& ); void setCallSign(const std::string& );
void setSpeed( double speed_KTAS ); void setSpeed( double speed_KTAS );
@ -208,7 +209,8 @@ protected:
double rotation; // value used by radar display instrument double rotation; // value used by radar display instrument
double ht_diff; // value used by radar display instrument double ht_diff; // value used by radar display instrument
std::string model_path; //Path to the 3D model std::string model_path; // Path to the 3D model
int _fallback_model_index; // Index into /sim/multiplay/fallback-models[]
SGModelPlacement aip; SGModelPlacement aip;
bool delete_me; bool delete_me;
@ -316,10 +318,9 @@ public:
const char* _getTriggerNode() const; const char* _getTriggerNode() const;
const char* _getName() const; const char* _getName() const;
const char* _getSubmodel() const; const char* _getSubmodel() const;
const int _getFallbackModelIndex() const;
// These are used in the Mach number calculations // These are used in the Mach number calculations
double rho; double rho;
double T; // temperature, degs farenheit double T; // temperature, degs farenheit
double p; // pressure lbs/sq ft double p; // pressure lbs/sq ft
@ -348,6 +349,10 @@ inline void FGAIBase::setPath(const char* model ) {
model_path.append(model); model_path.append(model);
} }
inline void FGAIBase::setFallbackModelIndex(const int i ) {
_fallback_model_index = i;
}
inline void FGAIBase::setSMPath(const std::string& p) { inline void FGAIBase::setSMPath(const std::string& p) {
_path = p; _path = p;
} }

View file

@ -134,8 +134,6 @@ FGAIManager::init() {
globals->get_commands()->addCommand("unload-scenario", this, &FGAIManager::unloadScenarioCommand); globals->get_commands()->addCommand("unload-scenario", this, &FGAIManager::unloadScenarioCommand);
_environmentVisiblity = fgGetNode("/environment/visibility-m"); _environmentVisiblity = fgGetNode("/environment/visibility-m");
_mp_use_detailed_models = fgGetNode("/sim/multiplay/use-detailed-models", true);
// Create an (invisible) AIAircraft representation of the current // Create an (invisible) AIAircraft representation of the current
// users's aircraft, that mimicks the user aircraft's behavior. // users's aircraft, that mimicks the user aircraft's behavior.
@ -315,7 +313,7 @@ FGAIManager::attach(FGAIBase *model)
modelPolicy = FGAIBase::PREFER_AI; modelPolicy = FGAIBase::PREFER_AI;
break; break;
case FGAIBase::otMultiplayer: case FGAIBase::otMultiplayer:
modelPolicy = this->_mp_use_detailed_models->getBoolValue() ? FGAIBase::PREFER_DATA : FGAIBase::PREFER_AI; modelPolicy = FGAIBase::PREFER_DATA;
break; break;
default: default:
break; break;

View file

@ -120,8 +120,6 @@ private:
SGPropertyNode_ptr wind_from_east_node; SGPropertyNode_ptr wind_from_east_node;
SGPropertyNode_ptr wind_from_north_node; SGPropertyNode_ptr wind_from_north_node;
SGPropertyNode_ptr _environmentVisiblity; SGPropertyNode_ptr _environmentVisiblity;
SGPropertyNode_ptr _mp_use_detailed_models;
ai_list_type ai_list; ai_list_type ai_list;

View file

@ -59,6 +59,7 @@ FGAIMultiplayer::~FGAIMultiplayer() {
bool FGAIMultiplayer::init(ModelSearchOrder searchOrder) bool FGAIMultiplayer::init(ModelSearchOrder searchOrder)
{ {
props->setStringValue("sim/model/path", model_path); props->setStringValue("sim/model/path", model_path);
props->setIntValue("sim/model/fallback-model-index", _getFallbackModelIndex());
//refuel_node = fgGetNode("systems/refuel/contact", true); //refuel_node = fgGetNode("systems/refuel/contact", true);
isTanker = false; // do this until this property is isTanker = false; // do this until this property is
// passed over the net // passed over the net

View file

@ -119,6 +119,8 @@ const int MAX_BOOL_BUFFERS = 3;
const int V2018_1_BASE = 11990; const int V2018_1_BASE = 11990;
const int EMESARYBRIDGETYPE_BASE = 12200; const int EMESARYBRIDGETYPE_BASE = 12200;
const int EMESARYBRIDGE_BASE = 12000; const int EMESARYBRIDGE_BASE = 12000;
const int V2018_3_BASE = 13000;
const int FALLBACK_MODEL_ID = 13000;
/* /*
* definition of properties that are to be transmitted. * definition of properties that are to be transmitted.
@ -661,6 +663,8 @@ static const IdPropertyList sIdPropertyList[] = {
{ EMESARYBRIDGETYPE_BASE + 27, "sim/multiplay/emesary/bridge-type[27]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL, NULL }, { EMESARYBRIDGETYPE_BASE + 27, "sim/multiplay/emesary/bridge-type[27]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL, NULL },
{ EMESARYBRIDGETYPE_BASE + 28, "sim/multiplay/emesary/bridge-type[28]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL, NULL }, { EMESARYBRIDGETYPE_BASE + 28, "sim/multiplay/emesary/bridge-type[28]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL, NULL },
{ EMESARYBRIDGETYPE_BASE + 29, "sim/multiplay/emesary/bridge-type[29]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL, NULL }, { EMESARYBRIDGETYPE_BASE + 29, "sim/multiplay/emesary/bridge-type[29]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL, NULL },
{ FALLBACK_MODEL_ID, "sim/model/fallback-model-index", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL, NULL },
}; };
/* /*
* For the 2017.x version 2 protocol the properties are sent in two partitions, * For the 2017.x version 2 protocol the properties are sent in two partitions,
@ -1977,6 +1981,7 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
} }
const T_PositionMsg* PosMsg = Msg.posMsg(); const T_PositionMsg* PosMsg = Msg.posMsg();
FGExternalMotionData motionInfo; FGExternalMotionData motionInfo;
int fallback_model_index = 0;
motionInfo.time = XDR_decode_double(PosMsg->time); motionInfo.time = XDR_decode_double(PosMsg->time);
motionInfo.lag = XDR_decode_double(PosMsg->lag); motionInfo.lag = XDR_decode_double(PosMsg->lag);
for (unsigned i = 0; i < 3; ++i) for (unsigned i = 0; i < 3; ++i)
@ -2222,6 +2227,13 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
} }
if (pData) if (pData)
motionInfo.properties.push_back(pData); motionInfo.properties.push_back(pData);
// Special case - we need the /sim/model/fallback-model-index to create
// the MP model
if (pData->id == FALLBACK_MODEL_ID) {
fallback_model_index = pData->int_value;
SG_LOG(SG_NETWORK, SG_DEBUG, "Found Fallback model index in message " << fallback_model_index);
}
} }
else else
{ {
@ -2238,7 +2250,7 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
noprops: noprops:
FGAIMultiplayer* mp = getMultiplayer(MsgHdr->Callsign); FGAIMultiplayer* mp = getMultiplayer(MsgHdr->Callsign);
if (!mp) if (!mp)
mp = addMultiplayer(MsgHdr->Callsign, PosMsg->Model); mp = addMultiplayer(MsgHdr->Callsign, PosMsg->Model, fallback_model_index);
mp->addMotionInfo(motionInfo, stamp); mp->addMotionInfo(motionInfo, stamp);
} // FGMultiplayMgr::ProcessPosMsg() } // FGMultiplayMgr::ProcessPosMsg()
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -2301,13 +2313,15 @@ FGMultiplayMgr::FillMsgHdr(T_MsgHdr *MsgHdr, int MsgId, unsigned _len)
FGAIMultiplayer* FGAIMultiplayer*
FGMultiplayMgr::addMultiplayer(const std::string& callsign, FGMultiplayMgr::addMultiplayer(const std::string& callsign,
const std::string& modelName) const std::string& modelName,
const int fallback_model_index)
{ {
if (0 < mMultiPlayerMap.count(callsign)) if (0 < mMultiPlayerMap.count(callsign))
return mMultiPlayerMap[callsign].get(); return mMultiPlayerMap[callsign].get();
FGAIMultiplayer* mp = new FGAIMultiplayer; FGAIMultiplayer* mp = new FGAIMultiplayer;
mp->setPath(modelName.c_str()); mp->setPath(modelName.c_str());
mp->setFallbackModelIndex(fallback_model_index);
mp->setCallSign(callsign); mp->setCallSign(callsign);
mMultiPlayerMap[callsign] = mp; mMultiPlayerMap[callsign] = mp;

View file

@ -89,7 +89,8 @@ private:
union MsgBuf; union MsgBuf;
FGAIMultiplayer* addMultiplayer(const std::string& callsign, FGAIMultiplayer* addMultiplayer(const std::string& callsign,
const std::string& modelName); const std::string& modelName,
const int fallback_model_index);
FGAIMultiplayer* getMultiplayer(const std::string& callsign); FGAIMultiplayer* getMultiplayer(const std::string& callsign);
void FillMsgHdr(T_MsgHdr *MsgHdr, int iMsgId, unsigned _len = 0u); void FillMsgHdr(T_MsgHdr *MsgHdr, int iMsgId, unsigned _len = 0u);
void ProcessPosMsg(const MsgBuf& Msg, const simgear::IPAddress& SenderAddress, void ProcessPosMsg(const MsgBuf& Msg, const simgear::IPAddress& SenderAddress,
@ -129,4 +130,3 @@ private:
}; };
#endif #endif