重构RomFile,支持依赖Rom的联动下载,以及多文件Rom的下载

This commit is contained in:
ALIENJACK\alien 2025-01-23 14:19:26 +08:00
parent 6a770fe4f1
commit c147e1dd91
18 changed files with 6563 additions and 1189 deletions

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ae0d9b04c112f5b4c98feb0af7ed5676
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: cf3c029a754c0dc40b15ce6b1962e31f
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c4467b8175b4db64093d603a93775dff
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7478117b6f7d6cb4cb8c0f5d56205ea1
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,6 +3,7 @@ using AxibugEmuOnline.Client.Network;
using AxibugProtobuf;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
@ -22,14 +23,6 @@ namespace AxibugEmuOnline.Client.ClientCore
public static AppChat chat;
public static UserDataManager user;
public static AppEmu emu;
/// <summary>
/// nes Rom库
/// </summary>
public static RomLib nesRomLib;
/// <summary>
/// 收藏 Rom库
/// </summary>
public static RomLib starRomLib;
public static HttpAPI httpAPI;
public static CacheManager CacheMgr;
public static AppRoom roomMgr;
@ -39,6 +32,12 @@ namespace AxibugEmuOnline.Client.ClientCore
public static SaveSlotManager SavMgr;
static bool bTest;
static string mTestSrvIP;
/// <summary> 收藏 Rom库 </summary>
public static RomLib starRomLib;
private static Dictionary<RomPlatformType, RomLib> s_romLibs = new Dictionary<RomPlatformType, RomLib>();
#region Mono
public static TickLoop tickLoop;
private static CoroutineRunner coRunner;
@ -62,6 +61,11 @@ namespace AxibugEmuOnline.Client.ClientCore
}
public static string PersistentDataRoot() => s_persistentRoot;
public static RomLib GetRomLib(RomPlatformType platform)
{
return s_romLibs[platform];
}
public static void Init(bool isTest = false, string testSrvIP = "", bool bUseLocalWebApi = false, string mLocalWebApi = "")
{
log = new LogManager(OnLogOut);
@ -81,7 +85,14 @@ namespace AxibugEmuOnline.Client.ClientCore
httpAPI = new HttpAPI();
if (bUseLocalWebApi)
httpAPI.WebHost = mLocalWebApi;
nesRomLib = new RomLib(RomPlatformType.Nes);
foreach (RomPlatformType plat in Enum.GetValues(typeof(RomPlatformType)))
{
if (plat == RomPlatformType.All || plat == RomPlatformType.Invalid) continue;
s_romLibs[plat] = new RomLib(plat);
}
starRomLib = new RomLib();
CacheMgr = new CacheManager();
roomMgr = new AppRoom();
@ -121,6 +132,7 @@ namespace AxibugEmuOnline.Client.ClientCore
}
private static IEnumerator AppTickFlow()
{
while (true)
@ -211,7 +223,7 @@ namespace AxibugEmuOnline.Client.ClientCore
private static void Tick()
{
nesRomLib.ExecuteFetchRomInfo();
foreach (var romLib in s_romLibs.Values) romLib.ExecuteFetchRomInfo();
starRomLib.ExecuteFetchRomInfo();
gamePadMgr.Update();

View File

@ -32,7 +32,7 @@ namespace AxibugEmuOnline.Client.Manager
if (!m_emuCore.IsNull()) StopGame();
var roomInfo = App.roomMgr.mineRoomMiniInfo;
roomInfo.FetchRomFileInRoomInfo(RomPlatformType.Nes, (_, romFile) =>
roomInfo.FetchRomFileInRoomInfo((_, romFile) =>
{
if (!romFile.RomReady) //这个rom并没有下载,所以取消进入房间
{

View File

@ -4,6 +4,7 @@ using AxibugProtobuf;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
@ -13,41 +14,103 @@ namespace AxibugEmuOnline.Client
{
private HttpAPI.Resp_RomInfo webData;
private bool hasLocalFile;
//private UnityWebRequest downloadRequest;
private AxiHttpProxy.SendDownLoadProxy downloadRequest;
/// <summary> 依赖的Rom文件 </summary>
private List<RomFile> dependencies = new List<RomFile>();
public bool IsUserRom { get; private set; }
/// <summary> 指示该Rom是否是多文件Rom </summary>
public bool MultiFileRom
{
get
{
switch (Platform)
{
case RomPlatformType.Nes: return false;
case RomPlatformType.Cps1: return true;
default: throw new NotImplementedException($"未实现的平台{Platform}");
}
}
}
/// <summary> 指示该Rom文件的存放路径 </summary>
public string LocalFilePath =>
IsUserRom ?
$"{App.PersistentDataPath(Platform)}/UserRoms/{FileName}" :
$"{App.PersistentDataPath(Platform)}/RemoteRoms/{FileName}";
public string LocalFilePath => $"{App.PersistentDataPath(Platform)}/RemoteRoms/{FileName}";
/// <summary> 指示该Rom文件是否已下载完毕 </summary>
public bool RomReady => hasLocalFile;
///// <summary> 指示是否正在下载Rom文件 </summary>
//public bool IsDownloading => downloadRequest != null && downloadRequest.result == UnityWebRequest.Result.InProgress;
//public float Progress => IsDownloading ? downloadRequest.downloadProgress : 0;
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 => downloadRequest != null && !downloadRequest.downloadHandler.isDone;
public float Progress => IsDownloading ? downloadRequest.downloadHandler.DownLoadPr : 0;
public bool IsDownloading
{
get
{
var selfDownloading = downloadRequest != null && !downloadRequest.downloadHandler.isDone;
if (selfDownloading) return true;
foreach (var depRom in dependencies)
{
if (depRom.IsDownloading) return true;
}
return false;
}
}
public float Progress
{
get
{
if (!IsDownloading) return 0;
float total = 0f;
total += downloadRequest != null ? downloadRequest.downloadHandler.DownLoadPr : 0;
foreach (var depRom in dependencies)
{
total += depRom.Progress;
}
return total;
}
}
public RomPlatformType Platform => webData != null ? (RomPlatformType)webData.ptype : RomPlatformType.Invalid;
/// <summary> 指示该Rom信息是否已填充 </summary>
public bool InfoReady => webData != null;
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 => IsUserRom ? Path.GetFileNameWithoutExtension(FileName) : webData.romName;
public string Alias => webData.romName;
/// <summary> 描述 </summary>
public string Descript => IsUserRom ? string.Empty : webData.desc;
public string Descript => webData.desc;
/// <summary> 游戏类型 </summary>
public string GameTypeDes => IsUserRom ? string.Empty : webData.gType;
public string GameTypeDes => webData.gType;
/// <summary> 小图URL </summary>
public string ImageURL => IsUserRom ? string.Empty : webData.imgUrl;
public string ImageURL => webData.imgUrl;
/// <summary> 文件名 </summary>
public string FileName { get; private set; }
@ -81,25 +144,67 @@ namespace AxibugEmuOnline.Client
if (RomReady) return;
if (IsDownloading) return;
//检查依赖Rom的下载情况
App.StartCoroutine(DownloadRemoteRom((bytes) =>
{
if (bytes != null)
{
var directPath = Path.GetDirectoryName(LocalFilePath);
Directory.CreateDirectory(directPath);
File.WriteAllBytes(LocalFilePath, bytes);
hasLocalFile = true;
Eventer.Instance.PostEvent(EEvent.OnRomFileDownloaded, ID);
}
OnDownloadOver?.Invoke(this);
{
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));
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();
}
foreach (var item in unzipFiles)
{
var path = item.Key;
var data = item.Value;
File.WriteAllBytes(path, data);
}
}
else
{
var directPath = Path.GetDirectoryName(LocalFilePath);
Directory.CreateDirectory(directPath);
File.WriteAllBytes(LocalFilePath, bytes);
hasLocalFile = true;
Eventer.Instance.PostEvent(EEvent.OnRomFileDownloaded, ID);
}
OnDownloadOver?.Invoke(this);
}
public byte[] GetRomFileData()
{
if (!IsUserRom && webData == null) throw new Exception("Not Valid Rom");
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);
@ -146,50 +251,45 @@ namespace AxibugEmuOnline.Client
var request = downloadRequest;
downloadRequest = null;
if (!request.downloadHandler.bHadErr)
callback(request.downloadHandler.data);
else
callback(null);
//downloadRequest = UnityWebRequest.Get($"{App.httpAPI.WebHost}/{webData.url}");
//yield return downloadRequest.SendWebRequest();
//var request = downloadRequest;
//downloadRequest = null;
//if (request.result != UnityWebRequest.Result.Success)
//{
// callback(null);
//}
//else
//{
// callback(request.downloadHandler.data);
//}
}
public void SetWebData(HttpAPI.Resp_RomInfo resp_RomInfo)
{
webData = resp_RomInfo;
FileName = Path.GetFileName(webData.url);
FileName = MultiFileRom ? Path.GetFileNameWithoutExtension(webData.url) : Path.GetFileName(webData.url);
FileName = System.Net.WebUtility.UrlDecode(FileName);
if (File.Exists(LocalFilePath))
{
var fileBytes = File.ReadAllBytes(LocalFilePath);
var localHash = RomLib.CalcHash(fileBytes);
hasLocalFile = localHash == webData.hash;
if (!hasLocalFile)
File.Delete(LocalFilePath);
}
else
{
hasLocalFile = false;
if (MultiFileRom)
hasLocalFile = Directory.Exists(LocalFilePath);
else
hasLocalFile = File.Exists(LocalFilePath);
//收集依赖Rom
if (webData.parentRomIdsList != null)
{
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);
}));
}
}
OnInfoFilled?.Invoke();
App.StartCoroutine(WaitInfoReady());
}
private IEnumerator WaitInfoReady()
{
while (!InfoReady) yield return null;
OnInfoFilled?.Invoke();
}
}
}

View File

@ -1,4 +1,5 @@
using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf;
using AxiReplay;
using System;
using System.IO;
@ -20,7 +21,7 @@ namespace AxibugEmuOnline.Client
{
try
{
var romFile = App.nesRomLib.GetRomFile(fname);
var romFile = App.GetRomLib(RomPlatformType.Nes).GetRomFile(fname);
var bytes = romFile.GetRomFileData();
Debug.Log($"Open {romFile.Alias}");
return new MemoryStream(bytes);
@ -34,7 +35,7 @@ namespace AxibugEmuOnline.Client
public void GetRomPathInfo(string fname, out string fullPath, out string directPath)
{
var romFile = App.nesRomLib.GetRomFile(fname);
var romFile = App.GetRomLib(RomPlatformType.Nes).GetRomFile(fname);
UnityEngine.Debug.Assert(romFile != null);
fullPath = romFile.LocalFilePath;

View File

@ -70,7 +70,7 @@ namespace AxibugEmuOnline.Client
Supporter.Setup(m_coreSupporter);
Debuger.Setup(new CoreDebuger());
App.nesRomLib.AddRomFile(rom);
App.GetRomLib(RomPlatformType.Nes).AddRomFile(rom);
try
{

View File

@ -1,6 +1,7 @@
using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.UI;
using AxibugProtobuf;
using Coffee.UIExtensions;
using System;
using UnityEngine;
@ -35,7 +36,7 @@ namespace AxibugEmuOnline.Client
}
public int RomID { get { return m_romfile != null && m_romfile.InfoReady ? m_romfile.ID : -1; } }
private RomLib m_romlib => App.nesRomLib;
private RomLib m_romlib => App.GetRomLib(m_romfile.Platform);
public bool RomInfoReady => m_romfile != null && m_romfile.InfoReady;

View File

@ -17,16 +17,7 @@ namespace AxibugEmuOnline.Client
get
{
if (StarRom) return App.starRomLib;
else
{
switch (Platform)
{
case RomPlatformType.Nes:
return App.nesRomLib;
default:
throw new System.NotImplementedException($"未实现的平台 {Platform}");
}
}
else return App.GetRomLib(Platform);
}
}

View File

@ -95,7 +95,7 @@ namespace AxibugEmuOnline.Client
SetBaseInfo("--", $"<b>{hostNick}</b>的房间", $"{cur}/{max}");
SetIcon(null);
roomInfo.FetchRomFileInRoomInfo(roomInfo.GamePlatformType, (room, romFile) =>
roomInfo.FetchRomFileInRoomInfo((room, romFile) =>
{
if (room.RoomID != RoomID) return;

View File

@ -34,7 +34,7 @@ namespace AxibugEmuOnline.Client
}
private static Dictionary<int, RomFile> s_RomFileCahcesInRoomInfo = new Dictionary<int, RomFile>();
public static void FetchRomFileInRoomInfo(this Protobuf_Room_MiniInfo roomInfo, RomPlatformType platform, Action<Protobuf_Room_MiniInfo, RomFile> callback)
public static void FetchRomFileInRoomInfo(this Protobuf_Room_MiniInfo roomInfo, Action<Protobuf_Room_MiniInfo, RomFile> callback)
{
RomFile romFile;
@ -42,20 +42,16 @@ namespace AxibugEmuOnline.Client
{
callback.Invoke(roomInfo, romFile);
return;
}
switch (platform)
{
case RomPlatformType.Nes:
App.StartCoroutine(App.httpAPI.GetRomInfo(roomInfo.GameRomID, (romWebData) =>
{
RomFile _romFile = new RomFile(0, 0);
_romFile.SetWebData(romWebData);
s_RomFileCahcesInRoomInfo[roomInfo.GameRomID] = _romFile;
callback.Invoke(roomInfo, _romFile);
}));
break;
}
}
App.StartCoroutine(App.httpAPI.GetRomInfo(roomInfo.GameRomID, (romWebData) =>
{
RomFile _romFile = new RomFile(0, 0);
_romFile.SetWebData(romWebData);
s_RomFileCahcesInRoomInfo[roomInfo.GameRomID] = _romFile;
callback.Invoke(roomInfo, _romFile);
}));
}
}