#So rebuilding the dictionary in Start

1 messages · Page 1 of 1 (latest)

grim jetty
#

Remove static from everything, and make your ItemDatabase inherit MonoBehavior

#

Then drag it in the scene

#

Only classes inheriting UnityEngine.Object can have serialized values

#

so either a MonoBehavior or a ScriptableObject

odd glen
#

and Dictionary can't be serialized anyway

grim jetty
#

(which is incredibly annoying and I can't believe it still can't be done)

odd glen
#

so yes you'd have to build it, or use SerializedDictionary which is an extension someone suggested me. Havent tried yet tho

buoyant solar
#

Well, my intention was to create this ItemDatabase as a static class that could be accessed from anywhere easily. I just would like a dictionary to look up items from a string.

#

I guess I'm going about doing this the wrong way.

grim jetty
#

You cannot serialize a static instance, it must inherit UnityEngine.Object

#

So start by deciding if you want your database to live in the hierarchy or the project

buoyant solar
#

I want it to live in the project.

grim jetty
#

Then change it to public class ItemDatabase : ScriptableObject

#

add [CreateMenuItem(menuName = "ItemDatabase")] above it

#

Then you will get a new editor option to create an ItemDatabase instance

#

(that lives in your project, and can have serialized state)

buoyant solar
#

Right, I'm familiar with the basics of scriptable objects. Making a scriptable object that is static like that will work? and then just Itemdatabase.itemDictionary will work how I'm expecting it to?

grim jetty
#

No, it cannot be static, that was my mistake

buoyant solar
#

Sorry I'm not the greatest at all of this, I really appreciate the help.

grim jetty
#

You will need to write some code to fetch an instance of your scriptable object. The legacy approach is using Resources.Load, the newer one is to use Addressables

#

You can start with Resources.Load for prototyping, it's easier to set up

#

This will return the serialized instance of your ItemDatabase asset

#

Which you can then read at runtime

buoyant solar
#

Well, I already have a GameManager object in my hierarchy, I could probably just drop a reference to the SO in that and call GameManager.ItemDatabase for a simple method couldn't i?

grim jetty
#

That's fine too

#

As long as your GameManager is an actual game object and not also static

buoyant solar
#

It's singleton. That isn't an issue is it? It's a pattern I followed from a video about having a singleton GameManager that instantiates prefabs of other non singleton managers as children and has public references to them.

grim jetty
#

That's fine

buoyant solar
#

I will do. As you can probably tell there are some gaps in my understanding of serialization in Unity, among other things.

grim jetty
odd glen
grim jetty
#

Serialization especially is a tricky topic in unity

grim jetty
buoyant solar
# odd glen some people like to hate on Singletons. But for these use cases they are awesome

Yeah, I've seen a lot of people talk about singletons, but I watched a youtube video (https://www.youtube.com/watch?v=tcatvGLvCDc&ab_channel=ThousandAnt) linked in an article about this method and it seemed really awesome. It's very modular as well, if you set it up right, where you can just instantiate the systems you need to work with.

We take a look at how Sam set up his Master Singleton in his game Zarvot, and many common problems and considerations taken, as well as the advantages and disadvantages of his “Master Singleton” structure.

Singletons are very useful and can be very dangerous. Hopefully this video sheds some light on how Sam did it for his game.

If you’d like t...

▶ Play video
#

Anyway, I appreciate the help from both of you. Thanks again!

grim jetty
#

Also what the video describes is not actually the singleton pattern

#

😅

buoyant solar
#

Well, it uses a singleton. But its purpose is just to allow other gameobjects it holds references to to reference each other.

grim jetty
#

Yes, but that pattern is called the service locator pattern, not singleton

#

The actual services in this case are singletons

buoyant solar
#

Ah ok. I didn't recall the name of the pattern.

#

I do recall that name from the article I read that mentioned it, though. It seems like a good pattern for something like an overall game manager to me, though.

grim jetty
#

That enables you to pass separate ItemDatabase to different instance of objects, which may even make so you don't need a "global" item database

#

You could instead pass a direct Item instead, if a specific item is needed by an instance, or a DropTableList, which contains items, but holds different information, etc

buoyant solar
grim jetty
#

So you want to initialize it with some values and then modify that at runtime?

buoyant solar
odd glen
#

oh, don't use ScriptableObject if you want to edit the data

#

when you build the game, it won't save anything

#

even tho it does in editor

buoyant solar
#

Right, that's what I was thinking.

grim jetty
#

e.g. a player

buoyant solar
#

The main idea behind my system was that it works like this: In the editor I create a scriptable object version of the editor and add it to the ItemDatabase, the ItemDatabase then builds an "Item" from the scriptable object that is actually used by the game with a unique item ID. I then pass it an ItemID when I need to know something about an item.

#

So it's like a global item database of all the items in the game.

grim jetty
#

Those items contains some information about them though right? For example, how much the item costs

buoyant solar
#

Correct. But the inventory of a character would only need to know the ItemID.

grim jetty
#

I still don't see why you need to change any data on the ItemDatabase

#

It just holds references to all items

buoyant solar
#

Because I want the player to be able to create items during gameplay.

grim jetty
#

You mean a concrete instance of an item, for example, so that the item can take damage

buoyant solar
#

Well, I mean I want to add the item to the item database so that all I need to store in their inventory is its ID.

grim jetty
#

Why not just store the item on the actor

#

Instead of an ID

buoyant solar
#

I guess it seemed like it would be better for when I needed to save the inventories if they've been modified. Just saving a array of IDs vs all of the data on the item.

grim jetty
#

I mean I assume the item would store the item ID

buoyant solar
#

Well, if the inventory contains the actual item, then there's not much of a need for it to have an ID.

grim jetty
#

Sure, for saving 🙂

#

Saving is an entirely different beast, and there is no easy answer to it, it heavily depends on the project

#

I'll write you a small code sample as an example of what I would do to achieve something like you mentioned. To go back to what you asked earlier, you can store runtime data on a scriptable object, but it won't be serialized

#

(and I would recommend not making it serialized, and I would also recommend not storing runtime data on a scriptable object at all)

buoyant solar
#

Well, I have Easy Save 3, which based on my testing works ok for saving things like how I've structured my inventory system. I just wanted to create a database that would let me get a reference to my items when I need to so I could just replace them with their ID in the inventory and look them up when needed.

#

Could I just save the runtime changes to a scriptable object with Easy Save 3 and load those changes when needed?

grim jetty
#

No, as the scriptable object is not something that is saved at runtime

#

You will need to save your save game to a file

#

The main use of scriptable objects is authoring time data

buoyant solar
#

Well, that's what I mean. Easy Save 3 can write a dictionary out to a file and load it back from that file. Could I just save and load runtime changes to the dictionary on the scriptable object with that?

grim jetty
#

Sure, but I wouldn't recommend it

#

I would instead store this runtime data on something that lives in your scene, e.g. a game object, or ideally, on the actor that owns the item

buoyant solar
#

Or I guess at this point I understand what I need to do. I think I'll just create an ItemDatabaseManager object with a script that holds a DefaultItemDatabase scriptable object it will copy data from when a new game is started. Then it will have a bool itemDatabaseHasBeenModifies and when a game is loaded it if that bool is true it will load the dictionary in from a file.

grim jetty
#

Just to illustrate the use case for scriptable objects, this is roughly of how I would implement something like this:

#
public class ItemSettings : ScriptableObject
{
  public int Cost;

  public Item Create()
  {
    return new Item(); //set stuff here from settings
  }
}

//This is the thing getting saved
public class Item
{
}
#

Your item database would hold all ItemSettings, and let you create new items, and Item holds instance data (e.g. damage taken) for an instance of an item

buoyant solar
#
public class WeaponItemSO : EquippableItemSO
{
    public WeaponType weaponType;
    public float attackPower;
    private void Awake()
    {
        itemType = ItemType.Weapon;
    }
    public override void BuildItem()
    {
        item = new WeaponItemData
        {
            name = name,
            itemID = itemID,
            useable = useable,
            itemType = itemType,
            itemMaterial = itemMaterial,
            weaponType = weaponType,
            attackPower = attackPower,
            useResource = useResource,
            onUseResourceDecrease = onUseResourceDecrease,
            destroyOnResourceDepleted = destroyOnResourceDepleted,
            replaceOnResourceDepleted = replaceOnResourceDepleted,
            replacementItemID = replacementItemID
        };
    }
}```
#

I'm doing something very similar already in using scriptable objects to create items.

grim jetty
#

yep, that looks good, but I wouldn't store the instances of WeaponItemData in the ItemDatabase

buoyant solar
#

Well, my idea was that everything about the item should be in the database, because I really only need to know that information if a character equips an item or if i need to show it to the player.

#

That was my thought process at least.

#

So I figured inventoryslots could just contain the ItemID and the amount of the item in the slot. Then if a character equips an item or something I can use the ItemID to see how their stats need to change, for example.

grim jetty
#

I understand the thought process, there is just no advantage to doing it this way that I can see. If you want to save your game, you need to save your actors anyways since they have the item id.

grim jetty
buoyant solar
#

But then when I save an inventory, I would have all the extra data like the stats of the item being saved for every inventory, right?

grim jetty
#

No, because all immutable data is stored in ItemSettings, not in Item. Whether or not that data is immutable depends on your game

#

For example, if Damage is immutable, you would read it as myItem.ItemSettings.Damage instead of myItem.Damage

#

All instances of Item share the same reference to the ItemSettings object that created it

#

When serializing your game state to a save file, all Item instances store the id of the ItemSettings that created it, so they can find the scriptable object that contains those immutable values at runtime

buoyant solar
#

But if an item is created at runtime, it wouldn't have an associated scriptableobject, so all of the data for items has to be stored in the database.

grim jetty
#

Why does it not have an associated scriptable object?

#

You are creating the item from the scriptable object at runtime

#

public class ItemSettings : ScriptableObject
{
  public Item Create()
  {
    return new Item() { ItemSettings = this };
  }
}

public class Item
{
  public ItemSettings Settings;
}

#

Then you could for example have an enemy that drops an item on death:


public class Enemy : MonoBehavior
{
  public ItemSettings ItemToDropOnDeath;

  public void OnDeath()
  {
    ItemSettings.Create().Spawn(transform.position);
  }
}

buoyant solar
#

I'm sorry I'm having a little trouble articulating what I'm not understanding, I guess.

#

What I was trying to say is if "Damage" for example is stored on the scriptable object then if I wanted a new item at runtime with a different Damage value, I would use the scriptable object to make an Item and then change its damage value?

grim jetty
#

Why are you deciding the damage at runtime, what value do you want to set here?

buoyant solar
#

Well, to have a specific example, imagine the item in question is a sword. I want the player to be able to make a sword with stats they have picked while playing the game.

grim jetty
#

Is there any authoring time data that decides this damage value?

#

In this example I would assume it depends on the stats chosen, not on the item at all

buoyant solar
#

Well, there will be formulas to determine ranged of inputs eventually but at the moment I just wanted to input numbers through UI.

#

ranges*

#

I was aiming for the time being to make it capable of relatively arbitrary item generation. Like create a sword with any damage value I want, for example.

grim jetty
#

This is entirely up to you, and is extremely game specific.
For example, you could have a base damage value, and then add a random multiplier to generate "procedural" weapons:

public class ItemSettings : ScriptableObject
{
  public float BaseDamage;

  public Item Create()
  {
    return new Item() { ItemSettings = this, Damage = BaseDamage * Random.Range(0.5f, 1.5f) };
  }
}

public class Item
{
  public ItemSettings Settings;
  public float Damage;
}
#

Or you could make the damage not be an authoring time value at all:

public class ItemSettings : ScriptableObject
{
  public Item Create(float damage)
  {
    return new Item() { ItemSettings = this, Damage = damage };
  }
}

public class Item
{
  public ItemSettings Settings;
  public float Damage;
}
#

The scriptable object holds all the shared and authoring time data required to create the concrete instance

#

If you don't have any authoring time data required to create your item, then you don't need a scriptable object for it

#

At then end of the day they are just an authoring time data storage mechanism, nothing more

buoyant solar
#

Right, my plan was to use them to create all of the items that would be in the game when it is new, but allow the player to modify them in various ways while playing and for modified items to be able to be given to NPCs and such. Pretty standard stuff and this seems like a really obvious use case for scriptable objects.

#

Well, modify instances of items, i mean, not the base version of the item.

grim jetty
#

But how are you creating all the items that will be in the game at the start of the game, that is the definition of authoring data

buoyant solar
#

I'm creating them from the scriptable objects.

grim jetty
#

All of them at once?

buoyant solar
#

What do you mean?

grim jetty
#

create all of the items that would be in the game when it is new

#

I would assume you create the exact amount of items you need at the time

#

For example, if there are 2 entities with 2 weapons each, there would be 4 Item instances

#

Even if you have 500 different ItemSettings instances

#

For example, if you spawn an enemy

public class Enemy : MonoBehavior
{
  public ItemSettings WeaponToEquipOnSpawning;

  public Item EquippedWeapon;

  void Start()
  {
    EquippedWeapon = WeaponToEquipOnSpawning.Create();
  }
}
#

Coming back to your question earlier, you can modify the created instance of Item, but you shouldn't modify the shared instance ItemSettings

#

so you could do EquippedWeapon.Damage = 500;

#

The easiest analogy I can give is that ItemSettings represent the uniquely authored weapons in your game, so you could have 500 different weapons. Then you can create an infinite number of instances of these unique designs at runtime, modifying whatever data you need.

#

What parts of your data are on ItemSettings and what are on Item is not something I can tell you, that's part of your game design

buoyant solar
#

Right, I think this is more or less what I'm trying to do. I think based on everything you've told me I'll be able to get the behavior I want.

grim jetty
#

At the end of the day I'm just telling you how I would do this, you are free to implement it however you want. One thing I would recommend to you though is that you do not modify a scriptable object's data at runtime, it's just not what they are for

buoyant solar
#

Right, that was my understanding. They are intended for authoring data in the editor only.

grim jetty
#

I'm off to bed then

buoyant solar
#

Have a nice night. Thanks once again for all of the help!

grim jetty
#

No worries, I hope I didn't confuse you too much, these aren't easy concepts to explain, especially if you are relatively new to unity