/// <inheritdoc />
        protected override async void OnEventFired(object source, LocalPlayerWorldObjectSpawnedEventArgs args)
        {
            //TODO: We should extract this into a warping service.

            //TODO: Send rotation
            //TODO: What should the W coord be? How sould we handle this poition?
            //We can't do anything with the data right now
            await SendService.SendMessage(new Sub60TeleportToPositionCommand((byte)EntityGuid.GetEntityId(args.EntityGuid),
                                                                             ScalerService.UnScale(args.WorldObject.transform.position).ToNetworkVector3()).ToPayload());

            //Now we have to send a 1F to start the warp
            //Tell the server we're warping now
            await SendService.SendMessage(new Sub60WarpToNewAreaCommand((byte)EntityGuid.GetEntityId(args.EntityGuid), ZoneSettings.ZoneId).ToPayload());

            //TODO: is it save to send this in the lobby??
            await SendService.SendMessage(new Sub60FinishedMapLoadCommand(EntityGuid.GetEntityId(args.EntityGuid)).ToPayload());

            //TODO: Should we send ClientId with this one too?
            //We can just send a finished right away, we have nothing to load really
            await SendService.SendMessage(new Sub60FinishedWarpingBurstingCommand((byte)EntityGuid.GetEntityId(args.EntityGuid)).ToPayload());
        }
Example #2
0
 private static void AssertEntityContainedInMappable(IDictionary <int, PlayerZoneData> mappable, int entityGuid)
 {
     if (!mappable.ContainsKey(entityGuid))
     {
         throw new InvalidOperationException($"Mappable does not contain {nameof(PlayerZoneData)} for EntityType: {EntityGuid.GetEntityType(entityGuid)} Id: {EntityGuid.GetEntityId(entityGuid)}");
     }
 }
Example #3
0
        /// <inheritdoc />
        public void Update(int entity, long currentTime)
        {
            //We might then we should not block here for so long but
            //the issue is if we didn't then someone could carefully stream movement packets
            //to players in the lobby and put them in an endless loop trying to skip skippable packets
            lock (SyncObj)
            {
                //If we have no current state we have to get one.
                if (CurrentState == null)
                {
                    //But if there are no states we should give up.
                    if (MovementStates.Count == 0)
                    {
                        return;
                    }

                    CurrentState = MovementStates.Dequeue();

                    //This prevents an endless loop
                    //Though this should never happen
                    //Reentrant lock will also prevent anything from changing
                    //so this is safe.
                    if (CurrentState != null)
                    {
                        Update(entity, currentTime);
                        return;
                    }
                    else
                    {
                        throw new InvalidOperationException($"Dequeued a NULL State in {nameof(MovementManager)} for Entity: {entity} Id: {EntityGuid.GetEntityId(entity)}");
                    }
                }

                //TODO: We should cache finished call maybe
                //The case where we have a non-null currentstate is done
                //or we we have queued up movement states and the current state is low priority/skippable.
                if (CurrentState.isSkippable && MovementStates.Count != 0)
                {
                    //Error in logic was here originally, it tried to dequeue a new state if the
                    //above expression was true. The issue was, it's possible for a state to be finished and not have anything more to dequeue.
                    //Because of that we should only handle skippable AND something left in there.
                    //isFinished can be handled last.
                    CurrentState = MovementStates.Dequeue();

                    //This may seem weird, but calling into the same method again here recursively makes sense
                    //because it'll check if the next state is finished (probably not) or is skippable and we have more.
                    //It will eventually run out of skippable states or we'll find one that isn't skippable
                    Update(entity, currentTime);
                    return;
                }

                //At this point the CurrentState is either finished, unskippable or we've got no more states left.
                //If it's finished then we have no reason to call it.
                if (CurrentState.isFinished)
                {
                    //Setting this null here will allow
                    //for the next call to basically check if it's null and if we have no more and it can leave
                    //quick.
                    CurrentState = null;
                    return;
                }
            }

            //TODO: Is it safe to assume that an object exists for the entity Update is calling with?
            //Once we have the current state though and we can use it THEN we can release the lock.
            GameObject entityWorldObject = EntityWorldObjectMap[entity];

            CurrentState.Update(entityWorldObject, currentTime);
        }