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",
fgGetString("/sim/multiplay/default-model", default_model)));
setFallbackModelIndex(scFileNode->getIntValue("fallback-model-index", 0));
setHeading(scFileNode->getDoubleValue("heading", 0.0));
setSpeed(scFileNode->getDoubleValue("speed", 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;
if (searchOrder == DATA_ONLY) {
SG_LOG(SG_AI, SG_DEBUG, "Resolving model path: DATA only");
auto p = simgear::SGModelLib::findDataFile(model_path);
if (!p.empty()) {
// We've got a model, use it
_installed = true;
SG_LOG(SG_AI, SG_DEBUG, "Found model " << p);
path_list.push_back(p);
} else {
// No model, so fall back to the default
path_list.push_back(fgGetString("/sim/multiplay/default-model", default_model));
}
} 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.
for (SGPath p : globals->get_data_paths("AI")) {
p.append(model_path);
if (p.exists()) {
SG_LOG(SG_AI, SG_DEBUG, "Found AI model: " << p.local8BitStr());
path_list.push_back(p.local8BitStr());
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 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;
}
// At this point we've either still to find a valid path, or we're
// looking for a regular model to display at closer range.
// At this point we're looking for a regular model to display at closer range.
auto p = simgear::SGModelLib::findDataFile(model_path);
if (!p.empty()) {
_installed = true;
SG_LOG(SG_AI, SG_DEBUG, "Found DATA model " << 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;
}
vector<string> model_list = resolveModelPath(searchOrder);
props->addChild("type")->setStringValue("AI");
_modeldata = new FGAIModelData(props);
vector<string> model_list = resolveModelPath(searchOrder);
_model= SGModelLib::loadPagedModel(model_list, props, _modeldata);
_model->setName("AI-model range animation node");
@ -982,6 +1006,10 @@ const char* FGAIBase::_getSubmodel() const {
return _submodel.c_str();
}
const int FGAIBase::_getFallbackModelIndex() const {
return _fallback_model_index;
}
void FGAIBase::CalculateMach() {
// Calculate rho at altitude, using standard atmosphere
// For the temperature T and the pressure p,

View file

@ -74,6 +74,7 @@ public:
void updateInterior();
void setManager(FGAIManager* mgr, SGPropertyNode* p);
void setPath( const char* model );
void setFallbackModelIndex(const int i );
void setSMPath( const std::string& p );
void setCallSign(const std::string& );
void setSpeed( double speed_KTAS );
@ -114,7 +115,7 @@ public:
int _getSubID() const;
bool getDie();
bool isValid() const;
bool isValid() const;
void setFlightPlan(std::unique_ptr<FGAIFlightPlan> f);
@ -208,7 +209,8 @@ protected:
double rotation; // 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;
bool delete_me;
@ -316,10 +318,9 @@ public:
const char* _getTriggerNode() const;
const char* _getName() const;
const char* _getSubmodel() const;
const int _getFallbackModelIndex() const;
// These are used in the Mach number calculations
double rho;
double T; // temperature, degs farenheit
double p; // pressure lbs/sq ft
@ -348,6 +349,10 @@ inline void FGAIBase::setPath(const char* model ) {
model_path.append(model);
}
inline void FGAIBase::setFallbackModelIndex(const int i ) {
_fallback_model_index = i;
}
inline void FGAIBase::setSMPath(const std::string& p) {
_path = p;
}

View file

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

View file

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

View file

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

View file

@ -119,6 +119,8 @@ const int MAX_BOOL_BUFFERS = 3;
const int V2018_1_BASE = 11990;
const int EMESARYBRIDGETYPE_BASE = 12200;
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.
@ -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 + 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 },
{ 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,
@ -1977,6 +1981,7 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
}
const T_PositionMsg* PosMsg = Msg.posMsg();
FGExternalMotionData motionInfo;
int fallback_model_index = 0;
motionInfo.time = XDR_decode_double(PosMsg->time);
motionInfo.lag = XDR_decode_double(PosMsg->lag);
for (unsigned i = 0; i < 3; ++i)
@ -2222,6 +2227,13 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
}
if (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
{
@ -2238,7 +2250,7 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg,
noprops:
FGAIMultiplayer* mp = getMultiplayer(MsgHdr->Callsign);
if (!mp)
mp = addMultiplayer(MsgHdr->Callsign, PosMsg->Model);
mp = addMultiplayer(MsgHdr->Callsign, PosMsg->Model, fallback_model_index);
mp->addMotionInfo(motionInfo, stamp);
} // FGMultiplayMgr::ProcessPosMsg()
//////////////////////////////////////////////////////////////////////
@ -2301,13 +2313,15 @@ FGMultiplayMgr::FillMsgHdr(T_MsgHdr *MsgHdr, int MsgId, unsigned _len)
FGAIMultiplayer*
FGMultiplayMgr::addMultiplayer(const std::string& callsign,
const std::string& modelName)
const std::string& modelName,
const int fallback_model_index)
{
if (0 < mMultiPlayerMap.count(callsign))
return mMultiPlayerMap[callsign].get();
FGAIMultiplayer* mp = new FGAIMultiplayer;
mp->setPath(modelName.c_str());
mp->setFallbackModelIndex(fallback_model_index);
mp->setCallSign(callsign);
mMultiPlayerMap[callsign] = mp;

View file

@ -89,7 +89,8 @@ private:
union MsgBuf;
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);
void FillMsgHdr(T_MsgHdr *MsgHdr, int iMsgId, unsigned _len = 0u);
void ProcessPosMsg(const MsgBuf& Msg, const simgear::IPAddress& SenderAddress,
@ -129,4 +130,3 @@ private:
};
#endif