# Multiplayer modding (experimental) This page describes how to create and run mods for the experimental multiplayer release of Teardown. It assumes that you are already familiar with the single-player modding workflow, the editor and the Lua scripting basics. ## Multiplayer scripting video tutorials We recommend starting with the multiplayer scripting video series. These tutorials walk through: - Basic multiplayer scripting concepts - Handling multiple players and input - Overlay graphics and user interfaces - Game modes and the multiplayer helper library (`mplib`) - A few more advanced topics and optimizations Number | Video | Length ------ | ------|-------- 1 | Multiplayer Scripting Part 1 - Introduction | 2:48 2 | Multiplayer Scripting Part 2 - Multiple Players | 2:19 3 | Multiplayer Scripting Part 3 - Input handling | 1:37 4 | Multiplayer Scripting Part 4 - Overlay graphics | 2:47 5 | Multiplayer Scripting Part 5 - User Interfaces | 2:06 6 | Multiplayer Scripting Part 6 - Optimization | 2:12 7 | Multiplayer Scripting Part 7 - Custom tools | 3:20 8 | Multiplayer Scripting Part 8 - Game modes | 2:23 9 | Multiplayer Scripting Part 9 - Multiplayer Library - mplib | 1:30 10 | Multiplayer Scripting Part 10 - Advanced topics | 1:53 ## What makes a mod a multiplayer mod? A mod becomes a **multiplayer mod** when it explicitly declares support for multiplayer. ### info.txt requirement To express support for multiplayer, the mod’s `info.txt` must contain: ``` version = 2 ``` Setting `version = 2` tells the engine that the mod is compatible with multiplayer. If `version = 2` is missing, the mod will be treated as a traditional single-player mod. ## Script requirements for multiplayer mods Multiplayer mods rely on the **version 2 scripting system**, which introduces a client/server architecture inside each script. To function correctly in multiplayer, all Lua scripts in the mod must: 1. Declare script version 2 2. Use the correct client/server/shared structure 3. Implement multiplayer-aware logic that supports multiple players ### Enabling version 2 scripting Each Lua script must start with: ``` #version 2 ``` This enables the script as a version 2 (multiplayer) script. Without this tag, the script will only be enabled in singleplayer, and is automatically (and silently) disabled in multiplayer ### client/server/shared In version 2, the *same script file* is loaded on both the server and each client, but different parts of the script run depending on where it is executed. Multiplayer behavior is organized through three built-in script tables: Built-in table | Description ------ | ------ server | Exists only on the server. You can store your own global variables here; they will exist only on the host. client | Exists only on clients. Used for rendering, interface, effects and client-side predictions. shared | Data synchronized automatically from the server to each client’s copy of the same script. Clients see this as read-only. Any serializable data type can be stored here but changing large amounts of data frequently will consume bandwidth. Because the host player is both **server and client**, their machine runs both a server and a client version of the script. ### Callback functions Version 2 scripts may implement optional callback functions on both the server and the client. Just like in version 1 scripts, not all callbacks need to be used. However, since certain things can only be done on server or client, their respective lists of available callbacks differ. #### Server-side callbacks Most multiplayer game logic should be implemented on the server: scoring, game mode rules, spawning, validating player actions, etc. Server function | Description ------ | ------ function server.init() | Called once when the script loads function server.tick(dt) | Called once per frame (variable timestep) function server.update(dt) | Fixed-timestep update (60 Hz max); may run zero, one or two times per frame function server.postUpdate() | Like update, but runs after physics function server.destroy() | Called when the script (or game mode) stops #### Client-side callbacks The client part of the script is mainly responsible for visual presentation: * overlay graphics * HUD and UI * local-only particle effects or sounds * camera-based calculations * per-player animations Client function | Description ------ | ------ function client.init() | Called once when the script loads function client.tick(dt) | Called once per frame (variable timestep) function client.update(dt) | Fixed-timestep update (60 Hz max) function client.postUpdate() | After physics; often used by animators function client.draw() | Called during 2D overlay rendering; Ui.* is only valid here function client.render(dt) | Called once per frame before final rendering function client.destroy() | Called when the script (or game mode) stops ### Additional considerations To behave correctly in multiplayer, scripts must: * Handle **multiple players**, not just a single local player * Place authoritative logic in the **server** section * Perform UI, HUD, overlays and local effects in the **client** section * Use **shared** only for synchronized read-only state * Never assume that client state is authoritative * Only call client-safe or server-safe API functions inside the appropriate callbacks If any script in the mod is missing `#version 2`, the mod cannot fully participate in multiplayer and may partially or completely fail to run in a session. ## Game Modes In multiplayer, a new mod type called **Game Mode** is introduced. There are two types of Game Modes: * **Global Game Modes** — defined in Global Mods. * **Content Game Modes** — defined in Content Mods. A Content Mod can define multiple Content Game Modes. A Global Mod can define multiple Global Game Modes. To specify that a mod contains game modes, a file named **`gamemodes.txt`** must exist in the mod’s root directory. ### Defining Global Game Modes Global Game Modes are defined in `gamemodes.txt` like this: ``` [My Game Mode 1] description = "This game mode will always restart the level when selected" path = mygamemode1.lua restart = true [My Game Mode 2] description = "This game mode can be played without restarting the level" path = mygamemode2.lua ``` ### Defining Content Game Modes Content Game Modes are defined in `gamemodes.txt` like this: ``` [My Game Mode 1] description = "Description 1" layers = gamemodelayer1, alwaysActiveLayer [My Game Mode 2] description = "Description 2" layers = gamemodelayer2, alwaysActiveLayer ``` --- ### Activation and Behavior Rules Only **one Game Mode** can be active at a time. * **Global Game Modes** are played on the currently loaded level and do not use layers. * **Content Game Modes** always start on the `main.xml` level and load the layers defined in the `gamemodes.txt` file. ### Restarting Levels When the **host player** is in a level and playing a Game Mode, pressing **Restart** in the pause menu will restart the current level. The **active Game Mode** will remain active when re-entering the level after the restart. ### Level Transitions If a **Content Game Mode** triggers a level transition using `StartLevel`, the next level will begin with the **same active Game Mode**. If the player switches to a **Global Game Mode**, the new level will be **restarted** and loaded **without any layers**. Switching **back** to the original Content Game Mode will always start the **`main.xml`** level defined by that Content Mod. ## Multiplayer Lua Library (mplib) `mplib` is a multiplayer support library for Teardown. It provides a collection of shared Lua modules that simplify creating multiplayer game modes by handling common systems such as gameplay logic, HUD and UI, tool and loot behavior, player spawning, stats, syncing, and client/server coordination. Read more about it at the [mplib documentation](https://tuxedolabsorg.github.io/mplib/). You can also find the source code for `mplib` on GitHub: [tuxedolabsorg/mplib](https://github.com/tuxedolabsorg/mplib) ## Standardized level markup for multiplayer For the multiplayer release, Teardown introduces a set of **standardized level markup conventions** to simplify the creation of multiplayer game modes. These conventions define how levels can expose spawn points, tool crates, objectives, and other multiplayer-relevant locations. This section provides an overview of the **Location Node** setup used for spawning players and tool crates in the built-in multiplayer game modes. These tags are simply internal conventions we use for our own content. Community-created game modes are **not required** to use the same tags. However, adopting them where they make sense is recommended, because doing so improves **compatibility** between custom levels and different multiplayer game modes. In most of Teardown’s built-in levels, you will now find the following structure containing all multiplayer-related Location Nodes:  ``` multiplayer ├── ammo spawn │ ├── low │ │ └── Location Nodes tagged "ammospawn rarity=low" │ ├── medium │ │ └── Location Nodes tagged "ammospawn rarity=medium" │ └── high │ └── Location Nodes tagged "ammospawn rarity=high" │ ├── player spawn │ ├── free for all │ │ └── Location Nodes tagged "playerspawn" │ └── team based │ ├── team 1 │ │ └── Location Nodes tagged "teamspawn=1" │ └── team 2 │ └── Location Nodes tagged "teamspawn=2" │ ├── Location Nodes tagged "pointofinterest=1" └── Location Nodes tagged "pointofinterest=2" ``` ### **playerspawn** The tag **`playerspawn`** is used in game modes **without teams**. Game modes such as *Deathmatch* use these locations when spawning players. ### **teamspawn** The tag **`teamspawn`** is used in team-based game modes and must include the team index. Examples: * Team 1 → `teamspawn=1` * Team 2 → `teamspawn=2` * Additional teams follow the same pattern (`teamspawn=3`, `teamspawn=4`, …) Game modes use these Location Nodes to provide team-specific spawn points. ### **ammospawn** and **rarity** The tag **`ammospawn`** is always accompanied by a **rarity** value that defines the type of ammo/tool crate typically placed at that Location Node. Supported rarities: * **Low:** `ammospawn rarity=low` * **Medium:** `ammospawn rarity=medium` * **High:** `ammospawn rarity=high` Multiplayer introduces **four categories of ammo/tool crates**, each represented with a different crate color: | Rarity / Type | Crate color | Typical placement | | ------------- | --------------- | ------------------------------------------------ | | Low | Gray | Spawns on low-rarity nodes | | Medium | Blue | Spawns on medium-rarity nodes | | High | Red | Spawns on high-rarity nodes | | Tool mods | Purple / Custom | Only spawns on rarities allowed by the game mode | #### Important note Each game mode decides: * which crate types exist * which crates correspond to which rarities * how crate distribution works For example, a game mode could choose to spawn **high-rarity crates on low-rarity Location Nodes**. If you are testing your `ammospawn` nodes, make sure you use a game mode whose ammo-crate behavior matches your expectations. ### **pointofinterest** The tag **`pointofinterest`** must also include a team index: * Team 1 → `pointofinterest=1` * Team 2 → `pointofinterest=2` Point-of-interest nodes are used for **game-mode-specific structures** that should appear near a team’s spawn position in team-based modes. Examples include: * Capture-the-Flag bases * Team-specific objectives * Mode-controlled interaction points These nodes give game modes a consistent way to place important objects relative to each team’s position in the map. # Teardown Links Teardown Web Site - https://www.teardowngame.com/ Teardown Modding Information - https://www.teardowngame.com/modding/ Teardown Lua API (Experimental) - https://www.teardowngame.com/experimental/api.html Teardown Lua XML (Experimental) - https://www.teardowngame.com/experimental/api.xml Teardown Steam Workshop - https://steamcommunity.com/app/1167630/workshop/ Teardown Official Discord - https://discord.gg/teardown