Forum rules - please read before posting.

Inventory - Linked Prefabs

edited July 2019 in Technical Q&A

Hello,

Assuming the linked prefabs for inventory items are unique, is there any way a linked prefab can know what InvID it's attached to?

Thanks!

Comments

  • edited July 2019

    You can iterate through the defined items and compare their linkedPrefab variable, i.e.:

    public int GetLinkedID (GameObject prefab)
    {
        foreach (InvItem item in KickStarter.inventoryManager.items)
        {
            if (item.linkedPrefab == prefab)
            {
                return item.id;
            }
        }
        Debug.LogWarning ("Not found");
        return -1;
    }
    
  • edited November 2020

    AC Ver: 1.72.2
    Unity Ver: 2019.4.8f1

    Sorry for dragging up an old question but would you believe I'm only now able to look at this. Unfortunately I'm not geting the results I would expect and in all cases I get an output of -1

    Here's my code, which is attached to a prefab which is instantiated during runtime:

     public int test;
    
        private void Start()
        {
            test = GetLinkedID(this.gameObject);
            print(test);
        }
    
        public int GetLinkedID(GameObject prefab)
        {
            foreach (InvItem item in KickStarter.inventoryManager.items)
            {
                if (item.linkedPrefab == prefab)
                {
                    return item.id;
                }
            }
            Debug.LogWarning("Not found");
            return -1;
        }
    

    Does the code above require a change in light of inventory updates in v1.72?

    My other thought is perhaps the name of the prefab at runtime is causing problems? When the prefab is instantiated in my game it appears in the Hierarchy with a (Clone) suffix as

    However the setup in the inventory manager is

  • The "prefab" parameter in the GetLinkedID function needs to be the original prefab - not a scene instance of it, which Unity will treat as a separate object.

    If you want to compare a scene instance with the "Linked prefab", you'll need to attach something else to compare them with. The Constant ID component, with Retain in prefab?, would be ideal - as you can then just compare ID values between both, i.e.:

    public int GetLinkedID (GameObject sceneInstance)
    {
        int sceneInstanceID = sceneInstance.GetComponent <ConstantID>().constantID;
        foreach (InvItem item in KickStarter.inventoryManager.items)
        {
            if (item.linkedPrefab == null) return;
    
            int prefabID = item.linkedPrefab.GetComponent <ConstantID>().constantID;
            if (prefabID == sceneInstanceID)
            {
                return item.id;
            }
        }
        Debug.LogWarning("Not found");
        return -1;
    }
    
  • edited November 2020

    Thanks @ChrisIceBox. Thinking about this, it's insane to be doing a ForEach each time the prefab is instantiated (and that happens a lot in my game) - in that case just manually setting the ID value on the original prefab, which is what happens currently, would be more performant.

    However, I like the code idea to diminish the risk of setup error. Is there a way in Unity to have it run such code before runtime so the values are all set on the original prefab before hitting play?

  • edited November 2020

    I mean, all you really need is a component with a public "ItemID" integer variable in it, that you can use to record the ID - even manually, if necessary.

    To do this automatically and outside of Play Mode, you can write a function to set this value, and precede the function with ContextMenu, i.e.:

    [ContextMenu ("Set ID")]
    void SetOwnIDValue () { /*...*/ }
    

    That'll then allow you to trigger the function from a menu via the component's "Cog" menu in its Inspector.

  • Sorry I didn't mean your solution was insane, just the way I was thinking / currently trying to use it.

  • Oh that [ContextMenu] is very cool. I've never dabbled with that before.

  • It works!

    Here's my setup:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using AC;
    
    public class PlayerThrowableItem : MonoBehaviour
    {
        public int inventoryID; //THIS MUST MATCH AC INVENTORY ID FOR THE ITEM OTHERWISE INCORRECT INTERACTIONS WILL BE TRIGGERED
        public GameObject owner;
        public bool isUsed = false;
    
        public int GetLinkedID(GameObject prefab)
        {
            foreach (InvItem item in KickStarter.inventoryManager.items)
            {
                if (item.linkedPrefab == prefab)
                {
                    return item.id;
                }
            }
            Debug.LogWarning("Not found");
            return -1;
        }
    
        [ContextMenu("Set ID")]
        void SetOwnIDValue()
        {
            print("ID set");
            inventoryID = GetLinkedID(gameObject);
        }
    }
    

    And it in action:

    Does that all look solid? Any improvements I'm missing?

  • You could mark the whole class with [ExecuteInEditMode], and then call the function from OnEnable, to have it run automatically when added.

    Since it'll also run when the game begins, do a check for the ID value (i.e. -1 or not) to prevent it from running again if it's already been set.

  • edited November 2020

    @ChrisIceBox Aww yeah, those sound good. Will look into those. Unity say that [ExecuteInEditMode] is being phased out because of prefab mode and that ExecuteAlways might be the ticket.

    Really appreciate you introducing me to some new Unity tricks!

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.