#

EDuke32 Addon Manager Documentation

IMPORTANT: This is the initial documentation for the test build of the Addon Manager for eduke32.

Contents and the specification in this document are subject to change based on user feedback and project requirements.

Introduction

This document serves as an introduction and documentation on using the new mod manager in eduke32. The goal of the feature is to provide an integrated tool for users to combine mods and launch them, without needing to set parameters, replace files or pollute the base directory.

It is also intended to give modders a better foundation for packaging and sharing user content with the community, and to increase compatibility between different mod packages. Once the specification is considered stable, it would be welcome to see other ports implement this spec as an option.

The feature is currently undergoing a testing phase before being integrated into eduke32 mainline. We encourage all creators to try and package their mods to use the addon manager, such that potential issues can be spotted early on. You can hereby test the manager in arbitrary ways, for any combination of any type of TC, mods and maps. We appreciate any feedback on the feature, and we hope that this will greatly improve the user experience in the modding scene.

Please share feedback, ideas, issues and experiences either in: Duke4.net Forums Duke4.net Discord

You can also report issues on the following Gitlab page:

https://voidpoint.io/dibollinger/eduke32/-/issues

Obtaining Test Releases

Test builds of eduke32 that integrate the addon manager can be found below.

If you encounter any unexpected behavior, errors and crashes, please report them in the appropriate spaces. Post any log files, screenshots or other evidence of the problem that could help in debugging.

In case of a crash, you can also try to reproduce it with a debug build before reporting, as this may give a more detailed (useful) log from the crash.

We also prepared a sample package of example mods to help people get started with testing the feature, and which can be used as examples for creators to prepare their own mods for the addon manager.

Release Win64 - Win32

Debug Win64 - Win32

Source https://voidpoint.io/terminx/eduke32/-/tree/addons_menu

Sample pack Download


Selecting and Launching Addons

After starting the above build of eduke32, you will notice a new menu option on the main menu called "Addons" (in Ion Fury: "User Content") which, when selected, will open the addon manager. From this menu, you can select the mods, total conversions or official addons which you wish to enable:

Note that you will need to confirm your selection before starting a new game! Doing so will perform a soft reboot of the game, with the chosen addons being activated.

Your selection, as well as the load order of addons, will be remembered between game sessions, and is stored inside eduke32.cfg. You can edit this file to change the addon settings outside of the game. You can also enable a checkbox on the startup window to load the previously selected addons on startup.

Adding Addons to the Menu

To have addons show up inside the manager, you will need to create a folder called useraddons/ inside the same directory as eduke32.exe, and place your downloaded packages inside that folder. You can also specify a different addon directory using the -addondir command line parameter.

Addons may be packaged in the form of .zip, .grp, .ssi, .pk3 or .pk4 archives, or in the form of subfolders. An addon is recognized by the file addon.json located within the base directory of the package. If this file does not exist, the game will not display the addon within the menu. Moreover, there is a special case backwards-compatibility for grpinfo addons, which can be considered a precursor to this format.

Assuming that the game is installed under c:\duke3d\ you will end up with c:\duke3d\useraddons

Here are two examples on what the folder structure might look like:

Plain path copied over

c:\duke3d\useraddons\myaddon\addon.json
c:\duke3d\useraddons\myaddon\game.con
c:\duke3d\useraddons\myaddon\TILES000.ART
c:\duke3d\useraddons\myaddon\duke3d.def
c:\duke3d\useraddons\myaddon\eiffel_blue.mid
c:\duke3d\useraddons\myaddon\maps\bigcity.map
c:\duke3d\useraddons\myaddon\maps\sewermap.map
c:\duke3d\useraddons\myaddon\maps\50battlelor.map

Loading a zip file

c:\duke3d\useraddons\myaddon.zip

Please follow the instructions of the mod author to ensure that the package will show up in the menu.

If you have issues, make sure that you don't for example end up with paths such as

useraddons\myaddon\myaddon\addon.json

which is an easy mistake to do if extracting zip files. Remember that the JSON file must always be located in the base path of the addon.

Using the Menu

Activating addons inside the menu is simple. Simply navigate to the addon you wish to enable, hit Enter or click Mouse1, and the addon will be selected. Then navigate to the first entry in the menu to confirm your selection, upon which the game will reboot with the selected addons enabled.

Content with automatic map start will throw you straight to the skill selection screen. If you decide to go back from here then to reach it again:

Apart from navigating the cursor and selecting items, the addons menu also supports the following additional keybinds:

The load order may have an effect on how scripts are compiled, and how sounds, textures and other assets will be replaced. Generally speaking, the last active mod in the list will be the last one to be loaded.

If for example two mods replace the same sound file, the one further down in the load order list will be the one that takes effect ingame.

Each addon will display an info box that provides details about the addon. This includes both a user-defined description, as well as automatically determined properties of the addon.

Visualized in an image:

General Information

Addons are categorized into 3 separate groups:

Note that some addons may have dependencies and incompatibilities:

For each addon, the following information is displayed in the info box:

When using the debug builds, some additional information will be displayed, which can help diagnose problems with the addon or the executable.

If you want to ignore incompatibilities or other issues, and select and launch any combination of addons, you can set the cvar cl_addonmenu_strict 0 in the console, which will disable all restrictions in selecting addons in the menu.


Creating Addons

In order to set up a mod to appear in the addon manager, it is only necessary to create a file named addon.json which is to be placed in the base folder of your addon's content. This file acts as a descriptor that identifies your addon, provides title, author information, description, and additional options, such as which CON and DEF files to load.

You can package your mod as a .zip, .pk3, .pk4, .grp or .ssi, or in the form of a subfolder, which needs to be placed inside the useraddons/ directory.

The addon.json file is expected to follow standard JSON syntax. The minimum content for the file consists of the manifest_version and id keys, as follows:

{
  "manifest_version": "1.0",
  "id": "myaddon"
}

The former identifies the version of the json descriptor, while the later is an identity that is required to allow other addons to reference this addon in dependencies and incompatibilities.

If the descriptor is found in the package, the addon menu will list it for activation. On being activated, the package is added to the engine search path, and the game will basically act as if all the contents of the package were placed directly in the directory of eduke32.exe. As such, mod content can now be cleanly separated.

Mapster32 does not currently support the addon manager, but may do so in a future release. If you wish to create maps with addon content right now, you can load the package contents using the -j launch parameter for subfolders, and the -g launch parameter for package addons. To playtest the maps with the respective addons, you can enable them in the main game menu, and then check the "Launch previously selected addons" button in the startup menu.

Example Addon JSON

The following is an example addon.json descriptor that provides an addon manager entry for the "Shaky Grounds" episode:

{
    "id": "merlijn-shakygrounds",
    "game": "duke3d",
    "title": "Shaky Grounds",
    "author": "Merlijn v. Oostrum",
    "version": "4.0",
    "description": { "path" : "sg_addondesc.txt" },
    "preview": "preview.png",
    "CON": { "type": "module", "path": "./sgmodule.con" }
}

Each token is explained in detail in the specification below. Important to note is that the new addon manager allows specifying CON files that are appended as modules, rather than complete code replacements. In Shaky Ground's case, the CON files would define level and episode names as well as the music and some new sounds, but would not otherwise alter the actor behavior.

You are encouraged to use this json, or the addon.json files from the samples package as a reference.

GRPINFO Addons

The addon package manager also provides backwards-compatibility support for games defined inside grpinfo, as well as the following (semi-)official addons:

The game will only list the package in the menu if it has GAMEFLAG_ADDON (bit 16) specified in flags field of the grpinfo file. This provides support for existing grpinfo files, such as those of the EDuke32 Addons Compilation.

The tokens inside the grpinfo file translate as such:

In the future, the .grpinfo file may be extended with additional tokens to display additional information in the menu, such as a preview image, description and author.

We recommend packaging mods, TCs and maps with custom content using the JSON format, as this allows for modular loading of addons. If you intend to create a standalone game, we recommend you use the .grpinfo files.

Addon Descriptor Specification v1.0

This section lists all available tokens for version 1.0 of the addon descriptor, as well as their meaning.

New tokens may be added in future versions based on requirements and user feedback.


id - Addon Identity

Mandatory token.

The id token is a creator-specified value that is supposed to uniquely identify the addon, such that other addons are able to refer to it through the dependencies and incompatibles tokens.

The specified value must be a string. Only alphabetical and numerical characters are allowed, as well as the characters +, -, _ and -.

To ensure that this value is as unique as possible, try to use a prefix that is unique to you as an author, separated by a dash, then followed by an abbreviation of the title of the addon.

Example usage:

"id": "db64-exampleaddon",

version - Addon Version

Optional token.

Takes a single string value which specifies the version of the addon. This value is used by dependencies to refer to a specific required version of an addon. If the string is omitted, the dependency will always match.

The version string must be a sequence of number segments separated by periods. The string may end with a dash, followed by an arbitrary ASCII character sequence. Dependencies will typically assume a running numbering system, i.e. =>1.4 is 1.4 or newer. Thus it's required that you stick to x.y version labels with optional text as -z at the end.

While this token is optional, it is still recommended to specify a version for each released addon package.

Example Usage:

"version": "3.14-RC2",

Other examples:

{ "1.0",  "2.0.0.0",  "3.4-alpha", "0.1.20" }

game - Game Dependency

Optional token.

Takes either a string, or an array of strings as value. Specifies the type of game for which this addon can be used. For instance, if the specified gametype is "duke3d", the addon will not appear in the menu if Ion Fury is currently running.

If multiple strings are specified, the addon will show up for all of the specified games. If this token is omitted, the addon will show up for any game.

Recognized values are:

{ "any", "duke3d", "nam", "ww2gi", "fury" }

Example usage:

"game": ["nam", "ww2gi"],

gamecrc - Extended Game Dependency

Optional token.

Takes either a hex string, an integer, or an array of hex strings or integers as value. Each value is the CRC32 checksum of the GRP that must be found in the dependency chain of the currently selected game package. Like the "game" token, this token restricts which game types the addon will show up for. If at least one CRC matches for at least one GRP in the dependency chain, the addon will appear in the menu.

This value can be used to achieve more fine-grained exclusion where the "game" token does not suffice. This is useful if the game dependency should be based on a custom grpinfo file, or if a specific version of a game is targetted, such as "World Tour" for Duke3D.

Example usage:

"gamecrc": "0x982AFE4A",

Or alternatively, as a signed integer:

"gamecrc": -1742012854,

It can also be an array of hex string or integer CRCs. If any is fulfilled, the addon will be shown:

"gamecrc": [ "0xdeadbeef", -1742012854 ],

title - Addon Title

Optional token, expects a string as value.

This is the name of the addon as displayed in the menu, and is used purely as visual information for the user. If omitted, the game will instead display the package or subfolder name. If the title exceeds the boundaries of the screen, it will be truncated.

Example Usage:

"title": "Duke Nukem 4D"

author - Addon Author

Optional token, expects a string.

Name of the author and/or possible contributors, which will be displayed in the info box on the menu. If omitted, will not display any authors.

If the string length exceeds the screen boundaries, the text will wrap. Therefore, you can specify as many authors as needed.

Example Usage:

"author": "Bob Bobbington and the musketeers"

description - Addon Description

Optional token.

Expects either a single string, or an object that contains the path to a description file. This defines the addon description shown to the user, which can include a brief of your addon, story, further credits, links and other bits. You can format the string using newline characters ("\n"), as well as color palette sequences (e.g. "^12" for palette 12).

If a filepath is specified, then this path should be relative to a subfolder contained within the package. There is no length limitation imposed currently. If omitted, will not display a description.

Example usage:

"description": "^2Example addon continues!\n\n^0Aliens are at it again and have created an example addon to cause further mayhem!\n\nStory and conception by Bob Bobbington and maps by The musketeers! (Dank Dave & Steve Jobs)"

Or, if referring to a separate file for better formatting:

"description": { "path": "path/to/desc.txt" }

preview - Preview Image

Optional token.

Expects a string as value, which represents the relative path to an image file contained within the package. If the image is successfully imported, will display a preview while the addon is under the cursor in the menu. Accepts .PNG, .JPG, .GIF, .BMP and .PCX files.

Animations are not supported, and the dimensions of the image are restricted to 320x200px.

Example usage:

"preview": "path/to/preview.png"

GRP - Additional GRP/ZIP packages

Optional token.

Accepts either a string or an array of strings as value. Defines a list of relative paths to GRP or ZIP archives contained within the package. These will be loaded together with the remaining addon content once the addon is activated.

Example usage:

"GRP": "path/to/package.grp"

or

"GRP": [ "package1.grp", "package2.zip" ]

CON - CON Script Path

Optional token.

Accepts either a single object, or an array of objects as value. Within each object you specify the path to the CON script, as well as the type of the script. Paths must be relative from the addon package base folder.

There are currently two types of scripts:

Note that there is limited support for overriding existing CON definitions at this time. It is however possible to override level, music and episode definitions, for instance. More may be introduced later on in development.

Example usage:

"CON": { "type": "main", "path": "path/to/game.con"}

or as a module:

"CON":
[
  { "type": "module", "path": "path/to/moduleA.con"},
  { "type": "module", "path": "path/to/moduleB.con"}
]

DEF - DEF Script Path

Optional token.

Accepts either a single object, or an array of objects as value. Used exactly like the "CON" script token, but instead loads DEF files. Paths must be relative from the addon package.

Also supports two types of scripts:

Example usage:

"DEF": { "type": "main", "path": "path/to/duke3d.def"}

or as a module:

"DEF":
[
  { "type": "module", "path": "path/to/moduleA.def"},
  { "type": "module", "path": "path/to/moduleB.def"}
]

RTS - RTS File Path

Optional token.

Expects a single string, which describes the relative path of the RTS wad file to load. RTS files contain the sounds used for the "Remote Ridicule" taunts, and are structured like WAD files from Doom.

Example usage:

"RTS": "path/to/game.rts"

dependencies - Addon Dependencies

Optional token.

Expects either a single object, or an array of objects as value. Each object contains at least the identity ("id") of the required addon, and optionally also a version dependency.

For example you can require an official addon as a base and then supply additional maps or art as an addon to it. This makes it possible to, for instance, create maps explicitly for "Duke Nukem: Life's a Beach" without needing to integrate the maps into the dependency itself.

Version dependencies accept the following strings as prefix ">=", "<=", "==", ">" or "<". If the prefix is omitted, exact equality is assumed. If the version is omitted, compatibility with all versions is assumed.

Note that version strings are compared per segment, until a difference in value is detected. Characters after the dash are compared using lexical order.

Example Usage:

"dependencies":
[
  {"id": "dukevaca" },
  {"id": "vacaplus", "version": ">=1.2.2" }
]

incompatibles - Incompatible Addons

Optional token.

Expects either an object, or an array of objects. Uses the same format as dependencies, and prevents activating the selected addon with any of the ones listed within this token.

In case your mod is known to break or otherwise is incompatible with some known addons, you may list said incompatible addons using this token, to prevent users from launching them together.

Example Usage:

"incompatibles": {"id": "brutal-duke", "version": "<2.0" }

rendmodes - Compatible Renderers

Optional token.

Expects either a single string, or an array of strings. Each string represents one supported renderer. If omitted, all modes are implicitly assumed to be supported.

If your mod requires a certain renderer to be used, then you can specify them using this token. For example, a HRP+Model pack should boot into polymost/polymer, and conversely, some maps may only look correct in classic mode.

If the user currently has an incompatible rendermode selected, the game will automatically switch to the lowest supported mode after reboot (e.g. if "Classic" is not supported, the game switches to the "Polymost" renderer if available).

Supported values are:

{ "classic", "polymost", "polymer", "opengl" }

OpenGL stands for either "polymost" or "polymer".

Example Usage:

"rendmodes": [ "classic", "polymost" ]

startmap - Map File to Launch after Reboot

Optional token.

Expects a single object, which either specifies the relative path to a map file as a string, or integers pointing to a specific map slot. Can load both usermaps as well as levels defined in a specific episode slot.

The "volume" token is the "episode" slot, while the "level" token is the level slot.

Allows you to auto-start a map after the addon was activated and the game has rebooted. The player will be displayed the skill select menu before the level is started. The player is able to abort starting the level as well, which will return him back to the main menu.

Example Usage:

Usermap:

"startmap": { "file": "path/to/file.map" },

Level Slot:

"startmap": { "volume": 0, "level": 3 }

Changelog

Known Issues

There are some known issues with the current addon manager implementation:

Future plans

The Idea Bin

Various ideas get collected here, if time & motivation allows then they might get also moved to "Future plans". This can include community ideas and additional notes as responses.

Credits