public static async Task Main(string[] args) { Console.WriteLine(DBCToolsExtensions.BuildToolsWelcomeMessage("CreateJSON")); //Try to load configuration file Config = new ApplicationConfigurationLoader().BuildConfigFile(); if (!Directory.Exists(Config.DiffOutputPath)) { Directory.CreateDirectory(Config.DiffOutputPath); } Parallel.ForEach(Directory.GetFiles(Config.DbcOutputPath).Select(Path.GetFileNameWithoutExtension), async dbcFile => { DbcTypeParser parser = new DbcTypeParser(); if (!parser.HasDbcType(dbcFile)) { //TODO: We should create a logger specifically for Program. if (Config.LoggingLevel >= LogLevel.Warning) { Console.WriteLine($"Encountered unknown DBC Type: {dbcFile}. Will skip."); } return; } IServiceProvider provider = new JSONContainerServiceBuilder(Config, dbcFile).Build(); using (var scope = provider.CreateScope()) { ILogger <Program> logger = scope.ServiceProvider.GetService <ILogger <Program> >(); try { if (logger.IsEnabled(LogLevel.Information)) { logger.LogInformation($"Populating CSV file for DBC: {dbcFile}"); } //This may look silly but we want to support the 50+ DBC types so //it needs to be handle magically otherwise we'd have to write code for each one. IDbcTargetFillable tableFiller = scope.ServiceProvider.GetService <IDbcTargetFillable>(); await tableFiller.FillAsync() .ConfigureAwait(false); } catch (Exception e) { if (logger.IsEnabled(LogLevel.Error)) { logger.LogError($"Encountered Exception: {e.Message} \n\n Stack: {e.StackTrace}"); } throw; } } }); Console.WriteLine("Finished. Press any key!"); }
static async Task Main(string[] args) { Console.WriteLine(DBCToolsExtensions.BuildToolsWelcomeMessage("CreateGDBC")); //Try to load configuration file Config = new ApplicationConfigurationLoader().BuildConfigFile(); DbcTypeParser dbcTypeParser = new DbcTypeParser(); Directory.CreateDirectory($"G{Config.DbcOutputPath}"); //For each implement DBCType we should try to build a DBC file for it. foreach (Type dbcType in dbcTypeParser.ComputeAllKnownDbcTypes()) { string dbcName = dbcTypeParser.GetDbcName(dbcType); IServiceProvider provider = new CreateGDbcContainerServiceBuilder(Config, dbcType).Build(); using (IServiceScope scope = provider.CreateScope()) { IDbcTargetFillable fillable = scope.ServiceProvider.GetService <IDbcTargetFillable>(); if (fillable == null) { throw new InvalidOperationException($"Failed to load Fillable for Type: {dbcType.Name}"); } await fillable.FillAsync(); using (Stream ms = scope.ServiceProvider.GetRequiredService <Stream>()) { //it is important to reset this position //Since we're 20 bytes in after likely writing the header last //Though the above statement could change, either way we want to be at the begining. ms.Position = 0; //It is possible nothing has been written, this is kinda hacky to put this //and leak this in a couple places. But it means no entires were found. if (ms.Length == 0) { continue; } //Once everything has been filled we should create the file using (FileStream fs = new FileStream($"G{Config.DbcOutputPath}/{dbcName}.gdbc", FileMode.CreateNew, FileAccess.ReadWrite)) { await ms.CopyToAsync(fs); } } } } Console.WriteLine("Finished. Press any key!"); }
/// <summary> /// Builds a <see cref="IServiceProvider"/> that registers /// <see cref="IDbcTargetFillable"/> which is the only service you should /// request from the container. This service will handle all complex /// logic for inserting and saving to the database. This is done so that support /// for 50 different DBC models and tables can be handled by one single set of generic services. /// </summary> /// <returns></returns> public IServiceProvider Build() { //With only the filename (which is why args will be passed in when this is a tool) //we need to be able to know the DBC model type AND we need to know what Types to use //to do the handling //We always need the TypeConverters so we register them first. ContainerBuilder builder = new ContainerBuilder(); ServiceCollection serviceCollection = new ServiceCollection(); builder.RegisterTypeConvertersFromAssembly(typeof(Program).Assembly); RegisterCreateDatabaseDatabaseService(serviceCollection); Type dbcModelType = new DbcTypeParser().ComputeDbcType(DbcType); TypedParameter pathParameter = CreateInputPathParameter(); //TODO: Support configurable DBC location/path. //If it's an open generic model it will mean that it requires string type type args //Not requiring this is much simplier, but it is still doable when the model is generic if (!dbcModelType.IsGenericTypeDefinition) { RegisterNonGenericDbcModelServices(builder, dbcModelType, pathParameter); } else { RegisterGenericDbcModelServices(builder, dbcModelType, pathParameter); } //TODO: Create a parsed string type so this dictionary is not exposed //May look odd but some TypeConverters actually need the string database //so they can convert from string offset/pointer to the actual string for the database. builder.Register <IReadOnlyDictionary <uint, string> >(context => { IDbcStringReadable readable = context.Resolve <IDbcStringReadable>(); //This is blocking return(readable.ParseOnlyStrings() .ConfigureAwait(false) .GetAwaiter() .GetResult()); }) .SingleInstance() .As <IReadOnlyDictionary <uint, string> >(); //TODO: Make logging optional serviceCollection.RegisterLoggingServices(Config.LoggingLevel); //This takes the ASP/Core service collection and pushes it all into AutoFac. builder.Populate(serviceCollection); return(new AutofacServiceProvider(builder.Build())); }
public static void Test_DBC_File_Converts_To_Table_Back_To_Same_DBC_File(Type t) { //arrange DbcTypeParser parser = new DbcTypeParser(); string dbcType = parser.GetDbcName(t); string filePath = Path.Combine(TestContext.CurrentContext.TestDirectory, "DBC", $"{dbcType}.dbc"); if (!File.Exists(filePath)) { Assert.Inconclusive($"No DBC file test into provided for Type: {t.Name}"); } ApplicationConfiguration config = new ApplicationConfiguration("test", true, LogLevel.Debug, Path.Combine(TestContext.CurrentContext.TestDirectory, "DBC"), "DBC_OUTPUT", "MPQ", "patch-6", "JSON"); //If we have a DBC file then we should prepare the DBC to Database stuff //so we can create an in memory database using (MockCreateDatabaseContainerServiceBuilder databaseCreatorContainer = new MockCreateDatabaseContainerServiceBuilder(config, dbcType, filePath)) { IServiceProvider databaseCreatorServiceProvider = databaseCreatorContainer.Build(); databaseCreatorServiceProvider.GetService <IDbcTargetFillable>().Fill(); //At this point the inmemory database is filled. MockedCreateDbcContainerServiceBuilder dbcCreatorContainer = new MockedCreateDbcContainerServiceBuilder(config, t, databaseCreatorServiceProvider.GetService <DbContext>()); IServiceProvider dbcCreatorServiceProvider = dbcCreatorContainer.Build(); dbcCreatorServiceProvider.GetService <IDbcTargetFillable>().Fill(); //At this point the DBC file should be in DbContext and the table should have //been loaded and turned back into a DBC file. Meaning we can now compare streams using (FileStream MockedFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) using (BinaryReader binaryRead2 = new BinaryReader(dbcCreatorServiceProvider.GetService <Stream>())) using (BinaryReader binaryRead1 = new BinaryReader(MockedFileStream)) { binaryRead2.BaseStream.Position = 0; binaryRead1.BaseStream.Position = 0; byte[] originalBytes = binaryRead1.ReadBytes((int)MockedFileStream.Length); byte[] outputBytes = binaryRead2.ReadBytes((int)binaryRead2.BaseStream.Length); Assert.AreEqual(originalBytes.Length, outputBytes.Length, $"Mismatch length on DBC to SQL to DBC for Type: {dbcType}"); for (int i = 0; i < originalBytes.Length; i++) { Assert.AreEqual(originalBytes[i], outputBytes[i], $"Mismatched value on DBC to SQL to DBC for Type: {dbcType} for Index: {i}"); } } } }
static async Task Main(string[] args) { //Try to load configuration file Config = new ApplicationConfigurationLoader().BuildConfigFile(); //TODO: This is just test code, we want to handle inputs better. Console.WriteLine($"Will create tables and database if they do not exist."); //TODO: We shouldn't check everytime we create a DBC table. Do this elsewhere await CreateDatabaseIfNotCreated(); ConsoleLogger defaultLogger = new ConsoleLogger("Console", (s, level) => level >= Config.LoggingLevel, false); foreach (string dbcFile in Directory.GetFiles("DBC").Select(Path.GetFileNameWithoutExtension)) { //TODO: Register in IoC DbcTypeParser parser = new DbcTypeParser(); if (!parser.HasDbcType(dbcFile)) { //TODO: We should create a logger specifically for Program. if (defaultLogger.IsEnabled(LogLevel.Warning)) { defaultLogger.LogWarning($"Encountered unknown DBC Type: {dbcFile}. Will skip."); } continue; } //We should check if we know a DBC file of this type. IServiceProvider provider = new CreateDatabaseContainerServiceBuilder(Config, dbcFile).Build(); Stopwatch watch = new Stopwatch(); watch.Start(); using (var scope = provider.CreateScope()) { ILogger <Program> logger = scope.ServiceProvider.GetService <ILogger <Program> >(); try { if (logger.IsEnabled(LogLevel.Information)) { logger.LogInformation($"Populating table for DBC: {dbcFile}"); } //This may look silly but we want to support the 50+ DBC types so //it needs to be handle magically otherwise we'd have to write code for each one. IDbcTargetFillable tableFiller = scope.ServiceProvider.GetService <IDbcTargetFillable>(); await tableFiller.FillAsync(); } catch (Exception e) { if (logger.IsEnabled(LogLevel.Error)) { logger.LogError($"Encountered Exception: {e.Message} \n\n Stack: {e.StackTrace}"); } throw; } } watch.Stop(); if (defaultLogger.IsEnabled(LogLevel.Information)) { defaultLogger.LogInformation($"Created Table: {dbcFile} In Milliseconds: {watch.ElapsedMilliseconds}"); } } defaultLogger.LogWarning("Finished. Press any key!"); Console.ReadKey(); }