I'm writing save logic for an "inventory" component. This inventory holds any number of items and I'm trying to figure out how best to save/load them.
Essentially, I have an abstract base "Item" class, and every item is a subclass. So I might have "Battery", "Hammer", "Coin", etc.
In order to read correctly, I need to know the type. I've looked through the forums and found http://www.moodkie.com/forum/viewtopic. ... nent#p2968 - which would work for any custom type, not just components and is something I could use here.
Is that the recommended way to handle reading not-yet-known types?
I need to use this logic anyway because an item may have a variable list of components which need to be saved as well.
Custom classes and polymorphism
Re: Custom classes and polymorphism
Hi there,
A method which may be more applicable to your circumstance is described in the final post of this thread here: http://www.moodkie.com/forum/viewtopic. ... 956&p=2618
All the best,
Joel
A method which may be more applicable to your circumstance is described in the final post of this thread here: http://www.moodkie.com/forum/viewtopic. ... 956&p=2618
All the best,
Joel
Re: Custom classes and polymorphism
Unfortunately that's just not a feasible solution because eventually I'll have hundreds of items and some day would like to allow for mods to add custom items. Hard-coding every single one into the read method is going to get ugly fast.
Re: Custom classes and polymorphism
Easy Save 3 has the ability to handle polymorphism by default, but as it's currently in alpha we can't give a date as to when this would be available.
- Joel
- Joel
Re: Custom classes and polymorphism
I haven't tested this, pending fixing a type issue we're discussing in another thread, but what if I did this:
During write, I write the typeof to the file:
Then during read, I dynamically instantiate it:
I haven't tested this but should be close to what I think will work.
During write, I write the typeof to the file:
Code: Select all
writer.Write(data.GetType().ToString());
Code: Select all
var typeStr = reader.Read<string>();
var type = Type.GetType(typeStr);
if (type != null) {
data = (Item) Activator.CreateInstance(type);
}
Re: Custom classes and polymorphism
Yup, that works perfectly.
For anyone stumbling upon this thread in the future, here's my code:
For anyone stumbling upon this thread in the future, here's my code:
Code: Select all
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ES2UserType_Item : ES2Type {
public override void Write(object obj, ES2Writer writer) {
Item data = (Item)obj;
writer.Write(data.GetType().ToString());
writer.Write(data.quantity);
// Get all supported components
var supportedComponents = new List<Component>();
foreach(var component in data.gameObject.GetComponents<Component>()) {
if (ES2TypeManager.GetES2Type(component.GetType()) != null) {
supportedComponents.Add(component);
}
}
// Write count so we know how many to load
writer.Write(supportedComponents.Count);
// Save each component
foreach(var component in supportedComponents) {
var es2Type = ES2TypeManager.GetES2Type(component.GetType());
writer.Write(es2Type.hash);
writer.Write(component);
}
}
public override object Read(ES2Reader reader) {
Item data = null;
// Read back the actual item type
var typeStr = reader.Read<string>();
var type = Type.GetType(typeStr);
if (type != null) {
// Instantiate the item directly
data = (Item) Activator.CreateInstance(type);
// Set quantity
data.quantity = reader.Read<System.Int32>();
// How many components do we need to load?
int componentCount = reader.Read<int>();
// Restore components
for(int i = 0; i < componentCount; i++){
var es2Type = ES2TypeManager.GetES2Type(reader.Read<int>());
// Get component from GameObject, or add it if it doesn't have one.
Component component = data.gameObject.GetComponent(es2Type.type);
if (component == null) {
component = data.gameObject.AddComponent(es2Type.type);
}
reader.Read<System.Object>(es2Type, component);
}
}
// @todo log an error?
return data;
}
/* ! Don't modify anything below this line ! */
public ES2UserType_Item():base(typeof(Item)){}
}
Re: Custom classes and polymorphism
Glad that's working for you. Do be aware that there's a performance cost to Activator.CreateInstance if calling it regularly (around 11x slower than new).
All the best,
Joel
All the best,
Joel
Re: Custom classes and polymorphism
That's good to know. Functional saves/loads are my focus right now and I'm finally pretty close to having all that work done - just doing some cleanup, testing, etc.
Eventually I'll figure out how best to support mods. While hard-coding instance checks would be a pain for myself, since my game will likely have a hundred or more items, it will be impossible for modders who provide their own items. So I'll revisit how I handle this when I overhaul things to make way for mods.
I think in that case, a custom type or custom save logic will be essential. If that's the case though, I'll need to ensure those custom types are registered correctly with ES2 .
Eventually I'll figure out how best to support mods. While hard-coding instance checks would be a pain for myself, since my game will likely have a hundred or more items, it will be impossible for modders who provide their own items. So I'll revisit how I handle this when I overhaul things to make way for mods.
I think in that case, a custom type or custom save logic will be essential. If that's the case though, I'll need to ensure those custom types are registered correctly with ES2 .