SDK Setup
This area of our documentation is a work in progress as we move towards Crowd Control 2 release. Some info may be missing!
Before starting a new project or reporting errors, make sure you are using the latest build of the SDK and have the latest version of the main CC desktop app.
We recommend extracting the SDK with 7zip. Once extracted you can open the CrowdControl.SDK.exe
file.
What is a Game Pack?
A game pack is a C# (.cs) file which is loaded into the Crowd Control client application to connect the app to your mod. The SDK and game packs are primarily used by modders; game developers should instead check out our plugins for Unity, Godot 4.0 & 4.1 + 4.2 & 4.3, and GameMaker.
A game pack primarily consists of a list of effects and some metadata that defines how your pack connects to the game. The actual code for handling effects will take place in a game mod for newer titles, or directly in the game pack for older titles.
Creating a Game Pack
Starting Your Project
We recommend building your game pack from the PackProject
Visual Studio project inside the SDK folder as it will provide code completion/IntelliSense.
Choosing a Connector
To create a game pack, you'll first have to decide on which connector you'll use. If you are modding for...
- ...old emulated games: see Emulators Overview
- ...Unity PC games, use MelonLoader (ex. Cuphead)
- ...other PC games, use TCP/WebSockets (ex. Celeste)
- ...old PC games w/o modding frameworks, use Memory Inject (ex. Plants Vs Zombies)
PackProject comes with an example for NES games, but for this documentation we'll be using a simple TCP connector pack as an example. Here is the very minimum code necessary for a TCP game pack:
using ConnectorLib.SimpleTCP;
using CrowdControl.Common;
using ConnectorType = CrowdControl.Common.ConnectorType;
namespace CrowdControl.Games.Packs.YourGame;
public class YourGame : SimpleTCPPack<SimpleWebsocketServerConnector>
{
public YourGame(UserRecord player, Func<CrowdControlBlock, bool> responseHandler, Action<object> statusUpdateHandler) : base(player, responseHandler, statusUpdateHandler) {
}
public override Game Game => new("Your Game", "YourGame", "PC", ConnectorType.SimpleWebsocketServerConnector);
public override ushort Port => 28379; // pick something within 1024~49151
public override EffectList Effects => new Effect[]
{
// TODO
};
}
Adding an Effect
An Effect is an action that a viewer can trigger to occur within the game. This section will describe the metadata for effects, not the execution of them.
Continuing on from the prior example, we will replace the // TODO
placeholder comment with a simple effect:
new("Kill Player", "kill_player") { Price = 1000 },
This effect has a display name of Kill Player
, a code name of kill_player
(which is what's sent to your mod), and a default price of 1000 coins ($10, streamers can edit this to whatever they want).
This is the minimum information necessary, but it's a little barebones, so let's add a description. Feel free to get creative and silly with these!
new("Kill Player", "kill_player") { Price = 1000, Description = "Instantly deprives the player character of oxygen" },
Let's also add a category to help viewers sort through the effects.
new("Kill Player", "kill_player") { Price = 1000, Description = "Instantly deprives the player character of oxygen", Category = "Player" },
// or add several!
new("Kill Player", "kill_player") { Price = 1000, Description = "Instantly deprives the player character of oxygen", Category = new EffectGrouping("Player", "World") },
For multiplayer games, you might have several copies of effects for different players. If so, you might want to distinguish them with the Note field, which displays an extra message next to the effect name in a lighter font.
new("Kill Player", "kill_player_host") { Note = "Host", Price = 1000, Description = "Instantly deprives the player character of oxygen", Category = "Player" },
new("Kill Player", "kill_player_random") { Note = "Random Teammate", Price = 1000, Description = "Instantly deprives the player character of oxygen", Category = "Player" },
If your effect lasts for a period of time, then you'll want to use the Duration field. It accepts an integer number between 1 and 180 representing the default duration in seconds. Note that streamers are able to adjust this value. For more information on reading duration values, see the corresponding connector article.
new("Flip Screen", "flip_screen") { Price = 100, Duration = 30, Description = "Returns your vision to how it was at birth (real fact!)", Category = "Visual" },
If multiple copies of your effect can be ran at once, then you can set the Quantity field to allow viewers to stack the effect. If a viewer selects Quantity 5 on a Price 100 effect, then they will be charged 500 coins. Example uses include player damage, healing, giving items, etc. For more information on reading quantity values, see the corresponding connector article.
new("Damage Player", "damage_player") { Price = 100, Quantity = 1..10, Description = "Pricks the player with needles", Category = "Player" },
// or, shorter:
new("Damage Player", "damage_player") { Price = 100, Quantity = 10, Description = "Pricks the player with needles", Category = "Player" },
Our final pack now looks like this:
using ConnectorLib.SimpleTCP;
using CrowdControl.Common;
using ConnectorType = CrowdControl.Common.ConnectorType;
namespace CrowdControl.Games.Packs.YourGame;
public class YourGame : SimpleTCPPack<SimpleWebsocketServerConnector>
{
public YourGame(UserRecord player, Func<CrowdControlBlock, bool> responseHandler, Action<object> statusUpdateHandler) : base(player, responseHandler, statusUpdateHandler) {
}
public override Game Game => new("Your Game", "YourGame", "PC", ConnectorType.SimpleWebsocketServerConnector);
public override ushort Port => 28379; // pick something within 1024~49151
public override EffectList Effects => new Effect[]
{
new("Damage Player", "damage_player") { Price = 100, Quantity = 10, Description = "Pricks the player with needles", Category = "Player" },
new("Flip Screen", "flip_screen") { Price = 100, Duration = 30, Description = "Returns your vision to how it was at birth (real fact!)", Category = "Visual" },
new("Kill Player", "kill_player_host") { Note = "Host", Price = 1000, Description = "Instantly deprives the player character of oxygen", Category = "Player" },
new("Kill Player", "kill_player_random") { Note = "Random Teammate", Price = 1000, Description = "Instantly deprives the player character of oxygen", Category = "Player" },
};
}
Handling an Effect
The exact technical specifics of how to handle an effect depends on the connector, so please see those corresponding docs.
In general, your code should attempt to execute the effect, then report back within five seconds on whether or not the effect successfully executed. If the effect failed, then you can ask the Crowd Control app to try requesting the effect again in a couple seconds, or you can cancel the effect. If an effect is cancelled goes for a minute without getting executed, then the Crowd Control app will reject the effect and refund the purchaser.
Running a Game Pack
- Load your .cs from the Load Pack Source button and select your pack from the list.
- Select the correct Game Connector from the drop down.
- Then hit Connect on the SDK to initate the connection.
Test effects LIVE or share with a friend
This feature will be back in the CC2 desktop app soon! In the mean time, see Submit to the CC Team; we'll set up private access for you and your friends while you work towards a public release.
Support
If you run into any issues or questions, you can look over at our #cc-developer channel in our Discord under the Crowd Control category! We have a good amount of devs working on games, so feel free to just hang out!
Submit to the CC Team
If you want to make your pack available for all users and see it up on our offical support list, please reach out on Discord!
Let us know all the detils about your setup! Any specific build of the game or extra settings that might be required.
Our team will put your pack through our QA process. If we have any questions or issues to report, we'll let you know as soon as we are able to.
We'll create the setup guide, one click setup, icons, etc to get it implemented and has the same user flow as all our other packs.
More info here on How We Work: https://crowdcontrol.live/how-we-work