VEL-Connect/unity_package/Runtime/VelNetPersist.cs

227 lines
7.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using UnityEngine;
using VelNet;
namespace VELConnect
{
public class VelNetPersist : NetworkComponent
{
private const float interval = 5f;
private double nextUpdate;
private bool loading;
private const bool debugLogs = true;
public string persistId;
private void Update()
{
if (Time.timeAsDouble > nextUpdate && VelNetManager.InRoom && !loading)
{
nextUpdate = Time.timeAsDouble + interval + UnityEngine.Random.Range(0, interval);
if (networkObject.IsMine)
{
Save();
}
}
}
private void OnEnable()
{
VelNetManager.OnJoinedRoom += OnJoinedRoom;
}
private void OnDisable()
{
VelNetManager.OnJoinedRoom -= OnJoinedRoom;
}
private void OnJoinedRoom(string roomName)
{
Load();
}
private void Load()
{
loading = true;
if (debugLogs) Debug.Log($"[VelNetPersist] Loading {name}");
if (networkObject.isSceneObject)
{
// 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}')",
VELConnectManager.GetRequestCallback(
VELConnectManager.VelConnectUrl +
$"/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.network_id == networkObject.sceneNetworkId.ToString() && i.room == VelNetManager.Room).ToList();
if (obj.items.Count < 1)
{
Debug.LogError("[VelNetPersist] No data found for " + name);
loading = false;
return;
}
else if (obj.items.Count > 1)
{
Debug.LogError(
$"[VelNetPersist] Multiple records found for app='{Application.productName}' && room='{VelNetManager.Room}' && network_id='{networkObject.sceneNetworkId}'. Using the first one.");
}
LoadData(obj.items.FirstOrDefault());
}, s => { loading = false; });
}
else
{
VELConnectManager.GetRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId, s =>
{
VELConnectManager.PersistObject obj = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
LoadData(obj);
},
s => { loading = false; });
}
}
public void LoadData(VELConnectManager.PersistObject obj)
{
if (string.IsNullOrEmpty(obj.data))
{
Debug.LogError($"[VelNetPersist] No data found for {name}");
loading = false;
return;
}
persistId = obj.id;
using BinaryReader reader = new BinaryReader(new MemoryStream(Convert.FromBase64String(obj.data)));
networkObject.UnpackState(reader);
//
// List<SyncState> syncStateComponents = networkObject.syncedComponents.OfType<SyncState>().ToList();
// if (obj.data.Count != syncStateComponents.Count)
// {
// Debug.LogError($"[VelNetPersist] Different number of components");
// loading = false;
// return;
// }
//
// for (int i = 0; i < syncStateComponents.Count; i++)
// {
// Debug.Log($"[VelNetPersist] Unpacking {obj.name} {syncStateComponents[i].GetType().Name}");
// syncStateComponents[i].UnpackState(Convert.FromBase64String(obj.data[i].state));
// }
if (debugLogs) Debug.Log($"[VelNetPersist] Loaded {name}");
loading = false;
}
public void Save(Action<VELConnectManager.PersistObject> successCallback = null)
{
if (debugLogs) Debug.Log($"[VelNetPersist] Saving {name}");
List<SyncState> syncStateComponents = networkObject.syncedComponents.OfType<SyncState>().ToList();
if (networkObject == null)
{
Debug.LogError("NetworkObject is null on SyncState", this);
return;
}
// List<VELConnectManager.ComponentState> componentData = new List<VELConnectManager.ComponentState>();
// foreach (SyncState syncState in syncStateComponents)
// {
// if (syncState == null)
// {
// Debug.LogError("SyncState is null for Persist", this);
// return;
// }
//
// if (syncState.networkObject == null)
// {
// Debug.LogError("Network Object is null for SyncState", syncState);
// return;
// }
//
// componentData.Add(new VELConnectManager.ComponentState()
// {
// componentIdx = networkObject.syncedComponents.IndexOf(syncState),
// state = Convert.ToBase64String(syncState.PackState())
// });
// }
using BinaryWriter writer = new BinaryWriter(new MemoryStream());
networkObject.PackState(writer);
string data = Convert.ToBase64String(((MemoryStream)writer.BaseStream).ToArray());
// if we have a persistId, update the record, otherwise create a new one
if (string.IsNullOrEmpty(persistId))
{
Debug.LogWarning($"We don't have an existing persistId, so we are creating a new record for {networkObject.prefabName}");
VELConnectManager.PostRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records", JsonConvert.SerializeObject(
new VELConnectManager.PersistObject()
{
app = Application.productName,
room = VelNetManager.Room,
network_id = networkObject.sceneNetworkId.ToString(),
spawned = !networkObject.isSceneObject,
name = networkObject.isSceneObject ? networkObject.name : networkObject.prefabName,
data = data,
}), null, s =>
{
Debug.Log(s);
VELConnectManager.PersistObject resp = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
persistId = resp.id;
successCallback?.Invoke(resp);
});
}
else
{
VELConnectManager.PostRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId, JsonConvert.SerializeObject(
new VELConnectManager.PersistObject()
{
app = Application.productName,
room = VelNetManager.Room,
network_id = networkObject.sceneNetworkId.ToString(),
spawned = !networkObject.isSceneObject,
name = networkObject.prefabName,
data = data,
}), null, s =>
{
Debug.Log(s);
VELConnectManager.PersistObject resp = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
successCallback?.Invoke(resp);
}, method: "PATCH");
}
}
public void Delete(Action<VELConnectManager.PersistObject> successCallback = null)
{
if (string.IsNullOrEmpty(persistId))
{
Debug.LogError("We can't delete an object that doesn't have a persistId");
return;
}
VELConnectManager.PostRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId, null, null,
s =>
{
Debug.Log(s);
VELConnectManager.PersistObject resp = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
successCallback?.Invoke(resp);
}, Debug.LogError,
method: "DELETE");
}
public override void ReceiveBytes(byte[] message)
{
throw new NotImplementedException();
}
}
}