Esempio n. 1
0
        internal void instances_callback(int code)
        {
            switch (code)
            {
            case 283:
                if (Settings.TrackerEnabled && Settings.AutoTracker && mainForm.TrackerFormLoaded)
                {
                    mainForm.TrackerForm.new_tracker(1);
                }
                return;

            case 581:
                if (Settings.TrackerEnabled && Settings.AutoTracker && mainForm.TrackerFormLoaded)
                {
                    mainForm.TrackerForm.new_tracker(2);
                }
                return;

            case 598:
                if (Settings.TrackerEnabled && Settings.AutoTracker && mainForm.TrackerFormLoaded)
                {
                    mainForm.TrackerForm.new_tracker(3);
                }
                return;

            case 639:
                if (Settings.TrackerEnabled && Settings.AutoTracker && mainForm.TrackerFormLoaded)
                {
                    mainForm.TrackerForm.new_tracker(4);
                }
                return;

            default:
                break;
            }
            if (isRoulette && Settings.RouletteTips)
            {
                Task.Factory.StartNew(() =>
                {
                    var instance = Data.GetInstance(code);
                    var roulette = Data.GetRoulette(queueCode);
                    if (instance.Tips != null)
                    {
                        mainForm.Show_DutyTips(roulette.Name, instance.Name, instance.Tips, instance.Macro);
                    }
                    else if (instance.Macro != null)
                    {
                        var respond = LMessageBox.Dialog($"已通过[{roulette.Name}]进入<{instance.Name}>副本区域,是否复制该副本可用的宏?", $"DFA:<{instance.Name}> 简易攻略", MessageBoxButtons.YesNo, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
                        if (respond == DialogResult.Yes)
                        {
                            this.Invoke(() => { Clipboard.SetDataObject(instance.Macro, true); });
                        }
                    }
                });
            }
        }
Esempio n. 2
0
 internal void instances_callback(int code)
 {
     if (Settings.copyMacro)
     {
         Task.Factory.StartNew(() =>
         {
             var instance = Data.GetInstance(code);
             if (instance.Macro != null)
             {
                 var respond = LMessageBox.Dialog(Localization.GetText("ui-settings-copymacro-dialog-text", instance.Name), Localization.GetText("ui-settings-copymacro-dialog-title"), MessageBoxButtons.YesNo, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
                 if (respond == DialogResult.Yes)
                 {
                     this.Invoke(() => { Clipboard.SetDataObject(instance.Macro, true); });
                 }
             }
         });
     }
 }
        private void HandleMessage(byte[] message)
        {
            try
            {
                if (message.Length < 32)
                {
                    // type == 0x0000 이였던 메시지는 여기서 걸러짐
                    return;
                }

                mainForm.overlayForm.SetStatus(true);

                var opcode = BitConverter.ToUInt16(message, 18);

#if !DEBUG
                if (opcode != 0x0078 &&
                    opcode != 0x0079 &&
                    opcode != 0x0080 &&
                    opcode != 0x006C &&
                    opcode != 0x006F &&
                    opcode != 0x0121 &&
                    opcode != 0x0143 &&
                    opcode != 0x022F)
                {
                    return;
                }
#endif

                var data = message.Skip(32).ToArray();

                if (opcode == 0x022F)
                {
                    var code = BitConverter.ToInt16(data, 4);
                    var type = data[8];

                    if (type == 0x0B)
                    {
                        Log.I("l-field-instance-entered", Data.GetInstance(code).Name);
                    }
                    else if (type == 0x0C)
                    {
                        Log.I("l-field-instance-left");
                    }

                    /*if (Settings.ShowOverlay && Settings.AutoOverlayHide)
                     * {
                     *  mainForm.overlayForm.Invoke(() =>
                     *  {
                     *      if (type == 0x0B)
                     *      {
                     *          mainForm.overlayForm.Hide();
                     *      }
                     *      else if (type == 0x0C)
                     *      {
                     *          mainForm.overlayForm.Show();
                     *      }
                     *  });
                     * }*/
                }
                else if (opcode == 0x0143)
                {
                    var type = data[0];

                    if (type == 0x9B)
                    {
                        /*
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var progress = data[8];
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 진행도 {1}%", fate.Name, progress);
                         */
                    }
                    else if (type == 0x79)
                    {
                        /*
                         * // 돌발 임무 종료 (지역 이동시 발생할 수 있는 모든 임무에 대해 전부 옴)
                         *
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var status = BitConverter.ToUInt16(data, 28);
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 종료!", fate.Name);
                         */
                    }
                    else if (type == 0x74)
                    {
                        // 돌발 임무 발생 (지역 이동시에도 기존 돌발 목록이 옴)

                        var code = BitConverter.ToUInt16(data, 4);

                        var fate = Data.GetFATE(code);

                        if (Settings.FATEs.Contains(code))
                        {
                            mainForm.overlayForm.SetFATEAsOccured(fate);
                            Log.I("l-fate-occured-info", fate.Name);

                            if (!Settings.ShowOverlay)
                            {
                                mainForm.ShowNotification("notification-fate-occured", fate.Name);
                            }

                            if (Settings.FlashWindow)
                            {
                                WinApi.FlashWindow(mainForm.FFXIVProcess);
                            }

                            if (Settings.TwitterEnabled)
                            {
                                WebApi.Tweet("tweet-fate-occured", fate.Name);
                            }
                        }
                    }
                }

                /*else if (opcode == 0x006C) // 3.5 cross-world 파티 참가하면 문제가 발생하는 부분.
                 * {
                 *  var code = BitConverter.ToUInt16(data, 192);
                 *
                 *  var instance = Data.GetInstance(code);
                 *
                 *  state = State.QUEUED;
                 *  mainForm.overlayForm.SetDutyCount(1);
                 *
                 *  Log.I("l-queue-started-general", instance.Name);
                 * }*/
                else if (opcode == 0x0078)
                {
                    var status = data[0];
                    var reason = data[4];

                    if (status == 0)
                    {
                        state = State.QUEUED;

                        var rouletteCode = data[20];

                        if (rouletteCode != 0 && (data[15] == 0 || data[15] == 64)) //무작위 임무 신청, 한국서버/글로벌 서버
                        {
                            var roulette = Data.GetRoulette(rouletteCode);
                            mainForm.overlayForm.SetRoulleteDuty(roulette);
                            Log.I("l-queue-started-roulette", roulette.Name);
                        }
                        else //특정 임무 신청
                        {
                            var instances = new List <Instance>();

                            for (int i = 0; i < 5; i++)
                            {
                                var code = BitConverter.ToUInt16(data, 22 + (i * 2));
                                if (code == 0)
                                {
                                    break;
                                }
                                instances.Add(Data.GetInstance(code));
                            }

                            if (!instances.Any())
                            {
                                return;
                            }

                            mainForm.overlayForm.SetDutyCount(instances.Count);

                            Log.I("l-queue-started-general",
                                  string.Join(", ", instances.Select(x => x.Name).ToArray()));
                        }
                    }
                    else if (status == 3)
                    {
                        state = reason == 8 ? State.QUEUED : State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.E("l-queue-stopped");
                    }
                    else if (status == 6)
                    {
                        state = State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.I("l-queue-entered");
                    }
                    else if (status == 4) //글섭에서 매칭 잡혔을 때 출력
                    {
                        var roulette = data[20];
                        var code     = BitConverter.ToUInt16(data, 22);

                        Instance instance;

                        if (!Settings.CheatRoulette && roulette != 0)
                        {
                            instance = new Instance {
                                Name = Data.GetRoulette(roulette).Name
                            };
                        }
                        else
                        {
                            instance = Data.GetInstance(code);
                        }

                        state = State.MATCHED;
                        mainForm.overlayForm.SetDutyAsMatched(instance);

                        if (Settings.FlashWindow)
                        {
                            WinApi.FlashWindow(mainForm.FFXIVProcess);
                        }

                        if (!Settings.ShowOverlay)
                        {
                            mainForm.ShowNotification("notification-queue-matched", instance.Name);
                        }

                        if (Settings.TwitterEnabled)
                        {
                            WebApi.Tweet("tweet-queue-matched", instance.Name);
                        }

                        Log.S("l-queue-matched", instance.Name);
                    }
                }
                else if (opcode == 0x006F)
                {
                    var status = data[0];

                    if (status == 0)
                    {
                        // 플레이어가 매칭 참가 확인 창에서 취소를 누르거나 참가 확인 제한 시간이 초과됨
                        // 매칭 중단을 알리기 위해 상단 2DB status 3 패킷이 연이어 옴
                    }
                    if (status == 1)
                    {
                        // 플레이어가 매칭 참가 확인 창에서 확인을 누름
                        // 다른 매칭 인원들도 전부 확인을 눌렀을 경우 입장을 위해 상단 2DB status 6 패킷이 옴
                        mainForm.overlayForm.StopBlink();
                    }
                }
                else if (opcode == 0x0121) //글로벌 서버
                {
                    var status = data[5];

                    if (status == 128)
                    {
                        // 매칭 참가 신청 확인 창에서 확인을 누름
                        mainForm.overlayForm.StopBlink();
                    }
                }
                else if (opcode == 0x0079)
                {
                    var code   = BitConverter.ToUInt16(data, 0);
                    var status = data[4];
                    var tank   = data[5];
                    var dps    = data[6];
                    var healer = data[7];

                    var instance = Data.GetInstance(code);

                    if (status == 1)
                    {
                        // 인원 현황 패킷
                        var member = tank * 10000 + dps * 100 + healer;

                        if (state == State.MATCHED && lastMember != member)
                        {
                            // 매칭도중일 때 인원 현황 패킷이 오고 마지막 인원 정보와 다른 경우에 누군가에 의해 큐가 취소된 경우.
                            state = State.QUEUED;
                            mainForm.overlayForm.CancelDutyFinder();
                        }
                        else if (state == State.IDLE)
                        {
                            // 프로그램이 매칭 중간에 켜짐
                            state = State.QUEUED;
                            mainForm.overlayForm.SetDutyCount(-1); // 알 수 없음으로 설정함 (TODO: 알아낼 방법 있으면 정확히 나오게 수정하기)
                            mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                        }
                        else if (state == State.QUEUED)
                        {
                            mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                        }

                        lastMember = member;
                    }
                    else if (status == 2)
                    {
                        // 현재 매칭된 파티의 역할별 인원 수 정보
                        // 조율 해제 상태여도 역할별로 정확히 날아옴
                        mainForm.overlayForm.SetMemberCount(tank, dps, healer);
                        return;
                    }
                    else if (status == 4)
                    {
                        // 매칭 뒤 참가자 확인 현황 패킷
                        mainForm.overlayForm.SetConfirmStatus(instance, tank, dps, healer);
                    }
                    Log.I("l-queue-updated", instance.Name, status, tank, instance.Tank, healer, instance.Healer, dps,
                          instance.DPS);
                }
                else if (opcode == 0x0080)
                {
                    var roulette = data[2];
                    var code     = BitConverter.ToUInt16(data, 4);

                    Instance instance;

                    if (!Settings.CheatRoulette && roulette != 0)
                    {
                        instance = new Instance {
                            Name = Data.GetRoulette(roulette).Name
                        };
                    }
                    else
                    {
                        instance = Data.GetInstance(code);
                    }

                    state = State.MATCHED;
                    mainForm.overlayForm.SetDutyAsMatched(instance);

                    if (Settings.FlashWindow)
                    {
                        WinApi.FlashWindow(mainForm.FFXIVProcess);
                    }

                    if (!Settings.ShowOverlay)
                    {
                        mainForm.ShowNotification("notification-queue-matched", instance.Name);
                    }

                    if (Settings.TwitterEnabled)
                    {
                        WebApi.Tweet("tweet-queue-matched", instance.Name);
                    }

                    Log.S("l-queue-matched", instance.Name);
                }
            }
            catch (Exception ex)
            {
                Log.Ex(ex, "l-analyze-error-general");
            }
        }
Esempio n. 4
0
        private void HandleMessage(byte[] message)
        {
            try
            {
                if (message.Length < 32)
                {
                    // type == 0x0000 이였던 메시지는 여기서 걸러짐
                    return;
                }

                mainForm.overlayForm.SetStatus(true);

                var opcode = BitConverter.ToUInt16(message, 18);

#if !DEBUG
                if (opcode != 0x0078 &&
                    opcode != 0x0079 &&
                    opcode != 0x0080 &&
                    opcode != 0x006C &&
                    opcode != 0x006F &&
                    opcode != 0x0121 &&
                    opcode != 0x0143 &&
                    opcode != 0x022F &&
                    // v5.1
                    opcode != 0x008F &&
                    opcode != 0x00AE &&
                    opcode != 0x00B3 &&
                    opcode != 0x015E &&
                    opcode != 0x0121 &&
                    opcode != 0x0304 &&
                    // v5.11
                    opcode != 0x0164 &&
                    opcode != 0x032D &&
                    opcode != 0x03CF &&
                    opcode != 0x02A8 &&
                    opcode != 0x032F &&
                    opcode != 0x0339 &&
                    opcode != 0x0002)
                {
                    return;
                }
#endif

                var data = message.Skip(32).ToArray();

                if (opcode == 0x022F)
                {
                    var code = BitConverter.ToInt16(data, 4);
                    var type = data[8];

                    if (type == 0x0B)
                    {
                        Log.I("l-field-instance-entered", Data.GetInstance(code).Name);
                    }
                    else if (type == 0x0C)
                    {
                        Log.I("l-field-instance-left");
                    }

                    /*if (Settings.ShowOverlay && Settings.AutoOverlayHide)
                     * {
                     *  mainForm.overlayForm.Invoke(() =>
                     *  {
                     *      if (type == 0x0B)
                     *      {
                     *          mainForm.overlayForm.Hide();
                     *      }
                     *      else if (type == 0x0C)
                     *      {
                     *          mainForm.overlayForm.Show();
                     *      }
                     *  });
                     * }*/
                }
                else if (opcode == 0x0143)
                {
                    var type = data[0];

                    if (type == 0x9B)
                    {
                        /*
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var progress = data[8];
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 진행도 {1}%", fate.Name, progress);
                         */
                    }
                    else if (type == 0x79)
                    {
                        /*
                         * // 돌발 임무 종료 (지역 이동시 발생할 수 있는 모든 임무에 대해 전부 옴)
                         *
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var status = BitConverter.ToUInt16(data, 28);
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 종료!", fate.Name);
                         */
                    }
                    else if (type == 0x74)
                    {
                        // 돌발 임무 발생 (지역 이동시에도 기존 돌발 목록이 옴)

                        var code = BitConverter.ToUInt16(data, 4);

                        var fate = Data.GetFATE(code);

                        if (Settings.FATEs.Contains(code))
                        {
                            mainForm.overlayForm.SetFATEAsOccured(fate);
                            if (Settings.ShowOverlay)
                            {
                                mainForm.overlayForm.Show();
                            }
                            Log.I("l-fate-occured-info", fate.Name);

                            if (Settings.FateSound)
                            {
                                fatePlayer = new SoundPlayer(str);
                                fatePlayer.Stream.Position = 0; // fatePlayer가 Play()를 끝내기 전에 다시 Play()를 할 때 (한 번에 여러 돌발이 나타날 때) 버그 방지를 위해 필요한 코드
                                fatePlayer.Play();
                            }
                            else if (Settings.CustomSound)
                            {
                                notificationPlayer.Play();
                            }
                            if (!Settings.ShowOverlay)
                            {
                                mainForm.ShowNotification("notification-fate-occured", fate.Name);
                            }

                            if (Settings.FlashWindow)
                            {
                                WinApi.FlashWindow(mainForm.FFXIVProcess);
                            }

                            if (Settings.TelegramEnabled)
                            {
                                WebApi.Request("telegram", "fate-occured", fate.Name);
                            }

                            if (Settings.DiscordEnabled)
                            {
                                WebApi.Request("discord", "fate-occured", fate.Name);
                            }

                            if (Settings.customHttpRequest && Settings.requestOnFateOccured)
                            {
                                WebApi.customHttpRequest("fate-occured", fate.Name);
                            }
                        }
                    }
                }
                else if (opcode == 0x0078)
                {
                    var status = data[0];
                    var reason = data[4];

                    if (status == 0)
                    {
                        state = State.QUEUED;

                        rouletteCode = data[20];

                        if (Settings.ShowOverlay)
                        {
                            mainForm.overlayForm.Show();
                        }

                        if (rouletteCode != 0 && (data[15] == 0 || data[15] == 64)) //무작위 임무 신청, 한국서버/글로벌 서버
                        {
                            var roulette = Data.GetRoulette(rouletteCode);
                            mainForm.overlayForm.SetRoulleteDuty(roulette);
                            Log.I("l-queue-started-roulette", roulette.Name);
                        }
                        else //특정 임무 신청
                        {
                            rouletteCode = 0;
                            var instances = new List <Instance>();

                            for (int i = 0; i < 5; i++)
                            {
                                var code = BitConverter.ToUInt16(data, 22 + (i * 2));
                                if (code == 0)
                                {
                                    break;
                                }
                                instances.Add(Data.GetInstance(code));
                            }

                            if (!instances.Any())
                            {
                                return;
                            }

                            mainForm.overlayForm.SetDutyCount(instances.Count);

                            Log.I("l-queue-started-general",
                                  string.Join(", ", instances.Select(x => x.Name).ToArray()));
                        }
                    }
                    else if (status == 3)
                    {
                        state = reason == 8 ? State.QUEUED : State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.E("l-queue-stopped");
                    }
                    else if (status == 6)
                    {
                        state = State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.I("l-queue-entered");
                        mainForm.overlayForm.instances_callback(lastCode);
                    }
                    else if (status == 4) //글섭에서 매칭 잡혔을 때 출력
                    {
                        var roulette = data[20];
                        var code     = BitConverter.ToUInt16(data, 22);

                        Instance instance;
                        if (Settings.CustomSound)
                        {
                            notificationPlayer.Play();
                        }
                        if (!Settings.CheatRoulette && roulette != 0)
                        {
                            instance = new Instance {
                                Name = Data.GetRoulette(roulette).Name
                            };
                        }
                        else
                        {
                            instance = Data.GetInstance(code);
                        }

                        state = State.MATCHED;
                        mainForm.overlayForm.SetDutyAsMatched(instance);

                        if (Settings.FlashWindow)
                        {
                            WinApi.FlashWindow(mainForm.FFXIVProcess);
                        }

                        if (!Settings.ShowOverlay)
                        {
                            mainForm.ShowNotification("notification-queue-matched", instance.Name);
                        }

                        if (Settings.TelegramEnabled)
                        {
                            WebApi.Request("telegram", "duty-matched", instance.Name);
                        }

                        if (Settings.DiscordEnabled)
                        {
                            WebApi.Request("discord", "duty-matched", instance.Name);
                        }

                        if (Settings.customHttpRequest && Settings.requestOnDutyMatched)
                        {
                            WebApi.customHttpRequest("duty-matched", instance.Name);
                        }

                        Log.S("l-queue-matched", instance.Name);
                    }
                }
                else if (opcode == 0x008F || opcode == 0x0164) // v5.1, v5.11 (enroll duty)
                {
                    var status = data[0];
                    var reason = data[4];

                    state = State.QUEUED;

                    // rouletteCode = data[20];
                    rouletteCode = data[8];

                    if (Settings.ShowOverlay)
                    {
                        mainForm.overlayForm.Show();
                    }
                    if (rouletteCode != 0 && (data[15] == 0 || data[15] == 64)) //무작위 임무 신청, 한국서버/글로벌 서버
                    {
                        var roulette = Data.GetRoulette(rouletteCode);
                        mainForm.overlayForm.SetRoulleteDuty(roulette);
                        Log.I("l-queue-started-roulette", roulette.Name);
                    }
                    else //특정 임무 신청
                    {
                        rouletteCode = 0;
                        var instances = new List <Instance>();

                        for (int i = 0; i < 5; i++)
                        {
                            var code = BitConverter.ToUInt16(data, 12 + (i * 4));
                            if (code == 0)
                            {
                                break;
                            }
                            instances.Add(Data.GetInstance(code));
                        }
                        if (!instances.Any())
                        {
                            return;
                        }
                        mainForm.overlayForm.SetDutyCount(instances.Count);
                        mainForm.overlayForm.SetDutyAsMatching();
                        Log.I("l-queue-started-general",
                              string.Join(", ", instances.Select(x => x.Name).ToArray()));
                    }
                }
                else if (opcode == 0x00B3 || opcode == 0x032D) // v5.1, v5.11 (duty matched)
                {
                    var roulette = rouletteCode;
                    var code     = BitConverter.ToUInt16(data, 20);

                    Instance instance;
                    if (Settings.CustomSound)
                    {
                        notificationPlayer.Play();
                    }
                    if (!Settings.CheatRoulette && roulette != 0)
                    {
                        instance = new Instance {
                            Name = Data.GetRoulette(roulette).Name
                        };
                    }
                    else
                    {
                        instance = Data.GetInstance(code);
                    }

                    state = State.MATCHED;
                    mainForm.overlayForm.SetDutyAsMatched(instance);

                    if (Settings.FlashWindow)
                    {
                        WinApi.FlashWindow(mainForm.FFXIVProcess);
                    }

                    if (!Settings.ShowOverlay)
                    {
                        mainForm.ShowNotification("notification-queue-matched", instance.Name);
                    }

                    if (Settings.TelegramEnabled)
                    {
                        WebApi.Request("telegram", "duty-matched", instance.Name);
                    }

                    if (Settings.DiscordEnabled)
                    {
                        WebApi.Request("discord", "duty-matched", instance.Name);
                    }

                    if (Settings.customHttpRequest && Settings.requestOnDutyMatched)
                    {
                        WebApi.customHttpRequest("duty-matched", instance.Name);
                    }

                    Log.S("l-queue-matched", instance.Name);
                }
                else if (opcode == 0x006F)
                {
                    var status = data[0];

                    if (status == 0)
                    {
                        // 플레이어가 매칭 참가 확인 창에서 취소를 누르거나 참가 확인 제한 시간이 초과됨
                        // 매칭 중단을 알리기 위해 상단 2DB status 3 패킷이 연이어 옴
                    }
                    if (status == 1)
                    {
                        // 플레이어가 매칭 참가 확인 창에서 확인을 누름
                        // 다른 매칭 인원들도 전부 확인을 눌렀을 경우 입장을 위해 상단 2DB status 6 패킷이 옴
                        mainForm.overlayForm.StopBlink();
                    }
                }
                else if (opcode == 0x015E)            // cancel duty
                {
                    if (data[3] == 0 || data[3] == 8) // v5.1에서 8로 바뀌었다고 들음
                    {
                        state = State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.E("l-queue-stopped");
                    }
                }
                else if (opcode == 0x0121) // v5.1 commence duty
                {
                    var status = data[5];

                    if (status == 128)
                    {
                        // 매칭 참가 신청 확인 창에서 확인을 누름
                        mainForm.overlayForm.StopBlink();
                    }
                }
                else if (opcode == 0x03CF) // v5.11 cancel duty
                {
                    var status = data[0];

                    if (status == 0x73) // 매칭 취소
                    {
                        state = State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.E("l-queue-stopped");
                    }
                }
                else if (opcode == 0x0079)
                {
                    var code   = BitConverter.ToUInt16(data, 0);
                    var status = data[8];
                    var tank   = data[9];
                    var dps    = data[10];
                    var healer = data[11];
                    var order  = data[4];

                    var instance = Data.GetInstance(code);

                    if (status == 1)
                    {
                        // 인원 현황 패킷
                        var member = tank * 10000 + dps * 100 + healer;

                        if (state == State.MATCHED && lastMember != member)
                        {
                            // 매칭도중일 때 인원 현황 패킷이 오고 마지막 인원 정보와 다른 경우에 누군가에 의해 큐가 취소된 경우.
                            state = State.QUEUED;
                            mainForm.overlayForm.CancelDutyFinder();
                        }
                        else if (state == State.IDLE)
                        {
                            // 프로그램이 매칭 중간에 켜짐
                            state = State.QUEUED;
                            mainForm.overlayForm.SetDutyCount(-1); // 알 수 없음으로 설정함 (TODO: 알아낼 방법 있으면 정확히 나오게 수정하기)
                            if (rouletteCode > 0 || (tank == 0 && dps == 0 && healer == 0))
                            {
                                mainForm.overlayForm.SetDutyStatus(order);
                            }
                            else
                            {
                                mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                            }
                        }
                        else if (state == State.QUEUED)
                        {
                            if (rouletteCode > 0 || (tank == 0 && dps == 0 && healer == 0))
                            {
                                mainForm.overlayForm.SetDutyStatus(order);
                            }
                            else
                            {
                                mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                            }
                        }

                        // 직전 맴버 구성과 같은 상황이면 알림주지 않음
                        if (Settings.TelegramEnabled && Settings.TelegramQueueStatusEnabled)
                        {
                            if (rouletteCode == 0 && lastMember != member || !(tank == 0 && dps == 0 && healer == 0)) // 무작위 임무가 아님 (Not roulette duty)
                            {
                                WebApi.Request("telegram", "duty-status", $"{instance.Name}, {tank}/{instance.Tank}, {healer}/{instance.Healer}, {dps}/{instance.DPS}");
                            }
                            else if (order != 0 && lastOrder != order) // 매칭 현황을 받아오는 중이면 제외 (except 'retrieving information')
                            {
                                var roulette = Data.GetRoulette(rouletteCode);
                                WebApi.Request("telegram", "duty-status-roulette", $"{roulette.Name} - #{order}");
                            }
                        }

                        lastMember = member;
                        lastOrder  = order;
                    }
                    else if (status == 2)
                    {
                        // 현재 매칭된 파티의 역할별 인원 수 정보
                        // 조율 해제 상태여도 역할별로 정확히 날아옴
                        mainForm.overlayForm.SetMemberCount(tank, dps, healer);
                        return;
                    }
                    else if (status == 4)
                    {
                        // 매칭 뒤 참가자 확인 현황 패킷
                        mainForm.overlayForm.SetConfirmStatus(instance, tank, dps, healer);
                    }
                    lastCode = code;
                    Log.I("l-queue-updated", instance.Name, status, tank, instance.Tank, healer, instance.Healer, dps,
                          instance.DPS);
                }
                else if (opcode == 0x0304)
                {
                    //var code = BitConverter.ToUInt16(data, 0); // 이제 던전 안알려줌. 대신 max 인원 알려줌.
                    //var status = data[8];
                    var order     = data[6];
                    var waitTime  = data[7];
                    var tank      = data[8];
                    var tankMax   = data[9];
                    var healer    = data[10];
                    var healerMax = data[11];
                    var dps       = data[12];
                    var dpsMax    = data[13];

                    //var instance = Data.GetInstance(code);

                    //if (status == 1)
                    //{
                    // 인원 현황 패킷
                    var member = tank * 10000 + dps * 100 + healer;

                    if (state == State.MATCHED && lastMember != member)
                    {
                        // 매칭도중일 때 인원 현황 패킷이 오고 마지막 인원 정보와 다른 경우에 누군가에 의해 큐가 취소된 경우.
                        state = State.QUEUED;
                        mainForm.overlayForm.CancelDutyFinder();
                    }
                    else if (state == State.IDLE)
                    {
                        // 프로그램이 매칭 중간에 켜짐
                        state = State.QUEUED;
                        mainForm.overlayForm.SetDutyCount(-1); // 알 수 없음으로 설정함 (TODO: 알아낼 방법 있으면 정확히 나오게 수정하기)
                        if (rouletteCode > 0)
                        {
                            mainForm.overlayForm.SetDutyStatus(order);
                        }
                        else
                        {
                            mainForm.overlayForm.SetDutyStatus(tank, tankMax, dps, dpsMax, healer, healerMax);
                        }
                    }
                    else if (state == State.QUEUED)
                    {
                        if (rouletteCode > 0)
                        {
                            mainForm.overlayForm.SetDutyStatus(order);
                        }
                        else
                        {
                            mainForm.overlayForm.SetDutyStatus(tank, tankMax, dps, dpsMax, healer, healerMax);
                        }
                    }

                    // 직전 맴버 구성과 같은 상황이면 알림주지 않음
                    if (Settings.TelegramEnabled && Settings.TelegramQueueStatusEnabled)
                    {
                        if (rouletteCode == 0 && lastMember != member || !(tank == 0 && dps == 0 && healer == 0)) // 무작위 임무가 아님 (Not roulette duty)
                        {
                            WebApi.Request("telegram", "duty-status", $"{tank}/{tankMax}, {healer}/{healerMax}, {dps}/{dpsMax}");
                        }
                        else if (order != 0 && lastOrder != order) // 매칭 현황을 받아오는 중이면 제외 (except 'retrieving information')
                        {
                            var roulette = Data.GetRoulette(rouletteCode);
                            WebApi.Request("telegram", "duty-status-roulette", $"{roulette.Name} - #{order}");
                        }
                    }

                    lastMember = member;
                    lastOrder  = order;
                    //}

                    /*else if (status == 2)
                     * {
                     *  // 현재 매칭된 파티의 역할별 인원 수 정보
                     *  // 조율 해제 상태여도 역할별로 정확히 날아옴
                     *  mainForm.overlayForm.SetMemberCount(tank, dps, healer);
                     *  return;
                     * }*/
                    Log.I("l-queue-updated", "", /*status*/ 1, tank, tankMax, healer, healerMax, dps, dpsMax);
                }
                else if (opcode == 0x00AE || opcode == 0x032F) // v5.1, v5.11 매칭 뒤 참가자 확인 현황 패킷
                {
                    var code   = BitConverter.ToUInt16(data, 8);
                    var tank   = data[12];
                    var healer = data[14];
                    var dps    = data[16];

                    var instance = Data.GetInstance(code);

                    mainForm.overlayForm.SetConfirmStatus(instance, tank, dps, healer);

                    lastCode = code;
                    Log.I("l-queue-updated", instance.Name, 4, tank, instance.Tank, healer, instance.Healer, dps,
                          instance.DPS);
                }
                else if (opcode == 0x0080)
                {
                    var roulette = data[2];
                    var code     = BitConverter.ToUInt16(data, 4);

                    Instance instance;
                    if (Settings.CustomSound)
                    {
                        notificationPlayer.Play();
                    }
                    if (!Settings.CheatRoulette && roulette != 0)
                    {
                        instance = new Instance {
                            Name = Data.GetRoulette(roulette).Name
                        };
                    }
                    else
                    {
                        instance = Data.GetInstance(code);
                    }

                    state = State.MATCHED;
                    mainForm.overlayForm.SetDutyAsMatched(instance);

                    if (Settings.FlashWindow)
                    {
                        WinApi.FlashWindow(mainForm.FFXIVProcess);
                    }

                    if (!Settings.ShowOverlay)
                    {
                        mainForm.ShowNotification("notification-queue-matched", instance.Name);
                    }

                    if (Settings.TelegramEnabled)
                    {
                        WebApi.Request("telegram", "duty-matched", instance.Name);
                    }

                    if (Settings.DiscordEnabled)
                    {
                        WebApi.Request("discord", "duty-matched", instance.Name);
                    }

                    if (Settings.customHttpRequest && Settings.requestOnDutyMatched)
                    {
                        WebApi.customHttpRequest("duty-matched", instance.Name);
                    }

                    Log.S("l-queue-matched", instance.Name);
                }
            }
            catch (Exception ex)
            {
                Log.Ex(ex, "l-analyze-error-general");
            }
        }
Esempio n. 5
0
        private void HandleMessage(byte[] message)
        {
            try
            {
                if (message.Length < 32)
                {
                    // type == 0x0000 Messages were filtered here
                    return;
                }

                var opcode = BitConverter.ToUInt16(message, 18);

#if !DEBUG
                if (opcode != 0x0078 &&
                    opcode != 0x0079 &&
                    opcode != 0x0080 &&
                    opcode != 0x006C &&
                    opcode != 0x006F &&
                    opcode != 0x0121 &&
                    opcode != 0x0143 &&
                    opcode != 0x022F)
                {
                    return;
                }
#endif

                var data = message.Skip(32).ToArray();

                // Entry / exit
                if (opcode == 0x022F)
                {
                    var code = BitConverter.ToInt16(data, 4);
                    var type = data[8];

                    Log.B(data);

                    if (type == 0x0B)
                    {
                        //Log.I("l-field-instance-entered", Data.GetInstance(code).Name);
                        // EVENT: When worn, code = dungeon code
                        //
                        //Log.I("l-field-instance-entered " + code);
                        Log.I("Incoming code=" + code);
                        fireEvent(EventType.INSTANCE_ENTER, new int[] { code });
                    }
                    else if (type == 0x0C)
                    {
                        // EVENT: Come out of dress
                        //Log.I("l-field-instance-left");
                        Log.I("I'm leaving=" + code);
                        fireEvent(EventType.INSTANCE_EXIT, new int[] { code });
                    }
                }
                //Outbreak: occurring, in progress, ending
                else if (opcode == 0x0143)
                {
                    var type = data[0];

                    if (type == 0x9B)
                    {
                        var code     = BitConverter.ToUInt16(data, 4);
                        var progress = data[8];

                        /*
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" Breakthrough progress {1}%", fate.Name, progress);
                         */
                        // EVENT: breakthrough, code = breakthrough, progress = progress percentage
                        //Log.I(code + " Breakthrough progress " + progress);
                        fireEvent(EventType.FATE_PROGRESS, new int[] { code, progress });
                    }
                    else if (type == 0x79)
                    {
                        // Unexpected mission termination (for all missions that may occur when moving the area)

                        var code   = BitConverter.ToUInt16(data, 4);
                        var status = BitConverter.ToUInt16(data, 28);

                        /*
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" Break out!", fate.Name);
                         */
                        // EVENT: At the end of the mission, code = emergency code,
                        Log.I("Abrupt end=" + code + ", status=" + status);
                        fireEvent(EventType.FATE_END, new int[] { code, status });
                    }
                    else if (type == 0x74)
                    {
                        // Occurrence of an outbreak (even if you move the area, the existing breakdown list comes)
                        // EVENT: Occurrence of an unexpected mission, code = Unexpected code (also occurs when moving map)
                        var code = BitConverter.ToUInt16(data, 4);
                        Log.I("Abrupt =" + code);
                        //var fate = Data.GetFATE(code);
                        fireEvent(EventType.FATE_BEGIN, new int[] { code });
                    }
                }
                // Matching information
                else if (opcode == 0x0078)
                {
                    var status = data[0];
                    var reason = data[4];

                    //apply
                    if (status == 0)
                    {
                        NetCompatibility = false;
                        state            = State.QUEUED;

                        var rouletteCode = data[20];

                        if (rouletteCode != 0 && (data[15] == 0 || data[15] == 64)) //Random assignment application, Korea server / global server
                        {
                            //var roulette = Data.GetRoulette(rouletteCode);
                            //mainForm.overlayForm.SetRoulleteDuty(roulette);
                            //Log.I("l-queue-started-roulette", roulette.Name);
                            Log.I("Matching application, random type=" + rouletteCode);
                            fireEvent(EventType.MATCH_BEGIN, new int[] { (int)MatchType.ROULETTE, rouletteCode });
                        }
                        else //Apply for a specific mission
                        {
                            // var instances = new List<Instance>();
                            var instances = new List <int>();
                            for (int i = 0; i < 5; i++)
                            {
                                var code = BitConverter.ToUInt16(data, 22 + (i * 2));
                                if (code == 0)
                                {
                                    break;
                                }
                                //instances.Add(Data.GetInstance(code));
                                instances.Add(code);
                            }

                            if (!instances.Any())
                            {
                                return;
                            }

                            var args = new List <int>();
                            args.Add((int)MatchType.SELECTIVE);
                            args.Add(instances.Count);
                            for (int i = 0; i < instances.Count; i++)
                            {
                                args.Add(instances[i]);
                            }

                            // Log.I("l-queue-started-general",
                            //string.Join(", ", instances.Select(x => x.Name).ToArray()));*/
                            Log.I("Matching application, selected =", string.Join(", ", instances) + ", count=" + instances.Count);
                            fireEvent(EventType.MATCH_BEGIN, args.ToArray());
                        }
                    }
                    // cancel
                    else if (status == 3)
                    {
                        state = reason == 8 ? State.QUEUED : State.IDLE;
                        //mainForm.overlayForm.CancelDutyFinder();

                        //Log.E("l-queue-stopped");
                        Log.I("Unmatch, reason=" + reason);
                        fireEvent(EventType.MATCH_END, new int[] { (int)MatchEndType.CANCELLED });
                    }
                    // Entered
                    else if (status == 6)
                    {
                        state = State.IDLE;
                        //mainForm.overlayForm.CancelDutyFinder();

                        //Log.I("l-queue-entered");
                        Log.I("Match entry");
                        fireEvent(EventType.MATCH_END, new int[] { (int)MatchEndType.ENTER_INSTANCE });
                    }
                    // Matching
                    else if (status == 4) // Output when matched in the foreground
                    {
                        var roulette = data[20];
                        var code     = BitConverter.ToUInt16(data, 22);

                        Instance instance;

                        //If the matched indent information can not be checked,

                        if (roulette != 0)
                        {
                            instance = new Instance {
                                Name = Data.GetRoulette(roulette).Name
                            };
                        }
                        else
                        {
                            instance = Data.GetInstance(code);
                        }

                        state = State.MATCHED;


                        Log.I("Matching (Gloss) Match type=" + roulette + ", Matched indones=" + code);
                        fireEvent(EventType.MATCH_ALERT, new int[] { roulette, code });
                    }
                }
                else if (opcode == 0x006F)
                {
                    /*
                     * var status = data[0];
                     *
                     * if (status == 0)
                     * {
                     *  // Player clicks Cancel in the Match Participation Confirmation window or the Participation Confirmation Timeout is exceeded
                     *                          // Upper 2db status 3 packets coming in to notify matching termination
                     *  log.i("Matched stopped status=" + status + ", cancel or timeout");
                     * }
                     * if (status == 1)
                     * {
                     *  // Player clicks OK in the matching entry confirmation window
                     *                         // If all other matching personnel have clicked OK, the top 2db status 6 packets for admission
                     *  //mainform.overlayform.stopblink();
                     *  log.i("Matched status =" + status + ", press confirm or others);
                     * }*/
                }
                else if (opcode == 0x0121) // Global server
                {
                    var status = data[5];

                    if (status == 128)
                    {
                        //Click OK on the Matching Application Confirmation window
                        //mainForm.overlayForm.StopBlink();
                        Log.I("Matching, Matching Click OK in the application confirmation window (Global)");
                    }
                }
                // Status in matched state
                else if (opcode == 0x0079)
                {
                    var  code   = BitConverter.ToUInt16(data, 0);
                    byte status = 0;
                    byte tank   = 0;
                    byte dps    = 0;
                    byte healer = 0;
                    if (NetCompatibility) // V4.5 版本兼容性
                    {
                        order = data[4];  //职能等待顺序
                        order--;
                        status = data[8];
                        tank   = data[9];
                        dps    = data[10];
                        healer = data[11];
                    }
                    else
                    {
                        order  = data[5];
                        status = data[4];
                        tank   = data[5];
                        dps    = data[6];
                        healer = data[7];
                    }

                    if (status == 0 && tank == 0 && healer == 0 && dps == 0) // 检查数据异常进行兼容处理
                    {
                        NetCompatibility = true;
                        order            = 255;
                        status           = data[8];
                        tank             = data[9];
                        dps    = data[10];
                        healer = data[11];
                    }

                    //var instance = Data.GetInstance(code);

                    if (status == 1)
                    {
                        // Personnel status packet
                        var member = tank * 10000 + dps * 100 + healer;

                        if (state == State.MATCHED && lastMember != member)
                        {
                            // If the queue status is canceled by someone when the status packet arrives at the time of matching and is different from the last person information.
                            state = State.QUEUED;
                            //mainForm.overlayForm.CancelDutyFinder();
                            Log.I("Match progress, someone canceled");
                        }
                        else if (state == State.IDLE)
                        {
                            // Program is on in the middle of matching
                            state = State.QUEUED;
                            //mainForm.overlayForm.SetDutyCount(-1); // Set to unknown (TODO: If there is a way to find out, fix it to be correct)
                            //mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                        }
                        else if (state == State.QUEUED)
                        {
                            //mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                        }

                        lastMember = member;
                    }
                    else if (status == 2)
                    {
                        // Information on the number of people by role of the currently matched party
                        // Even if it is in un-tuned state,
                        //mainForm.overlayForm.SetMemberCount(tank, dps, healer);
                        return;
                    }
                    else if (status == 4)
                    {
                        // After Matching, Participant Confirmation Status Packet
                        //mainForm.overlayForm.SetConfirmStatus(instance, tank, dps, healer);
                    }
                    //Log.I("l-queue-updated", instance.Name, status, tank, instance.Tank, healer, instance.Healer, dps, instance.DPS);
                    Log.I("Matching progress, code=" + code + ", " + status + ", T " + tank + ", H " + healer + ", D " + dps);
                    fireEvent(EventType.MATCH_PROGRESS, new int[] { code, status, tank, healer, dps });
                }
                else if (opcode == 0x0080)
                {
                    var roulette = data[2];
                    var code     = BitConverter.ToUInt16(data, 4);

                    Instance instance;

                    if (roulette != 0)
                    {
                        instance = new Instance {
                            Name = Data.GetRoulette(roulette).Name
                        };
                    }
                    else
                    {
                        instance = Data.GetInstance(code);
                    }

                    state = State.MATCHED;

                    Log.S("l-queue-matched " + code);
                    fireEvent(EventType.MATCH_ALERT, new int[] { roulette, code });
                }
            }
            catch (Exception ex)
            {
                Log.Ex(ex, "[" + pid + "]l-analyze-error-general");
            }
        }
Esempio n. 6
0
        private void HandleMessage(byte[] message)
        {
            try
            {
                if (message.Length < 32)
                {
                    // type == 0x0000 이였던 메시지는 여기서 걸러짐
                    return;
                }

                mainForm.overlayForm.SetStatus(true);

                var opcode = BitConverter.ToUInt16(message, 18);
                if (opcode != 0x0142 &&
                    opcode != 0x0143 &&
                    opcode != 0x006C &&
                    opcode != 0x0074 &&
                    opcode != 0x0076 &&
                    opcode != 0x02DB &&
                    opcode != 0x006F &&
                    opcode != 0x02DE &&
                    opcode != 0x0339)
                {
                    return;
                }

                var data = message.Skip(32).ToArray();

                if (opcode == 0x0142)
                {
                    var type = data[0];

                    if (type == 0xCF)
                    {
                        var selfkey = BitConverter.ToInt32(message, 8);
                        var charkey = BitConverter.ToInt32(message, 40);

                        var code = BitConverter.ToUInt16(data, 16);
                        var zone = Data.GetArea(code);

                        byte teleMeasure = message[36];

                        if (selfkey == charkey) // isSelf
                        {
                            ushort lastCode = (BitConverter.ToUInt16(System.Text.Encoding.Unicode.GetBytes(new char[] { Data.GetAreaName(code).Last() }), 0));
                            string lastChar = ((lastCode - 0xAC00U) % 28 == 0 || lastCode - 0xAC00U == 8 ? "로" : "으로");

                            if (teleMeasure != 0x0C)
                            {
                                Log.D("{1}{2} 지역으로 이동했습니다. ({0})", code, Data.GetAreaName(code), lastChar);
                            }
                            else
                            {
                                Log.D("임무에서 퇴장했습니다. ({0})", teleMeasure);
                            }

                            mainForm.overlayForm.currentArea = code;
                        }
                    }
                }
                else if (opcode == 0x0143)
                {
                    var type = data[0];

                    if (type == 0x9B)
                    {
                        /*
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var progress = data[8];
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 진행도 {1}%", fate.Name, progress);
                         */
                    }
                    else if (type == 0x79)
                    {
                        /*
                         * // 돌발 임무 종료 (지역 이동시 발생할 수 있는 모든 임무에 대해 전부 옴)
                         *
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var status = BitConverter.ToUInt16(data, 28);
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 종료!", fate.Name);
                         */
                    }
                    else if (type == 0x74)
                    {
                        // 돌발 임무 발생 (지역 이동시에도 기존 돌발 목록이 옴)

                        var code = BitConverter.ToUInt16(data, 4);

                        var fate = Data.GetFATE(code);

                        if (Settings.FATEs.Contains(code))
                        {
                            mainForm.overlayForm.SetFATEAsAppeared(fate);

                            if (Settings.FlashWindow)
                            {
                                WinApi.FlashWindow(mainForm.FFXIVProcess);
                            }

                            if (Settings.TwitterEnabled)
                            {
                                WebApi.Tweet("< {0} > 돌발 발생!", fate.Name);
                            }
                        }

                        Log.D("\"{0}\" 돌발 발생!", fate.Name);
                    }
                }
                else if (opcode == 0x006C)
                {
                    var code = BitConverter.ToUInt16(data, 192);

                    var instance = Data.GetInstance(code);

                    state = State.QUEUED;
                    mainForm.overlayForm.SetDutyCount(1);

                    Log.I("DFAN: 매칭 시작됨 (6C) [{0}]", instance.Name);
                }
                else if (opcode == 0x0074)
                {
                    var instances = new List <Instance>();

                    for (int i = 0; i < 5; i++)
                    {
                        var code = BitConverter.ToUInt16(data, 192 + (i * 2));
                        if (code == 0)
                        {
                            break;
                        }
                        instances.Add(Data.GetInstance(code));
                    }

                    if (!instances.Any())
                    {
                        return;
                    }

                    state = State.QUEUED;
                    mainForm.overlayForm.SetDutyCount(instances.Count);

                    Log.I("DFAN: 매칭 시작됨 (74) [{0}]", string.Join(", ", instances.Select(x => x.Name).ToArray()));
                }
                else if (opcode == 0x0076)
                {
                    var code     = data[192];
                    var roulette = Data.GetRoulette(code);

                    state = State.QUEUED;
                    mainForm.overlayForm.SetRoulleteDuty(roulette);

                    Log.I("DFAN: 무작위 임무 매칭 시작됨 [{0}]", roulette.Name);
                }
                else if (opcode == 0x02DB)
                {
                    var status = data[0];

                    if (status == 3)
                    {
                        state = State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.E("DFAN: 매칭 중지됨 (2DB)");
                    }
                    else if (status == 6)
                    {
                        state = State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.I("DFAN: 입장함");
                    }
                }
                else if (opcode == 0x006F)
                {
                    var status = data[0];

                    if (status == 0)
                    {
                        // 플레이어가 매칭 참가 확인 창에서 취소를 누르거나 참가 확인 제한 시간이 초과됨
                        // 매칭 중단을 알리기 위해 상단 2DB status 3 패킷이 연이어 옴
                    }
                    if (status == 1)
                    {
                        // 플레이어가 매칭 참가 확인 창에서 확인을 누름
                        // 다른 매칭 인원들도 전부 확인을 눌렀을 경우 입장을 위해 상단 2DB status 6 패킷이 옴
                        mainForm.overlayForm.StopBlink();
                    }
                }
                else if (opcode == 0x02DE)
                {
                    var code   = BitConverter.ToUInt16(data, 0);
                    var status = data[4];
                    var tank   = data[5];
                    var dps    = data[6];
                    var healer = data[7];

                    var instance = Data.GetInstance(code);

                    if (status == 1)
                    {
                        // 인원 현황 패킷
                        var member = tank * 10000 + dps * 100 + healer;

                        if (state == State.MATCHED && lastMember != member)
                        {
                            // 매칭도중일 때 인원 현황 패킷이 오고 마지막 인원 정보와 다른 경우에 누군가에 의해 큐가 취소된 경우.
                            state = State.QUEUED;
                            mainForm.overlayForm.CancelDutyFinder();
                        }
                        else if (state == State.IDLE)
                        {
                            // 프로그램이 매칭 중간에 켜짐
                            state = State.QUEUED;
                            mainForm.overlayForm.SetDutyCount(-1); // 알 수 없음으로 설정함 (TODO: 알아낼 방법 있으면 정확히 나오게 수정하기)
                            mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                        }
                        else if (state == State.QUEUED)
                        {
                            mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                        }

                        lastMember = member;
                    }
                    else if (status == 2)
                    {
                        // 현재 매칭된 파티의 역할별 인원 수 정보
                        // 조율 해제 상태여도 역할별로 정확히 날아옴
                        mainForm.overlayForm.SetMemberCount(tank, dps, healer);
                        return;
                    }
                    else if (status == 4)
                    {
                        // 매칭 뒤 참가자 확인 현황 패킷
                        mainForm.overlayForm.SetConfirmStatus(instance, tank, dps, healer);
                    }

                    Log.I("DFAN: 매칭 상태 업데이트됨 [{0}, {1}, {2}/{3}, {4}/{5}, {6}/{7}]",
                          instance.Name, status, tank, instance.Tank, healer, instance.Healer, dps, instance.DPS);
                }
                else if (opcode == 0x0339)
                {
                    var roulette = data[3];
                    var code     = BitConverter.ToUInt16(data, 4);

                    Instance instance;

                    if (!Settings.CheatRoulette && roulette != 0)
                    {
                        instance = new Instance(Data.GetRoulette(roulette).Name, 0, 0, 0);
                    }
                    else
                    {
                        instance = Data.GetInstance(code);
                    }

                    state = State.MATCHED;
                    mainForm.overlayForm.SetDutyAsMatched(instance);

                    if (Settings.FlashWindow)
                    {
                        WinApi.FlashWindow(mainForm.FFXIVProcess);
                    }

                    if (!Settings.ShowOverlay)
                    {
                        mainForm.ShowNotification("< {0} > 매칭!", instance.Name);
                    }

                    if (Settings.TwitterEnabled)
                    {
                        WebApi.Tweet("< {0} > 매칭!", instance.Name);
                    }

                    Log.S("DFAN: 매칭됨 [{0}]", instance.Name);
                }
            }
            catch (Exception ex)
            {
                Log.Ex(ex, "메시지 처리중 에러 발생함");
            }
        }
Esempio n. 7
0
        private async System.Threading.Tasks.Task HandleMessageAsync(byte[] message)
        {
            try
            {
                if (message.Length < 32)
                {
                    // type == 0x0000 이였던 메시지는 여기서 걸러짐
                    // Messages with type == 0x0000 are filtered out here
                    return;
                }

                mainForm.overlayForm.SetStatus(true);

                var opcode = BitConverter.ToUInt16(message, 18);

#if !DEBUG
                if (opcode != 0x0078 &&
                    opcode != 0x0079 &&
                    opcode != 0x0080 &&
                    opcode != 0x006C &&
                    opcode != 0x006F &&
                    opcode != 0x0121 &&
                    opcode != 0x0143 &&
                    opcode != 0x022F)
                {
                    return;
                }
#endif

                var data = message.Skip(32).ToArray();

                if (!seenPackets.Contains(opcode))
                {
                    Log.I(string.Format("Saw packet type {0:x4}.", opcode));
                    seenPackets.Add(opcode);
                }

                if (opcode == 0x022F)
                {
                    var code = BitConverter.ToInt16(data, 4);
                    var type = data[8];

                    Log.B(data);

                    if (type == 0x0B)
                    {
                        Log.I("l-field-instance-entered", Data.GetInstance(code).Name);
                    }
                    else if (type == 0x0C)
                    {
                        Log.I("l-field-instance-left");
                    }

                    if (Settings.ShowOverlay && Settings.AutoOverlayHide)
                    {
                        mainForm.overlayForm.Invoke(() =>
                        {
                            if (type == 0x0B)
                            {
                                mainForm.overlayForm.Hide();
                            }
                            else if (type == 0x0C)
                            {
                                mainForm.overlayForm.Show();
                            }
                        });
                    }
                }
                else if (opcode == 0x0143)
                {
                    var type = data[0];

                    if (type == 0x9B)
                    {
                        /*
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var progress = data[8];
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 진행도 {1}%", fate.Name, progress);
                         */
                    }
                    else if (type == 0x79)
                    {
                        /*
                         * // 돌발 임무 종료 (지역 이동시 발생할 수 있는 모든 임무에 대해 전부 옴)
                         *
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var status = BitConverter.ToUInt16(data, 28);
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 종료!", fate.Name);
                         */
                    }
                    else if (type == 0x74)
                    {
                        // 돌발 임무 발생 (지역 이동시에도 기존 돌발 목록이 옴)

                        var code = BitConverter.ToUInt16(data, 4);

                        var fate = Data.GetFATE(code);

                        if (Settings.FATEs.Contains(code))
                        {
                            mainForm.overlayForm.SetFATEAsOccured(fate);
                            Log.I("l-fate-occured-info", fate.Name);

                            if (Settings.FlashWindow)
                            {
                                WinApi.FlashWindow(mainForm.FFXIVProcess);
                            }

                            if (Settings.TwitterEnabled)
                            {
                                WebApi.Tweet("tweet-fate-occured", fate.Name);
                            }
                        }
                    }
                }

                /*else if (opcode == 0x006C) // 3.5 cross-world 파티 참가하면 문제가 발생하는 부분.
                 * {
                 *  var code = BitConverter.ToUInt16(data, 192);
                 *
                 *  var instance = Data.GetInstance(code);
                 *
                 *  state = State.QUEUED;
                 *  mainForm.overlayForm.SetDutyCount(1);
                 *
                 *  Log.I("l-queue-started-general", instance.Name);
                 * }*/
                else if (opcode == 0x0078)
                {
                    var status = data[0];
                    var reason = data[4];

                    if (status == 0)
                    {
                        state = State.QUEUED;

                        var rouletteCode = data[20];

                        // Random assignment, Korea server / global server
                        if (rouletteCode != 0 && (data[15] == 0 || data[15] == 64)) //무작위 임무 신청, 한국서버/글로벌 서버
                        {
                            var roulette = Data.GetRoulette(rouletteCode);
                            mainForm.overlayForm.SetRoulleteDuty(roulette);
                            Log.I("l-queue-started-roulette", roulette.Name);
                        }
                        else //특정 임무 신청
                        // Apply for a specific mission
                        {
                            var instances = new List <Instance>();

                            for (int i = 0; i < 5; i++)
                            {
                                var code = BitConverter.ToUInt16(data, 22 + (i * 2));
                                if (code == 0)
                                {
                                    break;
                                }
                                instances.Add(Data.GetInstance(code));
                            }

                            if (!instances.Any())
                            {
                                return;
                            }

                            mainForm.overlayForm.SetDutyCount(instances.Count);

                            Log.I("l-queue-started-general",
                                  string.Join(", ", instances.Select(x => x.Name).ToArray()));
                        }
                    }
                    else if (status == 3)
                    {
                        state = reason == 8 ? State.QUEUED : State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.E("l-queue-stopped");
                    }
                    else if (status == 6)
                    {
                        state = State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();

                        Log.I("l-queue-entered");
                    }
                    else if (status == 4) //글섭에서 매칭 잡혔을 때 출력
                                          // Output when matched in Gap
                    {
                        var roulette = data[20];
                        var code     = BitConverter.ToUInt16(data, 22);

                        Instance instance;

                        if (!Settings.CheatRoulette && roulette != 0)
                        {
                            instance = new Instance {
                                Name = Data.GetRoulette(roulette).Name
                            };
                        }
                        else
                        {
                            instance = Data.GetInstance(code);
                        }

                        state = State.MATCHED;
                        mainForm.overlayForm.SetDutyAsMatched(instance);

                        if (Settings.FlashWindow)
                        {
                            WinApi.FlashWindow(mainForm.FFXIVProcess);
                        }

                        if (!Settings.ShowOverlay)
                        {
                            mainForm.ShowNotification("notification-queue-matched", instance.Name);
                        }

                        if (Settings.TwitterEnabled)
                        {
                            WebApi.Tweet("tweet-queue-matched", instance.Name);
                        }

                        Log.S("l-queue-matched", instance.Name);
                    }
                }
                else if (opcode == 0x006F)
                {
                    var status = data[0];

                    if (status == 0)
                    {
                        // 플레이어가 매칭 참가 확인 창에서 취소를 누르거나 참가 확인 제한 시간이 초과됨
                        // 매칭 중단을 알리기 위해 상단 2DB status 3 패킷이 연이어 옴

                        // Player clicks Cancel in the Match Participation Confirmation window or the Participation Confirmation Timeout is exceeded
                        // Upper 2DB status 3 packets in succession
                    }
                    if (status == 1)
                    {
                        // 플레이어가 매칭 참가 확인 창에서 확인을 누름
                        // 다른 매칭 인원들도 전부 확인을 눌렀을 경우 입장을 위해 상단 2DB status 6 패킷이 옴

                        // Player clicks OK in the matching entry confirmation window
                        // If all other matching personnel have clicked OK, the top 2DB status 6 packets for admission
                        mainForm.overlayForm.StopBlink();
                    }
                }
                else if (opcode == 0x0121)
                // Global server
                {
                    var status = data[5];

                    if (status == 128)
                    {
                        // 매칭 참가 신청 확인 창에서 확인을 누름
                        // Click OK on Confirmation of Matching Application
                        mainForm.overlayForm.StopBlink();
                    }
                }
                else if (opcode == 0x0079)
                {
                    var code   = BitConverter.ToUInt16(data, 0);
                    var status = data[4];
                    var tank   = data[5];
                    var dps    = data[6];
                    var healer = data[7];

                    var instance = Data.GetInstance(code);

                    if (status == 1)
                    {
                        // 인원 현황 패킷
                        // Personnel Status Packet
                        var member = tank * 10000 + dps * 100 + healer;

                        if (state == State.MATCHED && lastMember != member)
                        {
                            // 매칭도중일 때 인원 현황 패킷이 오고 마지막 인원 정보와 다른 경우에 누군가에 의해 큐가 취소된 경우.
                            // If the queue status is canceled by somebody when the status packet arrives when it is in the
                            // middle of matching and is different from the last passer's information.
                            state = State.QUEUED;
                            mainForm.overlayForm.CancelDutyFinder();
                        }
                        else if (state == State.IDLE)
                        {
                            // 프로그램이 매칭 중간에 켜짐
                            // program is on in the middle of matching
                            state = State.QUEUED;
                            mainForm.overlayForm.SetDutyCount(-1); // 알 수 없음으로 설정함 (TODO: 알아낼 방법 있으면 정확히 나오게 수정하기)
                                                                   // Set to unknown (TODO: if there is a way to find out, fix it to be correct)
                            mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                        }
                        else if (state == State.QUEUED)
                        {
                            mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                        }

                        lastMember = member;
                    }
                    else if (status == 2)
                    {
                        // 현재 매칭된 파티의 역할별 인원 수 정보
                        // 조율 해제 상태여도 역할별로 정확히 날아옴
                        // Information on the number of people by role of the currently matched party
                        // Even if it is in un-tuned state,
                        mainForm.overlayForm.SetMemberCount(tank, dps, healer);
                        return;
                    }
                    else if (status == 4)
                    {
                        // 매칭 뒤 참가자 확인 현황 패킷
                        // Participant check status packet after matching
                        mainForm.overlayForm.SetConfirmStatus(instance, tank, dps, healer);
                    }
                    Log.I("l-queue-updated", instance.Name, status, tank, instance.Tank, healer, instance.Healer, dps,
                          instance.DPS);
                }
                else if (opcode == 0x0080)
                {
                    var roulette = data[2];
                    var code     = BitConverter.ToUInt16(data, 4);

                    Instance instance;

                    if (!Settings.CheatRoulette && roulette != 0)
                    {
                        instance = new Instance {
                            Name = Data.GetRoulette(roulette).Name
                        };
                    }
                    else
                    {
                        instance = Data.GetInstance(code);
                    }

                    state = State.MATCHED;
                    mainForm.overlayForm.SetDutyAsMatched(instance);

                    if (Settings.FlashWindow)
                    {
                        WinApi.FlashWindow(mainForm.FFXIVProcess);
                    }

                    if (!Settings.ShowOverlay)
                    {
                        mainForm.ShowNotification("notification-queue-matched", instance.Name);
                    }

                    if (Settings.TwitterEnabled)
                    {
                        WebApi.Tweet("tweet-queue-matched", instance.Name);
                    }

                    Log.S("l-queue-matched", instance.Name);
                }
                else if (opcode == 0x00e6)
                {
                    var itemId = BitConverter.ToUInt32(data, 0);
                    int offset = 4;

                    while (offset < data.Length)
                    {
                        var resp = await HandleSaleMessageAsync(itemId, data, offset);

                        if (resp < 0)
                        {
                            break;
                        }
                        offset += resp;
                    }
                    //Log.Bu(data);
                }
                else if (opcode == 0x00e1 || opcode == 0xe2 || opcode == 0xe6)
                {
                    var itemId = BitConverter.ToUInt32(data, 0);
                    // Log.I(string.Format("packet {0:x4} {0}", itemId));
                    //Log.Bu(data);
                }
            }
            catch (Exception ex)
            {
                Log.Ex(ex, "l-analyze-error-general");
            }
        }
Esempio n. 8
0
        private void HandleMessage(byte[] message)
        {
            try
            {
                //Log.Echo(BitConverter.ToString(message));
                if (message.Length < 32)
                {
                    // type == 0x0000 이였던 메시지는 여기서 걸러짐
                    return;
                }

                mainForm.overlayForm.SetStatus(true);

                var opcode = BitConverter.ToUInt16(message, 18);
                //Log.Debug("Debug:opcode" + opcode.ToString());
#if !DEBUG
                if (opcode != 0x0078 &&
                    opcode != 0x0079 &&
                    opcode != 0x0080 &&
                    opcode != 0x006C &&
                    opcode != 0x006F &&
                    opcode != 0x0121 &&
                    opcode != 0x0143 &&
                    opcode != 0x022F)
                {
                    return;
                }
#endif

                var data = message.Skip(32).ToArray();

                if (opcode == 0x022F)
                {
                    var code = BitConverter.ToInt16(data, 4);
                    var type = data[8];

                    if (type == 0x0B)
                    {
                        Log.I("l-field-instance-entered", Data.GetInstance(code).Name);
                    }
                    else if (type == 0x0C)
                    {
                        Log.I("l-field-instance-left");
                    }

                    //if (Settings.ShowOverlay && Settings.AutoOverlayHide)
                    //{
                    //    mainForm.overlayForm.Invoke(() =>
                    //    {
                    //        if (type == 0x0B)
                    //        {
                    //            mainForm.overlayForm.Hide();
                    //        }
                    //        else if (type == 0x0C)
                    //        {
                    //            mainForm.overlayForm.Show();
                    //        }
                    //    });
                    //}
                }
                else if (opcode == 0x0143)
                {
                    var type = data[0];

                    if (type == 0x9B)
                    {
                        /*
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var progress = data[8];
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 진행도 {1}%", fate.Name, progress);
                         */
                    }
                    else if (type == 0x79)
                    {
                        /*
                         * // 돌발 임무 종료 (지역 이동시 발생할 수 있는 모든 임무에 대해 전부 옴)
                         *
                         * var code = BitConverter.ToUInt16(data, 4);
                         * var status = BitConverter.ToUInt16(data, 28);
                         *
                         * var fate = Data.GetFATE(code);
                         *
                         * //Log.D("\"{0}\" 돌발 종료!", fate.Name);
                         */
                    }
                    else if (type == 0x74)
                    {
                        // 돌발 임무 발생 (지역 이동시에도 기존 돌발 목록이 옴)

                        var code = BitConverter.ToUInt16(data, 4);

                        var fate = Data.GetFATE(code);

                        if (Settings.FATEs.Contains(code))
                        {
                            if (Settings.AutoTracker && mainForm.TrackerFormLoaded)
                            {
                                mainForm.TrackerForm.set_nm_killed(code);
                            }
                            mainForm.overlayForm.SetFATEAsOccured(fate);
                        }
                    }
                }

                /*else if (opcode == 0x006C) // 3.5 cross-world 파티 참가하면 문제가 발생하는 부분.
                 * {
                 *  var code = BitConverter.ToUInt16(data, 192);
                 *
                 *  var instance = Data.GetInstance(code);
                 *
                 *  state = State.QUEUED;
                 *  mainForm.overlayForm.SetDutyCount(1);
                 *
                 *  Log.I("l-queue-started-general", instance.Name);
                 * }*/
                else if (opcode == 0x0078)
                {
                    var status = data[0];
                    var reason = data[4];

                    if (status == 0)
                    {
                        NetCompatibility = false;
                        state            = State.QUEUED;
                        rouletteCode     = data[20];

                        if (rouletteCode != 0 && (data[15] == 0 || data[15] == 64)) //무작위 임무 신청, 한국서버/글로벌 서버
                        {
                            var roulette = Data.GetRoulette(rouletteCode);
                            mainForm.overlayForm.SetRoulleteDuty(roulette);
                            mainForm.overlayForm.queueCode = rouletteCode;
                            Log.I("l-queue-started-roulette", roulette.Name);
                        }
                        else //특정 임무 신청
                        {
                            rouletteCode = 0;
                            var instances = new List <Instance>();

                            for (int i = 0; i < 5; i++)
                            {
                                var code = BitConverter.ToUInt16(data, 22 + (i * 2));
                                if (code == 0)
                                {
                                    break;
                                }
                                instances.Add(Data.GetInstance(code));
                            }

                            if (!instances.Any())
                            {
                                return;
                            }

                            mainForm.overlayForm.SetDutyCount(instances.Count);
                            mainForm.overlayForm.queueCount = instances.Count;
                            Log.I("l-queue-started-general",
                                  string.Join(", ", instances.Select(x => x.Name).ToArray()));
                        }
                    }
                    else if (status == 3)
                    {
                        state = reason == 8 ? State.QUEUED : State.IDLE;
                        if (reason == 8)
                        {
                            mainForm.overlayForm.CancelDuty();
                        }
                        else
                        {
                            mainForm.overlayForm.CancelDutyFinder();
                            Log.E("l-queue-stopped");
                        }
                    }
                    else if (status == 6)
                    {
                        state = State.IDLE;
                        mainForm.overlayForm.CancelDutyFinder();
                        Log.I("l-queue-entered");
                        mainForm.overlayForm.instances_callback(lastCode);
                    }
                    else if (status == 4) //글섭에서 매칭 잡혔을 때 출력
                    {
                        var roulette = data[20];
                        var code     = BitConverter.ToUInt16(data, 22);

                        Instance instance;

                        if (!Settings.CheatRoulette && roulette != 0)
                        {
                            instance = new Instance {
                                Name = Data.GetRoulette(roulette).Name
                            };
                        }
                        else
                        {
                            instance = Data.GetInstance(code);
                        }

                        state = State.MATCHED;
                        mainForm.overlayForm.SetDutyAsMatched(instance);
                    }
                }
                else if (opcode == 0x006F)
                {
                    var status = data[0];

                    if (status == 0)
                    {
                        // 取消或确认超时
                        // 플레이어가 매칭 참가 확인 창에서 취소를 누르거나 참가 확인 제한 시간이 초과됨
                        // 매칭 중단을 알리기 위해 상단 2DB status 3 패킷이 연이어 옴
                    }
                    if (status == 1)
                    {
                        // 确认
                        // 플레이어가 매칭 참가 확인 창에서 확인을 누름
                        // 다른 매칭 인원들도 전부 확인을 눌렀을 경우 입장을 위해 상단 2DB status 6 패킷이 옴
                        mainForm.overlayForm.StopBlink();
                    }
                }
                else if (opcode == 0x0121) //글로벌 서버
                {
                    var status = data[5];

                    if (status == 128)
                    {
                        // 매칭 참가 신청 확인 창에서 확인을 누름
                        mainForm.overlayForm.StopBlink();
                    }
                }
                else if (opcode == 0x0079)
                {
                    var  code   = BitConverter.ToUInt16(data, 0);
                    byte status = 0;
                    byte tank   = 0;
                    byte dps    = 0;
                    byte healer = 0;
                    byte order  = 255;
                    if (NetCompatibility)
                    {
                        order = data[4];
                        order--;
                        status = data[8];
                        tank   = data[9];
                        dps    = data[10];
                        healer = data[11];
                    }
                    else
                    {
                        order  = data[5];
                        status = data[4];
                        tank   = data[5];
                        dps    = data[6];
                        healer = data[7];
                    }

                    if (status == 0 && tank == 0 && healer == 0 && dps == 0) // 4.5版本兼容性
                    {
                        Log.Debug("Debug:Patch V4.5 NetCompatibility Enabled");
                        NetCompatibility = true;
                        order            = 255;
                        status           = data[8];
                        tank             = data[9];
                        dps    = data[10];
                        healer = data[11];
                    }
                    var instance = Data.GetInstance(code);

                    if (status == 1)
                    {
                        // 인원 현황 패킷
                        var member = tank * 10000 + dps * 100 + healer;

                        if (state == State.MATCHED && lastMember != member)
                        {
                            // 队友取消
                            // 매칭도중일 때 인원 현황 패킷이 오고 마지막 인원 정보와 다른 경우에 누군가에 의해 큐가 취소된 경우.
                            state = State.QUEUED;
                            mainForm.overlayForm.CancelDuty();
                        }
                        else if (state == State.IDLE)
                        {
                            // 프로그램이 매칭 중간에 켜짐
                            state = State.QUEUED;
                            mainForm.overlayForm.SetDutyCount(-1); // 알 수 없음으로 설정함 (TODO: 알아낼 방법 있으면 정확히 나오게 수정하기)
                            if (NetCompatibility && rouletteCode > 0)
                            {
                                mainForm.overlayForm.SetDutyStatus(instance, order, dps, healer);
                            }
                            else
                            {
                                mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                            }
                        }
                        else if (state == State.QUEUED)
                        {
                            if (NetCompatibility && rouletteCode > 0)
                            {
                                mainForm.overlayForm.SetDutyStatus(instance, order, dps, healer);
                            }
                            else
                            {
                                mainForm.overlayForm.SetDutyStatus(instance, tank, dps, healer);
                            }
                        }

                        lastMember = member;
                    }
                    else if (status == 2)
                    {
                        // 현재 매칭된 파티의 역할별 인원 수 정보
                        // 조율 해제 상태여도 역할별로 정확히 날아옴
                        mainForm.overlayForm.SetMemberCount(tank, dps, healer);
                        return;
                    }
                    else if (status == 4)
                    {
                        // 매칭 뒤 참가자 확인 현황 패킷
                        mainForm.overlayForm.SetConfirmStatus(instance, tank, dps, healer);
                    }
                    lastCode = code;
                    Log.I("l-queue-updated", instance.Name, status, tank, instance.Tank, healer, instance.Healer, dps,
                          instance.DPS);
                }
                else if (opcode == 0x0080)
                {
                    var roulette = data[2];
                    var code     = BitConverter.ToUInt16(data, 4);

                    Instance instance;

                    if (!Settings.CheatRoulette && roulette != 0)
                    {
                        instance = new Instance {
                            Name = Data.GetRoulette(roulette).Name
                        };
                    }
                    else
                    {
                        instance = Data.GetInstance(code);
                    }

                    state = State.MATCHED;
                    mainForm.overlayForm.SetDutyAsMatched(instance);
                }
            }
            catch (Exception ex)
            {
                Log.Ex(ex, "l-analyze-error-general");
            }
        }