forked from sin365/AxibugEmuOnline
330 lines
11 KiB
C#
330 lines
11 KiB
C#
using AxibugEmuOnline.Client.ClientCore;
|
|
using AxibugEmuOnline.Client.Event;
|
|
using AxibugProtobuf;
|
|
using ICSharpCode.SharpZipLib.Zip;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
|
|
namespace AxibugEmuOnline.Client
|
|
{
|
|
public class RomFile
|
|
{
|
|
private HttpAPI.Resp_RomInfo webData;
|
|
/// <summary> 依赖的Rom文件 </summary>
|
|
private List<RomFile> dependencies = new List<RomFile>();
|
|
|
|
/// <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}");
|
|
}
|
|
}
|
|
}
|
|
|
|
bool m_hasLocalFile;
|
|
public bool HasLocalFile
|
|
{
|
|
get
|
|
{
|
|
if (!m_hasLocalFile) return false;
|
|
|
|
foreach (var depRom in dependencies)
|
|
{
|
|
if (!depRom.HasLocalFile) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary> 指示该Rom文件的存放路径 </summary>
|
|
public string LocalFilePath => $"{App.PersistentDataPath(Platform)}/RemoteRoms/{FileName}";
|
|
|
|
/// <summary> 指示该Rom文件是否已下载完毕 </summary>
|
|
public bool RomReady
|
|
{
|
|
get
|
|
{
|
|
if (!HasLocalFile) return false;
|
|
|
|
foreach (var depRom in dependencies)
|
|
{
|
|
if (!depRom.RomReady) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
/// <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);
|
|
}
|
|
}
|
|
|
|
public RomPlatformType Platform => webData != null ? (RomPlatformType)webData.ptype : RomPlatformType.Invalid;
|
|
/// <summary> 指示该Rom信息是否已填充 </summary>
|
|
public bool InfoReady
|
|
{
|
|
get
|
|
{
|
|
if (webData == null) return false;
|
|
|
|
foreach (var depRom in dependencies)
|
|
{
|
|
if (!depRom.InfoReady) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
/// <summary> 唯一标识 </summary>
|
|
public int ID => webData != null ? webData.id : -1;
|
|
/// <summary> 别名 </summary>
|
|
public string Alias => webData.romName;
|
|
/// <summary> 描述 </summary>
|
|
public string Descript => webData.desc;
|
|
/// <summary> 游戏类型 </summary>
|
|
public string GameTypeDes => webData.gType;
|
|
/// <summary> 小图URL </summary>
|
|
public string ImageURL => webData.imgUrl;
|
|
|
|
/// <summary> 文件名 </summary>
|
|
public string FileName { get; private set; }
|
|
/// <summary> 在查询结果中的索引 </summary>
|
|
public int Index { get; private set; }
|
|
/// <summary> 在查询结果中的所在页 </summary>
|
|
public int Page { get; private set; }
|
|
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;
|
|
}
|
|
}
|
|
|
|
public event Action<RomFile> OnDownloadOver;
|
|
public event Action OnInfoFilled;
|
|
|
|
public RomFile(int index, int insidePage)
|
|
{
|
|
Index = index;
|
|
Page = insidePage;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
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)
|
|
{
|
|
var currentEntry = zip.GetNextEntry();
|
|
if (currentEntry == null) break;
|
|
|
|
if (currentEntry.IsDirectory) continue;
|
|
|
|
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);
|
|
}
|
|
|
|
public byte[] GetRomFileData()
|
|
{
|
|
Debug.Assert(!MultiFileRom, "仅供单文件Rom使用的接口");
|
|
|
|
if (webData == null) throw new Exception("Not Valid Rom");
|
|
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)
|
|
{
|
|
var currentEntry = zip.GetNextEntry();
|
|
if (currentEntry == null) break;
|
|
|
|
if (!currentEntry.Name.ToLower().EndsWith(".nes")) continue;
|
|
|
|
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);
|
|
FileName = System.Net.WebUtility.UrlDecode(FileName);
|
|
|
|
//收集依赖Rom
|
|
if (webData.parentRomIdsList != null)
|
|
{
|
|
dependencies.Clear();
|
|
foreach (var romID in webData.parentRomIdsList)
|
|
{
|
|
var romFile = new RomFile(Index, Page);
|
|
dependencies.Add(romFile);
|
|
App.StartCoroutine(App.httpAPI.GetRomInfo(romID, (romInfo) =>
|
|
{
|
|
romFile.SetWebData(romInfo);
|
|
}));
|
|
}
|
|
}
|
|
|
|
CheckLocalFileState();
|
|
|
|
App.StartCoroutine(WaitInfoReady());
|
|
}
|
|
|
|
private IEnumerator WaitInfoReady()
|
|
{
|
|
while (!InfoReady) yield return null;
|
|
|
|
OnInfoFilled?.Invoke();
|
|
}
|
|
}
|
|
}
|