Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chronofoil + readme update #62

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "lib/Machina"]
path = lib/Machina
url = https://github.com/MapleHinata/machina
[submodule "lib/Chronofoil.CaptureFile"]
path = lib/Chronofoil.CaptureFile
url = https://github.com/ProjectChronofoil/Chronofoil.CaptureFile
20 changes: 20 additions & 0 deletions FFXIVMonReborn.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Machina", "lib\Machina\Mach
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Machina.FFXIV", "lib\Machina\Machina.FFXIV\Machina.FFXIV.csproj", "{4303E4F0-4C90-44EB-90C2-691451FE49E7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Chronofoil.CaptureFile", "lib\Chronofoil.CaptureFile\src\Chronofoil.CaptureFile.csproj", "{63756043-1B5A-4989-9F43-73AC7F656A11}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -80,6 +82,24 @@ Global
{4303E4F0-4C90-44EB-90C2-691451FE49E7}.Release-Unsigned|x64.Build.0 = Release|Any CPU
{4303E4F0-4C90-44EB-90C2-691451FE49E7}.Release-Unsigned|x86.ActiveCfg = Release|Any CPU
{4303E4F0-4C90-44EB-90C2-691451FE49E7}.Release-Unsigned|x86.Build.0 = Release|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Debug|Any CPU.Build.0 = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Debug|x64.ActiveCfg = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Debug|x64.Build.0 = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Debug|x86.ActiveCfg = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Debug|x86.Build.0 = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release|Any CPU.ActiveCfg = Release|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release|Any CPU.Build.0 = Release|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release|x64.ActiveCfg = Release|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release|x64.Build.0 = Release|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release|x86.ActiveCfg = Release|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release|x86.Build.0 = Release|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release-Unsigned|Any CPU.ActiveCfg = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release-Unsigned|Any CPU.Build.0 = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release-Unsigned|x64.ActiveCfg = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release-Unsigned|x64.Build.0 = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release-Unsigned|x86.ActiveCfg = Debug|Any CPU
{63756043-1B5A-4989-9F43-73AC7F656A11}.Release-Unsigned|x86.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
10 changes: 2 additions & 8 deletions FFXIVMonReborn/FFXIVMonReborn.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<ProjectGuid>{7F56C183-CFA0-47D1-9683-53C484465CB6}</ProjectGuid>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
Expand Down Expand Up @@ -67,17 +67,10 @@
</Target>
<ItemGroup>
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.0" />
<PackageReference Include="IndexRange" Version="1.0.1-beta.1" />
<PackageReference Include="Lumina" Version="3.10.2" />
<PackageReference Include="Lumina.Excel" Version="6.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.1.0-1.final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0-1.final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0-1.final" />
<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.1.0-1.final" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="RestSharp.Newtonsoft.Json" Version="1.5.1" />
<PackageReference Include="SharpPcap" Version="6.2.5" />
Expand All @@ -87,6 +80,7 @@
<Resource Include="icon.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\lib\Chronofoil.CaptureFile\src\Chronofoil.CaptureFile.csproj" />
<ProjectReference Include="..\lib\Machina\Machina.FFXIV\Machina.FFXIV.csproj" />
<ProjectReference Include="..\lib\Machina\Machina\Machina.csproj" />
</ItemGroup>
Expand Down
126 changes: 126 additions & 0 deletions FFXIVMonReborn/Importers/ChronofoilImporter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
using FFXIVMonReborn.DataModel;
using System;
using System.Collections.Generic;
using Machina.FFXIV;
using System.Runtime.CompilerServices;
using Chronofoil.CaptureFile;
using Chronofoil.CaptureFile.Binary;
using Chronofoil.CaptureFile.Binary.Packet;
using Chronofoil.CaptureFile.Generated;
using Direction = Chronofoil.CaptureFile.Generated.Direction;
using Packet = Chronofoil.CaptureFile.Binary.Packet.Packet;

namespace FFXIVMonReborn.Importers;

public static class ChronofoilImporter
{
private static readonly List<PacketEntry> PacketEntries = new();

public static Capture Load(string path)
{
var reader = new CaptureReader(path);

var frameIndex = 0;
foreach (var frame in reader.GetFrames())
{
if (frame.Header.Protocol == Protocol.Chat) continue;

var set = frameIndex % 2;
var frameHeader = GetFrameHeader(frame.Frame.Span);
foreach (var packet in PacketsFromFrame(frame.Frame.Span))
{
var type = packet.IpcHeader?.Type ?? (ushort)packet.Header.Type;
var unixTime = packet.IpcHeader?.Timestamp ?? (uint)DateTimeOffset.FromUnixTimeMilliseconds((long)frameHeader.TimeValue).ToUnixTimeSeconds();
var routeId = packet.IpcHeader?.ServerId ?? 0;
var connection = frame.Header.Protocol switch
{
Protocol.Zone => FFXIVNetworkMonitor.ConnectionType.Game,
// Protocol.Chat => FFXIVNetworkMonitor.ConnectionType.Game,
Protocol.Lobby => FFXIVNetworkMonitor.ConnectionType.Lobby,
_ => throw new ArgumentOutOfRangeException()
};

var packetEntry = new PacketEntry
{
IsVisible = true,
ActorControl = -1,
Data = packet.Data,
Message = type.ToString("X4"),
Direction = frame.Header.Direction == Direction.Rx ? "S" : "C",
Category = set.ToString(),
Timestamp = DateTimeOffset.FromUnixTimeMilliseconds((long)frameHeader.TimeValue).ToLocalTime().ToString(@"MM\/dd\/yyyy HH:mm:ss"),
Size = packet.Header.Size.ToString(),
Set = set,
RouteID = routeId.ToString(),
PacketUnixTime = unixTime,
SystemMsTime = 0,
Connection = connection
};
PacketEntries.Add(packetEntry);
}

frameIndex++;
}

var capture = new Capture
{
Packets = PacketEntries.ToArray(),
UsingSystemTime = "false",
Version = -1,
};
return capture;
}

public static FrameHeader GetFrameHeader(ReadOnlySpan<byte> frame)
{
var headerSize = Unsafe.SizeOf<FrameHeader>();
var headerSpan = frame[..headerSize];
return headerSpan.CastTo<FrameHeader>();
}

public static List<Packet> PacketsFromFrame(ReadOnlySpan<byte> frame)
{
var list = new List<Packet>();

var headerSize = Unsafe.SizeOf<FrameHeader>();
var headerSpan = frame[..headerSize];
var header = headerSpan.CastTo<FrameHeader>();
var frameSpan = frame[..(int)header.TotalSize];
var data = frameSpan.Slice(headerSize, (int)header.TotalSize - headerSize);

// Console.WriteLine($"Frame has {header.Count} packets");

var offset = 0;
for (int i = 0; i < header.Count; i++)
{
var packet = new Packet();

// Get this packet's PacketElementHeader. It tells us the size
var pktHdrSize = Unsafe.SizeOf<PacketElementHeader>();
var pktHdrSlice = data.Slice(offset, pktHdrSize);
var pktHdr = pktHdrSlice.CastTo<PacketElementHeader>();

packet.Header = pktHdr;

// This span contains all packet data, excluding the element header, including the IPC header
var pktData = data.Slice(offset, (int)pktHdr.Size);

if (pktHdr.Type == PacketType.Ipc)
{
var ipcHdrSize = Unsafe.SizeOf<PacketIpcHeader>();
var ipcHdrSlice = pktData.Slice(pktHdrSize, ipcHdrSize);
var ipcHdr = ipcHdrSlice.CastTo<PacketIpcHeader>();

packet.IpcHeader = ipcHdr;
}
packet.Data = pktData.ToArray();

// Console.WriteLine($"Adding packet with type {pktHdr.Type} [{pktHdr.Size}] to list");
list.Add(packet);
offset += (int)pktHdr.Size;
}

// Console.WriteLine($"Returning list with {list.Count} packets");
return list;
}
}
4 changes: 3 additions & 1 deletion FFXIVMonReborn/Views/XivMonTab.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ public void LoadCapture()
OpenFileDialog openFileDialog = new OpenFileDialog();

openFileDialog.Multiselect = true;
openFileDialog.Filter = @"XML/Pcap|*.xml;*.pcap;*.pcapng";
openFileDialog.Filter = @"XML/Pcap/Chronofoil|*.xml;*.pcap;*.pcapng;*.ccfcap;*.cfcap";
openFileDialog.Title = @"Select Capture file(s)";

if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
Expand Down Expand Up @@ -968,6 +968,8 @@ public void LoadCapture(string path)

if (path.EndsWith("xml"))
capture = XmlCaptureImporter.Load(path);
else if (path.EndsWith("cfcap"))
capture = ChronofoilImporter.Load(path);
else
capture = PcapImporter.Load(path);

Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Depends on a fork of [Machina](https://github.com/goaaats/machina) by Ravahn.
- Enter filters for displayed packets, in the GUI see `Filters > Show Help`
## pcap Parsing
- Support for parsing pcap captures. pcap captures must be versioned via the `Database` functionality after import and saved as XML to retain any changes made to them
## Chronofoil capture support
- Support for [Chronofoil](https://github.com/ProjectChronofoil) captures. Chronofoil captures must be versioned via the `Database` functionality after import and saved as XML to retain any changes made to them
## Packet struct version control
- Syncs with [Sapphire](http://github.com/SapphireServer/Sapphire) packet structs (or another repo). See `Options > Set Repository`. Changing this value will erase local definitions. For safety of local data, this must be manually resynced via this menu or `Database > Redownload Definitions` whenever you wish to update definitions
- Allows versioning of a capture via the `Database` menu. To temporarily preview packets with specific, right-click the packet in the viewer and `Apply specific struct to packet`
Expand All @@ -26,7 +28,16 @@ Depends on a fork of [Machina](https://github.com/goaaats/machina) by Ravahn.
## Scripting
- Run C# scripts on captures. Make use of game files via the [Lumina](https://github.com/NotAdam/Lumina) library to further process captures
- Scripts can be run per capture or per packet via right-click on the packet list entry
- Running scripts can be significantly slower when using struct parsing. It is recommended to access the data using offsets instead for faster parsing of captures
## Packet Diff
- Compare the currently opened capture with another saved capture to try find opcode changes (not very accurate)
## Capture Anonymisation (partial)
- `File > Anonymise Captures` to strip saved XML captures of your Character Name and IDs (requires some manual input).
- Anonymised `Content ID` is `BE EE EF D1 EE EE EE ED`
- - `Content ID` is your character's GUID on game servers. This can be found as part of the path `My Games/FINAL FANTASY XIV - A Realm Reborn/FFXIV_CHR################`. You will need to specify the `Content ID` for the correct character in the capture you wish to anonymise
- Anonymised `Character ID`is `DE AD BE EF`
- Anonymised `Character Name` is `Player One`
- Chat packets are excluded where possible when anonymising captures (assuming the opcode is correct). May still need manual removal where the opcode wasn't updated in time due to opcode shifts
- **Note**: This may not prevent the game developers from finding you if they really want to but can increase the effort required

To apply changes to a capture it must be saved again, preferably to a file with a new name to preserve packet data in case of incorrect filtering.
1 change: 1 addition & 0 deletions lib/Chronofoil.CaptureFile
Submodule Chronofoil.CaptureFile added at ba8340