Howto:Creating a simple modding framework

From FlightGear wiki
Jump to navigation Jump to search
This article is a stub. You can help the wiki by expanding it.


Status

Objective

List of addons

  • tanker.nas
  • tutorials
  • fgcamera
  • advanced weather
  • bombable

Background

Directory Structure

Mods should be using their own directory structure, resembling $FG_ROOT (the base package), e.g.:

  • Aircraft
  • GUI
  • Textures
  • Sounds
  • Nasal

etc

Requirements

  • register hooks to invoke callbacks for specific simulator/addon events (pause/unpause etc)
  • mutual dependencies

Versioning

1rightarrow.png See FlightGear Version Check for the main article about this subject.

Prototype

The protoype will be set up like this:

  • an optional Nasal submodule stored in $FG_ROOT/Nasal/modding
  • mods live under $FG_ROOT/Mods, each in its own folder
  • each mod folder's structure will basically resemble the structure of the base package, with its sub-folders for resources like scripts, textures, sounds etc
  • each mod will have a top-level specs.mod file
  • each specs.mod file is a conventional Nasal file that inherits from an interface class living in the Mod namespace
  • the specs.mod file implements routines for enabling/disabling and configuring the mod


The loader will traverse $FG_ROOT/Mods to obtain a list (vector) of directories. For each directory found, it will use io.load_nasal() to call the specs.mod file for that mode In turn, each specs.mod file will register itself, e.g. to add menubar items and register GUI dialogs etc

Proof of Concept

The following snippet of code assumes that you put it into $FG_ROOT/Nasal/mod/mod.nas In addition, you need to add a folder to $FG_ROOT named Mods, beneath this folder you can add other folders (one, two, three in this case) - with each folder being treated as a separate "mod", having its own mod.specs file

diff --git a/Mods/one/mod.specs b/Mods/one/mod.specs
new file mode 100644
index 0000000..c1b3d8f
--- /dev/null
+++ b/Mods/one/mod.specs
@@ -0,0 +1 @@
+print("Mod 1 registered");
diff --git a/Mods/three/mod.specs b/Mods/three/mod.specs
new file mode 100644
index 0000000..c1b3d8f
--- /dev/null
+++ b/Mods/three/mod.specs
@@ -0,0 +1 @@
+print("Mod 3 registered");
diff --git a/Mods/two/mod.specs b/Mods/two/mod.specs
new file mode 100644
index 0000000..c1b3d8f
--- /dev/null
+++ b/Mods/two/mod.specs
@@ -0,0 +1 @@
+print("Mod 2 registered");
##
# $FG_ROOT/Nasal/mod/loader.nas

var ModdingRegistry = {};

var ModdingInterface = {
 new: func() {},
 del: func() {},
 register: func(name) {
 var slotNotEmpty = contains(ModdingRegistry, name);
 if (slotNotEmpty) {
 print("Warning: Overwriting/re-adding mod:", name);
 ModdingRegistry[name].del(); # invoke the destructor of the mod
 # ModdingRegistry[name] = 
 }

 },
};

var fgroot = getprop("/sim/fg-root");
var modFolder = fgroot ~ '/'~ 'Mods/';

# http://wiki.flightgear.org/Nasal_library#directory.28.29
var modDirectories = directory( modFolder );

# debug.dump( modDirectories );

foreach(var mod; modDirectories) {
print("Mod directory found:", mod);
var entrypoint = modFolder ~ mod ~ '/mod.specs';
print("Trying to load:", entrypoint,"\n");
io.load_nasal( entrypoint );
}

## invoke:
# init code
# setup  code
# loading code
# clean up code