Files put inside a Resources folder still don't end up in the build
Heya,
I'm saving (small) puzzle levels by creating data containers and serializing them. They can then be loaded at runtime to build each level.
Now I created an Resources folder inside the Editor, imported several levels, and then built the game. However, none of the files are ever found in the Resources folder of the final build, needing me to import them myself. This usually wouldn't be an issue, but since I am using Unity Cloud Build, I can't simply insert the files onto the server, since I can't tamper with the builds.
Every resource I checked, including the doc, says that all files inside one (or multiple) resource folder/s will be included in the build, even if not referenced by any objects.
Note, I am not using Resources.Load(); since I couldn't yet figure out I would properly type the file that I get returned. (I save them by feeding a FileStream into a BinaryFormatter, which is also the way I load them. If anybody got any advice for how to use Resources.Load and then deserialize the object, I'd be glad.)
Answer by WillNode · Sep 18, 2016 at 01:18 PM
Now I created an Resources folder inside the Editor
This is the problem. In any circumstances any files put in 'Editor' will be excluded in the build, including that 'Resources' Folder. You really need to move that folder outside from the Editor folder.
And About Resources.Load.... I'm usually use it's generic version, like
Resources.Load<Texture>("Folder/Texture") // Relative path excluding the extension
Texture is used if it a texture, or TextAsset if it contains a plain text.
EDIT : This is how i use the JsonUtility:
[CreateAssetMenu]
public class TileDataContainer : ScriptableObject
{
public int level;
public List<ThumbDetail> tiles = new List<ThumbDetail> ();
public static TileDataContainer Load (int level)
{
var l = "TileData" + level.ToString("0");
if (PlayerPrefs.HasKey (l)) {
var r = ScriptableObject.CreateInstance<TileDataContainer> ();
JsonUtility.FromJsonOverwrite (PlayerPrefs.GetString (l), r);
return r;
} else {
// You need to create this scriptable inside the "Level" folder in
// resource folder named "TileData0", "TileData1"...
// use 'Create' menu in the project tab for that.
var r = Resources.Load<TileDataContainer> ("Level/" + l);
return r;
}
// Now always save the return value somewhere in your code, not from here anymore.
}
public static void Save (TileDataContainer data)
{
var l = "TileData" + data.level.ToString("0");
var s = JsonUtility.ToJson (data);
PlayerPrefs.SetString (l, s);
PlayerPrefs.Save();
}
}
Heya,
thanks for your answer, but it seems like I wrote it an bit ambigious:
I didn't put the Resources folder inside the Editor folder, rather I created it inside the Editor view (as in, inside Unity) and not the File Explorer. Resources is located like all other folders inside of "Assets".
As for Resources.Load : The Serialized file is an Array with all the objects. Once I deserialize the file I need the function to return that array, but BinaryFormatter only inputs a stream, not an TextAsset, and I haven't found something that allows me to Deserialize that TextAsset (XmlSerializer doesn't work because it's not an X$$anonymous$$L style file.)
Wait a $$anonymous$$ute, are you using .NET functions to load Resources data? No, it'll never work. You have to use Resources.Load, since the file is embedded within your application, and there is no another way to do it.
And about the file, uhh... you need something to deserialize it. why don't you use ScriptableObject ins$$anonymous$$d? it's way much faster and you don't need to deserialize anything.
Here's the current Save/Load code that I have:
public static void Save(List<TileInfo> TileInfo , int Level)
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.dataPath + "/Resources/Level" + Level + ".gd");
bf.Serialize(file, TileInfo);
file.Close();
}
public static List<TileInfo> Load(int Level)
{
var LoadedData = new List<TileInfo>();
if (File.Exists(Application.dataPath + "/Resources/Level" + Level + ".gd"))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.dataPath + "/Resources/Level" + Level + ".gd", File$$anonymous$$ode.Open);
LoadedData = (List<TileInfo>)bf.Deserialize(file);
file.Close();
}
return LoadedData;
}
And it actually works flawlessly, it just requires me to copy the files into the end built. In Play $$anonymous$$ode inside the Unity Editor I don't need to drag and drop any files. I know it isn't the most beautiful way, but it still doesn't explain why the files inside Resources don't get copied over. I've also tried to insert some innocent things like pictures in there, they don't get included in the end built either.
Also thanks for showing me ScriptableObject, that is indeed quite useful.
Edit: Note that I also imported the LevelFiles into the resources file inside Unity, the way you normally import files. They are all listed there.
Indeed interesting, you need to read and write the data, not just read it. That code will work only in the editor. If you ask me, you may need these classes: ScriptableObject for storing the List content, JsonUtility for the parser, PlayerPrefs for storing read/write data, Resources for storing the default data, in case it is not found in the PlayerPrefs.
Note: JsonUtility is new in 5.4, and far stable in 5.5 ScriptableObject is created by ScriptableObject.CreateInstance, or [CreateAsset$$anonymous$$enu]
That would be very kind. TileInfo is an abstract class that multiple classes derive from and add their own data. I think it would help immensly to see an implementation. The way my LevelLoader is currently set up is that it loads the list of TileInfos from the file, iterates over the list and checks a field called TileType that is defined in the TileInfo and set by each derived class and then instatiates the corresponding GameObject with a switch function.
So the save function would input an List of TileInfos and the number of the level, and the load function would input the number of the level and return a List of TileInfos.
Again, thanks. It will help immensily for my own understanding of how to save levels that I don't want to save as scenes (due to overhead as they are really small)
Thank you. How does it handle Inheritance? If an class inherits from TileInfo and has its own unique fields, does the object after being loaded and recast to its proper class still have those information?
Ouh... sorry, i didn't read that. This is the actual weaknesses from unity's serializer system. It wouldn't work with Inheritance. But you know what i've means, simply put the data into PlayerPrefs, and everything done.
Likely you need some advanced parsers that support this behaviour. You can google that for the solution, or in the asset store, if you prefer the quickest way. I'm found some of the solution like:
http://stackoverflow.com/questions/2434534/serialize-an-object-to-string
It's fine. I've got an idea for an workaround that is maintainable enough because there aren't too many different TileTypes anyways.
Thanks for everything!
Uhm. Should I mark this answer as solution because it didn't answer the question why files are not included in the final build?