Skip to content

Guide to using CSync

1. Creating your config class

Create a new class extending SyncedConfig.

public class MyConfig : SyncedConfig<MyConfig>

Within this class, we declare fields for each config entry we would like to sync. Optionally, you can also declare non-synced config entries too. Each SyncedEntry must be annotated with the [DataMember] attribute.

public class MyConfig : SyncedConfig<MyConfig> {
    public ConfigEntry<float> DebugLevel { get; private set; }
    [DataMember] public SyncedEntry<float> MovementSpeed; // fields may be annotated directly
    [field: DataMember] public SyncedEntry<float> ClimbSpeed { get; private set; } // properties must specify 'field' as attribute target


When using client side and synced entries in the same class, any instance of ConfigEntry should NOT be marked with [DataMember]!

2. Binding entries

We add a constructor to our config class that calls the base constructor.

public class MyConfig : SyncedConfig<MyConfig> {
    public MyConfig(ConfigFile configFile) : base("My.Plugin.Guid") { } 

Before binding, we add the following line at the top of the constructor.


We bind our entries to the BepInEx config file like usual. However, we will use the BindSyncedEntry extension method to bind SyncedEntry instances.

public MyConfig(ConfigFile cfg) : base("My.Plugin.Guid") {
    DebugLevel = cfg.Bind(
        new ConfigDefinition("General", "Debug Level"),
        new ConfigDescription("Debug logging level for the mod.")

    MovementSpeed = cfg.BindSyncedEntry(
        new ConfigDefinition("Movement", "Movement Speed"),
        new ConfigDescription("The base speed at which the player moves.")

    ClimbSpeed = cfg.BindSyncedEntry(
        new ConfigDefinition("Movement", "Climb Speed"),
        new ConfigDescription("The base speed at which the player climbs.")

3. Instantiating the config class

We declare an internal static field to hold our config instance so that it is accessible from anywhere in our project. Note the new modifier is only necessary when naming the field Config.

We instantiate the config class in the Awake method of our BepInEx plugin and assign our field to the new instance.

internal static new MyConfig Config; 

static void Awake() {
    Config = new MyConfig(base.Config); 

4. Declaring dependency

We declare CSync a dependency of our BepInEx plugin by adding a BepInDependency attribute that specifies CSync's plugin GUID.

[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
[BepInDependency("com.sigurd.csync", "4.1.0")] 
public class MyPlugin : BaseUnityPlugin

If we plan to upload our mod to Thunderstore, we must ensure we specify the dependency within our manifest.json file by adding CSync's Thunderstore package ID to the dependency array.

  "dependencies": ["BepInEx-BepInExPack-5.4.2100", "Sigurd-CSync-4.1.0"] 


Please ensure your manifest contains the latest version, the one seen above may be outdated!

5. Using your config

We may reference our config entries from the field we declared in our BepInEx plugin.


Try not to cache any entries' values in a variable; doing so means it is possible that you are not using the most up-to-date value.

You can get (or set) the local value of a SyncedEntry:

SyncedEntry<int> myEntry;
myEntry.LocalValue = 5;

Note that you cannot set the Value of a SyncedEntry - you can only assign to .LocalValue.

6. Events

The following events are available for convenience:



  • on the host, immediately after initially packing all the entries' values
  • on the client, immediately after initially unpacking all the entries' values
ManualLogSource logger;
MyConfig Config;

Config.InitialSyncComplete += (sender, args) => {
    logger.LogInfo("Initial sync complete!"); 



  • on the host, when the local value is changed
  • on the client, when the host's local value is changed
  • on the client, when disconnecting from a session
ManualLogSource logger;
SyncedEntry<float> myEntry;

myEntry.Changed += (sender, args) => {
    logger.LogInfo($"The old value was {args.OldValue}");
    logger.LogInfo($"The new value is {args.NewValue}");