# Miscellaneous and tips for custom modules

# Miscellaneous and tips for custom modules

## Localization

For module properties that support a `LocalizationField` parameter it's best to use a localization file.

```csharp
[LocalizedField("Path/To/Your/Localization/String")]
public ModuleProperty<bool> SomeToggleProperty = new(false);
```

Localizations will be automatically loaded by SpaceWarp if placed in `../BepInEx/plugins/YourModFolder/localizations/` inside a `.csv` file.

Structure your `.csv` file like so:

```text
Key,Type,Desc,English,German,French,Italian,Spanish,Japanese,Korean,Polish,Russian,Chinese (Simplified),Portuguese (Brazil),Chinese (Traditional)
Path/To/Your/Localization/String,Text,,English translation goes here,German translation goes here
```

If you don't provide a translation string for a language, it will default to English for that particular string.

If you need to place a comma (`,`) in your translation string, wrap it inside double quotation marks, like so:

```text
Path/To/Your/Localization/String,Text,,"I can write commas here, no problem, as much commas I'd like."
```

## PAM module headers and sorting

If you want your module to have a header before its properties or if it needs to be sorted relative to other modules in the same part, define this in your Patch Manager `.patch` file:

```text
:parts {
    +Module_OrbitalSurvey {
        +Data_OrbitalSurvey {
            ..
        }
    }
    PAMModuleVisualsOverride +: [
        {
            PartComponentModuleName: PartComponentModule_MyCustomModule,
            ModuleDisplayName: "Path/To/Your/Localization/String/Where/Your/Module/Name/Is/Defined",
            ShowHeader: true,
            ShowFooter: true // setting ShowFooter doesn't appear to have any effect? Update this guide if you have new info
        }
    ];
    PAMModuleSortOverride +: [
        {
            PartComponentModuleName: PartComponentModule_MyCustomModule,
            sortIndex: 40 // try setting a different value if you don't get what you need
        }
    ];
}
```

## Register your module for background resource processing

Resource consumption while the vessel is unloaded is disabled by default, as an effort to enhance performance of the stock game. If your module needs to consume resources while it's not loaded (for example life support consumption), Space Warp supports registration of your module to consume resources.

Do this somewhere where you initialize stuff for your mod (example here: in your plugin class):

```csharp
public class YourModPlugin : BaseSpaceWarpPlugin
{
    public override void OnInitialized()
    {
        SpaceWarp.API.Parts.PartComponentModuleOverride
            .RegisterModuleForBackgroundResourceProcessing<PartComponentModule_YourCustomModule>();
    }
}
```

## Tip: add reference to your Part Component module in your Data module class

If you need a reference to your Part Component class from inside your Data class, you can do it like so:

```csharp
public class Data_MyCustomModule : ModuleData
{
    [JsonIgnore]
    public PartComponentModule_MyCustomModule PartComponentModule;
}

public class PartComponentModule_MyCustomModule : PartComponentModule
{
    private Data_MyCustomModule _dataMyCustomModule;

    public override void OnStart(double universalTime)
    {
        if (!DataModules.TryGetByType<Data_MyCustomModule>(out _dataMyCustomModule))
        {
            return;
        }

        _dataMyCustomModule.PartComponentModule = this;
    }
}
```

## Tip: fetch VesselComponent, PartOwner, Body or other values of your vessel or part

```csharp
public class PartComponentModule_MyCustomModule : PartComponentModule
{
    public override void OnStart(double universalTime)
    {
        var partOwner = base.Part.PartOwner;
        var vessel = partOwner.SimulationObject.Vessel;
        var body = vessel.mainBody.Name;
        var altitude = vessel.AltitudeFromRadius;
    }
}
```

## Tip: fetch other modules attached to the part

Sometimes you might need data from other modules.

```csharp
public class PartComponentModule_MyCustomModule : PartComponentModule
{
    private Data_Deployable _dataDeployable;
    private PartComponentModule_ScienceExperiment _moduleScienceExperiment;

    public override void OnStart(double universalTime)
    {
        Part.TryGetModule(typeof(PartComponentModule_ScienceExperiment), out var m);
        _moduleScienceExperiment = m as PartComponentModule_ScienceExperiment;

        Part.TryGetModule(typeof(PartComponentModule_Deployable), out var m2);
        if (m2 != null)
        {
            var moduleDeployable = m2 as PartComponentModule_Deployable;
            foreach (var dataDeployable in moduleDeployable.DataModules?.ValuesList)
            {
                if (dataDeployable is Data_Deployable)
                {
                    _dataDeployable = dataDeployable as Data_Deployable;

                    _dataDeployable.toggleExtend.OnChangedValue += (_) => YourMethodThatWillReactToDeploying();
                    break;
                }
            }
        }
    }
}
```