Implement GPAK data loading
This commit is contained in:
parent
e22825a204
commit
d0396cf19d
9 changed files with 1332 additions and 10 deletions
21
dep/K4os.Compression.LZ4/K4os.Compression.LZ4.License
Normal file
21
dep/K4os.Compression.LZ4/K4os.Compression.LZ4.License
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 Milosz Krajewski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
BIN
dep/K4os.Compression.LZ4/K4os.Compression.LZ4.dll
Normal file
BIN
dep/K4os.Compression.LZ4/K4os.Compression.LZ4.dll
Normal file
Binary file not shown.
1211
dep/K4os.Compression.LZ4/K4os.Compression.LZ4.xml
Normal file
1211
dep/K4os.Compression.LZ4/K4os.Compression.LZ4.xml
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -18,6 +18,8 @@ After getting the client, you need to set up a web server to serve SiteConfig.xm
|
|||
|
||||
6. Compile MHServerEmu with Visual Studio or any other tool you prefer.
|
||||
|
||||
7. Copy `Calligraphy.sip` and `mu_cdata.sip` located in `Marvel Heroes\Data\Game` to `MHServerEmu\Assets\GPAK`.
|
||||
|
||||
Now you can actually start everything and get in-game.
|
||||
|
||||
1. Start Apache by running ```Apache24\bin\httpd.exe```.
|
||||
|
|
|
|||
1
src/MHServerEmu/Assets/GPAK/IMPORTANT
Normal file
1
src/MHServerEmu/Assets/GPAK/IMPORTANT
Normal file
|
|
@ -0,0 +1 @@
|
|||
Copy Calligraphy.sip and mu_cdata.sip from Marvel Heroes\Data\Game to here
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Text;
|
||||
using MHServerEmu.Common;
|
||||
using MHServerEmu.GameServer.Data.Gpak;
|
||||
|
||||
namespace MHServerEmu.GameServer.Data
|
||||
{
|
||||
|
|
@ -8,6 +9,9 @@ namespace MHServerEmu.GameServer.Data
|
|||
private static readonly Logger Logger = LogManager.CreateLogger();
|
||||
|
||||
public static bool IsInitialized { get; private set; }
|
||||
public static GpakFile Calligraphy { get; private set; }
|
||||
public static GpakFile Resource { get; private set; }
|
||||
|
||||
public static Dictionary<ulong, Prototype> PrototypeDataDict { get; private set; }
|
||||
|
||||
public static ulong[] GlobalEnumRefTable { get; private set; }
|
||||
|
|
@ -16,17 +20,23 @@ namespace MHServerEmu.GameServer.Data
|
|||
|
||||
static Database()
|
||||
{
|
||||
Logger.Info("Loading prototypes...");
|
||||
long startTime = ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeMilliseconds();
|
||||
|
||||
Calligraphy = new("Calligraphy.sip");
|
||||
Resource = new("mu_cdata.sip");
|
||||
|
||||
Logger.Trace("Loading prototypes...");
|
||||
PrototypeDataDict = LoadPrototypeData($"{Directory.GetCurrentDirectory()}\\Assets\\PrototypeDataTable.bin");
|
||||
Logger.Info($"Loaded {PrototypeDataDict.Count} prototypes");
|
||||
|
||||
GlobalEnumRefTable = LoadPrototypeEnumRefTable($"{Directory.GetCurrentDirectory()}\\Assets\\GlobalEnumRefTable.bin");
|
||||
ResourceEnumRefTable = LoadPrototypeEnumRefTable($"{Directory.GetCurrentDirectory()}\\Assets\\ResourceEnumRefTable.bin");
|
||||
PropertyIdPowerRefTable = LoadPrototypeEnumRefTable($"{Directory.GetCurrentDirectory()}\\Assets\\PropertyIdPowerRefTable.bin");
|
||||
|
||||
if (PrototypeDataDict.Count > 0 && GlobalEnumRefTable.Length > 0 && ResourceEnumRefTable.Length > 0 && PropertyIdPowerRefTable.Length > 0)
|
||||
if (VerifyData())
|
||||
{
|
||||
// -1 is here because the first entry is 0 to offset values and align with the data we get from the game
|
||||
Logger.Info($"Loaded {PrototypeDataDict.Count} prototypes");
|
||||
long loadTime = ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeMilliseconds() - startTime;
|
||||
Logger.Info($"Finished loading in {loadTime} ms");
|
||||
IsInitialized = true;
|
||||
}
|
||||
else
|
||||
|
|
@ -36,6 +46,24 @@ namespace MHServerEmu.GameServer.Data
|
|||
}
|
||||
}
|
||||
|
||||
public static void ExportGpakEntries()
|
||||
{
|
||||
Logger.Info("Exporting Calligraphy entries...");
|
||||
Calligraphy.ExportEntries("Calligraphy.tsv");
|
||||
Logger.Info("Exporting Resource entries...");
|
||||
Resource.ExportEntries("mu_cdata.tsv");
|
||||
Logger.Info("Finished exporting GPAK entries");
|
||||
}
|
||||
|
||||
public static void ExportGpakData()
|
||||
{
|
||||
Logger.Info("Exporting Calligraphy data...");
|
||||
Calligraphy.ExportData();
|
||||
Logger.Info("Exporting Resource data...");
|
||||
Resource.ExportData();
|
||||
Logger.Info("Finished exporting GPAK data");
|
||||
}
|
||||
|
||||
private static Dictionary<ulong, Prototype> LoadPrototypeData(string path)
|
||||
{
|
||||
Dictionary<ulong, Prototype> prototypeDict = new();
|
||||
|
|
@ -97,5 +125,15 @@ namespace MHServerEmu.GameServer.Data
|
|||
return Array.Empty<ulong>();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool VerifyData()
|
||||
{
|
||||
return Calligraphy.Entries.Length > 0
|
||||
&& Resource.Entries.Length > 0
|
||||
&& PrototypeDataDict.Count > 0
|
||||
&& GlobalEnumRefTable.Length > 0
|
||||
&& ResourceEnumRefTable.Length > 0
|
||||
&& PropertyIdPowerRefTable.Length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using K4os.Compression.LZ4;
|
||||
using MHServerEmu.Common;
|
||||
|
||||
namespace MHServerEmu.GameServer.Data.Gpak
|
||||
|
|
@ -10,7 +12,7 @@ namespace MHServerEmu.GameServer.Data.Gpak
|
|||
|
||||
public int Header { get; } // KAPG
|
||||
public int Field1 { get; }
|
||||
public GpakEntry[] Entries { get; }
|
||||
public GpakEntry[] Entries { get; } = Array.Empty<GpakEntry>();
|
||||
|
||||
public GpakFile(string gpakFileName)
|
||||
{
|
||||
|
|
@ -18,15 +20,18 @@ namespace MHServerEmu.GameServer.Data.Gpak
|
|||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
Logger.Trace($"Loading {gpakFileName}...");
|
||||
|
||||
using (FileStream fileStream = File.OpenRead(path))
|
||||
{
|
||||
byte[] buffer = new byte[4096];
|
||||
|
||||
// Header
|
||||
Header = ReadInt(fileStream, buffer);
|
||||
Field1 = ReadInt(fileStream, buffer);
|
||||
Entries = new GpakEntry[ReadInt(fileStream, buffer)];
|
||||
|
||||
Entries = new GpakEntry[ReadInt(fileStream, buffer)];
|
||||
|
||||
// Entry metadata
|
||||
for (int i = 0; i < Entries.Length; i++)
|
||||
{
|
||||
ulong id = ReadUlong(fileStream, buffer);
|
||||
|
|
@ -42,12 +47,46 @@ namespace MHServerEmu.GameServer.Data.Gpak
|
|||
Entries[i] = new(id, filePath, field2, offset, compressedSize, uncompressedSize);
|
||||
}
|
||||
|
||||
Logger.Debug($"Loaded {Entries.Length} GPAK entries");
|
||||
// Entry data
|
||||
foreach (GpakEntry entry in Entries)
|
||||
{
|
||||
byte[] compressedData = new byte[entry.CompressedSize];
|
||||
byte[] uncompressedData = new byte[entry.UncompressedSize];
|
||||
fileStream.Read(compressedData, 0, compressedData.Length);
|
||||
LZ4Codec.Decode(compressedData, uncompressedData);
|
||||
entry.Data = uncompressedData;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Info($"Loaded {Entries.Length} GPAK entries from {gpakFileName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warn($"{gpakFileName} not found");
|
||||
Logger.Error($"{gpakFileName} not found");
|
||||
}
|
||||
}
|
||||
|
||||
public void ExportEntries(string fileName)
|
||||
{
|
||||
using (StreamWriter streamWriter = new($"{GpakDirectory}\\{fileName}"))
|
||||
{
|
||||
foreach (GpakEntry entry in Entries)
|
||||
{
|
||||
string entryString = $"{entry.Id}\t{entry.FilePath}\t{entry.Field2}\t{entry.Offset}\t{entry.CompressedSize}\t{entry.UncompressedSize}";
|
||||
streamWriter.WriteLine(entryString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ExportData()
|
||||
{
|
||||
foreach (GpakEntry entry in Entries)
|
||||
{
|
||||
string uncompressedFilePath = $"{GpakDirectory}\\{entry.FilePath}";
|
||||
string uncompressedFileDirectory = Path.GetDirectoryName(uncompressedFilePath);
|
||||
|
||||
if (Directory.Exists(uncompressedFileDirectory) == false) Directory.CreateDirectory(uncompressedFileDirectory);
|
||||
File.WriteAllBytes($"{GpakDirectory}\\{entry.FilePath}", entry.Data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,15 @@
|
|||
<Reference Include="Google.ProtocolBuffers">
|
||||
<HintPath>..\..\dep\protobuf-csharp\Google.ProtocolBuffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="K4os.Compression.LZ4">
|
||||
<HintPath>..\..\dep\K4os.Compression.LZ4\K4os.Compression.LZ4.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Assets\GPAK\IMPORTANT">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Packets\DangerRoomBeginLoading.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ namespace MHServerEmu
|
|||
_frontendServer.Shutdown();
|
||||
else if (input.Equals("parse", StringComparison.OrdinalIgnoreCase))
|
||||
PacketHelper.ParseServerMessagesFromAllPacketFiles();
|
||||
else if (input.Equals("exportgpakentries", StringComparison.OrdinalIgnoreCase))
|
||||
Database.ExportGpakEntries();
|
||||
else if (input.Equals("exportgpakdata", StringComparison.OrdinalIgnoreCase))
|
||||
Database.ExportGpakData();
|
||||
}
|
||||
|
||||
_frontendServer.Shutdown();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue