/// <summary> /// Caution: Non atomic operation! /// Save the key/value pair in the DataStore. /// This method will split the payload into multiple smaller packages, in order to overcome /// GameJolts 1MB limit. These packages will be appended via the update operation. /// If one or more parts are already uploaded and then an error occurs (for e.g. no network connection), /// this method will stop uploading further packages. If this happens the DataStore might contain /// incomplete data, therefore you might want to delete the entry or try uploading again. /// By using the <paramref name="progress"/> callback, you could also try to continue from the last position. /// </summary> /// <param name="key">The key name.</param> /// <param name="value">The value to store.</param> /// <param name="global">A boolean indicating whether the key is global (<c>true</c>) or private to the user (<c>false</c>).</param> /// <param name="callback">A callback function accepting a single parameter, a boolean indicating success.</param> /// <param name="progress">A callback function accepting a single parameter, the number of already uploaded bytes. /// This callback is called after each successfull segment upload.</param> /// <param name="maxSegmentSize">Maximum segment size. The data to upload is split into segments of at most this size.</param> public static void SetSegmented(string key, string value, bool global, Action <bool> callback, Action <int> progress = null, int maxSegmentSize = SoftLimit) { if (callback == null) { throw new ArgumentNullException(); } if (maxSegmentSize < 10 || maxSegmentSize > SoftLimit) { throw new ArgumentOutOfRangeException(); } int encodedKeySize = GetEncodedSize(key); if (encodedKeySize >= KeySizeLimit) { LogHelper.Error("Failed to upload data, because the key is too long."); callback(false); return; } maxSegmentSize = Math.Min(maxSegmentSize, SoftLimit - encodedKeySize); var segments = new Queue <string>(); int encodedSize = Segmentate(Encoding.ASCII.GetBytes(value), maxSegmentSize, segments); if (encodedKeySize + encodedSize > HardLimit) { LogHelper.Error("Dataset is larger than 16MB!"); callback(false); return; } const int keyLimit = SoftLimit * 3 / 4; if (encodedKeySize > keyLimit) { LogHelper.Warning("Key is very long, only {0} bytes left for the data. " + "Therefore many segments may be needed to upload the data." + "Consider using smaller keys.", SoftLimit - key.Length); } // set first segment var dataSend = 0; var segment = segments.Dequeue(); var payload = new Dictionary <string, string> { { "key", key }, { "data", segment } }; Action <string> completedAction = null; completedAction = response => { if (response == null) // request failed { callback(false); } else // request succeeded { dataSend += segment.Length; if (progress != null) { progress(dataSend); } if (dataSend >= value.Length) // data uploaded completely { callback(true); } else // append next segment { segment = segments.Dequeue(); Update(key, segment, DataStoreOperation.Append, global, completedAction); } } }; Request.Post(Constants.ApiDatastoreSet, null, payload, response => completedAction(response.Success ? segment : null), !global); }