using Microsoft.Extensions.Logging; using Yuanshen.Gameserver.Game; namespace Yuanshen.Gameserver.Database; internal sealed class PlayerPersistence { private readonly Player _player; private readonly GameState _state; private readonly IPlayerRepository _repository; private readonly PlayerSessionRegistry _registry; private readonly ILogger _logger; private long _sessionId; public PlayerPersistence(Player player, GameState state, IPlayerRepository repository, PlayerSessionRegistry registry, ILogger logger) { _player = player; _state = state; _repository = repository; _registry = registry; _logger = logger; } public uint PlayerUid => _player.Uid; public void Bind(long sessionId) => _sessionId = sessionId; public void Acquire() => _registry.Acquire(_player.Uid, _sessionId); public void Release() => _registry.Release(_player.Uid, _sessionId); public ValueTask LoadAsync() => _repository.LoadAsync(_player.Uid); public async ValueTask SaveAsync() { if (!_player.IsInitialized) return false; if (!_registry.IsOwner(_player.Uid, _sessionId)) { _logger.LogDebug("Skipped save for player {uid}: session {sessionId} is stale", _player.Uid, _sessionId); return false; } try { bool saved = await _repository.SaveAsync(_player.ToRecord(_state.CurrentPos)); if (saved) _logger.LogDebug("Persisted player {uid} at ({x}, {y}, {z}), killed={killed}", _player.Uid, _state.CurrentPos.X, _state.CurrentPos.Y, _state.CurrentPos.Z, _player.KilledNodeIds.Count); return saved; } catch (Exception exception) { _logger.LogError("Failed to persist player {uid}: {message}", _player.Uid, exception.Message); return false; } } }