using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Compression; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using ColdMint.scripts.database; using ColdMint.scripts.database.dataPackEntity; using ColdMint.scripts.dataPack.entryLoader; using ColdMint.scripts.debug; using ColdMint.scripts.serialization; using ColdMint.scripts.utils; using Godot; using Microsoft.EntityFrameworkCore; namespace ColdMint.scripts.dataPack.local; /// /// LocalDataPack /// 本地数据包 /// public class LocalDataPack : IDataPack { private string zipFilePath; private string zipFileName; private IDataPackManifest? manifest; public LocalDataPack(string zipFilePath) { this.zipFilePath = zipFilePath; zipFileName = Path.GetFileName(zipFilePath); } /// /// Create index information for packets in the database /// 在数据库内为数据包创建索引信息 /// public async Task BuildIndex() { //我们首先根据文件名在数据表内查找对应的Md5值,在判断Md5值是否发生变化。 var entryLoaders = new List(); entryLoaders.Add(new ItemLoader()); entryLoaders.Add(new SpriteLoader()); var md5 = Md5Utils.GetFileMd5(zipFilePath); var dataPackDbContext = DataBaseManager.GetRequiredService(); var zipFileInfoDbSet = dataPackDbContext.ZipFileInfo; var query = from zipFileInfo in zipFileInfoDbSet where zipFileInfo.ZipFileName == zipFileName select zipFileInfo; var oldZipFileInfo = await query.FirstOrDefaultAsync(); if (oldZipFileInfo == null || oldZipFileInfo.ZipFileMd5 != md5) { //Get the list file GetEntry internal Dictionary based implementation, very fast //获取清单文件 GetEntry内部基于Dictionary实现,速度很快 //If there is no manifest file, we do not scan the zip and only save the Md5 value for next check //如果没有清单文件,我们不扫描zip,仅保存Md5值,以便下次检查 using var archive = ZipFile.Open(zipFilePath, ZipArchiveMode.Read, Encoding.GetEncoding("GBK")); var manifestEntry = archive.GetEntry(Config.DataPackManifestName); if (manifestEntry == null) { LogCat.LogErrorWithFormat("no_manifest_file", zipFilePath); } else { var dataPackManifestLoader = new DataPackManifestLoader(); await dataPackManifestLoader.ExecutionLoad(string.Empty, zipFileName, dataPackDbContext, manifestEntry); LogCat.LogWithFormat("build_an_index", zipFilePath); var zipEntryInfoDbSet = dataPackDbContext.ZipEntryInfo; if (oldZipFileInfo != null) { //Delete old records that are outdated //删除过时的旧记录 var entriesToDelete = zipEntryInfoDbSet .Where(entry => entry.FileName == zipFileName) .ToList(); dataPackDbContext.ZipEntryInfo.RemoveRange(entriesToDelete); var itemsToDelete = dataPackDbContext.ItemInfo .Where(item => item.ZipFileName == zipFileName) .ToList(); dataPackDbContext.ItemInfo.RemoveRange(itemsToDelete); var spritesToDelete = dataPackDbContext.SpriteInfo .Where(sprite => sprite.ZipFileName == zipFileName) .ToList(); dataPackDbContext.SpriteInfo.RemoveRange(spritesToDelete); await dataPackDbContext.SaveChangesAsync(); } foreach (var entry in archive.Entries) { if (entry.FullName.EndsWith(Config.ZipPathCharacter)) { //Ignore folders //忽略文件夹 continue; } var nowDateTime = DateTime.Now; foreach (var entryLoader in entryLoaders) { var needLoad = entryLoader.NeedLoad(entry); if (needLoad) { await entryLoader.ExecutionLoad(dataPackManifestLoader.Namespace, zipFileName, dataPackDbContext, entry); } } var zipEntryInfo = new ZipEntryInfo { FullName = entry.FullName, FileName = zipFileName, CrateTime = nowDateTime }; LogCat.LogWithFormat("add_file_index", entry.FullName); await zipEntryInfoDbSet.AddAsync(zipEntryInfo); } } if (oldZipFileInfo == null) { //创建一份 var zipNowDateTime = DateTime.Now; var zipFileInfo = new ZipFileInfo { ZipFileName = zipFileName, ZipFileMd5 = md5, EntryCount = archive.Entries.Count, CrateTime = zipNowDateTime, UpdateTime = zipNowDateTime }; dataPackDbContext.ZipFileInfo.Add(zipFileInfo); } else { var zipNowDateTime = DateTime.Now; oldZipFileInfo.UpdateTime = zipNowDateTime; oldZipFileInfo.ZipFileMd5 = md5; oldZipFileInfo.EntryCount = archive.Entries.Count; dataPackDbContext.Update(oldZipFileInfo); } try { await dataPackDbContext.SaveChangesAsync(); } catch (Exception e) { LogCat.LogError(e); } LogCat.LogWithFormat("index_updated", zipFilePath); return; } //没有变化什么也不做 LogCat.LogWithFormat("index_is_up_to_date", zipFilePath); } /// /// Load manifest file /// 加载清单文件 /// public async Task LoadManifest() { var dataPackDbContext = DataBaseManager.GetRequiredService(); var dataPackInfoDbSet = dataPackDbContext.DataPackInfo; var dataPackInfo = from dataPack in dataPackInfoDbSet where dataPack.ZipFileName == zipFileName select dataPack; if (dataPackInfo != null) { manifest = await dataPackInfo.FirstOrDefaultAsync(); } } public IDataPackManifest Manifest => manifest ?? EmptyManifest.CreateEmptyManifest(zipFileName); /// /// Get the item's data /// 获取物品的数据 /// /// public string GetItemsData() { return Path.Join(zipFilePath, "items"); } }