Can we preload MonoBehaviours without a GameObject?

Discussion and help for Easy Save 3
Post Reply
Gladyon
Posts: 30
Joined: Thu Sep 07, 2017 6:51 am

Can we preload MonoBehaviours without a GameObject?

Post by Gladyon »

Here is my problem:
I'd like to load all the data of my game in the startup sequence, and then instantiate the GameObjects on demand when the game need them.

So, I would need to be able to load the MonoBehaviours, but not directly in a GameObject (as I have none when I load the data from the disk).
The idea would be to store them in strings (well, it wouldn't be ideal because of the memory required, but as I am on Windows I suppose it would work) or better, in a binary format.
And then, it would just be to deserialize the loaded data into actual GameObjects I create myself.
I'm thinking about methods like 'LoadIntoStorage<T>(String key, out String Storage)' and 'LoadFromStorage<T>(String Storage, T Obj)'.


I'm not sure if it's currently possible in ES3 (but I hope to be mistaken), that said, from what I saw in the code, it shouldn't be so complex to do.
So, if it isn't already possible, would it be possible to give me a clue or 2 about where to modify ES3 in order to include such a feature?


Note: I only need MonoBehaviour because I already have the other components taken care of in another way, but I'm sure that if something like that worked for MonoBehaviour it would work for any Unity component as well, which would make it an even better feature.
Last edited by Gladyon on Mon Apr 16, 2018 4:03 pm, edited 1 time in total.
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: Can we preload MonoBehaviours without a GameObject?

Post by Joel »

Hi there,

As I think you already know, it is not possible for a MonoBehaviour to exist without a GameObject to attach it to. This is a limitation of Unity rather than of Easy Save 3.

However, what you seem to be describing is caching the data in memory, which is the purpose of an ES3File: http://docs.moodkie.com/easy-save-3/es3 ... g-es3file/

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Gladyon
Posts: 30
Joined: Thu Sep 07, 2017 6:51 am

Re: Can we preload MonoBehaviours without a GameObject?

Post by Gladyon »

You are really fast to answer, that's impressive!


I was thinking about methods like 'LoadIntoStorage<T>(String key, out String Storage)' and 'LoadFromStorage<T>(String Storage, T Obj)'.
Of course binary storage would be a lot more interesting, but it would require ES3 to be able to save/load in binary format, which is quite a lot of work I think.

I will try ES3File caching, as I already uses ES3File that should be quite easy to implement.
The problem is that I will have to store all the files, and I have several hundreds of them...
I'm pretty sure I will end up with some trouble at the end with all these files.


Just for information, I store the data in my own structures in order to improve the performances, as I rebuild entire scenes from scratch at runtime (which is faster than loading a Unity scene by the way...), and I'm not sure ES3 is optimized enough for such a task (and in addition, I also have some sort of simplified structure as the files are meant to be modded directly).
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: Can we preload MonoBehaviours without a GameObject?

Post by Joel »

There's actually a feature request for binary formatting here which you can vote on, but it would indeed be quite a bit of work.

Easy Save 2 uses binary formatting, and the ES2Reader class also stores the data in memory. Reading sequentially from an ES2Reader is close to the fastest you can possibly read data from a file, as it is essentially loading the variables from the stream in sequence without random access.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Gladyon
Posts: 30
Joined: Thu Sep 07, 2017 6:51 am

Re: Can we preload MonoBehaviours without a GameObject?

Post by Gladyon »

Is it possible to load an array of MonoBehaviours into a GameObject?

It seems that I have to load the MonoBehaviours one by one, which would add useless complexity to the file.
Well, I had no success loading them one by one, it seems that the array wasn't the problem.

The problem is that I cannot instantiate a MonoBehaviour on a GameObject I have created myself.
It seems that ES3 creates itself a GameObject and adds the MonoBehaviour to it.


After a few hours I finally managed to hack my way into it:
- get the real type of the MonoBehaviour
- add the component to my own GameObject
- call ES3File.LoadInto(key, <TheAddedComponent>)

In order to get the real type of the Monobehaviour I had to create the following method in ES3:

Code: Select all

public Type GetRealType<T>(string key)
{
	ES3Data es3Data;

	if(!cache.TryGetValue(key, out es3Data))
		throw new KeyNotFoundException("Key \"" + key + "\" was not found in this ES3File. Impossible to get its type");

	var settings = (ES3Settings)this.settings.Clone();
	settings.encryptionType = ES3.EncryptionType.None;

	using(var ms = new System.IO.MemoryStream(es3Data.bytes, false))
    {
		using(var reader = ES3Reader.Create(ms, settings, false))
        {
            ES3Type Thetype = ES3TypeMgr.GetOrCreateES3Type(typeof(T));

		    if(Thetype == null)
			    throw new NotSupportedException("Type of "+typeof(T).Name+" is not currently supported, and could not be loaded using reflection.");
		    else if(Thetype.isPrimitive)
        		throw new Exception("I don't know how to get the real type");
		    else if(Thetype.isCollection)
			    throw new Exception("I don't know how to get the real type");
		    else if(Thetype.isDictionary)
			    throw new Exception("I don't know how to get the real type");

            if (reader.StartReadObject())
                return null;

			string propertyName = Thetype.ReadPropertyName(reader);
			if(propertyName == ES3Type.typeFieldName)
				return reader.ReadType();
			else if(propertyName == null)
				return null;
			else
                throw new Exception("I don't know what's happening here...");
        }
    }
}
Of course, it is not completely working as I ignored the cases where it is not a MonoBehaviour.
I really do think that having a 'GetRealType(string key)' method would be a good addition to ES3.
And I'm pretty sure that someone who knows ES3 code better than me can replace the exceptions I added with the right code.


Also, I found that while looking into the code:

Code: Select all

if(type == null)
	throw new NotSupportedException("Type of "+type.type.ToString()+" is not currently supported, and could not be loaded using reflection.");
Obviously that will throw, but not the intended exception.

That said, the ES3 code I am using is a bit old (end of 2017), so it is probably already fixed.
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: Can we preload MonoBehaviours without a GameObject?

Post by Joel »

Hi there,

It's not possible to load an array of Components into a GameObject, unless the GameObject already had blank Components of the same type attached, and these were put into an array in the same order as they are in the array you are loading.

However, I've PM'd you a version of the ES3File class with a GetKeyType(string key) method which is more efficient than the method you are currently using.

Also the bug you have found has already been fixed at our end. Thanks for bringing it to my attention though!

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Post Reply