VEL-Connect/unity_package/Runtime/VelNetPersist.cs

180 lines
5.7 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;
public bool loading;
private const bool debugLogs = false;
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()
{
if (networkObject.isSceneObject)
{
VelConnectPersistenceManager.RegisterSceneObject(this);
}
}
private void OnDisable()
{
VelConnectPersistenceManager.UnregisterSceneObject(this);
}
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
{
Debug.LogError("TODO idk when this would happen");
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);
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;
}
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.name}");
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 =>
{
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 =>
{
VELConnectManager.PersistObject resp = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
successCallback?.Invoke(resp);
}, method: "PATCH");
}
}
public void Delete()
{
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, null, Debug.LogError,
method: "DELETE");
}
public override void ReceiveBytes(byte[] message)
{
throw new NotImplementedException();
}
}
}