optimizations and code simplification for loading persistent object data, fixes for deleting persistent objects
parent
8c5ed4ed26
commit
d02eddfe79
|
|
@ -19,10 +19,12 @@ namespace VELConnect
|
||||||
public class VELConnectManager : MonoBehaviour
|
public class VELConnectManager : MonoBehaviour
|
||||||
{
|
{
|
||||||
public string velConnectUrl = "http://localhost";
|
public string velConnectUrl = "http://localhost";
|
||||||
|
|
||||||
public static string VelConnectUrl
|
public static string VelConnectUrl
|
||||||
{
|
{
|
||||||
get => instance.velConnectUrl;
|
get => instance.velConnectUrl;
|
||||||
set {
|
set
|
||||||
|
{
|
||||||
instance.velConnectUrl = value;
|
instance.velConnectUrl = value;
|
||||||
SetDeviceField(new Dictionary<DeviceField, string>
|
SetDeviceField(new Dictionary<DeviceField, string>
|
||||||
{
|
{
|
||||||
|
|
@ -33,6 +35,7 @@ namespace VELConnect
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VELConnectManager instance;
|
private static VELConnectManager instance;
|
||||||
|
|
||||||
public class State
|
public class State
|
||||||
|
|
@ -897,7 +900,6 @@ namespace VELConnect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void GetRequestCallback(string url, Action<string> successCallback = null,
|
public static void GetRequestCallback(string url, Action<string> successCallback = null,
|
||||||
Action<string> failureCallback = null)
|
Action<string> failureCallback = null)
|
||||||
{
|
{
|
||||||
|
|
@ -940,12 +942,17 @@ namespace VELConnect
|
||||||
|
|
||||||
private static IEnumerator PostRequestCallbackCo(string url, string postData,
|
private static IEnumerator PostRequestCallbackCo(string url, string postData,
|
||||||
Dictionary<string, string> headers = null, Action<string> successCallback = null,
|
Dictionary<string, string> headers = null, Action<string> successCallback = null,
|
||||||
Action<string> failureCallback = null, string method="POST")
|
Action<string> failureCallback = null, string method = "POST")
|
||||||
{
|
{
|
||||||
UnityWebRequest webRequest = new UnityWebRequest(url, method);
|
UnityWebRequest webRequest = new UnityWebRequest(url, method);
|
||||||
|
UploadHandlerRaw uploadHandler = null;
|
||||||
|
if (!string.IsNullOrEmpty(postData))
|
||||||
|
{
|
||||||
byte[] bodyRaw = Encoding.UTF8.GetBytes(postData);
|
byte[] bodyRaw = Encoding.UTF8.GetBytes(postData);
|
||||||
UploadHandlerRaw uploadHandler = new UploadHandlerRaw(bodyRaw);
|
uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||||
webRequest.uploadHandler = uploadHandler;
|
webRequest.uploadHandler = uploadHandler;
|
||||||
|
}
|
||||||
|
|
||||||
webRequest.downloadHandler = new DownloadHandlerBuffer();
|
webRequest.downloadHandler = new DownloadHandlerBuffer();
|
||||||
webRequest.SetRequestHeader("Content-Type", "application/json");
|
webRequest.SetRequestHeader("Content-Type", "application/json");
|
||||||
if (headers != null)
|
if (headers != null)
|
||||||
|
|
@ -971,7 +978,7 @@ namespace VELConnect
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadHandler.Dispose();
|
uploadHandler?.Dispose();
|
||||||
webRequest.Dispose();
|
webRequest.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Networking;
|
||||||
using VelNet;
|
using VelNet;
|
||||||
|
|
||||||
namespace VELConnect
|
namespace VELConnect
|
||||||
|
|
@ -10,6 +13,9 @@ namespace VELConnect
|
||||||
{
|
{
|
||||||
public static VelConnectPersistenceManager instance;
|
public static VelConnectPersistenceManager instance;
|
||||||
|
|
||||||
|
// The items in this list are used when loading existing data from the server on room join
|
||||||
|
private List<VelNetPersist> sceneObjects = new List<VelNetPersist>();
|
||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
@ -27,19 +33,57 @@ namespace VELConnect
|
||||||
|
|
||||||
private void OnJoinedRoom(string roomName)
|
private void OnJoinedRoom(string roomName)
|
||||||
{
|
{
|
||||||
// if we're the first to join this room
|
StartCoroutine(OnJoinedRoomCo(roomName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator OnJoinedRoomCo(string roomName)
|
||||||
|
{
|
||||||
|
foreach (VelNetPersist velNetPersist in sceneObjects)
|
||||||
|
{
|
||||||
|
velNetPersist.loading = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pagesLeft = 1;
|
||||||
|
int totalCounter = 200;
|
||||||
|
int page = 1;
|
||||||
|
List<VELConnectManager.PersistObject> allResults = new List<VELConnectManager.PersistObject>();
|
||||||
|
while (pagesLeft > 0)
|
||||||
|
{
|
||||||
|
if (totalCounter < 0)
|
||||||
|
{
|
||||||
|
Debug.LogError("Too many pages of persisted objects. This must be a bug.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
using UnityWebRequest webRequest =
|
||||||
|
UnityWebRequest.Get(VELConnectManager.VelConnectUrl + $"/api/collections/PersistObject/records?filter=(app='{Application.productName}')&page={page++}");
|
||||||
|
yield return webRequest.SendWebRequest();
|
||||||
|
|
||||||
|
switch (webRequest.result)
|
||||||
|
{
|
||||||
|
case UnityWebRequest.Result.ConnectionError:
|
||||||
|
case UnityWebRequest.Result.DataProcessingError:
|
||||||
|
case UnityWebRequest.Result.ProtocolError:
|
||||||
|
Debug.LogError("Error: " + webRequest.error + "\n" + Environment.StackTrace);
|
||||||
|
Debug.LogError("Failed to get persisted spawned objects");
|
||||||
|
yield break;
|
||||||
|
break;
|
||||||
|
case UnityWebRequest.Result.Success:
|
||||||
|
string text = webRequest.downloadHandler.text;
|
||||||
|
VELConnectManager.RecordList<VELConnectManager.PersistObject> obj =
|
||||||
|
JsonConvert.DeserializeObject<VELConnectManager.RecordList<VELConnectManager.PersistObject>>(text);
|
||||||
|
allResults.AddRange(obj.items);
|
||||||
|
pagesLeft = obj.totalPages - obj.page;
|
||||||
|
totalCounter--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn items if we're the first to join this room
|
||||||
if (VelNetManager.Players.Count == 1)
|
if (VelNetManager.Players.Count == 1)
|
||||||
{
|
{
|
||||||
VELConnectManager.GetRequestCallback(
|
List<VELConnectManager.PersistObject> spawnedItems = allResults.Where(i => i.spawned && i.room == VelNetManager.Room).ToList();
|
||||||
VELConnectManager.VelConnectUrl +
|
foreach (VELConnectManager.PersistObject persistObject in spawnedItems)
|
||||||
$"/api/collections/PersistObject/records?filter=(app='{Application.productName}')",
|
|
||||||
s =>
|
|
||||||
{
|
|
||||||
VELConnectManager.RecordList<VELConnectManager.PersistObject> obj =
|
|
||||||
JsonConvert.DeserializeObject<VELConnectManager.RecordList<VELConnectManager.PersistObject>>(s);
|
|
||||||
obj.items = obj.items.Where(i => i.spawned && i.room == VelNetManager.Room).ToList();
|
|
||||||
|
|
||||||
foreach (VELConnectManager.PersistObject persistObject in obj.items)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(persistObject.data))
|
if (string.IsNullOrEmpty(persistObject.data))
|
||||||
{
|
{
|
||||||
|
|
@ -53,13 +97,49 @@ namespace VELConnect
|
||||||
persist.persistId = persistObject.id;
|
persist.persistId = persistObject.id;
|
||||||
persist.LoadData(persistObject);
|
persist.LoadData(persistObject);
|
||||||
}
|
}
|
||||||
}, s => { Debug.LogError("Failed to get persisted spawned objects", this); });
|
}
|
||||||
|
|
||||||
|
// load data for scene objects
|
||||||
|
List<VELConnectManager.PersistObject> sceneObjectData = allResults.Where(i => i.room == VelNetManager.Room).ToList();
|
||||||
|
foreach (VelNetPersist velNetPersist in sceneObjects)
|
||||||
|
{
|
||||||
|
List<VELConnectManager.PersistObject> thisObjectData = sceneObjectData.Where(i => i.network_id == velNetPersist.networkObject.sceneNetworkId.ToString()).ToList();
|
||||||
|
switch (thisObjectData.Count)
|
||||||
|
{
|
||||||
|
case < 1:
|
||||||
|
Debug.LogError($"[VelNetPersist] No data found for {velNetPersist.name} (network_id='{velNetPersist.networkObject.sceneNetworkId}')");
|
||||||
|
velNetPersist.loading = false;
|
||||||
|
continue;
|
||||||
|
case > 1:
|
||||||
|
Debug.LogError(
|
||||||
|
$"[VelNetPersist] Multiple records found for app='{Application.productName}' && room='{VelNetManager.Room}' && network_id='{velNetPersist.networkObject.sceneNetworkId}'. Deleting all but the first one.");
|
||||||
|
IEnumerable<VELConnectManager.PersistObject> toDelete = thisObjectData.Skip(1);
|
||||||
|
foreach (VELConnectManager.PersistObject persistObject in toDelete)
|
||||||
|
{
|
||||||
|
VELConnectManager.PostRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistObject.id, null, null, null,
|
||||||
|
Debug.LogError, method: "DELETE");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
velNetPersist.LoadData(thisObjectData.FirstOrDefault());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void RegisterSceneObject(VelNetPersist obj)
|
||||||
|
{
|
||||||
|
instance.sceneObjects.Add(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnregisterSceneObject(VelNetPersist obj)
|
||||||
|
{
|
||||||
|
instance.sceneObjects.Remove(obj);
|
||||||
|
}
|
||||||
|
|
||||||
// We don't need to register objects, because they will do that automatically when they spawn if they have the VelNetPersist component
|
// We don't need to register objects, because they will do that automatically when they spawn if they have the VelNetPersist component
|
||||||
// We need to unregister objects when they are destroyed because destroying could happen because we left the scene
|
// We need to unregister objects when they are destroyed because destroying could happen because we left the scene (which shouldn't delete it from the server)
|
||||||
public static void UnregisterObject(NetworkObject obj)
|
public static void DestroySpawnedObject(NetworkObject obj)
|
||||||
{
|
{
|
||||||
VelNetPersist[] persistedComponents = obj.GetComponents<VelNetPersist>();
|
VelNetPersist[] persistedComponents = obj.GetComponents<VelNetPersist>();
|
||||||
if (persistedComponents.Length > 1)
|
if (persistedComponents.Length > 1)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace VELConnect
|
||||||
{
|
{
|
||||||
private const float interval = 5f;
|
private const float interval = 5f;
|
||||||
private double nextUpdate;
|
private double nextUpdate;
|
||||||
private bool loading;
|
public bool loading;
|
||||||
private const bool debugLogs = false;
|
private const bool debugLogs = false;
|
||||||
public string persistId;
|
public string persistId;
|
||||||
|
|
||||||
|
|
@ -30,17 +30,15 @@ namespace VELConnect
|
||||||
|
|
||||||
private void OnEnable()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
VelNetManager.OnJoinedRoom += OnJoinedRoom;
|
if (networkObject.isSceneObject)
|
||||||
|
{
|
||||||
|
VelConnectPersistenceManager.RegisterSceneObject(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDisable()
|
private void OnDisable()
|
||||||
{
|
{
|
||||||
VelNetManager.OnJoinedRoom -= OnJoinedRoom;
|
VelConnectPersistenceManager.UnregisterSceneObject(this);
|
||||||
}
|
|
||||||
|
|
||||||
private void OnJoinedRoom(string roomName)
|
|
||||||
{
|
|
||||||
Load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Load()
|
private void Load()
|
||||||
|
|
@ -52,31 +50,32 @@ namespace VELConnect
|
||||||
{
|
{
|
||||||
// It looks like a PocketBase bug is preventing full filtering from happening:
|
// It looks like a PocketBase bug is preventing full filtering from happening:
|
||||||
// $"/api/collections/PersistObject/records?filter=(app='{Application.productName}' && room='{VelNetManager.Room}' && network_id='{networkObject.sceneNetworkId}')",
|
// $"/api/collections/PersistObject/records?filter=(app='{Application.productName}' && room='{VelNetManager.Room}' && network_id='{networkObject.sceneNetworkId}')",
|
||||||
VELConnectManager.GetRequestCallback(
|
// VELConnectManager.GetRequestCallback(
|
||||||
VELConnectManager.VelConnectUrl +
|
// VELConnectManager.VelConnectUrl +
|
||||||
$"/api/collections/PersistObject/records?filter=(app='{Application.productName}')",
|
// $"/api/collections/PersistObject/records?filter=(app='{Application.productName}')",
|
||||||
s =>
|
// s =>
|
||||||
{
|
// {
|
||||||
VELConnectManager.RecordList<VELConnectManager.PersistObject> obj =
|
// VELConnectManager.RecordList<VELConnectManager.PersistObject> obj =
|
||||||
JsonConvert.DeserializeObject<VELConnectManager.RecordList<VELConnectManager.PersistObject>>(s);
|
// JsonConvert.DeserializeObject<VELConnectManager.RecordList<VELConnectManager.PersistObject>>(s);
|
||||||
obj.items = obj.items.Where(i => i.network_id == networkObject.sceneNetworkId.ToString() && i.room == VelNetManager.Room).ToList();
|
// obj.items = obj.items.Where(i => i.network_id == networkObject.sceneNetworkId.ToString() && i.room == VelNetManager.Room).ToList();
|
||||||
if (obj.items.Count < 1)
|
// if (obj.items.Count < 1)
|
||||||
{
|
// {
|
||||||
Debug.LogError("[VelNetPersist] No data found for " + name);
|
// Debug.LogError("[VelNetPersist] No data found for " + name);
|
||||||
loading = false;
|
// loading = false;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
else if (obj.items.Count > 1)
|
// else if (obj.items.Count > 1)
|
||||||
{
|
// {
|
||||||
Debug.LogError(
|
// Debug.LogError(
|
||||||
$"[VelNetPersist] Multiple records found for app='{Application.productName}' && room='{VelNetManager.Room}' && network_id='{networkObject.sceneNetworkId}'. Using the first one.");
|
// $"[VelNetPersist] Multiple records found for app='{Application.productName}' && room='{VelNetManager.Room}' && network_id='{networkObject.sceneNetworkId}'. Using the first one.");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
LoadData(obj.items.FirstOrDefault());
|
// LoadData(obj.items.FirstOrDefault());
|
||||||
}, s => { loading = false; });
|
// }, s => { loading = false; });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Debug.LogError("TODO idk when this would happen");
|
||||||
VELConnectManager.GetRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId, s =>
|
VELConnectManager.GetRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId, s =>
|
||||||
{
|
{
|
||||||
VELConnectManager.PersistObject obj = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
|
VELConnectManager.PersistObject obj = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
|
||||||
|
|
@ -160,7 +159,7 @@ namespace VELConnect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Delete(Action<VELConnectManager.PersistObject> successCallback = null)
|
public void Delete()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(persistId))
|
if (string.IsNullOrEmpty(persistId))
|
||||||
{
|
{
|
||||||
|
|
@ -168,12 +167,8 @@ namespace VELConnect
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
VELConnectManager.PostRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId, null, null,
|
VELConnectManager.PostRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId,
|
||||||
s =>
|
null, null, null, Debug.LogError,
|
||||||
{
|
|
||||||
VELConnectManager.PersistObject resp = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
|
|
||||||
successCallback?.Invoke(resp);
|
|
||||||
}, Debug.LogError,
|
|
||||||
method: "DELETE");
|
method: "DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "edu.uga.engr.vel.vel-connect",
|
"name": "edu.uga.engr.vel.vel-connect",
|
||||||
"displayName": "VEL-Connect",
|
"displayName": "VEL-Connect",
|
||||||
"version": "5.0.2",
|
"version": "5.0.3",
|
||||||
"unity": "2019.1",
|
"unity": "2019.1",
|
||||||
"description": "Web-based configuration for VR applications",
|
"description": "Web-based configuration for VR applications",
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ export type DeviceRecord = {
|
||||||
current_room?: string
|
current_room?: string
|
||||||
data: RecordIdString
|
data: RecordIdString
|
||||||
friendly_name?: string
|
friendly_name?: string
|
||||||
|
friendlier_name?: string
|
||||||
last_online?: IsoDateString
|
last_online?: IsoDateString
|
||||||
modified_by?: string
|
modified_by?: string
|
||||||
os_info?: string
|
os_info?: string
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue