0
\$\begingroup\$

As the title states, I am getting this error and I cannot figure out why. I have tried Google and I couldn't find a precise answer as to how to fix it.

Error:

Assets\Ultimate Survival\Scripts\By Namespace\UltimateSurvival\Inventory\InventoryController.cs(189,32): error CS0029: Cannot implicitly convert type 'UltimateSurvival.ItemProperty.Value' to 'UnityEngine.GameObject'

Code:

public bool Try_DropItem(SavableItem item, Slot parentSlot = null)
{
    if(item && item.ItemData.WorldObject)
    {
        var cameraTransform = GameController.WorldCamera.transform;

        GameObject w_Object = item.ItemData.WorldObject;

        if (item.ItemData.IsBuildable)
        {
            w_Object = item.GetPropertyValue("Bag");
        }

        GameObject droppedItem = Instantiate(w_Object, cameraTransform.position + cameraTransform.TransformVector(m_DropOffset), Random.rotation) as GameObject;

        var rigidbody = droppedItem.GetComponent<Rigidbody>();
        if(rigidbody)
        {
            rigidbody.angularVelocity = Random.rotation.eulerAngles * m_DropAngularFactor;
            rigidbody.AddForce(cameraTransform.forward * m_DropSpeed, ForceMode.VelocityChange);

            Physics.IgnoreCollision(m_Player.GetComponent<Collider>(), droppedItem.GetComponent<Collider>());
        }

        var pickup = droppedItem.GetComponent<ItemPickup>();
        if(pickup)
            pickup.ItemToAdd = item;

        if(parentSlot)
            parentSlot.ItemHolder.SetItem(null);

        return true;

    }

    return false;
}

ItemProperty:

using System;
using System.Collections.Generic;
using UnityEngine;

namespace UltimateSurvival
{
[Serializable]
public class ItemCategory
{
    public string Name { get { return m_Name; } }

    public ItemData[] Items { get { return m_Items; } }

    [SerializeField]
    private string m_Name;

    [SerializeField]
    private ItemData[] m_Items;
}

/// <summary>
/// The data / definition for an item.
/// </summary>
[Serializable]
public class ItemData
{
    public string Name { get { return m_Name; } }

    public string DisplayName { get { return m_DisplayName; } }

    public int Id { get { return m_Id; } set { m_Id = value; } }

    public string Category { get { return m_Category; } set { m_Category = value; } }

    public Sprite Icon { get { return m_Icon; } }

    public GameObject WorldObject { get { return m_WorldObject; } }

    public string[] Descriptions { get { return m_Descriptions; } }

    public int StackSize { get { return m_StackSize; } }

    public List<ItemProperty.Value> PropertyValues { get { return m_PropertyValues; } }

    public bool IsBuildable { get { return m_IsBuildable; } }

    public bool IsCraftable { get { return m_IsCraftable; } }

    public Recipe Recipe { get { return m_Recipe; } }

    [SerializeField]
    private string m_Name;

    [SerializeField]
    private string m_DisplayName;

    [SerializeField]
    private int m_Id;

    [SerializeField]
    private string m_Category;

    [SerializeField]
    private Sprite m_Icon;

    [SerializeField]
    private GameObject m_WorldObject;

    [SerializeField]
    [Multiline]
    private string[] m_Descriptions;

    [SerializeField]
    private int m_StackSize = 1;

    [SerializeField]
    private List<ItemProperty.Value> m_PropertyValues;

    [SerializeField]
    private bool m_IsBuildable;

    [SerializeField]
    private bool m_IsCraftable;

    [SerializeField]
    private Recipe m_Recipe;
}

/// <summary>
/// A SavableItem is an instance of an item, which can have it's own properties, vs ItemData which is just the data for an item, just the definition.
/// </summary>
[Serializable]
public class SavableItem
{
    public Message<ItemProperty.Value> PropertyChanged = new Message<ItemProperty.Value>();

    public Message StackChanged = new Message();

    public bool Initialized { get; private set; }

    public ItemData ItemData { get; private set; }

    public int Id { get { return ItemData.Id; } }

    public string Name { get { return ItemData.Name; } }

    public int CurrentInStack { get { return m_CurrentInStack; } set { m_CurrentInStack = value; StackChanged.Send(); } }

    public List<ItemProperty.Value> CurrentPropertyValues { get { return m_CurrentPropertyValues; } }

    [SerializeField]
    private int m_CurrentInStack;

    [SerializeField]
    private List<ItemProperty.Value> m_CurrentPropertyValues;


    public static implicit operator bool(SavableItem item) { return item != null; }

    /// <summary>
    /// 
    /// </summary>
    public SavableItem(ItemData data, int currentInStack = 1, List<ItemProperty.Value> customPropertyValues = null)
    {
        CurrentInStack = Mathf.Clamp(currentInStack, 1, data.StackSize);

        if(customPropertyValues != null)
            m_CurrentPropertyValues = CloneProperties(customPropertyValues);
        else
            m_CurrentPropertyValues = CloneProperties(data.PropertyValues);

        ItemData = data;
        Initialized = true;

        for(int i = 0;i < m_CurrentPropertyValues.Count;i ++)
            m_CurrentPropertyValues[i].Changed.AddListener(On_PropertyChanged);
    }

    /// <summary>
    /// Must be called after the item was loaded / deserialized, (not required when the item is created at runtime, through the constructor).
    /// </summary>
    public void OnLoad(ItemDatabase itemDatabase)
    {
        if(itemDatabase)
        {
            ItemData data;
            if(itemDatabase.FindItemById(Id, out data))
            {
                ItemData = data;
                Initialized = true;

                for(int i = 0;i < m_CurrentPropertyValues.Count;i ++)
                    m_CurrentPropertyValues[i].Changed.AddListener(On_PropertyChanged);
            }
            else
                Debug.LogErrorFormat("[SavableItem] - This item couldn't be initialized and will not function properly. No item with the name {0} was found in the database!", Name);
        }
        else
            Debug.LogError("[SavableItem] - This item couldn't be initialized and will not function properly. The item database provided is null!");
    }

    public string GetDescription(int index)
    {
        string description = string.Empty;
        if(index > -1 && ItemData.Descriptions.Length > index)
        {
            try
            {
                description = string.Format(ItemData.Descriptions[index], m_CurrentPropertyValues.ToArray());
            }
            catch
            {
                Debug.LogError("[SavableItem] - You tried to access a property through the item description, but the property doesn't exist. The item name is: " + Name);
            }
        }

        return description;
    }

    public bool HasProperty(string name)
    {
        if(!Initialized)
        {
            Debug.LogError("[SavableItem] - This SavableItem is not initialized, probably it was loaded and not initialized! (call OnLoad() after loading / deserializing).");
            return false;
        }

        for(int i = 0;i < m_CurrentPropertyValues.Count;i ++)
            if(m_CurrentPropertyValues[i].Name == name)
                return true;

        return false;
    }

    /// <summary>
    /// Use this if you are sure the item has this property.
    /// </summary>
    public ItemProperty.Value GetPropertyValue(string name)
    {
        ItemProperty.Value propertyValue = null;

        if(!Initialized)
        {
            Debug.LogError("[SavableItem] - This SavableItem is not initialized, probably it was loaded and not initialized! (call OnLoad() after loading / deserializing).");
            return null;
        }

        for(int i = 0;i < m_CurrentPropertyValues.Count;i ++)
            if(m_CurrentPropertyValues[i].Name == name)
            {
                propertyValue = m_CurrentPropertyValues[i];
                break;
            }

        return propertyValue;
    }

    /// <summary>
    /// Use this if you are NOT sure the item has this property.
    /// </summary>
    public bool FindPropertyValue(string name, out ItemProperty.Value propertyValue)
    {
        propertyValue = null;

        if(!Initialized)
        {
            Debug.LogError("[SavableItem] - This SavableItem is not initialized, probably it was loaded and not initialized! (call OnLoad() after loading / deserializing).");
            return false;
        }

        for(int i = 0;i < m_CurrentPropertyValues.Count;i ++)
            if(m_CurrentPropertyValues[i].Name == name)
            {
                propertyValue = m_CurrentPropertyValues[i];
                return true;
            }

        return false;
    }

    private List<ItemProperty.Value> CloneProperties(List<ItemProperty.Value> properties)
    {
        List<ItemProperty.Value> list = new List<ItemProperty.Value>();
        for(int i = 0;i < properties.Count;i ++)
            list.Add(properties[i].GetClone());

        return list;
    }

    private void On_PropertyChanged(ItemProperty.Value propertyValue)
    {
        PropertyChanged.Send(propertyValue);
    }
}

}

\$\endgroup\$
  • \$\begingroup\$ Looks like the problem is this line w_Object = item.GetPropertyValue("Bag");. w_Object wants a UnityEngine.GameObject, but GetPropertyValue is returning an UltimateSurvival.ItemProperty.Value instead. Can you show us what that type looks like, so we can recommend ways to fix this? \$\endgroup\$ – DMGregory Nov 27 at 19:51
  • \$\begingroup\$ the type UltimateSurvival.ItemProperty.Value is returning a string \$\endgroup\$ – rackemup420 Nov 27 at 19:52
  • \$\begingroup\$ Okay, and what's your plan for using that string information to select/produce a GameObject? It's a bit tough to know whether we should look it up in a map, or use Find to look for a scene object with that name, or construct a new GameObject using that string, etc. without understanding your application context. \$\endgroup\$ – DMGregory Nov 27 at 19:54
  • \$\begingroup\$ i want to produce a gameobject and the title of the prefab is stored in that UltimateSurvival.ItemProperty.Value, or instead of having it setup like that can i just reference a prefab in GameObject droppedItem = Instantiate(w_Object, cameraTransform.position + cameraTransform.TransformVector(m_DropOffset), Random.rotation) as GameObject; where instead of w_Object can i just reference a prefab name there? \$\endgroup\$ – rackemup420 Nov 27 at 19:56
0
\$\begingroup\$

Your problem is here:

w_Object = item.GetPropertyValue("Bag");

You've declared w_Object is a GameObject, but this function is returning an UltimateSurvival.ItemProperty.Value (which you say is effectively a string? We can't see that part in your question...)

Unity doesn't know how to convert that value into the GameObject you want to reference, so we have to tell it what we want it to do.

I want to produce a gameobject and the title of the prefab is stored in that UltimateSurvival.ItemProperty.Value

Here's one simple way to do it, where you populate a shortlist of prefabs in the Unity Inspector.

public List<GameObject> prefabs;

GameObject InstantiatePrefabByName(string name) {
    // Find a prefab in our list that has a name matching this string.
    var source = prefabs.Find(prefab => prefab.name == name);

    // If we didn't find a hit, throw an error that helps us diagnose the issue.
    if(source == null) {
        Debug.LogErrorFormat(
            "Tried to instantiate unknown prefab name, \"{0}\"", 
            name
        );
        // Return a dummy game object as the best we can do.
        return new GameObject(name + " (Missing)");
    }

    // Instantiate our prefab and return the instance.
    return Instantiate(source);
}

Then you can call this with something like...

// I assume you get your string value with ToString() - if not, swap this part.
string prefabName = item.GetPropertyValue("Bag").ToString();

// Now we call our prefab-finding-and-spawning function with this string.
w_Object = InstantiatePrefabByName(prefabName);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.