mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 06:19:22 +00:00
Make work on Stable, Add response on claim fail
This commit is contained in:
parent
e7b2ad4c31
commit
ef2be62605
15 changed files with 268 additions and 108 deletions
|
@ -19,11 +19,11 @@ public enum PedestalType
|
|||
/// </summary>
|
||||
public static class PedestalInfoBatchProcessor
|
||||
{
|
||||
private static readonly Dictionary<PedestalType, Dictionary<string, TaskCompletionSource<PedestalInfoResponseButWithPublicationState>>> _pendingRequests
|
||||
private static readonly Dictionary<PedestalType, Dictionary<string, TaskCompletionSource<PedestalInfoResponse_ButCorrect>>> _pendingRequests
|
||||
= new()
|
||||
{
|
||||
{ PedestalType.Avatar, new Dictionary<string, TaskCompletionSource<PedestalInfoResponseButWithPublicationState>>() },
|
||||
{ PedestalType.Prop, new Dictionary<string, TaskCompletionSource<PedestalInfoResponseButWithPublicationState>>() }
|
||||
{ PedestalType.Avatar, new Dictionary<string, TaskCompletionSource<PedestalInfoResponse_ButCorrect>>() },
|
||||
{ PedestalType.Prop, new Dictionary<string, TaskCompletionSource<PedestalInfoResponse_ButCorrect>>() }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<PedestalType, bool> _isBatchProcessing
|
||||
|
@ -36,9 +36,9 @@ public static class PedestalInfoBatchProcessor
|
|||
private static readonly object _lock = new();
|
||||
private const float BATCH_DELAY = 2f;
|
||||
|
||||
public static Task<PedestalInfoResponseButWithPublicationState> QueuePedestalInfoRequest(PedestalType type, string contentId)
|
||||
public static Task<PedestalInfoResponse_ButCorrect> QueuePedestalInfoRequest(PedestalType type, string contentId)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<PedestalInfoResponseButWithPublicationState>();
|
||||
var tcs = new TaskCompletionSource<PedestalInfoResponse_ButCorrect>();
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
|
@ -62,12 +62,12 @@ public static class PedestalInfoBatchProcessor
|
|||
await Task.Delay(TimeSpan.FromSeconds(BATCH_DELAY));
|
||||
|
||||
List<string> contentIds;
|
||||
Dictionary<string, TaskCompletionSource<PedestalInfoResponseButWithPublicationState>> requestBatch;
|
||||
Dictionary<string, TaskCompletionSource<PedestalInfoResponse_ButCorrect>> requestBatch;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
contentIds = _pendingRequests[type].Keys.ToList();
|
||||
requestBatch = new Dictionary<string, TaskCompletionSource<PedestalInfoResponseButWithPublicationState>>(_pendingRequests[type]);
|
||||
requestBatch = new Dictionary<string, TaskCompletionSource<PedestalInfoResponse_ButCorrect>>(_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<IEnumerable<PedestalInfoResponseButWithPublicationState>>(operation, contentIds);
|
||||
var response = await ApiConnection.MakeRequest<IEnumerable<PedestalInfoResponse_ButCorrect>>(operation, contentIds);
|
||||
|
||||
if (response?.Data != 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; }
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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<bool> onClaimActionCompleted)
|
||||
public async Task<ShareClaimResult> HandleClaimAccept(string userId)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
if (details == null)
|
||||
return ShareClaimResult.Rejected();
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await ShareApiHelper.ShareContentAsync<BaseResponse>(
|
||||
ShareApiHelper.ShareContentType.Avatar, avatarId, userId);
|
||||
await ShareApiHelper.ShareContentAsync<BaseResponse>(
|
||||
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);
|
||||
}
|
||||
catch (Exception ex)
|
||||
// Add to temp shares if session access
|
||||
if (bubble.Data.Access == ShareAccess.Session)
|
||||
{
|
||||
ShareBubblesMod.Logger.Error($"Error sharing avatar: {ex.Message}");
|
||||
onClaimActionCompleted(false);
|
||||
TempShareManager.Instance.AddTempShare(ShareApiHelper.ShareContentType.Avatar,
|
||||
avatarId, userId);
|
||||
}
|
||||
});
|
||||
|
||||
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()
|
||||
|
|
|
@ -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<bool> onClaimActionCompleted); // Handle the claim action (Share via API)
|
||||
Task<ShareClaimResult> HandleClaimAccept(string userId);
|
||||
void Cleanup(); // Cleanup any resources
|
||||
}
|
27
ShareBubbles/ShareBubbles/Implementation/ShareClaimResult.cs
Normal file
27
ShareBubbles/ShareBubbles/Implementation/ShareClaimResult.cs
Normal file
|
@ -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);
|
||||
}
|
|
@ -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<bool> onClaimActionCompleted)
|
||||
public async Task<ShareClaimResult> HandleClaimAccept(string userId)
|
||||
{
|
||||
if (details == null)
|
||||
return ShareClaimResult.Rejected();
|
||||
|
||||
try
|
||||
{
|
||||
onClaimActionCompleted(false);
|
||||
return;
|
||||
await ShareApiHelper.ShareContentAsync<BaseResponse>(
|
||||
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<BaseResponse>(
|
||||
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()
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
LoggerInbound($"Bubble with ID {bubbleNetworkId} claim response: {claimAccepted}");
|
||||
ClaimResponseType responseType = (ClaimResponseType)responseTypeRaw;
|
||||
|
||||
if (_pendingClaimRequests.TryGetValue(bubbleNetworkId, out PendingClaimRequest request))
|
||||
request.CompletionSource.TrySetResult(responseType);
|
||||
|
||||
LoggerInbound($"Bubble with ID {bubbleNetworkId} claim response: {responseType}");
|
||||
}
|
||||
|
||||
private static void HandleActiveBubblesRequest(ModNetworkMessage msg)
|
||||
|
|
|
@ -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<uint, PendingClaimRequest> _pendingClaimRequests = new();
|
||||
|
||||
public class PendingClaimRequest
|
||||
{
|
||||
public TaskCompletionSource<ClaimResponseType> CompletionSource { get; }
|
||||
public DateTime RequestTime { get; }
|
||||
public uint BubbleId { get; }
|
||||
|
||||
public PendingClaimRequest(uint bubbleId)
|
||||
{
|
||||
CompletionSource = new TaskCompletionSource<ClaimResponseType>();
|
||||
RequestTime = DateTime.UtcNow;
|
||||
BubbleId = bubbleId;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
|
@ -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<ClaimResponseType> 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()
|
||||
|
|
|
@ -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);
|
||||
// Fire and forget but with error handling~
|
||||
_ = RequestContentClaimAsync().ContinueWith(task =>
|
||||
{
|
||||
if (!task.IsFaulted)
|
||||
return;
|
||||
|
||||
ShareBubblesMod.Logger.Error($"Error requesting content claim: {task.Exception}");
|
||||
CurrentClaimState = ClaimState.Rejected;
|
||||
}, TaskScheduler.FromCurrentSynchronizationContext());
|
||||
}
|
||||
|
||||
private async Task<ModNetwork.ClaimResponseType> RequestContentClaimAsync()
|
||||
{
|
||||
if (!CanRequestClaim())
|
||||
return ModNetwork.ClaimResponseType.Rejected;
|
||||
|
||||
CurrentClaimState = ClaimState.Requested;
|
||||
|
||||
return;
|
||||
bool RequestClaimTimeoutInactive()
|
||||
try
|
||||
{
|
||||
if (!lastClaimRequest.HasValue) return true;
|
||||
TimeSpan timeSinceLastRequest = DateTime.Now - lastClaimRequest.Value;
|
||||
return timeSinceLastRequest.TotalSeconds >= ClaimTimeout;
|
||||
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
|
||||
|
|
|
@ -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<ShareBubble>().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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue