Skip to content

Commit

Permalink
New Crowdin updates (#23)
Browse files Browse the repository at this point in the history
* New translations mod-testing-tips.md (French)

* New translations blender-resources.md (French)

* New translations coding-ai.md (French)

* New translations unity-project.md (French)

* New translations mod-testing-tips.md (Spanish)

* New translations blender-resources.md (Spanish)

* New translations coding-ai.md (Spanish)

* New translations unity-project.md (Spanish)

* New translations mod-testing-tips.md (Danish)

* New translations blender-resources.md (Danish)

* New translations coding-ai.md (Danish)

* New translations unity-project.md (Danish)

* New translations mod-testing-tips.md (German)

* New translations blender-resources.md (German)

* New translations coding-ai.md (German)

* New translations unity-project.md (German)

* New translations mod-testing-tips.md (Finnish)

* New translations blender-resources.md (Finnish)

* New translations coding-ai.md (Finnish)

* New translations unity-project.md (Finnish)

* New translations mod-testing-tips.md (Hungarian)

* New translations blender-resources.md (Hungarian)

* New translations coding-ai.md (Hungarian)

* New translations unity-project.md (Hungarian)

* New translations mod-testing-tips.md (Italian)

* New translations blender-resources.md (Italian)

* New translations coding-ai.md (Italian)

* New translations unity-project.md (Italian)

* New translations mod-testing-tips.md (Japanese)

* New translations blender-resources.md (Japanese)

* New translations coding-ai.md (Japanese)

* New translations unity-project.md (Japanese)

* New translations mod-testing-tips.md (Korean)

* New translations blender-resources.md (Korean)

* New translations coding-ai.md (Korean)

* New translations unity-project.md (Korean)

* New translations mod-testing-tips.md (Dutch)

* New translations blender-resources.md (Dutch)

* New translations coding-ai.md (Dutch)

* New translations unity-project.md (Dutch)

* New translations mod-testing-tips.md (Polish)

* New translations blender-resources.md (Polish)

* New translations coding-ai.md (Polish)

* New translations unity-project.md (Polish)

* New translations mod-testing-tips.md (Russian)

* New translations blender-resources.md (Russian)

* New translations coding-ai.md (Russian)

* New translations unity-project.md (Russian)

* New translations mod-testing-tips.md (Ukrainian)

* New translations blender-resources.md (Ukrainian)

* New translations coding-ai.md (Ukrainian)

* New translations unity-project.md (Ukrainian)

* New translations mod-testing-tips.md (Chinese Simplified)

* New translations blender-resources.md (Chinese Simplified)

* New translations coding-ai.md (Chinese Simplified)

* New translations unity-project.md (Chinese Simplified)

* New translations mod-testing-tips.md (Portuguese, Brazilian)

* New translations blender-resources.md (Portuguese, Brazilian)

* New translations coding-ai.md (Portuguese, Brazilian)

* New translations unity-project.md (Portuguese, Brazilian)

* New translations mod-testing-tips.md (Thai)

* New translations blender-resources.md (Thai)

* New translations coding-ai.md (Thai)

* New translations unity-project.md (Thai)

* New translations mod-testing-tips.md (Chinese Simplified)

* New translations networking.md (French)

* New translations networking.md (Spanish)

* New translations networking.md (Danish)

* New translations networking.md (German)

* New translations networking.md (Finnish)

* New translations networking.md (Hungarian)

* New translations networking.md (Italian)

* New translations networking.md (Japanese)

* New translations networking.md (Korean)

* New translations networking.md (Dutch)

* New translations networking.md (Polish)

* New translations networking.md (Russian)

* New translations networking.md (Ukrainian)

* New translations networking.md (Chinese Simplified)

* New translations networking.md (Portuguese, Brazilian)

* New translations networking.md (Thai)

* New translations initial-setup.md (Portuguese, Brazilian)

* New translations initial-setup.md (Portuguese, Brazilian)

* New translations installing-r2modman-linux.md (Portuguese, Brazilian)

* New translations initial-setup.md (Portuguese, Brazilian)

* New translations initial-setup.md (Portuguese, Brazilian)

* New translations custom-configs.md (Chinese Simplified)

* New translations custom-configs.md (Chinese Simplified)

* New translations custom-configs.md (Chinese Simplified)

* New translations open-source-and-ethics.md (Chinese Simplified)

* New translations csync.md (Chinese Simplified)

* New translations troubleshooting.md (Chinese Simplified)

* New translations troubleshooting.md (Chinese Simplified)

* New translations writing-articles.md (Chinese Simplified)

* New translations developing-categories.md (Chinese Simplified)

* New translations developing-configs.md (Chinese Simplified)

* New translations developing-pages.md (Chinese Simplified)

* New translations event-listening.md (Chinese Simplified)

* New translations event-listening.md (Chinese Simplified)

* New translations usage-guide.md (Chinese Simplified)

* New translations usage-guide.md (Chinese Simplified)

* New translations customscrap.md (French)

* New translations customscrap.md (Spanish)

* New translations customscrap.md (Danish)

* New translations customscrap.md (German)

* New translations customscrap.md (Finnish)

* New translations customscrap.md (Hungarian)

* New translations customscrap.md (Italian)

* New translations customscrap.md (Japanese)

* New translations customscrap.md (Korean)

* New translations customscrap.md (Dutch)

* New translations customscrap.md (Polish)

* New translations customscrap.md (Russian)

* New translations customscrap.md (Ukrainian)

* New translations customscrap.md (Chinese Simplified)

* New translations customscrap.md (Portuguese, Brazilian)

* New translations customscrap.md (Thai)

* New translations blender-resources.md (Chinese Simplified)

* New translations blender-resources.md (Chinese Simplified)

* New translations coding-ai.md (Chinese Simplified)

* New translations coding-ai.md (Chinese Simplified)

* New translations overview.md (Chinese Simplified)

* New translations unity-project.md (Chinese Simplified)

* New translations csync.md (Chinese Simplified)

* New translations troubleshooting.md (Chinese Simplified)

* New translations usage-guide.md (Chinese Simplified)

* New translations csync.md (French)

* New translations troubleshooting.md (French)

* New translations usage-guide.md (French)

* New translations outdated.md (French)

* New translations usage-guide-outdated.md (French)

* New translations v2-migration.md (French)

* New translations csync.md (Spanish)

* New translations troubleshooting.md (Spanish)

* New translations usage-guide.md (Spanish)

* New translations outdated.md (Spanish)

* New translations usage-guide-outdated.md (Spanish)

* New translations v2-migration.md (Spanish)

* New translations csync.md (Danish)

* New translations troubleshooting.md (Danish)

* New translations usage-guide.md (Danish)

* New translations outdated.md (Danish)

* New translations usage-guide-outdated.md (Danish)

* New translations v2-migration.md (Danish)

* New translations csync.md (German)

* New translations troubleshooting.md (German)

* New translations usage-guide.md (German)

* New translations outdated.md (German)

* New translations usage-guide-outdated.md (German)

* New translations v2-migration.md (German)

* New translations csync.md (Finnish)

* New translations troubleshooting.md (Finnish)

* New translations usage-guide.md (Finnish)

* New translations outdated.md (Finnish)

* New translations usage-guide-outdated.md (Finnish)

* New translations v2-migration.md (Finnish)

* New translations csync.md (Hungarian)

* New translations troubleshooting.md (Hungarian)

* New translations usage-guide.md (Hungarian)

* New translations outdated.md (Hungarian)

* New translations usage-guide-outdated.md (Hungarian)

* New translations v2-migration.md (Hungarian)

* New translations csync.md (Italian)

* New translations troubleshooting.md (Italian)

* New translations usage-guide.md (Italian)

* New translations outdated.md (Italian)

* New translations usage-guide-outdated.md (Italian)

* New translations v2-migration.md (Italian)

* New translations csync.md (Japanese)

* New translations troubleshooting.md (Japanese)

* New translations usage-guide.md (Japanese)

* New translations outdated.md (Japanese)

* New translations usage-guide-outdated.md (Japanese)

* New translations v2-migration.md (Japanese)

* New translations csync.md (Korean)

* New translations troubleshooting.md (Korean)

* New translations usage-guide.md (Korean)

* New translations outdated.md (Korean)

* New translations usage-guide-outdated.md (Korean)

* New translations v2-migration.md (Korean)

* New translations csync.md (Dutch)

* New translations troubleshooting.md (Dutch)

* New translations usage-guide.md (Dutch)

* New translations outdated.md (Dutch)

* New translations usage-guide-outdated.md (Dutch)

* New translations v2-migration.md (Dutch)

* New translations csync.md (Polish)

* New translations troubleshooting.md (Polish)

* New translations usage-guide.md (Polish)

* New translations outdated.md (Polish)

* New translations usage-guide-outdated.md (Polish)

* New translations v2-migration.md (Polish)

* New translations csync.md (Russian)

* New translations troubleshooting.md (Russian)

* New translations usage-guide.md (Russian)

* New translations outdated.md (Russian)

* New translations usage-guide-outdated.md (Russian)

* New translations v2-migration.md (Russian)

* New translations csync.md (Ukrainian)

* New translations troubleshooting.md (Ukrainian)

* New translations usage-guide.md (Ukrainian)

* New translations outdated.md (Ukrainian)

* New translations usage-guide-outdated.md (Ukrainian)

* New translations v2-migration.md (Ukrainian)

* New translations outdated.md (Chinese Simplified)

* New translations usage-guide-outdated.md (Chinese Simplified)

* New translations v2-migration.md (Chinese Simplified)

* New translations csync.md (Portuguese, Brazilian)

* New translations troubleshooting.md (Portuguese, Brazilian)

* New translations usage-guide.md (Portuguese, Brazilian)

* New translations outdated.md (Portuguese, Brazilian)

* New translations usage-guide-outdated.md (Portuguese, Brazilian)

* New translations v2-migration.md (Portuguese, Brazilian)

* New translations csync.md (Thai)

* New translations troubleshooting.md (Thai)

* New translations usage-guide.md (Thai)

* New translations outdated.md (Thai)

* New translations usage-guide-outdated.md (Thai)

* New translations v2-migration.md (Thai)

* New translations csync.md (Chinese Simplified)

* New translations developing-pages.md (Chinese Simplified)

* New translations outdated.md (Chinese Simplified)

* New translations v2-migration.md (Chinese Simplified)

* New translations customscrap.md (Chinese Simplified)

* New translations v2-migration.md (Chinese Simplified)

* New translations writing-articles.md (Russian)

* New translations configurable-company.md (Chinese Simplified)

* New translations configurable-company.md (Chinese Simplified)

* New translations configurable-company.md (Chinese Simplified)

* New translations initial-setup.md (Portuguese, Brazilian)

* New translations initial-setup.md (Portuguese, Brazilian)

* New translations installing-r2modman.md (Korean)

* New translations mod-testing-tips.md (Portuguese, Brazilian)

* New translations mod-testing-tips.md (Portuguese, Brazilian)

* New translations unity-project.md (French)

* New translations unity-project.md (Spanish)

* New translations unity-project.md (Danish)

* New translations unity-project.md (German)

* New translations unity-project.md (Finnish)

* New translations unity-project.md (Hungarian)

* New translations unity-project.md (Italian)

* New translations unity-project.md (Japanese)

* New translations unity-project.md (Korean)

* New translations unity-project.md (Dutch)

* New translations unity-project.md (Polish)

* New translations unity-project.md (Russian)

* New translations unity-project.md (Ukrainian)

* New translations unity-project.md (Chinese Simplified)

* New translations unity-project.md (Portuguese, Brazilian)

* New translations unity-project.md (Thai)
  • Loading branch information
lc-crowdin authored Mar 28, 2024
1 parent 3e40082 commit 34ceb12
Show file tree
Hide file tree
Showing 839 changed files with 99,940 additions and 327 deletions.
299 changes: 299 additions & 0 deletions translations/da_DK/docs/advanced-modding/custom-config-syncing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
---
prev: true
next: false
description: An intermediate overview of how to sync custom configs for your Lethal Company mods.
---

# Custom Config Syncing

:::warning
**This is an advanced article. While this introduces some C# concepts, it is highly recommended to understand C# and the basics of modding this game <i>before</i> reading this article.**
:::

## Preface

A very common case for many mod developers is wanting to synchronize the host's configuration file with all other players.

There are many different ways you could achieve this, but we will only go through the most straightforward approach that should work for most cases.

## Manually Syncing Instances

For this approach, we will take advantage of [Custom Messages](https://docs-multiplayer.unity3d.com/netcode/current/advanced-topics/message-system/custom-messages/#named-messages), specifically Named Messages.
They are unbound to any GameObject, meaning **NetcodeWeaver** and **NetworkBehaviour** are **NOT necessary**.

:::info
Before you proceed, it is recommended you familiarize yourself with [Custom configs](/advanced-modding/custom-configs).
:::

### Prerequisites

Add an **Assembly Reference** to the following files:<br>
`Unity.Netcode.Runtime.dll`<br>
`Unity.Collections.dll`

These can be found at `.../Lethal Company/Lethal Company_Data/Managed`.

Now create a `SyncedInstance.cs` file which your config will inherit from, this handles the serialization/de-serialization of data.<br>
It also provides some helper methods to prevent repeating ourselves.

```cs
[Serializable]
public class SyncedInstance<T> {
internal static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager;
internal static bool IsClient => NetworkManager.Singleton.IsClient;
internal static bool IsHost => NetworkManager.Singleton.IsHost;

[NonSerialized]
protected static int IntSize = 4;

public static T Default { get; private set; }
public static T Instance { get; private set; }

public static bool Synced { get; internal set; }

protected void InitInstance(T instance) {
Default = instance;
Instance = instance;

// Makes sure the size of an integer is correct for the current system.
// We use 4 by default as that's the size of an int on 32 and 64 bit systems.
IntSize = sizeof(int);
}

internal static void SyncInstance(byte[] data) {
Instance = DeserializeFromBytes(data);
Synced = true;
}

internal static void RevertSync() {
Instance = Default;
Synced = false;
}

public static byte[] SerializeToBytes(T val) {
BinaryFormatter bf = new();
using MemoryStream stream = new();

try {
bf.Serialize(stream, val);
return stream.ToArray();
}
catch (Exception e) {
Plugin.Logger.LogError($"Error serializing instance: {e}");
return null;
}
}

public static T DeserializeFromBytes(byte[] data) {
BinaryFormatter bf = new();
using MemoryStream stream = new(data);

try {
return (T) bf.Deserialize(stream);
} catch (Exception e) {
Plugin.Logger.LogError($"Error deserializing instance: {e}");
return default;
}
}
}
```

### 1. Inherit SyncedInstance

We will now make use of the config class file made prior by changing this line:

```cs
public class Config
```

Into a synced alternative that can be serialized.

```cs
[Serializable]
public class Config : SyncedInstance<Config>
```

In addition, we need to make sure 'Instance' is a reference to this class by adding another line in the **constructor**.

```cs
public Config(ConfigFile cfg) {
InitInstance(this); // Add this line
// ...
}
```

### 2. Setup request/receiver methods

Now simply paste the three following methods within the class.
While these might look intimidating, they will hopefully start to make more sense in step 3.

```cs
public static void RequestSync() {
if (!IsClient) return;

using FastBufferWriter stream = new(IntSize, Allocator.Temp);
MessageManager.SendNamedMessage("ModName_OnRequestConfigSync", 0uL, stream);
}
```

```cs
public static void OnRequestSync(ulong clientId, FastBufferReader _) {
if (!IsHost) return;

Plugin.Logger.LogInfo($"Config sync request received from client: {clientId}");

byte[] array = SerializeToBytes(Instance);
int value = array.Length;

using FastBufferWriter stream = new(value + IntSize, Allocator.Temp);

try {
stream.WriteValueSafe(in value, default);
stream.WriteBytesSafe(array);

MessageManager.SendNamedMessage("ModName_OnReceiveConfigSync", clientId, stream);
} catch(Exception e) {
Plugin.Logger.LogInfo($"Error occurred syncing config with client: {clientId}\n{e}");
}
}
```

```cs
public static void OnReceiveSync(ulong _, FastBufferReader reader) {
if (!reader.TryBeginRead(IntSize)) {
Plugin.Logger.LogError("Config sync error: Could not begin reading buffer.");
return;
}

reader.ReadValueSafe(out int val, default);
if (!reader.TryBeginRead(val)) {
Plugin.Logger.LogError("Config sync error: Host could not sync.");
return;
}

byte[] data = new byte[val];
reader.ReadBytesSafe(ref data, val);

SyncInstance(data);

Plugin.Logger.LogInfo("Successfully synced config with host.");
}
```

### 3. Apply patch to PlayerControllerB

Add in the following method, replacing "ModName" with the name (or abbreviation) of your mod.

Keep in mind that `ConnectClientToPlayerObject` is run just before the player is spawned.
This means if you are patching `SpawnPlayerAnimation`, you might find it gets called before the config has finished syncing!

```cs
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
public static void InitializeLocalPlayer() {
if (IsHost) {
MessageManager.RegisterNamedMessageHandler("ModName_OnRequestConfigSync", OnRequestSync);
Synced = true;

return;
}

Synced = false;
MessageManager.RegisterNamedMessageHandler("ModName_OnReceiveConfigSync", OnReceiveSync);
RequestSync();
}
```

If you are having issues with this patch, you may want to try **GameNetworkManager** instead.

```cs
[HarmonyPatch(typeof(GameNetworkManager), "SteamMatchmaking_OnLobbyMemberJoined")]
```

Finally, we need to make sure the client reverts back to their own config upon leaving.

```cs
[HarmonyPostfix]
[HarmonyPatch(typeof(GameNetworkManager), "StartDisconnect")]
public static void PlayerLeave() {
Config.RevertSync();
}
```

## Synced Config Usage

Every client will now have their config synchronized to the hosts upon joining the game.
All that's left to do is use the synced variables where appropriate.

We can do this by referencing `Config.Instance` from any class.
Here's an example that sets the local player's movement speed.

```cs
public static void ExamplePatch(PlayerControllerB __instance) {
if (__instance == null)
return;

float syncedSpeed = Config.Instance.MOVEMENT_SPEED;
if (__instance.IsOwner && __instance.isPlayerControlled) {
__instance.movementSpeed = syncedSpeed;
Plugin.Logger.LogInfo("Movement speed synced with host config.");
}
}
```

To use client-side variables (not the synced instance), we can access `Config.Default`.

```cs
public static void ExamplePatch(PlayerControllerB __instance) {
if (!__instance) return;

// Sets current stamina, regardless of host config.
__instance.sprintMeter = Config.Default.STAMINA;
}
```

## Troubleshooting

> Syncing doesnt work when I patch manually.
If you're using `PatchAll()` with type parameters, make sure to patch the `Config` class like other files.<br>
Example:

```cs
harmony.PatchAll(typeof(StartMatchLeverPatch));
harmony.PatchAll(typeof(GameNetworkManagerPatch));
harmony.PatchAll(typeof(Config)); // Add this line
```

> I am not seeing any logs from the request/receiver methods?
Harmony may refuse to patch the `InitializeLocalPlayer` method inside `Config.cs` if you have already have a dedicated patch file for `PlayerControllerB`. You can try placing the method there instead.

```cs
[HarmonyPatch(typeof(PlayerControllerB))]
internal class PlayerControllerBPatch
{
[HarmonyPostfix]
[HarmonyPatch("ConnectClientToPlayerObject")]
public static void InitializeLocalPlayer() {
if (Config.IsHost) {
try {
Config.MessageManager.RegisterNamedMessageHandler("ModName_OnRequestConfigSync", Config.OnRequestSync);
Config.Synced = true;
}
catch (Exception e) {
Plugin.Logger.LogError(e);
}

return;
}

Config.Synced = false;
Config.MessageManager.RegisterNamedMessageHandler("ModName_OnReceiveConfigSync", Config.OnReceiveSync);
Config.RequestSync();
}
}
```

<br>If you incounter any other issues with custom configs, please ask on the [community discord](https://discord.gg/nYcQFEpXfU)!
89 changes: 89 additions & 0 deletions translations/da_DK/docs/advanced-modding/custom-configs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
prev: false
next: true
description: An intermediate overview of how to implement custom configs for your Lethal Company mods.
---

# Custom Configs

:::warning
**This is an advanced article. While this introduces some C# concepts, it is highly recommended to understand C# and the basics of modding this game <i>before</i> reading this article.**
:::

:::info
This tutorial is taken and adapted from the [BepInEx Configuration Documentation](https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html). For more resources refer to that.
:::

## Creating Config Entries

Create a config class and add entries for any variables that you want to be configurable.

```cs
public class Config
{
public static ConfigEntry<string> configGreeting;
public static ConfigEntry<bool> configDisplayGreeting;

// ...
}
```

Then we can start binding our config entries to the fields we just created inside of a class constructor.

```cs
public Config(ConfigFile cfg)
{
configGreeting = cfg.Bind(
"General", // Config section
"GreetingText", // Key of this config
"Hello, world!", // Default value
"Greeting text upon game launch" // Description
);

configDisplayGreeting = cfg.Bind(
"General.Toggles", // Config subsection
"DisplayGreeting", // Key of this config
true, // Default value
"To show the greeting text" // Description
);
}
```

We then need to run said constructor to bind said configs to proper values and properties for users.<br><br>
In your main class (usually `Plugin.cs`), implement the constructor with a parameter referencing the file that will be created by BepInEx.

```cs
public class MyExampleMod : BaseUnityPlugin
{
public static new Config MyConfig { get; internal set; }

// ...
private void Awake()
{
MyConfig = new(base.Config);
}
}
```

## Using Config Entries

You can now get the data from the config variables you have made using the `.Value` property.

```cs
private void MyExamplePatch()
{
private void MyExampleMethod()
{
// Instead of just Logger.LogInfo("Hello, world!")
if(Config.configDisplayGreeting.Value)
Logger.LogInfo(Config.configGreeting.Value);
}
}
```

:::danger STOP
Understand that your config file **Will Not Be Created** until your mod is loaded ingame **at least once**. See the [r2modman Configs Page](/installation/configuration) for using your configs.
:::

Now you have config files for your mods! If it's extremely important that your mod has a config value that's the same for every player, you may want to consider reading the page on [custom config syncing](/advanced-modding/custom-config-syncing).
Loading

0 comments on commit 34ceb12

Please sign in to comment.