public IpPacket(byte[] buffer) { try { var versionAndHeaderLength = buffer[0]; Version = versionAndHeaderLength >> 4 == 4 ? ProtocolFamily.InterNetwork : ProtocolFamily.InterNetworkV6; HeaderLength = (byte)((versionAndHeaderLength & 15) * 4); // 0b1111 = 15 Protocol = (ProtocolType)buffer[9]; SourceIpAddress = new IPAddress(BitConverter.ToUInt32(buffer, 12)); DestinationIpAddress = new IPAddress(BitConverter.ToUInt32(buffer, 16)); Data = buffer.Skip(HeaderLength).ToArray(); IsValid = true; } catch (Exception ex) { Version = ProtocolFamily.Unknown; HeaderLength = 0; Protocol = ProtocolType.Unknown; SourceIpAddress = null; DestinationIpAddress = null; Data = null; IsValid = false; MsgLog.Exception(ex, "l-packet-error-ip"); } }
public void UpdateGameConnections(Process process) { var update = _connections.Count < 2; var currentConnections = GetConnections(process); foreach (var connection in _connections) { if (!currentConnections.Contains(connection)) { // 기존 연결 끊겨 있음, 새로 해야함 update = true; MsgLog.Error("l-network-detected-connection-closing"); break; } } if (update) { var lobbyEndPoint = GetLobbyEndPoint(process); _connections = currentConnections.Where(x => !x.RemoteEndPoint.Equals(lobbyEndPoint)).ToList(); foreach (var connection in _connections) { MsgLog.Info("l-network-detected-connection", connection); } } }
public TcpPacket(byte[] buffer) { try { SourcePort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, 0)); DestinationPort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, 2)); var offsetAndFlags = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, 12)); DataOffset = (byte)((offsetAndFlags >> 12) * 4); Flags = (TcpFlags)(offsetAndFlags & 511); // 0b111111111 = 511 Payload = buffer.Skip(DataOffset).ToArray(); IsValid = true; } catch (Exception ex) { SourcePort = 0; DestinationPort = 0; DataOffset = 0; Flags = TcpFlags.NONE; Payload = null; IsValid = false; MsgLog.Exception(ex, "l-packet-error-tcp"); } }
private void CboClientVersion_SelectedIndexChanged(object sender, EventArgs e) { if (cboClientVersion.SelectedIndex < 0) { return; } try { var v = GameData.ClientVersions[cboClientVersion.SelectedIndex]; //MsgLog.S("i-client-version", string.Format("이전={0}, 변경={1}", Settings.ClientVersion, v.Value)); if (Settings.ClientVersion != v.Value) { Settings.ClientVersion = v.Value; txtClientVersion.Text = v.Value.ToString(); PacketWorker.Codes = GameData.PacketCodes[v.Value]; #if true MsgLog.S("i-client-version", $"{v.Name}, {PacketWorker.Codes.FATE:X4}/{PacketWorker.Codes.Duty:X4}/{PacketWorker.Codes.Match:X4}"); #else MsgLog.S("i-client-version", v.Name); #endif SaveSettings(); } } catch { } }
private static void Fill(string json) { try { var data = JsonConvert.DeserializeObject <Group>(json); var version = data.Version; if (version > decimal.Truncate(Version)) { var fates = new Dictionary <int, Fate>(); foreach (var area in data.Areas) { foreach (var fate in area.Value.Fates) { fate.Value.Area = area.Value; fates.Add(fate.Key, fate.Value); } } Areas = data.Areas; Instances = data.Instances; Roulettes = data.Roulettes; Fates = fates; Version = version; } } catch (Exception ex) { MsgLog.Ex(ex, "l-data-error"); } }
// public void DeInitPlugin() { _isPluginEnabled = false; _frmOverlay.Hide(); _frmOverlay = null; SaveSettings(); _actTabPage = null; if (_actLabelStatus != null) { _actLabelStatus.Text = Localization.GetText("l-plugin-stopped"); _actLabelStatus = null; } foreach (var e in _pronets) { e.Value.Network.StopCapture(); } _timer.Enabled = false; MsgLog.SetTextBox(null); }
// private void ReadGameData(Localization.Locale gamelang = null) { Localization.Locale lang = gamelang ?? (Localization.Locale)cboGameLanguage.SelectedItem; if (_localeGame == null || !lang.Code.Equals(_localeGame.Code)) { _localeGame = lang; string json; switch (lang.Index) { case 1: json = Properties.Resources.gamedata_ja; break; case 2: json = Properties.Resources.gamedata_de; break; case 3: json = Properties.Resources.gamedata_fr; break; case 4: json = Properties.Resources.gamedata_ko; break; default: json = Properties.Resources.gamedata_en; break; } GameData.Initialize(json); MsgLog.I("i-data-version", GameData.Version, GameData.Areas.Count, GameData.Instances.Count, GameData.Roulettes.Count, GameData.Fates.Count); } }
private void RegisterToFirewall() { try { var netFwMgr = GetInstance <INetFwMgr>("HNetCfg.FwMgr"); var netAuthApps = netFwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications; var exists = false; foreach (var netAuthAppObject in netAuthApps) { if (netAuthAppObject is INetFwAuthorizedApplication netAuthApp && netAuthApp.ProcessImageFileName == _exePath && netAuthApp.Enabled) { exists = true; } } if (!exists) { var networkApp = GetInstance <INetFwAuthorizedApplication>("HNetCfg.FwAuthorizedApplication"); networkApp.Enabled = true; networkApp.Name = "ACT_DFASSIST"; networkApp.ProcessImageFileName = _exePath; networkApp.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL; netAuthApps.Add(networkApp); MsgLog.Success("l-firewall-registered"); } } catch (Exception ex) { MsgLog.Exception(ex, "l-firewall-error"); } }
private void SaveSettings() { if (!_isInitSetting) { return; } txtOverayLocation.Text = $"{Settings.OverlayLocation.X},{Settings.OverlayLocation.Y}"; try { using (var fs = new FileStream(Settings.Path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) using (var xw = new XmlTextWriter(fs, Encoding.UTF8) { Formatting = Formatting.Indented, Indentation = 1, IndentChar = '\t' }) { xw.WriteStartDocument(true); xw.WriteStartElement("Config"); // <Config> xw.WriteStartElement("SettingsSerializer"); // <Config><SettingsSerializer> _srset.ExportToXml(xw); // Fill the SettingsSerializer XML xw.WriteEndElement(); // </SettingsSerializer> xw.WriteEndElement(); // </Config> xw.WriteEndDocument(); // Tie up loose ends (shouldn't be any) xw.Flush(); // Flush the file buffer to disk xw.Close(); } } catch (Exception ex) { MsgLog.Ex(ex, "Exception: save setting failed"); } }
// private void CboLogBackground_SelectedValueChanged(object sender, EventArgs e) { if (!string.IsNullOrWhiteSpace(cboLogBackground.Text) && !cboLogBackground.Text.Equals(Color.Transparent.Name)) { rtxLogger.BackColor = Color.FromName(cboLogBackground.Text); MsgLog.I("i-selected-color", cboLogBackground.Text); } }
private IPEndPoint GetLobbyEndPoint(Process process) { IPEndPoint ipep = null; string lobbyHost = null; var lobbyPort = 0; try { using (var managementObjectSearcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id)) { foreach (var managementBaseObject in managementObjectSearcher.Get()) { var commandline = managementBaseObject["CommandLine"].ToString(); var args = commandline.Split(' '); foreach (var arg in args) { var splitted = arg.Split('='); if (splitted.Length != 2) { continue; } switch (splitted[0]) { case "DEV.LobbyHost01": lobbyHost = splitted[1]; break; case "DEV.LobbyPort01": lobbyPort = int.Parse(splitted[1]); break; } } } } if (lobbyHost != null && lobbyPort > 0) { var address = Dns.GetHostAddresses(lobbyHost)[0]; ipep = new IPEndPoint(address, lobbyPort); } } catch (Exception ex) { MsgLog.Exception(ex, "l-network-error-finding-lobby"); } return(ipep); }
// private void ReadGameData(Localization.Locale gamelang = null) { Localization.Locale lang = gamelang ?? (Localization.Locale)cboGameLanguage.SelectedItem; if (_localeGame == null || !lang.Code.Equals(_localeGame.Code)) { _localeGame = lang; GameData.Initialize(Settings.PluginPath, lang.Code); MsgLog.Info("l-info-version", GameData.Version, GameData.Areas.Count, GameData.Instances.Count, GameData.Roulettes.Count, GameData.Fates.Count); } }
private void FilterAndProcessPacket(byte[] buffer) { try { var ipPacket = new IpPacket(buffer); if (!ipPacket.IsValid || ipPacket.Protocol != ProtocolType.Tcp) { return; } var tcpPacket = new TcpPacket(ipPacket.Data); if (!tcpPacket.IsValid) { return; } if (!tcpPacket.Flags.HasFlag(TcpFlags.ACK | TcpFlags.PSH)) { return; } var sourceEndPoint = new IPEndPoint(ipPacket.SourceIpAddress, tcpPacket.SourcePort); var destinationEndPoint = new IPEndPoint(ipPacket.DestinationIpAddress, tcpPacket.DestinationPort); var connection = new Connection { LocalEndPoint = sourceEndPoint, RemoteEndPoint = destinationEndPoint }; var reverseConnection = new Connection { LocalEndPoint = destinationEndPoint, RemoteEndPoint = sourceEndPoint }; if (!(_connections.Contains(connection) || _connections.Contains(reverseConnection))) { return; } if (!_connections.Contains(reverseConnection)) { return; } lock (_lockAnalyse) PacketFFXIV.Analyze(_pid, tcpPacket.Payload, ref _state); } catch (Exception ex) { MsgLog.Exception(ex, "l-network-error-filtering-packet"); } }
public void StartCapture(Process process) { _pid = process.Id; Task.Factory.StartNew(() => { try { MsgLog.Info("l-network-starting"); if (IsRunning) { MsgLog.Error("l-network-error-already-started"); return; } UpdateGameConnections(process); if (_connections.Count < 2) { MsgLog.Error("l-network-error-no-connection"); return; } var localAddress = _connections[0].LocalEndPoint.Address; RegisterToFirewall(); _socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP); _socket.Bind(new IPEndPoint(localAddress, 0)); _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true); _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AcceptConnection, true); _socket.IOControl(IOControlCode.ReceiveAll, RcvAllIpLevel, null); _socket.ReceiveBufferSize = _recvBuffer.Length * 4; _socket.BeginReceive(_recvBuffer, 0, _recvBuffer.Length, 0, OnReceive, null); IsRunning = true; MsgLog.Success("l-network-started"); } catch (Exception ex) { MsgLog.Exception(ex, "l-network-error-starting"); } }); }
public void StopCapture() { try { if (!IsRunning) { MsgLog.Error("l-network-error-already-stopped"); return; } _socket.Close(); _connections.Clear(); MsgLog.Info("l-network-stopping"); } catch (Exception ex) { MsgLog.Exception(ex, "l-network-error-stopping"); } }
private void OnReceive(IAsyncResult ar) { try { var length = _socket.EndReceive(ar); var buffer = _recvBuffer.Take(length).ToArray(); _socket.BeginReceive(_recvBuffer, 0, _recvBuffer.Length, 0, OnReceive, null); FilterAndProcessPacket(buffer); } catch (Exception ex) when(ex is ObjectDisposedException || ex is NullReferenceException) { IsRunning = false; _socket = null; MsgLog.Success("l-network-stopped"); } catch (Exception ex) { MsgLog.Exception(ex, "l-network-error-receiving-packet"); } }
// public void DeInitPlugin() { _isPluginEnabled = false; _frmOverlay.Hide(); _frmOverlay = null; SaveSettings(); _isInitSetting = false; _actTabPage = null; if (_actLabelStatus != null) { _actLabelStatus.Text = Localization.GetText("l-plugin-stopped"); _actLabelStatus = null; } PacketWorker.EndMachina(); MsgLog.SetTextBox(null); }
private static void HandleMessage(int pid, byte[] message, ref MatchStatus state) { try { if (message.Length < 32) { // type == 0x0000 이였던 메시지는 여기서 걸러짐 return; } var opcode = BitConverter.ToUInt16(message, 18); #if !DEBUG if ( opcode != 0x006F && opcode != 0x0078 && opcode != 0x0079 && opcode != 0x0080 && opcode != 0x0121 && opcode != 0x0143 && opcode != 0x022F && // 5.1 opcode != 0x008F && opcode != 0x00AE && opcode != 0x00B3 && opcode != 0x015E && opcode != 0x0304 && // 5.11 opcode != 0x0002 && opcode != 0x0164 && opcode != 0x0339 && opcode != 0x032D && opcode != 0x032F && opcode != 0x03CF) { return; } #endif var data = message.Skip(32).ToArray(); if (opcode == 0x022F) // 인스턴스 들어오고 나가기 { var code = BitConverter.ToInt16(data, 4); if (code == 0) { return; } var type = data[8]; if (type == 0x0B) { // 들어옴 MsgLog.Info("l-field-instance-entered", GameData.GetInstanceName(code)); FireEvent(pid, GameEvents.InstanceEnter, new int[] { code }); } else if (type == 0x0C) { // 나감 MsgLog.Info("l-field-instance-left"); FireEvent(pid, GameEvents.InstanceLeave, new int[] { code }); } } // 22F else if (opcode == 0x0143) // FATE 관련 { #if false // FATE 막음 2019-11-01 var type = data[0]; if (type == 0x9B) { var code = BitConverter.ToUInt16(data, 4); var progress = data[8]; FireEvent(pid, GameEvents.FateProgress, new int[] { code, progress }); } else if (type == 0x79) // FATE 끗 { var code = BitConverter.ToUInt16(data, 4); var status = BitConverter.ToUInt16(data, 28); FireEvent(pid, GameEvents.FateEnd, new int[] { code, status }); } else if (type == 0x74) // FATE 시작! 에이리어 이동해도 진행중인 것도 이걸로 처리됨 { var code = BitConverter.ToUInt16(data, 4); if (Settings.LoggingWholeFates || Settings.SelectedFates.Contains(code.ToString())) { MsgLog.Info("l-fate-occured-info", GameData.GetFate(code).Name); FireEvent(pid, GameEvents.FateBegin, new int[] { code }); } } #endif } // 143 else if (opcode == 0x0078) // 5.1이전 듀티 { var status = data[0]; var reason = data[4]; if (status == 0) // 듀티 큐 { state = MatchStatus.Queued; _rouletteCode = data[20]; if (_rouletteCode != 0 && (data[15] == 0 || data[15] == 64)) // 루렛, 한국/글로벌 { MsgLog.Info("l-queue-started-roulette", GameData.GetRouletteName(_rouletteCode)); FireEvent(pid, GameEvents.MatchBegin, new[] { (int)MatchType.Roulette, _rouletteCode }); } else // 듀티 지정 큐 (Dungeon/Trial/Raid) { _rouletteCode = 0; var instances = new List <int>(); for (var i = 0; i < 5; i++) { var code = BitConverter.ToUInt16(data, 22 + i * 2); if (code == 0) { break; } instances.Add(code); } if (!instances.Any()) { return; } var args = new List <int> { (int)MatchType.Assignment, instances.Count }; foreach (var item in instances) { args.Add(item); } MsgLog.Info("l-queue-started-general", string.Join(", ", instances.Select(x => GameData.GetInstanceName(x)).ToArray())); FireEvent(pid, GameEvents.MatchBegin, args.ToArray()); } } else if (status == 3) // 취소 { state = reason == 8 ? MatchStatus.Queued : MatchStatus.Idle; MsgLog.Info("l-queue-stopped"); FireEvent(pid, GameEvents.MatchEnd, new[] { (int)MatchResult.Cancel }); } else if (status == 6) // 들어가기 { state = MatchStatus.Idle; MsgLog.Info("l-queue-entered"); FireEvent(pid, GameEvents.MatchEnd, new[] { (int)MatchResult.Enter }); } else if (status == 4) // 매치 { var roulette = data[20]; var code = BitConverter.ToUInt16(data, 22); state = MatchStatus.Matched; MsgLog.Info("l-queue-matched", GameData.GetInstanceName(code)); FireEvent(pid, GameEvents.MatchDone, new int[] { roulette, code }); } } // 78 else if (opcode == 0x006F) { var status = data[0]; if (status == 0) { // 플레이어가 매칭 참가 확인 창에서 취소를 누르거나 참가 확인 제한 시간이 초과됨 // 매칭 중단을 알리기 위해 상단 2DB status 3 패킷이 연이어 옴 } if (status == 1) { // 플레이어가 매칭 참가 확인 창에서 확인을 누름 // 다른 매칭 인원들도 전부 확인을 눌렀을 경우 입장을 위해 상단 2DB status 6 패킷이 옴 FireEvent(pid, GameEvents.MatchCancel, new int[] { -1 }); } } // 6F else if (opcode == 0x0121) // 글로벌 깜빡 { var status = data[5]; if (status == 128) { // 매칭 참가 신청 확인 창에서 확인을 누름, 그러니깐 표시 안하도됨 FireEvent(pid, GameEvents.MatchCancel, new int[] { -1 }); } } // 121 else if (opcode == 0x0079) // 매치 상태 { var code = BitConverter.ToUInt16(data, 0); var order = data[4]; var status = data[8]; var tank = data[9]; var dps = data[10]; var healer = data[11]; var member = tank * 10000 + healer * 100 + dps; var instance = GameData.GetInstance(code); if (status == 1) { if (state == MatchStatus.Matched && _lastMember != member) { // 마지막 정보와 다름, 다른 사람에 의한 취소... 인데 이거 되나??!!! state = MatchStatus.Queued; FireEvent(pid, GameEvents.MatchCancel, new int[] { -1 }); } else if (state == MatchStatus.Idle || state == MatchStatus.Queued) { if (state == MatchStatus.Idle) { // 매칭 중간에 플러그인이 시작됨 state = MatchStatus.Queued; } if (_rouletteCode > 0 || (tank == 0 && healer == 0 && dps == 0)) { FireEvent(pid, GameEvents.MatchOrder, new int[] { order }); } else { FireEvent(pid, GameEvents.MatchStatus, new int[] { (int)MatchType.ShortStatus, code, status, tank, healer, dps }); } } _lastMember = member; _lastOrder = order; } else if (status == 2) { // 매칭 파티의 인원 정보 FireEvent(pid, GameEvents.MatchStatus, new int[] { (int)MatchType.ShortStatus, code, status, tank, healer, dps }); return; // 이건 로그를 안뿌린다 } else //if (status == 4) { // 매칭하고 파티 인원 상태 // 추가로: 다른거땜에 오버레이가 지워질 수도 있음... ㅠㅠ FireEvent(pid, GameEvents.MatchStatus, new int[] { (int)MatchType.ShortStatus, code, status, tank, healer, dps }); if (status != 4) { // 기타면 로그 출력X // ....그러고보니 status == 2일때도 여기서 처리해도 되는데 지면이 부족하여 패-_-스 return; } } var memberinfo = $"{order} | {tank}/{instance.Tank}, {healer}/{instance.Healer}, {dps}/{instance.Dps} | {member}"; MsgLog.Info("l-queue-updated", instance.Name, status, memberinfo); } // 79 else if (opcode == 0x0080) { var roulette = data[2]; var code = BitConverter.ToUInt16(data, 4); state = MatchStatus.Matched; FireEvent(pid, GameEvents.MatchDone, new int[] { roulette, code }); MsgLog.Success("l-queue-matched ", code); } // 80 #region 5.1 추가 else if (opcode == 0x008F) // 5.1 큐 (opcode = 0x0078, status = 0) { var status = data[0]; var reason = data[4]; state = MatchStatus.Queued; _rouletteCode = data[8]; if (_rouletteCode != 0 && (data[15] == 0 || data[15] == 64)) // 루렛, 한국/글로벌 { MsgLog.Info("l-queue-started-roulette", GameData.GetRouletteName(_rouletteCode)); FireEvent(pid, GameEvents.MatchBegin, new[] { (int)MatchType.Roulette, _rouletteCode }); } else // 듀티 지정 큐 (Dungeon/Trial/Raid) { _rouletteCode = 0; var instances = new List <int>(); for (var i = 0; i < 5; i++) { var code = BitConverter.ToUInt16(data, 12 + (i * 4)); if (code == 0) { break; } } if (!instances.Any()) { return; } var args = new List <int> { (int)MatchType.Assignment, instances.Count }; foreach (var item in instances) { args.Add(item); } MsgLog.Info("l-queue-started-general", string.Join(", ", instances.Select(x => GameData.GetInstanceName(x)).ToArray())); FireEvent(pid, GameEvents.MatchBegin, args.ToArray()); } } // 8F else if (opcode == 0x00B3) // 5.1 매칭 (opcode = 0x0078, status = 4) { var code = BitConverter.ToUInt16(data, 20); state = MatchStatus.Matched; MsgLog.Info("l-queue-matched", GameData.GetInstanceName(code)); FireEvent(pid, GameEvents.MatchDone, new int[] { _rouletteCode, code }); } // B3 else if (opcode == 0x015E) // 5.1 캔슬 (opcode = 0x0078, status = 3) { var status = data[3]; if (status == 8) // 0이아님 { state = MatchStatus.Idle; MsgLog.Info("l-queue-stopped"); FireEvent(pid, GameEvents.MatchEnd, new[] { (int)MatchResult.Cancel }); } } // 15E else if (opcode == 0x0304) // 5.1, 5.11 상태 (opcode = 0x0078, status = 1) { var order = data[6]; var wait = data[7]; var tank = data[8]; var maxtank = data[9]; var healer = data[10]; var maxhealer = data[11]; var dps = data[12]; var maxdps = data[13]; var member = tank * 10000 + healer * 100 + dps; if (state == MatchStatus.Matched && _lastMember != member) { // 마지막 정보와 다름, 다른 사람에 의한 취소... 인데 이거 되나??!!! state = MatchStatus.Queued; FireEvent(pid, GameEvents.MatchCancel, new int[] { -1 }); } else if (state == MatchStatus.Idle || state == MatchStatus.Queued) { if (state == MatchStatus.Idle) { // 매칭 중간에 플러그인 시작 state = MatchStatus.Queued; } if (_rouletteCode > 0 || (tank == 0 && healer == 0 && dps == 0) || (tank > maxtank || healer > maxhealer || dps > maxdps)) { FireEvent(pid, GameEvents.MatchOrder, new int[] { order }); } else { FireEvent(pid, GameEvents.MatchStatus, new int[] { (int)MatchType.LongStatus, 0, order, tank, healer, dps, maxtank, maxhealer, maxdps }); } } _lastMember = member; _lastOrder = order; var memberinfo = $"{tank}/{maxtank}, {healer}/{maxhealer}, {dps}/{maxdps}"; MsgLog.Info("l-queue-updated", $"#{order}", wait, memberinfo); } // 304 else if (opcode == 0x00AE) // 5.1 매칭하고 파티 인원 (opcode = 0x0078, status = 4) { var code = BitConverter.ToUInt16(data, 8); var tank = data[12]; var healer = data[14]; var dps = data[16]; FireEvent(pid, GameEvents.MatchStatus, new int[] { (int)MatchType.ShortStatus, code, 0, tank, healer, dps }); } // AE #endregion // 5.1 추가 #region 5.11 추가 else if (opcode == 0x0339) // 5.11 인스턴스 들어오고 나가기 { var code = BitConverter.ToInt16(data, 4); if (code == 0) { return; } var type = data[8]; if (type == 0x0B) { // 들어옴 MsgLog.Info("l-field-instance-entered", GameData.GetInstanceName(code)); FireEvent(pid, GameEvents.InstanceEnter, new int[] { code }); } else if (type == 0x0C) { // 나감 MsgLog.Info("l-field-instance-left"); FireEvent(pid, GameEvents.InstanceLeave, new int[] { code }); } } // 339 else if (opcode == 0x0164) // 5.11 큐 { var status = data[0]; var reason = data[4]; state = MatchStatus.Queued; _rouletteCode = data[8]; if (_rouletteCode != 0 && (data[15] == 0 || data[15] == 64)) { MsgLog.Info("l-queue-started-roulette", GameData.GetRouletteName(_rouletteCode)); FireEvent(pid, GameEvents.MatchBegin, new[] { (int)MatchType.Roulette, _rouletteCode }); } else // 듀티 지정 큐 (Dungeon/Trial/Raid) { _rouletteCode = 0; var instances = new List <int>(); for (var i = 0; i < 5; i++) { var code = BitConverter.ToUInt16(data, 12 + (i * 4)); if (code == 0) { break; } } if (!instances.Any()) { return; } var args = new List <int> { (int)MatchType.Assignment, instances.Count }; foreach (var item in instances) { args.Add(item); } MsgLog.Info("l-queue-started-general", string.Join(", ", instances.Select(x => GameData.GetInstanceName(x)).ToArray())); FireEvent(pid, GameEvents.MatchBegin, args.ToArray()); } } // 164 else if (opcode == 0x032D) // 5.11 매칭 { //var roulette = BitConverter.ToUInt16(data, 2); var code = BitConverter.ToUInt16(data, 20); state = MatchStatus.Matched; MsgLog.Info("l-queue-matched", GameData.GetInstanceName(code)); FireEvent(pid, GameEvents.MatchDone, new int[] { _rouletteCode, code }); } // 32D else if (opcode == 0x03CF) // 5.11 듀티 상태 { var status = data[0]; if (status == 0x73) // 매칭 취소 { state = MatchStatus.Idle; MsgLog.Info("l-queue-stopped"); FireEvent(pid, GameEvents.MatchEnd, new[] { (int)MatchResult.Cancel }); } else if (status == 0x81) // 매칭 넣었음 { //state = MatchStatus.Idle; //FireEvent(pid, GameEvents.MatchEnd, new[] { (int)MatchResult.Enter }); } } // 3CF else if (opcode == 0x032F) // 5.11 매칭하고 파티 인원 { var code = BitConverter.ToUInt16(data, 8); var tank = data[12]; var maxtank = data[13]; var healer = data[14]; var maxhealer = data[15]; var dps = data[16]; var maxdps = data[17]; if (tank > maxtank || healer > maxhealer || dps > maxdps) { FireEvent(pid, GameEvents.MatchDone, new int[] { _rouletteCode, code }); } else { //FireEvent(pid, GameEvents.MatchStatus, new int[] { (int)MatchType.ShortStatus, code, 0, tank, healer, dps }); FireEvent(pid, GameEvents.MatchStatus, new int[] { (int)MatchType.LongStatus, code, 0, tank, healer, dps, maxtank, maxhealer, maxdps }); } } // 32F else if (opcode == 0x0002) // 5.11 매칭 완료 { // 딱히 할건없음 //FireEvent(pid, GameEvents.MatchCancel, new int[] { -1 }); } // 2 #endregion // 5.11 추가 } catch (Exception ex) { #if false MsgLog.Exception(ex, "l-analyze-error-handle"); #else // 에이리어 이동할때만 나타난다. 메시지를 출력하지 말자 // DFASSIST에서는 안나는데 플러그인은 이동만 하면 난다 var fmt = Localization.GetText("l-analyze-error-handle"); var msg = MsgLog.Escape(ex.Message); System.Diagnostics.Debug.WriteLine($"{fmt}: {msg}"); // 오버레이는 지워버리는게 좋겠다 //FireEvent(pid, GameEvents.MatchEnd, new[] { (int)MatchResult.Cancel }); #endif } }
// private void ActInitialize() { if (_isInActInit) { return; } _isInActInit = true; MsgLog.SetTextBox(rtxLogger); ActGlobals.oFormActMain.Shown -= OFormActMain_Shown; Localization.Locale defaultlocale = Localization.DefaultLocale; ReadLocale(defaultlocale); #if DEBUG MsgLog.Info("ui-dbg-msg", System.Environment.CurrentDirectory); MsgLog.Info("ui-dbg-msg", Settings.PluginPath); #endif ReadGameData(defaultlocale); _isPluginEnabled = true; cboUiLanguage.DataSource = Localization.Locales.Clone(); cboUiLanguage.DisplayMember = "Name"; cboUiLanguage.ValueMember = "Code"; cboGameLanguage.DataSource = Localization.Locales.Clone(); cboGameLanguage.DisplayMember = "Name"; cboGameLanguage.ValueMember = "Code"; Dock = DockStyle.Fill; _actLabelStatus.Text = "Initializing..."; UpdateUiLanguage(); _actLabelStatus.Text = Localization.GetText("l-plugin-started"); _actTabPage.Text = Localization.GetText("app-name"); _actTabPage.Controls.Add(this); _srset = new SettingsSerializer(this); ReadSettings(); UpdateFates(); UpdateProcesses(); if (_timer == null) { _timer = new Timer { Interval = 10000 }; _timer.Tick += _timer_Tick; } _timer.Enabled = true; _isInActInit = false; }
// private void UpdateProcesses() { var ps = new List <Process>(); ps.AddRange(Process.GetProcessesByName("ffxiv")); ps.AddRange(Process.GetProcessesByName("ffxiv_dx11")); foreach (var p in ps) { try { if (_pronets.ContainsKey(p.Id)) { continue; } var pn = new ProNet(p, new Network()); PacketFFXIV.OnEventReceived += PacketFFXIV_OnEventReceived; _pronets.TryAdd(p.Id, pn); MsgLog.Success("l-process-set-success", p.Id); } catch (Exception e) { MsgLog.Exception(e, "l-process-set-failed"); } } var dels = new List <int>(); foreach (var e in _pronets) { if (e.Value.Process.HasExited) { e.Value.Network.StopCapture(); dels.Add(e.Key); } else { if (e.Value.Network.IsRunning) { e.Value.Network.UpdateGameConnections(e.Value.Process); } else { e.Value.Network.StartCapture(e.Value.Process); } } } foreach (var u in dels) { try { _pronets.TryRemove(u, out var _); PacketFFXIV.OnEventReceived -= PacketFFXIV_OnEventReceived; } catch (Exception e) { MsgLog.Exception(e, "l-process-remove-failed"); } } }
// private void ActInitialize() { if (_isInActInit) { return; } _isInActInit = true; MsgLog.SetTextBox(rtxLogger); ActGlobals.oFormActMain.Shown -= OFormActMain_Shown; Localization.Locale defaultlocale = Localization.DefaultLocale; ReadLocale(defaultlocale); #if DEBUG && false MsgLog.D("ui-dbg", System.Environment.CurrentDirectory); MsgLog.D("ui-dbg", Settings.PluginPath); #endif ReadGameData(defaultlocale); _isPluginEnabled = true; cboUiLanguage.DataSource = Localization.Locales.Clone(); cboUiLanguage.DisplayMember = "Name"; cboUiLanguage.ValueMember = "Code"; cboGameLanguage.DataSource = Localization.Locales.Clone(); cboGameLanguage.DisplayMember = "Name"; cboGameLanguage.ValueMember = "Code"; cboClientVersion.DataSource = GameData.ClientVersions.Clone(); cboClientVersion.DisplayMember = "Name"; cboClientVersion.ValueMember = "Value"; cboClientVersion.SelectedIndex = 0; Dock = DockStyle.Fill; _actLabelStatus.Text = "Initializing..."; UpdateUiLanguage(); _actLabelStatus.Text = Localization.GetText("l-plugin-started"); _actTabPage.Text = Localization.GetText("app-name"); _actTabPage.Controls.Add(this); _srset = new SettingsSerializer(this); ReadSettings(); UpdateFates(); // string tagname = Settings.GetTagNameForUpdate(); if (!Settings.TagName.Equals(tagname)) { MsgLog.I("i-client-updated", tagname); if (!txtUpdateSkip.Text.Equals(tagname)) { Task.Run(() => { var res = MessageBox.Show( Localization.GetText("i-visit-updated"), Localization.GetText("app-name"), MessageBoxButtons.YesNo, MessageBoxIcon.Information); if (res == DialogResult.Yes) { Process.Start("https://github.com/purutu/ACT.DFAssist/releases/latest"); } else { txtUpdateSkip.Text = tagname; SaveSettings(); } }); } } // PacketWorker.OnEventReceived += PacketWorker_OnEventReceived; PacketWorker.BeginMachina(); _isInActInit = false; }
// process packet private static void PacketFFXIV(string pid, byte[] message) { var opcode = BitConverter.ToUInt16(message, 18); #if !DEBUG if (opcode != Codes.Instance && opcode != Codes.FATE && opcode != Codes.Duty && opcode != Codes.Match) { return; } #endif var data = message.Skip(32).ToArray(); #if false if (opcode == Codes.Instance) // 인스턴스 { // [2020-01-13] 코드를 찾을 수 없다. var code = BitConverter.ToInt16(data, 4); var type = data[8]; if (type == 0x0B) { // 들어옴 MsgLog.Instance("l-instance-enter", GameData.GetInstanceName(code)); FireEvent(pid, GameEvents.InstanceEnter, new int[] { code }); } else if (type == 0x0C) { // 나감 MsgLog.Instance("l-instance-leave"); FireEvent(pid, GameEvents.InstanceLeave, new int[] { code }); } } // Codes.Instance else #endif if (opcode == Codes.FATE) // FATE 관련 { var type = data[0]; if (type == 0x74) // FATE 시작! 에이리어 이동해도 진행중인 것도 이걸로 처리됨 { var code = BitConverter.ToUInt16(data, 4); if (Settings.LoggingWholeFates || Settings.SelectedFates.Contains(code.ToString())) { MsgLog.Fate("l-fate-occured-info", GameData.GetFate(code).Name); FireEvent(pid, GameEvents.FateOccur, new int[] { code }); } } } // Codes.FATE else if (opcode == Codes.Duty) // 듀티 { var status = data[0]; var reason = data[4]; var roulette = data[Codes.RouletteCode]; if (roulette != 0 && (data[15] == 0 || data[15] == 64)) // 루렛, 한국/글로벌 { MsgLog.Duty("i-queue-roulette", GameData.GetRouletteName(roulette)); FireEvent(pid, GameEvents.MatchQueue, new[] { (int)MatchType.Roulette, roulette }); } else // 골라놓은 듀티 큐 (Dungeon/Trial/Raid) { var instances = new List <int>(); for (var i = 0; i < 5; i++) { var code = BitConverter.ToUInt16(data, 12 + (i * 4)); if (code == 0) { break; } } if (!instances.Any()) { return; } var args = new List <int> { (int)MatchType.Assignment, instances.Count }; foreach (var item in instances) { args.Add(item); } MsgLog.Duty("i-queue-instance", string.Join(", ", instances.Select(x => GameData.GetInstanceName(x)).ToArray())); FireEvent(pid, GameEvents.MatchQueue, args.ToArray()); } } // Codes.Duty else if (opcode == Codes.Match) // 매칭 { var roulette = BitConverter.ToUInt16(data, 2); var code = BitConverter.ToUInt16(data, 20); MsgLog.Duty("i-matched", GameData.GetInstanceName(code)); FireEvent(pid, GameEvents.MatchDone, new int[] { roulette, code }); } // Codes.Match }
public static void Analyze(int pid, byte[] payload, ref MatchStatus state) { try { while (true) { if (payload.Length < 4) { break; } var type = BitConverter.ToUInt16(payload, 0); if (type == 0x0000 || type == 0x5252) { if (payload.Length < 28) { break; } var length = BitConverter.ToInt32(payload, 24); if (length <= 0 || payload.Length < length) { break; } using (var messages = new MemoryStream(payload.Length)) { using (var stream = new MemoryStream(payload, 0, length)) { stream.Seek(40, SeekOrigin.Begin); if (payload[33] == 0x00) { stream.CopyTo(messages); } else { stream.Seek(2, SeekOrigin.Current); // 닷넷 DeflateStream 버그 (앞 2바이트 넘겨야함) using (var z = new DeflateStream(stream, CompressionMode.Decompress)) z.CopyTo(messages); } } messages.Seek(0, SeekOrigin.Begin); var messageCount = BitConverter.ToUInt16(payload, 30); for (var i = 0; i < messageCount; i++) { try { var buffer = new byte[4]; var read = messages.Read(buffer, 0, 4); if (read < 4) { MsgLog.Error("l-analyze-error-length", read, i, messageCount); break; } var messageLength = BitConverter.ToInt32(buffer, 0); var message = new byte[messageLength]; messages.Seek(-4, SeekOrigin.Current); messages.Read(message, 0, messageLength); HandleMessage(pid, message, ref state); } catch (Exception ex) { MsgLog.Exception(ex, "l-analyze-error-general"); } } } if (length < payload.Length) { // 더 처리해야 할 패킷이 남아 있음 payload = payload.Skip(length).ToArray(); continue; } } else { // 앞쪽이 잘려서 오는 패킷 workaround // 잘린 패킷 1개는 버리고 바로 다음 패킷부터 찾기... // TODO: 버리는 패킷 없게 제대로 수정하기 for (var offset = 0; offset < payload.Length - 2; offset++) { var possibleType = BitConverter.ToUInt16(payload, offset); if (possibleType == 0x5252) { payload = payload.Skip(offset).ToArray(); Analyze(pid, payload, ref state); break; } } } break; } } catch (Exception ex) { MsgLog.Exception(ex, "l-analyze-error"); } }