BOSS is a utility that helps mod users avoid serious conflicts by setting the mod plugins they have installed in their optimal load order. It also provides over 10,000 plugin-specific messages, including usage notes, requirements, incompatibilities, warnings on bugs and installation mistake notifications.
The load order BOSS sets is decided by its masterlist, which lists all the plugins recognised by BOSS in their optimal load order, and contains the plugin-specific messages BOSS provides. Each game that BOSS supports has a separate masterlist, which are kept up to date via community submissions. Users can customise BOSS's positioning of plugins and the messages it displays using a userlist file. Each game has a separate userlist.
This documentation details the BOSS API (a.k.a. BAPI) and is intended for use by third party developers of modding utilities for TES III: Morrowind, TES IV: Oblivion, TES V: Skyrim, Nehrim - At Fate's Edge, Fallout 3 and Fallout: New Vegas.
BAPI has a C frontend and is available as 32-bit and 64-bit DLLs that can be loaded by other modding utilities. BAPI currently has the following capabilities:
BAPI is intended as a full solution to the management of load order and plugin activation status across all supported games, freeing client utilities from the requirement to maintain their own code for those functions. The source code is available at BOSS's Google Code repository. BAPI is licensed as part of BOSS under the GNU General Public License v3, see the main BOSS readme for more information.
Load ordering is the method used to determine how conflicts between mod plugins should be decided. If two plugins alter the same game data, then the changes made by the plugin loading later will override those made by the plugin loading earlier. This rule of one results in a list of plugins, with those earlier in the list having any conflicting changes overriden by those later in the list. This list is the load order of the plugins.
A game will only load the plugins that are active. Up to 255 plugins, including the game's .esm file, can be active at any one time. Active plugins are listed in the game's plugins.txt
file (or Morrowind.ini
, in the case of Morrowind), which is stored in the user's local application data folder. Nevertheless, it is useful when working with load orders to consider the load order of all plugins, even if only some of them will actually be loaded. This is both because it is easier to display a single list of plugins than a list and an unordered set, and because modders have engineered methods that allow the changes made by inactive plugins to be loaded by another plugin (eg. Wrye *ash's Bashed Patch). When any such methods are being used, the load order of inactive plugins decides which plugins override others, similar to as if they were active.
In Morrowind, Oblivion, Nehrim, Fallout 3, Fallout: New Vegas and early versions (pre-1.4.26) of Skyrim, load order is decided by the relative timestamps of plugins in the game's Data directory. An installed plugin's load order is therefore an intrinsic property of that plugin.
In Skyrim v1.4.26+, a new textfile-based load order system was introduced, in which load order is decide by the order in which plugins are listed in plugins.txt
. This brought with it a fundamental change, in that load order is no longer an intrinsic property of a plugin, and so inactive plugins do not have any load order.
Note: The games enforce one rule that overrides the load order of plugins set by either system. This rule is that master files always load before all plugin files. Simple enough, except that master files are not necessarily .esm
files, and plugin files aren't necessarily .esp
files. Whether a file is a master or a plugin depends on the value of a bit flag in the file itself, rather than its file extension. This also confuses terminology, so the usage in this readme is clarified below:
.esp
or .esm
extension.
.ghost
extension appended to its filename.
As the load order of all plugins, not just inactive plugins, is important, a standard solution that would allow ordering of inactive plugins was decided by Lojack (Wrye Bash), Kaburke (Nexus Mod Manager), WrinklyNinja (BOSS) and Dark0ne (owner of the Nexus sites) that could serve the community's needs. The BOSS API contains the canonical implementation of this standard.
The standard dictates that:
plugins.txt
.
plugins.txt
is encoded in Windows-1252.
plugins.txt
is by default stored in the user's local application data folder, eg. C:\Users\WrinklyNinja\AppData\Local\Skyrim\plugins.txt
on Windows Vista/7.
loadorder.txt
file.
loadorder.txt
is encoded in UTF-8, without a Byte Order Mark.
loadorder.txt
is stored alongside the plugins.txt
, in whichever location that is.
plugins.txt
and loadorder.txt
contain only a list of plugin filenames (files with .esp
or .esm
extensions), one per line.
plugins.txt
and loadorder.txt
, master files are listed before plugin files.
plugins.txt
and loadorder.txt
are to be kept in synchronisation with one another: when one file is changed, the other must also be changed in the same manner (unless the change is not applicable, eg. deactivating a plugin doesn't change the contents of loadorder.txt
).
There are some circumstances that produce scenarios in which the behaviour of utilities is not defined. These are detailed in the table below.
Circumstance | Recommended Behaviour | BOSS API Behaviour |
---|---|---|
An attempt is made to activate a plugin with a filename that cannot be represented in the Windows-1252 encoding. | Utilities check that filename strings are encoded correctly before outputting them. On a failure to convert to the correct encoding, the user should be alerted that the plugin in question cannot be activated. | BAPI attempts to convert the filename string, fails and returns a warning code with an associated string containing the filename in question to the client, after performing whatever other processing that was required by the function the client called. The client is then free to decide on the action taken. |
The plugins.txtand loadorder.txtfiles become unsynchronised. | Utilities check for synchronisation on startup and maintain it throughout their operation, rather than re-synchronising the files on program close, for instance. This is to prevent issues for any other programs open at the same time. If desynchronisation is detected, the only standard-based recovery option is to derive plugins.txtfrom loadorder.txt, first getting a list of filenames to be written from plugins.txt. Alternatively, a utility could use some internal load order backup to restore from. See the coloured box below for a more detailed breakdown of the issue. | BAPI detects loss of synchronisation when a database is created and returns a warning code to the client after creating the database. The client is then free to decide on the action taken. |
For one reason or another, a plugin becomes listed twice in loadorder.txt . | Utilities use the earliest-listed instance of that plugin, as this is most likely to be correct. | The API ignores all but the earliest-listed instance of a plugin, neither operating on or returning any other instance. |
The Desynchronisation ProblemIf either
plugins.txt
orloadorder.txt
are changed such that the load order of the plugins inplugins.txt
is not the same inplugins.txt
andloadorder.txt
, then the difference cannot generally be precisely resolved without discarding one file's ordering. This is due to the load order of plugins in plugins.txt being weakly defined, ie. it is defined relative to other active plugins, but not in relation to inactive plugins. An example:If you use the API to set a load order of A,b,c,d,E,f,g where uppercase letters denote active plugins, then you use the Skyrim launcher to move A after E, thenplugins.txt
will read E,A whileloadorder.txt
remains unchanged. There is no way of knowing from the contents of plugins.txt whether you moved A after E or E before A. If these were the only two plugins, then it would not be an issue, but you also have inactive plugins interspersed amongst them, so you have the following possibilities, all of which are potentially valid, but also potentially damaging in terms of conflicts, etc.:b,c,d,E,A,f,gThere is no way of knowing which is the correct order to choose for the full load order based on the active load order. You must therefore choose to use one of the two files' orderings. Since
b,c,d,E,f,A,g
b,c,d,E,f,g,A
E,A,b,c,d,f,gplugins.txt
does not define the load order positions of inactive plugins, it is unsuitable, andloadorder.txt
must be used. The alternative would be for a utility to restore load order from their own internal backup, hence why the standard does not define a specific behaviour, as it may beloadorder.txt
that was altered and is now wrong.
BAPI's implementation of load ordering support presents one set of functions that handle the differences between timestamp-based and textfile-based load ordering opaquely, so there is no difference in usage for clients. It is fully compatible with the community standard for textfile-based load ordering, handling all requirements internally.
In addition, BAPI also handles the following:
ghostinactive plugins by appending a
.ghost
extension to the filename. This reduces the effect of a bug in several supported games known as directory thrashing, which can lead to significant performance hits. BAPI treats ghosted plugins like normal plugins, and accepts their unghosted filenames in its function parameters, so the client doesn't need to keep track of their ghosted status. BAPI will also automatically unghost any plugins that are activated through its interface.
Skyrim.esm
& Update.esm
: These two Skyrim plugins are special cases, as they are always loaded by the game. However, if Update.esm
is not included in plugins.txt
, it is loaded after any other active master files. BAPI handles the special treatment of Skyrim.esm and Update.esm for the client, ensuring that they can never be deactivated and that Update.esm
is always explicitly loaded in plugins.txt
, either at the client's specified position or after other master files.
The API uses character strings and integers for information input/output.
The API also introduces three new structures:
typedef struct _boss_db_int * boss_db;
The boss_db structure abstracts the definition of BOSS's internal state while still providing type safety across the API.
typedef struct {
uint32_t id;
const uint8_t * name;
} BashTag;
The BashTag structure gives the Unique Identifier (UID) for each Bash Tag and the corresponding Bash Tag name.
typedef struct {
uint32_t type;
const uint8_t * message;
} BossMessage;
The BossMessage structure gives the type of a message and the message string itself.
BAPI manages the memory of strings and arrays it returns internally, so such strings and arrays should not be deallocated by the client.
A string/array returned by a function lasts until a BAPI function is called which returns data of the same type (eg. a string is stored until the client calls another function which returns a string, an integer array lasts until another integer array is returned, etc.).
Strings and arrays may also be deallocated by calling Load or DestroyBossDb. DestroyBossDb also destroys the database passed as its argument.
The two exceptions to the above are the strings returned by GetLastErrorDetails and GetVersionString, which exist independently of each other and strings returned by other functions. A string returned by one of these two functions lasts until that function is called again, or until CleanUpAPI is called.
The BOSS API functions uses the following uint32_t return codes to signal how a function completes. WARN return codes signify a problem that did not cause the function to exit prematurely, whereas ERROR return codes signify issues that did cause the function to exit prematurely.
Return Code | Description |
---|---|
BOSS_API_OK | The function completed successfully. |
BOSS_API_OK_NO_UPDATE_NECESSARY | No update was found for the masterlist. |
BOSS_API_WARN_BAD_FILENAME | The plugin filename contains characters that do not have Windows-1251/1252 code points. The plugin cannot be activated. |
BOSS_API_WARN_LO_MISMATCH | The order of plugins in plugins.txtand their order in loadorder.txtdoes not match. This is due to something (eg. the Skyrim launcher) editing one file without sychronising the other. Synchronisation is automatic when load order is managed through BAPI. |
BOSS_API_ERROR_FILE_WRITE_FAIL | A file could not be written to. |
BOSS_API_ERROR_FILE_DELETE_FAIL | A file could not be deleted. |
BOSS_API_ERROR_FILE_NOT_UTF8 | The specified BOSS file (masterlist or userlist) is not encoded in UTF-8. |
BOSS_API_ERROR_FILE_NOT_FOUND | The specified file could not be found. |
BOSS_API_ERROR_FILE_RENAME_FAIL | A file could not be renamed. |
BOSS_API_ERROR_TIMESTAMP_READ_FAIL | The modification date of a file could not be read. |
BOSS_API_ERROR_TIMESTAMP_WRITE_FAIL | The modification date of a file could not be set. |
BOSS_API_ERROR_PARSE_FAIL | There was an error parsing the file. |
BOSS_API_ERROR_CONDITION_EVAL_FAIL | There was an error evaluating the conditionals in the masterlist. |
BOSS_API_ERROR_REGEX_EVAL_FAIL | There was an error evaluating the regular expressions in the masterlist. |
BOSS_API_ERROR_NO_MEM | The API was unable to allocate the required memory. |
BOSS_API_ERROR_INVALID_ARGS | Invalid arguments were given for the function. |
BOSS_API_ERROR_NETWORK_FAIL | There was an error in an Internet-related operation. |
BOSS_API_ERROR_NO_INTERNET_CONNECTION | No Internet connection detected. |
BOSS_API_ERROR_NO_TAG_MAP | No Bash Tag map has been generated yet. GetBashTagMap must be run before GetModBashTags to build the Bash Tag map. |
BOSS_API_ERROR_PLUGINS_FULL | Writing the specified plugins to plugins.txtwould bring the number of active plugins over 255, which is the maximum allowed. |
BOSS_API_ERROR_GAME_NOT_FOUND | The specified game could not be found. |
BOSS_API_RETURN_MAX | Matches the value of the highest-numbered return code. It isn't returned by any functions. |
The following uint32_t codes are used by CreateBossDb to specify which game the API is acting for, in cases where distinctions between games are necessary.
Game Code | Game |
---|---|
BOSS_API_GAME_OBLIVION | The Elder Scrolls IV: Oblivion |
BOSS_API_GAME_FALLOUT3 | Fallout 3 |
BOSS_API_GAME_FALLOUTNV | Fallout: New Vegas |
BOSS_API_GAME_NEHRIM | Nehrim - At Fate's Edge |
BOSS_API_GAME_SKYRIM | The Elder Scrolls V: Skyrim |
BOSS_API_GAME_MORROWIND | The Elder Scrolls III: Morrowind |
The following codes are used by GetLoadOrderMethod to signify which load order system BAPI is running for.
Load Order Method Code | Description |
---|---|
BOSS_API_LOMETHOD_TIMESTAMP | The API is running for a game which uses the timestamp-based load order system. Oblivion, Fallout 3, Fallout: New Vegas all use this system, as does pre-v1.4.26 Skyrim. |
BOSS_API_LOMETHOD_TEXTFILE | The API is running for a game which uses the textfile-based load order system. Skyrim v1.4.26+ uses this system. |
The following codes are returned by GetDirtyMessage to signify the cleanliness status of the plugin passed to the function.
Plugin Cleanliness Code | Description |
---|---|
BOSS_API_CLEAN_NO | The plugin does not need cleaning or should not be cleaned. |
BOSS_API_CLEAN_YES | The plugin needs cleaning. |
BOSS_API_CLEAN_UNKNOWN | BOSS does not know whether the plugin needs cleaning or not, or if it should not be cleaned. |
The following codes are used in the BossMessage data structure to signify what type of message a particular message is.
Message Type Code | Description |
---|---|
BOSS_API_MESSAGE_SAY | A general message. |
BOSS_API_MESSAGE_TAG | A Bash Tag suggestion or suggestions. |
BOSS_API_MESSAGE_REQUIREMENT | An installation requirement or requirements. |
BOSS_API_MESSAGE_INCOMPATIBILITY | An incompatibility or incompatibilities. |
BOSS_API_MESSAGE_DIRTY | A message about dirty edits. |
BOSS_API_MESSAGE_WARN | A warning message. |
BOSS_API_MESSAGE_ERROR | An error message. |
BOSS API provides the functions listed below to clients. Where a function returns a uint32_t value, this is the function's return code.
uint32_t GetLastErrorDetails (uint8_t ** details);
bool IsCompatibleVersion (const uint32_t bossVersionMajor, const uint32_t bossVersionMinor, const uint32_t bossVersionPatch);
uint32_t GetVersionString (uint8_t ** bossVersionStr);
uint32_t CreateBossDb (boss_db * db, const uint32_t clientGame, const uint8_t * dataPath);
NULL
or empty, the API attempts to detect the path of the game by scanning sibling folders of the working directory and by scanning the Windows Registry for an install path key.
void DestroyBossDb (boss_db db);
void CleanUpAPI ();
boss_db
argument, and scanning the data directory specified when the database was created for newly added plugins.
uint32_t Load (boss_db db, const uint8_t * masterlistPath, const uint8_t * userlistPath);
NULL
, no userlist will be loaded.
uint32_t EvalConditionals (boss_db db);
These functions require a database to be created, but do not require Load to have been called, apart from SetProxy, which does not require a database to be created.
SetProxy - Sets the proxy settings for BAPI globally, so that all subsequent BAPI network function calls are affected until SetProxy is called again or BAPI is unloaded.uint32_t SetProxy (const uint8_t * hostname, const uint32_t port, const uint8_t * username, const uint8_t * password);
NULL
, no proxy will be used, allowing clients to unset a previously set proxy.
0
, no proxy will be used, allowing clients to unset a previously set proxy.
NULL
NULL
uint32_t UpdateMasterlist (boss_db db, const uint8_t * masterlistPath);
NULL
, but not both. If link is NULL
, load order suggestions and detail on what the plugin does is crucial for addition to the masterlist.
uint32_t SubmitUnrecognisedPlugin (boss_db db, const uint8_t * plugin, const uint8_t * link, const uint8_t * info);
These functions require a database to be created, but do not require Load to have been called. Plugins should be passed with their unghosted filenames, whether or not they are currently ghosted.
GetActivePlugins - Returns the contents of plugins.txt.uint32_t GetActivePlugins (boss_db db, uint8_t *** plugins, size_t * numPlugins);
NULL
.
uint32_t SetActivePlugins (boss_db db, uint8_t ** plugins, const size_t numPlugins);
uint32_t IsPluginActive (boss_db db, const uint8_t * plugin, bool * isActive);
true
if the plugin is active, and false
otherwise.
.ghost
extension is removed.
uint32_t SetPluginActive (boss_db db, const uint8_t * plugin, const bool active);
true
, then the plugin is activated if it is not already active. If false
, the plugin is deactivated unless it is already inactive.
These functions require a database to be created, but only SortMods requires Load to have been called. Plugins should be passed with their unghosted filenames, whether or not they are currently ghosted.
GetLoadOrderMethod - Returns which method BOSS is using for the load order.uint32_t GetLoadOrderMethod (boss_db db, uint32_t * method);
false
, then sortedPlugins, sortedListLength, unrecognisedPlugins and unrecListLength can either all be valid pointers, or can all be NULL
.
uint32_t SortMods (boss_db db, const bool trialOnly, uint8_t *** sortedPlugins, size_t * sortedListLength, uint8_t *** unrecognisedPlugins, size_t * unrecListLength);
NULL
.
NULL
.
uint32_t GetLoadOrder (boss_db db, uint8_t *** plugins, size_t * numPlugins);
NULL
.
Update.esm
may be positioned in the second position from the top of the load order.
uint32_t SetLoadOrder (boss_db db, uint8_t ** plugins, const size_t numPlugins);
masters before plugin filesrule, and no master may be positioned before the game's master file.
uint32_t GetPluginLoadOrder (boss_db db, const uint8_t * plugin, size_t * index);
Update.esm
may be positioned in the second position from the top of the load order.
uint32_t SetPluginLoadOrder (boss_db db, const uint8_t * plugin, const size_t index);
masters before plugin filesrule, and no master may be positioned before the game's master file.
uint32_t GetIndexedPlugin (boss_db db, const size_t index, uint8_t ** plugin);
uint32_t IsPluginMaster (boss_db db, const uint8_t * plugin, bool * isMaster);
true
if the plugin is a master, and false
otherwise.
uint32_t GetBashTagMap (boss_db db, BashTag ** tagMap, size_t * numTags);
NULL
if no Bash Tags are encountered.
NULL
.
uint32_t GetModBashTags (boss_db db, const uint8_t * modName, uint32_t ** tagIds_added, size_t * numTags_added, uint32_t **tagIds_removed, size_t *numTags_removed, bool * userlistModified);
NULL
if no Bash Tag additions are suggested.
NULL
.
NULL
if no Bash Tag removals are suggested.
NULL
.
true
if the userlist contains Bash Tag suggestion message alterations for the specified plugin, and false
otherwise.
uint32_t GetDirtyMessage (boss_db db, const uint8_t * modName, uint8_t ** message, uint32_t * needsCleaning);
NULL
.
uint32_t GetPluginMessages (boss_db db, const uint8_t * plugin, BossMessage ** message, size_t * numMessages);
NULL
.
NULL
.
uint32_t IsRecognised (boss_db db, const uint8_t * plugin, bool * recognised);
true
if the plugin is present in the masterlist, and false
otherwise.
uint32_t DumpMinimal (boss_db db, const uint8_t * outputFile, const bool overwrite);
true
and outputFile already exists, the existing file will be overwritten. If false
and outputFile already exists, no data will be written. Otherwise, data will be written to outputFile.
Below are (lengthy) code snippets showing examples of how the BOSS API may be used.
#include <iostream>
#include <stdint.h>
#include <fstream>
#include <clocale>
#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
#include <boost/filesystem.hpp>
#include "BOSS-API.h"
using namespace std;
int main() {
//Set the locale to get encoding conversions working correctly.
setlocale(LC_CTYPE, "");
locale global_loc = locale();
locale loc(global_loc, new boost::filesystem::detail::utf8_codecvt_facet());
boost::filesystem::path::imbue(loc);
boss_db db;
uint8_t * mPath = reinterpret_cast<uint8_t *>("Oblivion/masterlist.txt");
uint8_t * uPath = reinterpret_cast<uint8_t *>("");
uint8_t * dPath = reinterpret_cast<uint8_t *>("../Data");
uint32_t game = BOSS_API_GAME_OBLIVION;
const uint8_t * file = reinterpret_cast<uint8_t *>("minimal.txt");
const uint8_t * cleanMod = reinterpret_cast<uint8_t *>("All Natural Base.esm");
const uint8_t * doNotCleanMod = reinterpret_cast<uint8_t *>("bgBalancingEVLAMEAddition.esp");
const uint8_t * inactiveMod = reinterpret_cast<uint8_t *>("français.esp");
const uint8_t * messageMod = reinterpret_cast<uint8_t *>("PerkUP-5555.esp");
const uint8_t * isActiveMod = reinterpret_cast<uint8_t *>("汉语漢語.esp");
uint8_t ** sortedPlugins;
uint8_t ** unrecPlugins;
size_t len;
uint8_t * message;
size_t numTagsAdded, numTagsRemoved;
bool modified;
uint32_t * tagIDsAdded, * tagIDsRemoved;
bool active;
BashTag * BTmap;
size_t size;
uint32_t toClean;
BossMessage * messages;
uint32_t ret;
ofstream out("API test.txt");
out << "TESTING IsCompatibleVersion(...)" << endl;
bool b = IsCompatibleVersion(2,0,0);
if (b)
out << '\t' << "API is compatible." << endl;
else
out << '\t' << "API is incompatible." << endl;
out << "TESTING GetVersionString(...)" << endl;
ret = GetVersionString(&message);
if (ret != BOSS_API_OK)
out << '\t' << "Failed to get version string. Error: " << ret << endl;
else
out << '\t' << "Version: " << *message << endl;
out << "TESTING CreateBossDb(...)" << endl;
ret = CreateBossDb(&db, game, NULL);
if (ret != BOSS_API_OK)
out << '\t' << "Creation failed. Error: " << ret << endl;
else {
out << "TESTING UpdateMasterlist(...)" << endl;
ret = UpdateMasterlist(db, mPath);
if (ret != BOSS_API_OK)
out << '\t' << "Masterlist update failed. Error: " << ret << endl;
out << "TESTING Load(...)" << endl;
ret = Load(db, mPath, NULL);
if (ret != BOSS_API_OK) {
uint32_t ret2 = GetLastErrorDetails(&message);
out << '\t' << "Loading failed. Error: " << ret << ", " << ret2 << ", " << message << endl;
} else {
out << "TESTING EvalConditionals(...)" << endl;
ret = EvalConditionals(db);
if (BOSS_API_OK != ret)
out << '\t' << "Conditional evaluation failed. Error: " << ret << endl;
else {
out << "TESTING SortMods(...)" << endl;
ret = SortMods(db, false, &sortedPlugins, &len, &unrecPlugins, &size);
if (BOSS_API_OK != ret)
out << '\t' << "Sorting failed. Error: " << ret << endl;
else {
out << '\t' << "List size: " << len << endl;
for (size_t i=0; i<len; i++) {
out << '\t' << '\t' << i << " : " << sortedPlugins[i] << endl;
}
out << '\t' << "Unrecognised plugin list size: " << size << endl;
for (size_t i=0; i<size; i++) {
out << '\t' << '\t' << i << " : " << unrecPlugins[i] << endl;
}
}
out << "TESTING GetDirtyMessage(...)" << endl;
//This should give no dirty message.
ret = GetDirtyMessage(db, cleanMod, &message, &toClean);
if (ret != BOSS_API_OK)
out << '\t' << "Failed to get dirty info on \"" << cleanMod << "\". Error no " << ret << endl;
else {
out << '\t' << "\"" << cleanMod << "\" clean status: " << toClean << endl;
if (message != NULL) {
out << '\t' << "Message: " << message << endl;
}
}
out << "TESTING GetDirtyMessage(...)" << endl;
//Now try getting dirty message from one that will have one.
ret = GetDirtyMessage(db, doNotCleanMod, &message, &toClean);
if (ret != BOSS_API_OK)
out << '\t' << "Failed to get dirty info on \"" << doNotCleanMod << "\". Error no " << ret << endl;
else {
out << '\t' << "\"" << doNotCleanMod << "\" clean status: " << toClean << endl;
if (message != NULL) {
out << '\t' << "Message: " << message << endl;
}
}
out << "TESTING DumpMinimal(...)" << endl;
ret = DumpMinimal(db, file, true);
if (ret != BOSS_API_OK)
out << '\t' << "Dump failed. Error no " << ret << endl;
out << "TESTING GetBashTagMap(...)" << endl;
ret = GetBashTagMap(db, &BTmap, &size);
if (ret != BOSS_API_OK)
out << '\t' << "Failed to get Bash Tag map. Error no " << ret << endl;
else {
out << '\t' << "Tag map size: " << size << endl;
out << '\t' << "Bash Tags:" << endl;
for (size_t i=0; i<size; i++)
out << '\t' << '\t' << BTmap[i].id << " : " << BTmap[i].name << endl;
}
out << "TESTING GetModBashTags(...)" << endl;
ret = GetModBashTags(db, doNotCleanMod, &tagIDsAdded, &numTagsAdded, &tagIDsRemoved, &numTagsRemoved, &modified);
if (ret != BOSS_API_OK)
out << '\t' << "Failed to get Bash Tags for \"" << doNotCleanMod << "\". Error no " << ret << endl;
else {
out << '\t' << "Tags for \"" << doNotCleanMod << "\":" << endl
<< '\t' << '\t' << "Modified by userlist: " << modified << endl
<< '\t' << '\t' << "Number of tags added: " << numTagsAdded << endl
<< '\t' << '\t' << "Number of tags removed: " << numTagsRemoved << endl
<< '\t' << '\t' << "Tags added:" << endl;
for (size_t i=0; i<numTagsAdded; i++)
out << '\t' << '\t' << tagIDsAdded[i] << endl;
out << '\t' << '\t' << "Tags removed:" << endl;
for (size_t i=0; i<numTagsRemoved; i++)
out << '\t' << '\t' << tagIDsRemoved[i] << endl;
}
out << "TESTING GetLoadOrder(...)" << endl;
ret = GetLoadOrder(db, &sortedPlugins, &len);
if (BOSS_API_OK != ret)
out << '\t' << "GetLoadOrder(...) failed. Error: " << ret << endl;
else {
out << '\t' << "List size: " << len << endl;
for (size_t i=0; i<len; i++) {
out << '\t' << '\t' << i << " : " << sortedPlugins[i] << endl;
}
}
out << "TESTING SetLoadOrder(...)" << endl;
ret = SetLoadOrder(db, sortedPlugins, len);
if (BOSS_API_OK != ret)
out << '\t' << "SetLoadOrder(...) failed. Error: " << ret << endl;
else {
out << '\t' << "List size: " << len << endl;
for (size_t i=0; i<len; i++) {
out << '\t' << '\t' << i << " : " << sortedPlugins[i] << endl;
}
}
out << "TESTING GetActivePlugins(...)" << endl;
ret = GetActivePlugins(db, &sortedPlugins, &len);
if (BOSS_API_OK != ret)
out << '\t' << "GetActivePlugins(...) failed. Error: " << ret << endl;
else {
out << '\t' << "List size: " << len << endl;
for (size_t i=0; i<len; i++) {
out << '\t' << '\t' << i << " : " << sortedPlugins[i] << endl;
}
}
out << "TESTING SetActivePlugins(...)" << endl;
ret = SetActivePlugins(db, sortedPlugins, len);
if (BOSS_API_OK != ret)
out << '\t' << "SetActivePlugins(...) failed. Error: " << ret << endl;
else {
out << '\t' << "List size: " << len << endl;
for (size_t i=0; i<len; i++) {
out << '\t' << '\t' << i << " : " << sortedPlugins[i] << endl;
}
}
out << "TESTING GetPluginLoadOrder(...)" << endl;
ret = GetPluginLoadOrder(db, doNotCleanMod, &len);
if (BOSS_API_OK != ret)
out << '\t' << "GetPluginLoadOrder(...) failed. Error: " << ret << endl;
else {
out << '\t' << "\"" << doNotCleanMod << "\" position: " << len << endl;
}
out << "TESTING SetPluginLoadOrder(...)" << endl;
len = 1;
ret = SetPluginLoadOrder(db, doNotCleanMod, len);
if (BOSS_API_OK != ret)
out << '\t' << "SetPluginLoadOrder(...) failed. Error: " << ret << endl;
else {
out << '\t' << "\"" << doNotCleanMod << "\" set position: " << len << endl;
}
out << "TESTING GetIndexedPlugin(...)" << endl;
len = 10;
ret = GetIndexedPlugin(db, len, &message);
if (BOSS_API_OK != ret)
out << '\t' << "GetIndexedPlugin(...) failed. Error: " << ret << endl;
else {
out << '\t' << "Plugin at position " << len << " : " << message << endl;
}
out << "TESTING GetPluginMessages(...)" << endl;
ret = GetPluginMessages(db, messageMod, &messages, &len);
if (BOSS_API_OK != ret)
out << '\t' << "GetIndexedPlugin(...) failed. Error: " << ret << endl;
else {
out << '\t' << "Message array size: " << size << endl;
out << '\t' << "Messages:" << endl;
for (size_t i=0; i<len; i++)
out << '\t' << '\t' << messages[i].type << " : " << messages[i].message << endl;
}
//Assume there are at least 3 plugins.
out << "TESTING SetPluginActive(...)" << endl;
ret = SetPluginActive(db, sortedPlugins[2], true);
if (BOSS_API_OK != ret)
out << '\t' << "SetPluginActive(...) failed. Error: " << ret << endl;
else {
out << '\t' << "\"" << sortedPlugins[2] << "\" activated." << endl;
}
//Assume there are at least 3 plugins.
out << "TESTING IsPluginActive(...)" << endl;
ret = IsPluginActive(db, sortedPlugins[2], &active);
if (BOSS_API_OK != ret)
out << '\t' << "IsPluginActive(...) failed. Error: " << ret << endl;
else {
out << '\t' << "\"" << sortedPlugins[2] << "\" active status: " << active << endl;
}
out << "TESTING IsPluginMaster(...)" << endl;
ret = IsPluginMaster(db, cleanMod, &active);
if (BOSS_API_OK != ret)
out << '\t' << "IsPluginMaster(...) failed. Error: " << ret << endl;
else if (active)
out << '\t' << "\"" << cleanMod << "\" is a master." << endl;
else
out << '\t' << "\"" << cleanMod << "\" is not a master." << endl;
out << "TESTING IsPluginMaster(...)" << endl;
ret = IsPluginMaster(db, doNotCleanMod, &active);
if (BOSS_API_OK != ret)
out << '\t' << "IsPluginMaster(...) failed. Error: " << ret << endl;
else if (active)
out << '\t' << "\"" << doNotCleanMod << "\" is a master." << endl;
else
out << '\t' << "\"" << doNotCleanMod << "\" is not a master." << endl;
}
}
DestroyBossDb(db);
}
out.close();
return 0;
}
Contact information for the BOSS Development Team may be found in the Project Members
section of the main BOSS readme. For API-specific support it is best to contact WrinklyNinja, who played a large role in setting up the textfile-based load order standard, created the API, and is currently responsible for BOSS code development.
Credit goes to myk002 and Lojack for significant contributions to the API's development from initial template submission through to beta testing. Credit also goes to kaburke for his contribution to the beta testing of the API.
The BOSS API is written in C/C++ and makes use of the Boost, libcurl and UTF8-CPP libraries.
This document is part of the BOSS documentation.
Copyright (C) 2012 BOSS Development Team.
See the file BOSS ReadMe.html
for copying conditions.