diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2951b05..1054f54 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,12 +6,14 @@ cmake_minimum_required(VERSION 4.1.0)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "/EHsc /D_AMD64_ /DWIN32_LEAN_AND_MEAN") # Set C++ exception handler, define platform and ignore some unused headers
-project(dbd-unlocker LANGUAGES CXX C)
+project(dbd-unlocker LANGUAGES CXX CSharp)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# ------------------------------
# msvc stuff
# ------------------------------
+set(CMAKE_CSharp_PROJECT_TYPE_GUID "9A19103F-16F7-4668-BE54-9A1E7A4F7556")
+
if(CMAKE_GENERATOR MATCHES "Visual Studio")
string(APPEND CMAKE_CXX_FLAGS " /EHsc /DWIN32_LEAN_AND_MEAN /utf-8 /Zc:char8_t")
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64")
@@ -77,8 +79,19 @@ set_property(TARGET dbd-unlocker PROPERTY USE_FOLDERS ON)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT dbd-unlocker)
group_files("${UNLOCKER_SOURCES}")
+
+# ------------------------------
+# dumper
+# ------------------------------
+include_external_msproject(dbd-dumper "${CMAKE_CURRENT_SOURCE_DIR}/src/dumper/dbd-dumper.csproj")
+
include_external_msproject(CUE4Parse "${CMAKE_CURRENT_SOURCE_DIR}/vendor/CUE4Parse/CUE4Parse/CUE4Parse.csproj")
+
+set_target_properties(dbd-dumper PROPERTIES VS_PROJECT_TYPE "9A19103F-16F7-4668-BE54-9A1E7A4F7556")
set_target_properties(CUE4Parse PROPERTIES VS_PROJECT_TYPE "9A19103F-16F7-4668-BE54-9A1E7A4F7556")
add_dependencies(dbd-dumper CUE4Parse)
+
+set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT dbd-unlocker)
+
diff --git a/src/dumper/Directory.Build.props b/src/dumper/Directory.Build.props
new file mode 100644
index 0000000..355797c
--- /dev/null
+++ b/src/dumper/Directory.Build.props
@@ -0,0 +1,5 @@
+
+
+ ..\..\proj\obj\$(MSBuildProjectName)\
+
+
diff --git a/src/dumper/main.cs b/src/dumper/main.cs
new file mode 100644
index 0000000..ce73750
--- /dev/null
+++ b/src/dumper/main.cs
@@ -0,0 +1,124 @@
+using CUE4Parse.Compression;
+using CUE4Parse.Encryption.Aes;
+using CUE4Parse.FileProvider;
+using CUE4Parse.MappingsProvider;
+using CUE4Parse.UE4.Assets.Exports.Engine;
+using CUE4Parse.UE4.Assets.Exports.Texture;
+using CUE4Parse.UE4.Objects.Core.Misc;
+using CUE4Parse.UE4.Versions;
+using CUE4Parse.Utils;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+class DumpByDaylight
+{
+ private const string _pakDir = "E:\\Program Files (x86)\\Steam\\steamapps\\common\\Dead by Daylight\\DeadByDaylight\\Content\\Paks";
+ private const string _aesKey = "0x22B1639B548124925CF7B9CBAA09F9AC295FCF0324586D6B37EE1D42670B39B3";
+ private const string _mappingURL = "https://github.com/Masusder/FModel-DbdMappings/raw/refs/heads/main/Mappings/9.5.0/5.4.4-3172922+++DeadByDaylight+Quiche_REL-DeadByDaylight.usmap";
+
+ public static async Task DownloadMappingFileAsync(string url, string savePath)
+ {
+ try
+ {
+ using (var httpClient = new HttpClient())
+ {
+ Console.WriteLine("downloading mapping file...");
+ var bytes = await httpClient.GetByteArrayAsync(url);
+ await File.WriteAllBytesAsync(savePath, bytes);
+ Console.WriteLine($"mapping file downloaded to: {savePath}");
+ return savePath;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"failed to download mapping: {ex.Message}");
+ return null;
+ }
+ }
+
+ static async Task Main(string[] args)
+ {
+ // mapping
+ string mappingPath = Path.Combine(Path.GetTempPath(), "DeadByDaylight.usmap");
+ string? downloadedMapping = await DownloadMappingFileAsync(_mappingURL, mappingPath);
+
+ if (string.IsNullOrEmpty(downloadedMapping))
+ {
+ Console.WriteLine("failed to download mapping file, press any key to exit");
+ Console.ReadKey();
+ return;
+ }
+
+ ZlibHelper.Initialize();
+ OodleHelper.Initialize();
+
+ // parsing setup
+ var version = new VersionContainer(EGame.GAME_DeadByDaylight, ETexturePlatform.DesktopMobile);
+ var provider = new DefaultFileProvider(_pakDir, SearchOption.TopDirectoryOnly, version);
+ provider.MappingsContainer = new FileUsmapTypeMappingsProvider(downloadedMapping);
+
+ provider.Initialize();
+ provider.SubmitKey(new FGuid(), new FAesKey(_aesKey));
+ provider.Mount();
+
+ Console.WriteLine("\nProvider Initialized. Extracting Databases...");
+
+ string[] dbNames = { "ItemDB", "OfferingDB", "ItemAddonDB" };
+ var dataPak = provider.GetArchive("pakchunk4-Windows.utoc");
+
+ foreach (var dbName in dbNames)
+ {
+ var searchPaths = dataPak.Files.Keys
+ .Where(x => x.Contains($"/{dbName}.uasset", StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ var standard = new List();
+ var special = new List();
+
+ foreach (var path in searchPaths)
+ {
+ var cleanPath = path.Contains('.') ? path.Substring(0, path.LastIndexOf('.')) : path;
+
+ if (provider.TryLoadPackageObject(cleanPath, out var dataTable))
+ {
+ Console.WriteLine($"- Processing {dbName} (from {Path.GetFileName(path)})...");
+ foreach (var row in dataTable.RowMap)
+ {
+ bool isInventory = row.Value.GetOrDefault("Inventory");
+ bool isBloodweb = row.Value.GetOrDefault("Bloodweb");
+
+ if (isBloodweb)
+ {
+ standard.Add(row.Key.Text);
+ }
+ else if (isInventory)
+ {
+ special.Add(row.Key.Text);
+ }
+ }
+ }
+ }
+
+ if (standard.Count > 0 || special.Count > 0)
+ {
+ var result = new
+ {
+ Standard = standard.OrderBy(x => x).ToList(),
+ Special = special.OrderBy(x => x).ToList()
+ };
+
+ string outputPath = $"{dbName}_Names.json";
+ File.WriteAllText(outputPath, JsonConvert.SerializeObject(result, Formatting.Indented));
+ Console.WriteLine($" -> Saved {standard.Count} standard and {special.Count} special entries to {outputPath}");
+ }
+ }
+
+ Console.WriteLine("\nAll dumper operations finished. Press any key to Close.");
+ Console.ReadKey();
+ }
+}