VEL-Connect/unity_package/Runtime/VELConnectPersistenceManage...

156 lines
5.2 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
using VelNet;
namespace VELConnect
{
public class VelConnectPersistenceManager : MonoBehaviour
{
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()
{
instance = this;
}
private void OnEnable()
{
VelNetManager.OnJoinedRoom += OnJoinedRoom;
}
private void OnDisable()
{
VelNetManager.OnJoinedRoom -= OnJoinedRoom;
}
private void OnJoinedRoom(string roomName)
{
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)
{
List<VELConnectManager.PersistObject> spawnedItems = allResults.Where(i => i.spawned && i.room == VelNetManager.Room).ToList();
foreach (VELConnectManager.PersistObject persistObject in spawnedItems)
{
if (string.IsNullOrEmpty(persistObject.data))
{
Debug.LogError("Persisted object has no data");
continue;
}
NetworkObject spawnedObj = VelNetManager.NetworkInstantiate(persistObject.name, Convert.FromBase64String(persistObject.data));
VelNetPersist persist = spawnedObj.GetComponent<VelNetPersist>();
persist.persistId = persistObject.id;
persist.LoadData(persistObject);
}
}
// 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 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 DestroySpawnedObject(NetworkObject obj)
{
VelNetPersist[] persistedComponents = obj.GetComponents<VelNetPersist>();
if (persistedComponents.Length > 1)
{
Debug.LogError("NetworkObject has more than one VelNetPersist component");
}
foreach (VelNetPersist velNetPersist in persistedComponents)
{
velNetPersist.Delete();
}
}
}
}