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:
parent
23196184cc
commit
e43fe82094
7 changed files with 149 additions and 105 deletions
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue