Document directory
- Module Scanning)
- Module loading and unload (load/unload)
- Module searching)
- Module copying and synchronization (copy/synchronization dependency)
- Module merging and updates (merge/update)
- Module events and listeners (event/listener)
Summary
The module system was designed to provide users with a highly reusable development environment for code and resource (asset), which includes some important components:
- Module identity)
- Module Versioning (Version Control)
- Module deprecation)
- Module grouping)
- Module types (type)
- Module Dependencies)
- Module meta-data (metadata)
- Module load/unload configurations (loading/uninstalling announcement)
- Module synchronization/publishing (synchronization/release)
In essence, a module contains code and data, or only data (such as resource module), and the code can be combined in the form of a dispatch task.
For example, a module is only a sub-system in your game, Editor plug-in, or even resource package.
Prerequisites
The module system uses the TAMl file as the basic declaration and definition file of the module. Therefore, it is only necessary to understand TAMl. At the very least, you must know how to modify the TAMl file.
Script export information
- Module Manager (Modulemanager_scriptbinding.h)
- Module definition (Moduledefinition_scriptbinding.h)
Module System
The module system in this document is actually called the module manager in the engine ).
When the engine is started, an instance of the manager is automatically generated. This instance is exported to the script through an object called "moduledatabase" for use.
This name is called because in the torque environment, you cannot get the Object Name and object class name the same. In the script, you need to use "moduledatabase" to access the master module database.
Module Declaration
Before learning about the details of a module, another important thing is to understand how a module is defined.
A module only describes its own directory using a single TAMl file, which is similar to a resource (asset) defined by a TAMl file that contains one or more files.
TAMl files describing module information are generally considered as a module definition file.
All modules have a unique ID called "module ID". This number is only a string. The unique requirement is that this number cannot be repeated in all modules.
The number is arbitrary, but keeping it concise will help you remember it.
The module system does not care about the specific content of a module. The only concern is whether the module exists. A module is a "reusable Unit", which means that you can put the things you need together as a module, such as code and resources, and load it as needed.
Module Scan
At first, the module system does not have any modules, and there are no preparation or special modules. The module will be recorded only when you require it to scan the specified directory.
You can tell him to scan several paths to collect the desired module. When you want to scan the path, the module system will simply query the module's definition information:
// Scan for modules.ModuleDatabase.scanModules( "MyModules" );
The scanmodules method scans the specified path. The code above scans the subdirectory named mymodules. by default, this function recursively scans all subdirectories. If you do not want to do this, you can specify it using the second parameter. the function prototype is as follows:
/// Module discovery.bool scanModules( const char* pPath, const bool rootOnly = false );
The module system scans the files ending with "module. TAMl" (which can be modified. This is a macro definition) and checks whether the file contains the "moduledefinition" field. The simple definition is as follows:
<ModuleDefinitionModuleId="AICode"VersionId="1"/>
The most basic information required for module definition is "moduleid" and "versionid. versionid is the version number of a module. You can create multiple modules with the same module ID but different versions. when the module system finds a module definition, it first confirms the validity. In part of the so-called validation, the module system verifies whether a module with the same ID and version number exists. If yes, it will warn and ignore it. module Definition
As you can see, the module definition contains some data describing the module itself. The previous section only describes the simplest configuration. The following is a complete parameter table:
- Moduleid-unique string number, which can contain any character, comma and semicolon.
- Versionid-version number.
- Buildid-the build ID. Non-breaking changes to a module shocould use a higher build ID. Optional: if not specified then the build ID will be zero.
- Enabled-(optional) whether the module is invalid. If it is invalid, the loading is ignored.
- Deprecated-(optional) discard Switch
- Description-Description
- Author-author
- Group: the group in which a group of modules are read.
- Type-module category.
- Dependencies-(optional) module dependency description, a list of module IDS/version numbers separated by commas
- Scriptfile-(optional) script file to be compiled when the module is loaded.
- Createfunction-(optional) Name of the Script Creation method called when a module is created.
- Destroyfunction-(optional) Name of the script destruction method called when the module is destroyed.
- Scopeset-Secondary object, used as the module root. The objects in all modules are their sub-objects for convenient destruction and access.
- Assettagsmanifest-the name of tags asset manifest file if this module contains asset tags. optional: if not specified then no asset tags will be found for this module. currently, only a single asset tag manifest shocould exist.
- Synchronized-(optional) Synchronous loading, non-synchronous by default.
- Criticalmerge-whether the merging of a module prior to a restart is critical or not. Optional: if not specified then the module is not merge critical.
Module Design
As you can see, a module is identified by its module ID, but a component of the ID is the version number. They jointly determine a unique module, this means that you can load multiple modules with the same module number and different versions in the same module system. The problem arises if they are effectively different during storage. the module system does not organize modules in any special way. You can say that the modules are stored anywhere, the problem is how to let the module system know the directory to be scanned in parsing the module definition file.
The standard design is to place the module in a directory with the same directory name and the same version number and subdirectory name. For example:
Module ID |
Version ID |
Folder |
Redmodule |
1 |
Redmodule \ 1... |
Redmodule |
2 |
Redmodule \ 2... |
Greenmodule |
1 |
Greenmodule \ 1... |
Bluemodule |
1 |
Bluemodule \ 1... |
The following method can also be used:
Module ID |
Version ID |
Folder |
Redmodule |
1 |
Redmodule1... |
Redmodule |
2 |
Redmodule2... |
Greenmodule |
1 |
Greenmodule \ 1... |
Bluemodule |
1 |
Bluemodule \ 1... |
The option is on your own, but the design of modules with the same number and different versions in the level-2 directory is a standard, which can be a good impetus for future design.
Module loading/unloading
The module loading/unloading process is very simple. There are two functions to complete:
Two parameters need to be passed to call the load/unload method explicitly, as follows:
Moduledatabase. loadexplicit (
"Redmodule", 2
);
This method is simple, but it becomes complicated and cumbersome when the number of modules increases. For example:
ModuleDatabase.LoadExplicit( "RedModule", 2 );ModuleDatabase.LoadExplicit( "GreenModule", 1 );ModuleDatabase.LoadExplicit( "BlueModule", 1 );
When uninstalling:
ModuleDatabase.UnloadExplicit( "RedModule", 2 );ModuleDatabase.UnloadExplicit( "GreenModule", 1 );ModuleDatabase.UnloadExplicit( "BlueModule", 1 );
A simpler and quicker way is to use the concept of a module group to perform operations in the whole group. For example, you can specify the group when defining a module:
<ModuleDefinitionModuleId="RedModule"VersionId="1"Group="Colors"/><ModuleDefinitionModuleId="RedModule"VersionId="2"Group="Colors"/><ModuleDefinitionModuleId="GreenModule"VersionId="1"Group="Colors"/><ModuleDefinitionModuleId="BlueModule"VersionId="1"Group="Colors"/>
Subsequent loading/unloading operations:
ModuleManager.LoadGroup( "Colors" );ModuleManager.UnloadGroup( "Colors" );
Module dependency
When a module is loaded, it may request services or data from another module. This means that you must ensure that the dependent module is loaded in advance.
You can specify dependencies in the module definition file as follows: <moduledefinition
<ModuleDefinitionModuleId="GameCore"VersionId="1"/><ModuleDefinitionModuleId="Game"VersionId="1"Dependencies="GameCore=1"/>
Loading module game:
ModuleManager.LoadExplicit( "Game", 1 );
When executing a function, the module system checks the dependencies and first makes sure that version 1 of the gamecore module is loaded. If it is already loaded, the reference count is increased to ensure that it is not loaded twice.
Uninstall module game:
ModuleManager.UnloadExplicit( "Game", 1 );
When the function is executed, the module system checks the dependency item again, references minus one, And uninstalls it as 0.
If you need multiple dependency modules, write as follows:
<ModuleDefinitionModuleId="Game"VersionId="1"Dependencies="GameCore=1,AICore=2,AudioCore=1,PlugInCore=6"/>
Module type
You can divide a module into a specified type, which is not required by the module system.
However, the findmoduletypes method is very effective. A typical purpose is to filter module searches by type.
For example, many modules are provided to the "art" package. You can classify them as "artpack", as shown below:
<ModuleDefinitionModuleId="PlatformArtPack"VersionId="1"Description="Lots of cool platform assets."Type="ArtPack"/>
You can use the findmoduletypes method to obtain the list of related modules.
Module Startup Script
So far, we have learned how to load and uninstall scripts and how to configure relevant module variables, but they are not actually used in the real environment.
A module usually has a main script. When the module loads/uninstalls, it runs the specified function in the main script. The configuration variables related to the main script include the following:
- Scriptfile
- Createfunction
- Destroyfunction
For example:
<ModuleDefinitionModuleId="BlueModule"VersionId="1"ScriptFile="main.cs"CreateFunction="create"DestroyFunction="destroy"/>
Note that they are not a global method and cannot be defined as follows:
function create(){}function destroy(){}
Should:
function BlueModule::create(%this){}function BlueModule::destroy(%this){}
This definition is because when a module is loaded, the module system automatically generates an object with the same module ID. note that the script specified by scriptfile is compiled only once when the module is loaded. The created and destroyed functions are called when the corresponding module is loaded/uninstalled. scopeset
As mentioned above, the module system will generate a named object and specify two methods for it. This "scopeset" is very useful. In fact, this named object is created as a simset instance, because of this, you can add any desired object as its sub-object. the reason you can do this is that when the scopeset is destroyed, it not only destroys itself, but also destroys all objects (sub-objects) attached to it ).
In other words, when the module is detached, "scopeset" can be used as a very useful tool to help Delete "root nodes" of related objects ".
Module Manager
The following are four features of exporting to a script:
Module Scanning)
When you perform a module scan, the default system suffix is "module. TAMl", but you can modify it as follows:
ModuleDatabase.SetModuleExtension( "FunkyModules.taml" );
Module loading and unload (load/unload)
// Load the module group "CoreStuff".ModuleDatabase.LoadGroup( "CoreStuff" );// Unload the module group "CoreStuff".ModuleDatabase.UnloadGroup( "CoreStuff" );// Explicitly load the module "Game" at version "3".ModuleDatabase.LoadExplicit( "Game", 3 );// Explicitly unload the module "Game" at version "3".ModuleDatabase.UnloadExplicit( "Game", 3 );
Module searching)
It is important not only to be able to load/detach blocks, but also to find them. It is especially important when you dynamically load modules.
You may use a Dynamically Loaded resource or plug-in. In any case, finding a module is a very important function.
In all possible cases, when you look for a module, you will get a torque object, which is actually an instance of "moduledefinition, each module has one and contains all preset information.
// Find the "Game" module at version 3.%module = ModuleDatabase.findModule( "Game", 3 );// Output its description.echo( %module.Description );
As you can see, you can use any module number and version number to find the module and obtain the object defined in the description module. In addition, a query mechanism allows you to query all the module information:
// Find all modules % allmodules = moduledatabase. findmodules (false); // find the loading module % loadedmodules = moduledatabase. findmodules (true );
The return value is a list of model definition objects separated by spaces. Another useful query is the type. As mentioned above, the example is as follows:
// Find all "ArtPack" modules.%artPacks = ModuleDatabase.findModuleTypes( "ArtPack" );
Module copying and synchronization (copy/synchronization dependency)
This is a complex topic and will be detailed later!
The following methods will be detailed:
- Copymodules ()
- Synchronizedependencies ()
Module merging and updates (merge/update)
This is a complex topic and will be detailed later!
The following methods will be detailed:
- Ismodulemergeavailable ()
- Canmergemodules ()
- Mergemodules
Module events and listeners (event/listener)
When a module system executes an important operation, a response event is generated. The specific event is as follows:
- Onmoduleregister-called when the module is scanned, confirmed to be valid and registered
- Onmodulepreload-called before the module is loaded
- Onmodulepostload-called after the module is loaded
- Onmodulepreunload-called before the module is detached
- Onmodulepostunload-called after the module is uninstalled
The module system allows you to register your own objects to listen to these events:
- Addlistener ()
- Removelistener ()
When you execute these operations in torquescript, You need to assign an object as the listener. When an event is generated, the module system calls back to the specified script method:
// Create a listener object.new ScriptObject(MyModuleListener);// Add my object as a listener.ModuleDatabase.addListener(MyModuleListener);
Callback Function Definition:
function MyModuleListener::onModuleRegister( %module ){}function MyModuleListener::onModulePreLoad( %module ){}function MyModuleListener::onModulePostLoad( %module ){}function MyModuleListener::onModulePreUnload( %module ){}function MyModuleListener::onModulePostUnload( %module ){}