diff --git a/SherbetVaults/Commands/VaultCommand.cs b/SherbetVaults/Commands/VaultCommand.cs
index 0324741..ab6ba0e 100644
--- a/SherbetVaults/Commands/VaultCommand.cs
+++ b/SherbetVaults/Commands/VaultCommand.cs
@@ -2,6 +2,7 @@
using Rocket.API;
using RocketExtensions.Models;
using RocketExtensions.Plugins;
+using SherbetVaults.Models;
using SherbetVaults.Models.Enums;
namespace SherbetVaults.Commands
@@ -11,43 +12,54 @@ namespace SherbetVaults.Commands
[AllowedCaller(AllowedCaller.Player)]
public class VaultCommand : RocketCommand
{
+ private VaultPlayerLock PlayerLock { get; } = new VaultPlayerLock();
+
public override async UniTask Execute(CommandContext context)
{
- var targetVault = context.Arguments.Get(0, defaultValue: string.Empty, paramName: "Vault Name");
-
- var (vaultConfig, availability) = await Plugin.VaultSelector.GetVault(context.LDMPlayer, targetVault);
-
- switch (availability)
+ using (PlayerLock.TryObtainLock(context.PlayerID, out var valid))
{
- case EVaultAvailability.BadVaultID:
- await context.ReplyKeyAsync("Vault_Fail_NotFound", targetVault);
+ if (!valid)
+ {
+ // This player is already opening a vault.
return;
+ }
- case EVaultAvailability.NotAllowed:
- await context.ReplyKeyAsync("Vault_Fail_NoPermission", targetVault);
- return;
+ var targetVault = context.Arguments.Get(0, defaultValue: string.Empty, paramName: "Vault Name");
+
+ var (vaultConfig, availability) = await Plugin.VaultSelector.GetVault(context.LDMPlayer, targetVault);
+
+ switch (availability)
+ {
+ case EVaultAvailability.BadVaultID:
+ await context.ReplyKeyAsync("Vault_Fail_NotFound", targetVault);
+ return;
+
+ case EVaultAvailability.NotAllowed:
+ await context.ReplyKeyAsync("Vault_Fail_NoPermission", targetVault);
+ return;
- case EVaultAvailability.NoVaults:
- case EVaultAvailability.NoAllowedVaults:
- await context.ReplyKeyAsync("Vaults_No_Vaults");
+ case EVaultAvailability.NoVaults:
+ case EVaultAvailability.NoAllowedVaults:
+ await context.ReplyKeyAsync("Vaults_No_Vaults");
+ return;
+ }
+
+ if (vaultConfig == null)
+ {
+ await context.ReplyKeyAsync("Vault_Fail_CannotLoad", targetVault);
return;
- }
+ }
- if (vaultConfig == null)
- {
- await context.ReplyKeyAsync("Vault_Fail_CannotLoad", targetVault);
- return;
- }
+ var vault = await Plugin.VaultManager.GetVault(context.PlayerID, vaultConfig.VaultID);
- var vault = await Plugin.VaultManager.GetVault(context.PlayerID, vaultConfig.VaultID);
+ if (vault == null)
+ {
+ await context.ReplyKeyAsync("Vault_Fail_CannotLoad", vaultConfig.VaultID);
+ return;
+ }
- if (vault == null)
- {
- await context.ReplyKeyAsync("Vault_Fail_CannotLoad", vaultConfig.VaultID);
- return;
+ await vault.OpenForPlayerAsync(context.LDMPlayer);
}
-
- await vault.OpenForPlayerAsync(context.LDMPlayer);
}
private new SherbetVaultsPlugin Plugin =>
diff --git a/SherbetVaults/Models/VaultPlayerLock.cs b/SherbetVaults/Models/VaultPlayerLock.cs
new file mode 100644
index 0000000..e781fce
--- /dev/null
+++ b/SherbetVaults/Models/VaultPlayerLock.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Concurrent;
+
+namespace SherbetVaults.Models
+{
+ ///
+ /// Helps prevent client-side graphical item graphical glitches if a player spams the vault command.
+ ///
+ public class VaultPlayerLock
+ {
+ public ConcurrentDictionary m_PlayerBlocks = new ConcurrentDictionary();
+
+ public OpenBlockToken TryObtainLock(ulong player, out bool valid)
+ {
+ if (m_PlayerBlocks.TryGetValue(player, out var blocked))
+ {
+ if (blocked)
+ {
+ valid = false;
+ return default;
+ }
+ }
+ m_PlayerBlocks[player] = true;
+ valid = true;
+ return new OpenBlockToken(player, this);
+ }
+
+ private void Release(ulong player)
+ {
+ m_PlayerBlocks[player] = false;
+ }
+
+ public struct OpenBlockToken : IDisposable
+ {
+ public ulong PlayerID { get; }
+ private VaultPlayerLock Parent { get; }
+
+ private bool Disposed;
+
+ public OpenBlockToken(ulong playerID, VaultPlayerLock parent)
+ {
+ Disposed = false;
+ PlayerID = playerID;
+ Parent = parent;
+ }
+
+ public void Dispose()
+ {
+ if (!Disposed)
+ {
+ Disposed = true;
+ Parent?.Release(PlayerID);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/SherbetVaults/SherbetVaults.csproj b/SherbetVaults/SherbetVaults.csproj
index 5c1417b..1109806 100644
--- a/SherbetVaults/SherbetVaults.csproj
+++ b/SherbetVaults/SherbetVaults.csproj
@@ -442,6 +442,7 @@
+