diff --git a/VpSharp/src/Entities/VirtualParadiseModelObject.cs b/VpSharp/src/Entities/VirtualParadiseModelObject.cs index 8f8eca1..729e889 100644 --- a/VpSharp/src/Entities/VirtualParadiseModelObject.cs +++ b/VpSharp/src/Entities/VirtualParadiseModelObject.cs @@ -1,3 +1,4 @@ +using VpSharp.Exceptions; using VpSharp.Internal; using VpSharp.Internal.NativeAttributes; using static VpSharp.Internal.NativeMethods; @@ -53,6 +54,7 @@ public class VirtualParadiseModelObject : VirtualParadiseObject { ArgumentNullException.ThrowIfNull(action); + var taskCompletionSource = new TaskCompletionSource(); var builder = new VirtualParadiseModelObjectBuilder(Client, this, ObjectBuilderMode.Modify); await Task.Run(() => action(builder)).ConfigureAwait(false); @@ -60,9 +62,25 @@ public class VirtualParadiseModelObject : VirtualParadiseObject { nint handle = Client.NativeInstanceHandle; _ = vp_int_set(handle, IntegerAttribute.ObjectId, Id); + _ = vp_int_set(handle, IntegerAttribute.ReferenceNumber, Id); builder.ApplyChanges(); - _ = vp_object_change(handle); + Client.AddObjectUpdateCompletionSource(Id, taskCompletionSource); + + var reason = (ReasonCode)vp_object_change(handle); + if (reason != ReasonCode.Success) + { + Client.RemoveObjectUpdateCompletionSource(Id); + throw new VirtualParadiseException(reason); + } + } + + ReasonCode result = await taskCompletionSource.Task.ConfigureAwait(false); + Client.RemoveObjectUpdateCompletionSource(Id); + + if (result != ReasonCode.Success) + { + throw new VirtualParadiseException(result); } } diff --git a/VpSharp/src/VirtualParadiseClient.NativeCallbacks.cs b/VpSharp/src/VirtualParadiseClient.NativeCallbacks.cs index ac35395..36b3650 100644 --- a/VpSharp/src/VirtualParadiseClient.NativeCallbacks.cs +++ b/VpSharp/src/VirtualParadiseClient.NativeCallbacks.cs @@ -12,7 +12,7 @@ public sealed partial class VirtualParadiseClient private void SetNativeCallbacks() { // SetNativeCallback(NativeCallback.ObjectAdd, OnObjectAddNativeCallback); - // SetNativeCallback(NativeCallback.ObjectChange, OnObjectChangeNativeCallback); + SetNativeCallback(NativeCallback.ObjectChange, OnObjectChangeNativeCallback); // SetNativeCallback(NativeCallback.ObjectDelete, OnObjectDeleteNativeCallback); // SetNativeCallback(NativeCallback.GetFriends, OnGetFriendsNativeCallback); // SetNativeCallback(NativeCallback.FriendAdd, OnFriendAddNativeCallback); @@ -49,6 +49,16 @@ public sealed partial class VirtualParadiseClient taskCompletionSource.SetResult((reason, virtualParadiseObject)); } + private void OnObjectChangeNativeCallback(nint sender, ReasonCode reason, int reference) + { + if (!_objectUpdates.TryGetValue(reference, out TaskCompletionSource? taskCompletionSource)) + { + return; + } + + taskCompletionSource.SetResult(reason); + } + private void OnLoginNativeCallback(nint sender, ReasonCode reason, int reference) { _loginCompletionSource?.SetResult(reason); diff --git a/VpSharp/src/VirtualParadiseClient.Objects.cs b/VpSharp/src/VirtualParadiseClient.Objects.cs index f6c4109..20558ae 100644 --- a/VpSharp/src/VirtualParadiseClient.Objects.cs +++ b/VpSharp/src/VirtualParadiseClient.Objects.cs @@ -14,6 +14,8 @@ public sealed partial class VirtualParadiseClient private readonly ConcurrentDictionary> _objectCompletionSources = new(); private readonly ConcurrentDictionary _objects = new(); + private readonly ConcurrentDictionary> _objectUpdates = new(); + /// /// Enumerates all objects within a specified cell. @@ -151,6 +153,17 @@ public sealed partial class VirtualParadiseClient }; } + + internal void AddObjectUpdateCompletionSource(int id, TaskCompletionSource taskCompletionSource) + { + _objectUpdates.AddOrUpdate(id, _ => taskCompletionSource, (_, _) => taskCompletionSource); + } + + internal void RemoveObjectUpdateCompletionSource(int id) + { + _objectUpdates.TryRemove(id, out _); + } + private VirtualParadiseObject AddOrUpdateObject(VirtualParadiseObject obj) { ArgumentNullException.ThrowIfNull(obj);