Архитектура многопользовательской игровой платформы SignalR - PullRequest
0 голосов
/ 06 марта 2019

Я работаю на multiplayer game платформе, которая будет иметь несколько (в основном turn-based) multiplayer games. Основная идея заключается в том, что каждый player подключается к определенному game, и в этом game их будет несколько lobbies. Пользователь может ввести каждый lobby, где он будет видеть других игроков в lobby, а также game instances (открытые игры) в этом lobby. Пользователи также смогут создавать новые game instance в пределах lobby и ждать присоединения других игроков, чтобы начать игру.

У меня проблема с архитектурой текущего состояния игрока. Разве это нормально - иметь какую-то модель игрока (которая на самом деле была бы просто расширенной моделью пользователя), в которой сохраняется все состояние игрока? Примерно так:

public interface IPlayer
{
    Guid UserId { get; set; }
    string Name { get; set; }

    Guid GameDefinitionId { get; set; }
    Guid? LobbyId { get; set; }
    Guid? GameId { get; set; }
}
  • GameDefinitionId - Определяет, какое определение игры (покер, блэкджек и т. Д.) Выбрал пользователь. Каждая из игр имеет свой собственный hub, поэтому, когда пользователь подключен к hub (конкретному game), создается экземпляр Player с указанным GameDefinitionId, который является идентификатором этого game (поэтому его нет опционально в модели).
  • LobbyId - Необязательный идентификатор lobby, показывающий, что пользователь находится в указанном лобби.
  • GameId - Необязательный game идентификатор экземпляра, показывающий, что пользователь находится в указанном game.

Изменяя эти свойства (в настоящее время список IPlayer равен in-memory, но при необходимости я переместил бы его на database позже), я могу точно сказать, где находится пользователь, и контролировать его состояние. Обратите внимание, что пользователь не может быть в нескольких лобби или играх одновременно. Конечно, каждое изменение подтверждается service, и если изменение действительно, все заинтересованные clients уведомляются.

Это базовый концентратор, который каждая игра должна реализовывать

public abstract class MultiplayerGameHub : HubBase
{
    protected IPlayerHandler PlayerHandler { get; private set; }        

    public MultiplayerGameHub(
        IOnlineClientManager onlineClientManager,
        ISessionProvider sessionProvider,
        IPlayerHandler playerHandler)
        : base(onlineClientManager, sessionProvider)
    {
        PlayerHandler = playerHandler;
    }

    public virtual async Task Connect()
    {
        var gameDefinition = await GetGameDefinitionAsync();
        if (gameDefinition == null)
        {
            throw new HubException("Unknown game definition");
        }

        await PlayerHandler.ConnectAsync(Context.ConnectionId, gameDefinition.Id);
    }

    public virtual Task Disconnect()
    {
        return PlayerHandler.DisconnectAsync(Context.ConnectionId);
    }

    public Task JoinLobby(JoinLobbyParams model)
    {
        return PlayerHandler.JoinLobbyAsync(Context.ConnectionId, model.LobbyId);
    }

    public Task LeaveLobby()
    {
        return PlayerHandler.LeaveLobbyAsync(Context.ConnectionId);
    }

    public abstract Task<IGameDefinition> GetGameDefinitionAsync();
}

Это хороший подход, или я должен обращаться с этим по-другому?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...