0
\$\begingroup\$

Let me explain a little about the pickup items and inventory to make this much clearer.

Every in world item that can be picked up has a ScriptableObject assigned to it that contains all the information about that item (id, name, description, maxstacksize, sprite etc).

When a player picks up an item it gets added to a List<InventoryItem>. InventoryItem is a class that gets populated with some of the data pulled from the ScriptableObject (id, name, description, maxstacksize), and also gets an amount property.

I want to save the players inventory, but want to simplify the InventoryItem data. So I created an InventoryItemSimple struct that holds the id and amount for each item in the inventory, and then save that list to file.

When loading the player inventory, currently I have a BIG list of ScriptableObjects that map to the id. So I am looping over the saved inventory list and matching against the id in the lookup table, and then adding the item to the inventory. I want to avoid this as over time their could be 2,000+ unique objects that could be in the world.

What's a better method to handle this?

If I stick with the lookup table, do I need to worry about how much memory is being used? I don't think my lookup table will ever contain 2,000+ elements. But the thought of having one massive list to manage doesn't appeal to me.

\$\endgroup\$
  • 2
    \$\begingroup\$ A 2000-entry lookup table really doesn't sound so bad. Modern devices can chew through this no problem. Maybe it's the management side you need help with though? It should be possible to automate building the table of IDs so you don't need to maintain this manually. \$\endgroup\$ – DMGregory Mar 15 at 13:22
  • \$\begingroup\$ @DMGregory Yeah, I was kinda worried about building the table more than the size, I should have been clearer on that. I do wonder what the memory footprint would be though. Should I edit my question to look for a solution to automate it? I assume this would be an editor script of some kind? \$\endgroup\$ – JacketPotatoeFan Mar 15 at 13:38
  • 1
    \$\begingroup\$ If you have integer IDs paired to ScriptableObject references, that's probably no more than 12 bytes per entry, so under 24 kiB for 2000 of them. Add ~50% overhead if you're using a Dictionary and it would still all fit in L1 cache. That's honestly not enough memory to even worry about in most circumstances — especially if it makes your item serialization simple, robust, and scalable. \$\endgroup\$ – DMGregory Mar 15 at 13:44
2
\$\begingroup\$

I think you're trying to prematurely optimise this. There isn't a problem, and you should wait until there is a problem to deal with this.

Ultimately, you have to load all of these items into the inventory. You can either do this from memory, or from a db, or from a text file or whatever - with the associated speed/costs.

Alternatively, you could just hold the IDs of the items in the inventory, and then load the individual items as needed (i.e. "lazy loading") - but this doesn't sound like a particularly good fit for your scenario?

Basically you're doing a unique key based lookup, which is generally pretty fast. You could spread your items into lists by type (search by Id and Type) but this is only really necessary when you have a lot more items.

For now, it sounds like you can leave it alone unless you actually observe it causing a problem.

\$\endgroup\$
  • \$\begingroup\$ I totally agree on the premature optimizing of it. I have a habit of doing that. So really I just need a more automated way of building the lookup table so it becomes less manual, as I am adding new items all the time. \$\endgroup\$ – JacketPotatoeFan Mar 15 at 13:42
  • \$\begingroup\$ Glad to help, don't worry, having in mind an optimisation path is a REALLY GOOD programming habit - the key is deciding when to implement it :) \$\endgroup\$ – Phil S Mar 15 at 13:55
0
\$\begingroup\$

For saving scriptable objects this is the only real solution since unity doesn't save a reference, but instead just saves the values, then loads a new object of the scriptable object type with those values when your project loads. This means you need some way of equality that's not a reference to determine which object you had, is which scriptable object instance in this particular run. Thus your system of a table of IDs works.

Some advice for this method from experience:

  • GetHashCode() is not constant between runs. This means you can lose save data if you're using a hash based lookup. In my case I implemented a custom hash function I googled somewhere else.
  • Use AssetDatabase API to automatically build this table upon play in edit mode, and upon building. There's other unity APIs for extending the build pipeline, and you can use Awake with a script execution order to ensure the table is built on play. Or if you want to be explicit, add an editor script that gives you a button to rebuild the table.
  • Wrap the ScriptableObject as something like PersistentScriptableObject. In this class write a custom editor with OnEnable that uses AssetDatabase.TryGetGUIDAndLocalFileIdentifier() to store the GUID in a private variable. Use this as your key. This allows you to rename the asset, or basically do w/e you want with it, without the key changing. So if you change any properties between patches in your game, this will remain the same until you delete the asset. You can use this base class as a way to automate saving an object.
  • You can implement the ISerializationCallbackReceiver interface from unity, and have it automatically save and load itself from the table. No need for custom loading code on everything that stores it.
\$\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.