forked from sin365/AxibugEmuOnline
支持Http Rom仓库下载
This commit is contained in:
parent
62377ab9d4
commit
360ea2f579
Binary file not shown.
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: cda51a5b513e24a4db500829511ef182
|
guid: 0f9e31e301641e94eb97c78b5c04d45b
|
||||||
PluginImporter:
|
PluginImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
Binary file not shown.
@ -36,6 +36,8 @@ namespace AxibugEmuOnline.Client.ClientCore
|
|||||||
user = new UserDataManager();
|
user = new UserDataManager();
|
||||||
emu = new AppEmu();
|
emu = new AppEmu();
|
||||||
netgame = new AppNetGame();
|
netgame = new AppNetGame();
|
||||||
|
romLib = new RomLib();
|
||||||
|
httpAPI = new HttpAPI();
|
||||||
|
|
||||||
var go = new GameObject("[AppAxibugEmuOnline]");
|
var go = new GameObject("[AppAxibugEmuOnline]");
|
||||||
GameObject.DontDestroyOnLoad(go);
|
GameObject.DontDestroyOnLoad(go);
|
||||||
|
@ -10,6 +10,7 @@ namespace AxibugEmuOnline.Client
|
|||||||
public class HttpAPI
|
public class HttpAPI
|
||||||
{
|
{
|
||||||
public string WebSite = "http://emu.axibug.com/api";
|
public string WebSite = "http://emu.axibug.com/api";
|
||||||
|
public string DownSite = "http://emu.axibug.com";
|
||||||
|
|
||||||
public void GetNesRomList(Action<Resp_GameList> callback, int page, int pageSize = 10)
|
public void GetNesRomList(Action<Resp_GameList> callback, int page, int pageSize = 10)
|
||||||
{
|
{
|
||||||
@ -18,7 +19,7 @@ namespace AxibugEmuOnline.Client
|
|||||||
|
|
||||||
private IEnumerator GetNesRomListFlow(int page, int pageSize, Action<Resp_GameList> callback)
|
private IEnumerator GetNesRomListFlow(int page, int pageSize, Action<Resp_GameList> callback)
|
||||||
{
|
{
|
||||||
UnityWebRequest request = new UnityWebRequest($"{WebSite}/NesRomList?Page={page}&PageSize={pageSize}");
|
UnityWebRequest request = UnityWebRequest.Get($"{WebSite}/NesRomList?Page={page}&PageSize={pageSize}");
|
||||||
yield return request.SendWebRequest();
|
yield return request.SendWebRequest();
|
||||||
|
|
||||||
if (request.result != UnityWebRequest.Result.Success)
|
if (request.result != UnityWebRequest.Result.Success)
|
||||||
@ -31,21 +32,48 @@ namespace AxibugEmuOnline.Client
|
|||||||
callback.Invoke(resp);
|
callback.Invoke(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Resp_GameList
|
enum GameType : byte
|
||||||
{
|
{
|
||||||
public int Page { get; set; }
|
NONE = 0,
|
||||||
public int MaxPage { get; set; }
|
ACT,
|
||||||
public int ResultAllCount { get; set; }
|
ARPG,
|
||||||
public List<Resp_RomInfo> GameList { get; set; }
|
AVG,
|
||||||
|
ETC,
|
||||||
|
FTG,
|
||||||
|
PUZ,
|
||||||
|
RAC,
|
||||||
|
RPG,
|
||||||
|
SLG,
|
||||||
|
SPG,
|
||||||
|
SRPG,
|
||||||
|
STG,
|
||||||
|
TAB,
|
||||||
|
/// <summary>
|
||||||
|
/// 合卡
|
||||||
|
/// </summary>
|
||||||
|
ALLINONE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Resp_GameList
|
||||||
|
{
|
||||||
|
public int page;
|
||||||
|
public int maxPage;
|
||||||
|
public int resultAllCount;
|
||||||
|
public List<Resp_RomInfo> gameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
public class Resp_RomInfo
|
public class Resp_RomInfo
|
||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int id;
|
||||||
public string Hash { get; set; }
|
public string romName;
|
||||||
public string RomName { get; set; }
|
public string gType;
|
||||||
public string Url { get; set; }
|
public string desc;
|
||||||
public string ImgUrl { get; set; }
|
public string url;
|
||||||
|
public string imgUrl;
|
||||||
|
public string hash;
|
||||||
|
public int stars;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
using System;
|
using AxibugEmuOnline.Client.ClientCore;
|
||||||
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Networking;
|
||||||
|
|
||||||
namespace AxibugEmuOnline.Client
|
namespace AxibugEmuOnline.Client
|
||||||
{
|
{
|
||||||
@ -8,34 +13,106 @@ namespace AxibugEmuOnline.Client
|
|||||||
{
|
{
|
||||||
private HttpAPI.Resp_RomInfo webData;
|
private HttpAPI.Resp_RomInfo webData;
|
||||||
private bool hasLocalFile;
|
private bool hasLocalFile;
|
||||||
private string romName;
|
private string fileName;
|
||||||
private EnumPlatform platform;
|
private EnumPlatform platform;
|
||||||
|
|
||||||
public string LocalFilePath => $"{Application.persistentDataPath}/RemoteRoms/{platform}/{romName}";
|
public string LocalFilePath => $"{Application.persistentDataPath}/RemoteRoms/{platform}/{fileName}";
|
||||||
|
public bool FileReady => hasLocalFile;
|
||||||
|
public int ID => webData != null ? webData.id : -1;
|
||||||
|
public bool IsDownloading { get; private set; }
|
||||||
|
public string Alias => webData.romName;
|
||||||
|
public string FileName => fileName;
|
||||||
|
|
||||||
|
public event Action OnDownloadOver;
|
||||||
|
|
||||||
public RomFile(EnumPlatform platform)
|
public RomFile(EnumPlatform platform)
|
||||||
{
|
{
|
||||||
this.platform = platform;
|
this.platform = platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetRomFileData(Action<byte[]> callback)
|
public void BeginDownload()
|
||||||
{
|
{
|
||||||
if (webData == null) { callback.Invoke(null); return; }
|
if (FileReady) return;
|
||||||
if (hasLocalFile)
|
if (IsDownloading) return;
|
||||||
|
|
||||||
|
IsDownloading = true;
|
||||||
|
AppAxibugEmuOnline.StartCoroutine(DownloadRemoteRom((bytes) =>
|
||||||
{
|
{
|
||||||
var path = LocalFilePath;
|
IsDownloading = false;
|
||||||
|
|
||||||
|
if (bytes != null)
|
||||||
|
{
|
||||||
|
var directPath = Path.GetDirectoryName(LocalFilePath);
|
||||||
|
Directory.CreateDirectory(directPath);
|
||||||
|
|
||||||
|
File.WriteAllBytes(LocalFilePath, bytes);
|
||||||
|
hasLocalFile = true;
|
||||||
|
}
|
||||||
|
OnDownloadOver?.Invoke();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetRomFileData()
|
||||||
|
{
|
||||||
|
if (webData == null) throw new Exception("Not Valid Rom");
|
||||||
|
if (!FileReady) 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 (zip.GetNextEntry() is ZipEntry entry)
|
||||||
|
{
|
||||||
|
if (!entry.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");
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator DownloadRemoteRom(Action<byte[]> callback)
|
||||||
|
{
|
||||||
|
UnityWebRequest uwr = UnityWebRequest.Get($"{AppAxibugEmuOnline.httpAPI.DownSite}/{webData.url}");
|
||||||
|
yield return uwr.SendWebRequest();
|
||||||
|
|
||||||
|
if (uwr.result != UnityWebRequest.Result.Success)
|
||||||
|
{
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
callback(uwr.downloadHandler.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetWebData(HttpAPI.Resp_RomInfo resp_RomInfo)
|
public void SetWebData(HttpAPI.Resp_RomInfo resp_RomInfo)
|
||||||
{
|
{
|
||||||
webData = resp_RomInfo;
|
webData = resp_RomInfo;
|
||||||
romName = Path.GetFileName(webData.Url);
|
fileName = Path.GetFileName(webData.url);
|
||||||
|
|
||||||
if (File.Exists(LocalFilePath))
|
if (File.Exists(LocalFilePath))
|
||||||
{
|
{
|
||||||
hasLocalFile = true;
|
var fileBytes = File.ReadAllBytes(LocalFilePath);
|
||||||
|
var localHash = RomLib.CalcHash(fileBytes);
|
||||||
|
|
||||||
|
hasLocalFile = localHash == webData.hash;
|
||||||
|
if (!hasLocalFile)
|
||||||
|
File.Delete(LocalFilePath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,29 +1,25 @@
|
|||||||
using AxibugEmuOnline.Client.ClientCore;
|
using AxibugEmuOnline.Client.ClientCore;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace AxibugEmuOnline.Client
|
namespace AxibugEmuOnline.Client
|
||||||
{
|
{
|
||||||
public class RomLib
|
public class RomLib
|
||||||
{
|
{
|
||||||
private List<RomFile> nesRomFiles = new List<RomFile>();
|
private Dictionary<int, RomFile> nesRomFileIdMapper = new Dictionary<int, RomFile>();
|
||||||
|
private Dictionary<string, RomFile> nesRomFileNameMapper = new Dictionary<string, RomFile>();
|
||||||
|
|
||||||
public void GetNesRomFile(int index, Action<RomFile> callback)
|
public RomFile GetNesRomFile(string romFileName)
|
||||||
{
|
{
|
||||||
if (nesRomFiles.Count <= index)
|
nesRomFileNameMapper.TryGetValue(romFileName, out RomFile romFile);
|
||||||
{
|
return romFile;
|
||||||
int pageSize = 10;
|
|
||||||
int page = index / pageSize;
|
|
||||||
int indexInPage = index % page;
|
|
||||||
|
|
||||||
//填充空的RomFile数据
|
|
||||||
var needFill = index - nesRomFiles.Count + 1;
|
|
||||||
needFill += pageSize - indexInPage - 1;
|
|
||||||
for (int i = 0; i < needFill; i++)
|
|
||||||
{
|
|
||||||
nesRomFiles.Add(new RomFile(EnumPlatform.NES));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void GetNesRomFile(int page, int pageSize, Action<List<RomFile>> callback)
|
||||||
|
{
|
||||||
AppAxibugEmuOnline.httpAPI.GetNesRomList((romList) =>
|
AppAxibugEmuOnline.httpAPI.GetNesRomList((romList) =>
|
||||||
{
|
{
|
||||||
if (romList == null)
|
if (romList == null)
|
||||||
@ -32,13 +28,39 @@ namespace AxibugEmuOnline.Client
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < romList.GameList.Count; i++)
|
List<RomFile> result = new List<RomFile>();
|
||||||
|
for (int i = 0; i < romList.gameList.Count; i++)
|
||||||
{
|
{
|
||||||
nesRomFiles[pageSize * (page - 1) + i].SetWebData(romList.GameList[i]);
|
var webData = romList.gameList[i];
|
||||||
|
|
||||||
|
nesRomFileIdMapper.TryGetValue(webData.id, out var targetRomFile);
|
||||||
|
if (targetRomFile == null)
|
||||||
|
{
|
||||||
|
targetRomFile = new RomFile(EnumPlatform.NES);
|
||||||
|
targetRomFile.SetWebData(webData);
|
||||||
|
nesRomFileIdMapper[webData.id] = targetRomFile;
|
||||||
|
|
||||||
|
nesRomFileNameMapper[targetRomFile.FileName] = targetRomFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.Add(targetRomFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(result);
|
||||||
}
|
}
|
||||||
}, page, pageSize);
|
}, page, pageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string CalcHash(byte[] data)
|
||||||
|
{
|
||||||
|
var hashBytes = MD5.Create().ComputeHash(data);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (byte b in hashBytes)
|
||||||
|
{
|
||||||
|
sb.Append(b.ToString("x2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,10 @@ namespace AxibugEmuOnline.Client
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var stream = File.Open($"{RomDirectoryPath}/{fname}", FileMode.Open);
|
var romFile = AppAxibugEmuOnline.romLib.GetNesRomFile(fname);
|
||||||
return stream;
|
var bytes = romFile.GetRomFileData();
|
||||||
|
Debug.Log($"Open {romFile.Alias}");
|
||||||
|
return new MemoryStream(bytes);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using AxibugEmuOnline.Client.ClientCore;
|
using AxibugEmuOnline.Client.ClientCore;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using VirtualNes.Core;
|
using VirtualNes.Core;
|
||||||
@ -15,22 +16,14 @@ namespace AxibugEmuOnline.Client
|
|||||||
public VideoProvider VideoProvider;
|
public VideoProvider VideoProvider;
|
||||||
public AudioProvider AudioProvider;
|
public AudioProvider AudioProvider;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
public string RomName;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
Application.targetFrameRate = 60;
|
Application.targetFrameRate = 60;
|
||||||
VideoProvider.NesEmu = this;
|
VideoProvider.NesEmu = this;
|
||||||
AudioProvider.NesEmu = this;
|
AudioProvider.NesEmu = this;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
StartGame(RomName);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartGame(string romName)
|
public void StartGame(RomFile rom)
|
||||||
{
|
{
|
||||||
StopGame();
|
StopGame();
|
||||||
|
|
||||||
@ -39,7 +32,7 @@ namespace AxibugEmuOnline.Client
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
NesCore = new NES(romName);
|
NesCore = new NES(rom.FileName);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -92,6 +85,38 @@ namespace AxibugEmuOnline.Client
|
|||||||
UnityEditor.EditorUtility.SetDirty(db);
|
UnityEditor.EditorUtility.SetDirty(db);
|
||||||
UnityEditor.AssetDatabase.SaveAssets();
|
UnityEditor.AssetDatabase.SaveAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ContextMenu("LoadRom")]
|
||||||
|
public void LoadRom()
|
||||||
|
{
|
||||||
|
AppAxibugEmuOnline.romLib.GetNesRomFile(0, 10, (romFiles) =>
|
||||||
|
{
|
||||||
|
if (romFiles == null) return;
|
||||||
|
|
||||||
|
var file = romFiles[2];
|
||||||
|
|
||||||
|
if (file.FileReady)
|
||||||
|
{
|
||||||
|
StartGame(file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file.BeginDownload();
|
||||||
|
Action action = null;
|
||||||
|
action = () =>
|
||||||
|
{
|
||||||
|
file.OnDownloadOver -= action;
|
||||||
|
if (!file.FileReady)
|
||||||
|
{
|
||||||
|
throw new Exception("Download Failed");
|
||||||
|
}
|
||||||
|
StartGame(file);
|
||||||
|
};
|
||||||
|
file.OnDownloadOver += action;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ using System;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using VirtualNes.Core;
|
|
||||||
|
|
||||||
namespace AxibugEmuOnline.Client
|
namespace AxibugEmuOnline.Client
|
||||||
{
|
{
|
||||||
@ -31,6 +30,7 @@ namespace AxibugEmuOnline.Client
|
|||||||
// 获取数组的指针
|
// 获取数组的指针
|
||||||
wrapTexBufferPointer = handle.AddrOfPinnedObject();
|
wrapTexBufferPointer = handle.AddrOfPinnedObject();
|
||||||
|
|
||||||
|
Image.texture = wrapTex;
|
||||||
Image.material.SetTexture("_MainTex", wrapTex);
|
Image.material.SetTexture("_MainTex", wrapTex);
|
||||||
|
|
||||||
TexBufferSize = wrapTexBuffer.Length * 4;
|
TexBufferSize = wrapTexBuffer.Length * 4;
|
||||||
|
@ -470,49 +470,6 @@ namespace VirtualNes.Core
|
|||||||
// Start
|
// Start
|
||||||
if (state.HasButton(no, EnumButtonType.START)) bit |= 1 << 3;
|
if (state.HasButton(no, EnumButtonType.START)) bit |= 1 << 3;
|
||||||
|
|
||||||
// A rapid setup
|
|
||||||
if ((bit & (1 << 8)) != 0)
|
|
||||||
{
|
|
||||||
int spd = Supporter.Config.controller.nRapid[no][0];
|
|
||||||
if (spd >= 3) spd = 3;
|
|
||||||
|
|
||||||
int[] tbl = rentbl[spd];
|
|
||||||
|
|
||||||
if (padcnt[no][0] >= renmask[spd])
|
|
||||||
padcnt[no][0] = 0;
|
|
||||||
|
|
||||||
if ((tbl[padcnt[no][0]]) != 0)
|
|
||||||
bit |= (1 << 0);
|
|
||||||
else
|
|
||||||
bit = (byte)(bit & ~(1 << 0));
|
|
||||||
|
|
||||||
padcnt[no][0]++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
padcnt[no][0] = 0;
|
|
||||||
}
|
|
||||||
// B rapid setup
|
|
||||||
if ((bit & (1 << 9)) != 0)
|
|
||||||
{
|
|
||||||
int spd = Supporter.Config.controller.nRapid[no][1];
|
|
||||||
if (spd >= 3) spd = 3;
|
|
||||||
int[] tbl = rentbl[spd];
|
|
||||||
|
|
||||||
if (padcnt[no][1] >= renmask[spd])
|
|
||||||
padcnt[no][1] = 0;
|
|
||||||
|
|
||||||
if ((tbl[padcnt[no][1]]) != 0)
|
|
||||||
bit |= (1 << 1);
|
|
||||||
else
|
|
||||||
bit = (byte)(bit & ~(1 << 1));
|
|
||||||
|
|
||||||
padcnt[no][1]++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
padcnt[no][1] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (byte)(bit & 0xFF);
|
return (byte)(bit & 0xFF);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user