Thank you for the detailed question.
From the information you are telling I am assuming you are not using the "Equipper" component right?
Currently that script is quite limited and I often tell users that it is worth creating their own from scratch.
Right now you want to swap the hat sprite, but I assume you'll want to do the same for other things on the character like the weapon.
So my advice is to create a new component that would sit next to the character inventory. You can call the script "CharacterEquipper" or something like that. You'll use that component to listen to the inventory to know when an item was moved to the Equipped Item Collection.
The code example below should give you a good start. It is inspired from the Equipper script, make sure to check that one out if you have more questions. Also I added a lot of comments in the code to guide you, make sure to read them.
C#:
public class CharacterEquipper : MonoBehaviour //Optional Inherit IEquipper, if you do check the Equipper script.
{
[Tooltip("The equippers inventory.")]
[SerializeField] protected Inventory m_Inventory;
[Tooltip("The equippers itemCollection within the inventory.")]
[SerializeField]
protected ItemCollectionID m_EquipmentItemCollectionID =
new ItemCollectionID("Equipped", ItemCollectionPurpose.Equipped);
protected ItemSlotCollection m_EquipmentItemCollection;
/// <summary>
/// Initialize the Equipper.
/// </summary>
protected virtual void Start()
{
if (m_Inventory == null) { m_Inventory = GetComponent<Inventory>(); }
m_EquipmentItemCollection = m_Inventory.GetItemCollection(m_EquipmentItemCollectionID) as ItemSlotCollection;
if (m_EquipmentItemCollection == null) {
Debug.LogWarning("Your inventory does not have an equipment Item Collection.");
return;
}
// The events needs to be declared exactly as specified, the event target and the parameter must match perfectly.
EventHandler.RegisterEvent<ItemInfo, ItemStack>(m_Inventory, EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack, OnAddedItemToInventory);
EventHandler.RegisterEvent<ItemInfo>(m_Inventory, EventNames.c_Inventory_OnRemove_ItemInfo, OnRemovedItemFromInventory);
var equipmentItemAmounts = m_EquipmentItemCollection.GetAllItemStacks();
if (equipmentItemAmounts == null) {
Debug.LogWarning("The Equipment Item Collection is null.");
return;
}
for (int i = 0; i < equipmentItemAmounts.Count; i++) {
Equip(equipmentItemAmounts[i].Item);
}
}
/// <summary>
/// Make sure to unregister the listener on Destroy.
/// </summary>
private void OnDestroy()
{
EventHandler.UnregisterEvent<ItemInfo, ItemStack>(m_Inventory, EventNames.c_Inventory_OnAdd_ItemInfo_ItemStack, OnAddedItemToInventory);
EventHandler.UnregisterEvent<ItemInfo>(m_Inventory, EventNames.c_Inventory_OnRemove_ItemInfo, OnRemovedItemFromInventory);
}
/// <summary>
/// Equip item that was added to the equipment collection.
/// </summary>
/// <param name="originItemInfo">The origin Item info.</param>
/// /// <param name="addedItemStack">The added item stack.</param>
private void OnAddedItemToInventory(ItemInfo originItemInfo, ItemStack addedItemStack)
{
if (addedItemStack == null) { return; }
if (addedItemStack.ItemCollection == m_EquipmentItemCollection) {
Equip(addedItemStack.Item);
}
}
/// <summary>
/// Unequip an item that was removed from the equipment collection.
/// </summary>
/// <param name="removedItemInfo">The removed Item info.</param>
private void OnRemovedItemFromInventory(ItemInfo removedItemInfo)
{
if (removedItemInfo.ItemCollection == m_EquipmentItemCollection) {
UnEquip(removedItemInfo.Item);
}
}
/// <summary>
/// Equip an item.
/// </summary>
/// <param name="item">The item to equip.</param>
/// <returns>Return true only if the item equipped successfully.</returns>
public virtual void Equip(Item item)
{
// Visually Equip your item!
//Get the slot where the item was equipped by index:
var itemSlotIndex = m_EquipmentItemCollection.GetItemSlotIndex(item);
//Knowing the item slot index you can spawn the item in the right place
//Use attributes to get the item sprite and other values that can affect the player
if (item.TryGetAttributeValue("MyItemSprite", out Sprite sprite) == false) {
//The item attribute does not exist!
Debug.LogWarning("The attribute does not exist");
return;
}
//Use the 'sprite' variable to swap the Sprite.
//Do the same to get attack, health boosts, etc...
//You can even send an event from here so that other objects can listen.
}
/// <summary>
/// UnEquip an item.
/// </summary>
/// <param name="item">The item to unequip.</param>
public virtual void UnEquip(Item item)
{
// Visually Unequip Item!
//You can even send an event from here so that other objects can listen.
}
}
For your other question to restrict the items you can do so using a IItemRestriction, you can find the documenation for that here:
In most games Inventories have limitations, such as space or stack size, etc… By default ItemCollections have no limitations in the Inventory System. You are . . .
opsive.com
Essentially make a Monobehaviour that inherits that interface. In the AddCondition function check the item Attribute or category to know if the item is allowed to equip the items.
You could actually use the same "CharacterEquipper" script and just inherit the interface.
C#:
public class CharacterEquipper : MonoBehaviour, IItemRestriction //Make sure to inherit the IItemRestriction
{
//... The code from before
public void Initialize(IInventory inventory, bool force)
{
//Nothing to do here if you don't want to.
}
/// <summary>
/// Condition to add an item.
/// </summary>
/// <param name="itemInfo">The item Info that wants to be added.</param>
/// <param name="receivingCollection">The collection that will receive the item.</param>
/// <returns>The item info</returns>
public ItemInfo? AddCondition(ItemInfo itemInfo, ItemCollection receivingCollection)
{
// If we aren't adding to equipped then let the item go through
if (receivingCollection != m_EquipmentItemCollection) { return itemInfo; }
//Check the item attribute to know if it can be equipped
if (itemInfo.Item.TryGetAttributeValue("LevelRequired", out int itemLevel) == false) {
//Attribute does not exist meaning no level requirement so equip the item no problem.
return itemInfo;
}
//The item can be equipped fine if the character has a higher level
//if(character.level > itemLevel) { return itemInfo; }
//If not then the item cannot be equipped, therefore retrun null;
return null;
}
/// <summary>
/// No restriction on removing items.
/// </summary>
/// <param name="itemInfo">The item info to remove.</param>
/// <returns>The item info to remove.</returns>
public ItemInfo? RemoveCondition(ItemInfo itemInfo)
{
return itemInfo;
}
}
To learn more about getting values from an item check this:
https://opsive.com/support/documentation/ultimate-inventory-system/item/
I hope this helps, you should have everything to equip your item however you want, with control over what items get equipped.
If you find that you are limited by these options, and you want to have absolute control over your items equipping you can look into making a custom Item Collection, but that is more advanced, so only go for it if the options I gave you above aren't flexible enough