/// <inheritdoc />
        public async Task WriteHeader(DBCHeader header)
        {
            await DbcStream.FlushAsync();

            //TODO: This is kinda hack, but makes things really easy for callers. Header should always go in front.
            DbcStream.Position = 0;

            byte[] bytes = Serializer.Serialize(header);

            await DbcStream.WriteAsync(bytes, 0, bytes.Length);

            await DbcStream.FlushAsync();
        }
        /// <inheritdoc />
        public async Task WriteEntries(IReadOnlyCollection <TDbcWriteType> entries)
        {
            //The reason we don't do anything if we encounter no entires
            //is someone could have a partial database. It is not their fault if they don't want to
            //maintain some DBC types
            //So we must just skip writing emptyones
            if (entries.Count == 0)
            {
                if (Logger.IsEnabled(LogLevel.Warning))
                {
                    Logger.LogWarning($"Skipping TableType: {entries.Count} because it has no entries. If this is not desired you must populate the table somehow.");
                }

                return;
            }

            if (Logger.IsEnabled(LogLevel.Information))
            {
                Logger.LogDebug($"Writing: {entries.Count} Type: {typeof(TDbcWriteType).Name}");
            }

            //TODO: Make this more efficient
            DbcStringDatabase stringDatabase = StringDatabaseProvider.BuildDatabase();

            //We must move the writer ahead to leave room for the header
            //which we must write at the end.
            //TODO: This is a hack, we put a fake header in the stream at first so we can rewrite it later.
            await HeaderWriter.WriteHeader(new DBCHeader(1, 1, 1, 1));

            int entrySize = await EntryWriter.WriteContents(entries);

            //We have to order this otherwise the strings may be out of order based on their
            //offset that we set the original members to.
            var stringCollection = stringDatabase.StringToOffsetMap
                                   .OrderBy(pair => pair.Value)
                                   .Select(s => s.Key)
                                   .ToArray();

            await StringWriter.WriteStringContents(stringCollection);

            DBCHeader header = new DBCHeader(entries.Count, CalculateFieldCount(entrySize), entrySize, (int)stringDatabase.Currentoffset);

            if (Logger.IsEnabled(LogLevel.Debug))
            {
                Logger.LogDebug($"Generating Header for Type: {typeof(TDbcWriteType).Name} with HeaderValue: {header}");
            }

            //Now write the real header
            await HeaderWriter.WriteHeader(header);
        }
Example #3
0
        private async Task <Dictionary <uint, TDBCEntryType> > ReadDBCEntryBlock(DBCHeader header)
        {
            //Guessing the size here, no way to know.
            Dictionary <uint, TDBCEntryType> entryMap = new Dictionary <uint, TDBCEntryType>(header.RecordsCount);

            byte[] bytes = new byte[header.RecordSize * header.RecordsCount];

            //Lock for safety, we don't want anyone else accessing the stream while we read it.
            await ReadBytesIntoArrayFromStream(bytes);

            DefaultStreamReaderStrategy reader = new DefaultStreamReaderStrategy(bytes);

            for (int i = 0; i < header.RecordsCount; i++)
            {
                TDBCEntryType entry = default(TDBCEntryType);
                try
                {
                    entry = Serializer.Deserialize <TDBCEntryType>(reader);
                }
                catch (Exception e)
                {
                    if (Logger.IsEnabled(LogLevel.Error))
                    {
                        Logger.LogError($"Encountered error reading entry Type: {typeof(TDBCEntryType).Name} at Entry count: {i} Exception: {e.Message} \n\n Stack: {e.StackTrace}");
                    }

                    Console.WriteLine($"Encountered error reading entry Type: {typeof(TDBCEntryType).Name} at Entry count: {i} Exception: {e.Message} \n\n Stack: {e.StackTrace}");

                    throw;
                }

                entryMap.Add(entry.EntryId, entry);
            }

            if (Logger.IsEnabled(LogLevel.Debug))
            {
                Logger.LogDebug($"Finished reading entries for Type: {typeof(TDBCEntryType).Name}");
            }

            return(entryMap);
        }
Example #4
0
        //TODO: Does this work for 0 length blocks?
        private async Task <Dictionary <uint, string> > ReadDBCStringBlock(DBCHeader header)
        {
            Dictionary <uint, string> stringMap = new Dictionary <uint, string>(1000);

            DBCStream.Position = header.StartStringPosition;
            byte[] bytes = new byte[DBCStream.Length - DBCStream.Position];

            await ReadBytesIntoArrayFromStream(bytes);

            DefaultStreamReaderStrategyAsync stringReader = new DefaultStreamReaderStrategyAsync(bytes);

            for (int currentOffset = 0; currentOffset < bytes.Length;)
            {
                string readString = (await Serializer.DeserializeAsync <StringDBC>(stringReader)).StringValue;

                stringMap.Add((uint)currentOffset, readString);

                //We must move the offset forward length + null terminator
                currentOffset += readString.Length + 1;
            }

            return(stringMap);
        }