Getting Started
Basic knowledge of C# and Unity is required.
Setting Up Your Environment
Connecting Unity to your editor
Make sure your Unity Editor is connected to whatever you're using to write the script (e.g. Visual Studio Community).
In the Unity Editor, click Edit ??? Preferences ??? External Tools ??? External Script Editor ??? Visual Studio Community.

Restart both your Unity Editor and your Script Editor to make sure these changes take effect.
Creating your mod
Create a new mod and name it whatever your script does.
In the Unity Editor click Holdfast SDK Tools ??? Create Empty Mod

In this mod's folder create a new script and name it what you named your mod.


Double click the script in your Unity Project to open it.
Core Concepts
The script should implement the shared interface that you're going to be using. Each interface has a few different functions but operates the same.
IHoldfastGame, IHoldfastSharedMethods, IHoldfastSharedMethods2, IHoldfastSharedMethods3
- If you're using multiple IHoldfastSharedMethods, make sure you implement them together at the top of your script.
Example:
public class LineFormer : IHoldfastSharedMethods, IHoldfastSharedMethods2, IHoldfastSharedMethods3
Example: Here's a mod called "LineFormer" that has the script "LineFormer.cs" which implements the IHoldfastSharedMethods interface.

Example 2: Here's a mod called "MeleeTrainer" that has the script "MeleeTrainer.cs" which implements the IHoldfastSharedMethods & IHoldfastSharedMethods2 interfaces.

Client or Server, what are those?!
One of the most important concepts to understand while script modifying Holdfast is the concept of "Client" and "Server".
The Server is the game server which handles all players verification data, networking, chat/voip, etc. Whereas the Client is either your own client referred to as the "Owner/Local Player" or someone else referred to as a "Proxy".
Mod Install and Load Types
Similarly to the normal process of using the load_mod <steam_id> load type for mods, we've added:
load_mod_server_only <steamid>??? loads a mod specifically only on server side (such as a custom stats tracking or auto admin mod)load_mod_client_only <steamid>??? inversely only loads the mod on client side (such as a UI mod or an audio replacement mod)mods_installed_server_only <steamid>??? was also added
The advantage is mods that the client does not need to join the server ??? clients won't need to install the mod on their end.
The load order for this feature is: first all the Common Mods are loaded and then the client/server specific ones are loaded. The internal order of each list depends on the order of how they were typed in the config file.
Note: Players can only load mods that the server allows on their list, so a mods_installed_client_only <steamid> doesn't make sense. If you're going to be making a client only loaded mod, it needs to be installed on both the client and the server.
Mod Variables
Mods can receive variables through the PassConfigVariables() method. These variables are supplied in the server config file in the format:
mod_variable <string>??? Global Scope (outside of the map rotations)mod_variable_local <string>??? Local Scope (inside the map rotation)
Global Scope variables will always be loaded BEFORE any local scope variables.
Server config mod variables are sent to all mods running on the server. To prevent conflicts, prefix your variables. A common and effective pattern is modID:key:value, where modID is a unique identifier for your mod (like its Steam Workshop ID or a custom prefix).
Practical Example: Slay Players on Spawn
Part 1: The Mod Variable
mod_variable HardcoreMod:EnableKillOnSpawn:true
HardcoreMod: This is the modID.EnableKillOnSpawn: This is the key.True: This is the value.
Part 2: Script Implementation
This script would parse this variable and use its value. This example shows how to safely check for your mod's specific variable and convert the text "true" into a boolean true.

Security Concerns
As you might be aware, we have some security related scripts that, for example don't allow a modder to gain access to the server or client's machine (ie: System.IO, System.Reflection, etc), these typically will show up as an error on the server's console with something along the lines of:
[UMod.Scripting.ScriptDomain]: Illegal reference to disallowed namespace: System.Reflection.
We've added a feature for server hosts to be able to pass a -allowRestrictedMods in the launch parameters of the server. This will turn off the securities on the server machine ONLY, for ALL the mods. As such, if you rent your servers, you will need to talk to your host provider to enable this if they want to support it.
What this will allow you to do is hook directly with IO operations and other restricted features (writing files, databases, websites APIs, etc) so for development this will open major features.
Gotchas
It's highly recommended that most actions that a mod would do would be deferred by a frame or a few ms when it comes to interacting with a player (healing, damaging, reviving, positioning, rotation, etc). If you code something, and it's logically sound, but in-game it's not doing exactly as expected or has bugs occurring due to it, after trying to delay the action, feel free to ask in #mod-support.
Note: Don't use a "static" member inside of the Interface classes. This confuses the dynamic loader of C# and it'll be bad times for you trying to figure out why.
RC Commands Specific for Modding Use
Make carbon player bots not do any auto input
If you plan on modifying bots position or rotation, call the following script to force bots to not auto move or rotate. Note: this is different than setting the carbonplayer forceInputAxis/forceInputRotation, since those ones will lock ALL the bots in the action, whereas this will allow you to individually control bots's facing rotation and movement system.
rc carbonPlayers ignoreAutoControls <true/false>
Send network trajectory info to client without showing it to players
Similar to drawFirearmTrajectories, this will send the trajectory data from server to client. Unlike the aforementioned command, this will NOT display it to the player, but the mod will still be receiving the data. Enable this only if you're planning on using the "OnShotInfo" on a client side; for server side mods, this isn't required.
rc set drawFirearmTrajectoriesInfo <true/false>
Quiet Messages: Server-to-Client Data Transfer
Quiet messages are a powerful tool for a server-side mod to send data to a client-side mod without showing anything in the player's chat. They are essential for any mod where the server needs to update a client's custom UI or trigger a client-side action.
The communication flow is simple:
- The server executes an rc command to send a string of data.
- The client receives that string from the OnTextMessage event.
Sending Data from the Server
Use one of the following commands:
rc serverAdmin quietPrivateMessage <player_id> <message>
rc serverAdmin quietBroadcastMessage <message>
Receiving Data on The Client
Your client-side mod will receive the data in the OnTextMessage method. It's crucial to filter these messages to ensure you only process the ones intended for your mod.
Because OnTextMessage can be used by many different mods simultaneously, you must create a unique message format to avoid conflicts. A highly recommended pattern is to prefix your messages with a unique ID, like: MOD_ID:COMMAND:VALUE.
Practical Example: Welcome Message to a Debug.Log
Part 1: The Server-Side Code (Sending the Message)
This code runs on the server. When a player spawns, it sends them a quiet message containing their own PlayerID.

Part 2: The Client-Side Code (Receiving the Message)
This code runs on every client. It listens for the specific welcome message and logs it.

IHoldfastGame
To execute RC commands from your script you must gain access to one of the game's core methods. This is accomplished by implementing the "IHoldfastGame" interface.
Implement the Interface
First, ensure your script is using the HoldfastBridge namespace. Your main class signature must then use IHoldfastGame.

Receive and Store the Game Methods
The IHoldfastGame interface requires you to implement the OnGameMethodsInitialized method. The game engine calls this method once during startup and provides an IHoldfastGameMethods object.
The best practice is to store this object in a static property. This makes the game methods accessible from anywhere in your mod's codebase without needing to pass references around.

Execute a Command
With the GameMethods stored, you can now call ExecuteConsoleCommand from any part of your mod.
void ExecuteConsoleCommand(string command, out string output, out bool success);
command: The RC command string to execute.output: An out parameter that will be filled with any text the command returns. This is very useful for debugging.success: An out parameter that will be true if the command was recognized and executed successfully.
Practical Example: Toggling Mouse Lock for a UI Panel
This is a common use case. When you show a custom UI, you might want to unlock the mouse so the player can interact with it.

Here is a file that has all the SharedMethods in a single file so you can copy paste them easily:
https://github.com/Xarkanoth/Holdfast-Scripts/tree/main/IHoldfastSharedMethods
Key Scene GameObjects
When developing client-side mods, you will often need to find and interact with specific GameObjects that are part of the game's scene. Knowing the names of these objects and how to access them is essential for tasks like creating custom UI and manipulating cameras.
Note: GameObject names can change at any time with no update regarding the name change.
The Main Camera: Main Camera SCENE
This is the primary camera that renders the player's view. You might interact with it to get its position, change its field of view, or attach custom visual effects.
- Name:
Main Camera SCENE

The Main UI Canvas: Main Canvas
This GameObject is the root of most of Holdfast's user interface. If you want to add your own UI elements (like panels, text, or images), you will typically make them children of this canvas to ensure they are rendered correctly on the player's screen.
- Name:
Main Canvas

ClientScene GameObjects
| Name | Under | Description |
|---|---|---|
| Post Processing Global Volume | ClientScene | |
| MasterAudio - Client Scene | ClientScene | |
| Nature Renderer Global Settings | ClientScene | |
| Scripts | ClientScene | |
| Audio Listener | ClientScene | |
| WindZone | ClientScene | |
| Camera - Client | ClientScene | |
| Main Canvas | ClientScene | The UI panel that players see in-game. |
| Menu Canvas | ClientScene |
Main Canvas GameObjects
| Name | Description |
|---|---|
| Player Name Tags | |
| Priority Name Tag Canvas | |
| Spyglass Lens Panel | |
| Settings Loading Black Background | |
| End of Round Panel | |
| End of Match Panel | |
| Game Elements Panel | |
| New Player Joined Notification Panel | |
| Free Roam Panel | |
| Death Screen Panel | |
| Spectating Panel | |
| Top Info Bar | Turning off the Top Info Bar will result in it being turned back on automatically. |
| Kill Log Panel | |
| UI Proxy Player Card Container Panel | |
| Main Respawn Timer Container | |
| P Menu Panel | |
| Round Players Control Panel - Dialog Box | |
| Report Submitted Popup | |
| New Scoreboard Panel | |
| Round End Panel | |
| New Chat Panel | |
| VOIP Elements Panel | |
| Poll Voting Panel | |
| In-game Server Details Panel | |
| Controls Notification Popup |
Menu Canvas GameObjects
| Name | Description |
|---|---|
| Main Screen Panels | |
| IntroInfo Panel | |
| Game Console Panel | |
| Settings Loading Panel Overlay | |
| Tooltip Panel | |
| Loading Screen Panel |
Code Examples & Resources
- AGS's Misc Examples: https://github.com/CM2Walki/HoldfastMods
- Elf's Custom Factions: https://github.com/LoganBlinco/BaseCustomFactionMod ??? See also Custom Factions#Replacing Factions
- Spammy's Chat Filter: https://github.com/AgentNo/holdfast-scripts-and-configs/blob/main/scripts/spammys_chat_filter/SpammyChatFilter.cs
- Spammy's OwO Slapper: https://github.com/AgentNo/holdfast-scripts-and-configs/blob/main/scripts/no_uwu_allowed/TestScriptMod.cs
- Xarkanoth's Examples: https://github.com/Xarkanoth/Holdfast-Scripts
Feel free to post in the #mod-support channel on the Official Holdfast Discord for any help.
Support
Got a question that's not covered in this documentation?
We will gladly give you a helping hand should you require, so don't shy away from asking any questions. You will also find members within the community familiar with the toolset willing to do so.
Join the Official Discord, then head to the #become-a-modder channel and click the button to get the Modder role. This will unlock all channels concerning the discussion of modifications and scripting.