From ef2be62605083b39b2fdf339e2c943c5c717f510 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sun, 8 Dec 2024 16:54:19 -0600 Subject: [PATCH] Make work on Stable, Add response on claim fail --- .../API/PedestalInfoBatchProcessor.cs | 16 ++-- ...stalInfoResponseButWithPublicationState.cs | 13 --- .../PedestalInfoResponse_ButCorrect.cs | 10 +++ .../Implementation/AvatarBubbleImpl.cs | 55 ++++++++----- .../Implementation/IShareBubbleImpl.cs | 6 +- .../Implementation/ShareClaimResult.cs | 27 +++++++ .../Implementation/SpawnableBubbleImpl.cs | 61 ++++++++------ .../Networking/ModNetwork.Constants.cs | 2 + .../Networking/ModNetwork.Enums.cs | 15 +++- .../Networking/ModNetwork.Inbound.cs | 15 +++- .../Networking/ModNetwork.Main.cs | 21 +++++ .../Networking/ModNetwork.Outbound.cs | 42 +++++++--- ShareBubbles/ShareBubbles/ShareBubble.cs | 81 ++++++++++++++----- .../ShareBubbles/UI/BubbleInteract.cs | 8 +- .../ShareBubbles/UI/ReturnOnRelease.cs | 4 +- 15 files changed, 268 insertions(+), 108 deletions(-) delete mode 100644 ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponseButWithPublicationState.cs create mode 100644 ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponse_ButCorrect.cs create mode 100644 ShareBubbles/ShareBubbles/Implementation/ShareClaimResult.cs diff --git a/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs b/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs index 280a32f..00b9f41 100644 --- a/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs +++ b/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs @@ -19,11 +19,11 @@ public enum PedestalType /// public static class PedestalInfoBatchProcessor { - private static readonly Dictionary>> _pendingRequests + private static readonly Dictionary>> _pendingRequests = new() { - { PedestalType.Avatar, new Dictionary>() }, - { PedestalType.Prop, new Dictionary>() } + { PedestalType.Avatar, new Dictionary>() }, + { PedestalType.Prop, new Dictionary>() } }; private static readonly Dictionary _isBatchProcessing @@ -36,9 +36,9 @@ public static class PedestalInfoBatchProcessor private static readonly object _lock = new(); private const float BATCH_DELAY = 2f; - public static Task QueuePedestalInfoRequest(PedestalType type, string contentId) + public static Task QueuePedestalInfoRequest(PedestalType type, string contentId) { - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); lock (_lock) { @@ -62,12 +62,12 @@ public static class PedestalInfoBatchProcessor await Task.Delay(TimeSpan.FromSeconds(BATCH_DELAY)); List contentIds; - Dictionary> requestBatch; + Dictionary> requestBatch; lock (_lock) { contentIds = _pendingRequests[type].Keys.ToList(); - requestBatch = new Dictionary>(_pendingRequests[type]); + requestBatch = new Dictionary>(_pendingRequests[type]); _pendingRequests[type].Clear(); _isBatchProcessing[type] = false; //ShareBubblesMod.Logger.Msg($"Processing {type} pedestal info batch with {contentIds.Count} items"); @@ -82,7 +82,7 @@ public static class PedestalInfoBatchProcessor _ => throw new ArgumentException($"Unsupported pedestal type: {type}") }; - var response = await ApiConnection.MakeRequest>(operation, contentIds); + var response = await ApiConnection.MakeRequest>(operation, contentIds); if (response?.Data != null) { diff --git a/ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponseButWithPublicationState.cs b/ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponseButWithPublicationState.cs deleted file mode 100644 index ac764cb..0000000 --- a/ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponseButWithPublicationState.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ABI_RC.Core.Networking.API.Responses; - -namespace NAK.ShareBubbles.API.Responses; - -/// Same as PedestalInfoResponse, but with an additional field for publication state, if you could not tell by the name. -/// TODO: actually waiting on luc to add Published to PedestalInfoResponse -[Serializable] -public class PedestalInfoResponseButWithPublicationState : UgcResponse -{ - public UserDetails User { get; set; } - public bool Permitted { get; set; } - public bool Published { get; set; } -} \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponse_ButCorrect.cs b/ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponse_ButCorrect.cs new file mode 100644 index 0000000..4741a34 --- /dev/null +++ b/ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponse_ButCorrect.cs @@ -0,0 +1,10 @@ +using ABI_RC.Core.Networking.API.Responses; + +namespace NAK.ShareBubbles.API.Responses; + +[Serializable] +public class PedestalInfoResponse_ButCorrect : UgcResponse +{ + public UserDetails User { get; set; } + public bool Published { get; set; } // Client mislabelled this as Permitted, but it's actually Published +} \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs b/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs index 29c9a14..60dc79d 100644 --- a/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs +++ b/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs @@ -2,7 +2,10 @@ using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.IO; using ABI_RC.Core.Networking.API.UserWebsocket; +using ABI_RC.Core.Savior; using NAK.ShareBubbles.API; +using NAK.ShareBubbles.API.Exceptions; +using ShareBubbles.ShareBubbles.Implementation; using UnityEngine; using Object = UnityEngine.Object; @@ -36,8 +39,10 @@ namespace NAK.ShareBubbles.Impl Name = infoResponse.Name, ImageUrl = infoResponse.ImageUrl, AuthorId = infoResponse.User.Id, - IsPermitted = infoResponse.Permitted, IsPublic = infoResponse.Published, + + // Permit access if Public, Owned, or (CANNOT DO PRIVATE & SHARED CAUSE API DOESNT GIVE) + IsPermitted = infoResponse.Published || infoResponse.User.Id == MetaPort.Instance.ownerId, }; downloadedTexture = await ImageCache.GetImageAsync(details.ImageUrl); @@ -57,28 +62,40 @@ namespace NAK.ShareBubbles.Impl }); } - public void HandleClaimAccept(string userId, Action onClaimActionCompleted) + public async Task HandleClaimAccept(string userId) { - Task.Run(async () => + if (details == null) + return ShareClaimResult.Rejected(); + + try { - try + await ShareApiHelper.ShareContentAsync( + ShareApiHelper.ShareContentType.Avatar, + avatarId, + userId); + + // Add to temp shares if session access + if (bubble.Data.Access == ShareAccess.Session) { - var response = await ShareApiHelper.ShareContentAsync( - ShareApiHelper.ShareContentType.Avatar, avatarId, userId); - - // Store the temporary share to revoke when either party leaves the instance - if (bubble.Data.Access == ShareAccess.Session) - TempShareManager.Instance.AddTempShare(ShareApiHelper.ShareContentType.Avatar, - avatarId, userId); - - onClaimActionCompleted(response.IsSuccessStatusCode); + TempShareManager.Instance.AddTempShare(ShareApiHelper.ShareContentType.Avatar, + avatarId, userId); } - catch (Exception ex) - { - ShareBubblesMod.Logger.Error($"Error sharing avatar: {ex.Message}"); - onClaimActionCompleted(false); - } - }); + + return ShareClaimResult.Success(bubble.Data.Access == ShareAccess.Session); + } + catch (ContentAlreadySharedException) + { + return ShareClaimResult.AlreadyShared(); + } + catch (UserOnlyAllowsSharesFromFriendsException) + { + return ShareClaimResult.FriendsOnly(); + } + catch (Exception ex) + { + ShareBubblesMod.Logger.Error($"Error sharing avatar: {ex.Message}"); + return ShareClaimResult.Rejected(); + } } public void ViewDetailsPage() diff --git a/ShareBubbles/ShareBubbles/Implementation/IShareBubbleImpl.cs b/ShareBubbles/ShareBubbles/Implementation/IShareBubbleImpl.cs index 9551717..e6ad17e 100644 --- a/ShareBubbles/ShareBubbles/Implementation/IShareBubbleImpl.cs +++ b/ShareBubbles/ShareBubbles/Implementation/IShareBubbleImpl.cs @@ -1,4 +1,6 @@ -namespace NAK.ShareBubbles.Impl; +using ShareBubbles.ShareBubbles.Implementation; + +namespace NAK.ShareBubbles.Impl; public interface IShareBubbleImpl { @@ -8,6 +10,6 @@ public interface IShareBubbleImpl Task FetchContentInfo(); // Load the content info from the API void ViewDetailsPage(); // Open the details page for the content void EquipContent(); // Equip the content (Switch/Select) - void HandleClaimAccept(string userId, Action onClaimActionCompleted); // Handle the claim action (Share via API) + Task HandleClaimAccept(string userId); void Cleanup(); // Cleanup any resources } \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/Implementation/ShareClaimResult.cs b/ShareBubbles/ShareBubbles/Implementation/ShareClaimResult.cs new file mode 100644 index 0000000..ebb309a --- /dev/null +++ b/ShareBubbles/ShareBubbles/Implementation/ShareClaimResult.cs @@ -0,0 +1,27 @@ +using NAK.ShareBubbles.Networking; + +namespace ShareBubbles.ShareBubbles.Implementation; + +public class ShareClaimResult +{ + public ModNetwork.ClaimResponseType ResponseType { get; } + public bool RequiresSessionTracking { get; } + + private ShareClaimResult(ModNetwork.ClaimResponseType responseType, bool requiresSessionTracking = false) + { + ResponseType = responseType; + RequiresSessionTracking = requiresSessionTracking; + } + + public static ShareClaimResult Success(bool isSessionShare = false) + => new(ModNetwork.ClaimResponseType.Accepted, isSessionShare); + + public static ShareClaimResult AlreadyShared() + => new(ModNetwork.ClaimResponseType.AlreadyShared); + + public static ShareClaimResult FriendsOnly() + => new(ModNetwork.ClaimResponseType.NotAcceptingSharesFromNonFriends); + + public static ShareClaimResult Rejected() + => new(ModNetwork.ClaimResponseType.Rejected); +} \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs b/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs index a5ece85..fc29336 100644 --- a/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs +++ b/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs @@ -2,7 +2,10 @@ using ABI_RC.Core.IO; using ABI_RC.Core.Networking.API.UserWebsocket; using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; using NAK.ShareBubbles.API; +using NAK.ShareBubbles.API.Exceptions; +using ShareBubbles.ShareBubbles.Implementation; using UnityEngine; using Object = UnityEngine.Object; @@ -36,8 +39,10 @@ namespace NAK.ShareBubbles.Impl Name = infoResponse.Name, ImageUrl = infoResponse.ImageUrl, AuthorId = infoResponse.User.Id, - IsPermitted = infoResponse.Permitted, IsPublic = infoResponse.Published, + + // Permit access if Public, Owned, or (CANNOT DO PRIVATE & SHARED CAUSE API DOESNT GIVE) + IsPermitted = infoResponse.Published || infoResponse.User.Id == MetaPort.Instance.ownerId, }; downloadedTexture = await ImageCache.GetImageAsync(details.ImageUrl); @@ -57,36 +62,40 @@ namespace NAK.ShareBubbles.Impl }); } - public void HandleClaimAccept(string userId, Action onClaimActionCompleted) + public async Task HandleClaimAccept(string userId) { if (details == null) + return ShareClaimResult.Rejected(); + + try { - onClaimActionCompleted(false); - return; + await ShareApiHelper.ShareContentAsync( + ShareApiHelper.ShareContentType.Spawnable, + spawnableId, + userId); + + // Add to temp shares if session access + if (bubble.Data.Access == ShareAccess.Session) + { + TempShareManager.Instance.AddTempShare(ShareApiHelper.ShareContentType.Spawnable, + spawnableId, userId); + } + + return ShareClaimResult.Success(bubble.Data.Access == ShareAccess.Session); } - - Task.Run(async () => + catch (ContentAlreadySharedException) { - try - { - var response = await ShareApiHelper.ShareContentAsync( - ShareApiHelper.ShareContentType.Spawnable, - spawnableId, - userId); - - // Store the temporary share to revoke when either party leaves the instance - if (bubble.Data.Access == ShareAccess.Session) - TempShareManager.Instance.AddTempShare(ShareApiHelper.ShareContentType.Spawnable, - spawnableId, userId); - - onClaimActionCompleted(response.IsSuccessStatusCode); - } - catch (Exception ex) - { - ShareBubblesMod.Logger.Error($"Error sharing spawnable: {ex.Message}"); - onClaimActionCompleted(false); - } - }); + return ShareClaimResult.AlreadyShared(); + } + catch (UserOnlyAllowsSharesFromFriendsException) + { + return ShareClaimResult.FriendsOnly(); + } + catch (Exception ex) + { + ShareBubblesMod.Logger.Error($"Error sharing spawnable: {ex.Message}"); + return ShareClaimResult.Rejected(); + } } public void ViewDetailsPage() diff --git a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Constants.cs b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Constants.cs index 8aecac2..3450ed7 100644 --- a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Constants.cs +++ b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Constants.cs @@ -7,5 +7,7 @@ public static partial class ModNetwork private const string NetworkVersion = "1.0.1"; // change each time network protocol changes private const string ModId = $"NAK.SB:{NetworkVersion}"; // Cannot exceed 32 characters + private const float ClaimRequestTimeout = 30f; // 30 second timeout + #endregion Constants } \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Enums.cs b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Enums.cs index 86d9758..ac7cecd 100644 --- a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Enums.cs +++ b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Enums.cs @@ -29,9 +29,18 @@ public static partial class ModNetwork private enum MNLogLevel : byte { - Info = 0, - Warning = 1, - Error = 2 + Info, + Warning, + Error + } + + public enum ClaimResponseType : byte + { + Accepted, + Rejected, + NotAcceptingSharesFromNonFriends, + AlreadyShared, + Timeout } #endregion Enums diff --git a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Inbound.cs b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Inbound.cs index 708427a..a9caec4 100644 --- a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Inbound.cs +++ b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Inbound.cs @@ -150,11 +150,20 @@ public static partial class ModNetwork private static void HandleBubbleClaimResponse(ModNetworkMessage msg) { msg.Read(out uint bubbleNetworkId); - msg.Read(out bool claimAccepted); + msg.Read(out byte responseTypeRaw); - ShareBubbleManager.Instance.OnRemoteBubbleClaimResponse(msg.Sender, bubbleNetworkId, claimAccepted); + if (!Enum.IsDefined(typeof(ClaimResponseType), responseTypeRaw)) + { + LoggerInbound($"Invalid claim response type received: {responseTypeRaw}"); + return; + } + + ClaimResponseType responseType = (ClaimResponseType)responseTypeRaw; + + if (_pendingClaimRequests.TryGetValue(bubbleNetworkId, out PendingClaimRequest request)) + request.CompletionSource.TrySetResult(responseType); - LoggerInbound($"Bubble with ID {bubbleNetworkId} claim response: {claimAccepted}"); + LoggerInbound($"Bubble with ID {bubbleNetworkId} claim response: {responseType}"); } private static void HandleActiveBubblesRequest(ModNetworkMessage msg) diff --git a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Main.cs b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Main.cs index 2097211..be0b2bb 100644 --- a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Main.cs +++ b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Main.cs @@ -4,6 +4,7 @@ namespace NAK.ShareBubbles.Networking; public static partial class ModNetwork { + #region Mod Network Internals private static bool _isSubscribedToModNetwork; @@ -33,4 +34,24 @@ public static partial class ModNetwork } #endregion Mod Network Internals + + #region Pending Claim Requests + + private static readonly Dictionary _pendingClaimRequests = new(); + + public class PendingClaimRequest + { + public TaskCompletionSource CompletionSource { get; } + public DateTime RequestTime { get; } + public uint BubbleId { get; } + + public PendingClaimRequest(uint bubbleId) + { + CompletionSource = new TaskCompletionSource(); + RequestTime = DateTime.UtcNow; + BubbleId = bubbleId; + } + } + + #endregion } \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Outbound.cs b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Outbound.cs index 8f2d85d..a09e0e1 100644 --- a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Outbound.cs +++ b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Outbound.cs @@ -51,20 +51,44 @@ public static partial class ModNetwork LoggerOutbound($"Sending BubbleMove message for bubble {bubbleId}"); } - public static void SendBubbleClaimRequest(string bubbleOwnerId, uint bubbleNetworkId) + public static async Task SendBubbleClaimRequestAsync(string bubbleOwnerId, uint bubbleNetworkId) { if (!CanSendModNetworkMessage()) - return; + return ClaimResponseType.Rejected; - using ModNetworkMessage modMsg = new(ModId, bubbleOwnerId); - modMsg.Write((byte)MessageType.BubbleClaimRequest); - modMsg.Write(bubbleNetworkId); - modMsg.Send(); + // Create pending request + PendingClaimRequest request = new(bubbleNetworkId); + _pendingClaimRequests[bubbleNetworkId] = request; + + // Send request + using (ModNetworkMessage modMsg = new(ModId, bubbleOwnerId)) + { + modMsg.Write((byte)MessageType.BubbleClaimRequest); + modMsg.Write(bubbleNetworkId); + modMsg.Send(); + } LoggerOutbound($"Sending BubbleClaimRequest message for bubble {bubbleNetworkId}"); + + try + { + // Wait for response with timeout + using CancellationTokenSource cts = new(TimeSpan.FromSeconds(ClaimRequestTimeout)); + Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(ClaimRequestTimeout), cts.Token); + var responseTask = request.CompletionSource.Task; + + Task completedTask = await Task.WhenAny(responseTask, timeoutTask); + if (completedTask == timeoutTask) return ClaimResponseType.Timeout; + + return await responseTask; + } + finally + { + _pendingClaimRequests.Remove(bubbleNetworkId); + } } - public static void SendBubbleClaimResponse(string requesterUserId, uint bubbleNetworkId, bool success) + public static void SendBubbleClaimResponse(string requesterUserId, uint bubbleNetworkId, ClaimResponseType responseType) { if (!CanSendModNetworkMessage()) return; @@ -72,10 +96,10 @@ public static partial class ModNetwork using ModNetworkMessage modMsg = new(ModId, requesterUserId); modMsg.Write((byte)MessageType.BubbleClaimResponse); modMsg.Write(bubbleNetworkId); - modMsg.Write(success); + modMsg.Write((byte)responseType); modMsg.Send(); - LoggerOutbound($"Sending BubbleClaimResponse message for bubble {bubbleNetworkId}"); + LoggerOutbound($"Sending BubbleClaimResponse message for bubble {bubbleNetworkId}: {responseType}"); } public static void SendActiveBubblesRequest() diff --git a/ShareBubbles/ShareBubbles/ShareBubble.cs b/ShareBubbles/ShareBubbles/ShareBubble.cs index 05726a6..6a0d5a1 100644 --- a/ShareBubbles/ShareBubbles/ShareBubble.cs +++ b/ShareBubbles/ShareBubbles/ShareBubble.cs @@ -8,6 +8,8 @@ using NAK.ShareBubbles.Networking; using NAK.ShareBubbles.UI; using TMPro; using System.Collections; +using ABI_RC.Core.InteractionSystem; +using ShareBubbles.ShareBubbles.Implementation; namespace NAK.ShareBubbles; @@ -308,18 +310,62 @@ public class ShareBubble : MonoBehaviour public void RequestContentClaim() { if (!CanRequestClaim()) return; - if (!RequestClaimTimeoutInactive()) return; - lastClaimRequest = DateTime.Now; - ModNetwork.SendBubbleClaimRequest(OwnerId, Data.BubbleId); - CurrentClaimState = ClaimState.Requested; - - return; - bool RequestClaimTimeoutInactive() + // Fire and forget but with error handling~ + _ = RequestContentClaimAsync().ContinueWith(task => { - if (!lastClaimRequest.HasValue) return true; - TimeSpan timeSinceLastRequest = DateTime.Now - lastClaimRequest.Value; - return timeSinceLastRequest.TotalSeconds >= ClaimTimeout; + if (!task.IsFaulted) + return; + + ShareBubblesMod.Logger.Error($"Error requesting content claim: {task.Exception}"); + CurrentClaimState = ClaimState.Rejected; + }, TaskScheduler.FromCurrentSynchronizationContext()); + } + + private async Task RequestContentClaimAsync() + { + if (!CanRequestClaim()) + return ModNetwork.ClaimResponseType.Rejected; + + CurrentClaimState = ClaimState.Requested; + + try + { + ModNetwork.ClaimResponseType response = await ModNetwork.SendBubbleClaimRequestAsync(OwnerId, Data.BubbleId); + + switch (response) + { + case ModNetwork.ClaimResponseType.Accepted: + case ModNetwork.ClaimResponseType.AlreadyShared: + CurrentClaimState = ClaimState.Permitted; + break; + default: + case ModNetwork.ClaimResponseType.Rejected: + case ModNetwork.ClaimResponseType.Timeout: + CurrentClaimState = ClaimState.Rejected; + break; + case ModNetwork.ClaimResponseType.NotAcceptingSharesFromNonFriends: + CurrentClaimState = ClaimState.Rejected; + + string ownerName = CVRPlayerManager.Instance.TryGetPlayerName(OwnerId); + + ShareBubblesMod.Logger.Msg($"Claim request for {Data.BubbleId} rejected: " + + $"You are not friends with the owner ({ownerName}) and do not have the permission " + + $"enabled on the Community Hub to accept shares from non-friends."); + // Display in UI + ViewManager.Instance.TriggerAlert("Claim Request Rejected", + $"You are not friends with the owner ({ownerName}) and do not have the permission " + + "enabled on the Community Hub to accept shares from non-friends.", -1, false); + + break; + } + + return response; + } + catch + { + CurrentClaimState = ClaimState.Rejected; + return ModNetwork.ClaimResponseType.Rejected; } } @@ -341,22 +387,19 @@ public class ShareBubble : MonoBehaviour UpdateButtonStates(); } - public void OnRemoteWantsClaim(string requesterId) + public async void OnRemoteWantsClaim(string requesterId) { if (!IsOwnBubble) return; - // Check if requester is allowed to claim - bool isAllowed = Data.Rule == ShareRule.Everyone || - (Data.Rule == ShareRule.FriendsOnly && Friends.FriendsWith(requesterId)); - - if (!isAllowed) + // Rule check bypass attempt - reject immediately + if (Data.Rule == ShareRule.FriendsOnly && !Friends.FriendsWith(requesterId)) { - ModNetwork.SendBubbleClaimResponse(requesterId, Data.BubbleId, false); + ModNetwork.SendBubbleClaimResponse(requesterId, Data.BubbleId, ModNetwork.ClaimResponseType.Rejected); return; } - implementation.HandleClaimAccept(requesterId, - wasAccepted => ModNetwork.SendBubbleClaimResponse(requesterId, Data.BubbleId, wasAccepted)); + ShareClaimResult result = await implementation.HandleClaimAccept(requesterId); + ModNetwork.SendBubbleClaimResponse(requesterId, Data.BubbleId, result.ResponseType); } #endregion Mod Network Callbacks diff --git a/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs b/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs index ad2b4f4..d389a41 100644 --- a/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs +++ b/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs @@ -14,12 +14,12 @@ public class BubbleInteract : Interactable return Vector3.Distance(transform.position, sourcePos) < 1.5f; } - public override void OnInteractDown(InteractionContext context, ControllerRay controllerRay) + public override void OnInteractDown(ControllerRay controllerRay) { // Not used } - public override void OnInteractUp(InteractionContext context, ControllerRay controllerRay) + public override void OnInteractUp(ControllerRay controllerRay) { if (PlayerSetup.Instance.GetCurrentPropSelectionMode() != PlayerSetup.PropSelectionMode.None) @@ -39,12 +39,12 @@ public class BubbleInteract : Interactable GetComponentInParent().ViewDetailsPage(); } - public override void OnHoverEnter(InteractionContext context, ControllerRay controllerRay) + public override void OnHoverEnter() { // Not used } - public override void OnHoverExit(InteractionContext context, ControllerRay controllerRay) + public override void OnHoverExit() { // Not used } diff --git a/ShareBubbles/ShareBubbles/UI/ReturnOnRelease.cs b/ShareBubbles/ShareBubbles/UI/ReturnOnRelease.cs index b6e1eda..9c2416c 100644 --- a/ShareBubbles/ShareBubbles/UI/ReturnOnRelease.cs +++ b/ShareBubbles/ShareBubbles/UI/ReturnOnRelease.cs @@ -30,12 +30,12 @@ public class ReturnOnRelease : MonoBehaviour pickupable.onDrop.AddListener(OnPickupRelease); } - public void OnPickupGrabbed(InteractionContext _) + public void OnPickupGrabbed() { isReturning = false; } - public void OnPickupRelease(InteractionContext _) + public void OnPickupRelease() { isReturning = true; }