Beardlib Editor Tutorials

Guides and information on creating things with and using the Beardlib Editor addon for Beardlib.

Creating Custom Contractors

Creating Custom Contractors


Hello! Ever wanted to make a custom contractor for your custom heist? Well, here's an easy-to-follow guide on how to make a (possibly good) custom contractor

Disclaimers This is all mostly unavailable using the visual project editor. This also mainly applies to Windows, since I haven't used any other operating systems.

First of all, open your Steam folder!

Mac - ~/Library/Application Support/Steam/steamapps/common/PAYDAY 2

Linux - ~/.local/share/Steam/steamapps/common/PAYDAY 2

Windows 64bit - C:\Program Files (x86)\Steam\steamapps\common\PAYDAY 2

Windows 32bit - C:\Program Files)\Steam\steamapps\common\PAYDAY 2

This might be different depending on where you installed PAYDAY 2. Make sure you actually have BeardLib & BeardLib Editor

Making The Contractor Exist

Go into the 'Maps' folder, and into the heist you created previously. If you didn't create a heist, follow this tutorial. Part 1 of map editing: Creating your first heist

Then with a text editor such as 'Notepad++', 'Atom', or 'Sublime Text', right click the file labeled 'main.xml'. Add a string underneath the 'Localization' tag.

The string is this:

<contact assets_gui="guis/mission_briefing/preload_contact_bain" desc_id="contact_placeholder_desc" id="placeholder" name_id="contact_placeholder_name" package="packages/contact_bain"/>
I'll explain what each of these parameters mean.

assets_gui - I'm heavily certain this is the video used when displaying heists made by the contact, just use the one by Bain.

desc_id - This is the ID for the string in localization for the description of your contractor located in the Codex.

id - This is the ID that your contractor uses, self-explanatory, make sure it's not equal to another contractor or you might mess stuff up.

name_id - This is the ID for the string in localization for your contractor's name, highly important if you don't want error text!

package - I honestly don't know what this is, it's probably important for 'assets_gui'.

Customize these properly, don't just leave them all as placeholder. With the exception of assets_gui and package.

Localizing Your Strings

After you're done making your contractor in 'main.xml' go to the 'loc' folder in your heist folder, and then open 'english.txt'. This can be opened with ANY editor, including Windows Notepad.

This is where information like your contractor name & description, heist name and briefing, and map name and briefing goes. Copy the following stuff into the file. Make sure you only have one set of the curly brackets.

  "contact_placeholder_name" : "Placeholder"
  "contact_placeholder_desc" : "The placeholder description."	

You should absolutely edit all the information in here, if you set a different ID than contact_placeholder than change it to what you used in 'main.xml'. The right side text is what the text will look like in-game.

The Extra Polish

Without using hooks, you won't actually see the description of your contractor pop up. Using a specific hook you can make it appear in the Codex. This isn't necessary but it is a very nice touch.

Hooks:PostHook( GuiTweakData, "init", "maowcraftcontacttemplate", function(self) # Change maowcraftcontacttemplate
	local contact_data = {
		id = "placeholder", # Change placeholder
		name_id = "contact_placeholder_name", # Change contact_placeholder_name
			desc_id = "contact_placeholder_desc", # Change contact_placeholder_desc
			video = "dragon1", # Not necessary to be changed
			post_event = nil

	table.insert(self.crime_net.codex[1], contact_data)
  1. Copy this into a text editor, and save it as guitweakdata.lua.
  2. Change all the parameters to the information you put in your contractor.
  3. Create a new folder in your heist folder named 'Hooks'.
  4. Go back to 'main.xml'.
  5. Make a new tag at the top of 'main.xml'
<Hooks directory="Hooks">
		<hook file="guitweakdata.lua" source_file="lib/tweak_data/guitweakdata"/>  

Make sure to test that everything works, if something goes wrong, check again, or send a message at the #help channel of the official ModWorkshop discord server. Link to Discord Server - #help

Have a great day!

Custom Subtitled Dialogue and Sound

If your heist or mod needs custom dialogue that includes subtitles follow the following steps.

  1. Add your Sounds, for this example I will add sounds to a level for a custom map.
		<sounds directory="assets">
			<sounds directory="sounds">
				<sound id="cus_rex_test_1" path="cus_rex_test_1.ogg" subtitle_id="cus_rex_test_1"/>
				<sound id="cus_rex_test_2" path="cus_rex_test_2.ogg" subtitle_id="cus_rex_test_2"/>
  1. Set up the Dialogue Script Data, this will add the dialogue to the dialogue element in editor.

    In the Main.xml file add this to your levels script data:

		<script_data_mods directory="scriptdata">
			<mod replacement="new_dialogue.dialogue" replacement_type="custom_xml" target_ext="dialog" target_path="gamedata/dialogs/rex">
				<options merge_mode="add" mode="add"/>
			<mod replacement="index.dialog_index" replacement_type="custom_xml" target_ext="dialog_index" target_path="gamedata/dialogs/index">
				<options merge_mode="add" mode="add"/>

In your Scriptdata folder in the Project add 2 txt files: ('new_dialogue' can be renamed to anything you wish)


	<include name="new_dialogue"/>


	<dialog id="cus_rex_test_1" priority="1" sound="cus_rex_test_1"/>
	<dialog id="cus_rex_test_2" priority="1" sound="cus_rex_test_2"/>
  1. From there your Dialogue should be added to the game!

Additional Notes! If you want your sound to play in 3D space (from a speaker or character) make sure its a mono-sound. If you instead want your sound to play as if in the players ears (like Bain dialogue) make sure its in stereo-sound. Make sure you localise your subtitles or players will see 'ERROR:text' ingame.

Level Design

Level Design

Ai Escorts (and Special Objectives)

A test map is provided in the Attachments.

Escort Characters

All Escort characters will stop moving when enemies block their path, different radiuses apply for different hostages. Escort unit data typically contains the following (using Matt as an example, This is not important unless you want to make a custom character act as an escort)

<!--Escort Animations-->
<anim_state_machine name="anims/units/escort_guy/escort_undercover_machine" />

<!--Escort Extensions-->
	<extension name="base" class="CivilianBase" >
		<var name="_tweak_table" value="escort_undercover" />
		<var name="_spawn_state" value="escort_undercover/spawn/loop" />
	<!--Most important, makes the escort not die.-->
	<extension name="character_damage" class="CivilianDamage">
		<var name="immortal" value="true" />
		<var name="_no_blood" value="true" />

Escort Special Objectives/Patrols

Escorts in heists are fairly simple preset tracks for Escort civilians to follow.

First step is to choose your patrol path/s and add those positions to the level. Keep in mind you may need multiple patrol groups if you want your Ai to take different paths for different reasons.

Once you have a path for the Escort to take you need to add a SpecialObjective element for them to use that patrol group and use it like one. Not all of these settings are required, but most are not neccisary for what we are doing here. (Access Flags are not shown in the following image but use civ_male/civ_female to make it work for escorts.)

Telling Escorts to use a path

When spawning the Escort character you will want to include an EnemyDummyTrigger element to tell the escort to use the SpecialObjective we made.

Making things happen along the way

Since were using a SpecialObjective element to make these escorts we can include triggers and branches to them.

Level Design

Applying Custom Instances

Note: Newer versions of Beardlib Editor includes dedicated custom instances, this workflow is largely unneccisary and outdated. Information on the page is still useful past the main.xml example.

Instance Example (In the Main.xml)

	<instance id="level_id">
		<add file="levels/level_id/add.xml"/>
		<include directory="levels/level_id">
			<file file="" type="generic_xml"/>
			<file file="world/world.continent" type="custom_xml"/>
			<file file="world/world.mission" type="generic_xml"/>
			<file file="editor_only/editor_only.continent" type="custom_xml"/>
			<file file="editor_only/editor_only.mission" type="generic_xml"/>

With this setup you can work on the instance as a level without needing to move any files around


Example: table continent="world" folder="levels/instances/unique/hoxestatesecurityroom/world" indexsize="1000" name="hoxestatesecurityroom001" position="0 0 0" rotation="0 0 0 0" script="default" startindex="11000"









Example: entry index="12" type="string" value="hoxestatesecurityroom001"

entry index="12"




Level Design

Cubemaps, Cubelights and Lighting your level


A cubemap is a six-sided texture used for reflective surfaces to reflect stuff. Here's an example:

This looks wrong! Why are there buildings in the reflection even though we are indoors?

That's because diesel does not support realtime reflections, so map makers have to create cubemaps manually

To do so you will need to spawn a cubemap_gizmo from the editors spawn menu. Position it however you want. Then head over to the env manager and press "Build Cubemaps" (this will fail if you dont have python3 and PIL module installed) If successful, the editor will tell you the path to the cubemap relative to your map's directory. Remember this path!

Reload the map, click on the env tab in the upper menu and find your cubemap texture in the cubemap dialog box. Once selected, the global cubemap will change:

Eh, not too good looking, but it will do!

The game will keep track of changes to the cubemap texture so you won't have to reload the map each time you build cubemaps for the gizmo you're working with. Keep in mind that you will have to reload the map every time a new gizmo is added to the map!

This cubemap is global, how can i make certain areas have different cubemaps?

For that you'd need to create a separate env area, tick the cubemap option and include an environment file with a different cubemap texture. You'd need to do this for every area

Why are reflections unchanged for some units?

That's because these units override the global cubemap. To fix that you need to extract the unit, change the global_texture parameter to the path of your cubemap in the seq_manager and load it from extract. That way you can have per-unit local cubemaps!


Cubelights are a six-sided texture used for projecting static shadows from lightsources onto the environment Here's an example:

You can do that too! All you have to do is to spawn a light_omni_shadow_projection in the spawnmenu. All lights with a shadow_projection prefix can build projection textures. Now just select the light, head over to the env manager and press "Build Projection Lights" (this will fail if you dont have python3 and PIL module installed)

Same as with cubemaps, the projection texture will only start working after a reload. Let's compare the two: Before: After:

Building projection lights can also fix light leaking through map geometry

Projection lights don't build for a specific light unit!

If your light unit does not have options such as shadow resolution or doesn't have any light settings at all you would need to extract it to build projection lights

Level Design

Limitations and Issues with mapping in Diesel

Here is a list of potential issues you may have when working on custom maps.

Out of Memory Crash

Application has crashed: C++ exception
Could not load texture because IDirect3D9::CreateTexture call failed.
Direct3D could not allocate sufficient memory to complete the call.

This issue only happens on maps that have too many assets loaded, through overbloated packages or high file size assets. Temporary workaround to this issue is to lower texture settings to Medium or lower, however in most cases this can be avoided by loading assets that only exist in larger packages from Extract.

If you use more than 2000MB of memory in editor you will likely crash due to team Ai using a very large amount of memory, even more likely players will crash when using mods in the heist also. The White House heist uses ~1600MB. The Safehouse uses ~1600MB.

You can figure out how close you are to 'OOM' (Out of memory) crashing by using the -qa steam launch option.

Ingame it will look like this.

Loading units

TLDR: two of the solutions are near perfection but both have some drawbacks, adding them from extract cannot load some units and packages cause slow loading times and unstable maps.

Loading units for maps was an issue I tried solving for a long time.

Loading from extracted files

Phase 1:

With overkill adding a new function to add files(DB:create_entry) I found out you can force existing assets to be loaded by loading them from the map itself but sadly this has a few issues, first of all it takes a lot of space and secondly biggest issue is that it cannot load effects from what I know which can cause some units to crash.

Phase 2:

After releasing the editor I had that idea floating in my head that maybe we don't need the model and texture of the asset to make it load in the map(had the idea after finding out you can mostly only read these files inside the game using DB:open even if they're not loaded) and I was right, after testing that it had no issue what so ever to load the units.

With phase 2 we cut the file size of the map by a lot(for example I tried doing that for a big custom heist and it was only around 8mb) this makes that method a more viable option now the only remaining issue is that DB:create_entry does not support effects which is a big issue and can cause some units to fail to load, this option is not really viable for characters. DB:create_entry also doesn't support fonts from what I know(pls ovk)

In future versions of the editor you will see an improvement to the load from extract system.

Loading packages

After fiddling around with packages I found out you can load as much as you want as long as you monitor the size of the packages(packages are actually bundles just non hashed! so we can see their actual size by using core lua functions) this method a limitation, it can be quite hard to load packages for big maps resulting in the map loading too much packages which can also cause the loading to be very slow and make the map unstable.

Level Design

Making and adding Environments

Environment is like a config which decides how light and shadows look in your level, this is what makes the level a night map or a day one, you can also use environment areas to make rooms look better, here we will talk about making them generally.

All of the actions are done in environment menu which is the world icon at the top menu.


You can edit the values of the environment freely, for now we won't have an exact explanation for each value in there, you can play around with it until you feel comfortable with the controls and the environment itself.

Some points:


You can save the environment for any use by pressing save, this will open a dialog to fill a file name for the environment(the directory starts from your game directory)
Press Apply and you're done.

Adding to your level(including)

If you wish to include that environment in your level you have to press Include current, this will add the environment to your level, which will allow you to use it in the level in an envrionment area.

After pressing it, the environment should be added to the Included Environmnents

Using it

Level Design

Navigation in diesel

They are used to allow enemies to get from one navigation part to another.

When they are executed they can be used freely by enemies/ai teammates. You need to go to "Manage Access Flags" and select which units should be able to use this navlink.

"Search Position" needs to be somewhere in the navigation area that the enemy should go to after doing the animation.

Level Design

Optimisation: Occlusion and Portals

What is an Occluder?

Occluders are simple planes that are used to hide props (specifically objects of a unit).

In the model itself oc_planes (the commonly name for them) are a one-sided plane pointing its occluding face in the Y-Positive direction.