Trying to add items through code

Nex

New member
I've been trying to create items and item sets through code for quite a bit now, What i've done is create a new class that basically has some copy-pasta from the ItemPickup.cs in the following way:

* Using the CharacterAssist namespace
* Adding a custom ItemPickup.PickupSet[] that would eventually hold all weapons available in the game
* Fetching the player prefab, inventoryBase, ItemCollection, ItemSetManager and ItemPlacement on demand
* looping through the PickupSet[] on keypress (would later be done through network RPC's) to find an item of a certain type name
* trying to add the coresponding PickupSet to the itemSetManager with eg. itemSetManager.AddItemSet(item, itemset, default);
* instantiate and place the item on the player
* finally add the item to the inventory

So basically just like the pickup script works, just without all the parts about having to actually go to a pickup and collide with it.

The problem i'm facing (for the moment) is that i get an IndexOutOfRangeException: Index was outside the bounds of the array.

Which happens when trying to add the item set to the itemsetmanager, and i'm at a loss for any more ideas on how to fix this so I hope someone here could point me in the right direction.

(Any and all points in the direction of how to accomplish: Adding a variable weapon to the player, and players inventory, so they can equip it, all via Code and not any pre-defined pickup gameobjects placed in the world, will all be extremely helpful, the caveat here is that i don't want to: 1) pre-add the items to the players in editor-mode because the inventories are dynamic and read from a database, 2) use pickup-objects that you have to collide with, since the items once again will be added from the server-side through network RPC's)

Full code in code segment below

EDIT: Found some things to change (base class for one) and now it sort of works, except i have to press '2' twice before a sword is equipped, which feels a bit weird, anyone know why this is?

C#:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
using System.Linq;

// Opsive
using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Events;
using Opsive.UltimateCharacterController.Game;
using Opsive.UltimateCharacterController.Inventory;
using Opsive.UltimateCharacterController.Items;
using Opsive.UltimateCharacterController.Utility;

using Opsive.UltimateCharacterController.Objects.CharacterAssist;

[System.Serializable]
public class WeaponEquip : ItemPickup
{
    [Tooltip("The item types we got")]
    [SerializeField] protected List<ItemType> m_ItemTypes = new List<ItemType>();
    [Tooltip("All weapons we got")]
    [SerializeField] protected PickupSet[] m_WeaponPickupSets;
    [Tooltip("The number of ItemType that the character should receive.")]
    [SerializeField] protected int m_Count = 1;

    bool hasBeenGranted = false;

    private InventoryBase inventory;
    private ItemCollection itemCollection;
    private GameObject player;
    private ItemSetManager itemSetManager;
    private ItemPlacement itemPlacement;

    // Start is called before the first frame update
    void Start()
    {
        player = GetMyAvatar();
        itemSetManager = player.GetCachedComponent<ItemSetManager>();

        itemCollection = itemSetManager.ItemCollection;

        inventory = player.GetComponent<InventoryBase>();

        itemPlacement = player.GetComponentInChildren<ItemPlacement>(true);
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyUp(KeyCode.Alpha2))
        {
            Debug.Log("Trying to aquire sword..");
            foreach(var wps in m_WeaponPickupSets)
            {
                if(wps.ItemSet.Slots.First().name == "Sword")
                {
                    var item = wps.Item.GetCachedComponent<Item>();
                    if(itemSetManager != null)
                    {
                        itemSetManager.AddItemSet(item, wps.ItemSet, wps.Default);

                        // Instantiate and add the item to the character.
                        if (!inventory.HasItem(item))
                        {
                            var itemGameObject = ObjectPool.Instantiate(wps.Item, Vector3.zero, Quaternion.identity, itemPlacement.transform);
                            itemGameObject.name = wps.Item.name;
                            itemGameObject.transform.localPosition = Vector3.zero;
                            itemGameObject.transform.localRotation = Quaternion.identity;
                            item = itemGameObject.GetComponent<Item>();
                            inventory.AddItem(item, false);
                            // Pickup item here

                            AddToInventory("Sword");
                        }
                    }
                }
            }
        }
    }
    ItemType GetItemTypeByName(string itemTypeName)
    {
        var itemType = itemCollection.ItemTypes.Where(i => i.name == itemTypeName).FirstOrDefault();
        return itemType;
    }
    GameObject GetMyAvatar()
    {
        var avatars = GameObject.FindGameObjectsWithTag("Player");
        foreach(var ava in avatars)
        {
            if(ava.GetComponent<NetworkIdentity>().isLocalPlayer)
            {
                return ava;
            }
        }
        return new GameObject();
    }
    void AddToInventory(string itemType)
    {
        // Get the players avatar
        var ava = GetMyAvatar();

        // Use generic function to do the rest.
        _AddToInventory(ava, itemType);
    }

    // Overload for server use.
    void AddToInventory(GameObject ava, string itemType)
    {
        // Just use the private function
        _AddToInventory(ava, itemType);
    }
    private void _AddToInventory(GameObject ava, string itemTypeName)
    {
        if (inventory == null)
        {
            return;
        }

        var itemType = itemCollection.ItemTypes.Where(i => i.name == itemTypeName).FirstOrDefault();

        if(itemType)
        {
            inventory.PickupItemType(itemType, m_Count, -1, true, false);
        }
    }
}
 
Last edited:
Does PickupItemType get called once? Or twice?

It would seem once, first time i first get:
IndexOutOfRangeException: Index was outside the bounds of the array.
on : itemSetManager.AddItemSet(item, wps.ItemSet, wps.Default);

the second time i press it, everything goes smoothly through


IndexOutOfRangeException: Index was outside the bounds of the array.
Opsive.UltimateCharacterController.StateSystem.StateManager.InitializeInternal (UnityEngine.GameObject gameObject, Opsive.UltimateCharacterController.StateSystem.IStateOwner owner, Opsive.UltimateCharacterController.StateSystem.State[] states) (at Assets/Opsive/UltimateCharacterController/Scripts/StateSystem/StateManager.cs:79)
Opsive.UltimateCharacterController.StateSystem.StateManager.Initialize (UnityEngine.GameObject gameObject, Opsive.UltimateCharacterController.StateSystem.IStateOwner owner, Opsive.UltimateCharacterController.StateSystem.State[] states) (at Assets/Opsive/UltimateCharacterController/Scripts/StateSystem/StateManager.cs:67)
Opsive.UltimateCharacterController.StateSystem.StateObject.Initialize (UnityEngine.GameObject gameObject) (at Assets/Opsive/UltimateCharacterController/Scripts/StateSystem/StateObject.cs:29)
Opsive.UltimateCharacterController.Inventory.ItemSet.Initialize (UnityEngine.GameObject gameObject, Opsive.UltimateCharacterController.Inventory.ItemSetManager itemSetManager, System.Int32 categoryID, System.Int32 categoryIndex, System.Int32 index) (at Assets/Opsive/UltimateCharacterController/Scripts/Inventory/ItemSet.cs:84)
Opsive.UltimateCharacterController.Inventory.ItemSetManager.AddItemSet (Opsive.UltimateCharacterController.Items.Item item, Opsive.UltimateCharacterController.Inventory.ItemSet itemSet, System.Boolean defaultItemSet) (at Assets/Opsive/UltimateCharacterController/Scripts/Inventory/ItemSetManager.cs:184)
 
Last edited:
Having that exception will definitely cause problems. If you set a breakpoint is the states array null?
 
Having that exception will definitely cause problems. If you set a breakpoint is the states array null?

I added a Debug.Log to show me counts of states, the first time i press its 0, the second time its 1

However i have no idea why this is (one thought is i could do a quick and dirty and add a if state count is 0 add a default state first)

Ideas?
 
The states array should always have at least one item. Are you able to add the item with the pickup item component? This will indicate if it is a problem with your script or how the item is setup.
 
Yes if i use a "pickup gameobject" as per the tutorials then it works fine to pick it up and equip, and also if i click twice on the key '2' then it also gets equipped
 
Top