/// <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()); }
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)}"); } }
/// <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); }