Example #1
0
 /// <inheritdoc />
 public override async Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ServerTimeSyncronizationRequestPayload payload)
 {
     //TODO: Is ticks best? Or Unity3D deltatime since startup? Or Enviroment ticks?
     //TODO: Do we need to store the time diff? To track latency serverside for some reason?
     await context.PayloadSendService.SendMessage(new ServerTimeSyncronizationResponsePayload(payload.CurrentLocalTime, DateTime.UtcNow.Ticks))
     .ConfigureAwait(false);
 }
Example #2
0
        /// <inheritdoc />
        protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientRotationDataUpdateRequest payload, NetworkEntityGuid guid)
        {
            try
            {
                IMovementGenerator <GameObject> generator = MovementGenerator.RetrieveEntity(guid);
                IMovementData movementData = MovementDataMap.RetrieveEntity(guid);

                //TODO: This is a temporary hack, we nee d abetter solluition
                if (movementData is PositionChangeMovementData posChangeMoveDat)
                {
                    Vector2 direction = posChangeMoveDat.Direction;

                    //TODO: Sanity check position sent.
                    //TODO: Sanity check timestamp
                    MovementDataMap.ReplaceObject(guid, new PositionChangeMovementData(payload.TimeStamp, payload.ClientCurrentPosition, direction, payload.Rotation));
                }
                else
                {
                    throw new NotImplementedException($"TODO: Implement rotation when dealing with: {movementData.GetType().Name} type movement.");
                }

                OnPlayerRotationChanged?.Invoke(this, new PlayerRotiationChangeEventArgs(guid, payload.Rotation));
            }
            catch (Exception e)
            {
                if (Logger.IsErrorEnabled)
                {
                    Logger.Error($"Failed to update MovementData for GUID: {guid} Reason: {e.Message}");
                }

                throw;
            }

            return(Task.CompletedTask);
        }
Example #3
0
        /// <inheritdoc />
        protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientMovementDataUpdateRequest payload, NetworkEntityGuid guid)
        {
            try
            {
                IMovementGenerator <GameObject> generator = MovementGenerator.RetrieveEntity(guid);
                IMovementData movementData = MovementDataMap.RetrieveEntity(guid);
                PositionChangeMovementData changeMovementData = BuildPositionChangeMovementData(payload, generator, movementData);
                MovementDataMap.ReplaceObject(guid, changeMovementData);

                IActorRef playerActorRef = ActorReferenceMappable.RetrieveEntity(guid);

                playerActorRef.TellSelf(new PlayerMovementStateChangedMessage(changeMovementData.Direction));

                //If the generator is running, we should use its initial position instead of the last movement data's position.
                MovementGenerator.ReplaceObject(guid, BuildCharacterControllerMovementGenerator(guid, changeMovementData, generator, movementData));
            }
            catch (Exception e)
            {
                if (Logger.IsErrorEnabled)
                {
                    Logger.Error($"Failed to update MovementData for GUID: {guid} Reason: {e.Message}");
                }

                throw;
            }

            return(Task.CompletedTask);
        }
Example #4
0
        protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, SpellCastRequestPayload payload, NetworkEntityGuid guid)
        {
            IActorRef entityActor = ActorReferenceMappable.RetrieveEntity(guid);

            entityActor.TellSelf(new TryCastSpellMessage(payload));

            return(Task.CompletedTask);
        }
        /// <inheritdoc />
        public Task HandleMessage(IPeerSessionMessageContext <AuthenticationServerPayload> context, AuthenticationClientPayload payload)
        {
            if (Logger.IsWarnEnabled)
            {
                Logger.Warn($"Recieved unhandable Payload: {payload.GetType().Name} ConnectionId: {context.Details.ConnectionId}");
            }

            return(Task.CompletedTask);
        }
Example #6
0
        /// <inheritdoc />
        public async Task <bool> TryHandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, NetworkIncomingMessage <GameClientPacketPayload> message)
        {
            if (CanHandle(message))
            {
                await HandleMessage(context, message.Payload as TSpecificPayloadType);

                return(true);
            }

            return(false);
        }
Example #7
0
        public override async Task HandleMessage(IPeerSessionMessageContext <BaseGameServerPayload> context, ClientWalkMovementRequestPayload payload)
        {
            Console.WriteLine($"Recieved Path with Length: {payload.PathPoints.Length}");

            foreach (var v in payload.PathPoints)
            {
                Console.WriteLine($"X: {v.X} Y: {v.Y}");
            }

            //await context.PayloadSendService.SendMessage(new ServerUpdateLocalPlayerPayload(payload.PathPoints.Last()));
        }
        /// <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);
        }
        public override async Task HandleMessage(IPeerSessionMessageContext <BaseGameServerPayload> context, ClientSessionClaimRequestPayload payload)
        {
            //params never null

            //TODO: Implement authentication with the payload's JWT.

            //If successful, we should then queue them up for creation on the simulation thread.

            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"Recieved SessionClaim: {payload.JWT}");
            }

            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"Sending Welcome Packet.");
            }

            //TODO: This is just demo code, not how it should be handled.

            //208
            await context.PayloadSendService.SendMessage(new ServerSetClientWalkableInterfacePayload(-1));

            //Right-click player options
            for (int i = 0; i < 3; i++)
            {
                await context.PayloadSendService.SendMessage(new ServerSetPlayerRightClickOptionsPayload((byte)(i + 1), false, "Test"));
            }

            //249
            await context.PayloadSendService.SendMessage(new ServerSetLocalPlayerNetworkStatusPayload(true, 1));

            //206
            await context.PayloadSendService.SendMessage(new ServerSetChatModeStatusPayload(ChatModeType.On, ChatModeType.On, ChatModeType.On));

            //107
            await context.PayloadSendService.SendMessage(new ServerResetLocalCameraPayload());

            //68
            await context.PayloadSendService.SendMessage(new ServerResetInterfaceButtonStatePayload());

            await SendTabInterfaces(context.PayloadSendService);

            //176
            await context.PayloadSendService.SendMessage(new ServerWelcomeMessagePacketPayload(5, 10, 5, 69));

            //73
            await context.PayloadSendService.SendMessage(new ServerSetClientRegionPayload(402, 402));

            //Stub
            await context.PayloadSendService.SendMessage(new ServerUpdateLocalPlayerPayload(new Vector2 <short>(50, 50)));
        }
Example #10
0
        /// <inheritdoc />
        protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, PlayerModelChangeRequestPayload payload, NetworkEntityGuid guid)
        {
            //At this point, the player wants to change his model.
            //However we really can't be sure it's a valid model
            //so we validate it before setting the model id.
            //TODO: Validate the model id.
            ProjectVersionStage.AssertAlpha();
            IEntityDataFieldContainer entityDataFieldContainer = EntityFieldMap.RetrieveEntity(guid);

            //This change will be broadcast to anyone interested.
            entityDataFieldContainer.SetFieldValue(BaseObjectField.UNIT_FIELD_DISPLAYID, payload.ModelId);

            return(Task.CompletedTask);
        }
Example #11
0
        protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, PlayerNetworkTrackerChangeUpdateRequest payload, NetworkEntityGuid guid)
        {
            //TODO: Do some validation here. Players could be sending empty ones, or invalid ones.
            InterestCollection interestCollection = InterestCollections.RetrieveEntity(guid);
            PlayerNetworkTrackerChangeUpdateEvent changeUpdateEvent = new PlayerNetworkTrackerChangeUpdateEvent(new EntityAssociatedData <PlayerNetworkTrackerChangeUpdateRequest>(guid, payload));

            //Only send to players and not yourself.
            foreach (NetworkEntityGuid entity in interestCollection.ContainedEntities)
            {
                if (entity.EntityType == EntityType.Player && entity.EntityId != guid.EntityId)
                {
                    EntityMessageSender.SendMessageAsync(entity, changeUpdateEvent);
                }
            }

            return(Task.CompletedTask);
        }
Example #12
0
        /// <inheritdoc />
        protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientMovementDataUpdateRequest payload, NetworkEntityGuid guid)
        {
            try
            {
                MovementGenerator[guid] = new ServerPlayerInputChangeMovementGenerator(payload.MovementInput, data => MovementDataMap[guid] = data, CharacterControllerMappable[guid]);
            }
            catch (Exception e)
            {
                if (Logger.IsErrorEnabled)
                {
                    Logger.Error($"Failed to update MovementData for GUID: {guid} Reason: {e.Message}");
                }

                throw;
            }

            return(Task.CompletedTask);
        }
Example #13
0
        /// <inheritdoc />
        protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientInteractNetworkedObjectRequestPayload payload, NetworkEntityGuid guid)
        {
            //Special case here that indicates the client wants to clear their target.
            if (payload.TargetObjectGuid == NetworkEntityGuid.Empty)
            {
                IActorRef playerRef = ActorReferenceMappable.RetrieveEntity(guid);
                playerRef.Tell(new SetEntityActorTargetMessage(payload.TargetObjectGuid));
                //Just send the empty set target to the player entity
                return(Task.CompletedTask);
            }

            if (!ActorReferenceMappable.ContainsKey(payload.TargetObjectGuid))
            {
                if (Logger.IsWarnEnabled)
                {
                    Logger.Warn($"Client: {guid} attempted to interact with unknown actor {payload.TargetObjectGuid}.");
                }
            }
            else
            {
                IActorRef interactable = ActorReferenceMappable.RetrieveEntity(payload.TargetObjectGuid);
                IActorRef playerRef    = ActorReferenceMappable.RetrieveEntity(guid);

                switch (payload.InteractionType)
                {
                case ClientInteractNetworkedObjectRequestPayload.InteractType.Interaction:
                    //Important to indicate that the player itself is sending it.
                    interactable.Tell(new InteractWithEntityActorMessage(guid), playerRef);
                    break;

                case ClientInteractNetworkedObjectRequestPayload.InteractType.Selection:
                    //TODO: This can technically cause a race condition for target selection if client selects too fast.
                    interactable.Tell(new EntityActorSelectedMessage(guid), playerRef);
                    break;

                default:
                    throw new ArgumentOutOfRangeException($"Client used unknown interaction Type: {(int)payload.InteractionType}");
                }
            }

            return(Task.CompletedTask);
        }
Example #14
0
        /// <inheritdoc />
        public async Task HandleMessage(IPeerSessionMessageContext <AuthenticationServerPayload> context, AuthLogonChallengeRequest payload)
        {
            using (var repo = AccountRepository.Create())
            {
                bool accountExists = await repo.DoesAccountExists(payload.Identity)
                                     .ConfigureAwait(false);

                if (Logger.IsDebugEnabled)
                {
                    Logger.Debug($"Account: {payload.Identity} Exists: {accountExists} ConnectionId: {context.Details.ConnectionId}");
                }

                //Depending on if it exists we build an appropriate response
                AuthLogonChallengeResponse response = accountExists
                                        ? await BuildSuccessResponse(await repo.GetAccount(payload.Identity).ConfigureAwait(false), context.Details.ConnectionId)
                                        : BuildFailureResponse();

                await context.PayloadSendService.SendMessage(response)
                .ConfigureAwait(false);
            }
        }
        /// <inheritdoc />
        public async Task HandleMessage(IPeerSessionMessageContext <AuthenticationServerPayload> context, AuthRealmListRequest payload)
        {
            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"Recieved {payload.GetType().Name} From ConnectionId: {context.Details.ConnectionId}");
            }

            //All we need to do when we recieve this request
            //is send back a list of requests. It doesn't even technically matter if they're authenticated
            //or if they even provided the challenge/proof and failed.
            using (IAuthenticationRealmRepository realmService = RealmListService.Create())
            {
                IEnumerable <Realmlist> realms = await realmService.Retrieve();

                if (Logger.IsDebugEnabled)
                {
                    Logger.Debug($"Recieved RealmList repository response.");
                }

                //TODO: Implement complete realm info handling; right now only uses default
                //TODO: Better handle handle other realm types. Resitrcted, dev, test or locked types.
                RealmInfo[] realmInfos = realms
                                         .Select(BuildRealmInfoFromModel)
                                         .ToArray();

                RealmListContainer realmListContainer = new RealmListContainer(realmInfos);

                byte[] realmData = Serializer.Serialize(realmListContainer);

                AuthRealmListResponse response = new AuthRealmListResponse((ushort)(realmData.Length + 6), realmInfos);

                if (Logger.IsDebugEnabled)
                {
                    Logger.Debug($"Sending {typeof(AuthRealmListResponse).Name} PayloadSize: {response.PayloadSize}.");
                }

                await context.PayloadSendService.SendMessage(response);
            }
        }
Example #16
0
        /// <inheritdoc />
        protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientSetClickToMovePathRequestPayload payload, NetworkEntityGuid guid)
        {
            try
            {
                IMovementGenerator <GameObject> generator = MovementGenerator.RetrieveEntity(guid);

                IMovementData         movementData       = MovementDataMap.RetrieveEntity(guid);
                PathBasedMovementData changeMovementData = BuildPathData(payload, generator, movementData, guid);

                //If it doesn't have more one point reject it
                if (changeMovementData.MovementPath.Count < 2)
                {
                    return(Task.CompletedTask);
                }

                MovementDataMap.ReplaceObject(guid, changeMovementData);

                IActorRef playerActorRef = ActorReferenceMappable.RetrieveEntity(guid);

                Vector3 direction3D = (changeMovementData.MovementPath[1] - changeMovementData.MovementPath[0]);
                Vector2 direction2D = new Vector2(direction3D.x, direction3D.z).normalized;
                playerActorRef.TellSelf(new PlayerMovementStateChangedMessage(direction2D));

                //If the generator is running, we should use its initial position instead of the last movement data's position.
                MovementGenerator.ReplaceObject(guid, new PathMovementGenerator(changeMovementData));
            }
            catch (Exception e)
            {
                if (Logger.IsErrorEnabled)
                {
                    Logger.Error($"Failed to update MovementData for GUID: {guid} Reason: {e.Message}");
                }

                throw;
            }

            return(Task.CompletedTask);
        }
Example #17
0
 /// <inheritdoc />
 protected sealed override NetworkEntityGuid GenerateLockContext(IPeerSessionMessageContext <GameServerPacketPayload> context, TSpecificPayloadType payload)
 {
     //We just grab the entity, and assume that they want this.
     return(ExtractEntityGuidFromContext(context));
 }
 /// <inheritdoc />
 public abstract Task HandleMessage(IPeerSessionMessageContext <BaseGameServerPayload> context, TSpecificPayloadType payload);
Example #19
0
        /// <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))
                                                    .ConfigureAwaitFalse();
            }
            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)
            {
                if (Logger.IsWarnEnabled)
                {
                    Logger.Warn($"Client attempted to claim session for Character: {payload.CharacterId} but was denied.");
                }

                //TODO: Better error code
                await context.PayloadSendService.SendMessage(new ClientSessionClaimResponsePayload(ClientSessionClaimResponseCode.SessionUnavailable))
                .ConfigureAwaitFalse();

                return;
            }

            NetworkEntityGuid entityGuid = new NetworkEntityGuidBuilder()
                                           .WithId(payload.CharacterId)
                                           .WithType(EntityType.Player)
                                           .Build();

            //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)
                                                                   .ConfigureAwaitFalse();

            Vector3 position = locationResponse.isSuccessful ? locationResponse.Position : SpawnPointProvider.GetSpawnPoint().WorldPosition;

            SpawnPointData pointData = new SpawnPointData(position, Quaternion.identity);

            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"Recieved player location: {pointData.WorldPosition} from {(locationResponse.isSuccessful ? "Database" : "Spawnpoint")}");
            }

            //TODO: We need a cleaner/better way to load initial player data.
            ResponseModel <CharacterDataInstance, CharacterDataQueryReponseCode> characterData = await CharacterService.GetCharacterData(payload.CharacterId);

            //TODO: Check success.
            InitialCharacterDataMappable.AddObject(entityGuid, characterData.Result);

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

            await context.PayloadSendService.SendMessage(new ClientSessionClaimResponsePayload(ClientSessionClaimResponseCode.Success))
            .ConfigureAwaitFalse();
        }
Example #20
0
        /// <inheritdoc />
        public async Task HandleMessage(IPeerSessionMessageContext <AuthenticationServerPayload> context, AuthLogonProofRequest payload)
        {
            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"Recieved {payload.GetType().Name} Id: {context.Details.ConnectionId}");
            }

            BigInteger A = payload.A.ToBigInteger();

            //SRP6 Safeguard from specification: A % N cannot be 0.
            if (A % WoWSRP6ServerCryptoServiceProvider.N == 0)
            {
                //TODO: This can't be 0 or it breaks
            }

            //Check if we have a challenge entry for this connection
            //TODO: Add proper response code
            if (!await ChallengeRepository.HasEntry(context.Details.ConnectionId))
            {
                await context.PayloadSendService.SendMessage(new AuthLogonProofResponse(new LogonProofFailure()));

                return;
            }

            //TODO: Refactor
            using (WoWSRP6PublicComponentHashServiceProvider hasher = new WoWSRP6PublicComponentHashServiceProvider())
            {
                AuthenticationChallengeModel challenge = await ChallengeRepository.Retrieve(context.Details.ConnectionId);

                byte[] hash = hasher.Hash(A, challenge.PublicB);

                // Both:  u = H(A, B)
                BigInteger u = hash
                               .Take(20)
                               .ToArray()
                               .ToBigInteger();
                BigInteger N = WoWSRP6ServerCryptoServiceProvider.N;

                //Host:  S = (Av^u) ^ b (computes session key)
                BigInteger S = ((A * (challenge.V.ModPow(u, N))))                 //TODO: Do we need % N here?
                               .ModPow(challenge.PrivateB, N);

                //Host:  K = H(S)
                BigInteger K = hasher.HashSessionKey(S);

                byte[] preMHash = T3.ToCleanByteArray()
                                  .Concat(hasher.Hash(challenge.Identity.Reinterpret(Encoding.ASCII)).Take(20).ToArray())
                                  .Concat(challenge.Salt.ToCleanByteArray())
                                  .Concat(payload.A)
                                  .Concat(challenge.PublicB.ToCleanByteArray())
                                  .Concat(K.ToCleanByteArray())
                                  .ToArray();

                byte[] M = hasher.Hash(preMHash);

                Logger.Debug($"M: {M.Aggregate("", (s, b) => $"{s} {b}")}");
                Logger.Debug($"M1: {payload.M1.Aggregate("", (s, b) => $"{s} {b}")}");

                //TODO: Remove this test code
                if (TestClass.CompareBuffers(M, payload.M1, 20) == 0)
                {
                    Logger.Debug($"Auth Proof Success.");

                    byte[] M2 = hasher.Hash(payload.A.Concat(M).Concat(K.ToCleanByteArray()).ToArray());

                    //TODO: We also want to update last/login IP and other stuff
                    await AccountRepository.UpdateSessionKey(challenge.AccountId, K);

                    await context.PayloadSendService.SendMessage(new AuthLogonProofResponse(new LogonProofSuccess(M2)));
                }
                else
                {
                    Logger.Debug($"Auth Proof Failure.");

                    await context.PayloadSendService.SendMessage(new AuthLogonProofResponse(new LogonProofFailure()));
                }
            }

            //TODO: Implement
        }