/// <inheritdoc />
        protected override void HandleEvent(PlayerSessionClaimedEventArgs args)
        {
            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"Dequeueing entity creation request for: {args.EntityGuid.EntityType}:{args.EntityGuid.EntityId}");
            }

            //TODO: This is test data
            EntityFieldDataCollection <EntityDataFieldType> testData = new EntityFieldDataCollection <EntityDataFieldType>();

            //TODO: Test values set
            testData.SetFieldValue(EntityDataFieldType.EntityCurrentHealth, 100);
            testData.SetFieldValue(EntityDataFieldType.EntityMaxHealth, 120);

            using (LockingPolicy.WriterLock(null, CancellationToken.None))
            {
                //TODO: Time stamp
                //TODO: We should check if the result is valid? Maybe return a CreationResult?
                //We don't need to do anything with the returned object.
                GameObject playerGameObject = PlayerFactory.Create(new PlayerEntityCreationContext(args.EntityGuid, args.SessionContext, new PositionChangeMovementData(0, args.SpawnPosition, Vector2.zero), EntityPrefab.RemotePlayer, testData));
            }

            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"Sending player spawn payload Id: {args.EntityGuid.EntityId}");
            }

            OnPlayerWorldSessionCreated?.Invoke(this, new PlayerWorldSessionCreationEventArgs(args.EntityGuid));

            //TODO: If we want to do anything post-creation with the provide gameobject we could. But we really don't want to at the moment.
        }
        /// <inheritdoc />
        public override async Task HandleMessage(IPeerMessageContext <GameClientPacketPayload> context, PlayerSelfSpawnEventPayload payload)
        {
            //TODO: Actually handle this. Right now it's just demo code, it actually could fail.
            if (Logger.IsInfoEnabled)
            {
                Logger.Info($"Recieved server commanded PlayerSpawn. Player GUID: {payload.CreationData.EntityGuid} Position: {payload.CreationData.InitialMovementData.InitialPosition}");
            }

            EntityFieldDataCollection <EntityDataFieldType> entityData = CreateEntityDataCollectionFromPayload(payload.CreationData.InitialFieldValues);

            LogEntityDataFields(payload);

            await new UnityYieldAwaitable();

            //Don't do any checks for now, we just spawn
            GameObject playerGameObject = PlayerFactory.Create(new DefaultEntityCreationContext(payload.CreationData.EntityGuid, payload.CreationData.InitialMovementData, EntityPrefab.LocalPlayer, entityData));

            //Set local player entity guid, lots of dependencies need this set to work.
            LocalPlayerDetails.LocalPlayerGuid = payload.CreationData.EntityGuid;

            //Call all OnGameInitializables
            foreach (var init in Initializables)
            {
                await init.OnGameInitialized()
                .ConfigureAwait(false);
            }

            //TODO: We need to make this the first packet, or couple of packets. We don't want to do this inbetween potentially slow operatons.
            await context.PayloadSendService.SendMessageImmediately(new ServerTimeSyncronizationRequestPayload(DateTime.UtcNow.Ticks))
            .ConfigureAwait(false);
        }
        /// <inheritdoc />
        protected override void OnEventFired(object source, SelfPlayerSpawnEventArgs args)
        {
            EntityFieldDataCollection <EntityDataFieldType> entityData = CreateEntityDataCollectionFromPayload(args.CreationData.InitialFieldValues);

            //Don't do any checks for now, we just spawn
            GameObject playerGameObject = PlayerFactory.Create(new DefaultEntityCreationContext(args.CreationData.EntityGuid, args.CreationData.InitialMovementData, EntityPrefab.LocalPlayer, entityData));

            //Broadcast that the player has spawned.
            OnLocalPlayerSpawned?.Invoke(this, new LocalPlayerSpawnedEventArgs(args.CreationData.EntityGuid));
        }
        private static EntityFieldDataCollection <EntityDataFieldType> CreateEntityDataCollectionFromPayload(FieldValueUpdate fieldUpdateValues)
        {
            //TODO: We need better initial handling for entity data
            EntityFieldDataCollection <EntityDataFieldType> entityData = new EntityFieldDataCollection <EntityDataFieldType>();

            int currentSentIndex = 0;

            foreach (var setIndex in fieldUpdateValues.FieldValueUpdateMask.EnumerateSetBitsByIndex())
            {
                entityData.SetFieldValue(setIndex, fieldUpdateValues.FieldValueUpdates.ElementAt(currentSentIndex));
                currentSentIndex++;
            }

            return(entityData);
        }
Beispiel #5
0
        /// <inheritdoc />
        public override async Task HandleMessage(IPeerMessageContext <GameClientPacketPayload> context, NetworkObjectVisibilityChangeEventPayload payload)
        {
            foreach (var entity in payload.EntitiesToCreate)
            {
                if (Logger.IsDebugEnabled)
                {
                    Logger.Debug($"Encountered new entity: {entity.EntityGuid}");
                }
            }

            foreach (var entity in payload.OutOfRangeEntities)
            {
                if (Logger.IsErrorEnabled)
                {
                    Logger.Debug($"Leaving entity: {entity}");
                }
            }

            //Assume it's a player for now
            foreach (var creationData in payload.EntitiesToCreate)
            {
                //TODO: Right now we're creating a temporary entity data collection.
                EntityFieldDataCollection <EntityDataFieldType> testData = new EntityFieldDataCollection <EntityDataFieldType>();

                //We set the initial values off the main thread, it is much better that way.
                //However, that means initial values won't dispatch OnChange stuff.
                SetInitialFieldValues(creationData, testData);

                OnNetworkEntityNowVisible?.Invoke(this, new NetworkEntityNowVisibleEventArgs(creationData.EntityGuid, creationData, testData));
            }

            foreach (var destroyData in payload.OutOfRangeEntities)
            {
                OnNetworkEntityVisibilityLost?.Invoke(this, new NetworkEntityVisibilityLostEventArgs(destroyData));
            }

            //TODO: We should not waste 2, maybe even more, frames to prevent the race condition for spawn/despawn and other packets.
            //We SHOULD actually only call these awaits in other handlers where we realize we MAY not have spawned the entity yet.
            //This should yield better-case throughput because MANY packets could be handled unrelated inbetween these awaits.
            //Two tickable frames is long enough for all spawn/despawn logic to have run.
            await UnityExtended.AwaitNextTickableFrameAsync()
            .ConfigureAwait(false);

            await UnityExtended.AwaitNextTickableFrameAsync()
            .ConfigureAwait(false);
        }