Lethal Company
You are viewing a potentially older version of this package. View Latest Version
Install with App

Details

Date Uploaded
3 weeks ago
Downloads
56.5K
Size
122KB

Icon by my friend @down

HatLib

A personal library for my mods, does nothing on it's own.

DawnLib is a hard dependency for this library.

If depending on HatLib, use this in your plugin:

[BepInDependency(HatLib.Plugin.modGUID, BepInDependency.DependencyFlags.HardDependency)]

Add these to your .csproj:

<PackageReference Include="TeamXiaolan.DawnLib" Version="0.9.25" />
<PackageReference Include="TeamXiaolan.DawnLib.DuskMod" Version="0.9.25" />

For Devs

DuskConfigInjector

Creates or reads Dusk config entries for any mod registered via Dusk.

public static T Read<T>(string dawnModGUID, string section, string settingName)
public ConfigEntry<T>? Bind<T>(string section, string settingName, T defaultValue, string description)

First, get the Dusk GUID. This is the GUID created from the Author Name and Mod Name on your Dusk Mod Information ScriptableObject in Unity Editor and will always result in the GUID being AuthorName.ModName:

private static readonly DuskConfigInjector Dusk = new("AuthorName.ModName");

Then, configs are very similar to how you'd make them for BepInEx:

private static ConfigEntry<bool> Config1;
private static ConfigEntry<float> Config2;

internal static void Bind()
{
	Config1 = Dusk.Bind("Config Section", "Setting Name", false, "Config Description");
	Config2 = Dusk.Bind("Config Section", "Setting Name", 30f, "Speed multiplier", 0f, 100f); // Displays as a slider
}

You can also read an existing Dusk config value from another mod using its GUID, section, and setting name. An example usecase for this would be checking if an asset is enabled before registering a NetworkObject from it through DawnLib, or preventing a patch from running when the related content is disabled:

bool example = DuskConfigInjector.Read<bool>("AuthorName.ModName", "Config Section", "Config Name");

And then just call Bind() in your plugin's Awake().

PlayerAnimatorReplacement

A GrabbableObject replacement for items that need to swap the player's Animator Controller while being held.

Instead of inheriting from GrabbableObject, inherit from PlayerAnimatorReplacement:

public class ExampleItem : PlayerAnimatorReplacement

This gives the item a Player Animator field with a Local Animator and Remote Animator. The local animator is used for the player holding the item on their own client, while the remote animator is used for that player on other clients.

To swap the player's animator, call:

SwapHeldPlayerAnimator();

And to change it back to the vanilla player animator, call:

RestoreHeldPlayerAnimator();

For a simple item, you'd generally swap when the item is grabbed/equipped and restore it when pocketed/dropped:

public override void EquipItem()
{
	base.EquipItem();
	SwapHeldPlayerAnimator();
}

public override void GrabItem()
{
	SwapHeldPlayerAnimator();
	base.GrabItem();
}

public override void PocketItem()
{
	base.PocketItem();
	RestoreHeldPlayerAnimator();
}

public override void DiscardItem()
{
	base.DiscardItem();
	RestoreHeldPlayerAnimator();
}

The replacement Animator Controllers need these player layers to be present so it doesn't interfere or break vanilla's animations:

  • UpperBodyEmotes
  • EmotesNoArms
  • HoldingItemsRightHand
  • HoldingItemsBothHands
  • SpecialAnimations
DawnFindResource

Some helpers for finding loaded content from DawnLib registries using their NamespacedKeys.

public static void OnFreeze<TInfo>(Registry<TInfo> registry, Action action) where TInfo : INamespaced<TInfo>
public static bool Resolve<TInfo>(Registry<TInfo> registry, NamespacedKey<TInfo> key, out TInfo info) where TInfo : INamespaced<TInfo>
public static bool Resolve<TInfo, TValue>(Registry<TInfo> registry, NamespacedKey<TInfo> key, Func<TInfo, TValue?> read, string name, out TValue value) where TInfo : INamespaced<TInfo> where TValue : class

First, use OnFreeze to make sure the Dawn registry has finished loading before trying to grab anything from it:

DawnFindResource.OnFreeze(LethalContent.Items, LoadedResources);

private static void LoadedResources()
{
}

Then make a NamespacedKey for whatever you're trying to find:

NamespacedKey<DawnItemInfo> itemKey = NamespacedKey<DawnItemInfo>.Vanilla("gift"); // For vanilla
NamespacedKey<DawnItemInfo> itemKey = NamespacedKey<DawnItemInfo>.From("mod_namespace", "content_key"); // For modded

Resolve can give you the Dawn info itself:

if (DawnFindResource.Resolve(LethalContent.Items, itemKey, out DawnItemInfo itemInfo)) Item item = itemInfo.Item;

Or you can give it a selector to grab something from inside the loaded content instead. This can be useful for grabbing things such as prefabs, components, audio clips, materials, or whatever else you can reach from the Dawn info:

if (DawnFindResource.Resolve(LethalContent.Items, itemKey, info => info.Item.spawnPrefab, "item prefab", out GameObject itemPrefab)) ExamplePrefab = itemPrefab;

The name is only used to identify what was missing in the error log if the key is not found or the selected value is null.

OnFreeze also runs the action immediately if the registry has already frozen, so you don't have to care whether you're registering before or after Dawn finished loading it.

Thunderstore development is made possible with ads. Please consider making an exception to your adblock.