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 @@ +