mirror of
https://github.com/raphaeIl/Novaria.git
synced 2025-12-12 14:34:38 +01:00
basic table loader
This commit is contained in:
117
Novaria.Common/Util/GameDataController.cs
Normal file
117
Novaria.Common/Util/GameDataController.cs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Novaria.Common.Util
|
||||||
|
{
|
||||||
|
public class GameDataController : Singleton<GameDataController>
|
||||||
|
{
|
||||||
|
private int _magicKey = 234324;
|
||||||
|
private string _binVersion = "0.1.0.2";
|
||||||
|
|
||||||
|
public void LoadCommonBinData(string filepath, Action<int, byte[]> primaryIntAction, Action<string, byte[]> primaryStringAction, Action<long, byte[]> primaryLongAction, Action<byte[]> noPrimaryAction)
|
||||||
|
{
|
||||||
|
byte[] array = File.ReadAllBytes(filepath);
|
||||||
|
|
||||||
|
if (array == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using (MemoryStream memoryStream = new MemoryStream(array))
|
||||||
|
{
|
||||||
|
using (BinaryReader binaryReader = new BinaryReader(memoryStream))
|
||||||
|
{
|
||||||
|
var curr_magicKey = binaryReader.ReadInt32();
|
||||||
|
|
||||||
|
if (curr_magicKey == this._magicKey)
|
||||||
|
{
|
||||||
|
int num = (int)binaryReader.ReadInt16();
|
||||||
|
byte[] bytes = binaryReader.ReadBytes(num);
|
||||||
|
if (!(Encoding.UTF8.GetString(bytes) != this._binVersion))
|
||||||
|
{
|
||||||
|
bool flag = binaryReader.ReadByte() == 1;
|
||||||
|
byte b = binaryReader.ReadByte();
|
||||||
|
bool flag2 = b == 1;
|
||||||
|
bool flag3 = b == 2;
|
||||||
|
num = binaryReader.ReadInt32();
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
if (flag2)
|
||||||
|
{
|
||||||
|
this.LoadPrimaryKeyIntTable(binaryReader, num, primaryIntAction);
|
||||||
|
} else if (flag3)
|
||||||
|
{
|
||||||
|
this.LoadPrimaryLongIntTable(binaryReader, num, primaryLongAction);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.LoadPrimaryKeyStringTable(binaryReader, num, primaryStringAction);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.LoadNoPrimaryKeyTable(binaryReader, num, noPrimaryAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPrimaryKeyIntTable(BinaryReader br, int length, Action<int, byte[]> primaryIntAction)
|
||||||
|
{
|
||||||
|
if (primaryIntAction == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
int arg = br.ReadInt32();
|
||||||
|
int count = (int)br.ReadInt16();
|
||||||
|
byte[] arg2 = br.ReadBytes(count);
|
||||||
|
primaryIntAction(arg, arg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPrimaryLongIntTable(BinaryReader br, int length, Action<long, byte[]> primaryLongAction)
|
||||||
|
{
|
||||||
|
if (primaryLongAction == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
long arg = br.ReadInt64();
|
||||||
|
int count = (int)br.ReadInt16();
|
||||||
|
byte[] arg2 = br.ReadBytes(count);
|
||||||
|
primaryLongAction(arg, arg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void LoadPrimaryKeyStringTable(BinaryReader br, int length, Action<string, byte[]> primaryStringAction)
|
||||||
|
{
|
||||||
|
if (primaryStringAction == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
int count = (int)br.ReadInt16();
|
||||||
|
byte[] array = br.ReadBytes(count);
|
||||||
|
string @string = Encoding.UTF8.GetString(array);
|
||||||
|
count = (int)br.ReadInt16();
|
||||||
|
array = br.ReadBytes(count);
|
||||||
|
primaryStringAction(@string, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadNoPrimaryKeyTable(BinaryReader br, int length, Action<byte[]> noPrimaryAction)
|
||||||
|
{
|
||||||
|
if (noPrimaryAction == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
int count = (int)br.ReadInt16();
|
||||||
|
byte[] obj = br.ReadBytes(count);
|
||||||
|
noPrimaryAction(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,9 @@ using Serilog;
|
|||||||
|
|
||||||
using Novaria.GameServer.Controllers.Api.ProtocolHandlers;
|
using Novaria.GameServer.Controllers.Api.ProtocolHandlers;
|
||||||
using Novaria.Common.Crypto;
|
using Novaria.Common.Crypto;
|
||||||
|
using Novaria.Common.Util;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Novaria.GameServer.Services;
|
||||||
|
|
||||||
namespace Novaria.GameServer
|
namespace Novaria.GameServer
|
||||||
{
|
{
|
||||||
@@ -12,19 +15,6 @@ namespace Novaria.GameServer
|
|||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
PcapParser.PcapParser.Instance.LoadAllPackets(); // turn this off after real handlers are finished
|
PcapParser.PcapParser.Instance.LoadAllPackets(); // turn this off after real handlers are finished
|
||||||
|
|
||||||
// IDK how to dump
|
|
||||||
/*Log.Warning("Dumping Data.....");
|
|
||||||
var tables = Assembly.GetExecutingAssembly()
|
|
||||||
.GetTypes()
|
|
||||||
.Where(t => t.Name.StartsWith("table_"));
|
|
||||||
|
|
||||||
foreach (var file in Directory.GetFiles("../Novaria.Common/dataBin/"))
|
|
||||||
{
|
|
||||||
Log.Information(file);
|
|
||||||
var data = new GameDataExtraction().LoadCommonBinData(file);
|
|
||||||
Log.Information(data.ToString());
|
|
||||||
}*/
|
|
||||||
|
|
||||||
Log.Information("Starting SDK Server...");
|
Log.Information("Starting SDK Server...");
|
||||||
try
|
try
|
||||||
@@ -38,6 +28,7 @@ namespace Novaria.GameServer
|
|||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
builder.Services.AddProtocolHandlerFactory();
|
builder.Services.AddProtocolHandlerFactory();
|
||||||
|
builder.Services.AddExcelTableService();
|
||||||
builder.Services.AddControllers().AddApplicationPart(Assembly.GetAssembly(typeof(GameServer)));
|
builder.Services.AddControllers().AddApplicationPart(Assembly.GetAssembly(typeof(GameServer)));
|
||||||
|
|
||||||
// Add all Handler Groups
|
// Add all Handler Groups
|
||||||
|
|||||||
112
Novaria.GameServer/Services/TableService.cs
Normal file
112
Novaria.GameServer/Services/TableService.cs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
using Google.Protobuf;
|
||||||
|
using Google.Protobuf.Collections;
|
||||||
|
using Ionic.Zip;
|
||||||
|
using Nova.Client;
|
||||||
|
using Novaria.Common.Util;
|
||||||
|
using Serilog;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.Serialization.Formatters;
|
||||||
|
|
||||||
|
namespace Novaria.GameServer.Services
|
||||||
|
{
|
||||||
|
// note that all operations in this class MUST be thread-safe, idk if it is currently but if it's not, there will be race condition problems
|
||||||
|
public class TableService(ILogger<TableService> _logger)
|
||||||
|
{
|
||||||
|
private readonly ILogger<TableService> logger = _logger;
|
||||||
|
|
||||||
|
// example: maps Achievement (type) -> table_Achievement (instance), table_Achievement has a list that stores table
|
||||||
|
private readonly Dictionary<Type, IMessage> caches = [];
|
||||||
|
public static string ResourceDir = Path.Join(Path.GetDirectoryName(AppContext.BaseDirectory), "Resources");
|
||||||
|
|
||||||
|
private Type currentTableTypeCache; // this is the type that we're currently loading, ex. Achievement (type), reason for caching it in a field member? Nova uses hardcoded params Action<int, byte[]> so im too lazy to change
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Please <b>only</b> use this to get table that <b>have a respective file</b> (i.e. <c>CharacterExcelTable</c> have <c>characterexceltable.bytes</c>)
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="FileNotFoundException"></exception>
|
||||||
|
public IMessage GetTable<T>(bool bypassCache = false) where T : IMessage
|
||||||
|
{
|
||||||
|
var type = typeof(T);
|
||||||
|
currentTableTypeCache = type;
|
||||||
|
|
||||||
|
if (!bypassCache && caches.TryGetValue(type, out var cache))
|
||||||
|
return (T)cache;
|
||||||
|
|
||||||
|
var tableDir = Path.Combine(ResourceDir, "Tables");
|
||||||
|
var bytesFilePath = Path.Combine(tableDir, $"{typeof(T).Name}.bytes");
|
||||||
|
|
||||||
|
if (!File.Exists(bytesFilePath))
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException($"bytes files for {type.Name} not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
//TableEncryptionService.XOR(type.Name, bytes);
|
||||||
|
|
||||||
|
this.LoadCommonBin<T>(bytesFilePath); // after this, loaded table will be in the cache
|
||||||
|
|
||||||
|
logger.LogDebug("{Excel} loaded and cached", type.Name);
|
||||||
|
|
||||||
|
return caches[currentTableTypeCache];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadCommonBin<T>(string bytesFilePath)
|
||||||
|
{
|
||||||
|
currentTableTypeCache = typeof(T); // too lazy to change actions params, so do this
|
||||||
|
|
||||||
|
// get the table_XXX type
|
||||||
|
Type table_Type = Assembly.GetAssembly(typeof(table_Achievement)).GetTypes().Where(t => t.Name == $"table_{typeof(T).Name}").FirstOrDefault();
|
||||||
|
|
||||||
|
if (table_Type == null)
|
||||||
|
{
|
||||||
|
Log.Error($"table_{typeof(T).Name} type was not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inst = (IMessage)Activator.CreateInstance(table_Type);
|
||||||
|
caches[currentTableTypeCache] = inst;
|
||||||
|
|
||||||
|
GameDataController.Instance.LoadCommonBinData(bytesFilePath, new Action<int, byte[]>(this.AddCommonBin),
|
||||||
|
new Action<string, byte[]>(this.AddCommonBin),
|
||||||
|
new Action<long, byte[]>(this.AddCommonBin),
|
||||||
|
new Action<byte[]>(this.AddCommonBin));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddCommonBin(int _, byte[] data) { AddCommonBin_internal(_, data); }
|
||||||
|
private void AddCommonBin(string _, byte[] data) { AddCommonBin_internal(_, data); }
|
||||||
|
private void AddCommonBin(long _, byte[] data) { AddCommonBin_internal(_, data); }
|
||||||
|
private void AddCommonBin(byte[] data) { AddCommonBin_internal(null, data); }
|
||||||
|
|
||||||
|
private void AddCommonBin_internal(object _, byte[] data)
|
||||||
|
{
|
||||||
|
var parserProperty = currentTableTypeCache.GetProperties().Where(p => p.Name == "Parser").SingleOrDefault();
|
||||||
|
var parserInstance = parserProperty.GetValue(null);
|
||||||
|
|
||||||
|
var parsedData = typeof(MessageParser).GetMethods().Where(m => m.Name == "ParseFrom").FirstOrDefault().Invoke(parserInstance, new object[] { data }); ;
|
||||||
|
// add to target table, very inefficient rn
|
||||||
|
IMessage targetTable = caches[currentTableTypeCache];
|
||||||
|
var __ = currentTableTypeCache.GetProperties();
|
||||||
|
|
||||||
|
|
||||||
|
var listField = targetTable.GetType().GetProperties().Where(p => p.Name == "List").SingleOrDefault();
|
||||||
|
|
||||||
|
object repeatedFieldInstance = listField.GetValue(targetTable);
|
||||||
|
|
||||||
|
var addMethod = repeatedFieldInstance.GetType().GetMethods().Where(m => m.Name == "Add").FirstOrDefault();
|
||||||
|
|
||||||
|
addMethod.Invoke(repeatedFieldInstance, new object[] { parsedData });
|
||||||
|
|
||||||
|
//Log.Information($"Added {_}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ExcelTableServiceExtensions
|
||||||
|
{
|
||||||
|
public static void AddExcelTableService(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSingleton<TableService>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user