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