How load/save a number with saved games for Play Games Services in Unity games? - unity3d

I need to load/save the number of coins a user has earned in my Unity game with saved games for Play Games Services.
There is an example on how to save an image on this page: https://developer.android.com/games/pgs/unity/saved-games#write_a_saved_game
Can someone tell me how I can load/save a number instead of an image?

To be precise, I wouldn't say you are exactly saving an image. I mean, you do save it, but only as a cover for your game save file and I don't know if you can retrieve it (maybe you can, I haven't checked that really).
Probably the most important part of using google play save system is byte[] savedData argument. It's just a byte array, and it's up to you what are you going to pass there and how are you going to interpret that data on game load.
There are a lot of ways you could approach it. I personally create a custom GameSave object with all my data that I want to save, then I serialize it using JsonUtility.
string json = JsonUtility.ToJson(gameSave);
After that, I use MemoryStream and BinaryFormatter to convert the data in my json to byte array:
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, json);
byte[] data = memoryStream.GetBuffer();
Then you would have to pass that data to savedGameClient.CommitUpdate method as an argument.
Of course, that's just one of the ways of doing that, you can send something else than json from serialized class object.
Other stuff is pretty well documented, so once you handle that, you should manage to do the rest.

Related

Save and load entire scene in Unity

Okay, so I've been struggling around and searching for a while, saw a lot of different posts, but I did not find answer to my question.
My problem:
I have a scene in Unity with nothing in it, everything is created proceduraly and randomly on game start, and of course I want the player to be able to save his progress. I have found ways of saving progress in Unity, but everything was about writing a script for each class or object I want to save, but these seem to me inefficient, since in my game, there are randomly generated houses and buildings (which would be relatively easy to save), but there can also be objects placed inside these buildings and so on. Also later I plan on adding characters, which also need to be saved (like where they are, what are they holding and such). And as I mentioned, writing a save and load script for each object seems inefficient to me, since I'm used to Java's serializtaion, where I just write my Main Object containing all data to a file, so I'm looking for some easier ways to do so. Possibly a way to save entire scene state and then on loading just load the scene instead of generating it from scratch.
My Question:
Is there a way to save whole scene with all objects and information about them and then load it?
Thank you in advance!
There's no built-in method by which you can "save a scene" during runtime and then reload it later. In a Unity build, scenes are stored in a non-editable format, meaning that whenever you load a scene it will load up with the same format as it was built. This is a good thing, because you don't want to edit the contents of your build in a deployed game.
Now, that doesn't mean that a scene can't contain logic to configure itself differently. In fact, it sounds like that's what you're doing. The goal instead is to store the contents into a save file.
Consider switching your mentality from "I want to load a scene that generates random gameplay" to "I want to load a scene that configures itself based on a file." This is a layer of abstraction that gives greater control over what happens when you load your scene.
I would suggest creating a JSON configuration file that stores your important information, something like this might do:
{
"house_locations": [
{
"position": "(0, 0, 0)",
"objects": []
},
{
"position": "(10, 10, 10)",
"objects": []
}
],
"characters": [
{
"position": "(0, 0, 0)",
"inventory": [
{
"item_name": "knife"
},
{
"item_name": "shovel"
}
]
}
]
}
This is just a simple example, as you'll have to add the important data you want to represent your game.
Next, all you have to do when you want to start your game is to do one of the following things:
Are you starting a new game? => Generate a random configuration file, then use that to populate your scene.
Are you loading a saved game? => Use the saved configuration file to populate your scene.
You'll need some kind of WorldBuilder script to handle this. In your scene, you can have something like the following:
public class WorldBuilder : MonoBehaviour
{
// This is the actual contents of the world, represented as a JSON string.
private string _json = "";
public void BuildWorld(string configFilePath)
{
_json = LoadConfiguration(configFilePath);
BuildWorld(_json);
}
public void GenerateWorld()
{
_json = GenerateConfiguration();
BuildWorld(_json);
}
public void SaveWorld(string targetFilePath)
{
// Save the contents of _json out to a file so that it can be loaded
// up again later.
}
private string LoadConfiguration(string configFilePath)
{
// Load the actual file and return the file contents, which is a JSON string.
}
private void BuildWorld(string json)
{
// Actually build the world using the supplied JSON.
}
private string GenerateConfiguration()
{
// Return a randomly generated configuration file.
}
}
This approach separates the problem of saving the contents of the scene and generating the contents of the scene, making the code easier to write and maintain.
I do not know how to build a scene save patternor principles.
But there is a plugin which save scene in play mode, you may configure it according to your project.
https://assetstore.unity.com/packages/tools/utilities/autosaver-don-t-waste-time-anymore-54247
I would name 'LoadConfiguration' to 'LoadWorld'. Actually, I'd name it 'WorldSave' and 'WorldLoad' so it all matches up alphabetically.
Also, have loading be asynchronous:
public IEnumerator WorldLoad(string localWorldFilePath)
{
string filePath = Application.persistentDataPath + "/" + localWorldFilePath + ".json");
string lines = null;
//Loading the level loop:
using (SteamReader streamReader = new StreamReader(filePath,Encoding.UTF8))
{
lines += streamReader.ReadToEnd();
if (UnityEngine.Random.Range(0f,20f) > 15f) //< - probably a fancier way of doing this part)
yield return new WaitForEndOfFrame();
}
//Okay, we're done loading so return this:
yield return lines;
}
In fact, have saving be asynchronous too, using StreamWriter and make sure it's also encoded in UTF8, you can't just use File.Save and File.Load in other words.
Another idea, encrypt your files if you don't want modding (but people will just decrypt it anyway).
Start the coroutine somewhere else, the lower you make that '15f' the more it'll lock up your game, the higher you make it the less it will but the slower it'll go. There's a way to do it on a separate thread or something but I'm not an advanced programmer.
worldBuilder.StartCoroutine(WorldLoad);
TIP 1:
Ideally you wanna create your own scripting language through a console, if the idea of real-time custom scene file loading and saving is that you can create and edit your levels while the actual game is running so that you're bypassing using Unity as a level editor for example.
In other words you could press ~ and bring a console up and type 'WorldLoad(worldNameGoesHere)' and it'll load the world in your games built folders.
There's also a way using an editor script you can actually hook in and override Unity's standard 'Scene Save', in case you wanna do that also.
TIP 2:
Also make sure you encode in UTF8 format like above, saving and loading so you don't have it become a pain later when you want to implement asian languages like Japanese, Chinese, etc...

How to save/Manage Game Progress in Mobile devices (Unity)?

Currently I am saving game progress in a file in JSON format. Each time player completes the level a new entry will be added to JSON file as follow "level_N":{"score":234,"points":22},
this file will be saved at the end of Level complete. Consider scenario in which player reaches level 2345 or so, In that case saving to the file on level complete takes considerably longer time in some mobile devices. how to manage saving such a large amount of data ? do I have to use some other formats ? or do i have to save each level detail in separate file ?
PlayerPrefs is the easiest way to save data. It’s designed to handle basic data types (int, string, float) and works like a dictionary, so you can simply store JSON string as key-value pairs. And there is no size limit on iOS or Android (in webplayer it's limited to 1MB).
// read
PlayerPrefs.GetString(string key, string value);
// write
PlayerPrefs.SetString(string key, string value);
// load and update
const saveKey = "level_N";
Private void SaveProgress()
{
string saveValue = "your JSON string";
string loadValue = PlayerPrefs.GetString(saveKey);
if (!saveValue.Equals(loadValue))
{
PlayerPrefs.SetString(saveKey, saveValue);
PlayerPrefs.Save();
}
}
User data will be automatically written to disk during OnApplicationQuit(), but you may want to use PlayerPrefs.Save() in case your game crashes.
Having said that, saving a large amount of data to PlayerPrefs on mobile devices might be slow. So if you want to improve your game performance or need more space, you can use Application.persistentDataPath to save data to a public directory on the device. Similar to PlayerPrefs, data is not cleared when app is updated.
FileStream file = File.Open(Application.persistentDataPath + "/gameInfo.dat", FileMode.Open);
You can use PlayerPrefs class to save to save the local data.
In your case, you can trun your json to string then call PlayerPrefs.SetString to save/PlayerPrefs.GetString to get.
PlayerPrefs is always a good choice for local data managing but if you planning to add online features to your game, I recommend you to take a look at Firebase Realtime Database for sync json data with offline support. And let the firebase manage performance issues on mobile devices. Here you can see how to integrate Firebase Database to your Unity project easily.

JPEG encoder super slow, how to Optimize it?

I'm building an App with actionscript 3.0 in my Flash builder. This is a followup question this question.
I need to upload the bytearray to my server, but the function i use to convert the bitmapdata to a ByteArray is super slow, so slow it freezes up my mobile device. My code is as follows:
var jpgenc:JPEGEncoder = new JPEGEncoder(50);
trace('encode');
//encode the bitmapdata object and keep the encoded ByteArray
var imgByteArray:ByteArray = jpgenc.encode(bitmap);
temp2 = File.applicationStorageDirectory.resolvePath("snapshot.jpg");
var fs:FileStream = new FileStream();
trace('fs');
try{
//open file in write mode
fs.open(temp2,FileMode.WRITE);
//write bytes from the byte array
fs.writeBytes(imgByteArray);
//close the file
fs.close();
}catch(e:Error){
Is there a different way to convert it to a byteArray? Is there a better way?
Try to use blooddy library: http://www.blooddy.by . But i didn't test it on mobile devices. Comment if you will have success.
Use BitmapData.encode(), it's faster by orders of magnitude on mobile http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#encode%28%29
You should try to find a JPEG encoder that is capable of encoding asynchronously. That way the app can still be used while the image is being compressed. I haven't tried any of the libraries, but this one looks promising:
http://segfaultlabs.com/devlogs/alchemy-asynchronous-jpeg-encoding-2
It uses Alchemy, which should make it faster than the JPEGEncoder from as3corelib (which I guess is the one you're using at the moment.)
A native JPEG encoder is ideal, asynchronous would be good, but possibly still slow (just not blocking). Another option:
var pixels:ByteArray = bitmapData.getPixels(bitmapData.rect);
pixels.compress();
I'm not sure of native performance, and performance definitely depends on what kind of images you have.
The answer from Ilya was what did it for me. I downloaded the library and there is an example of how to use it inside. I have been working on getting the CameraUI in flashbuilder to take a picture, encode / compress it, then send it over via a web service to my server (the data was sent as a compressed byte array). I did this:
by.blooddy.crypto.image.JPEGEncoder.encode( bmp, 30 );
Where bmp is my bitmap data. The encode took under 3 seconds and was easily able to fit into my flow of control synchronously. I tried async methods but they ultimately took a really long time and were difficult to track for things like when a user moved from cell service to wifi or from tower to tower while an upload was going on.
Comment here if you need more details.

iPhone/iPad Base64->NSData->PDF how to?

Obj-C or Monotouch.Net C# answers are fine.
I have a Base64 string that is a PDF document received over a web service. I can get the NSData.
How do I take the NSData and save it as a PDF?
-- I get the NSData this way --
byte[] encodedDataAsBytes = System.Convert.FromBase64String (myBase64String);
string decoded = System.Text.Encoding.Unicode.GetString (encodedDataAsBytes);
NSData data = NSData.FromString (decoded, NSStringEncoding.ASCIIStringEncoding);
The simplest way to save it is probably to use NSData's writeToFile:options:error: method.
I found that using the .NET framework works better than trying to use the iOS framework for this problem. This will take any file and convert it to it's original then save it to the iPhone/iPad device. "path" is just a folder on the dev ice.
using (var f = System.IO.File.Create (path))
{
byte[] encodedDataAsBytes = System.Convert.FromBase64String (Base64PDFString);
f.Write (encodedDataAsBytes, 0, encodedDataAsBytes.Length);
}
I'm working on a project where I recently had to accomplish the same thing you are describing. I get base64 encoded PDF files as strings from a .NET web service which need to be decoded to their original and saved as PDF files in the applications documents directory.
My solution was:
Use ASIHTTPRequest to communicate with the web service.
I then use TBXML to parse incoming xml and get the base64 as an NSString.
To decode the string I use a method from QSUtilities library called decodeBase64WithString.
Finally I save the result with NSData's writeToFile.
I have tested and successfully used this method with PDF files that are up to 25mb. I also had a couple of test runs with a 48mb file but that file made the decodeBase64WithString method take up too much memory and my app crashed. Haven't found a solution to this yet..
If you are working with multiple large files be sure to free up your memory once in a while. I got all my files in one loop in which I had to use my own nsautorelease pool and drain it at the end of the loop to free up any autoreleased objects.

How to add metadata to WAV file?

I'm looking for some sample code to show me how to add metadata to the wav files we create.
Anyone?
One option is to add your own chunk with a unique id. Most WAV players will ignore it.
Another idea would to be use a labl chunk, associated with a que set at the beginning or end of the file. You'd also need a que chunk. See here for a reference
How to write the data is simple
Write "RIFF".
save the file position.
Write 4 bytes of 0's
Write all the existing chunks. Keep count of bytes written.
Add your chunk. Be sure to get the chunksize right. Keep
count of bytes written.
rewind to the saved position. Write the new size (as a 32-bit
number).
Close the file.
It's slightly more complicated if you are adding things to an existing list chunk, but the same principle applies.
Maybe the nist file format will give you what you want:
NIST
Here is a lib that could help, but im afraid it looks old. NIST Lib
Cant find more useful information right now how exactly to use it, and im afraid the information papers from my company must stay there. :L/
Try code below
private void WaveTag()
{
string fileName = "in.wav";
WaveReadWriter wrw = new WaveReadWriter(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite));
//removes INFO tags from audio stream
wrw.WriteInfoTag(null);
//writes INFO tags into audio stream
Dictionary<WaveInfo, string> tag = new Dictionary<WaveInfo, string>();
tag[WaveInfo.Comments] = "Comments...";
wrw.WriteInfoTag(tag);
wrw.Close();
//reads INFO tags from audio stream
WaveReader wr = new WaveReader(File.OpenRead(fileName));
Dictionary<WaveInfo, string> dir = wr.ReadInfoTag();
wr.Close();
if (dir.Count > 0)
{
foreach (string val in dir.Values)
{
Console.WriteLine(val);
}
}
}
from http://alvas.net/alvas.audio,articles.aspx#id3-tags-for-wave-files
If you examine the wave file spec you'll see that there does not seem to be room for annotations of any kind. An option would be to wrap the wave file with your own format that includes custom information but you would in effect be creating a whole new format that would not be readable by users who do not have your app. But you might be ok with that.