PLib 4.17.1
dotnet add package PLib --version 4.17.1
NuGet\Install-Package PLib -Version 4.17.1
<PackageReference Include="PLib" Version="4.17.1" />
paket add PLib --version 4.17.1
#r "nuget: PLib, 4.17.1"
// Install PLib as a Cake Addin #addin nuget:?package=PLib&version=4.17.1 // Install PLib as a Cake Tool #tool nuget:?package=PLib&version=4.17.1
PLib
PLib is Peter's library for making mods. All mods in this repository depend on PLib via ILMerge.
PLib 4.0 is now modular, allowing mods to only include and merge the components that they use, along with the much reduced PLib Core library. PLib 4.0 is not backwards compatible with PLib 2.0 and 3.0, but both can be run side by side (if that was possible). PLib 4.0 and up supports Harmony 2.0 for the new game versions merging the vanilla game and Spaced Out! DLC, but PLib 3.0 and lower do not.
Obtaining
Source
PLib can be checked out and compiled from source (tested on Visual Studio Community 2019).
If Oxygen Not Included is installed in a different location, make a copy of Directory.Build.Props.default
named Directory.Build.Props.user
and update the game folder paths appropriately.
Binary
DLL releases for major versions are available in the releases page. Only the complete library is available from NuGet, which is sufficient for most users. Individual components of the library are also available in the releases section.
NuGet
PLib is available as a NuGet package.
Usage
PLib must be included with mods that depend on it. The best method to do this is to use ILMerge or ILRepack and add the PLib project or DLL as a reference in the mod project. ILMerge is available as a NuGet package and is best used as a post-build command. Suggested command:
"$(ILMergeConsolePath)" /ndebug /out:$(TargetName)Merged.dll $(TargetName).dll PLib.dll /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319
This helps ensure that each mod uses the version of PLib that it was built against, reducing the risk of breakage due to PLib changes.
Note that if using ILMerge, all dependencies of your mod and PLib must be added as references to the project.
Avoid merging Unity assemblies with the compiled DLL, and turn off Copy Local on all other library DLLs such as 0Harmony
and Assembly-CSharp
.
PLib can also be packaged separately as a DLL with an individual mod, but on Mac and Linux this may lead to version issues.
Some parts of PLib need to be patched only once, or rely on having the latest version.
To handle this problem, PLib uses forwarded components, which only loads the components and patches that are in use, using the latest version of each component available across all installed mods.
Only one instance of each registered forwarded component is instantiated, even if multiple mods have the same version, although which one is used in case of a tie is unspecified.
Custom forwarded components in mod code can be implemented by subclassing PeterHan.PLib.Core.PForwardedComponent
.
Initialization
Initialize PLib by calling PUtil.InitLibrary(bool)
in OnLoad
.
PLib must be initialized before using most of PLib functionality, but instantiating most PLib components will now also initialize PLib if necessary.
It will emit the mod's AssemblyFileVersion
to the log if the bool
parameter is true, which can aid with debugging.
Using the AssemblyVersion
instead is discouraged, because changing AssemblyVersion
breaks any explicit references to the assembly by name.
(Ever wonder why .NET 3.5 still uses the .NET 2.0 version string?)
Core
The PLib.Core
component is required by all other PLib components.
It contains only a minimal patch manager and general utilities that do not require any patches at runtime, such as Detours, reflection utilities, and basic game helpers.
User Interface
The PLib.UI
component is used to create custom user interfaces, in the same style as the base game.
It requires PLib.Core
.
For more details on the classes in this component, see the XML documentation.
Side Screens
Add a side screen class in a postfix patch on DetailsScreen.OnPrefabInit
using PUIUtils.AddSideScreenContent<T>()
.
The type parameter should be a custom class which extends SideScreenContent
.
The optional argument can be used to set an existing UI GameObject
as the UI to be displayed, either created using PLib UI or custom creation.
If the argument is null
, create the UI in the OnPrefabInit
of the side screen content class, and use AddTo(gameObject, 0)
on the root PPanel to add it to the side screen content.
A reference to the UI GameObject
created by AddTo
should also be stored in the ContentContainer
property of the side screen content class.
Note that SetTarget
is called on the very first object selected before OnPrefabInit
runs for the first time.
Make sure that this case is handled in code, and that OnPrefabInit
refreshes the UI after it is built to match the current target object.
Options
The PLib.Options
component provides utilities for reading and writing config files, as well as editing configs in-game via the mod menu.
It requires PLib.UI
and PLib.Core
.
Reading/writing config files
To read, use PLib.Options.POptions.ReadSettings<T>()
where T is the type that the config file will be deserialized to.
In PLib 4.0, the type will be associated with the assembly that defines that type, not the calling assembly like PLib 2.0 and 3.0.
By default, PLib will place the config file in the mod assembly directory, named config.json
, and will give each archived version its own configuration.
The ConfigFile
attribute can be used to modify the name of the configuration file and enable auto-indenting to improve human readability.
If the UseSharedConfigLocation
flag is set, the configuration file will be saved in a location that survives updating or reinstalling the mod; the name of the mod's primary assembly will be used for the folder name.
To write, use PLib.Options.POptions.WriteSettings<T>(T settings)
, where again T is the settings type.
Registering for the config screen
PLib.Options adds configuration menus to the Mods screen for mods that are registered.
Register a mod by using POptions.RegisterOptions(UserMod2, Type settingsType)
in OnLoad
.
Creating a new POptions
instance is required to use this method, but only one POptions
instance should be created per mod.
The argument should be the type of the class the mod uses for its options, and must be JSON serializable.
Newtonsoft.Json
is bundled with the game and can be referenced.
The class used for mod options can also contain a ModInfo([string url=""], [string image=""])
annotation to display additional mod information.
Note that the title from PLib 2.0 and 3.0 is no longer part of this attribute, as this functionality has been moved to the Klei mod.yaml
file.
The URL can be used to specify a custom website for the mod's home page; if left empty, it defaults to the Steam Workshop page for the mod.
The image, if specified, will attempt to load a preview image (best size is 192x192) with that name from the mod's data folder and display it in the settings dialog.
Each option must be a property, not a member, and should be annotated with Option(string displaytext, [string tooltip=""])
to be visible in the mod config menu.
Currently supported types are: int
, int?
, float
, float?
, string
, bool
, Color
, Color32
, and Enum
.
If a property is a read-only System.Action
, a button will be created that will execute the returned action if clicked.
If a property is of type LocText
, no matter what it returns, the text in displaytext
will be displayed as a full-width label with no input field.
If a property is of a user-defined type, PLib will check the public properties of that type -- if any of them have Option
attributes, the property will be rendered as its own category with each of the inner options grouped inside.
If a valid localization string key name is used for displaytext
(such as STRINGS.YOURMOD.OPTIONS.YOUROPTION
), the localized value of that string from the strings database is used as the display text.
To support types not in the predefined list, the [DynamicOption(Type)]
attribute can be added to specify the type of an IOptionsEntry
handler class that can display the specified type.
If the type used as the handler has a constructor with the same signature as one of the predefined options entry classes, the arguments matching those parameters will be passed to it.
Categories
The optional third parameter of Option
allows setting a custom category for the option to group related options together.
The category name is displayed as the title for the section.
If a valid localization string key name is used for the category (such as STRINGS.YOURMOD.OPTIONS.YOURCATEGORY
), the localized value of that string from the strings database is used as the title.
All options inside a nested custom options class are placed under a category matching the title of the declaring Option
property.
Range limits
int
, int?
, float
and float?
options can have validation in the form of a range limit.
Annotate the property with PLib.Options.Limit(double min, double max)
.
If PLib.Options.Limit
is used on a string
field, the max
will be used as the maximum string length for the option value.
Note that users can still enter values outside of the range manually in the configuration file.
Example
using Newtonsoft.Json;
using PeterHan.PLib.Options;
// ...
[JsonObject(MemberSerialization.OptIn)]
[ModInfo("https://www.github.com/peterhaneve/ONIMods")]
public class TestModSettings
{
[Option("Wattage", "How many watts you can use before exploding.")]
[Limit(1, 50000)]
[JsonProperty]
public float Watts { get; set; }
public TestModSettings()
{
Watts = 10000f; // defaults to 10000, e.g. if the config doesn't exist
}
}
using PeterHan.PLib.Core;
using PeterHan.PLib.Options;
// ...
public sealed class ModLoad : KMod.UserMod2
{
public static void OnLoad()
{
PUtil.InitLibrary(false);
new POptions().RegisterOptions(typeof(TestModSettings));
}
}
This is how it looks in the mod menu:
Actions
The PLib.Actions
component is used to register actions to be executed on user input.
It requires PLib.Core
.
Actions created by this component can be rebound in the game options.
Register actions by using PActionManager.CreateAction(string, LocString, PKeyBinding)
in OnLoad
.
Creating a new PActionManager
instance is required to use this method, but only one PActionManager
instance should be created per mod.
The identifier should be unique to the action used and should include the mod name to avoid conflicts with other mods.
If multiple mods register the same action identifier, only the first will receive a valid PAction
.
The returned PAction
object has a GetKAction
method which can be used to retrieve an Action
that works in standard Klei functions.
The PKeyBinding
is used to specify the default key binding.
Note that the game can change the values in the Action
enum.
Instead of using the built-in Action.NumActions
to denote "no action", consider using PAction.MaxAction
instead which will use the correct value at runtime if necessary.
Lighting
The PLib.Lighting
component allows Light2D
objects to emit light in a custom shape and intensity falloff.
It requires PLib.Core
.
Register lighting types by using PLightManager.Register(string, CastLight)
in OnLoad
.
Creating a new PLightManager
instance is required to use this method, but only one PLightManager
instance should be created per mod.
The identifier should be unique to the light pattern that will be registered.
If multiple mods register the same lighting type identifier, all will receive a valid ILightShape
object but only the first mod to register that shape will be used to render it.
The returned ILightShape
object has a GetKLightShape
method which can be used to retrieve a LightShape
that works in standard Light2D
functions.
The CastLight
specifies a callback in the mod that can handle drawing the light. It needs the signature
void CastLight(LightingArgs args);
The mod will receive an object encapsulating the lighting arguments, including the source of the light with the Light2D
component and the starting cell.
See the LightingArgs
class for more details.
Buildings
The PLib.Buildings
component abstracts several details of adding new buildings.
It requires PLib.Core
.
Register a new building by using PBuildingManager.Register(PBuilding)
in OnLoad
.
Creating a new PBuildingManager
instance is required to use this method, but only one PBuildingManager
instance should be created per mod.
The PBuilding
instance should be created only once, in OnLoad
.
The building name, description, and effect can all be specified directly, or left empty to use the default localization string keys for each string.
The tech tree location and build menu location can also be specified without needing other patches.
Database
The PLib.Database
component deals with non-building operations involving the game database, translation, and codex files.
It requires PLib.Core
.
Translations
Register a mod for translation by using PLocalization.Register()
in OnLoad
.
Creating a new PLocalization
instance is required to use this method, but only one PLocalization
instance should be created per mod.
All classes in the mod assembly with public static
LocString
fields will be eligible for translation.
Translation files need to be placed in the translations
folder in the mod directory, named as the target language code (zh-CN for example) and ending with the .po
extension.
Note that the translation only occurs after all mods load, so avoid referencing the LocString
fields during class initialization or OnLoad
as they may not yet be localized at that time.
Codex Entries
Register a mod for codex loading by using PCodexManager.RegisterCreatures()
and/or PCodexManager.RegisterPlants()
.
Creating a new PCodexManager
instance is required to use this method, but only one PCodexManager
instance should be created per mod.
The codex files will be loaded using the same structure as the base game: a codex
folder must exist in the mod directory, with Creatures
and Plants
subfolders containing the codex data.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET Framework | net471 is compatible. net472 was computed. net48 was computed. net481 was computed. |
-
.NETFramework 4.7.1
- ILRepack.Lib.MSBuild.Task (>= 2.0.26)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Update side screen handling code for U53-640445.
Add new PPatchManager locations for DetailsScreen.OnPrefabInit and Db.PostProcess.