Import from CSV file?

hanguang

New member
Hi,
Because the document is tooooo long, so while I'm reading it, I want to ask you guys directly.
With Definition and Category that are predefined in the database, is it possible that I can
construct an item at runtime that does not exist in the database.
If yes, how do I save it?

I'm currently using another inventory system (InventoryEngine).
I already have a CSV file, when import to Unity my script will convert it to InventoryItem.
How do I migrate them to UIS?
Or does UIS support creating items from a CSV file?
If yes, what are the best practices?

1609161363013.png

1609161373570.png

1609161383538.png

Guang
 
Currently UIS does NOT support imports or exports of item categories/definitions within a database.

You will need to create your items again from scratch using the UIS Editor Manager.

We are still looking into a good solution to import import/export items from/to a csv or json file. Due to the nature of Item Definitions inheriting attribute from Item Categories it makes things not so trivial. Adding this feature is in our TODO list but it is not one of the top priorities, so it may take a while before it is implemented.

You can create Items at runtime but only using an ItemDefinition within the database. These items can be saved using our save system which serializes the item attributes, ID and reference to its ItemDefinition.
 
I found a way to do it:
1.Create a Weapon category.
2.Create a Sword definition.
3.Put every attribute into runtime stats.

At runtime, create various Swords from CSV file (iron sword, wood sword, and so on).

@Sangemdoko
 
I got a problem:
The name of the item is the same as the ScriptableObject. Which is a problem for my solution.
I create items from the same definition with different runtime values include a name (string) attribute.
Could you please add a DisplayName feature for the item? Or show me how to do it.

@Sangemdoko
 
Last edited:
I'm surprised I didn't have a component for that before but I've just added this (it'll be part of the next update)

Code:
/// <summary>
/// Item View component displaying an attribute value.
/// </summary>
public class AttributeItemView : ItemViewModule
{
    [Tooltip("The attribute name. Must be an integer.")]
    [SerializeField] protected string m_AttributeName;
    [Tooltip("The attribute value text.")]
    [SerializeField] protected Text m_AttributeValueText;
    [Tooltip("Default text value")]
    [SerializeField] protected string m_DefaultTextValue;
    public string AttributeName {
        get => m_AttributeName;
        set => m_AttributeName = value;
    }
    /// <summary>
    /// Set the value.
    /// </summary>
    /// <param name="info">The item info.</param>
    public override void SetValue(ItemInfo info)
    {
        var attribute = info.Item.GetAttribute(m_AttributeName);
        if(attribute == null){ return; }
        m_AttributeValueText.text = attribute.GetValueAsObject()?.ToString();
    }
    /// <summary>
    /// Clear the value.
    /// </summary>
    public override void Clear()
    {
        m_AttributeValueText.text = m_DefaultTextValue;
    }
}

This Item View will show the value of an attribute as text, in your case the name.

If you were using AttributeViews instead of Item Views you could have used the existing "ValueAttributeView".

If you aren't familiar with Item Views and attribute views check this video tutorial:
 
You can use an Inventory component or a Item Object to serialize an Item in the editor.
These will then be created as soon as the game start.

It's not possible to create Items (and register them) at editor time.
I believe you can create items without registering them, and then register them once the game starts. You'll need to do some reflection since some things are set protected specifically to prevent people from creating items without registering them.

You are doing things completely differently to everyone else and we didn't design UIS to go that way. Making the change to allow Editor Items will cause more harm than good for the majority of people in my opinion.

The only thing that comes up to mind that could actually work is creating a new class that inherits Item and use that to create items in the editor. You'll then have access to pretty much everything since they are protected and not private. So you'll be able to create and initialize those items however you like.

Note that I would advise against it, but it is your choice.
 
@Sangemdoko
Hi, I'm still working on my CSV import stuff, I'm almost done. When I figure it out, I'll post the whole solution in the thread.

For now, I'm encountering another problem:
I created a subclass named ModernItem, it has a static method to create ModernItem type of Item.
I did it for 2 reasons:
0. The ModernItem is created from a CSV file at runtime, then it is stored in a ScriptableObject.
1. I don't want to mess with the Item class (which is part of the framework).
2. I need the subclass type to distinguish it from other Items (e.g: BookItem, FoodItem).

But when I tried to call InventorySystemManager.CreateItem for one of stored ModernItem, it actually creates an Item class.
As you can see, the method only return Item type, how do I make it generic (to return subclass type)?
I really don't want to mess with the InventoryManager class (or related) unless there's no other way.

Below is the code of ModernItem class.
public class ModernItem : Item {
public static T Create<T>(string type) where T : ModernItem, new() {
var itemDefinition = InventorySystemManager.GetItemDefinition(type);

if (itemDefinition == null) {
Debug.LogWarning("Cannot create Item with null Item Definition.");
return null;
}

var manager = itemDefinition.Manager;

//If the category is immutable check if item alreadyExists in Inventory System Manager.
if (itemDefinition.IsMutable == false && itemDefinition.IsUnique == false && manager != null) {
var registeredItem = manager.Register.ItemRegister.FindItemWithOverrides(itemDefinition, null);
if (registeredItem != null) { return registeredItem as T; }
}

//Construct the new Item.
var createdItem = new T();
createdItem.m_ItemDefinition = itemDefinition;
createdItem.m_ItemDefinitionID = itemDefinition?.ID ?? 0;
createdItem.m_Name = itemDefinition?.name ?? "NULL";

//Initialize does not register because register may need to replace this item by an existing equivalent one if the item is immutable.
createdItem.Initialize(true);

//Register (item can be replaced by an existing registered item).
if (InterfaceUtility.IsNotNull(manager)) {
var item = createdItem as Item;
manager.Register.ItemRegister.Register(ref item);
}

return createdItem;
}

public string DisplayName;

public Attribute<T> GetAttr<T>(string name) {
var attr = GetAttribute<Attribute<T>>(name);
return attr;
}

public T TryGetAttr<T>(string attr) {
if (TryGetAttributeValue(attr, out T value)) {
return value;
}
return default(T);
}

public override void Initialize(bool force, bool updateAttributes = true) {
if (m_ItemObjects == null) {
m_ItemObjects = new ResizableArray<ItemObject>();
}
base.Initialize(force, updateAttributes);
}
}
 
Another issue:
Inventory.HasItem is not working for me, because my item is actually from the same definition but with different values.
How do I make it work?
Use foreach on the specific collection myself?
 
I'm afraid you are using UIS in a way it wasn't designed for you might encounter more issues like this one...

I would recommend you try a different approach, perhaps instead of creating Items from the csv, you could create Item Definitions. And then create Items from those... this might be a lot of work though.

You could create a custom ItemCollection which is more suited to your project. If you do so you can override the GetItemAmount function and maybe others.

If you were able to create custom Items with the ModernItem class, perhaps you can also override the IsSimilar function.

...I'm sorry I can't help you more than that
 
Actually, I AM creating Item from Item Definition, but the values are from a CSV file. That's it!
Say I have a sword definition, and I have 1,000 swords with different preset values.
The only way I can manage that is to create it at runtime and read values from a table (or anything that can hold a table of values).

The difference is I store the runtime swords in a ScriptableObject for my own convenience.
And you telling me I'm using UIS in a way it wasn't designed?

The UIS is great, please do not limit it. Currently, it has its weakness that is the lack of managing a large number of items.
With the solution I purposed, I think at least it's manageable.
Please work with me but against me. Maybe you can think of a different way to solve the problem.
 
Sorry I think I misunderstood what you were doing.
I'm glad you solved the create item of custom type issue.

The HasItem function checks if you have an item within your inventory. It checks for Similar items not items that are value equivalent. This is an issue when checking for mutable and common items. You may or may not want to check for items that are similar.

So thanks to your feedback I overloaded the function such that you may choose whether you wish to check by similarity or by value equivalence.

In the ItemCollection class change the following functions:

Code:
/// <summary>
/// Get the amount of item that is part of the itemCollection.
/// </summary>
/// <param name="item">The item to look for in the collection.</param>
/// <param name="similarItem">Find an itemInfo with that value equivalent item or just one similar?</param>
/// <returns>The amount of that item present in the collection.</returns>
public virtual int GetItemAmount(Item item, bool similarItem = true)
{
    if (item == null) { return 0; }
    var count = 0;
    for (int i = 0; i < m_ItemStacks.Count; i++) {
        if (similarItem) {
            if (m_ItemStacks[i].Item.SimilarTo(item)) {
                count += m_ItemStacks[i].Amount;
            }
        } else {
            if (m_ItemStacks[i].Item.ValueEquivalentTo(item)) {
                count += m_ItemStacks[i].Amount;
            }
        }
    }
    return count;
}

/// <summary>
/// Determines if the Item Collection contains the item.
/// </summary>
/// <param name="item">The item to check.</param>
/// <param name="similarItem">Find an itemInfo with that value equivalent item or just one similar?</param>
/// <returns>Returns true if the amount of items in the collection is equal or bigger than the amount specified.</returns>
public virtual bool HasItem(Item item, bool similarItem = true)
{
    if (item == null) { return false; }
    return GetItemAmount(item,similarItem) >= 1;
}
/// <summary>
/// Determines if the Item Collection contains the item.
/// </summary>
/// <param name="itemAmount">The item to check.</param>
/// <param name="similarItem">Find an itemInfo with that value equivalent item or just one similar?</param>
/// <returns>Returns true if the amount of items in the collection is equal or bigger than the amount specified.</returns>
public virtual bool HasItem(ItemAmount itemAmount, bool similarItem = true)
{
    if (itemAmount.Item == null) { return false; }
    return GetItemAmount(itemAmount.Item,similarItem) >= itemAmount.Amount;
}
/// <summary>
/// Determines if the Item Collection contains the item.
/// </summary>
/// <param name="itemInfo">The item to check.</param>
/// <param name="similarItem">Find an itemInfo with that value equivalent item or just one similar?</param>
/// <returns>Returns true if the amount of items in the collection is equal or bigger than the amount specified.</returns>
public virtual bool HasItem(ItemInfo itemInfo, bool similarItem = true)
{
    if (itemInfo.Item == null) { return false; }
    return GetItemAmount(itemInfo.Item,similarItem) >= itemInfo.Amount;
}

in the Inventory class you can replace those functions


Code:
/// <summary>
/// Determines if the Item Collection contains the item.
/// </summary>
/// <param name="item">The item to check.</param>
/// <param name="similarItem">Find an itemInfo with that value equivalent item or just one similar?</param>
/// <returns>Returns true if the amount of items in the collection is equal or bigger than the amount specified.</returns>
public virtual bool HasItem(Item item, bool similarItem = true)
{
    if (item == null) { return false; }
    return GetItemAmount(item, similarItem) >= 1;
}
/// <summary>
/// Determines if the Item Collection contains the item.
/// </summary>
/// <param name="itemAmount">The item to check.</param>
/// <param name="similarItem">Find an itemInfo with that value equivalent item or just one similar?</param>
/// <returns>Returns true if the amount of items in the collection is equal or bigger than the amount specified.</returns>
public virtual bool HasItem(ItemAmount itemAmount, bool similarItem = true)
{
    if (itemAmount.Item == null) { return false; }
    return GetItemAmount(itemAmount.Item, similarItem) >= itemAmount.Amount;
}
/// <summary>
/// Check if the inventory has at least the item amount specified.
/// </summary>
/// <param name="itemInfo">The item info to check.</param>
/// <param name="similarItem">Find an itemInfo with that value equivalent item or just one similar?</param>
/// <returns>True if the inventory has at least that amount.</returns>
public virtual bool HasItem(ItemInfo itemInfo, bool similarItem = true)
{
    if (itemInfo.Item == null) { return true; }
    return GetItemAmount(itemInfo.Item, similarItem) >= itemInfo.Amount;
}

/// <summary>
/// Return the amount of item in the inventory.
/// </summary>
/// <param name="item">The item to check.</param>
/// <param name="similarItem">Find an itemInfo with that value equivalent item or just one similar?</param>
/// <returns>The amount of that item in the inventory.</returns>
public virtual int GetItemAmount(Item item, bool similarItem=true)
{
    var amount = 0;
    for (int i = 0; i < m_ItemCollections.Count; i++) {
        if (IgnoreCollection(m_ItemCollections[i])) { continue; }
        amount += m_ItemCollections[i].GetItemAmount(item, similarItem);
    }
    return amount;
}

Once you make the change you'll be able to use
inventory.HasItem(item, false);
And this will tell if you have an item that is value equivalent and not just similar.

Items that mutable but common are considered similar.

I hope this helps, the changes pointed out above will be part of the next update, and again I'm sorry about the misunderstanding
 
Hanguang, did you ever get this working? I would be interested in seeing what you have so far, as I was thinking of attempting the same myself.
 
Top