AxibugEmuOnline/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/RomLib/RomFile.cs

333 lines
11 KiB
C#
Raw Normal View History

using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event;
using AxibugProtobuf;
2024-12-11 21:21:27 +08:00
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections;
using System.Collections.Generic;
2024-12-11 21:21:27 +08:00
using System.IO;
using UnityEngine;
2024-12-11 21:21:27 +08:00
namespace AxibugEmuOnline.Client
{
public class RomFile
{
private HttpAPI.Resp_RomInfo webData;
/// <summary> 依赖的Rom文件 </summary>
private List<RomFile> dependencies = new List<RomFile>();
2025-01-23 17:44:02 +08:00
RomPlatformType m_defaultPlatform;
2024-12-11 21:21:27 +08:00
/// <summary> 指示该Rom是否是多文件Rom </summary>
public bool MultiFileRom
{
get
{
switch (Platform)
{
case RomPlatformType.Nes: return false;
case RomPlatformType.Igs:
case RomPlatformType.Cps1:
case RomPlatformType.Cps2:
case RomPlatformType.Neogeo:
return true;
default: throw new NotImplementedException($"未实现的平台{Platform}");
}
}
}
2024-12-11 21:21:27 +08:00
bool m_hasLocalFile;
public bool HasLocalFile
{
get
{
if (!m_hasLocalFile) return false;
foreach (var depRom in dependencies)
{
if (!depRom.HasLocalFile) return false;
}
return true;
}
}
2024-12-11 21:21:27 +08:00
/// <summary> 指示该Rom文件的存放路径 </summary>
public string LocalFilePath => $"{App.PersistentDataPath(Platform)}/RemoteRoms/{FileName}";
2024-12-11 21:21:27 +08:00
/// <summary> 指示该Rom文件是否已下载完毕 </summary>
public bool RomReady
{
get
{
if (!HasLocalFile) return false;
foreach (var depRom in dependencies)
{
if (!depRom.RomReady) return false;
}
return true;
}
}
2024-12-11 21:21:27 +08:00
/// <summary> 指示是否正在下载Rom文件 </summary>
public bool IsDownloading
{
get
{
if (!InfoReady) return false;
var progress = App.FileDownloader.GetDownloadProgress(webData.url);
if (progress.HasValue) return true;
foreach (var depRom in dependencies)
{
if (depRom.IsDownloading) return true;
}
return false;
}
}
public float Progress
{
get
{
if (!IsDownloading) return 0;
float progress = 0f;
if (HasLocalFile) progress = 1f;
else
{
var downloadProgress = App.FileDownloader.GetDownloadProgress(webData.url);
progress = downloadProgress.HasValue ? downloadProgress.Value : 0;
}
foreach (var depRom in dependencies)
{
progress += depRom.Progress;
}
return progress / (dependencies.Count + 1);
}
}
2024-12-11 21:21:27 +08:00
2025-01-23 17:44:02 +08:00
public RomPlatformType Platform => webData != null ? (RomPlatformType)webData.ptype : m_defaultPlatform;
2024-12-11 21:21:27 +08:00
/// <summary> 指示该Rom信息是否已填充 </summary>
public bool InfoReady
{
get
{
if (webData == null) return false;
foreach (var depRom in dependencies)
{
if (!depRom.InfoReady) return false;
}
return true;
}
}
2024-12-11 21:21:27 +08:00
/// <summary> 唯一标识 </summary>
public int ID => webData != null ? webData.id : -1;
/// <summary> 别名 </summary>
public string Alias => webData.romName;
2024-12-11 21:21:27 +08:00
/// <summary> 描述 </summary>
public string Descript => webData.desc;
2024-12-11 21:21:27 +08:00
/// <summary> 游戏类型 </summary>
public string GameTypeDes => webData.gType;
2024-12-11 21:21:27 +08:00
/// <summary> 小图URL </summary>
public string ImageURL => webData.imgUrl;
2024-12-11 21:21:27 +08:00
/// <summary> 文件名 </summary>
public string FileName { get; private set; }
/// <summary> 在查询结果中的索引 </summary>
public int Index { get; private set; }
/// <summary> 在查询结果中的所在页 </summary>
2025-01-23 17:44:02 +08:00
public int Page { get; private set; }
2025-01-07 20:29:31 +08:00
public string Hash => webData != null ? webData.hash : string.Empty;
/// <summary> 标记是否收藏 </summary>
public bool Star
{
get { return webData != null ? webData.isStar > 0 : false; }
set
{
if (webData == null) return;
webData.isStar = value ? 1 : 0;
}
}
2024-12-11 21:21:27 +08:00
public event Action<RomFile> OnDownloadOver;
public event Action OnInfoFilled;
2025-01-23 17:44:02 +08:00
public RomFile(int index, int insidePage, RomPlatformType defaultPlatform)
2024-12-11 21:21:27 +08:00
{
Index = index;
Page = insidePage;
2025-01-23 17:44:02 +08:00
m_defaultPlatform = defaultPlatform;
2024-12-11 21:21:27 +08:00
}
public void CheckLocalFileState()
{
if (webData == null) m_hasLocalFile = false;
else
{
if (App.FileDownloader.GetDownloadProgress(webData.url) == null)
{
if (MultiFileRom)
m_hasLocalFile = Directory.Exists(LocalFilePath);
else
m_hasLocalFile = File.Exists(LocalFilePath);
}
}
foreach (var depRom in dependencies)
depRom.CheckLocalFileState();
}
2024-12-11 21:21:27 +08:00
public void BeginDownload()
{
if (RomReady) return;
if (IsDownloading) return;
//检查依赖Rom的下载情况
foreach (var depRom in dependencies)
{
depRom.BeginDownload();
}
App.FileDownloader.BeginDownload(webData.url, (bytes) =>
{
HandleRomFilePostProcess(bytes);
});
}
private void HandleRomFilePostProcess(byte[] bytes)
{
if (bytes == null) return;
if (MultiFileRom)
{
Dictionary<string, byte[]> unzipFiles = new Dictionary<string, byte[]>();
//多rom文件的平台,下载下来的数据直接解压放入文件夹内
var zip = new ZipInputStream(new MemoryStream(bytes));
List<string> depth0Files = new List<string>();
while (true)
2024-12-11 21:21:27 +08:00
{
var currentEntry = zip.GetNextEntry();
if (currentEntry == null) break;
2024-12-11 21:21:27 +08:00
if (currentEntry.IsDirectory) continue;
2024-12-11 21:21:27 +08:00
var buffer = new byte[1024];
MemoryStream output = new MemoryStream();
while (true)
{
var size = zip.Read(buffer, 0, buffer.Length);
if (size == 0) break;
else output.Write(buffer, 0, size);
}
output.Flush();
unzipFiles[$"{LocalFilePath}/{currentEntry.Name}"] = output.ToArray();
}
string rootDirName = null;
//如果第一层目录只有一个文件并且是文件夹,则所有文件层级外提一层
if (depth0Files.Count == 1 && depth0Files[0].Contains('.'))
{
rootDirName = depth0Files[0];
}
foreach (var item in unzipFiles)
{
var path = rootDirName != null ? item.Key.Substring(0, rootDirName.Length + 1) : item.Key;
var data = item.Value;
Directory.CreateDirectory(Path.GetDirectoryName(path));
File.WriteAllBytes(path, data);
}
}
else
{
var directPath = Path.GetDirectoryName(LocalFilePath);
Directory.CreateDirectory(directPath);
File.WriteAllBytes(LocalFilePath, bytes);
}
Eventer.Instance.PostEvent(EEvent.OnRomFileDownloaded, ID);
OnDownloadOver?.Invoke(this);
}
2024-12-11 21:21:27 +08:00
public byte[] GetRomFileData()
{
Debug.Assert(!MultiFileRom, "仅供单文件Rom使用的接口");
if (webData == null) throw new Exception("Not Valid Rom");
2024-12-11 21:21:27 +08:00
if (!RomReady) throw new Exception("Rom File Not Downloaded");
var bytes = File.ReadAllBytes(LocalFilePath);
if (Path.GetExtension(LocalFilePath).ToLower() == ".zip")
{
var zip = new ZipInputStream(new MemoryStream(bytes));
while (true)
2024-12-11 21:21:27 +08:00
{
var currentEntry = zip.GetNextEntry();
if (currentEntry == null) break;
if (!currentEntry.Name.ToLower().EndsWith(".nes")) continue;
2024-12-11 21:21:27 +08:00
var buffer = new byte[1024];
MemoryStream output = new MemoryStream();
while (true)
{
var size = zip.Read(buffer, 0, buffer.Length);
if (size == 0) break;
else output.Write(buffer, 0, size);
}
output.Flush();
return output.ToArray();
}
}
else
{
return bytes;
}
throw new Exception("Not Valid Rom Data");
}
public void SetWebData(HttpAPI.Resp_RomInfo resp_RomInfo)
{
webData = resp_RomInfo;
FileName = MultiFileRom ? Path.GetFileNameWithoutExtension(webData.url) : Path.GetFileName(webData.url);
2024-12-11 21:21:27 +08:00
FileName = System.Net.WebUtility.UrlDecode(FileName);
//收集依赖Rom
if (webData.parentRomIdsList != null)
{
dependencies.Clear();
foreach (var romID in webData.parentRomIdsList)
{
2025-01-23 17:44:02 +08:00
var romFile = new RomFile(Index, Page, m_defaultPlatform);
dependencies.Add(romFile);
App.StartCoroutine(App.httpAPI.GetRomInfo(romID, (romInfo) =>
{
romFile.SetWebData(romInfo);
}));
}
}
CheckLocalFileState();
2024-12-11 21:21:27 +08:00
App.StartCoroutine(WaitInfoReady());
}
private IEnumerator WaitInfoReady()
{
while (!InfoReady) yield return null;
OnInfoFilled?.Invoke();
2024-12-11 21:21:27 +08:00
}
}
}