1
0
Fork 0

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:
ThorstenB 2011-04-02 15:13:29 +02:00
parent 4141b80b0c
commit 298f832d43
2 changed files with 82 additions and 27 deletions

View file

@ -737,12 +737,15 @@ void FGNasalSys::init()
// Now load the various source files in the Nasal directory
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) {
SGPath fullpath(scripts[i]);
SGPath file = fullpath.file();
loadModule(fullpath, file.base().c_str());
// Add modules in Nasal subdirectories to property tree
simgear::PathList directories = nasalDir.children(simgear::Dir::TYPE_DIR+
simgear::Dir::NO_DOT_OR_DOTDOT, "");
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
@ -777,6 +780,37 @@ void FGNasalSys::update(double)
_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
void FGNasalSys::loadPropertyScripts()
{
@ -785,33 +819,51 @@ void FGNasalSys::loadPropertyScripts()
for(int i=0; i<nasal->nChildren(); i++) {
SGPropertyNode* n = nasal->getChild(i);
bool is_loaded = false;
const char* module = n->getName();
if(n->hasChild("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++;
}
// 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 = 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);
SG_LOG(SG_NASAL, SG_ALERT, "Nasal error: " <<
"no <file> or <script> defined in " <<
"/nasal/" << module);
}
else
is_loaded = true;
}
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);
n->setBoolValue("loaded",is_loaded);
}
}

View file

@ -3,6 +3,7 @@
#include <simgear/misc/sg_path.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/nasal/nasal.h>
#include <simgear/scene/model/modellib.hxx>
#include <simgear/xml/easyxml.hxx>
@ -85,6 +86,8 @@ private:
static int _listenerId;
void loadPropertyScripts();
void loadScriptDirectory(simgear::Dir nasalDir);
void addModule(string moduleName, simgear::PathList scripts);
void hashset(naRef hash, const char* key, naRef val);
void logError(naContext);
naRef parse(const char* filename, const char* buf, int len);