private async Task SubmitTransaction(TransactionCommand cmd)
        {
            using (await _transactionLock.LockAsync())
            {
                _logger.Log(LogLevel.Debug, "gameSession", "Transaction submitted.", new
                {
                    map     = PlayerMap,
                    players = _players.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Id),
                    Cmd     = cmd
                });
                var responses = await Task.WhenAll(PlayerMap.Select(async p =>
                {
                    IScenePeerClient peer = null;
                    _players.TryGetValue(p.Value, out peer);

                    TransactionResponse response = null;
                    if (peer != null)
                    {
                        try
                        {
                            var r     = await peer.RpcTask <TransactionCommand, TransactionResponse>(VALIDATE_TRANSACTION_RPC, cmd);
                            r.Success = true;
                            response  = r;
                        }
                        catch (Exception)//Failed to execute transaction update on client
                        {
                            response = new TransactionResponse {
                                Success = false
                            };
                        }
                    }
                    return(Tuple.Create(p.Key, response));
                }));

                var receivedResponses = responses.Where(t => t.Item2 != null);

                var isValid = true;
                if (receivedResponses.Any())
                {
                    isValid = receivedResponses.All(t => t.Item2.Success) && receivedResponses.Select(t => t.Item2).Distinct().Count() == 1;
                }

                if (!isValid)
                {
                    await EnsureTransactionFailed($"game states hash comparaison failed: [{string.Join(", ", responses.Select(t => $"'{t.Item1}' => {t.Item2}"))}]");
                }
                var hash = responses.FirstOrDefault(r => r.Item2 != null)?.Item2.Hash;
                _commands.Add(new TransactionLogItem {
                    Command = cmd, ResultHash = hash ?? 0, HashAvailable = hash.HasValue
                });
            }
        }
        /// <summary>
        /// Adds a command to the game state
        /// </summary>
        /// <param name="userId">User that issued the command</param>
        /// <param name="playerId">Player that issued the command. (Different from userId to allow IA players or several players on a single client)</param>
        /// <param name="command">The command name</param>
        /// <param name="args"></param>
        /// <param name="updatedGameHash"></param>
        /// <returns></returns>
        public Task SubmitTransaction(string userId, string playerId, string command, JObject args)
        {
            if (userId != null)
            {
                if (playerId == null)
                {
                    throw new ClientException("Missing playerId");
                }
                string u;

                if (!PlayerMap.TryGetValue(playerId, out u))
                {
                    throw new InvalidOperationException("The user is not in the PlayerMap");
                }
                if (u != userId)
                {
                    throw new InvalidOperationException("The user cannot handler the specified playerId");
                }
                if (!_players.ContainsKey(userId))
                {
                    throw new InvalidOperationException("The user is not connected");
                }
            }
            if (command == null)
            {
                throw new ClientException("Missing command");
            }

            var cmd = new TransactionCommand
            {
                Cmd            = command,
                Arguments      = args.ToString(),
                CreatedOn      = DateTime.UtcNow,
                IssuerPlayerId = playerId,
                IssuerUserId   = userId,
                FinalStepId    = CurrrentStepId++
            };

            return(SubmitTransaction(cmd));
        }