Example #1
0
        public async Task GetP2PData(RequestContext <IScenePeerClient> ctx)
        {
            var provider = ctx.ReadObject <string>();

            switch (provider)
            {
            case "userId":
            {
                var userId = ctx.ReadObject <string>();
                var peer   = await _userSessions.GetPeer(userId);

                if (peer == null)
                {
                    throw new ClientException($"The user '{userId}' is not connected.");
                }

                var r = await _natIndex.TryGet(peer.Id.ToString());

                if (!r.Success)
                {
                    throw new ClientException($"The user '{userId}' (peer : '{peer.Id}') is not available for p2p (no p2p data set).");
                }
                else
                {
                    ctx.SendValue(r.Value.P2PTransports);
                }
                break;
            }

            case "peerId":
            {
                var peerId = ctx.ReadObject <long>();
                var r      = await _natIndex.TryGet(peerId.ToString());

                if (!r.Success)
                {
                    ctx.SendValue(new Dictionary <string, string>());
                }
                else
                {
                    ctx.SendValue(r.Value.P2PTransports);
                }
                break;
            }

            default:
                throw new ClientException($"Unknown provider '{provider}'.");
            }
        }
Example #2
0
        public async Task Report(RequestContext <IScenePeerClient> ctx)
        {
            try
            {
                var user = await _userSessions.GetUser(ctx.RemotePeer);

                var reportDto = ctx.ReadObject <ReportDto>();
                var report    = new Report
                {
                    ReportUserId   = user.Id,
                    ReportedUserId = reportDto.ReportedUserId,
                    ReportDate     = DateTimeOffset.FromUnixTimeSeconds(reportDto.Timestamp).DateTime,
                    Message        = reportDto.Message,
                    Category       = reportDto.Category,
                    CustomData     = reportDto.CustomData,
                };
                await _reportPlayers.ReportPlayer(report);
            }
            catch (Exception ex)
            {
                _logger.Log(LogLevel.Error, _logCategory, "Server error, report doesn't save", ex.Message);
                throw new ClientException("Server error, report doesn't save");
            }

            ctx.SendValue <string>("Report saved");
        }
        public Task GetPlayerData(RequestContext <IScenePeerClient> ctx)
        {
            var playerId = ctx.ReadObject <string>();

            ctx.SendValue(_service.GetPlayerData(playerId));
            return(Task.CompletedTask);
        }
Example #4
0
        public async Task Message(RequestContext <IScenePeerClient> ctx)
        {
            try
            {
                await _chat.OnMessageReceived(ctx.RemotePeer, ctx.ReadObject <string>(), (messageDto, destination) =>
                {
                    if (messageDto == null)
                    {
                        throw new InvalidOperationException("Message recieved internal error");
                    }

                    if (destination.HasFlag(DestinationType.Others))
                    {
                        _scene.Broadcast("receivemessage", messageDto);
                    }

                    if (destination.HasFlag(DestinationType.Self))
                    {
                        ctx.SendValue(messageDto);
                    }
                });
            }
            catch (Exception ex)
            {
                _logger.Log(LogLevel.Error, _logCategory, "Error occured when server received message", ex);
                throw new ClientException(ex.Message);
            }
        }
Example #5
0
        public async Task Cursor(RequestContext <IScenePeerClient> ctx)
        {
            var cursor = ctx.ReadObject <string>();
            var result = await _leaderboard.QueryCursor(cursor);

            ctx.SendValue(result);
        }
Example #6
0
        public async Task GetShard(RequestContext <IScenePeerClient> ctx)
        {
            var client = await _management.GetApplicationClient();

            // Get data send by client
            var mapId   = ctx.ReadObject <string>();
            var shardId = StringToHex(mapId);
            var shard   = await client.GetScene(shardId);

            if (shard == null)
            {
                var metadata = Newtonsoft.Json.Linq.JObject.FromObject(new { gameSession = new Server.Plugins.GameSession.GameSessionConfiguration {
                                                                                 Public = true, canRestart = true, UserData = mapId
                                                                             } });

                var template = global::Server.App.GAMESESSION_TEMPLATE;

                _logger.Log(LogLevel.Trace, "LocatorController", $"Creating scene {shardId} for map {mapId}", new { mapId, shardId });

                await client.CreateScene(
                    shardId,
                    template,
                    false,
                    metadata,
                    false);
            }
            var token = await client.CreateConnectionToken(shardId, "");

            ctx.SendValue(token);
        }
Example #7
0
        public Task <bool> ExtractData(string provider, RequestContext <IScenePeerClient> request, Group group)
        {
            //logger.Log(LogLevel.Info, "gamefinder", "Received player", new { group = group });
            var parameters = request.ReadObject <GameFinderParameters>();

            group.GroupData.Options = parameters;

            return(Task.FromResult(true));
        }
        public Task Push(RequestContext <IScenePeerClient> ctx)
        {
            var docs = ctx.ReadObject <List <Document> >();

            foreach (var doc in docs)
            {
                _analytics.Push(doc.Type, doc.Content);
            }

            return(Task.FromResult(true));
        }
        public async Task Submit(RequestContext <IScenePeerClient> ctx)
        {
            var userId = (await _sessions.GetUser(ctx.RemotePeer))?.Id;

            if (userId == null)
            {
                throw new ClientException("Authentication required");
            }
            var dto = ctx.ReadObject <TransactionDto>();
            await _game.SubmitTransaction(userId, dto.PlayerId, dto.Command, JObject.Parse(dto.Args));
        }
Example #10
0
        public async Task GetUserFromBearerToken(RequestContext <IScenePeerClient> ctx)
        {
            var app = await _environment.GetApplicationInfos();

            var data = TokenGenerator.DecodeToken <BearerTokenData>(ctx.ReadObject <string>(), app.PrimaryKey);

            if (data == null)
            {
                throw new ClientException("Invalid Token");
            }
            ctx.SendValue(data.UserId);
        }
Example #11
0
        public async Task UpdateP2PData(RequestContext <IScenePeerClient> ctx)
        {
            var user = await _userSessions.GetUser(ctx.RemotePeer);

            if (user == null)
            {
                //_logger.Trace("natTraversal", $"Failed to update nat traversal data: the peer '{ctx.RemotePeer.Id}' is not logged in.");
                throw new ClientException($"The peer '{ctx.RemotePeer.Id}' is not logged in.");
            }
            var p2p = ctx.ReadObject <Dictionary <string, string> >();
            var r   = await _natIndex.AddOrUpdateWithRetries(ctx.RemotePeer.Id.ToString(), new NatPunchthroughData { P2PTransports = p2p }, d => d.SetP2P(p2p));
        }
        public async Task SetPlayerData(RequestContext <IScenePeerClient> ctx)
        {
            var player = await _sessions.GetUser(ctx.RemotePeer);

            var data = ctx.ReadObject <MessagePackObject>();

            if (player == null)
            {
                throw new ClientException("Player not authenticated.");
            }
            _service.SetPlayerData(player.Id, data);
        }
Example #13
0
        public async Task Query(RequestContext <IScenePeerClient> ctx)
        {
            var rq = ctx.ReadObject <LeaderboardQuery>();

            if (rq.Count <= 0)
            {
                rq.Count = 10;
            }
            var r = await _leaderboard.Query(rq);

            ctx.SendValue(r);
        }
        public async Task AddPlayer(RequestContext <IScenePeerClient> ctx)
        {
            var userId = (await _sessions.GetUser(ctx.RemotePeer))?.Id;

            if (userId == null)
            {
                throw new ClientException("Authentication required");
            }

            var dto = ctx.ReadObject <string>();

            _game.AddPlayer(userId, dto);
        }
Example #15
0
        public async Task UpdateShutdownMode(RequestContext <IScenePeerClient> ctx)
        {
            ShutdownModeParameters shutdown = ctx.ReadObject <ShutdownModeParameters>();

            if (_service.IsHost(ctx.RemotePeer.SessionId))
            {
                await _service.UpdateShutdownMode(shutdown);
            }
            else
            {
                throw new ClientException("forbidden");
            }
        }
Example #16
0
        public async Task GetToken(RequestContext <IScenePeerClient> ctx)
        {
            var client = await _accessor.GetApplicationClient();

            var user = await _sessions.GetUser(ctx.RemotePeer);

            var sceneId = ctx.ReadObject <string>();

            _logger.Log(LogLevel.Debug, "authorization", $"Authorizing access to scene '{sceneId}'", new { sceneId, user.Id });
            var token = await client.CreateConnectionToken(sceneId, new byte[0], "application/octet-stream");

            ctx.SendValue(token);
        }
Example #17
0
        public async Task GetFile(RequestContext <IScenePeerClient> ctx)
        {
            var         branchName  = ctx.ReadObject <string>();
            var         path        = ctx.ReadObject <string>();
            MetafileDto metafileDto = null;

            try
            {
                metafileDto = await _assetsStorage.GetFile(branchName, path);
            }
            catch (BranchException ex)
            {
                _logger.Log(LogLevel.Warn, "AssetsStorageController", $"Branch not found: { branchName } ", ex.Message);
                throw new ClientException($"Branch Not Found:{ branchName }");
            }
            catch (FileException ex)
            {
                _logger.Log(LogLevel.Warn, "AssetsStorageController", $"File not found:  { path } ", ex.Message);
                throw new ClientException($"File not found :{ path }");
            }

            ctx.SendValue(metafileDto);
        }
Example #18
0
        public async Task LoadHistory(RequestContext <IScenePeerClient> ctx)
        {
            List <ChatMessageDto> result = new List <ChatMessageDto>();

            try
            {
                long startTimestamp = ctx.ReadObject <long>();
                long endTimestamp   = ctx.ReadObject <long>();

                DateTime start = TimestampHelper.UnixTimeStampSecondToDateTime(startTimestamp);
                DateTime end   = TimestampHelper.UnixTimeStampSecondToDateTime(endTimestamp);

                string channelName  = ctx.RemotePeer.SceneId;
                var    messagesData = await _chat.LoadHistory(channelName, start, end);

                foreach (ChatMessage msg in messagesData)
                {
                    var message = new ChatMessageDto {
                        Message   = msg.Message,
                        TimeStamp = TimestampHelper.DateTimeToUnixTimeStamp(msg.Date),
                        UserInfo  = new ChatUserInfoDto
                        {
                            UserId = msg.UserInfo.UserId,
                            Data   = msg.UserInfo.Data.ToString(),
                        }
                    };
                    result.Add(message);
                }
            }
            catch (Exception ex)
            {
                _logger.Log(LogLevel.Error, _logCategory, "Error occured when server try to load history", ex);
                throw new ClientException(ex.Message);
            }

            ctx.SendValue(result);
        }
        public async Task GetToken(RequestContext <IScenePeerClient> ctx)
        {
            var client = await _accessor.GetApplicationClient();

            var user = await _sessions.GetUser(ctx.RemotePeer);

            if (user == null)
            {
                throw new ClientException("userDisconnected");
            }
            var sceneId = ctx.ReadObject <string>();

            var token = await client.CreateConnectionToken(sceneId, new byte[0], "application/octet-stream");

            await ctx.SendValue(token);
        }
Example #20
0
        private Task OnGetShipInfos(RequestContext<IScenePeerClient> arg)
        {

            var shipIds = arg.ReadObject<ushort[]>();

            var ships = new List<ShipCreatedDto>(shipIds.Length);
            foreach (var id in shipIds)
            {
                Ship ship;
                if (_ships.TryGetValue(id, out ship))
                {
                    ships.Add(new ShipCreatedDto { timestamp = _scene.GetComponent<IEnvironment>().Clock, id = ship.id, team = ship.team, x = ship.x, y = ship.y, rot = ship.rot, weapons = ship.weapons, status = ship.Status });
                }
            }

            arg.SendValue(ships);
            return Task.FromResult(true);

        }
Example #21
0
        public async Task GetToken(RequestContext <IScenePeerClient> ctx)
        {
            _logger.Log(LogLevel.Trace, "authorization", "Receiving a token request to access a scene", new { });

            var client = await _accessor.GetApplicationClient();

            var user = await _sessions.GetUser(ctx.RemotePeer);

            if (user == null)
            {
                throw new ClientException("Client is not logged in.");
            }
            var sceneId = ctx.ReadObject <string>();

            _logger.Log(LogLevel.Debug, "authorization", $"Authorizing access to scene '{sceneId}'", new { sceneId, user.Id });
            var token = await client.CreateConnectionToken(sceneId, new byte[0], "application/octet-stream");

            ctx.SendValue(token);
        }
        public async Task Promote(RequestContext <IScenePeerClient> ctx)
        {
            var currentUser = await GetUser();

            var targetUserId = ctx.ReadObject <string>();
            var group        = await GetGroup(currentUser.Id);

            if (group.Leader != currentUser.Id)
            {
                throw new ClientException($"Only the leader can promote another player as leader.");
            }

            var r = await _groupsIndex.UpdateWithRetries(group.Id, g => g.PromoteAsLeader(targetUserId));

            if (!r.Success)
            {
                throw new ClientException("Failed to promote player.");
            }
            await BroadCastGroupUpdate(r.Value);
        }
        Task joinGameProcedure(RequestContext <IScenePeerClient> ctx)
        {
            // Make sure the client sends a unique name
            string name = ctx.ReadObject <string>();

            foreach (KeyValuePair <long, Player> player in mPlayers)
            {
                if (player.Value.name == name)
                {
                    throw new ClientException("The username you chose (\"" + name + "\") is already in use.");
                }
            }

            if (!mPlayers.TryAdd(ctx.RemotePeer.Id, new Player(name)))
            {
                throw new ClientException("The joinGame procedure must be called only once by clients.");
            }

            ctx.SendValue(mMapFilename);
            return(Task.FromResult(true));
        }
Example #24
0
        public async Task RequestPasswordRecovery(RequestContext <IScenePeerClient> requestContext, ISceneHost scene)
        {
            var email = requestContext.ReadObject <string>();

            var users = scene.DependencyResolver.Resolve <IUserService>();

            var user = await users.GetUserByClaim(PROVIDER_NAME, "email", email);

            if (user == null)
            {
                return;
            }
            var auth = (JObject)user.Auth[PROVIDER_NAME];
            var code = GenerateCode();

            if (await scene.DependencyResolver.Resolve <Plugins.Notification.INotificationChannel>().SendNotification("loginpassword.resetRequest", JObject.FromObject(new { email, code })))
            {
                auth["resetCode"] = JObject.FromObject(new { code = code, expiration = DateTime.UtcNow + TimeSpan.FromHours(1), retriesLeft = 3 });
                await users.AddAuthentication(user, PROVIDER_NAME, auth, (string)user.Auth[PROVIDER_NAME]["login"]);
            }
        }
Example #25
0
        public async Task ChangePassword(RequestContext <IScenePeerClient> requestContext, ISceneHost scene)
        {
            var rq = requestContext.ReadObject <ChangePasswordRequest>();

            var users = scene.DependencyResolver.Resolve <IUserService>();

            var user = await users.GetUserByClaim(PROVIDER_NAME, "email", rq.Email);

            dynamic auth = user.Auth[PROVIDER_NAME];
            var     code = auth?.resetCode?.code as string;

            if (code == null)
            {
                throw new ClientException("Couldn't reset password. (Error 1)");
            }
            var expiration = (DateTime)auth?.resetCode?.expiration;

            if (expiration < DateTime.UtcNow)
            {
                throw new ClientException("Couldn't reset password. (Error 3)");
            }
            var retriesLeft = (int)auth?.resetCode?.retriesLeft;

            if (retriesLeft <= 0)
            {
                throw new ClientException("Couldn't reset passord. (Error 2)");
            }
            if (code != rq.Code)
            {
                throw new ClientException("Couldn't reset password (Error 3)");
            }
            var salt           = GenerateSaltValue();
            var hashedPassword = HashPassword(rq.NewPassword, salt);

            auth.salt     = salt;
            auth.password = hashedPassword;
            await users.AddAuthentication(user, PROVIDER_NAME, auth, (string)auth.login);
        }
Example #26
0
        public async Task Send(RequestContext <IScenePeerClient> ctx)
        {
            var targetId = ctx.ReadObject <string>();
            var target   = await _sessions.GetPeer(targetId);

            var origin = await _sessions.GetUser(this.Request.RemotePeer);

            if (target == null)
            {
                throw new ClientException($"The user '{targetId}' is not connected");
            }
            var routes = target.Routes.Select(r => r.Name).ToArray();

            var memStream = new MemoryStream();

            ctx.InputStream.CopyTo(memStream);
            memStream.Seek(0, SeekOrigin.Begin);
            target.Send("messaging.receive", s =>
            {
                target.Serializer().Serialize(origin.Id, s);
                memStream.CopyTo(s);
            }, Core.PacketPriority.MEDIUM_PRIORITY, Core.PacketReliability.RELIABLE);
        }
        public async Task GetUserFromBearerToken(RequestContext <IScenePeerClient> ctx)
        {
            var app = await _environment.GetApplicationInfos();

            var bearerToken = ctx.ReadObject <string>();

            if (string.IsNullOrEmpty(bearerToken))
            {
                _logger.Log(LogLevel.Error, "authorization", $"Missing bearer token when calling GetUserFromBearerToken()", new { });
            }
            var data = TokenGenerator.DecodeToken <BearerTokenData>(bearerToken, app.PrimaryKey);

            if (data == null)
            {
                throw new ClientException("Invalid Token");
            }

            if (string.IsNullOrEmpty(data?.userId))
            {
                _logger.Log(LogLevel.Error, "authorization", $"Failed to retrieve userId from bearer token data", new { data });
            }
            await ctx.SendValue(data?.userId);
        }
Example #28
0
        public async Task GetSingle(RequestContext <IScenePeerClient> ctx)
        {
            var userId    = ctx.RemotePeer.GetUserData <string>();
            var profileId = ctx.ReadObject <string>();

            if (string.IsNullOrEmpty(profileId))
            {
                throw new ArgumentNullException($"profileId is null. userId={userId}");
            }
            var profile = await this._profileService.GetProfile(profileId);

            if (profile == null)
            {
                profile = await CreatePlayerProfile(ctx.RemotePeer);
            }

            if (profile != null)
            {
                EnsureUserOwnsProfile(userId, profile, "User {0} cannot retrieve a profile owned by user {1}.");
            }
            //_logger.Log(LogLevel.Debug, "profiles", "Get single ", new { metadata = ctx.RemotePeer.Metadata });
            if (!ctx.RemotePeer.Metadata.ContainsKey("bfg.profiles.compression"))
            {
                ctx.SendValue(profile);
            }
            else
            {
                ctx.SendValue(s =>
                {
                    using (var lzStream = new LZ4.LZ4Stream(s, LZ4.LZ4StreamMode.Compress, LZ4.LZ4StreamFlags.HighCompression))
                    {
                        ctx.RemotePeer.Serializer().Serialize(profile, lzStream);
                    }
                });
            }
        }
Example #29
0
        private Task OnExecuteTransaction(RequestContext <IScenePeer> ctx)
        {
            var input = ctx.ReadObject <UpdateDto>();

            Task <UpdateResponseDto> parameterTask;
            var action = OnUpdateGame;

            if (action != null)
            {
                parameterTask = TaskExtensions.InvokeWrapping(action, input).ContinueWith(task =>
                {
                    if (!task.IsFaulted)
                    {
                        return(new UpdateResponseDto {
                            Success = true, Hash = task.Result
                        });
                    }
                    else
                    {
                        _logger.Error(task.Exception);
                        return(new UpdateResponseDto {
                            Success = false, Reason = task.Exception.InnerExceptions[0].Message
                        });
                    }
                });
            }
            else
            {
                parameterTask = TaskHelper.FromResult(new UpdateResponseDto {
                    Success = false, Reason = "No callback has been registered for updating game."
                });
                _logger.Log(Diagnostics.LogLevel.Error, "TransactionBroker", "No callback has been registered for updating game.");
            }

            return(parameterTask.Then(parameter => ctx.SendValue(parameter, PacketPriority.MEDIUM_PRIORITY)));
        }
        // OnPlay is a response procedure handling the "play" rpc request sent by a client
        // An Rpc response procedure is created by server when an rpc request is received. These are totaly asynchronous so it can handle multiple rpc at the same time.
        // Here, we receive a Connection Data Transfert Object and send back an int to tell the client whether he can play or not.
        //
        private Task OnPlay(RequestContext<IScenePeerClient> ctx)
        {
            // we use RequestContext.ReadObject<Type>() to deserialize to data received from the Client.
            string name = ctx.ReadObject<ConnectionDtO>().name.ToLower();
            bool nameAlreadyTaken = false;

            foreach (var p in _players.Values)
            {
                string temp = p.name.ToLower();
                if (temp == name)
                {
                    nameAlreadyTaken = true;
                    break;
                }
            }
            if (nameAlreadyTaken == false)
            {
                var player = new Player(name);
                _log.Debug("main", "client joined with name : " + player.name);
                _players.TryAdd(ctx.RemotePeer.Id, player);
                ctx.SendValue(0);
            }
            else
            {
                ctx.SendValue(1);
            }
            return Task.FromResult(true);
        }
        private Task onJoinGame(RequestContext<IScenePeerClient> packet)
        {
            GameInfos game = packet.ReadObject<GameInfos>();

            game = m_games.Find(npc => { return (npc.IDOwner == game.IDOwner); });
            if (game.Playing || game.IDPlayers.Count == game.MaxPlayer)
            {
                packet.SendValue(null);
                return Task.FromResult(true);
            }
            game.IDPlayers[packet.RemotePeer.Id] = m_players[packet.RemotePeer];
            foreach (IScenePeerClient client in m_scene.RemotePeers)
                foreach (long key in game.IDPlayers.Keys)
                    if (client.Id == key && key != packet.RemotePeer.Id)
                        client.Send("UpdateGame", game);
            packet.SendValue(game);
            return Task.FromResult(true);
        }
        private async Task CreateAccount(RequestContext<IScenePeerClient> p, ISceneHost scene)
        {
            try
            {
                var userService = scene.GetComponent<IUserService>();
                var rq = p.ReadObject<CreateAccountRequest>();

                scene.GetComponent<ILogger>().Log(LogLevel.Trace, "user.provider.loginpassword", "Creating user " + rq.Login + ".", rq.Login);
                ValidateLoginPassword(rq.Login, rq.Password);

                var user = await userService.GetUserByClaim(PROVIDER_NAME, "login", rq.Login);

                if (user != null)
                {
                    scene.GetComponent<ILogger>().Log(LogLevel.Trace, "user.provider.loginpassword", "User with login " + rq.Login + " already exists.", rq.Login);

                    throw new ClientException("An user with this login already exist.");
                }

                user = await userService.GetUser(p.RemotePeer);
                if (user == null)
                {
                    try
                    {
                        var uid = PROVIDER_NAME + "-" + rq.Login;
                        user = await userService.CreateUser(uid, JObject.Parse(rq.UserData));
                    }
                    catch (Exception ex)
                    {
                        scene.GetComponent<ILogger>().Log(LogLevel.Trace, "user.provider.loginpassword", "Couldn't create user " + rq.Login + ".", ex);

                        throw new ClientException("Couldn't create account : " + ex.Message);
                    }
                }

                var salt = GenerateSaltValue();

                try
                {
                    await userService.AddAuthentication(user, PROVIDER_NAME, JObject.FromObject(new
                    {
                        login = rq.Login,
                        email = rq.Email,
                        salt = salt,
                        password = HashPassword(rq.Password, salt),
                        validated = false,
                    }));
                }
                catch (Exception ex)
                {
                    scene.GetComponent<ILogger>().Log(LogLevel.Trace, "user.provider.loginpassword", "Couldn't link account " + rq.Login + ".", ex);

                    throw new ClientException("Couldn't link account : " + ex.Message);
                }

                scene.GetComponent<ILogger>().Log(LogLevel.Trace, "user.provider.loginpassword", "Creating user " + rq.Login + ".", rq.Login);
                p.SendValue(new LoginResult
                {
                    Success = true
                });


            }
            catch (Exception ex)
            {
                p.SendValue(new LoginResult { ErrorMsg = ex.Message, Success = false });
            }
        }
Example #33
0
        private async Task<bool> UseSkillImpl(RequestContext<IScenePeerClient> arg)
        {

            var env = _scene.GetComponent<IEnvironment>();
            var p = arg.ReadObject<UserSkillRequest>();
            var ship = _ships[_players[arg.RemotePeer.Id].ShipId];

            if (ship.Status != ShipStatus.InGame || ship.currentPv <= 0)
            {
                return false;
                //throw new ClientException("You can only use skills during games.");
            }

            var timestamp = _scene.GetComponent<IEnvironment>().Clock;
            var weapon = ship.weapons.FirstOrDefault(w => w.id == p.skillId);
            if (weapon == null)
            {
                return false;
                //throw new ClientException(string.Format("Skill '{0}' not available.", p.skillId));
            }

            if (weapon.fireTimestamp + weapon.coolDown > timestamp)
            {
                return false;
                //throw new ClientException("Skill in cooldown.");
            }
            if (!_ships.ContainsKey(p.target))
            {
                return false;
            }

            var target = _ships[p.target];
            if (target.Status != ShipStatus.InGame)
            {
                return false;
                //throw new ClientException("Can only use skills on ships that are in game.");
            }
            var dx = ship.x - target.x;
            var dy = ship.y - target.y;
            if (weapon.range * weapon.range < dx * dx + dy * dy)
            {
                return false;
                //throw new ClientException("Target out of range.");
            }

            weapon.fireTimestamp = timestamp;
            var success = _rand.Next(100) < weapon.precision * 100;
            if (success)
            {
                if (target.currentPv > 0)
                {
                    target.ChangePv(-weapon.damage);
                }
            }

            this.RegisterSkill(ship.id, target.id, success, weapon.id, timestamp);

            arg.SendValue(new UseSkillResponse { error = false, errorMsg = null, skillUpTimestamp = weapon.fireTimestamp + weapon.coolDown, success = success });
            return true;
        }
Example #34
0
        public async Task FindMatch(RequestContext <IScenePeerClient> request)
        {
            _logger.Log(LogLevel.Trace, "matchmaker", "received a matchmaking request", new { });
            var group    = new Group();
            var provider = request.ReadObject <string>();

            var currentUser = await _sessions.GetUser(request.RemotePeer);

            foreach (var extractor in _extractors)
            {
                if (await extractor.ExtractData(provider, request, group))
                {
                    break;
                }
            }

            _logger.Log(LogLevel.Trace, "matchmaker", "data extracted from the matchmaking request", new { group });

            foreach (var p in group.Players)
            {
                if (_usersToGroup.ContainsKey(p.UserId))
                {
                    throw new ClientException($"'{p.UserId} is already waiting for a match.");
                }
            }
            var state = new MatchmakingRequestState(group);

            _waitingGroups[group] = state;
            foreach (var user in group.Players)
            {
                _usersToGroup[user.UserId] = group;
            }
            request.CancellationToken.Register(() =>
            {
                state.Tcs.TrySetCanceled();
            });
            var memStream = new MemoryStream();

            request.InputStream.Seek(0, SeekOrigin.Begin);
            request.InputStream.CopyTo(memStream);
            await BroadcastToPlayers(group, UPDATE_FINDMATCH_REQUEST_PARAMS_ROUTE, (s, sz) =>
            {
                memStream.Seek(0, System.IO.SeekOrigin.Begin);
                memStream.CopyTo(s);
            });
            await BroadcastToPlayers(group, UPDATE_NOTIFICATION_ROUTE, (s, sz) =>
            {
                s.WriteByte((byte)MatchmakingStatusUpdate.SearchStart);
            });

            state.State = RequestState.Ready;

            IMatchResolverContext resolutionContext;

            try
            {
                resolutionContext = await state.Tcs.Task;
            }
            catch (TaskCanceledException)
            {
                await BroadcastToPlayers(group, UPDATE_NOTIFICATION_ROUTE, (s, sz) => s.WriteByte((byte)MatchmakingStatusUpdate.Cancelled));
            }
            finally //Always remove group from list.
            {
                MatchmakingRequestState _;
                foreach (var player in group.Players)
                {
                    Group grp1;
                    _usersToGroup.TryRemove(player.UserId, out grp1);
                }
                _waitingGroups.TryRemove(group, out _);
                if (_.Candidate != null)
                {
                    MatchReadyCheck rc;

                    if (_pendingReadyChecks.TryGetValue(_.Candidate.Id, out rc))
                    {
                        if (!rc.RanToCompletion)
                        {
                            rc.Cancel(currentUser.Id);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Invite an user in the group of the connected player
        /// </summary>
        /// <param name="ctx"></param>
        /// <returns></returns>
        public async Task Invite(RequestContext <IScenePeerClient> ctx)
        {
            var currentUser = await GetUser();

            var targetUserId   = ctx.ReadObject <string>();
            int userDataLength = (int)(ctx.InputStream.Length - ctx.InputStream.Position);

            if (userDataLength > MaxInvitationUserDataLength)
            {
                throw new ClientException($"User data too big ({userDataLength} bytes). Maximum : {MaxInvitationUserDataLength} bytes");
            }
            var userData = new byte[userDataLength];

            ctx.InputStream.Read(userData, 0, userDataLength);
            //Check if user is connected
            var targetPeer = await _users.GetPeer(targetUserId);

            if (targetPeer == null)
            {
                throw new ClientException("The target user is not connected.");
            }
            _logger.Log(LogLevel.Trace, "group.invite", $"'{currentUser.Id}' inviting '{targetUserId}'", new { user = currentUser.Id, target = targetUserId });
            //Create a group whose leader is currentUser
            var group = Group.CreateGroup(currentUser.Id);
            await _groupsIndex.TryAdd(group.Id, group);

            //Get the current group of current user, and set it to the just created group if it doesn't exist.
            var groupResult = await _userToGroupIndex.GetOrAdd(currentUser.Id, new UserGroupData(group.Id, GroupMemberState.InGroup));

            if (groupResult.Value.State != GroupMemberState.InGroup)
            {
                throw new ClientException("You can't invite players when you have a pending invitation running yourself.");
            }
            //If the group of the current user is not the group that we just created, we are in one of these situations:
            // * The current user is already in a group of 1 or several players, in this case this group is the one we should select.
            // * The current user is associated in a way or another to a an invalid group : We should update the link with the new group.
            if (groupResult.Value.GroupId != group.Id)
            {
                var r = await _groupsIndex.TryGet(groupResult.Value.GroupId);

                if (r.Success)//The group that existed prior to the invitation process started is valid. We use it instead of the one we just created.
                {
                    await _groupsIndex.TryRemove(group.Id);

                    group = r.Value;
                }
                else//The group associated with the current player doesn't exist. We should replace the player-group association.
                {
                    if (!(await _userToGroupIndex.TryUpdate(currentUser.Id, new UserGroupData(group.Id, GroupMemberState.InGroup), groupResult.Version)).Success)
                    {
                        throw new ClientException("An error occured. Please retry.");
                    }
                }
            }



            //Set the target player in pending invitation state
            var targetResult = await _userToGroupIndex.GetOrAdd(targetUserId, new UserGroupData(group.Id, GroupMemberState.PendingInvitation));

            while (targetResult.Value.GroupId != group.Id)
            {
                // The user already has an userToGroupIndex
                // * She has a pending invitation
                // * The userToGroupIndex is unsynchronized, the linked group doesn't exist.
                // * She is already in a group
                //     * She is alone in her group. In this case, the former group must be cleant
                if (targetResult.Value.State == GroupMemberState.PendingInvitation)
                {
                    throw new ClientException("The player has already a pending invitation.");
                }
                else
                {
                    var targetGroup = await _groupsIndex.TryGet(targetResult.Value.GroupId); // Find the current group of the invited player

                    if (!targetGroup.Success)                                                //The group doesn't exist. The userToGroupIndex must be cleant.
                    {
                        await _userToGroupIndex.TryRemove(targetUserId);

                        targetResult = await _userToGroupIndex.GetOrAdd(targetUserId, new UserGroupData(group.Id, GroupMemberState.PendingInvitation));

                        continue;
                    }
                    else if (targetGroup.Value.Members.Count == 1)//Alone in a group. Clean it!
                    {
                        await _groupsIndex.TryRemove(targetResult.Value.GroupId);

                        await _userToGroupIndex.TryRemove(targetUserId);

                        targetResult = await _userToGroupIndex.GetOrAdd(targetUserId, new UserGroupData(group.Id, GroupMemberState.PendingInvitation));

                        continue;
                    }
                    else//Grouped with other players. Failure!
                    {
                        throw new ClientException("The player is already in a group.");
                    }
                }
            }

            //Try to add the invitation to the group, and check if the group is not full.
            group = await AddMemberToGroup(group.Id, targetUserId);

            var invitationAccepted = false;

            try
            {
                ////Broadcast to all group member that an invitation is pending.
                //await BroadcastToGroupMembers(group, "group.members.invitationPending", s =>
                //{
                //    using (var writer = new System.IO.BinaryWriter(s, Encoding.UTF8, true))
                //    {
                //        writer.Write(targetUserId);
                //        writer.Write(userData);
                //    }
                //});
                var tcs        = new TaskCompletionSource <bool>();
                var disposable = targetPeer.Rpc("group.invite.accept", s =>
                {
                    ctx.InputStream.CopyTo(s);
                }, Stormancer.Core.PacketPriority.MEDIUM_PRIORITY).Subscribe(p =>
                {
                    tcs.TrySetResult(p.Stream.ReadByte() != 0);
                });
                invitationAccepted = await tcs.Task;
            }
            catch (Exception ex)
            {
                _logger.Log(LogLevel.Error, "groups.invite", $"An error occured while inviting '{targetUserId}' to group '{group.Id}'", ex);
            }
            finally
            {
                await BroadcastToGroupMembers(group, "group.members.invitationComplete", s =>
                {
                    using (var writer = new System.IO.BinaryWriter(s, Encoding.UTF8, true))
                    {
                        writer.Write(targetUserId);
                        writer.Write(invitationAccepted);
                    }
                });
            }
            if (!invitationAccepted)//Refused invitation or error
            {
                await RemoveMemberFromGroup(group.Id, targetUserId);

                await _userToGroupIndex.TryRemove(targetUserId);

                throw new ClientException("The player refused the invitation.");
            }
            else
            {
                await _userToGroupIndex.UpdateWithRetries(targetUserId, d => d.UpdateState(GroupMemberState.InGroup));

                var r = await _groupsIndex.UpdateWithRetries(group.Id, g => g.AcceptInvitation(targetUserId));

                group = r.Value;
            }
            await BroadCastGroupUpdate(group);
        }
        public Task OnRegisterObject(RequestContext<IScenePeerClient> ctx)
        {
            _log.Debug("replicator", "registering object");
            var dto = ctx.ReadObject<ReplicatorDTO>();
            var obj = new ReplicatorObject();

            obj.Client = ctx.RemotePeer;
            obj.PrefabId = dto.PrefabId;
            obj.Id = Ids++;

            dto.Id = obj.Id;

            ctx.SendValue<ReplicatorDTO>(dto);

            foreach(IScenePeerClient client in _scene.RemotePeers)
            {
                if (client.Id != ctx.RemotePeer.Id)
                {
                    client.Send<ReplicatorDTO>("CreateObject", dto);
                }
            }
            return Task.FromResult(true);
        }