Avatar Equippable Prefabs
AvatarEquippable prefabs control how items appear in third-person view when other players see you holding them. You can create your own prefabs in Unity and load them through an AssetBundle.
Step 1: Create the Prefab in Unity
- Open Unity with the Schedule One project or a compatible Unity version.
- Create a new
GameObjectin your scene. - Add the
AvatarEquippablecomponent. - Configure the component:
- Hand: left or right
- Animation Trigger: for example
RightArm_Hold_ClosedHand - Suspiciousness:
0.0to1.0 - Trigger Type: trigger or bool
- Create a child
GameObjectnamedAlignmentPoint. - Position
AlignmentPointwhere the hand should grip the item and assign it to the component. - Add your 3D model as a child and align it relative to
AlignmentPoint. - Set the
AssetPath. - Save the object as a prefab.
Step 2: Export to AssetBundle
- Select the prefab in the Project window.
- Assign an AssetBundle label such as
myitem_equippables. - Build the AssetBundle and ensure the prefab is included.
Step 3: Embed the AssetBundle in Your Mod
- Add the bundle file to your mod project.
- Mark it as an embedded resource.
- Confirm the final resource name, for example
YourModName.Resources.myitem_equippables.
Step 4: Load and Register With S1API
using S1API.AssetBundles;
using S1API.Items;
using System.Reflection;
public class MyMod : MelonMod
{
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
{
if (sceneName == "Main")
{
InitializeAvatarEquippables();
}
}
private void InitializeAvatarEquippables()
{
var bundle = AssetLoader.GetAssetBundleFromStream(
"MyMod.Resources.myitem_equippables",
Assembly.GetExecutingAssembly()
);
AvatarEquippableRegistry.LoadAndRegisterFromBundle(
bundle: bundle,
prefabName: "MyItem_AvatarEquippable",
assetPath: "Equippables/MyItem"
);
MelonLogger.Msg("Registered AvatarEquippable prefab");
}
}
Alternative: Load From Embedded Bundle Directly
AvatarEquippableRegistry.LoadAndRegisterFromEmbeddedBundle(
bundleName: "myitem_equippables",
prefabName: "MyItem_AvatarEquippable",
assetPath: "Equippables/MyItem"
);
Step 5: Use the Registered Prefab
var equippable = ItemCreator.CreateEquippableBuilder()
.CreateViewmodelEquippable("MyItem")
.WithAvatarEquippable(
assetPath: "Equippables/MyItem",
hand: AvatarHand.Right,
animationTrigger: "RightArm_Hold_ClosedHand"
)
.Build();
Complete Example
using MelonLoader;
using S1API.AssetBundles;
using S1API.Items;
using System.Reflection;
using UnityEngine;
public class MyMod : MelonMod
{
private bool _initialized = false;
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
{
if (sceneName == "Main" && !_initialized)
{
InitializeMod();
_initialized = true;
}
}
private void InitializeMod()
{
RegisterAvatarEquippable();
var equippable = ItemCreator.CreateEquippableBuilder()
.CreateViewmodelEquippable("MyCustomItem")
.WithInteraction(canInteract: true, canPickup: true)
.WithViewmodelTransform(
position: new Vector3(0.2f, -0.15f, 0.3f),
rotation: Vector3.zero,
scale: Vector3.one
)
.WithAvatarEquippable(
assetPath: "Equippables/MyCustomItem",
hand: AvatarHand.Right,
animationTrigger: "RightArm_Hold_ClosedHand"
)
.WithUseCallback((itemInstance) =>
{
MelonLogger.Msg($"Used: {itemInstance.Definition.Name}");
})
.Build();
var item = ItemCreator.CreateBuilder()
.WithBasicInfo(
id: "my_custom_item",
name: "My Custom Item",
description: "A custom item with viewmodel and third-person animation",
category: ItemCategory.Tools
)
.WithEquippable(equippable)
.Build();
MelonLogger.Msg("Created custom item with AvatarEquippable!");
}
private void RegisterAvatarEquippable()
{
try
{
bool success = AvatarEquippableRegistry.LoadAndRegisterFromEmbeddedBundle(
bundleName: "myitem_equippables",
prefabName: "MyCustomItem_AvatarEquippable",
assetPath: "Equippables/MyCustomItem",
assemblyOverride: Assembly.GetExecutingAssembly()
);
if (success)
{
MelonLogger.Msg("Successfully registered AvatarEquippable prefab");
}
else
{
MelonLogger.Error("Failed to register AvatarEquippable prefab");
}
}
catch (System.Exception ex)
{
MelonLogger.Error($"Exception registering AvatarEquippable: {ex.Message}");
MelonLogger.Error(ex.StackTrace);
}
}
}
Tips
- Position
AlignmentPointexactly where the hand should grip the item - Match your model scale to existing equippables in the game
- Reuse existing animation triggers unless you fully control the animation setup
- The registered
assetPathmust exactly match the path used inWithAvatarEquippable() - Test multiplayer presentation, not just first-person view