Files
BuYuHouDuan/FishGameSrc/FishGameService/GameService/IBulletTracker.cs
T
2026-10-12 16:22:04 +08:00

108 lines
3.4 KiB
C#

using System.Collections.Concurrent;
namespace FishGameService.GameService
{
public interface IBulletTracker
{
void Add(string roomId, string userId, IEnumerable<string> bulletIds);
bool TryConsume(string roomId, string userId, string bulletId);
int Count(string roomId, string userId);
void Clear(string roomId, string userId);
}
public sealed class BulletTracker : IBulletTracker
{
private const int MaxBulletsPerPlayer = 100;
private readonly ConcurrentDictionary<string, PlayerBullets> _players = new();
public void Add(string roomId, string userId, IEnumerable<string> bulletIds)
{
var bullets = _players.GetOrAdd(Key(roomId, userId), _ => new PlayerBullets());
lock (bullets.SyncRoot)
{
foreach (var bulletId in bulletIds)
{
if (string.IsNullOrWhiteSpace(bulletId) || !bullets.Ids.Add(bulletId))
continue;
bullets.Order.Enqueue(bulletId);
}
while (bullets.Ids.Count > MaxBulletsPerPlayer && bullets.Order.Count > 0)
bullets.Ids.Remove(bullets.Order.Dequeue());
}
}
public bool TryConsume(string roomId, string userId, string bulletId)
{
if (string.IsNullOrWhiteSpace(bulletId)
|| !_players.TryGetValue(Key(roomId, userId), out var bullets))
return false;
lock (bullets.SyncRoot)
return bullets.Ids.Remove(bulletId);
}
public int Count(string roomId, string userId)
{
if (!_players.TryGetValue(Key(roomId, userId), out var bullets))
return 0;
lock (bullets.SyncRoot)
return bullets.Ids.Count;
}
public void Clear(string roomId, string userId)
{
_players.TryRemove(Key(roomId, userId), out _);
}
private static string Key(string roomId, string userId) => $"{roomId}|{userId}";
private sealed class PlayerBullets
{
public object SyncRoot { get; } = new();
public HashSet<string> Ids { get; } = new(StringComparer.Ordinal);
public Queue<string> Order { get; } = new();
}
}
public interface IFishKillTracker
{
bool TryAdd(string roomId, string fishId);
void Clear(string roomId);
}
public sealed class FishKillTracker : IFishKillTracker
{
private const int MaxFishPerRoom = 50;
private readonly ConcurrentDictionary<string, RoomFishIds> _rooms = new();
public bool TryAdd(string roomId, string fishId)
{
var room = _rooms.GetOrAdd(roomId, _ => new RoomFishIds());
lock (room.SyncRoot)
{
if (!room.Ids.Add(fishId))
return false;
room.Order.Enqueue(fishId);
while (room.Ids.Count > MaxFishPerRoom && room.Order.Count > 0)
room.Ids.Remove(room.Order.Dequeue());
return true;
}
}
public void Clear(string roomId) => _rooms.TryRemove(roomId, out _);
private sealed class RoomFishIds
{
public object SyncRoot { get; } = new();
public HashSet<string> Ids { get; } = new(StringComparer.Ordinal);
public Queue<string> Order { get; } = new();
}
}
}