🕶️
🕶️
🕶️
🕶️
NRSDK
v2.1.0
Ask or search…
K

Implementing Cloud Save and Load

1. CloudSaveAnchor

Add the CloudSaveAnchor method to NRWorldAnchorStore.
Use Firebase
Use Aliyun OSS
namespace NRKernal.Persistence
{
// ... Other codes ...
public class NRWorldAnchorStore : IDisposable
{
// ... Other codes ...
public const string CloudAnchor2ObjectFile = "cloud_anchor2object.json";
/// <summary>save an anchor to firebase cloud server</summary>
public async Task<bool> CloudSaveAnchor(NRWorldAnchor anchor)
{
NRDebugger.Info("[NRWorldAnchorStore] Cloud save Anchor: {0}", anchor.UserDefinedKey);
string localFilename = Path.Combine(MapPath, anchor.UUID);
Debug.LogError("UploadFile: "+localFilename);
NRDebugger.Info("[NRWorldAnchorStore] UploadFile:" + localFilename);
FirebaseStorageManager storageManager = FirebaseStorageManager.Instance;
await storageManager.UploadFile(anchor.UUID, localFilename);
// Update the cloud anchor to object dictionary
// Save the dictionary to a JSON file
string json = LitJson.JsonMapper.ToJson(m_Anchor2ObjectDict);
string path = Path.Combine(MapPath, CloudAnchor2ObjectFile);
NRDebugger.Info("[NRWorldAnchorStore] Save to the path for next upload:" + path + " json:" + json);
File.WriteAllText(path, json);
// Upload the JSON file to the cloud
await storageManager.UploadFile(CloudAnchor2ObjectFile, path);
return true;
}
}
// ... Other codes ...
}
}
1
namespace NRKernal.Persistence
2
{
3
// ... Other codes ...
4
5
public class NRWorldAnchorStore : IDisposable
6
{
7
// ... Other codes ...
8
9
private AliyunOSSManager ossManager;
10
11
// ... Other codes ...
12
13
public const string CloudAnchor2ObjectFile = "cloud_anchor2object.json";
14
/// <summary>save an anchor to Aliyun cloud server</summary>
15
public async Task<bool> CloudSaveAnchor(NRWorldAnchor anchor)
16
{
17
NRDebugger.Info("[NRWorldAnchorStore] Cloud save Anchor: {0}", anchor.UserDefinedKey);
18
19
string localFilename = Path.Combine(MapPath, anchor.UUID);
20
Debug.LogError("UploadFile: "+localFilename);
21
NRDebugger.Info("[NRWorldAnchorStore] UploadFile:" + localFilename);
22
23
24
ossManager = AliyunOSSManager.Instance;
25
// FirebaseStorageManager storageManager = FirebaseStorageManager.Instance;
26
await ossManager.UploadFile(anchor.UUID, localFilename);
27
// Update the cloud anchor to object dictionary
28
29
// Save the dictionary to a JSON file
30
string json = LitJson.JsonMapper.ToJson(m_Anchor2ObjectDict);
31
string path = Path.Combine(MapPath, CloudAnchor2ObjectFile);
32
NRDebugger.Info("[NRWorldAnchorStore] Save to the path for next upload:" + path + " json:" + json);
33
File.WriteAllText(path, json);
34
35
// Upload the JSON file to the cloud
36
await ossManager.UploadFile(CloudAnchor2ObjectFile, path);
37
38
return true;
39
}
40
41
// ... Other codes ...
42
}
43
}
44
Add the CloudSaveAnchor method in NRWorldAnchor, remember to add the namespace at the top of the script using System.Threading.Tasks;
public async Task<bool> CloudSaveAnchor()
{
return await NRWorldAnchorStore.Instance.CloudSaveAnchor(this);
}

2. CloudSave

Add the CloudSave method in AnchorItem.
public async void CloudSave()
{
if (m_NRWorldAnchor != null)
{
bool result=await NRWorldAnchorStore.Instance.CloudSaveAnchor(m_NRWorldAnchor);
if (result)
{
NRDebugger.Info("Ready to share anchor: " + m_NRWorldAnchor.UUID);
Debug.Log("Ready to share anchor: " + m_NRWorldAnchor.UUID);
}
else
{
Debug.LogError("Failed to save anchor");
}
}
else
{
Debug.LogError("m_NRWorldAnchor is null, failed to save this anchor to CloudStorage");
}
}

3. CloudLoad

Add CloudLoad() method in localMapExample: Download the specified file from the cloud server by specifying UUID and load it into the scene with LoadwithUUID.
public const string CloudAnchor2ObjectFile = "cloud_anchor2object.json";
public async Task CloudLoad(string uuid)
{
if (m_NRWorldAnchorStore == null)
{
Debug.Log("[m_NRWorldAnchorStore] is null");
return;
}
// Download the cloud anchor to object dictionary from the cloud
string path = Path.Combine(m_NRWorldAnchorStore.MapPath, CloudAnchor2ObjectFile);
//await ossManager.DownloadFile(CloudAnchor2ObjectFile, path);
await storageManager.DownloadFile(CloudAnchor2ObjectFile, path);
// Read the dictionary from the downloaded JSON file
Dictionary<string, string> m_Anchor2ObjectDict = new Dictionary<string, string>();
if (File.Exists(path))
{
string json = File.ReadAllText(path);
m_Anchor2ObjectDict = LitJson.JsonMapper.ToObject<Dictionary<string, string>>(json);
}
// Get the UserDefinedKey for the given uuid
string UserDefinedKey;
if (m_Anchor2ObjectDict.TryGetValue(uuid, out UserDefinedKey))
{
// Download the anchor file from the cloud
string anchorPath = Path.Combine(m_NRWorldAnchorStore.MapPath, uuid);
//await ossManager.DownloadFile(uuid, anchorPath);
await storageManager.DownloadFile(uuid, anchorPath);
Debug.Log("anchorPath: "+anchorPath);
Debug.Log("uuid: "+uuid);
Debug.Log("UserDefinedKey: "+UserDefinedKey);
// Create a new dictionary for the specific UUID and Key
Dictionary<string, string> specificAnchorDict = new Dictionary<string, string>();
specificAnchorDict[uuid] = UserDefinedKey;
// Save the downloaded dictionary to the NRWorldAnchorStore
m_NRWorldAnchorStore.SetAnchor2ObjectDict(specificAnchorDict);
// Load the anchor
m_NRWorldAnchorStore.LoadwithUUID(uuid, (UInt64 handle) =>
{
var go = Instantiate(m_AnchorPrefabDict[UserDefinedKey]);
Debug.Log("cloud load: successful! ");
#if UNITY_EDITOR
go.transform.position = UnityEngine.Random.insideUnitSphere + Vector3.forward * 2;
#else
go.transform.position = Vector3.forward * 10000;
#endif
NRWorldAnchor anchor = go.AddComponent<NRWorldAnchor>();
anchor.UserDefinedKey = UserDefinedKey;
anchor.UUID = uuid;
anchor.BindAnchor(handle);
go.SetActive(true);
NRDebugger.Info("[NRWorldAnchorStore] CloudLoadwithUUID: {0}, UserDefinedKey: {1} Handle: {2}", uuid, UserDefinedKey, handle);
});
}
else
{
Debug.LogError("No UserDefinedKey found for uuid: " + uuid);
}
}
This requires adding a method in NRWorldAnchorStore.cs to put the UUID of the anchor downloaded from the cloud into m_Anchor2ObjectDict.
public void SetAnchor2ObjectDict(Dictionary<string, string> newDict)
{
foreach (var item in newDict)
{
if (!m_Anchor2ObjectDict.ContainsKey(item.Key))
{
m_Anchor2ObjectDict.Add(item.Key, item.Value);
}
}
}
Similarly, this method needs to be added to NRWorldAnchor.
public void SetAnchor2ObjectDict(Dictionary<string, string> newDict)
{
NRWorldAnchorStore.Instance.SetAnchor2ObjectDict(newDict);
}

Test

We can simply test the upload and download functions in Unity Editor to see if they are working properly.

CloudSave:

  1. 1.
    Button Attachment: Attach the CloudSave method to a button. For demonstration purposes, we've linked it to a "share" button in our example.
  2. 2.
    Running in Unity Editor: Before proceeding with the Cloud Save operation, ensure that you've successfully saved the anchor. Launch your application within the Unity Editor to verify this.
  3. 3.
    Log Verification: After executing the Cloud Save, check the console for log messages. If you encounter a message similar to the one provided, it's a strong indication that your upload was successful.
  4. 4.
    Cloud Storage Validation: For added assurance, navigate to Firebase Storage or Aliyun OSS console to confirm that your data has been uploaded correctly.
    Firebase Console

CloudLoad

  1. 1.
    Modifying localmapExample: Add a test method and a test UUID within the localmapExample. Use the UUID of an anchor that's already stored on the cloud server.
public string testuuid;
public void TestCloudLoad()
{
CloudLoad(testuuid);
}
  1. 2.
    Button Attachment: Similar to the CloudSave process, attach this test method to a button.
  2. 3.
    Execution: Run the method by pressing the button in your application.
  3. 4.
    Log Verification: Monitor the console for log messages. If you see messages indicating a successful download, it means the anchor has been retrieved correctly from the cloud.
We've successfully completed 90% of the process. Great job on making it this far! In the next section, we'll delve into using Photon to transmit the UUID. This will seamlessly connect all the steps we've covered so far. Stay with us as we approach the finish line!