Support optional Nasal modules in fgdata/Nasal/MyModuleFoo
- Allow structuring generic Nasal sources into modules (i.e. support separate source folders for multiplayer/local weather/... sources) - Option to enable/disable loading of generic Nasal modules (i.e we only need to load stuff that is really needed/enabled). - Provide basic loading sequence: subfolders are strictly loaded _after_ the base directory. So submodules can rely on .nas-scripts like math.nas, io.nas, debug.nas, ... to be already loaded - dropping the need for awkward listeners/timers to delay module initialization (loading order within Nasal/*.nas is still random)
This commit is contained in:
parent
4141b80b0c
commit
298f832d43
2 changed files with 82 additions and 27 deletions
|
@ -737,12 +737,15 @@ void FGNasalSys::init()
|
||||||
|
|
||||||
// Now load the various source files in the Nasal directory
|
// Now load the various source files in the Nasal directory
|
||||||
simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal"));
|
simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal"));
|
||||||
simgear::PathList scripts = nasalDir.children(simgear::Dir::TYPE_FILE, ".nas");
|
loadScriptDirectory(nasalDir);
|
||||||
|
|
||||||
for (unsigned int i=0; i<scripts.size(); ++i) {
|
// Add modules in Nasal subdirectories to property tree
|
||||||
SGPath fullpath(scripts[i]);
|
simgear::PathList directories = nasalDir.children(simgear::Dir::TYPE_DIR+
|
||||||
SGPath file = fullpath.file();
|
simgear::Dir::NO_DOT_OR_DOTDOT, "");
|
||||||
loadModule(fullpath, file.base().c_str());
|
for (unsigned int i=0; i<directories.size(); ++i) {
|
||||||
|
simgear::Dir dir(directories[i]);
|
||||||
|
simgear::PathList scripts = dir.children(simgear::Dir::TYPE_FILE, ".nas");
|
||||||
|
addModule(directories[i].file(), scripts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set signal and remove node to avoid restoring at reinit
|
// set signal and remove node to avoid restoring at reinit
|
||||||
|
@ -777,6 +780,37 @@ void FGNasalSys::update(double)
|
||||||
_context = naNewContext();
|
_context = naNewContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loads all scripts in given directory
|
||||||
|
void FGNasalSys::loadScriptDirectory(simgear::Dir nasalDir)
|
||||||
|
{
|
||||||
|
simgear::PathList scripts = nasalDir.children(simgear::Dir::TYPE_FILE, ".nas");
|
||||||
|
for (unsigned int i=0; i<scripts.size(); ++i) {
|
||||||
|
SGPath fullpath(scripts[i]);
|
||||||
|
SGPath file = fullpath.file();
|
||||||
|
loadModule(fullpath, file.base().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create module with list of scripts
|
||||||
|
void FGNasalSys::addModule(string moduleName, simgear::PathList scripts)
|
||||||
|
{
|
||||||
|
if (scripts.size()>0)
|
||||||
|
{
|
||||||
|
SGPropertyNode* nasal = globals->get_props()->getNode("nasal");
|
||||||
|
SGPropertyNode* module_node = nasal->getChild(moduleName,0,true);
|
||||||
|
for (unsigned int i=0; i<scripts.size(); ++i) {
|
||||||
|
SGPropertyNode* pFileNode = module_node->getChild("file",i,true);
|
||||||
|
pFileNode->setStringValue(scripts[i].c_str());
|
||||||
|
}
|
||||||
|
if (!module_node->hasChild("enabled",0))
|
||||||
|
{
|
||||||
|
SGPropertyNode* node = module_node->getChild("enabled",0,true);
|
||||||
|
node->setBoolValue(true);
|
||||||
|
node->setAttribute(SGPropertyNode::USERARCHIVE,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Loads the scripts found under /nasal in the global tree
|
// Loads the scripts found under /nasal in the global tree
|
||||||
void FGNasalSys::loadPropertyScripts()
|
void FGNasalSys::loadPropertyScripts()
|
||||||
{
|
{
|
||||||
|
@ -785,33 +819,51 @@ void FGNasalSys::loadPropertyScripts()
|
||||||
|
|
||||||
for(int i=0; i<nasal->nChildren(); i++) {
|
for(int i=0; i<nasal->nChildren(); i++) {
|
||||||
SGPropertyNode* n = nasal->getChild(i);
|
SGPropertyNode* n = nasal->getChild(i);
|
||||||
|
bool is_loaded = false;
|
||||||
|
|
||||||
const char* module = n->getName();
|
const char* module = n->getName();
|
||||||
if(n->hasChild("module"))
|
if(n->hasChild("module"))
|
||||||
module = n->getStringValue("module");
|
module = n->getStringValue("module");
|
||||||
|
if (n->getBoolValue("enabled",true))
|
||||||
|
{
|
||||||
|
// allow multiple files to be specified within a single
|
||||||
|
// Nasal module tag
|
||||||
|
int j = 0;
|
||||||
|
SGPropertyNode *fn;
|
||||||
|
bool file_specified = false;
|
||||||
|
while((fn = n->getChild("file", j)) != NULL) {
|
||||||
|
file_specified = true;
|
||||||
|
const char* file = fn->getStringValue();
|
||||||
|
SGPath p(file);
|
||||||
|
if (!p.isAbsolute() || !p.exists())
|
||||||
|
{
|
||||||
|
p = globals->resolve_maybe_aircraft_path(file);
|
||||||
|
}
|
||||||
|
loadModule(p, module);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* src = n->getStringValue("script");
|
||||||
|
if(!n->hasChild("script")) src = 0; // Hrm...
|
||||||
|
if(src)
|
||||||
|
createModule(module, n->getPath().c_str(), src, strlen(src));
|
||||||
|
|
||||||
|
if(!file_specified && !src)
|
||||||
|
{
|
||||||
|
// module no longer exists - clear the archived "enable" flag
|
||||||
|
n->setAttribute(SGPropertyNode::USERARCHIVE,false);
|
||||||
|
SGPropertyNode* node = n->getChild("enabled",0,false);
|
||||||
|
if (node)
|
||||||
|
node->setAttribute(SGPropertyNode::USERARCHIVE,false);
|
||||||
|
|
||||||
// allow multiple files to be specified within a single
|
SG_LOG(SG_NASAL, SG_ALERT, "Nasal error: " <<
|
||||||
// Nasal module tag
|
"no <file> or <script> defined in " <<
|
||||||
int j = 0;
|
"/nasal/" << module);
|
||||||
SGPropertyNode *fn;
|
}
|
||||||
bool file_specified = false;
|
else
|
||||||
while((fn = n->getChild("file", j)) != NULL) {
|
is_loaded = true;
|
||||||
file_specified = true;
|
|
||||||
const char* file = fn->getStringValue();
|
|
||||||
SGPath p = globals->resolve_maybe_aircraft_path(file);
|
|
||||||
loadModule(p, module);
|
|
||||||
j++;
|
|
||||||
}
|
}
|
||||||
|
n->setBoolValue("loaded",is_loaded);
|
||||||
const char* src = n->getStringValue("script");
|
|
||||||
if(!n->hasChild("script")) src = 0; // Hrm...
|
|
||||||
if(src)
|
|
||||||
createModule(module, n->getPath().c_str(), src, strlen(src));
|
|
||||||
|
|
||||||
if(!file_specified && !src)
|
|
||||||
SG_LOG(SG_NASAL, SG_ALERT, "Nasal error: " <<
|
|
||||||
"no <file> or <script> defined in " <<
|
|
||||||
"/nasal/" << module);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/structure/subsystem_mgr.hxx>
|
#include <simgear/structure/subsystem_mgr.hxx>
|
||||||
|
#include <simgear/misc/sg_dir.hxx>
|
||||||
#include <simgear/nasal/nasal.h>
|
#include <simgear/nasal/nasal.h>
|
||||||
#include <simgear/scene/model/modellib.hxx>
|
#include <simgear/scene/model/modellib.hxx>
|
||||||
#include <simgear/xml/easyxml.hxx>
|
#include <simgear/xml/easyxml.hxx>
|
||||||
|
@ -85,6 +86,8 @@ private:
|
||||||
static int _listenerId;
|
static int _listenerId;
|
||||||
|
|
||||||
void loadPropertyScripts();
|
void loadPropertyScripts();
|
||||||
|
void loadScriptDirectory(simgear::Dir nasalDir);
|
||||||
|
void addModule(string moduleName, simgear::PathList scripts);
|
||||||
void hashset(naRef hash, const char* key, naRef val);
|
void hashset(naRef hash, const char* key, naRef val);
|
||||||
void logError(naContext);
|
void logError(naContext);
|
||||||
naRef parse(const char* filename, const char* buf, int len);
|
naRef parse(const char* filename, const char* buf, int len);
|
||||||
|
|
Loading…
Reference in a new issue