Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Triky313 committed Aug 13, 2023
2 parents 6be835a + c2c858e commit 5554773
Show file tree
Hide file tree
Showing 79 changed files with 1,673 additions and 1,429 deletions.
64 changes: 64 additions & 0 deletions src/StatisticAnalysisTool.Extractor/BinaryDecrypter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.IO.Compression;
using System.Security.Cryptography;

namespace StatisticAnalysisTool.Extractor;

public static class BinaryDecrypter
{
private static readonly byte[] Key = { 48, 239, 114, 71, 66, 242, 4, 50 };
private static readonly byte[] Iv = { 14, 166, 220, 137, 219, 237, 220, 79 };

public static async Task DecryptBinaryFileAsync(string inputPath, Stream outputStream)
{
await using var inputFile = File.OpenRead(inputPath);
var fileBuffer = new byte[inputFile.Length];
_ = await inputFile.ReadAsync(fileBuffer, 0, fileBuffer.Length);

var tDes = new DESCryptoServiceProvider
{
IV = Iv,
Mode = CipherMode.CBC,
Key = Key
};
var outBuffer = tDes.CreateDecryptor().TransformFinalBlock(fileBuffer, 0, fileBuffer.Length);

const int size = 4096;
var buffer = new byte[size];
int bytesRead;

await using GZipStream decompression = new GZipStream(new MemoryStream(outBuffer), CompressionMode.Decompress);
while ((bytesRead = decompression.Read(buffer, 0, buffer.Length)) > 0)
{
await outputStream.WriteAsync(buffer, 0, bytesRead);
}
}

public static async Task<MemoryStream> DecryptAndDecompressAsync(string inputPath)
{
await using var inputFile = File.OpenRead(inputPath);
var fileBuffer = new byte[inputFile.Length];
int bytesRead = await inputFile.ReadAsync(fileBuffer, 0, fileBuffer.Length);

var tDes = new DESCryptoServiceProvider
{
IV = Iv,
Mode = CipherMode.CBC,
Key = Key
};
var outBuffer = tDes.CreateDecryptor().TransformFinalBlock(fileBuffer, 0, bytesRead);

const int size = 4096;
var buffer = new byte[size];
int decompressedBytesRead;

await using GZipStream decompression = new GZipStream(new MemoryStream(outBuffer), CompressionMode.Decompress);
await using MemoryStream outputMemoryStream = new MemoryStream();

while ((decompressedBytesRead = await decompression.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await outputMemoryStream.WriteAsync(buffer, 0, decompressedBytesRead);
}

return outputMemoryStream;
}
}
55 changes: 55 additions & 0 deletions src/StatisticAnalysisTool.Extractor/BinaryDumper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using Newtonsoft.Json;
using System.Xml;
using Formatting = Newtonsoft.Json.Formatting;

namespace StatisticAnalysisTool.Extractor;

public class BinaryDumper
{
public static async Task ExtractAsync(string mainGameFolder, string outputFolderPath, string[] binFileNamesToExtract)
{
var allFiles = GetBinFilePaths(mainGameFolder, binFileNamesToExtract);
var outFiles = (string[]) allFiles.Clone();
for (var i = 0; i < outFiles.Length; i++)
{
outFiles[i] = outFiles[i].Remove(0, outFiles[i].LastIndexOf("GameData\\", StringComparison.Ordinal) + "GameData\\".Length);
}

foreach (string binFilePath in allFiles)
{
await DecryptBinFileAsync(outputFolderPath, binFilePath);
}
}

private static string[] GetBinFilePaths(string mainGameFolder, IEnumerable<string> binFileNamesToExtract)
{
return binFileNamesToExtract.Select(fileName => Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolder), $"{fileName}.bin"))
.ToArray();
}

private static async Task DecryptBinFileAsync(string outputFolderPath, string binFilePath)
{
var binFileWoe = Path.GetFileNameWithoutExtension(binFilePath);

if (binFileWoe.StartsWith("profanity", StringComparison.OrdinalIgnoreCase))
{
return;
}

var finalJsonPath = Path.Combine(outputFolderPath, binFileWoe + ".json");

await using var memoryStream = new MemoryStream();
await BinaryDecrypter.DecryptBinaryFileAsync(binFilePath, memoryStream);
memoryStream.Position = 0;

var xmlDocument = new XmlDocument();
var xmlReaderSettings = new XmlReaderSettings
{
IgnoreComments = true
};
var xmlReader = XmlReader.Create(memoryStream, xmlReaderSettings);
xmlDocument.Load(xmlReader);

await File.WriteAllTextAsync(finalJsonPath, JsonConvert.SerializeXmlNode(xmlDocument, Formatting.Indented, false));
}
}
8 changes: 8 additions & 0 deletions src/StatisticAnalysisTool.Extractor/Enums/ServerType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace StatisticAnalysisTool.Extractor.Enums;

public enum ServerType
{
Live,
Staging,
Playground
}
103 changes: 103 additions & 0 deletions src/StatisticAnalysisTool.Extractor/Extractor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using StatisticAnalysisTool.Extractor.Enums;

namespace StatisticAnalysisTool.Extractor;

public class Extractor
{
private readonly LocalizationData _localizationData = new();
private readonly string _mainGameServerFolderString;

public Extractor(string mainGameFolder, ServerType serverType)
{
string mainGameFolderString = Path.Combine(mainGameFolder, GetServerTypeString(serverType));
_mainGameServerFolderString = mainGameFolderString.Replace("'", "");
}

private async Task LoadLocationDataAsync()
{
if (_localizationData.IsDataLoaded())
{
return;
}

await _localizationData.LoadDataAsync(_mainGameServerFolderString);
}

public async Task ExtractIndexedItemGameDataAsync(string outputDirPath, string indexedItemsFileName)
{
await LoadLocationDataAsync();
await ItemData.CreateItemDataAsync(_mainGameServerFolderString, _localizationData, outputDirPath, indexedItemsFileName);
}

public async Task ExtractGameDataAsync(string outputDirPath, string[] binFileNamesToExtract)
{
await LoadLocationDataAsync();
await BinaryDumper.ExtractAsync(_mainGameServerFolderString, outputDirPath, binFileNamesToExtract);
}

private static string GetServerTypeString(ServerType serverType)
{
string serverTypeString = serverType switch
{
ServerType.Staging => "staging",
ServerType.Playground => "playground",
_ => "game"
};

return serverTypeString;
}

public static bool IsBinFileNewer(string toolFilePath, string mainGameFolder, ServerType serverType, string binFileName)
{
try
{
string mainGameFolderPath = Path.Combine(mainGameFolder, GetServerTypeString(serverType));
var binFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), $"{binFileName}.bin");
var toolFileDateTime = File.GetLastWriteTime(toolFilePath);

if (!File.Exists(binFilePath))
{
return false;
}

try
{
if (File.GetLastWriteTime(binFilePath) > toolFileDateTime)
{
return true;
}
}
catch
{
return false;
}

return false;
}
catch
{
return false;
}
}

public static bool IsValidMainGameFolder(string mainGameFolder, ServerType serverType)
{
string mainGameFolderPath = Path.Combine(mainGameFolder, GetServerTypeString(serverType));

var itemsBinFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), "items.bin");
var mobsBinFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), "mobs.bin");
var spellsBinFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), "spells.bin");
var worldBinFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), "cluster", "world.bin");

return File.Exists(itemsBinFilePath)
&& File.Exists(mobsBinFilePath)
&& File.Exists(spellsBinFilePath)
&& File.Exists(worldBinFilePath);
}

public void Dispose()
{
_localizationData.Dispose();
GC.SuppressFinalize(this);
}
}
43 changes: 43 additions & 0 deletions src/StatisticAnalysisTool.Extractor/ExtractorUtilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Text;
using System.Text.Json;

namespace StatisticAnalysisTool.Extractor;

public static class ExtractorUtilities
{
private static readonly JsonWriterOptions JsonWriterOptions = new ()
{
Indented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

public static void WriteItem(Stream stream, IdContainer idContainer, bool first = false)
{
if (!first)
{
stream.WriteByte((byte) ',');
stream.WriteByte((byte) '\n');
}

using var writer = new Utf8JsonWriter(stream, JsonWriterOptions);
if (idContainer is ItemContainer itemContainer)
{
JsonSerializer.Serialize(writer, itemContainer);
}
else
{
JsonSerializer.Serialize(writer, idContainer);
}
}

public static void WriteString(Stream stream, string val)
{
var buffer = Encoding.UTF8.GetBytes(val);
stream.Write(buffer, 0, buffer.Length);
}

public static string GetBinFilePath(string mainGameFolder)
{
return Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData");
}
}
7 changes: 7 additions & 0 deletions src/StatisticAnalysisTool.Extractor/IdContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace StatisticAnalysisTool.Extractor;

public class IdContainer
{
public string Index { get; set; }
public string UniqueName { get; set; }
}
9 changes: 9 additions & 0 deletions src/StatisticAnalysisTool.Extractor/ItemContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace StatisticAnalysisTool.Extractor;

public class ItemContainer : IdContainer
{
public string LocalizationNameVariable { get; set; }
public string LocalizationDescriptionVariable { get; set; }
public Dictionary<string, string> LocalizedNames { get; set; }
public Dictionary<string, string> LocalizedDescriptions { get; set; }
}
Loading

0 comments on commit 5554773

Please sign in to comment.