ContentLoader makes it easy to add new content to Brotato.
You can add: Characters, Items, Weapons, Weapon Sets, Challenges, Elites, Difficulties, Consumables.
For references, see the mods that use ContentLoader in Notable Mods below.
- Requirements
- Structure
- Adding Content
- ContentData Resources
- Items
- Characters
- Weapons
- Weapon's Characters
- Weapon Sets (Classes)
- Challenges
- Debug Items
- Appendix
You are free to structure your ContentLoader mods however you want, beyond ModLoader's required structure.
However, I would recommend that you follow the standard set by Invasion, which uses the following folders:
content
- Stores all the custom content, with subfolders for each type (items
,weapons
, etc)content_data
- For your ContentData resource filesextensions
- For code that extends vanillatranslations
- Translation CSVs (ie. custom text for item descriptions, etc)
💡 Tip: For your images, it is highly recommended that you prefix all filenames with
yourmodname_
. See .import on the ModLoader Wiki for info on the benefits of this.
To add content to the game: In your mod's _ready()
method, get the ContentLoader class and use its load_data
method.
func _ready()->void:
# Get the ContentLoader class
var ContentLoader = get_node("/root/ModLoader/Darkly77-ContentLoader/ContentLoader")
var content_dir = "res://mods-unpacked/Author-ModName/content_data/"
var mod_log = "Author-ModName"
# Add content. These .tres files are ContentData resources
ContentLoader.load_data(content_dir + "modname_characters.tres", mod_log)
ContentLoader.load_data(content_dir + "modname_items.tres", mod_log)
ℹ️ Note: ModLoader does not support global classes, which is why we need to use the
get_node
approach shown here. See Advanced > Child Nodes on the ModLoader Wiki for more info.
Use the ContentData
resource class to set up the content you want to add.
To create a new ContentData resource:
- Right-click a folder
- Choose "Add New Resource"
- In the search bar, enter
ContentData
- Choose the resource shown (it's the content_data.gd file)
- You can now add your content by dragging your data files into the respective arrays.
ℹ Note: Godot may have an issue where
ContentData
is not available when trying to create a new resource. To fix this, ContentLoader provides an empty ContentData resrouce called EXAMPLE.tres. It's in ContentLoader's main mod folder, and you can duplicate this file into your own mod's folders.
💡 Tip: Once you've created your first ContentData resource, you can create another one quickly by right-clicking it and choosing Duplicate (or click it and use the keyboard shortcut Ctrl + D.
By default, a new ContentData resource looks like this:
Add ItemData resource files to the Items array.
You can drag and drop resource files onto the array box.
⚠️ Warning: There's a bug in Godot where if you don't expand the array before you drag items onto it, the existing items may be wiped. So always expand arrays before you add to them!
Add CharacterData resource files to the Characters array.
Add WeaponData resources to the Weapons array.
In the setup shown here, we've added a weapon called "Chainsaw". Note how each tier of the weapon is added separately.
This lists the characters who can start with a weapon. It should be used in the same ContentData resource file that adds the weapon(s).
It is an array of arrays:
- The top-most array corresponds to the weapons in
weapons
. - Within each of these arrays, their own array is a list of characters who can start with that weapon.
💡 Tip: Adding each individual weapon as a separate ContentData resource will make using
weapon_characters
much easier.
This setup adds the 4 tiers for "Chainsaw" (as shown above), and also adds two characters who can start with the Tier 1 version of the weapon (ie. chainsaw_1_data.tres, which appears first in the weapons
array, and so corresponds with the 1st top-level array in Weapons Characters):
This next setup does the same, but also adds Knight as a starting character for the Tier 2 version (ie. chainsaw_2_data.tres, which appears second in the weapons
array, and so corresponds with the 2nd top-level array in Weapons Characters):
Add your custom weapon set resources to the Sets array. They can be added to a weapon's sets
array just like vanilla sets.
Add Challenge items to the Challenges array:
Adding items to the "Debug Items" array will add them to every character you play as, for every run. It has the same effect as using the debug_items
array in DebugService.
You can use it force an item to always be added to the player's inventory, without adding it to the shop pool.
- In an older version of Invasion, this was used to add a special item that showed the current version of the Invasion mod. This special item was not added to the normal Items array, and was not marked as "unlocked by default", which meant it wasn't part of the shop pool.
You can also use it to create a ContentData resource file that adds certain items for your own internal testing. This lets you keep your list of debug items in a single ContentData resource file, which can be selectively enabled/disabled. The advantage to doing this instead of using DebugService.items
is that you won't need to clear the items
array when you want to play without all the items.
Same as Debug Items, but for weapons.
Adds custom Elites to the pool. Custom Elites are spawned randomly during Elite waves, just like vanilla Elites.
Adds custom difficulties. Accepts a difficulty resource, which follows the same format as vanilla's difficulties.
For more details, view the README for my example mod: Darkly77-CustomDifficultyModes
Adds custom consumables. Please note that this feature has not been tested.
ContentLoader provides a few methods for loading data:
load_data(mod_data_path: String, mod_name: String = "Author-ModName"):
Add content from your ContentData resource. Specify the path to your ContentData resource file (.tres) with the 1st argument (mod_data_path
), and specify your mod ID with the 2nd (mod_name
).
The majority of mods will only ever need to use this method.
# Example:
var content_dir = "res://mods-unpacked/Author-ModName/content_data/"
var mod_log = "Author-ModName"
ContentLoader.load_data(content_dir + "modname_characters.tres", mod_log)
Add content via a dictionary, instead of a ContentData resource. This is an advanced feature that most mods will never use. But for those that want to, it allows you to programatically create mod content on the fly.
load_data_by_dictionary(content_data_dict: Dictionary, mod_name: String = "Author-ModName"):
Supports the following keys:
var content_data_dictionary = {
"items": [], # ItemData
"characters": [], # CharacterData
"weapons": [], # WeaponData
"sets": [], # SetData
"challenges": [], # ChallengeData / ExpandedChallengeData
"upgrades": [], # UpgradeData
"consumables": [], # ConsumableData
"elites": [], # Enemydata
"difficulties": [], # DifficultyData
"debug_items": [], # ItemData
"debug_weapons": [], # WeaponData
}
Also supports passing a dictionary with a single key, eg:
var content_data_dictionary = { "items": [] }
Note that you'll need to create textures from any images on disk. You can use Brotils for this, via brotils_create_texture_from_image_path
. ContentLoader already depends on Brotils, so you are safe to use this method.
load_data_by_content_data(content_data, mod_name: String = "Author-ModName"):
Load content from an instance of ContentData. Similar to load_data_by_dictionary
, but allows you to work with a ContentData object instead of JSON. Both have the same result, so which one you want to use depends on your personal preference.
As above, this is also an advanced feature that mods mods will never use.
Note 1: Mods can't use global classes, so you need to load the class before you create a new instance of it, eg:
var content_data = load("res://mods-unpacked/Darkly77-ContentLoader/content_data.gd").new()
Note 2: There may be an issue with adding things to the empty arrays of a new ContentData instance, and this can cause your content to be added to every array. To fix this, duplicate your empty arrays before adding to them. An example of how to do this is below. You can also search for debug_items.duplicate
in the code for the file content_loader.gd to see a working example.
var content_data = load("res://mods-unpacked/Darkly77-ContentLoader/content_data.gd").new()
var custom_items = [] # add item resources here
content_data.items = content_data.items.duplicate() # This is needed in case the array is empty
content_data.items.append_array(custom_items)
load_data_by_content_data(content_data, "Author-ModName")
ContentLoader stores all the content it adds, and provides 2 API methods to access the data. Note that while these methods use the string by_item
, "item" in this case actually means any content added via ContentLoader.
lookup_modid_by_itemid(item_id:String, type:String) -> String:
Gets the ID of a mod from an item ID.
item_id
is alwaysmy_id
.type
is either:character
/challenge
/elite
/item
/set
/upgrade
/weapon
lookup_modid_by_itemdata(item_data) -> String:
Gets the ID of a mod from a resource object.
item_data
is one of these types of objects: (CharacterData / ChallengeData / ConsumableData / SetData / UpgradeData / WeaponData / EnemyData / DifficultyData / ItemData).
ContentLoader adds content to ItemService
, which is possible without using ContentLoader.
However, it also performs a number of other important functions, including:
- Safely adds custom content to
ProgressData.upgrades_unlocked
. - Initialises custom characters (which need to have their own
CharacterDifficultyInfo
object). - Adds custom weapons to corresponding characters.
- Duplicates the debug_items and debug_weapons arrays before adding to them (which fixes a critical issue in Godot's engine).
- Tracks all added content (allowing any mod to see what content has been added, and by which mod).
- Re-runs the applicable vanilla funcs after adding content.
The mods listed here were created or ported by Darkly77, ContentLoader's lead developer. They show how to use its various features in a standardised way.
Their mod_main.gd file is the entry point for ContentLoader.
Mod | mod_main.gd |
---|---|
Assassin | mod_main.gd |
Invasion | mod_main.gd |
ContentLoader was created by Darkly77, with contributions from KANA.
It is based on dami's Multiple Mod Support, and its core functionality still uses dami's code.
Footnotes
-
download counter: the repo had to change so the counter got wiped, was 250, RIP ↩