While I don't want to be overly-strict on coding style, there are specific standards to apply. The standards in place aren't meant to cause headache. They are to keep the project consistent and predictable.
- Please review the codebase thoroughly before doing a PR.
See VERSIONING.md for the branch and hotfix versioning policy.
- All classes must exist in a logical namespace matching the folder structure.
- Internal API code should be placed in
S1API.Internalsub-namespaces.
namespace S1API.Internal.Utils { ... }These are purely based on my preference. Feel free to discuss with me if you feel otherwise.
- In general, naming follows the default Jetbrains Rider suggestions.
- PascalCase is to be utilized for class names, methods, properties, and non-private fields.
- camelCase is to be used for local variables and private fields.
- Prefix private fields and internal fields with
_.
private int _myInteger;
internal string _name;
internal object _gameBuilding;- Internal wrapper properties that reference game types should use PascalCase with an
S1prefix (e.g.,S1ItemInstance,S1ItemDefinition,S1LandVehicle).
internal readonly S1ItemFramework.ItemInstance S1ItemInstance;
internal S1ItemFramework.ItemDefinition S1ItemDefinition { get; }- Static readonly fields use PascalCase (e.g.,
All,Logger).
internal static readonly List<Building> All = new List<Building>();
private static readonly Log Logger = new Log("Namespace");- Enums do not need to be prefixed with
E. I'd like us to keep this consistent. - Utilize Enums over strings where possible. (e.g. "Low" ->
CustomerStandard.Low) - Utilize existing common naming conventions from the codebase.
I don't want to see
SomeManager,SomeHandler,SomeSystem, etc. throughout this codebase. See what is already in use naming-wise, and commit to it like everyone else.
- Internal classes must be marked as
internalto prevent confusion for modders. - Modder-facing API classes, methods, properties, and fields should use
public. - The exception to this rule is when you want a property available for abstraction by modders, but not publicly accessible.
- An example of this is the
NPC.cs. We utilize theprotectedaccess modifier to allow them to override, but not access from outside the class.
- An example of this is the
- Use
sealedon classes when inheritance is not intended (e.g., wrapper classes likeBuilding).
public sealed class Building { ... }- Explicit usage of access methods at all times.
- Arrow functions (
=>) are used for simple methods and properties. They are to be placed below the declaration and indented once.
// property example
public string Name =>
S1NPC.FullName;
// method example
public float AddNumbers(float a, float b) =>
a + b;- Use
readonlyorconstfor immutable values.- Internal readonly fields should be used for immutable references to game objects.
internal readonly S1ItemFramework.ItemInstance S1ItemInstance;- Nullable variables should be declared as so using
?.
public ItemInstance? ItemInstance { get; }- All modder-facing API declarations must have an associated summary.
/// <summary>
/// Destroys all game objects in the world.
/// </summary>
public void DestroyGameWorld() { ... }- This is now enforced and will produce build warnings. Please keep your code documented.
- Include detailed parameter descriptions in XML documentation when methods have parameters.
/// <summary>
/// Gets the definition of an item by its ID.
/// </summary>
/// <param name="itemID">The ID of the item.</param>
/// <returns>An instance of the item definition.</returns>
public static ItemDefinition GetItemDefinition(string itemID) { ... }- Use
#if (MONOMELON || MONOBEPINEX)and#elif (IL2CPPBEPINEX || MONOBEPINEX)for platform-specific logic. - Wrap and alias
usingstatements to provide platform-agnostic support.
#if (IL2CPPMELON)
using S1ItemFramework = Il2CppScheduleOne.ItemFramework;
#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX)
using S1ItemFramework = ScheduleOne.ItemFramework;
#endif- Use
#regionand#endregionto organize code sections when appropriate (e.g.,#region Private Members).
- Group related members together using comments or regions.
- Organize classes with: Internal members first, then public API, then private implementation details.
- Static utility classes should be marked as
static.
public static class ItemManager { ... }- Do not leak Il2Cpp (game) types across the API.
The API is intended to leave the modder in the native C#
Systemenvironment. - Utilize the tools present in our
Internalnamespace. They are there because we've collectively agreed on a better solution to a common problem.