-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Configurable Company API to wiki (#87)
* Added configurable company API * Fixed PR requested changes * Updated overview * updated dependency header
- Loading branch information
Showing
7 changed files
with
448 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
--- | ||
prev: true | ||
next: true | ||
description: Guide on how to add and use Configurable company for your plugin. | ||
--- | ||
|
||
# Configurable company for your plugin | ||
|
||
You will learn how you can add the API to your project and create simple configurations. | ||
|
||
For an in-depth guide on the configurations click one of the following buttons: | ||
[Developing pages](/dev/apis/configurable-company/developing-pages) | ||
[Developing categories](/dev/apis/configurable-company/developing-categories) | ||
[Developing configurations](/dev/apis/configurable-company/developing-configs) | ||
[Developing events](/dev/apis/configurable-company/event-listening) | ||
|
||
## Requirements | ||
|
||
To develop with Configurable company, you should have the following mods: | ||
|
||
- [BepinExPack by BepInEx](https://thunderstore.io/c/lethal-company/p/BepInEx/BepInExPack/) | ||
|
||
- [ConfigurableCompany by Ansuz/AMRV](https://thunderstore.io/c/lethal-company/p/AMRV/ConfigurableCompany/) | ||
|
||
I encourage to use a [mod manager](https://thunderstore.io/c/lethal-company/p/ebkr/r2modman/) to install them and avoid any problems. | ||
|
||
## Setting up environment | ||
|
||
:::warning | ||
This guide assumes you are using [Visual studio](https://visualstudio.microsoft.com) as IDE. | ||
::: | ||
|
||
Before adding the dependency to your project you should have your base plugin created, if you don't know how see [Initial setup](/dev/initial-setup) and [Starting a mod](/dev/starting-a-mod). | ||
|
||
You can add the project via [NuGet packages](#using-nuget-package-manager) or by [referencing it manually](#adding-file-manually). | ||
|
||
### Using NuGet package manager | ||
|
||
If you wish to learn how to use **NuGet**, [here](https://learn.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio) is a link to microsoft's guide. | ||
|
||
You need to add the package [**Amrv.ConfigurableCompany**](https://www.nuget.org/packages/Amrv.ConfigurableCompany). You can add it to your project by using the _manage nuget packages_ option from your project. | ||
Otherwise you can add the reference by manually editing the `.csproj` file and adding the following tags: | ||
|
||
```xml | ||
<ItemGroup> | ||
<PackageReference Include="Amrv.ConfigurableCompany" Version="2.5.0" PrivateAssets="all"/> | ||
</ItemGroup> | ||
``` | ||
|
||
### Adding dependency manually | ||
|
||
First of all you need a copy of the `.dll` file (wich you can [download manually](https://thunderstore.io/c/lethal-company/p/AMRV/ConfigurableCompany/versions/) or copy an existing one if you have the mod installed). | ||
|
||
Add the `Amrv.ConfigurableCompany.dll` to the library folder of your project. _Make sure you also include it as a reference in the project file `project.csproj`._ | ||
|
||
:::info | ||
You can reference the full path to the dll that you are using for the game, however I don't recommend using absolute paths. | ||
::: | ||
|
||
```xml | ||
<ItemGroup> | ||
<!--You can name the reference however you want as long as unique--> | ||
<Reference Include="ConfigurableCompany"> | ||
<!--This is an example path, use the one you have with the dll--> | ||
<HintPath>libs\ConfigurableCompany.dll</HintPath> | ||
</Reference> | ||
</ItemGroup> | ||
``` | ||
|
||
You might as well mark the mod as a hard dependency of your project. | ||
|
||
::: info | ||
You can get the dependency string and the mod version from the `LethalConfiguration` class. | ||
|
||
```cs | ||
LethalConfiguration.PLUGIN_GUID | ||
LethalConfiguration.PLUGIN_VERSION | ||
``` | ||
|
||
::: | ||
|
||
```cs | ||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)] | ||
[BepInDependency(LethalConfiguration.PLUGIN_GUID, BepInDependency.DependencyFlags.HardDependency)] // [!code ++] | ||
public class YourPlugin : BaseUnityPlugin { | ||
// The rest of the class goes here ... | ||
} | ||
``` | ||
|
||
## How does it work | ||
|
||
Configurations and categories need an `ID` that will identify those configurations even if your plugin is not enabled for the player, also allowing other plugins to interact with your configurations if they need to. | ||
|
||
As a convention I recommend that you define your ID's as follows: | ||
`owner_your-plugin-name_configuration-name` | ||
::: warning | ||
ID's must be composed of letters, numbers, underscores or hypens and should be in lowercase. | ||
Also they are meant to be unique. | ||
::: | ||
|
||
All configurations and categories will be loaded once the player decides to host a game and then the player will be able to modify any configuration to their liking. | ||
Once the player starts the game or saves all the changes will be loaded into their respective configuration. If you want do instantly detect when your configuration has changed you should [listen to the corresponding event](/dev/apis/configurable-company/event-listening). | ||
|
||
When another player joins, all the configurations will request a synchronization to the client. | ||
|
||
::: warning | ||
Keep in mind configurations depend on the current save file so (for now) until the player selects a file, configurations will hold their default value. | ||
::: | ||
|
||
## Creating a simple configuration | ||
|
||
ConfigurableCompany contains all the resources you need in a class called `LethalConfiguration` located at the namespace `Amrv.ConfigurableCompany`. There you can reference and declare everything you might need. | ||
|
||
Configurable company uses [builder pattern](https://en.wikipedia.org/wiki/Builder_pattern) to create pages, categories and configurations, making it very easy to add and update configurations. | ||
|
||
Here is an example that adds a `ranged float` that allows any value from **10** to **100** configuration: | ||
|
||
```cs | ||
Configuration simpleConfig = LethalConfiguration.CreateConfig("me_my-mod_id") | ||
.SetName("My first configuration") | ||
.SetType(ConfigurationTypes.RangeFloat(10, 100)) | ||
.SetTooltip("My cool description") | ||
.SetSynchronized(true) | ||
.Build(); // Note you can omit this Build call if you are assigning the config to a Configuration variable | ||
``` | ||
|
||
::: info | ||
Note there are more options to build your configurations, a full guide can be found in [Developing configs](/dev/apis/configurable-company/developing-configs.md). | ||
::: | ||
|
||
Now that you have your simple configuration you might need to get the value. You can get it in multiple ways but the most common ones are: | ||
|
||
```cs | ||
float value = simpleConfig.Get<float>(); | ||
float valueOrDefault = simpleConfig.Get<float>(10f); | ||
int valueCasted = simpleConfig.Get<int>(); | ||
``` | ||
|
||
::: tip | ||
You don't know when the user changes the value so as a recomendation you should use the values once the game starts or [listen to configuration changes](/dev/apis/configurable-company/event-listening.md). | ||
::: |
71 changes: 71 additions & 0 deletions
71
docs/dev/apis/configurable-company/developing-categories.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
--- | ||
prev: true | ||
next: true | ||
description: How to create Configurable company categories for your plugin and how to use them. | ||
--- | ||
|
||
# Developing Categories with Configurable Company | ||
|
||
## What is a Category | ||
|
||
Categories are another way to organize your configurations, like [configuration pages](/dev/apis/configurable-company/developing-pages.md) they don't modify how configurations work however they will allow players to focus on what configurations they want to change, specially when there are many configurations. | ||
|
||
## Creating a Category | ||
|
||
Categories are used to organize your configuration in a folder-like structure so that the final user can easily navigate the menu. These are symbolic and do not change the behavior of the configurations at all. | ||
|
||
To create a category is as simple as calling `LethalConfiguration.CreateCategory`. You can choose to provide an ID right from the start or later, however all categories must contain an unique ID. | ||
|
||
**IDs** must be lowercase, contain only letters, numbers, hypens `-` and underscores `_`. I'd recommend to make your IDs look something like `owner_your-plugin-name_category-name`. | ||
|
||
Here is an example on how you can create a category: | ||
|
||
:::info | ||
If you don't know what a parameter does, check [parameters](#parameters) section. | ||
::: | ||
```csharp | ||
ConfigurationCategory sampleCategory = LethalConfiguration.CreateCategory() | ||
.SetID("developer_some-mod_sample-category") | ||
.SetName("Sample category") | ||
.SetPage(ConfigurationPage) // Optional | ||
.SetColorRGB(255, 0, 0) // Optional | ||
.HideIfEmpty(false) // Optional | ||
.Build(); | ||
``` | ||
|
||
:::tip | ||
It's not necesary to call `Build()` if you are assigning the builder to a `ConfigurationCategory` as it will implicitly call the build method to create the category. | ||
::: | ||
|
||
## Parameters | ||
|
||
- `SetID(string)`: The unique ID of the category. | ||
- `SetName(string)`: The name that will be displayed on the in-game menu. | ||
- `SetColor(Color[white])`: (There are multiples methods to set the color. choose the prefered one based on your preferences) Sets the color of the category panel in the in-game menu. | ||
- `HideIfEmpty(bool[true])`: Marks the category to not be displayed at all if there are no configurations inside this category. | ||
- `SetPage(ConfigurationPage)`: Makes this category go listed on the provided page. One is generated by default but I encourage you to create a page for your mod. | ||
|
||
`Build()` will create the category. It will not be created until the method is called (However as mentioned above, the method will called automatically if you assign the creation to a category). | ||
|
||
::: warning | ||
Once the `Build()` is called, you will <u>**not**</u> be able to modify the category any further. | ||
::: | ||
|
||
## Using a Category | ||
|
||
To use a defined category, you must store the variable with the `ConfigurationCategory` and assign your configurations to it. | ||
|
||
You also have the option to get a category from it's ID, allowing you to even get categories declared in other plugins. | ||
|
||
```csharp | ||
string categoryId = "some-mod_category"; | ||
if (LethalConfiguration.TryGetCategory(categoryId, out ConfigurationCategory category)) { | ||
// If the category exists you can use it | ||
} else { | ||
// If the category does not exists you might need to create it | ||
} | ||
``` | ||
|
||
:::tip | ||
You can declare categories as `internal static readonly` variables to access them anywhere in your project. | ||
::: |
112 changes: 112 additions & 0 deletions
112
docs/dev/apis/configurable-company/developing-configs.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
--- | ||
prev: true | ||
next: true | ||
description: How to create Configurable Company configurations for your plugin and how to use them. | ||
--- | ||
|
||
# Developing Configurations with Configurable Company | ||
|
||
Configurations are the core of the API, they allow the developer to define options that the final user can modify to whatever value they want. | ||
|
||
Additionally configurations will be synchronized between the host and clients when they join their game. | ||
|
||
You can add a lot of information to configurations and even modify configurations from other plugins. | ||
|
||
::: warning | ||
As the developer you should avoid setting the value of a configuration manually as that might interfere with the player's choice. | ||
::: | ||
|
||
## Creating a configuration | ||
|
||
To create a configuration is as simple as calling `LethalConfiguration.CreateConfig`. You can choose to provide an ID right from the start or later, however all configurations must contain an unique ID. | ||
|
||
**IDs** must be lowercase, contain only letters, numbers, hypens `-` and underscores `_`. I'd recommend to make your IDs look something like `owner_your-plugin-configuration-name`. | ||
|
||
Here is an example on how you can create a configuration: | ||
:::info | ||
If you don't know what a parameter does, check [parameters](#parameters) section. | ||
::: | ||
|
||
```csharp | ||
LethalConfiguration.CreateConfig() | ||
.SetID("developer_some-mod_sample-configuration") | ||
.SetName("Sample configuration") | ||
.SetTooltip( // Optional but recommended | ||
"This is a custom configuration that does nothing", | ||
"This is a second line for the tooltip", | ||
"", | ||
"This is another line") | ||
.SetCategory(category) // Optional | ||
.SetType(ConfigurationTypes.String) | ||
.SetValue("Random value") | ||
.SetExperimental(false) // Optional | ||
.SetSynchronized(false) // Optional | ||
.Build(); // Optional | ||
``` | ||
|
||
:::tip | ||
It's not necesary to call `Build()` if you are assigning the builder to a `Configuration` as it will implicitly call the build method to create the configuration. | ||
::: | ||
|
||
## Parameters | ||
|
||
- `SetID(string)`: The unique ID of the configuration. | ||
- `SetName(string)`: The name that will be displayed on the in-game menu. | ||
- `SetTooltip(string array)`: Each line of the configuration tooltip. Keep it short and informative. | ||
- `SetCategory(string/ConfigurationCategory)`: Wich category will hold this configuration. There must be always a category, however a default one will be used as failsafe. | ||
- `SetType(ConfigurationType)`: The type of values that this configuration accepts. You can choose one from the alredy existing types `ConfigurationTypes.` or create your own. | ||
- `SetValue(object)`: The value that will contain upon creation. Might be changed instantly if read from file. | ||
- `SetExperimental(bool)`: If this configuration is not guaranteed to work. This is only visual notification for the users. | ||
- `SetSynchronized(bool)`: Marks the configuration to be synchronized with other clients when they join the game. Useful if a configuration might only change client-side. | ||
- `SetNeedsRestart(bool)`: Marks the configuration that the client must restart the game for it to work properly. | ||
|
||
::: warning | ||
Once the `Build()` is called, you will <u>**not**</u> be able to modify the category any further. | ||
::: | ||
|
||
## Configuration Types | ||
|
||
You can choose to create a configuration of your own type however it will take you less time to use one of the existing ones (or request a type to be implemented): | ||
|
||
- `String`: Allows any text (up to 32 characters). | ||
- `SmallString`: Allows a short text (up to 10 characters). | ||
- `Boolean`: Allows true or false. | ||
- `Percent`: Allows a float value that goes from **0** to **100**. | ||
- `Float`: Allows any float or whole number value. | ||
- `Integer`: Allows any whole number value. | ||
- `RangeInteger(min, max)`: A integer that only accepts value within the specified range. | ||
- `RangeFloat(min, max)`: A float that only accepts values within the specified range. | ||
- `Slider(min, max)`: A slider that allows any non-rounded value within the specified range. | ||
- `StringOfLength(length)`: A string that allows you to set a maximum amount of characters that can go from 1 to 48. | ||
- `Options(Enumeration/object collection or array)`: A choosable option that allows for a specific value in a collection _The provided collection must be of just one type, you **can't** use an heterogeneous array_. | ||
|
||
## Using a Configuration | ||
|
||
There are multiple ways you can get the value of a configuration. Each one might be used according to the situation. | ||
|
||
- `configuration.Get<T>()`: This will retrieve the value as an instance of T, no failsafes are used if the conversion of the value to T fails. | ||
- `configuration.Get<T>(T failsafe)`: This will retrieve the value as an instance of T but if the conversion fails it will return the `failsafe` value instead. | ||
- `configuration.TryGet<T>(out T value)`: This is a standard TryGet that will return true if the Get succeded and false if it failed. The resulting value will be stored in `T value`. | ||
- `configuration.Value`: Will return the raw object for the configuration without any cast or check. | ||
|
||
You also have the option to get a configuration from it's ID, allowing you to even get configurations declared in other plugins. | ||
|
||
```csharp | ||
string configurationId = "some-mod_configuration"; | ||
if (LethalConfiguration.TryGetConfig(configurationId, out Configuration category)) { | ||
// If the configuration exists you can use it | ||
} else { | ||
// If the configuration does not exists you might need to create it | ||
} | ||
``` | ||
|
||
_Some configuration types will be automatically converted to other types if you request it. For example the **Options** type will allow you to get the index of the item if you use `Get<int>()` or the value itself if you request it as `Get<T>()` (T being the type of the collection)._ | ||
|
||
To set a configuration you need to use `configuration.TrySet(newValue, ChangeReason)` and will return true if the set was succesful. | ||
|
||
You can also reset a configuration to it's default value using `configuration.Reset()`. | ||
|
||
:::warning | ||
Keep in mind that setting or resetting configurations is not recommended as may interfere with the needs of the final user. | ||
I encourage you to **not** set configurations by yourself and instead let the player choose their values. | ||
::: |
Oops, something went wrong.