ValorantReplayParser 0.1.0-alpha.2
dotnet add package ValorantReplayParser --version 0.1.0-alpha.2
NuGet\Install-Package ValorantReplayParser -Version 0.1.0-alpha.2
<PackageReference Include="ValorantReplayParser" Version="0.1.0-alpha.2" />
<PackageVersion Include="ValorantReplayParser" Version="0.1.0-alpha.2" />
<PackageReference Include="ValorantReplayParser" />
paket add ValorantReplayParser --version 0.1.0-alpha.2
#r "nuget: ValorantReplayParser, 0.1.0-alpha.2"
#:package ValorantReplayParser@0.1.0-alpha.2
#addin nuget:?package=ValorantReplayParser&version=0.1.0-alpha.2&prerelease
#tool nuget:?package=ValorantReplayParser&version=0.1.0-alpha.2&prerelease
ValorantReplayParser
<a href="https://discord.gg/QSRSfcege7"><img src="https://discordapp.com/api/guilds/764106279752826930/widget.png?style=banner2"/></a>
ValorantReplayParser reads VALORANT replay files (.vrf) and emits typed gameplay events and replay metadata. It is a narrow, VALORANT-specific parser, not a general Unreal Engine replay parser.
The NuGet release 0.1.0-alpha.2 is experimental. Replay formats and the public API may change as the reverse-engineered format understanding improves. A replay version passing the compatibility checks does not mean every gameplay feature in that replay is decoded. See the release notes and migration guide before upgrading from 0.1.0-alpha.1.
Requirements and installation
The package targets net10.0; consumers need the .NET 10 runtime. Building this repository requires the .NET 10 SDK. Install the prerelease with:
dotnet add package ValorantReplayParser --version 0.1.0-alpha.2
Read a replay
The default constructor selects the full parse profile and the built-in VALORANT descriptor catalog. Supply an IReplayEventSink to receive events. The sink is called synchronously as events are produced:
using System;
using System.IO;
using Replay.Models.Errors;
using Replay.Models.Events;
using Replay.Valorant;
var reader = new ValorantReplayReader(eventSink: new ConsoleEventSink());
try
{
// Open a fresh stream at the start of the replay for each read.
using var stream = File.OpenRead("path/to/replay.vrf");
ValorantReplayReadResult result = reader.Read(stream);
Console.WriteLine($"Read status: {result.Status}");
Console.WriteLine($"Packets: {result.PacketStats.PacketCount}");
foreach (var diagnostic in result.Diagnostics)
{
Console.Error.WriteLine($"{diagnostic.Code}: {diagnostic.Message}");
}
if (result.SuppressedDiagnosticCount > 0)
{
Console.Error.WriteLine(
$"{result.SuppressedDiagnosticCount} additional diagnostics were omitted from the retained list.");
}
}
catch (ReplayParseException exception)
{
// Includes invalid replay metadata/version and malformed replay data.
Console.Error.WriteLine($"Replay could not be parsed: {exception.Message}");
}
sealed class ConsoleEventSink : IReplayEventSink
{
public void Emit(ReplayEvent replayEvent)
{
Console.WriteLine(
$"{replayEvent.GetType().Name} at {replayEvent.TimeSeconds:0.000}s " +
$"(packet {replayEvent.PacketId})");
}
}
Read returns a detached ValorantReplayReadResult containing metadata, packet and bunch statistics, diagnostics, and export-group summaries. It does not retain the input archive or stream, so the result remains usable after those inputs are disposed.
Status is Completed when no recoverable warnings were recorded and CompletedWithWarnings when one or more warnings were recorded. Diagnostics retains up to 1,000 structured warnings; TotalDiagnosticCount counts all warnings and SuppressedDiagnosticCount reports warnings beyond that retained limit. Current warnings identify partial-bunch sequence errors, incomplete partial bunches at end of input, and speculative typed-decoder fallbacks to raw payloads.
Malformed replay structure, invalid required reads, unsupported full-parse versions, and resource-limit violations fail with a ReplayParseException subtype. A returned result means the container was traversed under those rules; it does not promise that every known or unknown VALORANT feature was semantically decoded or that the file contains a complete match.
Events are streamed to the sink and are provisional until Read returns successfully. If a later parse error occurs, events already emitted cannot be rolled back. Some semantic enrichers defer events until related replay data is available, so event timestamps are not guaranteed to increase globally in emission order. If the sink throws, parsing stops and the original sink exception is propagated.
Inventory and economy descriptors
Inventory and economy data arrive as typed payloads on ExportGroupReceived and RpcReceived events:
AresInventoryDescriptorexposes character and equippable references, active state, correction fields, and 16 named slot references inEAresItemSlotorder.GetDecodedItemSlots()enumerates only references observed in this update, including explicit GUID zero clears.ItemSlotDescriptor.Contentsexposes a single item reference.MultiItemSlotDescriptor.MultiContentsexposes anItemSlotContentsUpdatecontaining the declared arrayCountand sparse indexedUpdates. Omitted indices retain prior values; a reduced count truncates the array, and count zero means a known empty array.PurchasedItemComponentDescriptorexposes replicated purchase provenance: purchaseable, purchasing player, session flag, and transaction source.
AresInventoryDescriptor is in Replay.Valorant.GameState; slot and purchase types are in Replay.Valorant.Inventory, and economy descriptors are in Replay.Valorant.Economy. Select ExportCategory.Inventory or ExportCategory.Economy in a parse profile to retain the corresponding identity fields too. Payloads represent individual updates. Use HasDecoded(propertyName) to distinguish observed properties from defaults; nullable slot references are null when absent from that update, and GUID zero explicitly clears a reference. Use ExportGroupReceived.IsDeleted and ActorClosed to track removals in consumer-owned state.
MoneyManagementComponentDescriptor exposes observed credits, OwnerExclusivePlayerInfoDescriptor.RoundInfos exposes sparse round credit/loadout updates, and gun request parameter descriptors expose recorded request fields. Identity joins, merged inventory/economy snapshots, weapon-name resolution, credit deltas, and round buy classification belong to the analyser. The parser retains the wire references and timestamps without inferring when a client finished equipping.
Metadata-only reads and input ownership
Use ReadMetadata to inspect replay metadata without parsing packet payloads. The example reuses the reader from the preceding sample:
using var metadataStream = File.OpenRead("path/to/replay.vrf");
ValorantReplayMetadata metadata = reader.ReadMetadata(metadataStream);
Console.WriteLine(metadata.FullParseSupportStatus);
Console.WriteLine(metadata.FullParseUnsupportedReason);
Metadata parsing can report UnsupportedVersion; a full Read rejects such a replay early. ReadMetadata still throws for malformed metadata. Reopen the file for a later full read: the stream overload reads from its current position, buffers the remaining bytes, and advances the supplied stream to its end. The reader does not dispose the caller's stream. FBinaryArchive(Stream) also buffers the remaining stream contents in memory, so replay size contributes to memory use; the partial-bunch limits do not bound this whole-file buffer.
The same reader instance may be reused for sequential reads, but it does not support concurrent or reentrant reads. With the FBinaryArchive overloads, the archive must be positioned at the start of the replay for each operation. Supply a new archive positioned at the beginning for a metadata read followed by a full read.
Parse profiles and support
The default ParseProfile enables all currently defined categories and selects all built-in descriptors and fields unless additional filters are set. ParseProfile.Minimal sets enabled categories to None, which filters out fields and RPCs assigned gameplay categories. Category-neutral fields can still be decoded. It is useful when replay metadata and packet/bunch traversal are needed without categorized gameplay decoding; it is not a lightweight substitute for full semantic parsing and it does not bypass replay-version validation. Other profiles can select categories, export paths, and fields.
The full reader requires replay version 5.3.2, game network protocol version 0, Unreal version values 522/1009, and a registered payload transform for the replay branch. The transform registry currently contains exactly these branches:
++Ares-Core+release-11.06++Ares-Core+release-11.07++Ares-Core+release-11.08++Ares-Core+release-11.09++Ares-Core+release-11.10++Ares-Core+release-11.11++Ares-Core+release-12.00++Ares-Core+release-12.01++Ares-Core+release-12.02++Ares-Core+release-12.03++Ares-Core+release-12.04++Ares-Core+release-12.05++Ares-Core+release-12.06++Ares-Core+release-12.07++Ares-Core+release-12.08++Ares-Core+release-12.09++Ares-Core+release-12.10++Ares-Core+release-12.11++Ares-Core+release-13.00++Ares-Core+release-13.01++Ares-Core+release-13.02++Ares-Core+release-13.04++Ares-Core+release-13.05++Ares-Core+release-china-13.05++Ares-Core+release-13.06
An unregistered branch or a mismatch in the replay, protocol, or Unreal versions is unsupported. The reader fails early rather than trying a guessed compatibility path. These version checks establish compatibility with the parser's known container and transform layout, not complete gameplay-semantic coverage. The China 13.05 transform has recovered payload-vector tests; a complete China replay fixture is not included in this repository.
Within those explicitly supported branches, descriptors and custom decoders may register release boundaries. A boundary applies from that VALORANT release forward until another boundary replaces it. This is intended for known semantic changes such as shifted field handles; it does not make an unknown branch or wire format supported.
WasDecoded on emitted export-group and RPC events indicates that the applicable decoder path ran; it is not a completeness guarantee. For decoded descriptor payloads, HasDecoded(propertyName) indicates whether that specific property was decoded and assigned. A RawPayloadFallback diagnostic means an explicitly speculative typed decoder rolled back and preserved the bounded payload as raw data.
Custom descriptor catalogs
The descriptorCatalog constructor argument replaces the built-in descriptor catalog completely. To add custom descriptors while keeping the built-in VALORANT descriptors, begin with ValorantDescriptors.CreateCatalog() and add your descriptors to that catalog before constructing the reader:
using Replay.Valorant;
using Replay.Valorant.Descriptors;
using Replay.Models.Descriptors;
using Replay.Models.Replay;
var catalog = ValorantDescriptors.CreateCatalog();
catalog.Add(new ExportGroupDescriptor("/Game/Custom/Example", ExportCategory.Debug));
var legacy = new ExportGroupDescriptor("/Game/Custom/Versioned", ExportCategory.Debug);
var release1305 = new ExportGroupDescriptor("/Game/Custom/Versioned", ExportCategory.Debug);
catalog.Add(
new VersionedDefinition<ExportGroupDescriptor>(legacy)
.From(new ReplayReleaseVersion(13, 5), release1305));
var reader = new ValorantReplayReader(descriptorCatalog: catalog);
Replace the example descriptors with your implementations and field definitions. FieldDescriptorBuilder.Decode and RpcDescriptorBuilder.Decode also accept VersionedDefinition values for layouts where only the decoder changes. Class-net-cache variants use the corresponding DescriptorCatalog.Add overload. Low-level ExportBindingRegistry callers must supply a ReplayReleaseVersion when a selected definition contains release boundaries; ValorantReplayReader derives it from the replay branch automatically.
Starting from CreateCatalog() also preserves VALORANT's stable-subobject class paths and path-alias provider. Passing a new empty DescriptorCatalog intentionally replaces those defaults too.
Progress
| Area | Status |
|---|---|
| Player Movement | ✔ |
| Agents | ✔ |
| Abilities | 🚧 |
| Gunplay | ✔ |
| Game State | ❌ |
| World State | ❌ |
| Stable public API | ❌ |
Projects
Replay.Models: shared models, parse results, constants, context contracts, and parser errors.Replay.Encoding: byte/bit archives,FBinaryArchive, payload transforms, and Oodle decompression.Replay.Unreal: replay-info, chunk scanning, replay-header parsing, and the replay-container pipeline.Replay.Valorant: VALORANT models, export groups, RPCs, ClassNetCaches, and gameplay interpretation.CliReader: CLI/demo entry point.*.Tests: NUnit test projects.
Build and test
dotnet build "ValorantReplayParser.sln"
dotnet test "ValorantReplayParser.sln"
CLI
Log decoded replay activity and a parse summary:
dotnet run --project "src\CliReader\CliReader.csproj" -- log "C:\path\to\replay.vrf"
Export replay events and movement as JSON:
dotnet run --project "src\CliReader\CliReader.csproj" -- export "C:\path\to\replay.vrf" --output "C:\path\to\export"
Show the full command or subcommand help:
dotnet run --project "src\CliReader\CliReader.csproj" -- --help
dotnet run --project "src\CliReader\CliReader.csproj" -- export --help
Useful libraries
- VRFKit — Rust library for parsing .vrf files.
Special thanks
- To the folks from FortniteReplayDecompressor for their work and documentation of the replay system.
- GPT 5.5 for reverse engineering VALORANT payload transformation and movement encoding.
License and disclaimer
This project is distributed under the MIT License; see LICENSE.
This project is an independent, community-developed tool and is not affiliated with, endorsed by, sponsored by, or approved by Riot Games. VALORANT, Riot Games, and all related trademarks are the property of Riot Games, Inc.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- ValorantReplayParser.Models (>= 0.1.0-alpha.2)
- ValorantReplayParser.Unreal (>= 0.1.0-alpha.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-alpha.2 | 39 | 10/8/2026 |
| 0.1.0-alpha.1 | 60 | 9/30/2026 |