Ejemplo n.º 1
0
        /// <inheritdoc />
        public async Task <HubOnConnectionState> OnConnected(Hub hubConnectedTo)
        {
            //TODO: Verify that the character they requested is owned by them.
            ProjectVersionStage.AssertAlpha();

            NetworkEntityGuid guid = new NetworkEntityGuidBuilder()
                                     .WithId(int.Parse(hubConnectedTo.Context.UserIdentifier))
                                     .WithType(EntityType.Player)
                                     .Build();

            //We may already be able to register.
            if (await TryRegisterGuildStatus(guid, hubConnectedTo.Groups, hubConnectedTo.Context.ConnectionId).ConfigureAwait(false) == HubOnConnectionState.Success)
            {
                return(HubOnConnectionState.Success);
            }

            HubOnConnectionState state = await TryRequestCharacterGuildStatus(guid, hubConnectedTo.Context.UserIdentifier)
                                         .ConfigureAwait(false);

            if (state == HubOnConnectionState.Success)
            {
                return(await TryRegisterGuildStatus(guid, hubConnectedTo.Groups, hubConnectedTo.Context.ConnectionId)
                       .ConfigureAwait(false));
            }

            //Just error, we don't need to abort. Something didn't work right though.
            return(HubOnConnectionState.Error);
        }
Ejemplo n.º 2
0
        //TODO: Race condition here because it's possible the subsciber hasn't subscribed just yet.
        /// <inheritdoc />
        public async Task OnGameInitialized()
        {
            CharacterListResponse listResponse = await CharacterQueryable.GetCharacters(AuthTokenRepository.RetrieveWithType())
                                                 .ConfigureAwait(true);

            if (!listResponse.isSuccessful || listResponse.CharacterIds.Count == 0)
            {
                if (Logger.IsErrorEnabled)
                {
                    Logger.Error($"Failed to query character list. Recieved ResultCode: {listResponse.ResultCode}");
                }

                //We don't have character creation... Soooo, nothing we can do right now.
                return;
            }

            //TODO: Should we make this API spit out network guids?
            foreach (var characterId in listResponse.CharacterIds)
            {
                NetworkEntityGuid entityGuid = new NetworkEntityGuidBuilder()
                                               .WithType(EntityType.Player)
                                               .WithId(characterId)
                                               .Build();

                OnCharacterSelectionEntryChanged?.Invoke(this, new CharacterSelectionEntryDataChangeEventArgs(entityGuid));
            }
        }
Ejemplo n.º 3
0
        //TODO: Create a converter type
        private static ZoneServerNpcEntryModel BuildDatabaseNPCEntryToTransportNPC(NPCEntryModel npc)
        {
            NetworkEntityGuidBuilder guidBuilder = new NetworkEntityGuidBuilder();

            NetworkEntityGuid guid = guidBuilder.WithId(npc.EntryId)
                                     .WithType(EntityType.Npc)
                                     .Build();

            //TODO: Create a Vector3 converter
            return(new ZoneServerNpcEntryModel(guid, npc.NpcTemplateId, new Vector3(npc.SpawnPosition.X, npc.SpawnPosition.Y, npc.SpawnPosition.Z), npc.MovementType, npc.MovementData));
        }
        /// <inheritdoc />
        public override async Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientSessionClaimRequestPayload payload)
        {
            //TODO: We need better validation/authorization for clients trying to claim a session. Right now it's open to malicious attack
            ZoneServerTryClaimSessionResponse zoneServerTryClaimSessionResponse = null;

            try
            {
                ProjectVersionStage.AssertAlpha();
                zoneServerTryClaimSessionResponse = await GameServerClient.TryClaimSession(new ZoneServerTryClaimSessionRequest(await GameServerClient.GetAccountIdFromToken(payload.JWT), payload.CharacterId))
                                                    .ConfigureAwait(false);
            }
            catch (Exception e)            //we could get an unauthorized response
            {
                Logger.Error($"Failed to Query for AccountId: {e.Message}. AuthToken provided was: {payload.JWT}");
                throw;
            }

            if (!zoneServerTryClaimSessionResponse.isSuccessful)
            {
                //TODO: Better error code
                await context.PayloadSendService.SendMessage(new ClientSessionClaimResponsePayload(ClientSessionClaimResponseCode.SessionUnavailable))
                .ConfigureAwait(false);

                return;
            }

            NetworkEntityGuidBuilder builder = new NetworkEntityGuidBuilder();

            builder
            .WithId(payload.CharacterId)
            .WithType(EntityType.Player);

            //TODO: We assume they are authenticated, we don't check at the moment but we WILL and SHOULD. Just load their location.
            ZoneServerCharacterLocationResponse locationResponse = await GameServerClient.GetCharacterLocation(payload.CharacterId)
                                                                   .ConfigureAwait(false);

            Vector3 position = locationResponse.isSuccessful ? locationResponse.Position : Vector3.zero;

            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"Recieved player location: {position}");
            }

            //Just broadcast successful claim, let listeners figure out what to do with this information.
            OnSuccessfulSessionClaimed?.Invoke(this, new PlayerSessionClaimedEventArgs(builder.Build(), position, new PlayerEntitySessionContext(context.PayloadSendService, context.Details.ConnectionId)));

            await context.PayloadSendService.SendMessage(new ClientSessionClaimResponsePayload(ClientSessionClaimResponseCode.Success))
            .ConfigureAwait(false);

            //TODO: We shouldn't hardcode this, we should send the correct scene specified by the gameserver this zone/instance connects to to service.
            await context.PayloadSendService.SendMessage(new LoadNewSceneEventPayload(PlayableGameScene.LobbyType1))
            .ConfigureAwait(false);
        }
Ejemplo n.º 5
0
        /// <inheritdoc />
        public override async Task OnDisconnectedAsync(Exception exception)
        {
            NetworkEntityGuid guid = new NetworkEntityGuidBuilder()
                                     .WithId(int.Parse(Context.UserIdentifier))
                                     .WithType(EntityType.Player)
                                     .Build();

            //Right now this doesn't depend on entity, so we just do it.
            if (ZoneLookupService.Contains(Context.ConnectionId))
            {
                ZoneLookupService.Unregister(Context.ConnectionId);
            }

            if (Logger.IsEnabled(LogLevel.Information))
            {
                Logger.LogInformation($"About to attempt final cleanup for Entity: {guid}");
            }

            //If the entity is no longer contained we should clear up
            FinalEntityLockResult entityLockResult = await EntityLockService.TryAquireFinalEntityLockAsync(guid);

            if (entityLockResult.Result)
            {
                if (Logger.IsEnabled(LogLevel.Information))
                {
                    Logger.LogInformation($"Clearing Entity data for Entity: {guid}. Last connection related to the Entity.");
                }

                using (entityLockResult.LockObject)
                {
                    foreach (var c in EntityRemovable)
                    {
                        c.RemoveEntityEntry(guid);
                    }
                }
            }
            else
            {
                if (Logger.IsEnabled(LogLevel.Information))
                {
                    Logger.LogInformation($"Entity: {guid} still has active connections/sessions claiming interest. Won't cleanup entity data.");
                }

                //We still need to release interest
                //so that the ref count goes down, otherwise it'll never be cleaned up.
                await this.EntityLockService.ReleaseEntityInterestAsync(guid)
                .ConfigureAwait(false);
            }

            await base.OnDisconnectedAsync(exception);
        }
Ejemplo n.º 6
0
        /// <inheritdoc />
        public override async Task OnConnectedAsync()
        {
            await base.OnConnectedAsync()
            .ConfigureAwait(false);

            if (Logger.IsEnabled(LogLevel.Information))
            {
                Logger.LogInformation($"Account Connected: {ClaimsReader.GetUserName(Context.User)}:{ClaimsReader.GetUserId(Context.User)}");
            }

            NetworkEntityGuid guid = new NetworkEntityGuidBuilder()
                                     .WithId(int.Parse(Context.UserIdentifier))
                                     .WithType(EntityType.Player)
                                     .Build();

            //Register interest and then lock
            //We need to lock on the entity so only 1 connection for the entity can go through this process at a time.
            await EntityLockService.RegisterEntityInterestAsync(guid)
            .ConfigureAwait(false);

            using (await EntityLockService.AquireEntityLockAsync(guid).ConfigureAwait(false))
            {
                try
                {
                    foreach (var listener in OnConnectionHubListeners)
                    {
                        HubOnConnectionState connectionState = await listener.OnConnected(this).ConfigureAwait(false);

                        //if the listener indicated we need to abort for whatever reason we
                        //should believe it and just abort.
                        if (connectionState == HubOnConnectionState.Abort)
                        {
                            Context.Abort();
                            break;
                        }
                    }
                }
                catch (Exception e)
                {
                    if (Logger.IsEnabled(LogLevel.Error))
                    {
                        Logger.LogInformation($"Account: {ClaimsReader.GetUserName(Context.User)}:{ClaimsReader.GetUserId(Context.User)} failed to properly connect to hub. Error: {e.Message}\n\nStack: {e.StackTrace}");
                    }

                    Context.Abort();
                }
            }
        }
        protected EntityAssociatedData <T> BuildForwardableAssociatedData <T>([JetBrains.Annotations.NotNull] IHubConnectionMessageContext context, [JetBrains.Annotations.NotNull] T envolpeContents)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (envolpeContents == null)
            {
                throw new ArgumentNullException(nameof(envolpeContents));
            }

            //TODO: We should cache somehow the identifier's int value, parsing it each time I think can be costly.
            NetworkEntityGuid guid = new NetworkEntityGuidBuilder()
                                     .WithId(int.Parse(context.HubConntext.UserIdentifier))
                                     .WithType(EntityType.Player)
                                     .Build();

            return(new EntityAssociatedData <T>(guid, envolpeContents));
        }