master #108

Merged
sin365 merged 3 commits from Alienjack/AxibugEmuOnline:master into master 2025-08-22 10:18:40 +08:00
76 changed files with 7904 additions and 7710 deletions
Showing only changes of commit b4ce028b44 - Show all commits

View File

@ -90,9 +90,14 @@ namespace AxibugEmuOnline.Client.ClientCore
public static void Init(bool isTest = false, bool isUseGUIButton = false, string testSrvIP = "", bool bUseLocalWebApi = false, string mLocalWebApi = "") public static void Init(bool isTest = false, bool isUseGUIButton = false, string testSrvIP = "", bool bUseLocalWebApi = false, string mLocalWebApi = "")
{ {
log = new LogManager(OnLogOut); log = new LogManager(OnLogOut);
//其他平台必要的初始化 //其他平台必要的初始化
if (UnityEngine.Application.platform == RuntimePlatform.PSP2) PSP2Init(); #if UNITY_PSP2
PSP2Init();
#endif
#if UNITY_SWITCH
SwitchInit();
#endif
input = new InputDevicesManager(); input = new InputDevicesManager();
FileDownloader = new FileDownloader(); FileDownloader = new FileDownloader();
@ -153,11 +158,18 @@ namespace AxibugEmuOnline.Client.ClientCore
sonyVitaCommonDialog = new GameObject().AddComponent<SonyVitaCommonDialog>(); sonyVitaCommonDialog = new GameObject().AddComponent<SonyVitaCommonDialog>();
#endif #endif
#if UNITY_SWITCH
//创建创建Switch
switchCommon = new GameObject().AddComponent<SwitchCommon>();
#endif
}
private static void SwitchInit()
{
#if UNITY_SWITCH
AxiNS.instance.Init();
if (!AxiIO.Directory.Exists(App.PersistentDataRootPath()))
AxiIO.Directory.CreateDirectory(App.PersistentDataRootPath());
switchCommon = new GameObject().AddComponent<SwitchCommon>();
switchCommon.gameObject.name = "[SwitchCommon]";
GameObject.DontDestroyOnLoad(switchCommon);
#endif
} }

View File

@ -1,79 +1,79 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO.Compression; using System.IO.Compression;
using System.Net; using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Authentication; using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
public static class PSVThread public static class PSVThread
{ {
#if UNITY_PSP2 #if UNITY_PSP2
static AutoResetEvent autoEvent = new AutoResetEvent(false); static AutoResetEvent autoEvent = new AutoResetEvent(false);
static Queue<Action> qActs = new Queue<Action>(); static Queue<Action> qActs = new Queue<Action>();
static Queue<Action> qWork = new Queue<Action>(); static Queue<Action> qWork = new Queue<Action>();
#endif #endif
public static void DoTask(Action act) public static void DoTask(Action act)
{ {
#if UNITY_PSP2 #if UNITY_PSP2
AddSingleTask(act); AddSingleTask(act);
#else #else
ThreadPool.QueueUserWorkItem(new WaitCallback((state) => act.Invoke())); ThreadPool.QueueUserWorkItem(new WaitCallback((state) => act.Invoke()));
#endif #endif
} }
#if UNITY_PSP2 #if UNITY_PSP2
static Thread psvThread = new Thread(Loop); static Thread psvThread = new Thread(Loop);
static bool bSingleInit = false; static bool bSingleInit = false;
static void SingleInit() static void SingleInit()
{ {
if (bSingleInit) return; if (bSingleInit) return;
psvThread.Start(); psvThread.Start();
bSingleInit = true; bSingleInit = true;
} }
static void AddSingleTask(Action act) static void AddSingleTask(Action act)
{ {
SingleInit(); SingleInit();
lock (qActs) lock (qActs)
{ {
qActs.Enqueue(act); qActs.Enqueue(act);
} }
autoEvent.Set(); autoEvent.Set();
} }
static void Loop() static void Loop()
{ {
while (autoEvent.WaitOne()) while (autoEvent.WaitOne())
{ {
lock (qActs) lock (qActs)
{ {
while (qActs.Count > 0) { qWork.Enqueue(qActs.Dequeue()); } while (qActs.Count > 0) { qWork.Enqueue(qActs.Dequeue()); }
} }
while (qWork.Count > 0) while (qWork.Count > 0)
{ {
Action act = qWork.Dequeue(); Action act = qWork.Dequeue();
try try
{ {
act.Invoke(); act.Invoke();
} }
catch (Exception ex) catch (Exception ex)
{ {
UnityEngine.Debug.Log(ex.ToString()); UnityEngine.Debug.Log(ex.ToString());
} }
} }
} }
} }
#endif #endif
} }
public static class AxiHttp public static class AxiHttp
{ {
public const char T = '\n'; public const char T = '\n';
public const string CT = "\r\n"; public const string CT = "\r\n";
@ -1016,10 +1016,10 @@ public static class AxiHttp
string strRelativePathRet; string strRelativePathRet;
string strIPRet; string strIPRet;
/*string strProtocol = strURI.Substring(0, 7); /*string strProtocol = strURI.Substring(0, 7);
if (strProtocol != "http://" if (strProtocol != "http://"
|| ||
strProtocol != "https://") strProtocol != "https://")
return false;*/ return false;*/
if (!strURI.ToLower().StartsWith("http://") || strURI.ToLower().StartsWith("https://")) if (!strURI.ToLower().StartsWith("http://") || strURI.ToLower().StartsWith("https://"))
@ -1109,11 +1109,11 @@ public static class AxiHttp
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
} }
/// <summary> /// <summary>
/// 将16进制转换成10进制 /// 将16进制转换成10进制
/// </summary> /// </summary>
/// <param name="str">16进制字符串</param> /// <param name="str">16进制字符串</param>
/// <returns></returns> /// <returns></returns>
public static int convertToIntBy16(String str) public static int convertToIntBy16(String str)
{ {
try try
@ -1145,11 +1145,11 @@ public static class AxiHttp
} }
/// <summary> /// <summary>
/// 将字符串转换成数字错误返回0 /// 将字符串转换成数字错误返回0
/// </summary> /// </summary>
/// <param name="strs">字符串</param> /// <param name="strs">字符串</param>
/// <returns></returns> /// <returns></returns>
public static int convertToInt(String str) public static int convertToInt(String str)
{ {
@ -1231,6 +1231,6 @@ public static class AxiHttp
TimeoutObject.Set(); TimeoutObject.Set();
} }
} }
} }
} }

View File

@ -1,2 +1,11 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 5a498f74133ebfa4fa238a33a1c4c0c3 guid: 5a498f74133ebfa4fa238a33a1c4c0c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,7 +1,7 @@
using UnityEngine; using UnityEngine;
using static AxiHttp; using static AxiHttp;
public static class AxiHttpProxy public static class AxiHttpProxy
{ {
public static SendWebRequestProxy Get(string url) public static SendWebRequestProxy Get(string url)
{ {
@ -46,7 +46,7 @@ public static class AxiHttpProxy
public static void ShowAxiHttpDebugInfo(AxiRespInfo resp) public static void ShowAxiHttpDebugInfo(AxiRespInfo resp)
{ {
#if UNITY_EDITOR #if UNITY_EDITOR
Debug.Log($""); Debug.Log($"");
Debug.Log($"==== request ===="); Debug.Log($"==== request ====");
Debug.Log($"url =>{resp.url}"); Debug.Log($"url =>{resp.url}");
@ -75,22 +75,22 @@ public static class AxiHttpProxy
{ {
Debug.LogError($"code->{resp.code} err->{resp.ErrInfo} url->{resp.url}"); Debug.LogError($"code->{resp.code} err->{resp.ErrInfo} url->{resp.url}");
} }
#else #else
Debug.Log($"==== request url => { resp.url}"); Debug.Log($"==== request url => { resp.url}");
Debug.Log($"code =>{resp.code}"); Debug.Log($"code =>{resp.code}");
Debug.Log($"respInfo.bTimeOut =>{resp.bTimeOut}"); Debug.Log($"respInfo.bTimeOut =>{resp.bTimeOut}");
Debug.Log($"==== response ===="); Debug.Log($"==== response ====");
if (resp.downloadMode == AxiDownLoadMode.NotDownLoad) if (resp.downloadMode == AxiDownLoadMode.NotDownLoad)
{ {
Debug.Log($"body_text =>{resp.body}"); Debug.Log($"body_text =>{resp.body}");
Debug.Log($"body_text.Length =>{resp.body.Length}"); Debug.Log($"body_text.Length =>{resp.body.Length}");
} }
else else
{ {
Debug.Log($"==== download ===="); Debug.Log($"==== download ====");
Debug.Log($"respInfo.loadedLenght =>{resp.loadedLenght}"); Debug.Log($"respInfo.loadedLenght =>{resp.loadedLenght}");
} }
#endif #endif
//if (resp.downloadMode == AxiDownLoadMode.DownLoadBytes) //if (resp.downloadMode == AxiDownLoadMode.DownLoadBytes)
//{ //{
@ -118,6 +118,6 @@ public static class AxiHttpProxy
// Debug.Log($"DownLoad Err {ex.ToString()}"); // Debug.Log($"DownLoad Err {ex.ToString()}");
// } // }
//} //}
} }
} }

View File

@ -1,2 +1,11 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: ec8e2e405992b234eb08896da0f85317 guid: ec8e2e405992b234eb08896da0f85317
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,51 @@
using System;
using System.Collections;
using UnityEngine;
public class AxiHttpTest : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.T))
{
//for (int i = 0; i < 1000; i++)
StartCoroutine(DownloadFromURL("http://emu.axibug.com/UserSav/12/Nes/190/1/1.sav", "D:/1.bin", null));
}
}
IEnumerator DownloadFromURL(string url, string path, Action<byte[]> callback)
{
for (int i = 0; i < 1000; i++)
{
AxiHttpProxy.SendDownLoadProxy request = AxiHttpProxy.GetDownLoad(url);
while (!request.downloadHandler.isDone)
{
Debug.Log($"下载进度:{request.downloadHandler.DownLoadPr} ->{request.downloadHandler.loadedLenght}/{request.downloadHandler.NeedloadedLenght}");
yield return null;
}
AxiHttpProxy.ShowAxiHttpDebugInfo(request.downloadHandler);
Debug.Log($"下载进度完毕:data.Length=>" + request.downloadHandler.data.Length);
}
//if (!request.downloadHandler.bHadErr)
//{
// AxiIO.Directory.CreateDirectory(path);
// AxiIO.File.WriteAllBytes($"{path}/{url.GetHashCode()}", request.downloadHandler.data, false);
// callback?.Invoke(request.downloadHandler.data);
//}
//else
//{
// callback?.Invoke(null);
//}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 873427ab0a955e64fa2444505ef0775c

View File

@ -1,9 +1,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxiInputSP.UGUI namespace AxiInputSP.UGUI
{ {
public class AxiScreenGamepad : MonoBehaviour public class AxiScreenGamepad : MonoBehaviour
{ {
public delegate void OnAxiScreenGamepadActiveHandle(AxiScreenGamepad sender); public delegate void OnAxiScreenGamepadActiveHandle(AxiScreenGamepad sender);
public delegate void OnAxiScreenGamepadDisactiveHandle(AxiScreenGamepad sender); public delegate void OnAxiScreenGamepadDisactiveHandle(AxiScreenGamepad sender);
@ -58,5 +58,5 @@ namespace AxiInputSP.UGUI
{ {
OnGamepadDisactive?.Invoke(this); OnGamepadDisactive?.Invoke(this);
} }
} }
} }

View File

@ -24,7 +24,7 @@ public class DebuggerByGUI : MonoBehaviour
private Vector2 _scrollLogView = Vector2.zero; private Vector2 _scrollLogView = Vector2.zero;
private Vector2 _scrollCurrentLogView = Vector2.zero; private Vector2 _scrollCurrentLogView = Vector2.zero;
private Vector2 _scrollSystemView = Vector2.zero; private Vector2 _scrollSystemView = Vector2.zero;
private bool _expansion = false; private bool _expansion = false;
private Rect _windowRect = new Rect(0, 0, 100, 60); private Rect _windowRect = new Rect(0, 0, 100, 60);
private int _fps = 0; private int _fps = 0;
@ -32,9 +32,26 @@ public class DebuggerByGUI : MonoBehaviour
private int _frameNumber = 0; private int _frameNumber = 0;
private float _lastShowFPSTime = 0f; private float _lastShowFPSTime = 0f;
private void Start() public bool OpenHubOnStart = false;
public bool AutoShowLastLogLine = false;
public bool OnlyShowErrOnStart = false;
private void Start()
{ {
DontDestroyOnLoad(this.gameObject); if (OpenHubOnStart)
{
_expansion = true;
_windowRect.width = 1000;
_windowRect.height = 600;
}
if (OnlyShowErrOnStart)
{
_showInfoLog = false;
_showWarningLog = false;
}
DontDestroyOnLoad(this.gameObject);
if (AllowDebugging) if (AllowDebugging)
{ {
Application.logMessageReceived += LogHandler; Application.logMessageReceived += LogHandler;
@ -237,16 +254,22 @@ public class DebuggerByGUI : MonoBehaviour
GUILayout.Label(_logInformations[i].message); GUILayout.Label(_logInformations[i].message);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
GUI.contentColor = Color.white; GUI.contentColor = Color.white;
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
} }
GUILayout.EndScrollView(); GUILayout.EndScrollView();
_scrollCurrentLogView = GUILayout.BeginScrollView(_scrollCurrentLogView, "Box", GUILayout.Height(100)); _scrollCurrentLogView = GUILayout.BeginScrollView(_scrollCurrentLogView, "Box", GUILayout.Height(100));
if (_currentLogIndex != -1)
if (AutoShowLastLogLine)
{
_scrollLogView.y = Mathf.Lerp(_scrollLogView.y, float.MaxValue, 0.1f);
}
if (_currentLogIndex != -1)
{ {
GUILayout.Label(_logInformations[_currentLogIndex].message + "\r\n\r\n" + _logInformations[_currentLogIndex].stackTrace); GUILayout.Label(_logInformations[_currentLogIndex].message + "\r\n\r\n" + _logInformations[_currentLogIndex].stackTrace);
} }
GUILayout.EndScrollView(); GUILayout.EndScrollView();
} }
#endregion #endregion

View File

@ -1,69 +1,69 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf; using AxibugProtobuf;
using AxiReplay; using AxiReplay;
using System; using System;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public abstract class EmuCore : MonoBehaviour public abstract class EmuCore : MonoBehaviour
{ {
/// <summary> 获得模拟器核心中的状态快照对象 </summary> /// <summary> 获得模拟器核心中的状态快照对象 </summary>
public abstract object GetState(); public abstract object GetState();
/// <summary> 获得模拟器核心中的状态快照字节数据 </summary> /// <summary> 获得模拟器核心中的状态快照字节数据 </summary>
public abstract byte[] GetStateBytes(); public abstract byte[] GetStateBytes();
/// <summary> 加载状态快照 </summary> /// <summary> 加载状态快照 </summary>
/// <param name="state">该对象应该来自核心的<see cref="GetState"/>方法的返回值,或是从<see cref="GetStateBytes"/>返回的byte数组构建</param> /// <param name="state">该对象应该来自核心的<see cref="GetState"/>方法的返回值,或是从<see cref="GetStateBytes"/>返回的byte数组构建</param>
public abstract void LoadState(object state); public abstract void LoadState(object state);
/// <summary> 加载状态快照 </summary> /// <summary> 加载状态快照 </summary>
/// <param name="data">该对象应该来自核心的<see cref="GetStateBytes"/>返回的byte数组</param> /// <param name="data">该对象应该来自核心的<see cref="GetStateBytes"/>返回的byte数组</param>
public abstract void LoadStateFromBytes(byte[] data); public abstract void LoadStateFromBytes(byte[] data);
/// <summary> 暂停核心推帧 </summary> /// <summary> 暂停核心推帧 </summary>
public abstract void Pause(); public abstract void Pause();
/// <summary> 恢复核心推帧(从Pause状态恢复) </summary> /// <summary> 恢复核心推帧(从Pause状态恢复) </summary>
public abstract void Resume(); public abstract void Resume();
/// <summary> 启动模拟器逻辑 </summary> /// <summary> 启动模拟器逻辑 </summary>
public abstract MsgBool StartGame(RomFile romFile); public abstract MsgBool StartGame(RomFile romFile);
/// <summary> 释放模拟器核心 </summary> /// <summary> 释放模拟器核心 </summary>
public abstract void Dispose(); public abstract void Dispose();
/// <summary> 重置核心,通常由模拟器核心提供的功能 </summary> /// <summary> 重置核心,通常由模拟器核心提供的功能 </summary>
public abstract void DoReset(); public abstract void DoReset();
/// <summary> 获得模拟器核心的控制器设置器 </summary> /// <summary> 获得模拟器核心的控制器设置器 </summary>
/// <returns></returns> /// <returns></returns>
public abstract IControllerSetuper GetControllerSetuper(); public abstract IControllerSetuper GetControllerSetuper();
/// <summary> 核心所属平台 </summary> /// <summary> 核心所属平台 </summary>
public abstract RomPlatformType Platform { get; } public abstract RomPlatformType Platform { get; }
/// <summary> 获取当前模拟器帧序号,在加载快照和Reset后,应当重置为0 </summary> /// <summary> 获取当前模拟器帧序号,在加载快照和Reset后,应当重置为0 </summary>
public abstract uint Frame { get; } public abstract uint Frame { get; }
public abstract void PushEmulatorFrame(); public abstract void PushEmulatorFrame();
/// <summary> 模拟器核心推帧结束 </summary> /// <summary> 模拟器核心推帧结束 </summary>
protected abstract void AfterPushFrame(); protected abstract void AfterPushFrame();
public abstract void GetAudioParams(out int frequency, out int channels); public abstract void GetAudioParams(out int frequency, out int channels);
public abstract Texture OutputPixel { get; } public abstract Texture OutputPixel { get; }
public abstract RawImage DrawCanvas { get; } public abstract RawImage DrawCanvas { get; }
/// <summary> 指示该游戏实例是否处于联机模式 </summary> /// <summary> 指示该游戏实例是否处于联机模式 </summary>
public bool IsNetPlay public bool IsNetPlay
{ {
get get
{ {
if (!App.user.IsLoggedIn) return false; if (!App.user.IsLoggedIn) return false;
if (App.roomMgr.mineRoomMiniInfo == null) return false; if (App.roomMgr.mineRoomMiniInfo == null) return false;
if (App.roomMgr.RoomState <= RoomGameState.OnlyHost) return false; if (App.roomMgr.RoomState <= RoomGameState.OnlyHost) return false;
return true; return true;
} }
} }
} }
/// <typeparam name="INPUTDATA">输入数据类型</typeparam> /// <typeparam name="INPUTDATA">输入数据类型</typeparam>
public abstract class EmuCore<INPUTDATA> : EmuCore public abstract class EmuCore<INPUTDATA> : EmuCore
{ {
protected virtual bool EnableRollbackNetCode => false; protected virtual bool EnableRollbackNetCode => false;
public sealed override void PushEmulatorFrame() public sealed override void PushEmulatorFrame()
{ {
if (!TryPushEmulatorFrame()) return; if (!TryPushEmulatorFrame()) return;
@ -115,28 +115,28 @@ namespace AxibugEmuOnline.Client
bool result = false; bool result = false;
inputData = default(INPUTDATA); inputData = default(INPUTDATA);
if (IsNetPlay) if (IsNetPlay)
{ {
if (App.roomMgr.netReplay.TryGetNextFrame((int)Frame, EnableRollbackNetCode ? true : false, out m_replayData, out m_frameDiff, out m_inputDiff)) if (App.roomMgr.netReplay.TryGetNextFrame((int)Frame, EnableRollbackNetCode ? true : false, out m_replayData, out m_frameDiff, out m_inputDiff))
{ {
if (m_inputDiff) if (m_inputDiff)
{ {
App.log.Debug($"{DateTime.Now.ToString("hh:mm:ss.fff")} TryGetNextFrame remoteFrame->{App.roomMgr.netReplay.mRemoteFrameIdx} diff->{m_frameDiff} " + App.log.Debug($"{DateTime.Now.ToString("hh:mm:ss.fff")} TryGetNextFrame remoteFrame->{App.roomMgr.netReplay.mRemoteFrameIdx} diff->{m_frameDiff} " +
$"frame=>{m_replayData.FrameStartID} InPut=>{m_replayData.InPut}"); $"frame=>{m_replayData.FrameStartID} InPut=>{m_replayData.InPut}");
} }
inputData = ConvertInputDataFromNet(m_replayData); inputData = ConvertInputDataFromNet(m_replayData);
result = true; result = true;
} }
else else
{ {
result = false; result = false;
} }
} }
else//单机模式 else//单机模式
{ {
inputData = GetLocalInput(); inputData = GetLocalInput();
result = true; result = true;
} }
return result; return result;
@ -147,5 +147,5 @@ namespace AxibugEmuOnline.Client
protected abstract ulong InputDataToNet(INPUTDATA inputData); protected abstract ulong InputDataToNet(INPUTDATA inputData);
/// <summary> 模拟器核心推帧 </summary> /// <summary> 模拟器核心推帧 </summary>
protected abstract bool OnPushEmulatorFrame(INPUTDATA InputData); protected abstract bool OnPushEmulatorFrame(INPUTDATA InputData);
} }
} }

View File

@ -1,161 +1,161 @@
using AxibugEmuOnline.Client; using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf; using AxibugProtobuf;
using AxiReplay; using AxiReplay;
using MAME.Core; using MAME.Core;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
public class UMAME : EmuCore<ulong> public class UMAME : EmuCore<ulong>
{ {
public static UMAME instance { get; private set; } public static UMAME instance { get; private set; }
public MAMEEmu emu { get; private set; } public MAMEEmu emu { get; private set; }
UniLog mUniLog; UniLog mUniLog;
UniMouse mUniMouse; UniMouse mUniMouse;
[HideInInspector] [HideInInspector]
public UniVideoPlayer mUniVideoPlayer; public UniVideoPlayer mUniVideoPlayer;
UniSoundPlayer mUniSoundPlayer; UniSoundPlayer mUniSoundPlayer;
UniKeyboard mUniKeyboard; UniKeyboard mUniKeyboard;
UniResources mUniResources; UniResources mUniResources;
UniIO mUniIO; UniIO mUniIO;
public Text mFPS; public Text mFPS;
private Canvas mCanvas; private Canvas mCanvas;
public List<RomInfo> HadGameList = new List<RomInfo>(); public List<RomInfo> HadGameList = new List<RomInfo>();
string mChangeRomName = string.Empty; string mChangeRomName = string.Empty;
public UniTimeSpan mTimeSpan; public UniTimeSpan mTimeSpan;
public bool bQuickTestRom = false; public bool bQuickTestRom = false;
public string mQuickTestRom = string.Empty; public string mQuickTestRom = string.Empty;
public ReplayWriter mReplayWriter; public ReplayWriter mReplayWriter;
public ReplayReader mReplayReader; public ReplayReader mReplayReader;
public long currEmuFrame => emu.currEmuFrame; public long currEmuFrame => emu.currEmuFrame;
public static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); public static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
public static bool bInGame { get; private set; } public static bool bInGame { get; private set; }
public static bool bLogicUpdatePause { get; private set; } public static bool bLogicUpdatePause { get; private set; }
public string EmuDataPath { get { return App.PersistentDataPath(Platform); } } public string EmuDataPath { get { return App.PersistentDataPath(Platform); } }
public string RomPath => EmuDataPath + "/RemoteRoms/"; public string RomPath => EmuDataPath + "/RemoteRoms/";
public string SavePath => EmuDataPath + "/sav/"; public string SavePath => EmuDataPath + "/sav/";
public override RomPlatformType Platform { get { return mPlatform; } } public override RomPlatformType Platform { get { return mPlatform; } }
RomPlatformType mPlatform = RomPlatformType.Cps1; RomPlatformType mPlatform = RomPlatformType.Cps1;
public override uint Frame => (uint)emu.currEmuFrame; public override uint Frame => (uint)emu.currEmuFrame;
void Awake() void Awake()
{ {
instance = this; instance = this;
mFPS = GameObject.Find("FPS").GetComponent<Text>(); mFPS = GameObject.Find("FPS").GetComponent<Text>();
mCanvas = GameObject.Find("Canvas").GetComponent<Canvas>(); mCanvas = GameObject.Find("Canvas").GetComponent<Canvas>();
mCanvas.worldCamera = Camera.main; mCanvas.worldCamera = Camera.main;
emu = new MAMEEmu(); emu = new MAMEEmu();
mUniLog = new UniLog(); mUniLog = new UniLog();
mUniMouse = this.gameObject.AddComponent<UniMouse>(); mUniMouse = this.gameObject.AddComponent<UniMouse>();
mUniVideoPlayer = this.gameObject.AddComponent<UniVideoPlayer>(); mUniVideoPlayer = this.gameObject.AddComponent<UniVideoPlayer>();
mUniSoundPlayer = GameObject.Find("Audio").transform.GetComponent<UniSoundPlayer>(); mUniSoundPlayer = GameObject.Find("Audio").transform.GetComponent<UniSoundPlayer>();
mUniKeyboard = this.gameObject.AddComponent<UniKeyboard>(); mUniKeyboard = this.gameObject.AddComponent<UniKeyboard>();
mUniResources = new UniResources(); mUniResources = new UniResources();
mUniIO = new UniIO(); mUniIO = new UniIO();
mChangeRomName = string.Empty; mChangeRomName = string.Empty;
mTimeSpan = new UniTimeSpan(); mTimeSpan = new UniTimeSpan();
emu.Init(RomPath, mUniLog, mUniResources, mUniVideoPlayer, mUniSoundPlayer, mUniKeyboard, mUniMouse, mTimeSpan, mUniIO); emu.Init(RomPath, mUniLog, mUniResources, mUniVideoPlayer, mUniSoundPlayer, mUniKeyboard, mUniMouse, mTimeSpan, mUniIO);
} }
void OnEnable() void OnEnable()
{ {
} }
void OnDisable() void OnDisable()
{ {
StopGame(); StopGame();
} }
#region #region
public override object GetState() public override object GetState()
{ {
return SaveState(); return SaveState();
} }
public override byte[] GetStateBytes() public override byte[] GetStateBytes()
{ {
return SaveState(); return SaveState();
} }
public override void LoadState(object state) public override void LoadState(object state)
{ {
LoadState((byte[])state); LoadState((byte[])state);
} }
public override void LoadStateFromBytes(byte[] data) public override void LoadStateFromBytes(byte[] data)
{ {
LoadState(data); LoadState(data);
} }
public override void Pause() public override void Pause()
{ {
bLogicUpdatePause = false; bLogicUpdatePause = false;
} }
public override void Resume() public override void Resume()
{ {
bLogicUpdatePause = true; bLogicUpdatePause = true;
} }
public override MsgBool StartGame(RomFile romFile) public override MsgBool StartGame(RomFile romFile)
{ {
mPlatform = romFile.Platform; mPlatform = romFile.Platform;
mTimeSpan.InitStandTime(); mTimeSpan.InitStandTime();
if (LoadGame(romFile.FileName)) if (LoadGame(romFile.FileName))
return true; return true;
else else
return "Rom加载失败"; return "Rom加载失败";
} }
public override void Dispose() public override void Dispose()
{ {
StopGame(); StopGame();
} }
public override void DoReset() public override void DoReset()
{ {
StopGame(); StopGame();
LoadGame(mChangeRomName); LoadGame(mChangeRomName);
} }
public override IControllerSetuper GetControllerSetuper() public override IControllerSetuper GetControllerSetuper()
{ {
return mUniKeyboard.ControllerMapper; return mUniKeyboard.ControllerMapper;
} }
public override void GetAudioParams(out int frequency, out int channels) public override void GetAudioParams(out int frequency, out int channels)
{ {
mUniSoundPlayer.GetAudioParams(out frequency, out channels); mUniSoundPlayer.GetAudioParams(out frequency, out channels);
} }
#endregion #endregion
bool LoadGame(string loadRom) bool LoadGame(string loadRom)
{ {
emu.ResetRomRoot(RomPath); emu.ResetRomRoot(RomPath);
//Application.targetFrameRate = 60; //Application.targetFrameRate = 60;
mReplayWriter = new ReplayWriter(mChangeRomName, "fuck", ReplayData.ReplayFormat.FM32IP64, Encoding.UTF8); mReplayWriter = new ReplayWriter(mChangeRomName, "fuck", ReplayData.ReplayFormat.FM32IP64, Encoding.UTF8);
mChangeRomName = loadRom; mChangeRomName = loadRom;
StopGame(); StopGame();
//读取ROM //读取ROM
emu.LoadRom(mChangeRomName); emu.LoadRom(mChangeRomName);
//读取成功 //读取成功
if (emu.bRom) if (emu.bRom)
{ {
//读取ROM之后获得宽高初始化画面 //读取ROM之后获得宽高初始化画面
int _width; int _height; IntPtr _framePtr; int _width; int _height; IntPtr _framePtr;
emu.GetGameScreenSize(out _width, out _height, out _framePtr); emu.GetGameScreenSize(out _width, out _height, out _framePtr);
App.log.Debug($"_width->{_width}, _height->{_height}, _framePtr->{_framePtr}"); App.log.Debug($"_width->{_width}, _height->{_height}, _framePtr->{_framePtr}");
mUniVideoPlayer.Initialize(_width, _height, _framePtr); mUniVideoPlayer.Initialize(_width, _height, _framePtr);
//初始化音频 //初始化音频
mUniSoundPlayer.Initialize(); mUniSoundPlayer.Initialize();
//开始游戏 //开始游戏
emu.StartGame(); emu.StartGame();
bInGame = true; bInGame = true;
bLogicUpdatePause = true; bLogicUpdatePause = true;
return true; return true;
} }
else else
{ {
App.log.Debug($"ROM加载失败"); App.log.Debug($"ROM加载失败");
return false; return false;
} }
} }
protected override bool OnPushEmulatorFrame(ulong InputData) protected override bool OnPushEmulatorFrame(ulong InputData)
{ {
if (!bInGame) return false; if (!bInGame) return false;
if (!bLogicUpdatePause) return false; if (!bLogicUpdatePause) return false;
mUniKeyboard.SyncInput(InputData); mUniKeyboard.SyncInput(InputData);
@ -181,53 +181,53 @@ public class UMAME : EmuCore<ulong>
protected override void AfterPushFrame() protected override void AfterPushFrame()
{ {
mFPS.text = ($"fpsv {mUniVideoPlayer.videoFPS.ToString("F2")} fpsa {mUniSoundPlayer.audioFPS.ToString("F2")} ,Idx:{App.roomMgr.netReplay?.mCurrClientFrameIdx},RIdx:{App.roomMgr.netReplay?.mRemoteFrameIdx},RForward:{App.roomMgr.netReplay?.mRemoteForwardCount} ,RD:{App.roomMgr.netReplay?.mRemoteForwardCount} ,D:{App.roomMgr.netReplay?.mDiffFrameCount} ,Q:{App.roomMgr.netReplay?.mNetReplayQueue.Count}"); mFPS.text = ($"fpsv {mUniVideoPlayer.videoFPS.ToString("F2")} fpsa {mUniSoundPlayer.audioFPS.ToString("F2")} ,Idx:{App.roomMgr.netReplay?.mCurrClientFrameIdx},RIdx:{App.roomMgr.netReplay?.mRemoteFrameIdx},RForward:{App.roomMgr.netReplay?.mRemoteForwardCount} ,RD:{App.roomMgr.netReplay?.mRemoteForwardCount} ,D:{App.roomMgr.netReplay?.mDiffFrameCount} ,Q:{App.roomMgr.netReplay?.mNetReplayQueue.Count}");
} }
public void SaveReplay() public void SaveReplay()
{ {
string Path = SavePath + Machine.sName + ".rp"; string Path = SavePath + Machine.sName + ".rp";
string dbgPath = SavePath + Machine.sName + ".rpwrite"; string dbgPath = SavePath + Machine.sName + ".rpwrite";
mReplayWriter.SaveData(Path, true, dbgPath); mReplayWriter.SaveData(Path, true, dbgPath);
} }
public void StopGame() public void StopGame()
{ {
if (bInGame) if (bInGame)
{ {
emu.StopGame(); emu.StopGame();
mUniVideoPlayer.StopVideo(); mUniVideoPlayer.StopVideo();
mUniSoundPlayer.StopPlay(); mUniSoundPlayer.StopPlay();
bInGame = false; bInGame = false;
bLogicUpdatePause = false; bLogicUpdatePause = false;
} }
} }
byte[] SaveState() byte[] SaveState()
{ {
if (!AxiIO.Directory.Exists(SavePath)) if (!AxiIO.Directory.Exists(SavePath))
AxiIO.Directory.CreateDirectory(SavePath); AxiIO.Directory.CreateDirectory(SavePath);
System.IO.MemoryStream ms = new System.IO.MemoryStream(); System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.IO.BinaryWriter bw = new System.IO.BinaryWriter(ms); System.IO.BinaryWriter bw = new System.IO.BinaryWriter(ms);
emu.SaveState(bw); emu.SaveState(bw);
byte[] data = ms.ToArray(); byte[] data = ms.ToArray();
bw.Close(); bw.Close();
ms.Close(); ms.Close();
return data; return data;
//byte[] screenData = UMAME.instance.mUniVideoPlayer.GetScreenImg(); //byte[] screenData = UMAME.instance.mUniVideoPlayer.GetScreenImg();
//FileStream fsImg = new FileStream(SavePath + Machine.sName + ".jpg", FileMode.Create); //FileStream fsImg = new FileStream(SavePath + Machine.sName + ".jpg", FileMode.Create);
//fsImg.Write(screenData, 0, screenData.Length); //fsImg.Write(screenData, 0, screenData.Length);
//fsImg.Close(); //fsImg.Close();
} }
void LoadState(byte[] data) void LoadState(byte[] data)
{ {
System.IO.MemoryStream fs = new System.IO.MemoryStream(data); System.IO.MemoryStream fs = new System.IO.MemoryStream(data);
System.IO.BinaryReader br = new System.IO.BinaryReader(fs); System.IO.BinaryReader br = new System.IO.BinaryReader(fs);
emu.LoadState(br); emu.LoadState(br);
br.Close(); br.Close();
fs.Close(); fs.Close();
} }

View File

@ -1,111 +1,111 @@
using AxibugEmuOnline.Client; using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.Settings; using AxibugEmuOnline.Client.Settings;
using AxiReplay; using AxiReplay;
using MAME.Core; using MAME.Core;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
public class UniKeyboard : MonoBehaviour, IKeyboard public class UniKeyboard : MonoBehaviour, IKeyboard
{ {
public MameControllerMapper ControllerMapper { get; private set; } public MameControllerMapper ControllerMapper { get; private set; }
PlayMode mPlayMode; PlayMode mPlayMode;
void Awake() void Awake()
{ {
ControllerMapper = new MameControllerMapper(); ControllerMapper = new MameControllerMapper();
Init(); Init();
} }
public ulong GetPressedKeys() public ulong GetPressedKeys()
{ {
return mPlayMode.GetPressedKeys(); return mPlayMode.GetPressedKeys();
} }
public void SyncInput(ulong inputData) public void SyncInput(ulong inputData)
{ {
mPlayMode.CurrLocalInpuAllData = inputData; mPlayMode.CurrLocalInpuAllData = inputData;
} }
public ulong DoLocalPressedKeys() public ulong DoLocalPressedKeys()
{ {
return mPlayMode.DoLocalPressedKeys(); return mPlayMode.DoLocalPressedKeys();
} }
#region #region
public void Init() public void Init()
{ {
mPlayMode = new PlayMode(this); mPlayMode = new PlayMode(this);
} }
public static IEnumerable<string> GetInputpDataToMotionKey(ulong inputdata) public static IEnumerable<string> GetInputpDataToMotionKey(ulong inputdata)
{ {
if (inputdata == 0) if (inputdata == 0)
yield break; yield break;
for (int i = 0; i < MotionKey.AllNeedCheckList.Length; i++) for (int i = 0; i < MotionKey.AllNeedCheckList.Length; i++)
{ {
if ((inputdata & MotionKey.AllNeedCheckList[i]) > 0) if ((inputdata & MotionKey.AllNeedCheckList[i]) > 0)
yield return MotionKey.GetKeyName(MotionKey.AllNeedCheckList[i]); yield return MotionKey.GetKeyName(MotionKey.AllNeedCheckList[i]);
} }
} }
public class PlayMode public class PlayMode
{ {
UniKeyboard mUniKeyboard; UniKeyboard mUniKeyboard;
public ulong CurrLocalInpuAllData = 0; public ulong CurrLocalInpuAllData = 0;
public ulong CurrRemoteInpuAllData = 0; public ulong CurrRemoteInpuAllData = 0;
public PlayMode(UniKeyboard uniKeyboard) public PlayMode(UniKeyboard uniKeyboard)
{ {
this.mUniKeyboard = uniKeyboard; this.mUniKeyboard = uniKeyboard;
} }
public ulong GetPressedKeys() public ulong GetPressedKeys()
{ {
if (InGameUI.Instance.Core.IsNetPlay) if (InGameUI.Instance.Core.IsNetPlay)
return CurrRemoteInpuAllData; return CurrRemoteInpuAllData;
else else
return CurrLocalInpuAllData; return CurrLocalInpuAllData;
} }
public ulong DoLocalPressedKeys() public ulong DoLocalPressedKeys()
{ {
ulong tempLocalInputAllData = 0; ulong tempLocalInputAllData = 0;
tempLocalInputAllData |= mUniKeyboard.ControllerMapper.Controller0.GetSingleAllInput(); tempLocalInputAllData |= mUniKeyboard.ControllerMapper.Controller0.GetSingleAllInput();
tempLocalInputAllData |= mUniKeyboard.ControllerMapper.Controller1.GetSingleAllInput(); tempLocalInputAllData |= mUniKeyboard.ControllerMapper.Controller1.GetSingleAllInput();
tempLocalInputAllData |= mUniKeyboard.ControllerMapper.Controller2.GetSingleAllInput(); tempLocalInputAllData |= mUniKeyboard.ControllerMapper.Controller2.GetSingleAllInput();
tempLocalInputAllData |= mUniKeyboard.ControllerMapper.Controller3.GetSingleAllInput(); tempLocalInputAllData |= mUniKeyboard.ControllerMapper.Controller3.GetSingleAllInput();
#if UNITY_EDITOR #if UNITY_EDITOR
if (CurrLocalInpuAllData != tempLocalInputAllData) if (CurrLocalInpuAllData != tempLocalInputAllData)
{ {
string ShowKeyNames = string.Empty; string ShowKeyNames = string.Empty;
foreach (string keyname in GetInputpDataToMotionKey(CurrLocalInpuAllData)) foreach (string keyname in GetInputpDataToMotionKey(CurrLocalInpuAllData))
{ {
ShowKeyNames += keyname + " |"; ShowKeyNames += keyname + " |";
} }
Debug.Log("GetPressedKeys=>" + ShowKeyNames); Debug.Log("GetPressedKeys=>" + ShowKeyNames);
} }
#endif #endif
CurrLocalInpuAllData = tempLocalInputAllData; CurrLocalInpuAllData = tempLocalInputAllData;
//写入replay //写入replay
UMAME.instance.mReplayWriter.NextFramebyFrameIdx((int)UMAME.instance.mUniVideoPlayer.mFrame, CurrLocalInpuAllData); UMAME.instance.mReplayWriter.NextFramebyFrameIdx((int)UMAME.instance.mUniVideoPlayer.mFrame, CurrLocalInpuAllData);
CheckPlayerSlotChanged(); CheckPlayerSlotChanged();
return CurrLocalInpuAllData; return CurrLocalInpuAllData;
} }
void CheckPlayerSlotChanged() void CheckPlayerSlotChanged()
{ {
if (!mUniKeyboard.ControllerMapper.Controller0.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller0.AnyButtonDown()) if (!mUniKeyboard.ControllerMapper.Controller0.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller0.AnyButtonDown())
Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 0); Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 0);
if (!mUniKeyboard.ControllerMapper.Controller1.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller1.AnyButtonDown()) if (!mUniKeyboard.ControllerMapper.Controller1.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller1.AnyButtonDown())
Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 1); Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 1);
@ -113,340 +113,340 @@ public class UniKeyboard : MonoBehaviour, IKeyboard
Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 2); Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 2);
if (!mUniKeyboard.ControllerMapper.Controller3.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller3.AnyButtonDown()) if (!mUniKeyboard.ControllerMapper.Controller3.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller3.AnyButtonDown())
Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 3); Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 3);
} }
} }
public class ReplayMode public class ReplayMode
{ {
ulong currInputData; ulong currInputData;
public ReplayMode() public ReplayMode()
{ {
} }
public ulong GetPressedKeys() public ulong GetPressedKeys()
{ {
int targetFrame = (int)UMAME.instance.mUniVideoPlayer.mFrame; int targetFrame = (int)UMAME.instance.mUniVideoPlayer.mFrame;
AxiReplay.ReplayStep stepData; AxiReplay.ReplayStep stepData;
//有变化 //有变化
if (UMAME.instance.mReplayReader.NextFramebyFrameIdx(targetFrame, out stepData)) if (UMAME.instance.mReplayReader.NextFramebyFrameIdx(targetFrame, out stepData))
{ {
#if UNITY_EDITOR #if UNITY_EDITOR
string ShowKeyNames = string.Empty; string ShowKeyNames = string.Empty;
foreach (string keyname in GetInputpDataToMotionKey(currInputData)) foreach (string keyname in GetInputpDataToMotionKey(currInputData))
{ {
ShowKeyNames += keyname + " |"; ShowKeyNames += keyname + " |";
} }
Debug.Log("GetPressedKeys=>" + ShowKeyNames); Debug.Log("GetPressedKeys=>" + ShowKeyNames);
#endif #endif
currInputData = stepData.InPut; currInputData = stepData.InPut;
} }
return currInputData; return currInputData;
} }
} }
#endregion #endregion
} }
public class MameControllerMapper : IControllerSetuper public class MameControllerMapper : IControllerSetuper
{ {
public MameSingleConoller Controller0 = new MameSingleConoller(0); public MameSingleConoller Controller0 = new MameSingleConoller(0);
public MameSingleConoller Controller1 = new MameSingleConoller(1); public MameSingleConoller Controller1 = new MameSingleConoller(1);
public MameSingleConoller Controller2 = new MameSingleConoller(2); public MameSingleConoller Controller2 = new MameSingleConoller(2);
public MameSingleConoller Controller3 = new MameSingleConoller(3); public MameSingleConoller Controller3 = new MameSingleConoller(3);
ulong mCurrAllInput; ulong mCurrAllInput;
public void SetConnect(uint? con0ToSlot = null, public void SetConnect(uint? con0ToSlot = null,
uint? con1ToSlot = null, uint? con1ToSlot = null,
uint? con2ToSlot = null, uint? con2ToSlot = null,
uint? con3ToSlot = null) uint? con3ToSlot = null)
{ {
Controller0.ConnectSlot = con0ToSlot; Controller0.ConnectSlot = con0ToSlot;
Controller1.ConnectSlot = con1ToSlot; Controller1.ConnectSlot = con1ToSlot;
Controller2.ConnectSlot = con2ToSlot; Controller2.ConnectSlot = con2ToSlot;
Controller3.ConnectSlot = con3ToSlot; Controller3.ConnectSlot = con3ToSlot;
} }
public int? GetSlotConnectingControllerIndex(int slotIndex) public int? GetSlotConnectingControllerIndex(int slotIndex)
{ {
if (Controller0.ConnectSlot.HasValue && Controller0.ConnectSlot.Value == slotIndex) return 0; if (Controller0.ConnectSlot.HasValue && Controller0.ConnectSlot.Value == slotIndex) return 0;
else if (Controller1.ConnectSlot.HasValue && Controller1.ConnectSlot.Value == slotIndex) return 1; else if (Controller1.ConnectSlot.HasValue && Controller1.ConnectSlot.Value == slotIndex) return 1;
else if (Controller2.ConnectSlot.HasValue && Controller2.ConnectSlot.Value == slotIndex) return 2; else if (Controller2.ConnectSlot.HasValue && Controller2.ConnectSlot.Value == slotIndex) return 2;
else if (Controller3.ConnectSlot.HasValue && Controller3.ConnectSlot.Value == slotIndex) return 3; else if (Controller3.ConnectSlot.HasValue && Controller3.ConnectSlot.Value == slotIndex) return 3;
else return null; else return null;
} }
public IController GetSlotConnectingController(int slotIndex) public IController GetSlotConnectingController(int slotIndex)
{ {
if (Controller0.ConnectSlot.HasValue && Controller0.ConnectSlot.Value == slotIndex) return Controller0; if (Controller0.ConnectSlot.HasValue && Controller0.ConnectSlot.Value == slotIndex) return Controller0;
else if (Controller1.ConnectSlot.HasValue && Controller1.ConnectSlot.Value == slotIndex) return Controller1; else if (Controller1.ConnectSlot.HasValue && Controller1.ConnectSlot.Value == slotIndex) return Controller1;
else if (Controller2.ConnectSlot.HasValue && Controller2.ConnectSlot.Value == slotIndex) return Controller2; else if (Controller2.ConnectSlot.HasValue && Controller2.ConnectSlot.Value == slotIndex) return Controller2;
else if (Controller3.ConnectSlot.HasValue && Controller3.ConnectSlot.Value == slotIndex) return Controller3; else if (Controller3.ConnectSlot.HasValue && Controller3.ConnectSlot.Value == slotIndex) return Controller3;
else return null; else return null;
} }
static HashSet<uint> s_temp = new HashSet<uint>(); static HashSet<uint> s_temp = new HashSet<uint>();
public uint? GetFreeSlotIndex() public uint? GetFreeSlotIndex()
{ {
s_temp.Clear(); s_temp.Clear();
s_temp.Add(0); s_temp.Add(0);
s_temp.Add(1); s_temp.Add(1);
s_temp.Add(2); s_temp.Add(2);
s_temp.Add(3); s_temp.Add(3);
if (Controller0.ConnectSlot.HasValue) s_temp.Remove(Controller0.ConnectSlot.Value); if (Controller0.ConnectSlot.HasValue) s_temp.Remove(Controller0.ConnectSlot.Value);
if (Controller1.ConnectSlot.HasValue) s_temp.Remove(Controller1.ConnectSlot.Value); if (Controller1.ConnectSlot.HasValue) s_temp.Remove(Controller1.ConnectSlot.Value);
if (Controller2.ConnectSlot.HasValue) s_temp.Remove(Controller2.ConnectSlot.Value); if (Controller2.ConnectSlot.HasValue) s_temp.Remove(Controller2.ConnectSlot.Value);
if (Controller3.ConnectSlot.HasValue) s_temp.Remove(Controller3.ConnectSlot.Value); if (Controller3.ConnectSlot.HasValue) s_temp.Remove(Controller3.ConnectSlot.Value);
if (s_temp.Count > 0) return s_temp.First(); if (s_temp.Count > 0) return s_temp.First();
else return null; else return null;
} }
public void LetControllerConnect(int conIndex, uint slotIndex) public void LetControllerConnect(int conIndex, uint slotIndex)
{ {
MameSingleConoller targetController; MameSingleConoller targetController;
switch (conIndex) switch (conIndex)
{ {
case 0: targetController = Controller0; break; case 0: targetController = Controller0; break;
case 1: targetController = Controller1; break; case 1: targetController = Controller1; break;
case 2: targetController = Controller2; break; case 2: targetController = Controller2; break;
case 3: targetController = Controller3; break; case 3: targetController = Controller3; break;
default: default:
throw new System.Exception($"Not Allowed conIndex Range: {conIndex}"); throw new System.Exception($"Not Allowed conIndex Range: {conIndex}");
break; break;
} }
if (targetController.ConnectSlot.HasValue) return; if (targetController.ConnectSlot.HasValue) return;
targetController.ConnectSlot = slotIndex; targetController.ConnectSlot = slotIndex;
Eventer.Instance.PostEvent(EEvent.OnControllerConnectChanged); Eventer.Instance.PostEvent(EEvent.OnControllerConnectChanged);
} }
} }
/// <summary> /// <summary>
/// MAME控制器 /// MAME控制器
/// </summary> /// </summary>
public class MameSingleConoller : IController public class MameSingleConoller : IController
{ {
//public KeyCode INSERT_COIN, GAMESTART, //public KeyCode INSERT_COIN, GAMESTART,
//UP, DOWN, LEFT, RIGHT, //UP, DOWN, LEFT, RIGHT,
//BTN_A, BTN_B, BTN_C, BTN_D, BTN_E, BTN_F; //BTN_A, BTN_B, BTN_C, BTN_D, BTN_E, BTN_F;
public ulong tg_INSERT_COIN, tg_GAMESTART, public ulong tg_INSERT_COIN, tg_GAMESTART,
tg_UP, tg_DOWN, tg_LEFT, tg_RIGHT, tg_UP, tg_DOWN, tg_LEFT, tg_RIGHT,
tg_BTN_A, tg_BTN_B, tg_BTN_C, tg_BTN_D, tg_BTN_E, tg_BTN_F; tg_BTN_A, tg_BTN_B, tg_BTN_C, tg_BTN_D, tg_BTN_E, tg_BTN_F;
public ulong CurrLocalSingleAllInput { get; private set; } public ulong CurrLocalSingleAllInput { get; private set; }
private MAMEKeyBinding m_keyMapper; private MAMEKeyBinding m_keyMapper;
int mControllerIndex; int mControllerIndex;
uint? mConnectSlot; uint? mConnectSlot;
/// <summary> /// <summary>
/// 指示该手柄连接的手柄插槽 /// 指示该手柄连接的手柄插槽
/// <para><c>这个值代表了该手柄在实际游戏中控制的Player</c></para> /// <para><c>这个值代表了该手柄在实际游戏中控制的Player</c></para>
/// <value>[0,3] 例外:为空代表未连接</value> /// <value>[0,3] 例外:为空代表未连接</value>
/// </summary> /// </summary>
public uint? ConnectSlot public uint? ConnectSlot
{ {
get { return mConnectSlot; } get { return mConnectSlot; }
set { mConnectSlot = value; this.ResetTargetMotionKey(); } set { mConnectSlot = value; this.ResetTargetMotionKey(); }
} }
/// <summary> /// <summary>
/// 控制器编号 /// 控制器编号
/// <para><c>此编号并非对应游戏中的player1,player2,player3,player4,仅仅作为本地4个手柄的实例</c></para> /// <para><c>此编号并非对应游戏中的player1,player2,player3,player4,仅仅作为本地4个手柄的实例</c></para>
/// <value>[0,3]</value> /// <value>[0,3]</value>
/// </summary> /// </summary>
public int ControllerIndex public int ControllerIndex
{ {
get { return mControllerIndex; } get { return mControllerIndex; }
set set
{ {
mControllerIndex = value; mControllerIndex = value;
//this.LoadControlKeyForConfig(); //this.LoadControlKeyForConfig();
//走统一配置 //走统一配置
} }
} }
public MameSingleConoller(int controllerIndex) public MameSingleConoller(int controllerIndex)
{ {
ControllerIndex = controllerIndex; ControllerIndex = controllerIndex;
m_keyMapper = App.settings.KeyMapper.GetBinder<MAMEKeyBinding>(UMAME.instance.Platform); m_keyMapper = App.settings.KeyMapper.GetBinder<MAMEKeyBinding>(UMAME.instance.Platform);
} }
public bool AnyButtonDown() public bool AnyButtonDown()
{ {
return m_keyMapper.AnyKeyDown(ControllerIndex); return m_keyMapper.AnyKeyDown(ControllerIndex);
//if (Input.GetKeyDown(INSERT_COIN)) return true; //if (Input.GetKeyDown(INSERT_COIN)) return true;
//if (Input.GetKeyDown(GAMESTART)) return true; //if (Input.GetKeyDown(GAMESTART)) return true;
//if (Input.GetKeyDown(UP)) return true; //if (Input.GetKeyDown(UP)) return true;
//if (Input.GetKeyDown(DOWN)) return true; //if (Input.GetKeyDown(DOWN)) return true;
//if (Input.GetKeyDown(LEFT)) return true; //if (Input.GetKeyDown(LEFT)) return true;
//if (Input.GetKeyDown(RIGHT)) return true; //if (Input.GetKeyDown(RIGHT)) return true;
//if (Input.GetKeyDown(BTN_A)) return true; //if (Input.GetKeyDown(BTN_A)) return true;
//if (Input.GetKeyDown(BTN_B)) return true; //if (Input.GetKeyDown(BTN_B)) return true;
//if (Input.GetKeyDown(BTN_C)) return true; //if (Input.GetKeyDown(BTN_C)) return true;
//if (Input.GetKeyDown(BTN_D)) return true; //if (Input.GetKeyDown(BTN_D)) return true;
//if (Input.GetKeyDown(BTN_E)) return true; //if (Input.GetKeyDown(BTN_E)) return true;
//if (Input.GetKeyDown(BTN_F)) return true; //if (Input.GetKeyDown(BTN_F)) return true;
//return false; //return false;
} }
public ulong GetSingleAllInput() public ulong GetSingleAllInput()
{ {
if (!ConnectSlot.HasValue) if (!ConnectSlot.HasValue)
return 0; return 0;
CurrLocalSingleAllInput = 0; CurrLocalSingleAllInput = 0;
if (m_keyMapper.GetKey(UMAMEKSingleKey.INSERT_COIN, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_INSERT_COIN; if (m_keyMapper.GetKey(UMAMEKSingleKey.INSERT_COIN, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_INSERT_COIN;
if (m_keyMapper.GetKey(UMAMEKSingleKey.GAMESTART, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_GAMESTART; if (m_keyMapper.GetKey(UMAMEKSingleKey.GAMESTART, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_GAMESTART;
if (m_keyMapper.GetKey(UMAMEKSingleKey.UP, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_UP; if (m_keyMapper.GetKey(UMAMEKSingleKey.UP, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_UP;
if (m_keyMapper.GetKey(UMAMEKSingleKey.DOWN, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_DOWN; if (m_keyMapper.GetKey(UMAMEKSingleKey.DOWN, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_DOWN;
if (m_keyMapper.GetKey(UMAMEKSingleKey.LEFT, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_LEFT; if (m_keyMapper.GetKey(UMAMEKSingleKey.LEFT, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_LEFT;
if (m_keyMapper.GetKey(UMAMEKSingleKey.RIGHT, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_RIGHT; if (m_keyMapper.GetKey(UMAMEKSingleKey.RIGHT, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_RIGHT;
if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_A, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_A; if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_A, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_A;
if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_B, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_B; if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_B, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_B;
if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_C, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_C; if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_C, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_C;
if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_D, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_D; if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_D, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_D;
if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_E, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_E; if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_E, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_E;
if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_F, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_F; if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_F, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_F;
//if (Input.GetKey(INSERT_COIN)) CurrLocalSingleAllInput |= (ulong)tg_INSERT_COIN; //if (Input.GetKey(INSERT_COIN)) CurrLocalSingleAllInput |= (ulong)tg_INSERT_COIN;
//if (Input.GetKey(GAMESTART)) CurrLocalSingleAllInput |= (ulong)tg_GAMESTART; //if (Input.GetKey(GAMESTART)) CurrLocalSingleAllInput |= (ulong)tg_GAMESTART;
//if (Input.GetKey(UP)) CurrLocalSingleAllInput |= (ulong)tg_UP; //if (Input.GetKey(UP)) CurrLocalSingleAllInput |= (ulong)tg_UP;
//if (Input.GetKey(DOWN)) CurrLocalSingleAllInput |= (ulong)tg_DOWN; //if (Input.GetKey(DOWN)) CurrLocalSingleAllInput |= (ulong)tg_DOWN;
//if (Input.GetKey(LEFT)) CurrLocalSingleAllInput |= (ulong)tg_LEFT; //if (Input.GetKey(LEFT)) CurrLocalSingleAllInput |= (ulong)tg_LEFT;
//if (Input.GetKey(RIGHT)) CurrLocalSingleAllInput |= (ulong)tg_RIGHT; //if (Input.GetKey(RIGHT)) CurrLocalSingleAllInput |= (ulong)tg_RIGHT;
//if (Input.GetKey(BTN_A)) CurrLocalSingleAllInput |= (ulong)tg_BTN_A; //if (Input.GetKey(BTN_A)) CurrLocalSingleAllInput |= (ulong)tg_BTN_A;
//if (Input.GetKey(BTN_B)) CurrLocalSingleAllInput |= (ulong)tg_BTN_B; //if (Input.GetKey(BTN_B)) CurrLocalSingleAllInput |= (ulong)tg_BTN_B;
//if (Input.GetKey(BTN_C)) CurrLocalSingleAllInput |= (ulong)tg_BTN_C; //if (Input.GetKey(BTN_C)) CurrLocalSingleAllInput |= (ulong)tg_BTN_C;
//if (Input.GetKey(BTN_D)) CurrLocalSingleAllInput |= (ulong)tg_BTN_D; //if (Input.GetKey(BTN_D)) CurrLocalSingleAllInput |= (ulong)tg_BTN_D;
//if (Input.GetKey(BTN_E)) CurrLocalSingleAllInput |= (ulong)tg_BTN_E; //if (Input.GetKey(BTN_E)) CurrLocalSingleAllInput |= (ulong)tg_BTN_E;
//if (Input.GetKey(BTN_F)) CurrLocalSingleAllInput |= (ulong)tg_BTN_F; //if (Input.GetKey(BTN_F)) CurrLocalSingleAllInput |= (ulong)tg_BTN_F;
return CurrLocalSingleAllInput; return CurrLocalSingleAllInput;
} }
} }
public static class MameSingleControllSetter public static class MameSingleControllSetter
{ {
//不再需要 //不再需要
//public static void LoadControlKeyForConfig(this MameSingleConoller singlecontrol) //public static void LoadControlKeyForConfig(this MameSingleConoller singlecontrol)
//{ //{
// //TODO 等待支持配置,或统一 // //TODO 等待支持配置,或统一
// switch (singlecontrol.ControllerIndex) // switch (singlecontrol.ControllerIndex)
// { // {
// case 0: // case 0:
// singlecontrol.INSERT_COIN = KeyCode.Alpha5; // singlecontrol.INSERT_COIN = KeyCode.Alpha5;
// singlecontrol.GAMESTART = KeyCode.Alpha1; // singlecontrol.GAMESTART = KeyCode.Alpha1;
// singlecontrol.UP = KeyCode.W; // singlecontrol.UP = KeyCode.W;
// singlecontrol.DOWN = KeyCode.S; // singlecontrol.DOWN = KeyCode.S;
// singlecontrol.LEFT = KeyCode.A; // singlecontrol.LEFT = KeyCode.A;
// singlecontrol.RIGHT = KeyCode.D; // singlecontrol.RIGHT = KeyCode.D;
// singlecontrol.BTN_A = KeyCode.J; // singlecontrol.BTN_A = KeyCode.J;
// singlecontrol.BTN_B = KeyCode.K; // singlecontrol.BTN_B = KeyCode.K;
// singlecontrol.BTN_C = KeyCode.L; // singlecontrol.BTN_C = KeyCode.L;
// singlecontrol.BTN_D = KeyCode.U; // singlecontrol.BTN_D = KeyCode.U;
// singlecontrol.BTN_E = KeyCode.I; // singlecontrol.BTN_E = KeyCode.I;
// singlecontrol.BTN_F = KeyCode.O; // singlecontrol.BTN_F = KeyCode.O;
// break; // break;
// case 1: // case 1:
// singlecontrol.INSERT_COIN = KeyCode.KeypadMultiply; // singlecontrol.INSERT_COIN = KeyCode.KeypadMultiply;
// singlecontrol.GAMESTART = KeyCode.KeypadDivide; // singlecontrol.GAMESTART = KeyCode.KeypadDivide;
// singlecontrol.UP = KeyCode.UpArrow; // singlecontrol.UP = KeyCode.UpArrow;
// singlecontrol.DOWN = KeyCode.DownArrow; // singlecontrol.DOWN = KeyCode.DownArrow;
// singlecontrol.LEFT = KeyCode.LeftArrow; // singlecontrol.LEFT = KeyCode.LeftArrow;
// singlecontrol.RIGHT = KeyCode.RightArrow; // singlecontrol.RIGHT = KeyCode.RightArrow;
// singlecontrol.BTN_A = KeyCode.Keypad1; // singlecontrol.BTN_A = KeyCode.Keypad1;
// singlecontrol.BTN_B = KeyCode.Keypad2; // singlecontrol.BTN_B = KeyCode.Keypad2;
// singlecontrol.BTN_C = KeyCode.Keypad3; // singlecontrol.BTN_C = KeyCode.Keypad3;
// singlecontrol.BTN_D = KeyCode.Keypad4; // singlecontrol.BTN_D = KeyCode.Keypad4;
// singlecontrol.BTN_E = KeyCode.Keypad5; // singlecontrol.BTN_E = KeyCode.Keypad5;
// singlecontrol.BTN_F = KeyCode.Keypad6; // singlecontrol.BTN_F = KeyCode.Keypad6;
// break; // break;
// case 2: // case 2:
// break; // break;
// case 3: // case 3:
// break; // break;
// } // }
//} //}
public static void ResetTargetMotionKey(this MameSingleConoller singlecontrol) public static void ResetTargetMotionKey(this MameSingleConoller singlecontrol)
{ {
if (!singlecontrol.ConnectSlot.HasValue) if (!singlecontrol.ConnectSlot.HasValue)
{ {
singlecontrol.tg_INSERT_COIN singlecontrol.tg_INSERT_COIN
= singlecontrol.tg_GAMESTART = singlecontrol.tg_GAMESTART
= singlecontrol.tg_UP = singlecontrol.tg_UP
= singlecontrol.tg_DOWN = singlecontrol.tg_DOWN
= singlecontrol.tg_LEFT = singlecontrol.tg_LEFT
= singlecontrol.tg_RIGHT = singlecontrol.tg_RIGHT
= singlecontrol.tg_BTN_A = singlecontrol.tg_BTN_A
= singlecontrol.tg_BTN_B = singlecontrol.tg_BTN_B
= singlecontrol.tg_BTN_C = singlecontrol.tg_BTN_C
= singlecontrol.tg_BTN_D = singlecontrol.tg_BTN_D
= singlecontrol.tg_BTN_E = singlecontrol.tg_BTN_E
= singlecontrol.tg_BTN_F = singlecontrol.tg_BTN_F
= MotionKey.FinalKey; = MotionKey.FinalKey;
return; return;
} }
switch (singlecontrol.ConnectSlot.Value) switch (singlecontrol.ConnectSlot.Value)
{ {
case 0: case 0:
singlecontrol.tg_INSERT_COIN = MotionKey.P1_INSERT_COIN; singlecontrol.tg_INSERT_COIN = MotionKey.P1_INSERT_COIN;
singlecontrol.tg_GAMESTART = MotionKey.P1_GAMESTART; singlecontrol.tg_GAMESTART = MotionKey.P1_GAMESTART;
singlecontrol.tg_UP = MotionKey.P1_UP; singlecontrol.tg_UP = MotionKey.P1_UP;
singlecontrol.tg_DOWN = MotionKey.P1_DOWN; singlecontrol.tg_DOWN = MotionKey.P1_DOWN;
singlecontrol.tg_LEFT = MotionKey.P1_LEFT; singlecontrol.tg_LEFT = MotionKey.P1_LEFT;
singlecontrol.tg_RIGHT = MotionKey.P1_RIGHT; singlecontrol.tg_RIGHT = MotionKey.P1_RIGHT;
singlecontrol.tg_BTN_A = MotionKey.P1_BTN_1; singlecontrol.tg_BTN_A = MotionKey.P1_BTN_1;
singlecontrol.tg_BTN_B = MotionKey.P1_BTN_2; singlecontrol.tg_BTN_B = MotionKey.P1_BTN_2;
singlecontrol.tg_BTN_C = MotionKey.P1_BTN_3; singlecontrol.tg_BTN_C = MotionKey.P1_BTN_3;
singlecontrol.tg_BTN_D = MotionKey.P1_BTN_4; singlecontrol.tg_BTN_D = MotionKey.P1_BTN_4;
singlecontrol.tg_BTN_E = MotionKey.P1_BTN_5; singlecontrol.tg_BTN_E = MotionKey.P1_BTN_5;
singlecontrol.tg_BTN_F = MotionKey.P1_BTN_6; singlecontrol.tg_BTN_F = MotionKey.P1_BTN_6;
break; break;
case 1: case 1:
singlecontrol.tg_INSERT_COIN = MotionKey.P2_INSERT_COIN; singlecontrol.tg_INSERT_COIN = MotionKey.P2_INSERT_COIN;
singlecontrol.tg_GAMESTART = MotionKey.P2_GAMESTART; singlecontrol.tg_GAMESTART = MotionKey.P2_GAMESTART;
singlecontrol.tg_UP = MotionKey.P2_UP; singlecontrol.tg_UP = MotionKey.P2_UP;
singlecontrol.tg_DOWN = MotionKey.P2_DOWN; singlecontrol.tg_DOWN = MotionKey.P2_DOWN;
singlecontrol.tg_LEFT = MotionKey.P2_LEFT; singlecontrol.tg_LEFT = MotionKey.P2_LEFT;
singlecontrol.tg_RIGHT = MotionKey.P2_RIGHT; singlecontrol.tg_RIGHT = MotionKey.P2_RIGHT;
singlecontrol.tg_BTN_A = MotionKey.P2_BTN_1; singlecontrol.tg_BTN_A = MotionKey.P2_BTN_1;
singlecontrol.tg_BTN_B = MotionKey.P2_BTN_2; singlecontrol.tg_BTN_B = MotionKey.P2_BTN_2;
singlecontrol.tg_BTN_C = MotionKey.P2_BTN_3; singlecontrol.tg_BTN_C = MotionKey.P2_BTN_3;
singlecontrol.tg_BTN_D = MotionKey.P2_BTN_4; singlecontrol.tg_BTN_D = MotionKey.P2_BTN_4;
singlecontrol.tg_BTN_E = MotionKey.P2_BTN_5; singlecontrol.tg_BTN_E = MotionKey.P2_BTN_5;
singlecontrol.tg_BTN_F = MotionKey.P2_BTN_6; singlecontrol.tg_BTN_F = MotionKey.P2_BTN_6;
break; break;
//后续修改后 支持P3 P4 //后续修改后 支持P3 P4
case 2: case 2:
singlecontrol.tg_INSERT_COIN = MotionKey.FinalKey; singlecontrol.tg_INSERT_COIN = MotionKey.FinalKey;
singlecontrol.tg_GAMESTART = MotionKey.FinalKey; singlecontrol.tg_GAMESTART = MotionKey.FinalKey;
singlecontrol.tg_UP = MotionKey.FinalKey; singlecontrol.tg_UP = MotionKey.FinalKey;
singlecontrol.tg_DOWN = MotionKey.FinalKey; singlecontrol.tg_DOWN = MotionKey.FinalKey;
singlecontrol.tg_LEFT = MotionKey.FinalKey; singlecontrol.tg_LEFT = MotionKey.FinalKey;
singlecontrol.tg_RIGHT = MotionKey.FinalKey; singlecontrol.tg_RIGHT = MotionKey.FinalKey;
singlecontrol.tg_BTN_A = MotionKey.FinalKey; singlecontrol.tg_BTN_A = MotionKey.FinalKey;
singlecontrol.tg_BTN_B = MotionKey.FinalKey; singlecontrol.tg_BTN_B = MotionKey.FinalKey;
singlecontrol.tg_BTN_C = MotionKey.FinalKey; singlecontrol.tg_BTN_C = MotionKey.FinalKey;
singlecontrol.tg_BTN_D = MotionKey.FinalKey; singlecontrol.tg_BTN_D = MotionKey.FinalKey;
singlecontrol.tg_BTN_E = MotionKey.FinalKey; singlecontrol.tg_BTN_E = MotionKey.FinalKey;
singlecontrol.tg_BTN_F = MotionKey.FinalKey; singlecontrol.tg_BTN_F = MotionKey.FinalKey;
break; break;
case 3: case 3:
singlecontrol.tg_INSERT_COIN = MotionKey.FinalKey; singlecontrol.tg_INSERT_COIN = MotionKey.FinalKey;
singlecontrol.tg_GAMESTART = MotionKey.FinalKey; singlecontrol.tg_GAMESTART = MotionKey.FinalKey;
singlecontrol.tg_UP = MotionKey.FinalKey; singlecontrol.tg_UP = MotionKey.FinalKey;
singlecontrol.tg_DOWN = MotionKey.FinalKey; singlecontrol.tg_DOWN = MotionKey.FinalKey;
singlecontrol.tg_LEFT = MotionKey.FinalKey; singlecontrol.tg_LEFT = MotionKey.FinalKey;
singlecontrol.tg_RIGHT = MotionKey.FinalKey; singlecontrol.tg_RIGHT = MotionKey.FinalKey;
singlecontrol.tg_BTN_A = MotionKey.FinalKey; singlecontrol.tg_BTN_A = MotionKey.FinalKey;
singlecontrol.tg_BTN_B = MotionKey.FinalKey; singlecontrol.tg_BTN_B = MotionKey.FinalKey;
singlecontrol.tg_BTN_C = MotionKey.FinalKey; singlecontrol.tg_BTN_C = MotionKey.FinalKey;
singlecontrol.tg_BTN_D = MotionKey.FinalKey; singlecontrol.tg_BTN_D = MotionKey.FinalKey;
singlecontrol.tg_BTN_E = MotionKey.FinalKey; singlecontrol.tg_BTN_E = MotionKey.FinalKey;
singlecontrol.tg_BTN_F = MotionKey.FinalKey; singlecontrol.tg_BTN_F = MotionKey.FinalKey;
break; break;
} }
} }
} }

View File

@ -1,135 +1,135 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf; using AxibugProtobuf;
using AxiReplay; using AxiReplay;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using VirtualNes.Core; using VirtualNes.Core;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class CoreSupporter : ISupporterImpl public class CoreSupporter : ISupporterImpl
{ {
public System.IO.Stream OpenRom(string fname) public System.IO.Stream OpenRom(string fname)
{ {
try try
{ {
var romFile = App.GetRomLib(RomPlatformType.Nes).GetRomFile(fname); var romFile = App.GetRomLib(RomPlatformType.Nes).GetRomFile(fname);
var bytes = romFile.GetRomFileData(); var bytes = romFile.GetRomFileData();
Debug.Log($"Open {romFile.Alias}"); Debug.Log($"Open {romFile.Alias}");
return new System.IO.MemoryStream(bytes); return new System.IO.MemoryStream(bytes);
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.LogError(ex); Debug.LogError(ex);
return null; return null;
} }
} }
public void GetRomPathInfo(string fname, out string fullPath, out string directPath) public void GetRomPathInfo(string fname, out string fullPath, out string directPath)
{ {
var romFile = App.GetRomLib(RomPlatformType.Nes).GetRomFile(fname); var romFile = App.GetRomLib(RomPlatformType.Nes).GetRomFile(fname);
UnityEngine.Debug.Assert(romFile != null); UnityEngine.Debug.Assert(romFile != null);
fullPath = romFile.LocalFilePath; fullPath = romFile.LocalFilePath;
directPath = System.IO.Path.GetDirectoryName(fullPath); directPath = System.IO.Path.GetDirectoryName(fullPath);
} }
public System.IO.Stream OpenFile_DISKSYS() public System.IO.Stream OpenFile_DISKSYS()
{ {
return new System.IO.MemoryStream(Resources.Load<TextAsset>("NES/Disksys.rom").bytes); return new System.IO.MemoryStream(Resources.Load<TextAsset>("NES/Disksys.rom").bytes);
} }
public void SaveSRAMToFile(byte[] sramContent, string romName) public void SaveSRAMToFile(byte[] sramContent, string romName)
{ {
string sramDirectoryPath = $"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/{Config.path.szSavePath}"; string sramDirectoryPath = $"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/{Config.path.szSavePath}";
AxiIO.Directory.CreateDirectory(sramDirectoryPath); AxiIO.Directory.CreateDirectory(sramDirectoryPath);
romName = System.IO.Path.GetFileNameWithoutExtension(romName); romName = System.IO.Path.GetFileNameWithoutExtension(romName);
AxiIO.File.WriteAllBytes($"{sramDirectoryPath}/{romName}.sav", sramContent); AxiIO.File.WriteAllBytes($"{sramDirectoryPath}/{romName}.sav", sramContent);
} }
public void SaveDISKToFile(byte[] diskFileContent, string romName) public void SaveDISKToFile(byte[] diskFileContent, string romName)
{ {
string diskFileDirectoryPath = $"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/dsv"; string diskFileDirectoryPath = $"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/dsv";
AxiIO.Directory.CreateDirectory(diskFileDirectoryPath); AxiIO.Directory.CreateDirectory(diskFileDirectoryPath);
romName = System.IO.Path.GetFileNameWithoutExtension(romName); romName = System.IO.Path.GetFileNameWithoutExtension(romName);
AxiIO.File.WriteAllBytes($"{diskFileDirectoryPath}/{romName}.dsv", diskFileContent); AxiIO.File.WriteAllBytes($"{diskFileDirectoryPath}/{romName}.dsv", diskFileContent);
} }
public EmulatorConfig Config { get; private set; } = new EmulatorConfig(); public EmulatorConfig Config { get; private set; } = new EmulatorConfig();
public void PrepareDirectory(string directPath) public void PrepareDirectory(string directPath)
{ {
AxiIO.Directory.CreateDirectory($"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/{directPath}"); AxiIO.Directory.CreateDirectory($"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/{directPath}");
} }
public void SaveFile(byte[] fileData, string directPath, string fileName) public void SaveFile(byte[] fileData, string directPath, string fileName)
{ {
PrepareDirectory(directPath); PrepareDirectory(directPath);
var fileFullpath = $"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/{directPath}/{fileName}"; var fileFullpath = $"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/{directPath}/{fileName}";
AxiIO.File.WriteAllBytes(fileFullpath, fileData); AxiIO.File.WriteAllBytes(fileFullpath, fileData);
} }
public System.IO.Stream OpenFile(string directPath, string fileName) public System.IO.Stream OpenFile(string directPath, string fileName)
{ {
try try
{ {
var path = $"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/{directPath}/{fileName}"; var path = $"{App.PersistentDataPath(AxibugProtobuf.RomPlatformType.Nes)}/{directPath}/{fileName}";
var data = AxiIO.File.ReadAllBytes(path); var data = AxiIO.File.ReadAllBytes(path);
if (data == null) return null; if (data == null) return null;
return new System.IO.MemoryStream(data); return new System.IO.MemoryStream(data);
} }
catch catch
{ {
return null; return null;
} }
} }
public bool TryGetMapperNo(ROM rom, out int mapperNo) public bool TryGetMapperNo(ROM rom, out int mapperNo)
{ {
var db = Resources.Load<RomDB>("NES/ROMDB"); var db = Resources.Load<RomDB>("NES/ROMDB");
return db.GetMapperNo(rom.GetPROM_CRC(), out mapperNo); return db.GetMapperNo(rom.GetPROM_CRC(), out mapperNo);
} }
public ControllerState FromNet(AxiReplay.ReplayStep step) public ControllerState FromNet(AxiReplay.ReplayStep step)
{ {
var temp = new ServerInputSnapShot(); var temp = new ServerInputSnapShot();
var result = new ControllerState(); var result = new ControllerState();
temp.all = step.InPut; temp.all = step.InPut;
result.raw0 = temp.p1; result.raw0 = temp.p1;
result.raw1 = temp.p2; result.raw1 = temp.p2;
result.raw2 = temp.p3; result.raw2 = temp.p3;
result.raw3 = temp.p4; result.raw3 = temp.p4;
result.valid = true; result.valid = true;
return result; return result;
} }
public uint ToNet(ControllerState state) public uint ToNet(ControllerState state)
{ {
var temp = new ServerInputSnapShot(); var temp = new ServerInputSnapShot();
temp.p1 = (byte)state.raw0; temp.p1 = (byte)state.raw0;
temp.p2 = (byte)state.raw1; temp.p2 = (byte)state.raw1;
temp.p3 = (byte)state.raw2; temp.p3 = (byte)state.raw2;
temp.p4 = (byte)state.raw3; temp.p4 = (byte)state.raw3;
return (uint)temp.all; return (uint)temp.all;
} }
[StructLayout(LayoutKind.Explicit, Size = 8)] [StructLayout(LayoutKind.Explicit, Size = 8)]
struct ServerInputSnapShot struct ServerInputSnapShot
{ {
[FieldOffset(0)] [FieldOffset(0)]
public UInt64 all; public UInt64 all;
[FieldOffset(0)] [FieldOffset(0)]
public byte p1; public byte p1;
[FieldOffset(1)] [FieldOffset(1)]
public byte p2; public byte p2;
[FieldOffset(2)] [FieldOffset(2)]
public byte p3; public byte p3;
[FieldOffset(3)] [FieldOffset(3)]
public byte p4; public byte p4;
} }
} }
} }

View File

@ -1,137 +1,137 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf; using AxibugProtobuf;
using AxiReplay; using AxiReplay;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Xml.Linq; using System.Xml.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using VirtualNes.Core; using VirtualNes.Core;
using VirtualNes.Core.Debug; using VirtualNes.Core.Debug;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class NesEmulator : EmuCore<ControllerState> public class NesEmulator : EmuCore<ControllerState>
{ {
public VideoProvider VideoProvider; public VideoProvider VideoProvider;
public AudioProvider AudioProvider; public AudioProvider AudioProvider;
//模拟器核心实例化对象 //模拟器核心实例化对象
public NES NesCore { get; private set; } public NES NesCore { get; private set; }
/// <summary> 是否暂停 </summary> /// <summary> 是否暂停 </summary>
public bool IsPause { get; private set; } public bool IsPause { get; private set; }
public NesControllerMapper ControllerMapper { get; private set; } public NesControllerMapper ControllerMapper { get; private set; }
private void Awake() private void Awake()
{ {
ControllerMapper = new NesControllerMapper(); ControllerMapper = new NesControllerMapper();
} }
private void Start() private void Start()
{ {
App.tick.SetFrameRate(60); App.tick.SetFrameRate(60);
VideoProvider.NesEmu = this; VideoProvider.NesEmu = this;
AudioProvider.NesEmu = this; AudioProvider.NesEmu = this;
} }
public override RomPlatformType Platform => RomPlatformType.Nes; public override RomPlatformType Platform => RomPlatformType.Nes;
private CoreSupporter m_coreSupporter; private CoreSupporter m_coreSupporter;
/// <summary> /// <summary>
/// 指定ROM开始游戏 /// 指定ROM开始游戏
/// </summary> /// </summary>
public override MsgBool StartGame(RomFile rom) public override MsgBool StartGame(RomFile rom)
{ {
StopGame(); StopGame();
m_coreSupporter = new CoreSupporter(); m_coreSupporter = new CoreSupporter();
Supporter.Setup(m_coreSupporter); Supporter.Setup(m_coreSupporter);
Debuger.Setup(new CoreDebuger()); Debuger.Setup(new CoreDebuger());
App.GetRomLib(RomPlatformType.Nes).AddRomFile(rom); App.GetRomLib(RomPlatformType.Nes).AddRomFile(rom);
try try
{ {
NesCore = new NES(rom.FileName); NesCore = new NES(rom.FileName);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
{ {
NesCore = null; NesCore = null;
App.log.Error(ex.ToString()); App.log.Error(ex.ToString());
return ex.Message; return ex.Message;
} }
} }
public override void Pause() public override void Pause()
{ {
IsPause = true; IsPause = true;
} }
public override void Resume() public override void Resume()
{ {
IsPause = false; IsPause = false;
} }
public override void DoReset() public override void DoReset()
{ {
NesCore.Reset(); NesCore.Reset();
} }
public override void LoadState(object state) public override void LoadState(object state)
{ {
NesCore.LoadState((State)state); NesCore.LoadState((State)state);
} }
public override object GetState() public override object GetState()
{ {
return NesCore.GetState(); return NesCore.GetState();
} }
/// <summary> /// <summary>
/// 获取即时存档 /// 获取即时存档
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public override byte[] GetStateBytes() public override byte[] GetStateBytes()
{ {
return NesCore.GetState().ToBytes(); return NesCore.GetState().ToBytes();
} }
/// <summary> /// <summary>
/// 加载即时存档 /// 加载即时存档
/// </summary> /// </summary>
/// <param /// <param
/// name="data"> /// name="data">
/// </param> /// </param>
public override void LoadStateFromBytes(byte[] data) public override void LoadStateFromBytes(byte[] data)
{ {
var st = new State(); var st = new State();
st.FromByte(data); st.FromByte(data);
NesCore.LoadState(st); NesCore.LoadState(st);
} }
public override uint Frame => NesCore.FrameCount; public override uint Frame => NesCore.FrameCount;
/// <summary> /// <summary>
/// 停止游戏 /// 停止游戏
/// </summary> /// </summary>
public void StopGame() public void StopGame()
{ {
NesCore?.Dispose(); NesCore?.Dispose();
NesCore = null; NesCore = null;
} }
//推进帧 //推进帧
protected override bool OnPushEmulatorFrame(ControllerState inputData) protected override bool OnPushEmulatorFrame(ControllerState inputData)
{ {
if (NesCore == null || IsPause) return false; if (NesCore == null || IsPause) return false;
NesCore.pad.Sync(inputData); NesCore.pad.Sync(inputData);
NesCore.EmulateFrame(true); NesCore.EmulateFrame(true);
return true; return true;
} }
protected override ControllerState ConvertInputDataFromNet(ReplayStep step) protected override ControllerState ConvertInputDataFromNet(ReplayStep step)
@ -153,16 +153,16 @@ namespace AxibugEmuOnline.Client
{ {
var screenBuffer = NesCore.ppu.GetScreenPtr(); var screenBuffer = NesCore.ppu.GetScreenPtr();
VideoProvider.SetDrawData(screenBuffer); VideoProvider.SetDrawData(screenBuffer);
} }
public override IControllerSetuper GetControllerSetuper() public override IControllerSetuper GetControllerSetuper()
{ {
return ControllerMapper; return ControllerMapper;
} }
public override void Dispose() public override void Dispose()
{ {
StopGame(); StopGame();
} }
public override Texture OutputPixel => VideoProvider.OutputPixel; public override Texture OutputPixel => VideoProvider.OutputPixel;
@ -170,37 +170,37 @@ namespace AxibugEmuOnline.Client
public override void GetAudioParams(out int frequency, out int channels) public override void GetAudioParams(out int frequency, out int channels)
{ {
AudioProvider.GetAudioParams(out frequency, out channels); AudioProvider.GetAudioParams(out frequency, out channels);
}
#if UNITY_EDITOR
/// <summary>
/// 编辑器用
/// </summary>
[Conditional("UNITY_EDITOR")]
[ContextMenu("ImportNesDB")]
public void ImportNesDB()
{
var db = Resources.Load<RomDB>("NES/ROMDB");
db.Clear();
var xmlStr = System.IO.File.ReadAllText("nes20db.xml");
var xml = XDocument.Parse(xmlStr);
var games = xml.Element("nes20db")?.Elements("game");
System.Diagnostics.Debug.Assert(games != null, nameof(games) + " != null");
foreach (var game in games)
{
var crcStr = game.Element("rom")?.Attribute("crc32")?.Value;
var crc = uint.Parse($"{crcStr}", NumberStyles.HexNumber);
var mapper = int.Parse($"{game.Element("pcb")?.Attribute("mapper")?.Value}");
if (mapper > 255) continue;
db.AddInfo(new RomDB.RomInfo { CRC = crc, Mapper = mapper });
}
UnityEditor.EditorUtility.SetDirty(db);
UnityEditor.AssetDatabase.SaveAssets();
} }
#endif
} #if UNITY_EDITOR
/// <summary>
/// 编辑器用
/// </summary>
[Conditional("UNITY_EDITOR")]
[ContextMenu("ImportNesDB")]
public void ImportNesDB()
{
var db = Resources.Load<RomDB>("NES/ROMDB");
db.Clear();
var xmlStr = System.IO.File.ReadAllText("nes20db.xml");
var xml = XDocument.Parse(xmlStr);
var games = xml.Element("nes20db")?.Elements("game");
System.Diagnostics.Debug.Assert(games != null, nameof(games) + " != null");
foreach (var game in games)
{
var crcStr = game.Element("rom")?.Attribute("crc32")?.Value;
var crc = uint.Parse($"{crcStr}", NumberStyles.HexNumber);
var mapper = int.Parse($"{game.Element("pcb")?.Attribute("mapper")?.Value}");
if (mapper > 255) continue;
db.AddInfo(new RomDB.RomInfo { CRC = crc, Mapper = mapper });
}
UnityEditor.EditorUtility.SetDirty(db);
UnityEditor.AssetDatabase.SaveAssets();
}
#endif
}
} }

View File

@ -1,73 +1,73 @@
namespace AxibugEmuOnline.Client.Event namespace AxibugEmuOnline.Client.Event
{ {
public enum EEvent public enum EEvent
{ {
// 添加你自己需要的事件类型 // 添加你自己需要的事件类型
/// <summary> /// <summary>
/// 登录成功 /// 登录成功
/// </summary> /// </summary>
OnLoginSucceed, OnLoginSucceed,
/// <summary> /// <summary>
/// 当登录被置为false时 /// 当登录被置为false时
/// </summary> /// </summary>
OnLossLoginState, OnLossLoginState,
/// <summary> /// <summary>
/// 登录失败 /// 登录失败
/// </summary> /// </summary>
OnLoginFailed, OnLoginFailed,
OnChatMsg, OnChatMsg,
//自己的信息更新(比如改名更新) //自己的信息更新(比如改名更新)
OnSelfInfoUpdate, OnSelfInfoUpdate,
//更新其他用户信息 //更新其他用户信息
OnOtherUserInfoUpdate, OnOtherUserInfoUpdate,
//用户列表,登录和离开 //用户列表,登录和离开
OnUserListAllUpdate, OnUserListAllUpdate,
OnUserLogin, OnUserLogin,
OnUserLoginOut, OnUserLoginOut,
OnRoomListAllUpdate,//房间列表全量刷新 OnRoomListAllUpdate,//房间列表全量刷新
OnRoomListSingleAdd,//房间列表中新增房间 OnRoomListSingleAdd,//房间列表中新增房间
OnRoomListSingleUpdate,//房间列表中单个更新 OnRoomListSingleUpdate,//房间列表中单个更新
OnRoomListSingleClose,//房间关闭 OnRoomListSingleClose,//房间关闭
OnRoomGetRoomScreen,//获取到房间数据 OnRoomGetRoomScreen,//获取到房间数据
/// <summary> /// <summary>
/// 我的房间创建成功 /// 我的房间创建成功
/// </summary> /// </summary>
OnMineRoomCreated, OnMineRoomCreated,
/// <summary> /// <summary>
/// 我进入房间 /// 我进入房间
/// </summary> /// </summary>
OnMineJoinRoom, OnMineJoinRoom,
/// <summary> /// <summary>
/// 我离开房间 /// 我离开房间
/// </summary> /// </summary>
OnMineLeavnRoom, OnMineLeavnRoom,
/// <summary> /// <summary>
/// 其他人进入房间 /// 其他人进入房间
/// </summary> /// </summary>
OnOtherPlayerJoinRoom, OnOtherPlayerJoinRoom,
/// <summary> /// <summary>
/// 其他人离开房间 /// 其他人离开房间
/// </summary> /// </summary>
OnOtherPlayerLeavnRoom, OnOtherPlayerLeavnRoom,
/// <summary> /// <summary>
/// 服务器等待Step更新 /// 服务器等待Step更新
/// </summary> /// </summary>
OnRoomWaitStepChange, OnRoomWaitStepChange,
/// <summary> /// <summary>
/// 当房间中手柄位信息发生任何变化时触发,进入房间后也应该触发 /// 当房间中手柄位信息发生任何变化时触发,进入房间后也应该触发
/// </summary> /// </summary>
OnRoomSlotDataChanged, OnRoomSlotDataChanged,
/// <summary> /// <summary>
/// 当手柄连接设置发生变化时触发 /// 当手柄连接设置发生变化时触发
@ -92,5 +92,5 @@
/// 网络即时存档删除 /// 网络即时存档删除
/// </summary> /// </summary>
OnNetGameSavDeleted, OnNetGameSavDeleted,
} }
} }

View File

@ -1,66 +1,66 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugProtobuf; using AxibugProtobuf;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client.Manager namespace AxibugEmuOnline.Client.Manager
{ {
public class AppEmu public class AppEmu
{ {
/// <summary> /// <summary>
/// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符 /// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符
/// 但是Equals方法可以,所以,这个接口判断为空请使用Equals /// 但是Equals方法可以,所以,这个接口判断为空请使用Equals
/// </summary> /// </summary>
private EmuCore m_emuCore; private EmuCore m_emuCore;
private IControllerSetuper m_controllerSetuper; private IControllerSetuper m_controllerSetuper;
/// <summary> /// <summary>
/// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符 /// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符
/// 但是Equals方法可以,所以,这个接口判断为空请使用Equals /// 但是Equals方法可以,所以,这个接口判断为空请使用Equals
/// </summary> /// </summary>
public EmuCore Core => m_emuCore; public EmuCore Core => m_emuCore;
public AppEmu() public AppEmu()
{ {
Eventer.Instance.RegisterEvent(EEvent.OnMineJoinRoom, OnSelfJoinRoom); Eventer.Instance.RegisterEvent(EEvent.OnMineJoinRoom, OnSelfJoinRoom);
} }
private void OnSelfJoinRoom() private void OnSelfJoinRoom()
{ {
//如果当前正在游戏中,就先结束游戏 //如果当前正在游戏中,就先结束游戏
if (m_emuCore != null) StopGame(); if (m_emuCore != null) StopGame();
var roomInfo = App.roomMgr.mineRoomMiniInfo; var roomInfo = App.roomMgr.mineRoomMiniInfo;
roomInfo.FetchRomFileInRoomInfo((_, romFile) => roomInfo.FetchRomFileInRoomInfo((_, romFile) =>
{ {
if (!romFile.RomReady) //这个rom并没有下载,所以取消进入房间 if (!romFile.RomReady) //这个rom并没有下载,所以取消进入房间
{ {
App.roomMgr.SendLeavnRoom(); App.roomMgr.SendLeavnRoom();
} }
else else
{ {
BeginGame(romFile); BeginGame(romFile);
} }
}); });
} }
public void BeginGame(RomFile romFile) public void BeginGame(RomFile romFile)
{ {
if (m_emuCore != null) return; if (m_emuCore != null) return;
switch (romFile.Platform) switch (romFile.Platform)
{ {
case RomPlatformType.Nes: case RomPlatformType.Nes:
m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("NES/NesEmulator")).GetComponent<EmuCore>(); m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("NES/NesEmulator")).GetComponent<EmuCore>();
break; break;
case RomPlatformType.Cps1: case RomPlatformType.Cps1:
case RomPlatformType.Cps2: case RomPlatformType.Cps2:
case RomPlatformType.Igs: case RomPlatformType.Igs:
case RomPlatformType.Neogeo: case RomPlatformType.Neogeo:
case RomPlatformType.ArcadeOld: case RomPlatformType.ArcadeOld:
m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("MAME/UMAME")).GetComponent<EmuCore>(); m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("MAME/UMAME")).GetComponent<EmuCore>();
break; break;
case RomPlatformType.MasterSystem: case RomPlatformType.MasterSystem:
case RomPlatformType.GameGear: case RomPlatformType.GameGear:
@ -68,22 +68,22 @@ namespace AxibugEmuOnline.Client.Manager
case RomPlatformType.GameBoyColor: case RomPlatformType.GameBoyColor:
case RomPlatformType.ColecoVision: case RomPlatformType.ColecoVision:
case RomPlatformType.Sc3000: case RomPlatformType.Sc3000:
case RomPlatformType.Sg1000: case RomPlatformType.Sg1000:
m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("EssgeeUnity/EssgeeUnity")).GetComponent<EmuCore>(); m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("EssgeeUnity/EssgeeUnity")).GetComponent<EmuCore>();
break; break;
case RomPlatformType.WonderSwan: case RomPlatformType.WonderSwan:
case RomPlatformType.WonderSwanColor: case RomPlatformType.WonderSwanColor:
m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("StoicGooseUnity/StoicGooseUnity")).GetComponent<EmuCore>(); m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("StoicGooseUnity/StoicGooseUnity")).GetComponent<EmuCore>();
break; break;
} }
var result = m_emuCore.StartGame(romFile); var result = m_emuCore.StartGame(romFile);
if (result) if (result)
{ {
LaunchUI.Instance.HideMainMenu(); LaunchUI.Instance.HideMainMenu();
InGameUI.Instance.Show(romFile, m_emuCore); InGameUI.Instance.Show(romFile, m_emuCore);
CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Gaming; CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Gaming;
m_controllerSetuper = m_emuCore.GetControllerSetuper(); m_controllerSetuper = m_emuCore.GetControllerSetuper();
@ -91,17 +91,17 @@ namespace AxibugEmuOnline.Client.Manager
m_controllerSetuper.SetConnect(con0ToSlot: 0); m_controllerSetuper.SetConnect(con0ToSlot: 0);
Eventer.Instance.PostEvent(EEvent.OnControllerConnectChanged); Eventer.Instance.PostEvent(EEvent.OnControllerConnectChanged);
Eventer.Instance.RegisterEvent(EEvent.OnRoomSlotDataChanged, OnSlotDataChanged); Eventer.Instance.RegisterEvent(EEvent.OnRoomSlotDataChanged, OnSlotDataChanged);
} }
else else
{ {
StopGame(); StopGame();
OverlayManager.PopTip(result); OverlayManager.PopTip(result);
} }
} }
private void OnSlotDataChanged() private void OnSlotDataChanged()
{ {
long selfUID = App.user.userdata.UID; long selfUID = App.user.userdata.UID;
uint? con0Slot; uint? con0Slot;
uint? con1Slot; uint? con1Slot;
@ -113,29 +113,29 @@ namespace AxibugEmuOnline.Client.Manager
App.roomMgr.mineRoomMiniInfo.GetPlayerSlotIdxByUid(selfUID, 2, out con2Slot); App.roomMgr.mineRoomMiniInfo.GetPlayerSlotIdxByUid(selfUID, 2, out con2Slot);
App.roomMgr.mineRoomMiniInfo.GetPlayerSlotIdxByUid(selfUID, 3, out con3Slot); App.roomMgr.mineRoomMiniInfo.GetPlayerSlotIdxByUid(selfUID, 3, out con3Slot);
m_controllerSetuper.SetConnect(con0Slot, con1Slot, con2Slot, con3Slot); m_controllerSetuper.SetConnect(con0Slot, con1Slot, con2Slot, con3Slot);
Eventer.Instance.PostEvent(EEvent.OnControllerConnectChanged); Eventer.Instance.PostEvent(EEvent.OnControllerConnectChanged);
} }
public void StopGame() public void StopGame()
{ {
if (m_emuCore == null) return; if (m_emuCore == null) return;
m_emuCore.Dispose(); m_emuCore.Dispose();
GameObject.Destroy(m_emuCore.gameObject); GameObject.Destroy(m_emuCore.gameObject);
m_emuCore = null; m_emuCore = null;
InGameUI.Instance.Hide(); InGameUI.Instance.Hide();
LaunchUI.Instance.ShowMainMenu(); LaunchUI.Instance.ShowMainMenu();
m_controllerSetuper = null; m_controllerSetuper = null;
Eventer.Instance.UnregisterEvent(EEvent.OnRoomSlotDataChanged, OnSlotDataChanged); Eventer.Instance.UnregisterEvent(EEvent.OnRoomSlotDataChanged, OnSlotDataChanged);
} }
public void ResetGame() public void ResetGame()
{ {
if (m_emuCore == null) return; if (m_emuCore == null) return;
m_emuCore.DoReset(); m_emuCore.DoReset();
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,24 @@
using AxibugEmuOnline.Client.Settings; using AxibugEmuOnline.Client.Settings;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class AppSettings public class AppSettings
{ {
/// <summary> 背景颜色设定 </summary> /// <summary> 背景颜色设定 </summary>
public BgColorSettings BgColor { get; private set; } public BgColorSettings BgColor { get; private set; }
/// <summary> 滤镜设置 </summary> /// <summary> 滤镜设置 </summary>
public FilterManager Filter { get; private set; } public FilterManager Filter { get; private set; }
/// <summary> 画面比例设置 </summary> /// <summary> 画面比例设置 </summary>
public ScreenScaler ScreenScaler { get; private set; } public ScreenScaler ScreenScaler { get; private set; }
/// <summary> 键位设置 </summary> /// <summary> 键位设置 </summary>
public KeyMapperSetting KeyMapper { get; private set; } public KeyMapperSetting KeyMapper { get; private set; }
public AppSettings() public AppSettings()
{ {
BgColor = new BgColorSettings(); BgColor = new BgColorSettings();
Filter = new FilterManager(); Filter = new FilterManager();
ScreenScaler = new ScreenScaler(); ScreenScaler = new ScreenScaler();
KeyMapper = new KeyMapperSetting(); KeyMapper = new KeyMapperSetting();
} }
} }
} }

View File

@ -1,16 +1,16 @@
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client.Filters namespace AxibugEmuOnline.Client.Filters
{ {
public class Filter1990_esque : FilterEffect public class Filter1990_esque : FilterEffect
{ {
public override string Name => "1990-esque"; public override string Name => "1990-esque";
protected override string ShaderName => "Filter/1990-esque"; protected override string ShaderName => "Filter/1990-esque";
protected override void OnRenderer(Material renderMat, Texture src, RenderTexture result) protected override void OnRenderer(Material renderMat, Texture src, RenderTexture result)
{ {
Graphics.Blit(src, result, renderMat, 1); Graphics.Blit(src, result, renderMat, 1);
} }
} }
} }

View File

@ -1,139 +1,139 @@
using Assets.Script.AppMain.Filter; using Assets.Script.AppMain.Filter;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public abstract class FilterEffect public abstract class FilterEffect
{ {
public bool Enable { get; set; } public bool Enable { get; set; }
[Range(0.1f, 4f)] [Range(0.1f, 4f)]
public FloatParameter RenderScale; public FloatParameter RenderScale;
public abstract string Name { get; } public abstract string Name { get; }
public IReadOnlyCollection<EditableParamerter> EditableParam => m_editableParamList.AsReadOnly(); public IReadOnlyCollection<EditableParamerter> EditableParam => m_editableParamList.AsReadOnly();
List<EditableParamerter> m_editableParamList; List<EditableParamerter> m_editableParamList;
Material m_material; Material m_material;
protected virtual float m_defaultRenderScale { get => 1f; } protected virtual float m_defaultRenderScale { get => 1f; }
protected abstract string ShaderName { get; } protected abstract string ShaderName { get; }
private static int m_iResolutionID = Shader.PropertyToID("_iResolution"); private static int m_iResolutionID = Shader.PropertyToID("_iResolution");
public FilterEffect() public FilterEffect()
{ {
RenderScale = new FloatParameter(m_defaultRenderScale); RenderScale = new FloatParameter(m_defaultRenderScale);
GetEditableFilterParamters(); GetEditableFilterParamters();
Init(); Init();
} }
protected virtual void Init() protected virtual void Init()
{ {
if (ShaderName != null) if (ShaderName != null)
{ {
var shader = Shader.Find(ShaderName); var shader = Shader.Find(ShaderName);
if (shader != null) m_material = new Material(Shader.Find(ShaderName)); if (shader != null) m_material = new Material(Shader.Find(ShaderName));
} }
OnInit(m_material); OnInit(m_material);
} }
protected virtual void OnInit(Material renderMat) { } protected virtual void OnInit(Material renderMat) { }
void GetEditableFilterParamters() void GetEditableFilterParamters()
{ {
var parameters = (from t in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public) var parameters = (from t in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)
where t.FieldType.IsSubclassOf(typeof(FilterParameter)) where t.FieldType.IsSubclassOf(typeof(FilterParameter))
orderby t.MetadataToken orderby t.MetadataToken
select t); select t);
m_editableParamList = new List<EditableParamerter>(); m_editableParamList = new List<EditableParamerter>();
foreach (var param in parameters) foreach (var param in parameters)
{ {
var paramObj = (FilterParameter)param.GetValue(this); var paramObj = (FilterParameter)param.GetValue(this);
var rangeAtt = param.GetCustomAttribute<RangeAttribute>(); var rangeAtt = param.GetCustomAttribute<RangeAttribute>();
float min = 0; float min = 0;
float max = 10; float max = 10;
if (rangeAtt != null) { min = rangeAtt.min; max = rangeAtt.max; } if (rangeAtt != null) { min = rangeAtt.min; max = rangeAtt.max; }
var descrip = param.GetCustomAttribute<DescriptionAttribute>(); var descrip = param.GetCustomAttribute<DescriptionAttribute>();
string name = descrip != null ? descrip.Description : param.Name; string name = descrip != null ? descrip.Description : param.Name;
var editableParam = new EditableParamerter(name, paramObj, min, max); var editableParam = new EditableParamerter(name, paramObj, min, max);
m_editableParamList.Add(editableParam); m_editableParamList.Add(editableParam);
} }
} }
public virtual void Render(Texture src, RenderTexture result) public virtual void Render(Texture src, RenderTexture result)
{ {
if (m_material != null) m_material.SetVector(m_iResolutionID, new Vector4(result.width, result.height)); if (m_material != null) m_material.SetVector(m_iResolutionID, new Vector4(result.width, result.height));
OnRenderer(m_material, src, result); OnRenderer(m_material, src, result);
} }
protected abstract void OnRenderer(Material renderMat, Texture src, RenderTexture result); protected abstract void OnRenderer(Material renderMat, Texture src, RenderTexture result);
public class EditableParamerter public class EditableParamerter
{ {
private FilterParameter m_paramObject; private FilterParameter m_paramObject;
public Type ValueType => m_paramObject.ValueType; public Type ValueType => m_paramObject.ValueType;
public string Name { get; private set; } public string Name { get; private set; }
public object Value public object Value
{ {
get => m_paramObject.Value; get => m_paramObject.Value;
set => m_paramObject.Value = value; set => m_paramObject.Value = value;
} }
public object MinValue { get; private set; } public object MinValue { get; private set; }
public object MaxValue { get; private set; } public object MaxValue { get; private set; }
public EditableParamerter(string name, FilterParameter paramObject, float minValue, float maxValue) public EditableParamerter(string name, FilterParameter paramObject, float minValue, float maxValue)
{ {
m_paramObject = paramObject; m_paramObject = paramObject;
Name = name; Name = name;
var paramType = paramObject.GetType(); var paramType = paramObject.GetType();
if (paramObject.ValueType == typeof(int)) if (paramObject.ValueType == typeof(int))
{ {
MinValue = (int)minValue; MinValue = (int)minValue;
MaxValue = (int)maxValue; MaxValue = (int)maxValue;
} }
else if (paramObject.ValueType == typeof(float)) else if (paramObject.ValueType == typeof(float))
{ {
MinValue = minValue; MinValue = minValue;
MaxValue = maxValue; MaxValue = maxValue;
} }
} }
public void ResetToDefault() => m_paramObject.Value = null; public void ResetToDefault() => m_paramObject.Value = null;
public void Apply(object overrideValue) public void Apply(object overrideValue)
{ {
Value = overrideValue; Value = overrideValue;
} }
} }
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
internal class StripAttribute : Attribute internal class StripAttribute : Attribute
{ {
HashSet<RuntimePlatform> m_stripPlats; HashSet<RuntimePlatform> m_stripPlats;
/// <summary> /// <summary>
/// 指示一个滤镜是否会在指定的平台被剔除 /// 指示一个滤镜是否会在指定的平台被剔除
/// </summary> /// </summary>
/// <param name="strip">会被剔除的平台</param> /// <param name="strip">会被剔除的平台</param>
public StripAttribute(params RuntimePlatform[] stripPlatform) public StripAttribute(params RuntimePlatform[] stripPlatform)
{ {
m_stripPlats = new HashSet<RuntimePlatform>(stripPlatform); m_stripPlats = new HashSet<RuntimePlatform>(stripPlatform);
} }
public bool NeedStrip => m_stripPlats.Contains(Application.platform); public bool NeedStrip => m_stripPlats.Contains(Application.platform);
} }
} }
} }

View File

@ -1,14 +1,14 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf; using AxibugProtobuf;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using static AxibugEmuOnline.Client.FilterEffect; using static AxibugEmuOnline.Client.FilterEffect;
namespace AxibugEmuOnline.Client.Settings namespace AxibugEmuOnline.Client.Settings
{ {
public class FilterManager public class FilterManager
{ {
@ -17,9 +17,9 @@ namespace AxibugEmuOnline.Client.Settings
private AlphaWraper m_previewFilterWraper; private AlphaWraper m_previewFilterWraper;
FilterRomSetting m_filterRomSetting; FilterRomSetting m_filterRomSetting;
/// <summary> /// <summary>
/// 滤镜列表 /// 滤镜列表
/// </summary> /// </summary>
public IReadOnlyList<Filter> Filters => m_filters; public IReadOnlyList<Filter> Filters => m_filters;
public FilterManager() public FilterManager()
@ -104,24 +104,24 @@ namespace AxibugEmuOnline.Client.Settings
} }
/// <summary> 关闭滤镜预览 </summary> /// <summary> 关闭滤镜预览 </summary>
public void ShutDownFilterPreview() public void ShutDownFilterPreview()
{ {
if (m_previewFilterWraper == null) m_previewFilterWraper = new AlphaWraper(Initer.XMBBg, Initer.FilterPreview, false); if (m_previewFilterWraper == null) m_previewFilterWraper = new AlphaWraper(Initer.XMBBg, Initer.FilterPreview, false);
m_previewFilterWraper.On = false; m_previewFilterWraper.On = false;
} }
/// <summary> 开启滤镜预览 </summary> /// <summary> 开启滤镜预览 </summary>
public void EnableFilterPreview() public void EnableFilterPreview()
{ {
if (m_previewFilterWraper == null) m_previewFilterWraper = new AlphaWraper(Initer.XMBBg, Initer.FilterPreview, false); if (m_previewFilterWraper == null) m_previewFilterWraper = new AlphaWraper(Initer.XMBBg, Initer.FilterPreview, false);
m_previewFilterWraper.On = true; m_previewFilterWraper.On = true;
} }
/// <summary> /// <summary>
/// 打开滤镜 /// 打开滤镜
/// </summary> /// </summary>
/// <param name="filter"></param> /// <param name="filter"></param>
public void EnableFilter(Filter filter) public void EnableFilter(Filter filter)
{ {
foreach (var selfFiler in Filters) foreach (var selfFiler in Filters)
@ -131,9 +131,9 @@ namespace AxibugEmuOnline.Client.Settings
} }
} }
/// <summary> /// <summary>
/// 关闭滤镜效果 /// 关闭滤镜效果
/// </summary> /// </summary>
public void ShutDownFilter() public void ShutDownFilter()
{ {
//关闭所有后处理效果 //关闭所有后处理效果
@ -141,12 +141,12 @@ namespace AxibugEmuOnline.Client.Settings
filter.m_setting.Enable = false; filter.m_setting.Enable = false;
} }
/// <summary> /// <summary>
/// 为指定rom设置滤镜以及滤镜的预设 /// 为指定rom设置滤镜以及滤镜的预设
/// </summary> /// </summary>
/// <param name="rom">rom对象</param> /// <param name="rom">rom对象</param>
/// <param name="filter">滤镜</param> /// <param name="filter">滤镜</param>
/// <param name="preset">滤镜预设</param> /// <param name="preset">滤镜预设</param>
public void SetupFilter(RomFile rom, Filter filter, FilterPreset preset) public void SetupFilter(RomFile rom, Filter filter, FilterPreset preset)
{ {
m_filterRomSetting.Setup(rom, filter, preset); m_filterRomSetting.Setup(rom, filter, preset);
@ -155,11 +155,11 @@ namespace AxibugEmuOnline.Client.Settings
AxiPlayerPrefs.SetString(nameof(FilterRomSetting), json); AxiPlayerPrefs.SetString(nameof(FilterRomSetting), json);
} }
/// <summary> /// <summary>
/// 获得指定rom配置的滤镜设置 /// 获得指定rom配置的滤镜设置
/// </summary> /// </summary>
/// <param name="rom">rom对象</param> /// <param name="rom">rom对象</param>
/// <returns>此元组任意内任意成员都有可能为空</returns> /// <returns>此元组任意内任意成员都有可能为空</returns>
public GetFilterSetting_result GetFilterSetting(RomFile rom) public GetFilterSetting_result GetFilterSetting(RomFile rom)
{ {
var value = m_filterRomSetting.Get(rom); var value = m_filterRomSetting.Get(rom);
@ -198,9 +198,9 @@ namespace AxibugEmuOnline.Client.Settings
{ {
public string Name => m_setting.Name; public string Name => m_setting.Name;
public IReadOnlyCollection<EditableParamerter> Paramerters => m_setting.EditableParam; public IReadOnlyCollection<EditableParamerter> Paramerters => m_setting.EditableParam;
/// <summary> 滤镜预设 </summary> /// <summary> 滤镜预设 </summary>
public List<FilterPreset> Presets = new List<FilterPreset>(); public List<FilterPreset> Presets = new List<FilterPreset>();
/// <summary> 滤镜默认预设 </summary> /// <summary> 滤镜默认预设 </summary>
public FilterPreset DefaultPreset = new FilterPreset("DEFAULT"); public FilterPreset DefaultPreset = new FilterPreset("DEFAULT");
internal FilterEffect m_setting; internal FilterEffect m_setting;
@ -445,5 +445,5 @@ namespace AxibugEmuOnline.Client.Settings
public string PresetName; public string PresetName;
} }
} }
} }
} }

View File

@ -1,33 +1,33 @@
using System; using System;
using UnityEngine; using UnityEngine;
namespace Assets.Script.AppMain.Filter namespace Assets.Script.AppMain.Filter
{ {
public abstract class FilterParameter public abstract class FilterParameter
{ {
public abstract Type ValueType { get; } public abstract Type ValueType { get; }
object m_overrideValue; object m_overrideValue;
protected object m_defaultValue; protected object m_defaultValue;
public object Value public object Value
{ {
get => m_overrideValue ?? m_defaultValue; get => m_overrideValue ?? m_defaultValue;
set => m_overrideValue = value; set => m_overrideValue = value;
} }
} }
public class FilterParameter<T> : FilterParameter public class FilterParameter<T> : FilterParameter
{ {
public override Type ValueType => typeof(T); public override Type ValueType => typeof(T);
public void Override(T value) public void Override(T value)
{ {
Value = value; Value = value;
} }
public T GetValue() => (T)Value; public T GetValue() => (T)Value;
public FilterParameter(T defaultValue) public FilterParameter(T defaultValue)
{ {
m_defaultValue = defaultValue; m_defaultValue = defaultValue;
} }
public static implicit operator T(FilterParameter<T> value) public static implicit operator T(FilterParameter<T> value)
@ -38,26 +38,26 @@ namespace Assets.Script.AppMain.Filter
public static implicit operator FilterParameter<T>(T value) public static implicit operator FilterParameter<T>(T value)
{ {
return new FilterParameter<T>(value); return new FilterParameter<T>(value);
} }
} }
public class BoolParameter : FilterParameter<bool> public class BoolParameter : FilterParameter<bool>
{ {
public BoolParameter(bool defaultValue) : base(defaultValue) { } public BoolParameter(bool defaultValue) : base(defaultValue) { }
public static implicit operator bool(BoolParameter value) public static implicit operator bool(BoolParameter value)
{ {
return value.GetValue(); return value.GetValue();
} }
public static implicit operator BoolParameter(bool value) public static implicit operator BoolParameter(bool value)
{ {
return new BoolParameter(value); return new BoolParameter(value);
} }
} }
public class Vector2Parameter : FilterParameter<Vector2> public class Vector2Parameter : FilterParameter<Vector2>
{ {
public Vector2Parameter(Vector2 defaultValue) : base(defaultValue) { } public Vector2Parameter(Vector2 defaultValue) : base(defaultValue) { }
public static implicit operator Vector2(Vector2Parameter value) public static implicit operator Vector2(Vector2Parameter value)
@ -68,13 +68,13 @@ namespace Assets.Script.AppMain.Filter
public static implicit operator Vector2Parameter(Vector2 value) public static implicit operator Vector2Parameter(Vector2 value)
{ {
return new Vector2Parameter(value); return new Vector2Parameter(value);
} }
} }
public class FloatParameter : FilterParameter<float> public class FloatParameter : FilterParameter<float>
{ {
public FloatParameter(float defaultValue) : base(defaultValue) { } public FloatParameter(float defaultValue) : base(defaultValue) { }
public static implicit operator float(FloatParameter value) public static implicit operator float(FloatParameter value)
{ {
return value.GetValue(); return value.GetValue();
@ -83,9 +83,9 @@ namespace Assets.Script.AppMain.Filter
public static implicit operator FloatParameter(float value) public static implicit operator FloatParameter(float value)
{ {
return new FloatParameter(value); return new FloatParameter(value);
} }
} }
public class IntParameter : FilterParameter<int> public class IntParameter : FilterParameter<int>
{ {
public IntParameter(int defaultValue) : base(defaultValue) { } public IntParameter(int defaultValue) : base(defaultValue) { }
@ -99,5 +99,5 @@ namespace Assets.Script.AppMain.Filter
{ {
return new IntParameter(value); return new IntParameter(value);
} }
} }
} }

View File

@ -1,16 +1,16 @@
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client.Filters namespace AxibugEmuOnline.Client.Filters
{ {
public sealed class LCDPostEffect : FilterEffect public sealed class LCDPostEffect : FilterEffect
{ {
public override string Name => nameof(LCDPostEffect); public override string Name => nameof(LCDPostEffect);
protected override string ShaderName => "Filter/LCDPostEffect"; protected override string ShaderName => "Filter/LCDPostEffect";
protected override void OnRenderer(Material renderMat, Texture src, RenderTexture result) protected override void OnRenderer(Material renderMat, Texture src, RenderTexture result)
{ {
Graphics.Blit(src, result, renderMat); Graphics.Blit(src, result, renderMat);
} }
} }
} }

View File

@ -1,16 +1,16 @@
using Assets.Script.AppMain.Filter; using Assets.Script.AppMain.Filter;
using AxibugEmuOnline.Client; using AxibugEmuOnline.Client;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace AxibugEmuOnline.Client.Filters namespace AxibugEmuOnline.Client.Filters
{ {
public sealed class MattiasCRT : FilterEffect public sealed class MattiasCRT : FilterEffect
{ {
public override string Name => nameof(MattiasCRT); public override string Name => nameof(MattiasCRT);
protected override string ShaderName => "Filter/MattiasCRT"; protected override string ShaderName => "Filter/MattiasCRT";
public FilterParameter<EnumQuality> Quality = new FilterParameter<EnumQuality>(EnumQuality.High); public FilterParameter<EnumQuality> Quality = new FilterParameter<EnumQuality>(EnumQuality.High);
private LocalKeyword _kw_qualityLow; private LocalKeyword _kw_qualityLow;
private LocalKeyword _kw_qualityMid; private LocalKeyword _kw_qualityMid;
@ -18,31 +18,31 @@ namespace AxibugEmuOnline.Client.Filters
protected override void OnInit(Material renderMat) protected override void OnInit(Material renderMat)
{ {
_kw_qualityLow = new LocalKeyword(renderMat.shader, "_QUALITY_LOW"); _kw_qualityLow = new LocalKeyword(renderMat.shader, "_QUALITY_LOW");
_kw_qualityMid = new LocalKeyword(renderMat.shader, "_QUALITY_MID"); _kw_qualityMid = new LocalKeyword(renderMat.shader, "_QUALITY_MID");
_kw_qualityHigh = new LocalKeyword(renderMat.shader, "_QUALITY_HIGH"); _kw_qualityHigh = new LocalKeyword(renderMat.shader, "_QUALITY_HIGH");
} }
protected override void OnRenderer(Material renderMat, Texture src, RenderTexture result) protected override void OnRenderer(Material renderMat, Texture src, RenderTexture result)
{ {
renderMat.DisableKeyword(_kw_qualityLow); renderMat.DisableKeyword(_kw_qualityLow);
renderMat.DisableKeyword(_kw_qualityMid); renderMat.DisableKeyword(_kw_qualityMid);
renderMat.DisableKeyword(_kw_qualityHigh); renderMat.DisableKeyword(_kw_qualityHigh);
switch (Quality.GetValue()) switch (Quality.GetValue())
{ {
case EnumQuality.Low: renderMat.EnableKeyword(_kw_qualityLow); break; case EnumQuality.Low: renderMat.EnableKeyword(_kw_qualityLow); break;
case EnumQuality.Mid: renderMat.EnableKeyword(_kw_qualityMid); break; case EnumQuality.Mid: renderMat.EnableKeyword(_kw_qualityMid); break;
case EnumQuality.High: renderMat.EnableKeyword(_kw_qualityHigh); break; case EnumQuality.High: renderMat.EnableKeyword(_kw_qualityHigh); break;
} }
Graphics.Blit(src, result, renderMat); Graphics.Blit(src, result, renderMat);
} }
public enum EnumQuality public enum EnumQuality
{ {
Low, Low,
Mid, Mid,
High High
} }
} }
} }

View File

@ -1,71 +1,71 @@
using Assets.Script.AppMain.Filter; using Assets.Script.AppMain.Filter;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace AxibugEmuOnline.Client.Filters namespace AxibugEmuOnline.Client.Filters
{ {
[Strip(RuntimePlatform.PSP2)] [Strip(RuntimePlatform.PSP2)]
public class RetroArchMattiasCRTGlow : FilterEffect public class RetroArchMattiasCRTGlow : FilterEffect
{ {
public override string Name => nameof(RetroArchMattiasCRTGlow); public override string Name => nameof(RetroArchMattiasCRTGlow);
protected override string ShaderName => "Filter/RetroArch/MattiasCRTWithGlow"; protected override string ShaderName => "Filter/RetroArch/MattiasCRTWithGlow";
[Range(0.02f, 20f)] [Range(0.02f, 20f)]
public FloatParameter InputGamma = new FloatParameter(11); public FloatParameter InputGamma = new FloatParameter(11);
[Range(0.02f, 1f)] [Range(0.02f, 1f)]
public FloatParameter GaussianWidth = new FloatParameter(0.4f); public FloatParameter GaussianWidth = new FloatParameter(0.4f);
[Range(0.02f, 1f)] [Range(0.02f, 1f)]
public FloatParameter ColorBoost = new FloatParameter(0.4f); public FloatParameter ColorBoost = new FloatParameter(0.4f);
[Range(0.02f, 1f)] [Range(0.02f, 1f)]
public FloatParameter GlowWhitePoint = new FloatParameter(0.4f); public FloatParameter GlowWhitePoint = new FloatParameter(0.4f);
[Range(0.1f, 6f)] [Range(0.1f, 6f)]
public FloatParameter GlowRolloff = new FloatParameter(2.2f); public FloatParameter GlowRolloff = new FloatParameter(2.2f);
[Range(0.05f, 0.8f)] [Range(0.05f, 0.8f)]
public FloatParameter GlowStrength = new FloatParameter(0.45f); public FloatParameter GlowStrength = new FloatParameter(0.45f);
[Range(0.02f, 2.6f)] [Range(0.02f, 2.6f)]
public FloatParameter MonitorGamma = new FloatParameter(2.2f); public FloatParameter MonitorGamma = new FloatParameter(2.2f);
int m_gamma_ID = Shader.PropertyToID("_gamma"); int m_gamma_ID = Shader.PropertyToID("_gamma");
int m_horiz_gauss_width_ID = Shader.PropertyToID("_horiz_gauss_width"); int m_horiz_gauss_width_ID = Shader.PropertyToID("_horiz_gauss_width");
int m_BOOST_ID = Shader.PropertyToID("_BOOST"); int m_BOOST_ID = Shader.PropertyToID("_BOOST");
int m_GLOW_WHITEPOINT_ID = Shader.PropertyToID("_GLOW_WHITEPOINT"); int m_GLOW_WHITEPOINT_ID = Shader.PropertyToID("_GLOW_WHITEPOINT");
int m_GLOW_ROLLOFF_ID = Shader.PropertyToID("_GLOW_ROLLOFF"); int m_GLOW_ROLLOFF_ID = Shader.PropertyToID("_GLOW_ROLLOFF");
int m_BLOOM_STRENGTH_ID = Shader.PropertyToID("_BLOOM_STRENGTH"); int m_BLOOM_STRENGTH_ID = Shader.PropertyToID("_BLOOM_STRENGTH");
int m_OUTPUT_GAMMA_ID = Shader.PropertyToID("_OUTPUT_GAMMA"); int m_OUTPUT_GAMMA_ID = Shader.PropertyToID("_OUTPUT_GAMMA");
CommandBuffer m_multipPassCmd; CommandBuffer m_multipPassCmd;
int m_wrapRT; int m_wrapRT;
protected override void OnInit(Material renderMat) protected override void OnInit(Material renderMat)
{ {
m_multipPassCmd = new CommandBuffer(); m_multipPassCmd = new CommandBuffer();
m_wrapRT = Shader.PropertyToID($"{Name}.WrapRT"); m_wrapRT = Shader.PropertyToID($"{Name}.WrapRT");
} }
protected override void OnRenderer(Material renderMat, Texture src, RenderTexture result) protected override void OnRenderer(Material renderMat, Texture src, RenderTexture result)
{ {
m_multipPassCmd.Clear(); m_multipPassCmd.Clear();
m_multipPassCmd.GetTemporaryRT(m_wrapRT, result.width, result.height); m_multipPassCmd.GetTemporaryRT(m_wrapRT, result.width, result.height);
renderMat.SetFloat(m_gamma_ID, InputGamma.GetValue()); renderMat.SetFloat(m_gamma_ID, InputGamma.GetValue());
renderMat.SetFloat(m_horiz_gauss_width_ID, GaussianWidth.GetValue()); renderMat.SetFloat(m_horiz_gauss_width_ID, GaussianWidth.GetValue());
renderMat.SetFloat(m_BOOST_ID, ColorBoost.GetValue()); renderMat.SetFloat(m_BOOST_ID, ColorBoost.GetValue());
renderMat.SetFloat(m_GLOW_WHITEPOINT_ID, GlowWhitePoint.GetValue()); renderMat.SetFloat(m_GLOW_WHITEPOINT_ID, GlowWhitePoint.GetValue());
renderMat.SetFloat(m_GLOW_ROLLOFF_ID, GlowRolloff.GetValue()); renderMat.SetFloat(m_GLOW_ROLLOFF_ID, GlowRolloff.GetValue());
renderMat.SetFloat(m_BLOOM_STRENGTH_ID, GlowStrength.GetValue()); renderMat.SetFloat(m_BLOOM_STRENGTH_ID, GlowStrength.GetValue());
renderMat.SetFloat(m_OUTPUT_GAMMA_ID, MonitorGamma.GetValue()); renderMat.SetFloat(m_OUTPUT_GAMMA_ID, MonitorGamma.GetValue());
m_multipPassCmd.Blit(src, result); m_multipPassCmd.Blit(src, result);
for (int i = 0; i < renderMat.shader.passCount; i++) for (int i = 0; i < renderMat.shader.passCount; i++)
{ {
m_multipPassCmd.Blit(result, m_wrapRT, renderMat, i); m_multipPassCmd.Blit(result, m_wrapRT, renderMat, i);
m_multipPassCmd.Blit(m_wrapRT, result); m_multipPassCmd.Blit(m_wrapRT, result);
} }
m_multipPassCmd.ReleaseTemporaryRT(m_wrapRT); m_multipPassCmd.ReleaseTemporaryRT(m_wrapRT);
Graphics.ExecuteCommandBuffer(m_multipPassCmd); Graphics.ExecuteCommandBuffer(m_multipPassCmd);
} }
} }
} }

View File

@ -147,6 +147,25 @@ namespace AxibugEmuOnline.Client.Settings
controller.SetBinding(EssgeeSingleKey.LEFT, device.JOYSTICK.Left, 1); controller.SetBinding(EssgeeSingleKey.LEFT, device.JOYSTICK.Left, 1);
controller.SetBinding(EssgeeSingleKey.RIGHT, device.JOYSTICK.Right, 1); controller.SetBinding(EssgeeSingleKey.RIGHT, device.JOYSTICK.Right, 1);
} }
public override void Bind(SwitchJoyCon_D device, ControllerBinder controller)
{
controller.SetBinding(EssgeeSingleKey.OPTION_1, device.Plus, 0);
controller.SetBinding(EssgeeSingleKey.OPTION_2, device.Minus, 0);
controller.SetBinding(EssgeeSingleKey.UP, device.Up, 0);
controller.SetBinding(EssgeeSingleKey.DOWN, device.Down, 0);
controller.SetBinding(EssgeeSingleKey.LEFT, device.Left, 0);
controller.SetBinding(EssgeeSingleKey.RIGHT, device.Right, 0);
controller.SetBinding(EssgeeSingleKey.BTN_1, device.A, 0);
controller.SetBinding(EssgeeSingleKey.BTN_2, device.B, 0);
controller.SetBinding(EssgeeSingleKey.BTN_3, device.X, 0);
controller.SetBinding(EssgeeSingleKey.BTN_4, device.Y, 0);
controller.SetBinding(EssgeeSingleKey.UP, device.LeftStick.Up, 1);
controller.SetBinding(EssgeeSingleKey.DOWN, device.LeftStick.Down, 1);
controller.SetBinding(EssgeeSingleKey.LEFT, device.LeftStick.Left, 1);
controller.SetBinding(EssgeeSingleKey.RIGHT, device.LeftStick.Right, 1);
}
} }
public class MasterSystemKeyBinding : EssgeeKeyBinding public class MasterSystemKeyBinding : EssgeeKeyBinding

View File

@ -158,6 +158,27 @@ namespace AxibugEmuOnline.Client.Settings
controller.SetBinding(UMAMEKSingleKey.LEFT, device.JOYSTICK.Left, 1); controller.SetBinding(UMAMEKSingleKey.LEFT, device.JOYSTICK.Left, 1);
controller.SetBinding(UMAMEKSingleKey.RIGHT, device.JOYSTICK.Right, 1); controller.SetBinding(UMAMEKSingleKey.RIGHT, device.JOYSTICK.Right, 1);
} }
public override void Bind(SwitchJoyCon_D device, ControllerBinder controller)
{
controller.SetBinding(UMAMEKSingleKey.INSERT_COIN, device.Minus, 0);
controller.SetBinding(UMAMEKSingleKey.GAMESTART, device.Plus, 0);
controller.SetBinding(UMAMEKSingleKey.UP, device.Up, 0);
controller.SetBinding(UMAMEKSingleKey.DOWN, device.Down, 0);
controller.SetBinding(UMAMEKSingleKey.LEFT, device.Left, 0);
controller.SetBinding(UMAMEKSingleKey.RIGHT, device.Right, 0);
controller.SetBinding(UMAMEKSingleKey.BTN_A, device.A, 0);
controller.SetBinding(UMAMEKSingleKey.BTN_B, device.B, 0);
controller.SetBinding(UMAMEKSingleKey.BTN_C, device.X, 0);
controller.SetBinding(UMAMEKSingleKey.BTN_D, device.Y, 0);
controller.SetBinding(UMAMEKSingleKey.BTN_E, device.LeftSL, 0);
controller.SetBinding(UMAMEKSingleKey.BTN_F, device.RightSL, 0);
controller.SetBinding(UMAMEKSingleKey.UP, device.LeftStick.Up, 1);
controller.SetBinding(UMAMEKSingleKey.DOWN, device.LeftStick.Down, 1);
controller.SetBinding(UMAMEKSingleKey.LEFT, device.LeftStick.Left, 1);
controller.SetBinding(UMAMEKSingleKey.RIGHT, device.LeftStick.Right, 1);
}
} }
public class NEOGEOKeyBinding : MAMEKeyBinding public class NEOGEOKeyBinding : MAMEKeyBinding

View File

@ -17,7 +17,8 @@ public abstract class EmuCoreBinder<T> : InternalEmuCoreBinder,
IDeviceBinder<T, DualShockController_D>, IDeviceBinder<T, DualShockController_D>,
IDeviceBinder<T, XboxController_D>, IDeviceBinder<T, XboxController_D>,
IDeviceBinder<T, PSVController_D>, IDeviceBinder<T, PSVController_D>,
IDeviceBinder<T, ScreenGamepad_D> IDeviceBinder<T, ScreenGamepad_D>,
IDeviceBinder<T, SwitchJoyCon_D>
where T : Enum where T : Enum
{ {
//每一个实例代表一个对应模拟器平台的控制器索引 //每一个实例代表一个对应模拟器平台的控制器索引
@ -84,6 +85,7 @@ public abstract class EmuCoreBinder<T> : InternalEmuCoreBinder,
else if (device is XboxController_D xbC) Bind(xbC, binding); else if (device is XboxController_D xbC) Bind(xbC, binding);
else if (device is PSVController_D psvC) Bind(psvC, binding); else if (device is PSVController_D psvC) Bind(psvC, binding);
else if (device is ScreenGamepad_D screenGamepad) Bind(screenGamepad, binding); else if (device is ScreenGamepad_D screenGamepad) Bind(screenGamepad, binding);
else if (device is SwitchJoyCon_D nsJoyCon) Bind(nsJoyCon, binding);
else throw new NotImplementedException($"{device.GetType()}"); else throw new NotImplementedException($"{device.GetType()}");
} }
@ -306,4 +308,5 @@ public abstract class EmuCoreBinder<T> : InternalEmuCoreBinder,
public abstract void Bind(XboxController_D device, ControllerBinder controller); public abstract void Bind(XboxController_D device, ControllerBinder controller);
public abstract void Bind(PSVController_D device, ControllerBinder controller); public abstract void Bind(PSVController_D device, ControllerBinder controller);
public abstract void Bind(ScreenGamepad_D device, ControllerBinder controller); public abstract void Bind(ScreenGamepad_D device, ControllerBinder controller);
public abstract void Bind(SwitchJoyCon_D device, ControllerBinder controller);
} }

View File

@ -121,5 +121,22 @@ namespace AxibugEmuOnline.Client.Settings
controller.SetBinding(EnumButtonType.UP, device.JOYSTICK.Up, 1); controller.SetBinding(EnumButtonType.UP, device.JOYSTICK.Up, 1);
controller.SetBinding(EnumButtonType.DOWN, device.JOYSTICK.Down, 1); controller.SetBinding(EnumButtonType.DOWN, device.JOYSTICK.Down, 1);
} }
public override void Bind(SwitchJoyCon_D device, ControllerBinder controller)
{
controller.SetBinding(EnumButtonType.LEFT, device.Left, 0);
controller.SetBinding(EnumButtonType.RIGHT, device.Right, 0);
controller.SetBinding(EnumButtonType.UP, device.Up, 0);
controller.SetBinding(EnumButtonType.DOWN, device.Down, 0);
controller.SetBinding(EnumButtonType.A, device.A, 0);
controller.SetBinding(EnumButtonType.B, device.B, 0);
controller.SetBinding(EnumButtonType.SELECT, device.Minus, 0);
controller.SetBinding(EnumButtonType.START, device.Plus, 0);
controller.SetBinding(EnumButtonType.MIC, device.RightSL, 0);
controller.SetBinding(EnumButtonType.LEFT, device.LeftStick.Left, 1);
controller.SetBinding(EnumButtonType.RIGHT, device.LeftStick.Right, 1);
controller.SetBinding(EnumButtonType.UP, device.LeftStick.Up, 1);
controller.SetBinding(EnumButtonType.DOWN, device.LeftStick.Down, 1);
}
} }
} }

View File

@ -112,5 +112,20 @@ namespace AxibugEmuOnline.Client
controller.SetBinding(EnumCommand.SelectItemRight, device.JOYSTICK.Right, 1); controller.SetBinding(EnumCommand.SelectItemRight, device.JOYSTICK.Right, 1);
controller.SetBinding(EnumCommand.SelectItemUp, device.JOYSTICK.Up, 1); controller.SetBinding(EnumCommand.SelectItemUp, device.JOYSTICK.Up, 1);
} }
public override void Bind(SwitchJoyCon_D device, ControllerBinder controller)
{
controller.SetBinding(EnumCommand.Back, device.A, 0);
controller.SetBinding(EnumCommand.Enter, device.B, 0);
controller.SetBinding(EnumCommand.OptionMenu, device.Plus, 0);
controller.SetBinding(EnumCommand.SelectItemDown, device.Down, 0);
controller.SetBinding(EnumCommand.SelectItemLeft, device.Left, 0);
controller.SetBinding(EnumCommand.SelectItemRight, device.Right, 0);
controller.SetBinding(EnumCommand.SelectItemUp, device.Up, 0);
controller.SetBinding(EnumCommand.SelectItemDown, device.LeftStick.Down, 1);
controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1);
controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1);
controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
}
} }
} }

View File

@ -1,136 +1,136 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class CacheManager public class CacheManager
{ {
static readonly string CacheDirPath = $"{App.PersistentDataRoot()}/Caches"; static readonly string CacheDirPath = $"{App.PersistentDataRoot()}/Caches";
static readonly string TextureCacheDirPath = $"{CacheDirPath}/Texture"; static readonly string TextureCacheDirPath = $"{CacheDirPath}/Texture";
public void GetSpriteCache(string url, Action<Sprite, string> callback) public void GetSpriteCache(string url, Action<Sprite, string> callback)
{
GetCacheData(url, TextureCacheDirPath, callback);
}
/// <summary> 移除文件缓存 </summary>
public void ClearCaches()
{
if (AxiIO.Directory.Exists(CacheDirPath))
AxiIO.Directory.Delete(CacheDirPath, true);
}
IEnumerator DownloadFromURL(string url, string path, Action<byte[]> callback)
{ {
AxiHttpProxy.SendDownLoadProxy request = AxiHttpProxy.GetDownLoad($"{App.httpAPI.WebHost}/{url}"); GetCacheData(url, TextureCacheDirPath, callback);
}
while (!request.downloadHandler.isDone)
{ /// <summary> 移除文件缓存 </summary>
yield return null; public void ClearCaches()
//Debug.Log($"下载进度:{respInfo.DownLoadPr} ->{respInfo.loadedLenght}/{respInfo.NeedloadedLenght}"); {
} if (AxiIO.Directory.Exists(CacheDirPath))
AxiIO.Directory.Delete(CacheDirPath, true);
}
IEnumerator DownloadFromURL(string url, string path, Action<byte[]> callback)
{
AxiHttpProxy.SendDownLoadProxy request = AxiHttpProxy.GetDownLoad($"{App.httpAPI.WebHost}/{url}");
while (!request.downloadHandler.isDone)
{
yield return null;
//Debug.Log($"下载进度:{respInfo.DownLoadPr} ->{respInfo.loadedLenght}/{respInfo.NeedloadedLenght}");
}
AxiHttpProxy.ShowAxiHttpDebugInfo(request.downloadHandler); AxiHttpProxy.ShowAxiHttpDebugInfo(request.downloadHandler);
if (!request.downloadHandler.bHadErr) if (!request.downloadHandler.bHadErr)
{ {
AxiIO.Directory.CreateDirectory(path); AxiIO.Directory.CreateDirectory(path);
AxiIO.File.WriteAllBytes($"{path}/{url.GetHashCode()}", request.downloadHandler.data, false); AxiIO.File.WriteAllBytes($"{path}/{url.GetHashCode()}", request.downloadHandler.data, false);
callback.Invoke(request.downloadHandler.data); callback.Invoke(request.downloadHandler.data);
} }
else else
{ {
callback.Invoke(null); callback.Invoke(null);
} }
/* /*
var request = UnityWebRequest.Get($"{App.httpAPI.WebHost}/{url}"); var request = UnityWebRequest.Get($"{App.httpAPI.WebHost}/{url}");
yield return request.SendWebRequest(); yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success) if (request.result == UnityWebRequest.Result.Success)
{ {
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
File.WriteAllBytes($"{path}/{url.GetHashCode()}", request.downloadHandler.data); File.WriteAllBytes($"{path}/{url.GetHashCode()}", request.downloadHandler.data);
callback.Invoke(request.downloadHandler.data); callback.Invoke(request.downloadHandler.data);
} }
else else
callback.Invoke(null); callback.Invoke(null);
*/ */
} }
private Dictionary<string, object> cachesInMemory = new Dictionary<string, object>(); private Dictionary<string, object> cachesInMemory = new Dictionary<string, object>();
void GetCacheData<T>(string url, string path, Action<T, string> callback) where T : class void GetCacheData<T>(string url, string path, Action<T, string> callback) where T : class
{ {
object cacheObj; object cacheObj;
if (cachesInMemory.TryGetValue(url, out cacheObj) && cacheObj is T) if (cachesInMemory.TryGetValue(url, out cacheObj) && cacheObj is T)
{ {
T obj = (T)cacheObj; T obj = (T)cacheObj;
callback.Invoke(obj, url); callback.Invoke(obj, url);
return; return;
} }
var fileName = $"{url.GetHashCode()}"; var fileName = $"{url.GetHashCode()}";
byte[] rawData = null; byte[] rawData = null;
var filePath = $"{path}/{fileName}"; var filePath = $"{path}/{fileName}";
if (AxiIO.File.Exists(filePath)) if (AxiIO.File.Exists(filePath))
{ {
rawData = AxiIO.File.ReadAllBytes(filePath); rawData = AxiIO.File.ReadAllBytes(filePath);
var @out = RawDataConvert<T>(rawData); var @out = RawDataConvert<T>(rawData);
cachesInMemory[url] = @out; cachesInMemory[url] = @out;
callback.Invoke(@out, url); callback.Invoke(@out, url);
} }
else else
{ {
App.StartCoroutine(DownloadFromURL(url, path, (data) => App.StartCoroutine(DownloadFromURL(url, path, (data) =>
{ {
var @out = RawDataConvert<T>(data); var @out = RawDataConvert<T>(data);
cachesInMemory[url] = @out; cachesInMemory[url] = @out;
callback.Invoke(@out, url); callback.Invoke(@out, url);
})); }));
} }
} }
Type t_texture2d = typeof(Texture2D); Type t_texture2d = typeof(Texture2D);
Type t_sprite = typeof(Sprite); Type t_sprite = typeof(Sprite);
Type t_byteArray = typeof(byte[]); Type t_byteArray = typeof(byte[]);
Type t_object = typeof(object); Type t_object = typeof(object);
T RawDataConvert<T>(byte[] data) where T : class T RawDataConvert<T>(byte[] data) where T : class
{ {
var vt = typeof(T); var vt = typeof(T);
if (vt == t_texture2d || vt == t_sprite) if (vt == t_texture2d || vt == t_sprite)
{ {
Texture2D texture = new Texture2D(2, 2); Texture2D texture = new Texture2D(2, 2);
if (data == null) if (data == null)
{ {
var errorSpr = Resources.Load<Sprite>("UIImage/error"); var errorSpr = Resources.Load<Sprite>("UIImage/error");
if (vt == t_texture2d) return errorSpr.texture as T; if (vt == t_texture2d) return errorSpr.texture as T;
else return errorSpr as T; else return errorSpr as T;
} }
else else
{ {
texture.LoadImage(data); texture.LoadImage(data);
if (vt == t_texture2d) return texture as T; if (vt == t_texture2d) return texture as T;
else return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f)) as T; else return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f)) as T;
} }
} }
else if (vt == t_byteArray) else if (vt == t_byteArray)
{ {
return data as T; return data as T;
} }
else else
{ {
return data as T; return data as T;
} }
throw new NotImplementedException($"{vt.Name}"); throw new NotImplementedException($"{vt.Name}");
} }
} }
} }

View File

@ -1,298 +1,298 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class HttpAPI public class HttpAPI
{ {
public string WebHost = "http://emu.axibug.com"; public string WebHost = "http://emu.axibug.com";
public string WebSiteApi => WebHost + "/api"; public string WebSiteApi => WebHost + "/api";
public delegate void GetRomListAPI(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType Platform, int page, int pageSize = 10); public delegate void GetRomListAPI(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType Platform, int page, int pageSize = 10);
public delegate void SearchRomListAPI(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType Platform, string searchKey, int page, int pageSize = 10); public delegate void SearchRomListAPI(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType Platform, string searchKey, int page, int pageSize = 10);
public delegate void GetStarRomListAPI(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, int page, int pageSize = 10); public delegate void GetStarRomListAPI(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, int page, int pageSize = 10);
public void GetRomList(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, int page, int pageSize = 10) public void GetRomList(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, int page, int pageSize = 10)
{ {
App.StartCoroutine(GetRomListFlow(platform, page, pageSize, callback)); App.StartCoroutine(GetRomListFlow(platform, page, pageSize, callback));
} }
public void SearchRomList(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, string searchKey, int page, int pageSize = 10) public void SearchRomList(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, string searchKey, int page, int pageSize = 10)
{ {
App.StartCoroutine(SearchRomListFlow(platform, searchKey, page, pageSize, callback)); App.StartCoroutine(SearchRomListFlow(platform, searchKey, page, pageSize, callback));
} }
private IEnumerator SearchRomListFlow(AxibugProtobuf.RomPlatformType platform, string searchKey, int page, int pageSize, Action<int, Resp_GameList> callback) private IEnumerator SearchRomListFlow(AxibugProtobuf.RomPlatformType platform, string searchKey, int page, int pageSize, Action<int, Resp_GameList> callback)
{ {
if (!string.IsNullOrEmpty(searchKey)) if (!string.IsNullOrEmpty(searchKey))
{ {
string oldsearch = searchKey; string oldsearch = searchKey;
//searchKey = System.Net.WebUtility.UrlEncode(searchKey); //searchKey = System.Net.WebUtility.UrlEncode(searchKey);
searchKey = AxiHttp.UrlEncode(searchKey); searchKey = AxiHttp.UrlEncode(searchKey);
App.log.Info($"search->{oldsearch} ->{searchKey}"); App.log.Info($"search->{oldsearch} ->{searchKey}");
//searchKey = HttpUtility.UrlDecode(searchKey); //searchKey = HttpUtility.UrlDecode(searchKey);
} }
//避免特殊字符和个别文字编码问题 //避免特殊字符和个别文字编码问题
//byte[] gb2312Bytes = Encoding.Default.GetBytes(searchKey); //byte[] gb2312Bytes = Encoding.Default.GetBytes(searchKey);
//byte[] utf8Bytes = Encoding.Convert(Encoding.Default, Encoding.UTF8, gb2312Bytes); //byte[] utf8Bytes = Encoding.Convert(Encoding.Default, Encoding.UTF8, gb2312Bytes);
//// 将UTF-8编码的字节数组转换回字符串此时是UTF-8编码的字符串 //// 将UTF-8编码的字节数组转换回字符串此时是UTF-8编码的字符串
//string utf8String = Encoding.UTF8.GetString(utf8Bytes); //string utf8String = Encoding.UTF8.GetString(utf8Bytes);
//searchKey = UrlEncode(utf8String); //searchKey = UrlEncode(utf8String);
//App.log.Info($"search->{utf8String} ->{searchKey}"); //App.log.Info($"search->{utf8String} ->{searchKey}");
string url = $"{WebSiteApi}/RomList?Page={page}&PageSize={pageSize}&PType={(int)platform}&SearchKey={searchKey}&Token={App.user.Token}"; string url = $"{WebSiteApi}/RomList?Page={page}&PageSize={pageSize}&PType={(int)platform}&SearchKey={searchKey}&Token={App.user.Token}";
App.log.Info($"GetRomList=>{url}"); App.log.Info($"GetRomList=>{url}");
AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get(url); AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get(url);
yield return request.SendWebRequest; yield return request.SendWebRequest;
if (!request.downloadHandler.isDone) if (!request.downloadHandler.isDone)
{ {
callback.Invoke(page, null); callback.Invoke(page, null);
yield break; yield break;
} }
if (!request.downloadHandler.bHadErr) if (!request.downloadHandler.bHadErr)
{ {
var resp = JsonUtility.FromJson<Resp_GameList>(request.downloadHandler.text); var resp = JsonUtility.FromJson<Resp_GameList>(request.downloadHandler.text);
callback.Invoke(page, resp); callback.Invoke(page, resp);
yield break; yield break;
} }
App.log.Error(request.downloadHandler.ErrInfo); App.log.Error(request.downloadHandler.ErrInfo);
callback.Invoke(page, null); callback.Invoke(page, null);
/* /*
UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/NesRomList?Page={page}&PageSize={pageSize}&SearchKey={searchKey}"); UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/NesRomList?Page={page}&PageSize={pageSize}&SearchKey={searchKey}");
yield return request.SendWebRequest(); yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success) if (request.result != UnityWebRequest.Result.Success)
{ {
callback.Invoke(null); callback.Invoke(null);
yield break; yield break;
}*/ }*/
} }
private IEnumerator GetRomListFlow(AxibugProtobuf.RomPlatformType platform, int page, int pageSize, Action<int, Resp_GameList> callback) private IEnumerator GetRomListFlow(AxibugProtobuf.RomPlatformType platform, int page, int pageSize, Action<int, Resp_GameList> callback)
{ {
string url = $"{WebSiteApi}/RomList?Page={page}&PageSize={pageSize}&PType={(int)platform}&Token={App.user.Token}"; string url = $"{WebSiteApi}/RomList?Page={page}&PageSize={pageSize}&PType={(int)platform}&Token={App.user.Token}";
App.log.Info($"GetRomList=>{url}"); App.log.Info($"GetRomList=>{url}");
AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get(url); AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get(url);
yield return request.SendWebRequest; yield return request.SendWebRequest;
if (!request.downloadHandler.isDone) if (!request.downloadHandler.isDone)
{ {
callback.Invoke(page, null); callback.Invoke(page, null);
yield break; yield break;
} }
//请求成功 //请求成功
if (!request.downloadHandler.bHadErr) if (!request.downloadHandler.bHadErr)
{ {
var resp = JsonUtility.FromJson<Resp_GameList>(request.downloadHandler.text); var resp = JsonUtility.FromJson<Resp_GameList>(request.downloadHandler.text);
callback.Invoke(page, resp); callback.Invoke(page, resp);
yield break; yield break;
} }
App.log.Error(request.downloadHandler.ErrInfo); App.log.Error(request.downloadHandler.ErrInfo);
callback.Invoke(page, null); callback.Invoke(page, null);
/* /*
UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/NesRomList?Page={page}&PageSize={pageSize}"); UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/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)
{ {
callback.Invoke(null); callback.Invoke(null);
yield break; yield break;
} }
*/ */
} }
public void GetMarkList(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, int page, int pageSize = 10) public void GetMarkList(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, int page, int pageSize = 10)
{ {
App.StartCoroutine(GetMarkListFlow(platform, page, pageSize, callback)); App.StartCoroutine(GetMarkListFlow(platform, page, pageSize, callback));
} }
public void SearchMarkList(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, string searchKey, int page, int pageSize = 10) public void SearchMarkList(Action<int, Resp_GameList> callback, AxibugProtobuf.RomPlatformType platform, string searchKey, int page, int pageSize = 10)
{ {
App.StartCoroutine(SearchMarkListFlow(platform, searchKey, page, pageSize, callback)); App.StartCoroutine(SearchMarkListFlow(platform, searchKey, page, pageSize, callback));
} }
private IEnumerator SearchMarkListFlow(AxibugProtobuf.RomPlatformType platform, string searchKey, int page, int pageSize, Action<int, Resp_GameList> callback) private IEnumerator SearchMarkListFlow(AxibugProtobuf.RomPlatformType platform, string searchKey, int page, int pageSize, Action<int, Resp_GameList> callback)
{ {
if (!string.IsNullOrEmpty(searchKey)) if (!string.IsNullOrEmpty(searchKey))
{ {
string oldsearch = searchKey; string oldsearch = searchKey;
//searchKey = System.Net.WebUtility.UrlEncode(searchKey); //searchKey = System.Net.WebUtility.UrlEncode(searchKey);
searchKey = AxiHttp.UrlEncode(searchKey); searchKey = AxiHttp.UrlEncode(searchKey);
App.log.Info($"search->{oldsearch} ->{searchKey}"); App.log.Info($"search->{oldsearch} ->{searchKey}");
//searchKey = HttpUtility.UrlDecode(searchKey); //searchKey = HttpUtility.UrlDecode(searchKey);
} }
//避免特殊字符和个别文字编码问题 //避免特殊字符和个别文字编码问题
//byte[] gb2312Bytes = Encoding.Default.GetBytes(searchKey); //byte[] gb2312Bytes = Encoding.Default.GetBytes(searchKey);
//byte[] utf8Bytes = Encoding.Convert(Encoding.Default, Encoding.UTF8, gb2312Bytes); //byte[] utf8Bytes = Encoding.Convert(Encoding.Default, Encoding.UTF8, gb2312Bytes);
//// 将UTF-8编码的字节数组转换回字符串此时是UTF-8编码的字符串 //// 将UTF-8编码的字节数组转换回字符串此时是UTF-8编码的字符串
//string utf8String = Encoding.UTF8.GetString(utf8Bytes); //string utf8String = Encoding.UTF8.GetString(utf8Bytes);
//searchKey = UrlEncode(utf8String); //searchKey = UrlEncode(utf8String);
//App.log.Info($"search->{utf8String} ->{searchKey}"); //App.log.Info($"search->{utf8String} ->{searchKey}");
string url = $"{WebSiteApi}/MarkList?Page={page}&PageSize={pageSize}&SearchKey={searchKey}&Token={App.user.Token}"; string url = $"{WebSiteApi}/MarkList?Page={page}&PageSize={pageSize}&SearchKey={searchKey}&Token={App.user.Token}";
App.log.Info($"MarkList=>{url}"); App.log.Info($"MarkList=>{url}");
AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get(url); AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get(url);
yield return request.SendWebRequest; yield return request.SendWebRequest;
if (!request.downloadHandler.isDone) if (!request.downloadHandler.isDone)
{ {
callback.Invoke(page, null); callback.Invoke(page, null);
yield break; yield break;
} }
if (!request.downloadHandler.bHadErr) if (!request.downloadHandler.bHadErr)
{ {
var resp = JsonUtility.FromJson<Resp_GameList>(request.downloadHandler.text); var resp = JsonUtility.FromJson<Resp_GameList>(request.downloadHandler.text);
callback.Invoke(page, resp); callback.Invoke(page, resp);
yield break; yield break;
} }
App.log.Error(request.downloadHandler.ErrInfo); App.log.Error(request.downloadHandler.ErrInfo);
callback.Invoke(page, null); callback.Invoke(page, null);
/* /*
UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/NesRomList?Page={page}&PageSize={pageSize}&SearchKey={searchKey}"); UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/NesRomList?Page={page}&PageSize={pageSize}&SearchKey={searchKey}");
yield return request.SendWebRequest(); yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success) if (request.result != UnityWebRequest.Result.Success)
{ {
callback.Invoke(null); callback.Invoke(null);
yield break; yield break;
}*/ }*/
} }
private IEnumerator GetMarkListFlow(AxibugProtobuf.RomPlatformType platform, int page, int pageSize, Action<int, Resp_GameList> callback) private IEnumerator GetMarkListFlow(AxibugProtobuf.RomPlatformType platform, int page, int pageSize, Action<int, Resp_GameList> callback)
{ {
string url = $"{WebSiteApi}/MarkList?Page={page}&PageSize={pageSize}&PType={(int)platform}&Token={App.user.Token}"; string url = $"{WebSiteApi}/MarkList?Page={page}&PageSize={pageSize}&PType={(int)platform}&Token={App.user.Token}";
App.log.Info($"MarkList=>{url}"); App.log.Info($"MarkList=>{url}");
AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get(url); AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get(url);
yield return request.SendWebRequest; yield return request.SendWebRequest;
if (!request.downloadHandler.isDone) if (!request.downloadHandler.isDone)
{ {
callback.Invoke(page, null); callback.Invoke(page, null);
yield break; yield break;
} }
//请求成功 //请求成功
if (!request.downloadHandler.bHadErr) if (!request.downloadHandler.bHadErr)
{ {
var resp = JsonUtility.FromJson<Resp_GameList>(request.downloadHandler.text); var resp = JsonUtility.FromJson<Resp_GameList>(request.downloadHandler.text);
callback.Invoke(page, resp); callback.Invoke(page, resp);
yield break; yield break;
} }
App.log.Error(request.downloadHandler.ErrInfo); App.log.Error(request.downloadHandler.ErrInfo);
callback.Invoke(page, null); callback.Invoke(page, null);
/* /*
UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/NesRomList?Page={page}&PageSize={pageSize}"); UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/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)
{ {
callback.Invoke(null); callback.Invoke(null);
yield break; yield break;
} }
*/ */
} }
public IEnumerator GetRomInfo(int RomID, Action<Resp_RomInfo> callback) public IEnumerator GetRomInfo(int RomID, Action<Resp_RomInfo> callback)
{ {
AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get($"{WebSiteApi}/RomInfo?RomID={RomID}&Token={App.user.Token}"); AxiHttpProxy.SendWebRequestProxy request = AxiHttpProxy.Get($"{WebSiteApi}/RomInfo?RomID={RomID}&Token={App.user.Token}");
yield return request.SendWebRequest; yield return request.SendWebRequest;
if (!request.downloadHandler.isDone) if (!request.downloadHandler.isDone)
{ {
callback.Invoke(null); callback.Invoke(null);
yield break; yield break;
} }
//成功 //成功
if (!request.downloadHandler.bHadErr) if (!request.downloadHandler.bHadErr)
{ {
var resp = JsonUtility.FromJson<Resp_RomInfo>(request.downloadHandler.text); var resp = JsonUtility.FromJson<Resp_RomInfo>(request.downloadHandler.text);
callback.Invoke(resp); callback.Invoke(resp);
yield break; yield break;
} }
App.log.Error(request.downloadHandler.ErrInfo); App.log.Error(request.downloadHandler.ErrInfo);
callback.Invoke(null); callback.Invoke(null);
/* /*
UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/RomInfo?PType={PlatformType.Nes}&RomID={RomID}"); UnityWebRequest request = UnityWebRequest.Get($"{WebSiteApi}/RomInfo?PType={PlatformType.Nes}&RomID={RomID}");
yield return request.SendWebRequest(); yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success) if (request.result != UnityWebRequest.Result.Success)
{ {
callback.Invoke(null); callback.Invoke(null);
yield break; yield break;
}*/ }*/
} }
enum GameType : byte enum GameType : byte
{ {
NONE = 0, NONE = 0,
ACT, ACT,
ARPG, ARPG,
AVG, AVG,
ETC, ETC,
FTG, FTG,
PUZ, PUZ,
RAC, RAC,
RPG, RPG,
SLG, SLG,
SPG, SPG,
SRPG, SRPG,
STG, STG,
TAB, TAB,
/// <summary> /// <summary>
/// 合卡 /// 合卡
/// </summary> /// </summary>
ALLINONE, ALLINONE,
} }
[Serializable] [Serializable]
public class Resp_GameList public class Resp_GameList
{ {
public int page; public int page;
public int maxPage; public int maxPage;
public int resultAllCount; public int resultAllCount;
public List<Resp_RomInfo> gameList; public List<Resp_RomInfo> gameList;
} }
[Serializable] [Serializable]
public class Resp_RomInfo public class Resp_RomInfo
{ {
public int orderid; public int orderid;
public int id; public int id;
//TODO 后续根据ptype启动游戏时选择核心。和列表设计和UI分组解耦比如无视平台搜索列表收藏列表 //TODO 后续根据ptype启动游戏时选择核心。和列表设计和UI分组解耦比如无视平台搜索列表收藏列表
public int ptype; public int ptype;
public string romName; public string romName;
public string gType; public string gType;
public string desc; public string desc;
public string url; public string url;
public string imgUrl; public string imgUrl;
public string hash; public string hash;
public int stars; public int stars;
/// <summary> /// <summary>
/// 游玩计数 /// 游玩计数
/// </summary> /// </summary>
public int playcount; public int playcount;
/// <summary> /// <summary>
/// 是否收藏 /// 是否收藏
/// </summary> /// </summary>
public int isStar; public int isStar;
public List<int> parentRomIdsList; public List<int> parentRomIdsList;
} }
[Serializable] [Serializable]
public class Resp_CheckStandInfo public class Resp_CheckStandInfo
{ {
public int needUpdateClient; public int needUpdateClient;
public string serverIp; public string serverIp;
public ushort serverPort; public ushort serverPort;
public string clientVersion; public string clientVersion;
public string downLoadUrl; public string downLoadUrl;
} }
} }
} }

View File

@ -73,32 +73,48 @@ namespace AxibugEmuOnline.Client.InputDevices
{ {
return m_devices.Values; return m_devices.Values;
} }
List<string> templog = new List<string>();
/// <summary> 由外部驱动的逻辑更新入口 </summary> /// <summary> 由外部驱动的逻辑更新入口 </summary>
public void Update() public void Update()
{ {
foreach (var device in m_devices.Values) device.Update(); foreach (var device in m_devices.Values) device.Update();
DebugInputSystem(); //string HadDrive = "";
} //foreach (var device in InputSystem.devices)
//{
// if (device is Mouse)
// continue;
// bool bhadflag = false;
private static void DebugInputSystem() // templog.Clear();
{ // for (int i = 0; i < device.allControls.Count; i++)
return; // {
#if ENABLE_INPUT_SYSTEM // if (device.allControls[i].IsPressed(0))
foreach (var device in InputSystem.devices) // {
{ // if (device.allControls[i].name.ToLower() == "anykey")
if (device is Mouse) // continue;
continue; // bhadflag = true;
for (int i = 0; i < device.allControls.Count; i++) // string keyname = $"{device.allControls[i].GetType().FullName}|{device.allControls[i].name},";
{ // templog.Add(keyname);
if (device.allControls[i].IsPressed(0)) // }
{ // }
Debug.Log($"{device.displayName}| {device.allControls[i].displayName}|{device.allControls[i].name}");
} // if (bhadflag)
} // {
} // HadDrive += $" D:{device.GetType().FullName}|{device.GetType().BaseType.FullName}|{device.name}, K:";
#endif // foreach (var s in templog)
// {
// HadDrive += s;
// }
// }
//}
//if (!string.IsNullOrEmpty(HadDrive))
//{
// Debug.Log($"Had Drive: {HadDrive}");
//}
} }
} }
} }

View File

@ -1,22 +1,22 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugProtobuf; using AxibugProtobuf;
using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class RomFile public class RomFile
{ {
private HttpAPI.Resp_RomInfo webData; private HttpAPI.Resp_RomInfo webData;
/// <summary> 依赖的Rom文件 </summary> /// <summary> 依赖的Rom文件 </summary>
private List<RomFile> dependencies = new List<RomFile>(); private List<RomFile> dependencies = new List<RomFile>();
RomPlatformType m_defaultPlatform; RomPlatformType m_defaultPlatform;
/// <summary> 指示该Rom是否是多文件Rom </summary> /// <summary> 指示该Rom是否是多文件Rom </summary>
public bool MultiFileRom public bool MultiFileRom
{ {
get get
@ -41,10 +41,10 @@ namespace AxibugEmuOnline.Client
default: throw new NotImplementedException($"未实现的平台{Platform}"); default: throw new NotImplementedException($"未实现的平台{Platform}");
} }
} }
} }
public string FileExtentionName public string FileExtentionName
{ {
get get
{ {
switch (Platform) switch (Platform)
@ -63,10 +63,10 @@ namespace AxibugEmuOnline.Client
default: throw new NotImplementedException($"未实现的平台{Platform}"); default: throw new NotImplementedException($"未实现的平台{Platform}");
} }
} }
} }
bool m_hasLocalFile; bool m_hasLocalFile;
public bool HasLocalFile public bool HasLocalFile
{ {
get get
@ -80,12 +80,12 @@ namespace AxibugEmuOnline.Client
return true; return true;
} }
} }
/// <summary> 指示该Rom文件的存放路径 </summary> /// <summary> 指示该Rom文件的存放路径 </summary>
public string LocalFilePath => $"{App.PersistentDataPath(Platform)}/RemoteRoms/{FileName}"; public string LocalFilePath => $"{App.PersistentDataPath(Platform)}/RemoteRoms/{FileName}";
/// <summary> 指示该Rom文件是否已下载完毕 </summary> /// <summary> 指示该Rom文件是否已下载完毕 </summary>
public bool RomReady public bool RomReady
{ {
get get
@ -99,8 +99,8 @@ namespace AxibugEmuOnline.Client
return true; return true;
} }
} }
/// <summary> 指示是否正在下载Rom文件 </summary> /// <summary> 指示是否正在下载Rom文件 </summary>
public bool IsDownloading public bool IsDownloading
{ {
get get
@ -141,10 +141,10 @@ namespace AxibugEmuOnline.Client
return progress / (dependencies.Count + 1); return progress / (dependencies.Count + 1);
} }
} }
public RomPlatformType Platform => webData != null ? (RomPlatformType)webData.ptype : m_defaultPlatform; public RomPlatformType Platform => webData != null ? (RomPlatformType)webData.ptype : m_defaultPlatform;
/// <summary> 指示该Rom信息是否已填充 </summary> /// <summary> 指示该Rom信息是否已填充 </summary>
public bool InfoReady public bool InfoReady
{ {
get get
@ -158,23 +158,23 @@ namespace AxibugEmuOnline.Client
return true; return true;
} }
} }
/// <summary> 唯一标识 </summary> /// <summary> 唯一标识 </summary>
public int ID => webData != null ? webData.id : -1; public int ID => webData != null ? webData.id : -1;
/// <summary> 别名 </summary> /// <summary> 别名 </summary>
public string Alias => webData.romName; public string Alias => webData.romName;
/// <summary> 描述 </summary> /// <summary> 描述 </summary>
public string Descript => webData.desc; public string Descript => webData.desc;
/// <summary> 游戏类型 </summary> /// <summary> 游戏类型 </summary>
public string GameTypeDes => webData.gType; public string GameTypeDes => webData.gType;
/// <summary> 小图URL </summary> /// <summary> 小图URL </summary>
public string ImageURL => webData.imgUrl; public string ImageURL => webData.imgUrl;
/// <summary> 文件名 </summary> /// <summary> 文件名 </summary>
public string FileName { get; private set; } public string FileName { get; private set; }
/// <summary> 在查询结果中的索引 </summary> /// <summary> 在查询结果中的索引 </summary>
public int Index { get; private set; } public int Index { get; private set; }
/// <summary> 在查询结果中的所在页 </summary> /// <summary> 在查询结果中的所在页 </summary>
public int Page { get; private set; } public int Page { get; private set; }
public string Hash => webData != null ? webData.hash : string.Empty; public string Hash => webData != null ? webData.hash : string.Empty;
@ -189,16 +189,16 @@ namespace AxibugEmuOnline.Client
} }
} }
public event Action<RomFile> OnDownloadOver; public event Action<RomFile> OnDownloadOver;
public event Action OnInfoFilled; public event Action OnInfoFilled;
public RomFile(int index, int insidePage, RomPlatformType defaultPlatform) public RomFile(int index, int insidePage, RomPlatformType defaultPlatform)
{ {
Index = index; Index = index;
Page = insidePage; Page = insidePage;
m_defaultPlatform = defaultPlatform; m_defaultPlatform = defaultPlatform;
} }
public void CheckLocalFileState() public void CheckLocalFileState()
{ {
if (webData == null) m_hasLocalFile = false; if (webData == null) m_hasLocalFile = false;
@ -215,22 +215,22 @@ namespace AxibugEmuOnline.Client
foreach (var depRom in dependencies) foreach (var depRom in dependencies)
depRom.CheckLocalFileState(); depRom.CheckLocalFileState();
} }
public void BeginDownload() public void BeginDownload()
{ {
if (RomReady) return; if (RomReady) return;
if (IsDownloading) return; if (IsDownloading) return;
//检查依赖Rom的下载情况 //检查依赖Rom的下载情况
foreach (var depRom in dependencies) foreach (var depRom in dependencies)
{ {
depRom.BeginDownload(); depRom.BeginDownload();
} }
App.FileDownloader.BeginDownload(webData.url, (bytes) => App.FileDownloader.BeginDownload(webData.url, (bytes) =>
{ {
HandleRomFilePostProcess(bytes); HandleRomFilePostProcess(bytes);
}); });
} }
private void HandleRomFilePostProcess(byte[] bytes) private void HandleRomFilePostProcess(byte[] bytes)
@ -244,23 +244,23 @@ namespace AxibugEmuOnline.Client
var zip = new ZipInputStream(new System.IO.MemoryStream(bytes)); var zip = new ZipInputStream(new System.IO.MemoryStream(bytes));
List<string> depth0Files = new List<string>(); List<string> depth0Files = new List<string>();
while (true) while (true)
{ {
var currentEntry = zip.GetNextEntry(); var currentEntry = zip.GetNextEntry();
if (currentEntry == null) break; if (currentEntry == null) break;
if (currentEntry.IsDirectory) continue; if (currentEntry.IsDirectory) continue;
var buffer = new byte[1024]; var buffer = new byte[1024];
System.IO.MemoryStream output = new System.IO.MemoryStream(); System.IO.MemoryStream output = new System.IO.MemoryStream();
while (true) while (true)
{ {
var size = zip.Read(buffer, 0, buffer.Length); var size = zip.Read(buffer, 0, buffer.Length);
if (size == 0) break; if (size == 0) break;
else output.Write(buffer, 0, size); else output.Write(buffer, 0, size);
} }
output.Flush(); output.Flush();
unzipFiles[$"{LocalFilePath}/{currentEntry.Name}"] = output.ToArray(); unzipFiles[$"{LocalFilePath}/{currentEntry.Name}"] = output.ToArray();
} }
string rootDirName = null; string rootDirName = null;
@ -289,50 +289,50 @@ namespace AxibugEmuOnline.Client
OnDownloadOver?.Invoke(this); OnDownloadOver?.Invoke(this);
} }
public byte[] GetRomFileData() public byte[] GetRomFileData()
{ {
Debug.Assert(!MultiFileRom, "仅供单文件Rom使用的接口"); Debug.Assert(!MultiFileRom, "仅供单文件Rom使用的接口");
if (webData == null) throw new Exception("Not Valid Rom"); if (webData == null) throw new Exception("Not Valid Rom");
if (!RomReady) throw new Exception("Rom File Not Downloaded"); if (!RomReady) throw new Exception("Rom File Not Downloaded");
var bytes = AxiIO.File.ReadAllBytes(LocalFilePath); var bytes = AxiIO.File.ReadAllBytes(LocalFilePath);
if (System.IO.Path.GetExtension(LocalFilePath).ToLower() == ".zip") if (System.IO.Path.GetExtension(LocalFilePath).ToLower() == ".zip")
{ {
var zip = new ZipInputStream(new System.IO.MemoryStream(bytes)); var zip = new ZipInputStream(new System.IO.MemoryStream(bytes));
while (true) while (true)
{ {
var currentEntry = zip.GetNextEntry(); var currentEntry = zip.GetNextEntry();
if (currentEntry == null) break; if (currentEntry == null) break;
//当前平台单文件rom扩展名判断 //当前平台单文件rom扩展名判断
if (!currentEntry.Name.ToLower().EndsWith(FileExtentionName)) continue; if (!currentEntry.Name.ToLower().EndsWith(FileExtentionName)) continue;
var buffer = new byte[1024]; var buffer = new byte[1024];
System.IO.MemoryStream output = new System.IO.MemoryStream(); System.IO.MemoryStream output = new System.IO.MemoryStream();
while (true) while (true)
{ {
var size = zip.Read(buffer, 0, buffer.Length); var size = zip.Read(buffer, 0, buffer.Length);
if (size == 0) break; if (size == 0) break;
else output.Write(buffer, 0, size); else output.Write(buffer, 0, size);
} }
output.Flush(); output.Flush();
return output.ToArray(); return output.ToArray();
} }
} }
else else
{ {
return bytes; return bytes;
} }
throw new Exception("Not Valid Rom Data"); throw new Exception("Not Valid Rom Data");
} }
public void SetWebData(HttpAPI.Resp_RomInfo resp_RomInfo) public void SetWebData(HttpAPI.Resp_RomInfo resp_RomInfo)
{ {
webData = resp_RomInfo; webData = resp_RomInfo;
FileName = MultiFileRom ? System.IO.Path.GetFileNameWithoutExtension(webData.url) : System.IO.Path.GetFileName(webData.url); FileName = MultiFileRom ? System.IO.Path.GetFileNameWithoutExtension(webData.url) : System.IO.Path.GetFileName(webData.url);
FileName = System.Net.WebUtility.UrlDecode(FileName); FileName = System.Net.WebUtility.UrlDecode(FileName);
//收集依赖Rom //收集依赖Rom
if (webData.parentRomIdsList != null) if (webData.parentRomIdsList != null)
@ -349,9 +349,9 @@ namespace AxibugEmuOnline.Client
} }
} }
CheckLocalFileState(); CheckLocalFileState();
App.StartCoroutine(WaitInfoReady()); App.StartCoroutine(WaitInfoReady());
} }
private IEnumerator WaitInfoReady() private IEnumerator WaitInfoReady()
@ -359,6 +359,6 @@ namespace AxibugEmuOnline.Client
while (!InfoReady) yield return null; while (!InfoReady) yield return null;
OnInfoFilled?.Invoke(); OnInfoFilled?.Invoke();
} }
} }
} }

View File

@ -1,20 +1,20 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Common; using AxibugEmuOnline.Client.Common;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugProtobuf; using AxibugProtobuf;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using static AxibugEmuOnline.Client.HttpAPI; using static AxibugEmuOnline.Client.HttpAPI;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class RomLib public class RomLib
{ {
/// <summary> Rom请求,一页的大小 </summary> /// <summary> Rom请求,一页的大小 </summary>
private const int PAGE_SIZE = 10; private const int PAGE_SIZE = 10;
/// <summary> 请求指令 </summary> /// <summary> 请求指令 </summary>
private HashSet<int> FetchPageCmd = new HashSet<int>(); private HashSet<int> FetchPageCmd = new HashSet<int>();
private RomFile[] RomFetchList; private RomFile[] RomFetchList;
private Dictionary<int, RomFile> RomFileIdMapper = new Dictionary<int, RomFile>(); private Dictionary<int, RomFile> RomFileIdMapper = new Dictionary<int, RomFile>();
@ -57,23 +57,23 @@ namespace AxibugEmuOnline.Client
return romFile; return romFile;
} }
/// <summary> 清除所有下载的Rom文件 </summary> /// <summary> 清除所有下载的Rom文件 </summary>
public void ClearRomFile() public void ClearRomFile()
{ {
var path = $"{App.PersistentDataPath(m_platform)}/RemoteRoms"; var path = $"{App.PersistentDataPath(m_platform)}/RemoteRoms";
if (AxiIO.Directory.Exists(path)) AxiIO.Directory.Delete(path, true); if (AxiIO.Directory.Exists(path)) AxiIO.Directory.Delete(path, true);
} }
/// <summary> 移除一个已下载的Rom </summary> /// <summary> 移除一个已下载的Rom </summary>
public void RemoveOneRomFile(RomFile romFile) public void RemoveOneRomFile(RomFile romFile)
{ {
if (romFile.RomReady) if (romFile.RomReady)
AxiIO.File.Delete(romFile.LocalFilePath); AxiIO.File.Delete(romFile.LocalFilePath);
} }
/// <summary> /// <summary>
/// 获得所有Rom文件 /// 获得所有Rom文件
/// </summary> /// </summary>
public void FetchRomCount(Action<RomFile[]> callback, string searchKey = null) public void FetchRomCount(Action<RomFile[]> callback, string searchKey = null)
{ {
lastSearchKey = searchKey; lastSearchKey = searchKey;
@ -186,5 +186,5 @@ namespace AxibugEmuOnline.Client
{ {
RomFileNameMapper[rom.FileName] = rom; RomFileNameMapper[rom.FileName] = rom;
} }
} }
} }

View File

@ -1,126 +1,126 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Common; using AxibugEmuOnline.Client.Common;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.Network; using AxibugEmuOnline.Client.Network;
using AxibugProtobuf; using AxibugProtobuf;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
/// <summary> /// <summary>
/// 负责存档的云端保存和获取功能 /// 负责存档的云端保存和获取功能
/// </summary> /// </summary>
public class SavCloudApi public class SavCloudApi
{ {
public delegate void OnFetchGameSavListHandle(int romID, Protobuf_Mine_GameSavInfo[] savSlotData); public delegate void OnFetchGameSavListHandle(int romID, Protobuf_Mine_GameSavInfo[] savSlotData);
public event OnFetchGameSavListHandle OnFetchGameSavList; public event OnFetchGameSavListHandle OnFetchGameSavList;
public delegate void OnUploadedSavDataHandle(int romID, int slotIndex, Protobuf_Mine_GameSavInfo savInfo); public delegate void OnUploadedSavDataHandle(int romID, int slotIndex, Protobuf_Mine_GameSavInfo savInfo);
public event OnUploadedSavDataHandle OnUploadedSavData; public event OnUploadedSavDataHandle OnUploadedSavData;
public SavCloudApi() public SavCloudApi()
{ {
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdGamesavGetGameSavList, RecvGetGameSavList); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdGamesavGetGameSavList, RecvGetGameSavList);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdGamesavDelGameSav, RecvDelGameSavList); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdGamesavDelGameSav, RecvDelGameSavList);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdGamesavUploadGameSav, RecvUpLoadGameSav); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdGamesavUploadGameSav, RecvUpLoadGameSav);
} }
private HashSet<int> m_fetchingRomIDs = new HashSet<int>(); private HashSet<int> m_fetchingRomIDs = new HashSet<int>();
/// <summary> /// <summary>
/// 发送请求即时存档列表 /// 发送请求即时存档列表
/// </summary> /// </summary>
/// <param name="RomID"></param> /// <param name="RomID"></param>
public void SendGetGameSavList(int RomID) public void SendGetGameSavList(int RomID)
{ {
if (m_fetchingRomIDs.Contains(RomID)) return; if (m_fetchingRomIDs.Contains(RomID)) return;
Protobuf_Mine_GetGameSavList req = new Protobuf_Mine_GetGameSavList() Protobuf_Mine_GetGameSavList req = new Protobuf_Mine_GetGameSavList()
{ {
RomID = RomID, RomID = RomID,
}; };
App.log.Info($"SendGetGameSavList"); App.log.Info($"SendGetGameSavList");
App.network.SendToServer((int)CommandID.CmdGamesavGetGameSavList, ProtoBufHelper.Serizlize(req)); App.network.SendToServer((int)CommandID.CmdGamesavGetGameSavList, ProtoBufHelper.Serizlize(req));
} }
void RecvGetGameSavList(byte[] reqData) void RecvGetGameSavList(byte[] reqData)
{ {
Protobuf_Mine_GetGameSavList_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Mine_GetGameSavList_RESP>(reqData); Protobuf_Mine_GetGameSavList_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Mine_GetGameSavList_RESP>(reqData);
if (m_fetchingRomIDs.Remove(msg.RomID)) return; if (m_fetchingRomIDs.Remove(msg.RomID)) return;
Protobuf_Mine_GameSavInfo[] savArr = new Protobuf_Mine_GameSavInfo[4]; Protobuf_Mine_GameSavInfo[] savArr = new Protobuf_Mine_GameSavInfo[4];
for (int i = 0; i < savArr.Length; i++) for (int i = 0; i < savArr.Length; i++)
{ {
Protobuf_Mine_GameSavInfo info = msg.SavDataList.FirstOrDefault(w => w.SavDataIdx == i); Protobuf_Mine_GameSavInfo info = msg.SavDataList.FirstOrDefault(w => w.SavDataIdx == i);
savArr[i] = info; savArr[i] = info;
} }
OnFetchGameSavList?.Invoke(msg.RomID, savArr); OnFetchGameSavList?.Invoke(msg.RomID, savArr);
} }
/// <summary> /// <summary>
/// 发送删除即时存档 /// 发送删除即时存档
/// </summary> /// </summary>
/// <param name="RomID"></param> /// <param name="RomID"></param>
/// <param name="SavDataIdx"></param> /// <param name="SavDataIdx"></param>
public void SendDelGameSavList(int RomID, int SavDataIdx) public void SendDelGameSavList(int RomID, int SavDataIdx)
{ {
Protobuf_Mine_DelGameSav req = new Protobuf_Mine_DelGameSav() Protobuf_Mine_DelGameSav req = new Protobuf_Mine_DelGameSav()
{ {
RomID = RomID, RomID = RomID,
SavDataIdx = SavDataIdx SavDataIdx = SavDataIdx
}; };
App.log.Info($"SendDelGameSavList"); App.log.Info($"SendDelGameSavList");
App.network.SendToServer((int)CommandID.CmdGamesavDelGameSav, ProtoBufHelper.Serizlize(req)); App.network.SendToServer((int)CommandID.CmdGamesavDelGameSav, ProtoBufHelper.Serizlize(req));
} }
void RecvDelGameSavList(byte[] reqData) void RecvDelGameSavList(byte[] reqData)
{ {
Protobuf_Mine_DelGameSav_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Mine_DelGameSav_RESP>(reqData); Protobuf_Mine_DelGameSav_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Mine_DelGameSav_RESP>(reqData);
Eventer.Instance.PostEvent(EEvent.OnNetGameSavDeleted, msg.RomID, msg.SavDataIdx); Eventer.Instance.PostEvent(EEvent.OnNetGameSavDeleted, msg.RomID, msg.SavDataIdx);
} }
/// <summary> /// <summary>
/// 上传即时存档 /// 上传即时存档
/// </summary> /// </summary>
/// <param name="RomID"></param> /// <param name="RomID"></param>
/// <param name="SavDataIdx"></param> /// <param name="SavDataIdx"></param>
public void SendUpLoadGameSav(int RomID, int SavDataIdx, uint sequence, byte[] RawData, byte[] SavImgData) public void SendUpLoadGameSav(int RomID, int SavDataIdx, uint sequence, byte[] RawData, byte[] SavImgData)
{ {
//压缩 //压缩
byte[] compressRawData = Helper.CompressByteArray(RawData); byte[] compressRawData = Helper.CompressByteArray(RawData);
//压缩 //压缩
byte[] compressImgData = Helper.CompressByteArray(SavImgData); byte[] compressImgData = Helper.CompressByteArray(SavImgData);
Protobuf_Mine_UpLoadGameSav req = new Protobuf_Mine_UpLoadGameSav() Protobuf_Mine_UpLoadGameSav req = new Protobuf_Mine_UpLoadGameSav()
{ {
RomID = RomID, RomID = RomID,
SavDataIdx = SavDataIdx, SavDataIdx = SavDataIdx,
StateRaw = Google.Protobuf.ByteString.CopyFrom(compressRawData), StateRaw = Google.Protobuf.ByteString.CopyFrom(compressRawData),
SavImg = Google.Protobuf.ByteString.CopyFrom(compressImgData), SavImg = Google.Protobuf.ByteString.CopyFrom(compressImgData),
Sequence = (int)sequence Sequence = (int)sequence
}; };
App.log.Info($"SendDelGameSavList"); App.log.Info($"SendDelGameSavList");
App.log.Info($"上传即时存档数据 原数据大小:{RawData.Length},压缩后;{compressRawData.Length}"); App.log.Info($"上传即时存档数据 原数据大小:{RawData.Length},压缩后;{compressRawData.Length}");
App.log.Info($"上传截图 原数据大小:{SavImgData.Length},压缩后;{compressImgData.Length}"); App.log.Info($"上传截图 原数据大小:{SavImgData.Length},压缩后;{compressImgData.Length}");
App.network.SendToServer((int)CommandID.CmdGamesavUploadGameSav, ProtoBufHelper.Serizlize(req)); App.network.SendToServer((int)CommandID.CmdGamesavUploadGameSav, ProtoBufHelper.Serizlize(req));
} }
void RecvUpLoadGameSav(byte[] reqData) void RecvUpLoadGameSav(byte[] reqData)
{ {
Protobuf_Mine_UpLoadGameSav_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Mine_UpLoadGameSav_RESP>(reqData); Protobuf_Mine_UpLoadGameSav_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Mine_UpLoadGameSav_RESP>(reqData);
OnUploadedSavData?.Invoke(msg.RomID, msg.SavDataIdx, msg.UploadSevInfo); OnUploadedSavData?.Invoke(msg.RomID, msg.SavDataIdx, msg.UploadSevInfo);
} }
/// <summary> /// <summary>
/// 即时存档或网络截图下载完成之后,需要先解压再使用 /// 即时存档或网络截图下载完成之后,需要先解压再使用
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public byte[] UnGzipData(byte[] data) public byte[] UnGzipData(byte[] data)
{ {
return Helper.DecompressByteArray(data); return Helper.DecompressByteArray(data);
} }
} }
} }

View File

@ -172,6 +172,8 @@ namespace AxibugEmuOnline.Client
public unsafe void Save(uint sequence, byte[] savData, byte[] screenShotData) public unsafe void Save(uint sequence, byte[] savData, byte[] screenShotData)
{ {
if (IsBusy) return;
var filePath = FilePath; var filePath = FilePath;
var header = new Header var header = new Header

View File

@ -26,8 +26,8 @@ namespace AxibugEmuOnline.Client
} }
m_sequece = (uint)netData.Sequence; m_sequece = (uint)netData.Sequence;
m_downloadTask = AxiHttpProxy.GetDownLoad($"{App.httpAPI.WebHost}/{netData.SavUrl}?v={m_sequece}"); m_downloadTask = AxiHttpProxy.GetDownLoad($"{App.httpAPI.WebHost}/{netData.SavUrl}");
m_downloadTaskImg = AxiHttpProxy.GetDownLoad($"{App.httpAPI.WebHost}/{netData.SavImgUrl}?v={m_sequece}"); m_downloadTaskImg = AxiHttpProxy.GetDownLoad($"{App.httpAPI.WebHost}/{netData.SavImgUrl}");
Host.SetSavingFlag(); Host.SetSavingFlag();
} }
@ -52,25 +52,14 @@ namespace AxibugEmuOnline.Client
if (m_downloadTaskImg.downloadHandler.bHadErr) //下载失败 if (m_downloadTaskImg.downloadHandler.bHadErr) //下载失败
{ {
FSM.GetState<SyncFailedState>().Error = m_downloadTaskImg.downloadHandler.ErrInfo; FSM.ChangeState<IdleState>();
FSM.ChangeState<SyncFailedState>();
return; return;
} }
try var savData = Host.CloudAPI.UnGzipData(m_downloadTask.downloadHandler.data);
{ var imgData = Host.CloudAPI.UnGzipData(m_downloadTaskImg.downloadHandler.data);
var savData = Host.CloudAPI.UnGzipData(m_downloadTask.downloadHandler.data); Host.Save(m_sequece, savData, imgData);
var imgData = m_downloadTaskImg.downloadHandler.data; //图片数据已被服务器解压 FSM.ChangeState<SyncedState>();
Host.Save(m_sequece, savData, imgData);
FSM.ChangeState<SyncedState>();
}
catch
{
FSM.GetState<SyncFailedState>().Error = "云存档解压失败";
FSM.ChangeState<SyncFailedState>();
return;
}
} }
} }

View File

@ -1,225 +1,225 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Common; using AxibugEmuOnline.Client.Common;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.Network; using AxibugEmuOnline.Client.Network;
using AxibugProtobuf; using AxibugProtobuf;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace AxibugEmuOnline.Client.Manager namespace AxibugEmuOnline.Client.Manager
{ {
public class UserDataBase public class UserDataBase
{ {
public long UID { get; set; } public long UID { get; set; }
public string Account { get; set; } public string Account { get; set; }
public string NickName { get; set; } public string NickName { get; set; }
} }
public class MainUserDataBase : UserDataBase public class MainUserDataBase : UserDataBase
{ {
public bool IsLoggedIn { get; set; } = false; public bool IsLoggedIn { get; set; } = false;
public string Token { get; set; } public string Token { get; set; }
} }
public class UserDataManager public class UserDataManager
{ {
public UserDataManager() public UserDataManager()
{ {
//注册重连成功事件,以便后续自动登录 //注册重连成功事件,以便后续自动登录
App.network.OnReConnected += OnReConnected; App.network.OnReConnected += OnReConnected;
//网络事件注册 //网络事件注册
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUserOnlinelist, RecvUserOnlinelist); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUserOnlinelist, RecvUserOnlinelist);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUserJoin, RecvCmdUserJoin); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUserJoin, RecvCmdUserJoin);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUserLeave, RecvGetUserLeave); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUserLeave, RecvGetUserLeave);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdModifyNickName, RecvModifyNickName); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdModifyNickName, RecvModifyNickName);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUpdateSelfUserInfo, RecvUpdateSelfUserInfo); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUpdateSelfUserInfo, RecvUpdateSelfUserInfo);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUpdateOtherUserInfo, RecvUpdateOtherUserInfo); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdUpdateOtherUserInfo, RecvUpdateOtherUserInfo);
} }
public MainUserDataBase userdata { get; private set; } = new MainUserDataBase(); public MainUserDataBase userdata { get; private set; } = new MainUserDataBase();
public bool IsLoggedIn => userdata.IsLoggedIn; public bool IsLoggedIn => userdata.IsLoggedIn;
public string Token => userdata.IsLoggedIn ? userdata.Token : string.Empty; public string Token => userdata.IsLoggedIn ? userdata.Token : string.Empty;
Dictionary<long, UserDataBase> DictUID2User = new Dictionary<long, UserDataBase>(); Dictionary<long, UserDataBase> DictUID2User = new Dictionary<long, UserDataBase>();
public int OnlinePlayerCount => DictUID2User.Count; public int OnlinePlayerCount => DictUID2User.Count;
public void InitMainUserData(string UName, long UID, string token) public void InitMainUserData(string UName, long UID, string token)
{ {
userdata.NickName = UName; userdata.NickName = UName;
userdata.IsLoggedIn = true; userdata.IsLoggedIn = true;
userdata.UID = UID; userdata.UID = UID;
userdata.Token = token; userdata.Token = token;
#if UNITY_EDITOR #if UNITY_EDITOR
App.log.Debug($"收到登录token:{token}"); App.log.Debug($"收到登录token:{token}");
#endif #endif
//以及其他数据初始化 //以及其他数据初始化
//... //...
} }
/// <summary> /// <summary>
/// 登出 /// 登出
/// </summary> /// </summary>
public void LoginOutData() public void LoginOutData()
{ {
userdata.IsLoggedIn = false; userdata.IsLoggedIn = false;
//以及其他数据清理 //以及其他数据清理
//... //...
} }
/// <summary> /// <summary>
/// 当重连成功 /// 当重连成功
/// </summary> /// </summary>
public void OnReConnected() public void OnReConnected()
{ {
//如果之前已登录,则重新登录 //如果之前已登录,则重新登录
if (userdata.IsLoggedIn) if (userdata.IsLoggedIn)
{
App.login.Login();
}
}
#region
public void UpdateOrAddUser(UserMiniInfo minfo, out bool isNewUser)
{
lock (DictUID2User)
{
if (!DictUID2User.ContainsKey(minfo.UID))
{
DictUID2User[minfo.UID] = new UserDataBase()
{
UID = minfo.UID,
NickName = minfo.NickName,
Account = "",
};
isNewUser = true;
}
else
{
isNewUser = false;
DictUID2User[minfo.UID].NickName = minfo.NickName;
}
}
}
public void RemoveUser(long UID)
{
bool bflag = false;
string UName = "";
lock (DictUID2User)
{
if (DictUID2User.ContainsKey(UID))
{
UName = DictUID2User[UID].NickName;
DictUID2User.Remove(UID);
bflag = true;
}
}
if (bflag)
{
//抛出用户离开事件
Eventer.Instance.PostEvent(EEvent.OnUserLoginOut, UID, UName);
}
}
public UserDataBase GetUserByUid(long UID)
{
lock (DictUID2User)
{
if (DictUID2User.ContainsKey(UID))
{
return DictUID2User[UID];
}
return null;
}
}
public UserDataBase[] GetUserList()
{
UserDataBase[] ulist = new UserDataBase[DictUID2User.Count];
long[] UIDs = DictUID2User.Keys.ToArray();
for (int i = 0; i < UIDs.Length; i++)
{
ulist[i] = DictUID2User[UIDs[i]];
}
return ulist;
}
#endregion
/// <summary>
/// 请求拉取房间列表
/// </summary>
public void Send_GetUserList()
{
Protobuf_UserList msg = new Protobuf_UserList()
{
};
App.network.SendToServer((int)CommandID.CmdUserOnlinelist, ProtoBufHelper.Serizlize(msg));
}
public void RecvUserOnlinelist(byte[] reqData)
{
Protobuf_UserList_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_UserList_RESP>(reqData);
DictUID2User.Clear();
for (int i = 0; i < msg.UserList.Count; i++)
{
UserMiniInfo mi = msg.UserList[i];
bool isNewUser;
UpdateOrAddUser(mi, out isNewUser);
}
Eventer.Instance.PostEvent(EEvent.OnUserListAllUpdate);
}
public void RecvCmdUserJoin(byte[] reqData)
{
Protobuf_UserJoin_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_UserJoin_RESP>(reqData);
bool isNewUser;
UpdateOrAddUser(msg.UserInfo, out isNewUser);
if (isNewUser)
{ {
Eventer.Instance.PostEvent(EEvent.OnUserLogin, msg.UserInfo.UID, msg.UserInfo.NickName); App.login.Login();
OverlayManager.PopTip($"玩家[{msg.UserInfo.NickName}]上线了"); }
} }
}
#region
public void RecvGetUserLeave(byte[] reqData) public void UpdateOrAddUser(UserMiniInfo minfo, out bool isNewUser)
{ {
Protobuf_UserLeave_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_UserLeave_RESP>(reqData); lock (DictUID2User)
RemoveUser(msg.UID); {
} if (!DictUID2User.ContainsKey(minfo.UID))
{
/// <summary> DictUID2User[minfo.UID] = new UserDataBase()
/// 发送修改昵称请求 {
/// </summary> UID = minfo.UID,
/// <param name="NickName"></param> NickName = minfo.NickName,
public void Send_ModifyNickName(string NickName) Account = "",
{ };
Protobuf_Modify_NickName msg = new Protobuf_Modify_NickName() isNewUser = true;
{ }
NickName = NickName else
}; {
App.network.SendToServer((int)CommandID.CmdModifyNickName, ProtoBufHelper.Serizlize(msg)); isNewUser = false;
} DictUID2User[minfo.UID].NickName = minfo.NickName;
}
void RecvModifyNickName(byte[] reqData) }
{ }
Protobuf_Modify_NickName_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Modify_NickName_RESP>(reqData);
} public void RemoveUser(long UID)
{
private void RecvUpdateSelfUserInfo(byte[] reqData) bool bflag = false;
{ string UName = "";
Protobuf_Update_UserInfo_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Update_UserInfo_RESP>(reqData); lock (DictUID2User)
userdata.NickName = msg.UserInfo.NickName; {
Eventer.Instance.PostEvent(EEvent.OnSelfInfoUpdate); if (DictUID2User.ContainsKey(UID))
} {
UName = DictUID2User[UID].NickName;
private void RecvUpdateOtherUserInfo(byte[] reqData) DictUID2User.Remove(UID);
{ bflag = true;
Protobuf_Update_OtherUserInfo_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Update_OtherUserInfo_RESP>(reqData); }
UserDataBase userdata = GetUserByUid(msg.UID); }
if (userdata == null) if (bflag)
return; {
userdata.NickName = msg.UserInfo.NickName; //抛出用户离开事件
Eventer.Instance.PostEvent(EEvent.OnUserLoginOut, UID, UName);
App.roomMgr.ChangeCurrRoomPlayerName(msg.UID); }
}
Eventer.Instance.PostEvent(EEvent.OnOtherUserInfoUpdate, msg.UID); public UserDataBase GetUserByUid(long UID)
} {
lock (DictUID2User)
} {
} if (DictUID2User.ContainsKey(UID))
{
return DictUID2User[UID];
}
return null;
}
}
public UserDataBase[] GetUserList()
{
UserDataBase[] ulist = new UserDataBase[DictUID2User.Count];
long[] UIDs = DictUID2User.Keys.ToArray();
for (int i = 0; i < UIDs.Length; i++)
{
ulist[i] = DictUID2User[UIDs[i]];
}
return ulist;
}
#endregion
/// <summary>
/// 请求拉取房间列表
/// </summary>
public void Send_GetUserList()
{
Protobuf_UserList msg = new Protobuf_UserList()
{
};
App.network.SendToServer((int)CommandID.CmdUserOnlinelist, ProtoBufHelper.Serizlize(msg));
}
public void RecvUserOnlinelist(byte[] reqData)
{
Protobuf_UserList_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_UserList_RESP>(reqData);
DictUID2User.Clear();
for (int i = 0; i < msg.UserList.Count; i++)
{
UserMiniInfo mi = msg.UserList[i];
bool isNewUser;
UpdateOrAddUser(mi, out isNewUser);
}
Eventer.Instance.PostEvent(EEvent.OnUserListAllUpdate);
}
public void RecvCmdUserJoin(byte[] reqData)
{
Protobuf_UserJoin_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_UserJoin_RESP>(reqData);
bool isNewUser;
UpdateOrAddUser(msg.UserInfo, out isNewUser);
if (isNewUser)
{
Eventer.Instance.PostEvent(EEvent.OnUserLogin, msg.UserInfo.UID, msg.UserInfo.NickName);
OverlayManager.PopTip($"玩家[{msg.UserInfo.NickName}]上线了");
}
}
public void RecvGetUserLeave(byte[] reqData)
{
Protobuf_UserLeave_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_UserLeave_RESP>(reqData);
RemoveUser(msg.UID);
}
/// <summary>
/// 发送修改昵称请求
/// </summary>
/// <param name="NickName"></param>
public void Send_ModifyNickName(string NickName)
{
Protobuf_Modify_NickName msg = new Protobuf_Modify_NickName()
{
NickName = NickName
};
App.network.SendToServer((int)CommandID.CmdModifyNickName, ProtoBufHelper.Serizlize(msg));
}
void RecvModifyNickName(byte[] reqData)
{
Protobuf_Modify_NickName_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Modify_NickName_RESP>(reqData);
}
private void RecvUpdateSelfUserInfo(byte[] reqData)
{
Protobuf_Update_UserInfo_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Update_UserInfo_RESP>(reqData);
userdata.NickName = msg.UserInfo.NickName;
Eventer.Instance.PostEvent(EEvent.OnSelfInfoUpdate);
}
private void RecvUpdateOtherUserInfo(byte[] reqData)
{
Protobuf_Update_OtherUserInfo_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Update_OtherUserInfo_RESP>(reqData);
UserDataBase userdata = GetUserByUid(msg.UID);
if (userdata == null)
return;
userdata.NickName = msg.UserInfo.NickName;
App.roomMgr.ChangeCurrRoomPlayerName(msg.UID);
Eventer.Instance.PostEvent(EEvent.OnOtherUserInfoUpdate, msg.UID);
}
}
}

View File

@ -1,39 +1,39 @@
/// <summary> /// <summary>
/// String和Bool的缝合怪 /// String和Bool的缝合怪
/// </summary> /// </summary>
public struct MsgBool public struct MsgBool
{ {
public string ErrorMsg; public string ErrorMsg;
public bool Value; public bool Value;
//low C# readonly //low C# readonly
//public override readonly string ToString() //public override readonly string ToString()
public override string ToString() public override string ToString()
{ {
if (Value) if (Value)
{ {
return true.ToString(); return true.ToString();
} }
else else
{ {
return ErrorMsg; return ErrorMsg;
} }
} }
public static implicit operator MsgBool(string errorMsg) public static implicit operator MsgBool(string errorMsg)
{ {
return new MsgBool { Value = false, ErrorMsg = errorMsg }; return new MsgBool { Value = false, ErrorMsg = errorMsg };
} }
public static implicit operator MsgBool(bool value) public static implicit operator MsgBool(bool value)
{ {
return new MsgBool { Value = value }; return new MsgBool { Value = value };
} }
public static implicit operator bool(MsgBool msgBool) public static implicit operator bool(MsgBool msgBool)
{ {
return msgBool.Value; return msgBool.Value;
} }
//low C# //low C#
@ -42,8 +42,8 @@ public struct MsgBool
// return (msgBool.Value, msgBool.ErrorMsg); // return (msgBool.Value, msgBool.ErrorMsg);
//} //}
public static implicit operator string(MsgBool msgBool) public static implicit operator string(MsgBool msgBool)
{ {
return msgBool.ToString(); return msgBool.ToString();
} }
} }

View File

@ -1,102 +1,102 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugProtobuf; using AxibugProtobuf;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client.Network
{
public class NetMsg
{
private static NetMsg instance = new NetMsg();
public static NetMsg Instance { get { return instance; } }
private Dictionary<int, List<Delegate>> netEventDic = new Dictionary<int, List<Delegate>>(128);
private Queue<ValueTuple<int, int, byte[]>> queueNetMsg = new Queue<ValueTuple<int, int, byte[]>>();
public static object lockQueueNetMsg = new object();
private Queue<Action> queueEventFromNet = new Queue<Action>(); namespace AxibugEmuOnline.Client.Network
{
public class NetMsg
{
private static NetMsg instance = new NetMsg();
public static NetMsg Instance { get { return instance; } }
private Dictionary<int, List<Delegate>> netEventDic = new Dictionary<int, List<Delegate>>(128);
private Queue<ValueTuple<int, int, byte[]>> queueNetMsg = new Queue<ValueTuple<int, int, byte[]>>();
public static object lockQueueNetMsg = new object();
private Queue<Action> queueEventFromNet = new Queue<Action>();
public static object lockQueueEventFromNet = new object(); public static object lockQueueEventFromNet = new object();
private NetMsg() { } private NetMsg() { }
#region RegisterMsgEvent #region RegisterMsgEvent
public void RegNetMsgEvent(int cmd, Action<byte[]> callback) public void RegNetMsgEvent(int cmd, Action<byte[]> callback)
{ {
InterRegNetMsgEvent(cmd, callback); InterRegNetMsgEvent(cmd, callback);
}
private void InterRegNetMsgEvent(int cmd, Delegate callback)
{
if (netEventDic.ContainsKey(cmd))
{
if (netEventDic[cmd].IndexOf(callback) < 0)
{
netEventDic[cmd].Add(callback);
}
}
else
{
netEventDic.Add(cmd, new List<Delegate>() { callback });
}
}
#endregion
#region UnregisterCMD
public void UnregisterCMD(int evt, Action<byte[]> callback)
{
Delegate tempDelegate = callback;
InterUnregisterCMD(evt, tempDelegate);
}
private void InterUnregisterCMD(int cmd, Delegate callback)
{
if (netEventDic.ContainsKey(cmd))
{
netEventDic[cmd].Remove(callback);
if (netEventDic[cmd].Count == 0) netEventDic.Remove(cmd);
}
} }
#endregion
private void InterRegNetMsgEvent(int cmd, Delegate callback)
{
if (netEventDic.ContainsKey(cmd))
{
if (netEventDic[cmd].IndexOf(callback) < 0)
{
netEventDic[cmd].Add(callback);
}
}
else
{
netEventDic.Add(cmd, new List<Delegate>() { callback });
}
}
#endregion
#region UnregisterCMD
public void UnregisterCMD(int evt, Action<byte[]> callback)
{
Delegate tempDelegate = callback;
InterUnregisterCMD(evt, tempDelegate);
}
private void InterUnregisterCMD(int cmd, Delegate callback)
{
if (netEventDic.ContainsKey(cmd))
{
netEventDic[cmd].Remove(callback);
if (netEventDic[cmd].Count == 0) netEventDic.Remove(cmd);
}
}
#endregion
public void NextNetEvent() public void NextNetEvent()
{ {
DequeueNesMsg(); DequeueNesMsg();
DequeueEventFromNet(); DequeueEventFromNet();
} }
#region PostEventFromNet #region PostEventFromNet
public void EnqueueEventFromNet(Action act) public void EnqueueEventFromNet(Action act)
{ {
lock (lockQueueEventFromNet) lock (lockQueueEventFromNet)
{ {
queueEventFromNet.Enqueue(act); queueEventFromNet.Enqueue(act);
} }
} }
public void DequeueEventFromNet() public void DequeueEventFromNet()
{ {
lock (lockQueueEventFromNet) lock (lockQueueEventFromNet)
{ {
while (queueEventFromNet.Count > 0) while (queueEventFromNet.Count > 0)
{ {
var msgData = queueEventFromNet.Dequeue(); var msgData = queueEventFromNet.Dequeue();
PostNetEventFromNet(msgData); PostNetEventFromNet(msgData);
} }
} }
} }
void PostNetEventFromNet(Action act) void PostNetEventFromNet(Action act)
{ {
try try
{ {
@ -106,73 +106,73 @@ namespace AxibugEmuOnline.Client.Network
{ {
App.log.Error(ex.ToString()); App.log.Error(ex.ToString());
} }
} }
#endregion #endregion
#region PostNetMsg #region PostNetMsg
public void EnqueueNetMsg(int cmd, int ERRCODE, byte[] arg) public void EnqueueNetMsg(int cmd, int ERRCODE, byte[] arg)
{ {
lock (lockQueueNetMsg) lock (lockQueueNetMsg)
{ {
queueNetMsg.Enqueue(new ValueTuple<int, int, byte[]>(cmd, ERRCODE, arg)); queueNetMsg.Enqueue(new ValueTuple<int, int, byte[]>(cmd, ERRCODE, arg));
} }
} }
public void DequeueNesMsg() public void DequeueNesMsg()
{ {
lock (lockQueueNetMsg) lock (lockQueueNetMsg)
{ {
while (queueNetMsg.Count > 0) while (queueNetMsg.Count > 0)
{ {
var msgData = queueNetMsg.Dequeue(); var msgData = queueNetMsg.Dequeue();
PostNetMsgEvent(msgData.Item1, msgData.Item2, msgData.Item3); PostNetMsgEvent(msgData.Item1, msgData.Item2, msgData.Item3);
} }
} }
} }
public void PostNetMsgEvent(int cmd, int ERRCODE, byte[] arg) public void PostNetMsgEvent(int cmd, int ERRCODE, byte[] arg)
{ {
ErrorCode err = ((ErrorCode)ERRCODE); ErrorCode err = ((ErrorCode)ERRCODE);
if (err != ErrorCode.ErrorOk) if (err != ErrorCode.ErrorOk)
{ {
OverlayManager.PopTip("错误:" + err.ToString()); OverlayManager.PopTip("错误:" + err.ToString());
} }
List<Delegate> eventList = GetNetEventDicList(cmd); List<Delegate> eventList = GetNetEventDicList(cmd);
if (eventList != null) if (eventList != null)
{ {
foreach (Delegate callback in eventList) foreach (Delegate callback in eventList)
{ {
try try
{ {
((Action<byte[]>)callback)(arg); ((Action<byte[]>)callback)(arg);
} }
catch (Exception e) catch (Exception e)
{ {
App.log.Error(e.ToString()); App.log.Error(e.ToString());
} }
} }
} }
} }
#endregion #endregion
/// <summary> /// <summary>
/// 获取所有事件 /// 获取所有事件
/// </summary> /// </summary>
/// <param name="cmd"></param> /// <param name="cmd"></param>
/// <returns></returns> /// <returns></returns>
private List<Delegate> GetNetEventDicList(int cmd) private List<Delegate> GetNetEventDicList(int cmd)
{ {
if (netEventDic.ContainsKey(cmd)) if (netEventDic.ContainsKey(cmd))
{ {
List<Delegate> tempList = netEventDic[cmd]; List<Delegate> tempList = netEventDic[cmd];
if (null != tempList) if (null != tempList)
{ {
return tempList; return tempList;
} }
} }
return null; return null;
} }
} }
} }

View File

@ -1,9 +1,11 @@
using AxibugEmuOnline.Client; using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore;
using UnityEngine; using UnityEngine;
public class SwitchCommon : MonoBehaviour public class SwitchCommon : MonoBehaviour
{ {
void Start() void Start()
{ {
Debug.Log("SwitchCommon Start");
TickLoop.LoopAction_15s += ApplyCommit; TickLoop.LoopAction_15s += ApplyCommit;
} }

View File

@ -1,35 +1,35 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Settings; using AxibugEmuOnline.Client.Settings;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class ScreenScalerListMenuItem : VirtualSubMenuItem public class ScreenScalerListMenuItem : VirtualSubMenuItem
{ {
public override bool OnEnterItem() public override bool OnEnterItem()
{ {
App.settings.Filter.EnableFilterPreview(); App.settings.Filter.EnableFilterPreview();
return base.OnEnterItem(); return base.OnEnterItem();
} }
public override bool OnExitItem() public override bool OnExitItem()
{ {
App.settings.Filter.ShutDownFilterPreview(); App.settings.Filter.ShutDownFilterPreview();
return base.OnExitItem(); return base.OnExitItem();
} }
protected override void GetVirtualListDatas(VirtualListDataHandle callback) protected override void GetVirtualListDatas(VirtualListDataHandle callback)
{ {
List<object> list = new List<object>(); List<object> list = new List<object>();
foreach (var enumValue in Enum.GetValues(typeof(ScreenScaler.EnumScalerMode))) list.Add(enumValue); foreach (var enumValue in Enum.GetValues(typeof(ScreenScaler.EnumScalerMode))) list.Add(enumValue);
var select = list.IndexOf(App.settings.ScreenScaler.GlobalMode); var select = list.IndexOf(App.settings.ScreenScaler.GlobalMode);
if (select == -1) select = 0; if (select == -1) select = 0;
callback.Invoke(list, select); callback.Invoke(list, select);
} }
} }
} }

View File

@ -1,104 +1,104 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Settings; using AxibugEmuOnline.Client.Settings;
using AxibugEmuOnline.Client.UI; using AxibugEmuOnline.Client.UI;
using DG.Tweening; using DG.Tweening;
using DG.Tweening.Core; using DG.Tweening.Core;
using DG.Tweening.Plugins.Options; using DG.Tweening.Plugins.Options;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
/// <summary> /// <summary>
/// 背景颜色设置UI /// 背景颜色设置UI
/// </summary> /// </summary>
public class UI_BgSettingItem_Color : MenuItem, IVirtualItem public class UI_BgSettingItem_Color : MenuItem, IVirtualItem
{ {
public int Index { get; set; } public int Index { get; set; }
public BgColorSettings Datacontext { get; private set; } public BgColorSettings Datacontext { get; private set; }
public void SetData(object data) public void SetData(object data)
{ {
Datacontext = (BgColorSettings)data; Datacontext = (BgColorSettings)data;
Datacontext.OnColorChanged += Setting_OnColorChanged; Datacontext.OnColorChanged += Setting_OnColorChanged;
UpdateView(); UpdateView();
} }
private void Setting_OnColorChanged(XMBColor color) private void Setting_OnColorChanged(XMBColor color)
{ {
UpdateView(); UpdateView();
} }
private void UpdateView() private void UpdateView()
{ {
var color = Datacontext.CurrentColor; var color = Datacontext.CurrentColor;
Icon.GetMaterial().SetColor("_Color1", color.color1); Icon.GetMaterial().SetColor("_Color1", color.color1);
Icon.GetMaterial().SetColor("_Color2", color.color2); Icon.GetMaterial().SetColor("_Color2", color.color2);
SetBaseInfo("主题色", "设置主题色", color.Name); SetBaseInfo("主题色", "设置主题色", color.Name);
} }
public void SetDependencyProperty(object data) public void SetDependencyProperty(object data)
{ {
SetSelectState(data is ThirdMenuRoot && ((ThirdMenuRoot)data).SelectIndex == Index); SetSelectState(data is ThirdMenuRoot && ((ThirdMenuRoot)data).SelectIndex == Index);
} }
public void Release() public void Release()
{ {
Datacontext.OnColorChanged -= Setting_OnColorChanged; Datacontext.OnColorChanged -= Setting_OnColorChanged;
} }
public override bool OnEnterItem() public override bool OnEnterItem()
{ {
var options = Datacontext.Presets.Select(preset => new ColorOption(preset)).ToList(); var options = Datacontext.Presets.Select(preset => new ColorOption(preset)).ToList();
var currentColor = Datacontext.CurrentColor; var currentColor = Datacontext.CurrentColor;
var index = options.FindIndex(op => op.Color.GetHashCode() == currentColor.GetHashCode()); var index = options.FindIndex(op => op.Color.GetHashCode() == currentColor.GetHashCode());
OverlayManager.PopSideBar(options, Mathf.Clamp(index, 0, options.Count - 1)); OverlayManager.PopSideBar(options, Mathf.Clamp(index, 0, options.Count - 1));
return false; return false;
} }
public class ColorOption : ExecuteMenu public class ColorOption : ExecuteMenu
{ {
public XMBColor Color; public XMBColor Color;
public override string Name => Color.Name; public override string Name => Color.Name;
public ColorOption(XMBColor color) public ColorOption(XMBColor color)
{ {
Color = color; Color = color;
} }
public override void OnShow(OptionUI_MenuItem ui) public override void OnShow(OptionUI_MenuItem ui)
{ {
ui.IconUI.gameObject.SetActiveEx(true); ui.IconUI.gameObject.SetActiveEx(true);
ui.IconUI.SetMaterial(Resources.Load<Material>("Materials/XMBBackGroundPreview")); ui.IconUI.SetMaterial(Resources.Load<Material>("Materials/XMBBackGroundPreview"));
ui.IconUI.GetMaterial().SetColor("_Color1", Color.color1); ui.IconUI.GetMaterial().SetColor("_Color1", Color.color1);
ui.IconUI.GetMaterial().SetColor("_Color2", Color.color2); ui.IconUI.GetMaterial().SetColor("_Color2", Color.color2);
} }
private static TweenerCore<float, float, FloatOptions> s_colorChangeTween; private static TweenerCore<float, float, FloatOptions> s_colorChangeTween;
public override void OnFocus() public override void OnFocus()
{ {
float progress = 0; float progress = 0;
XMBColor start = App.settings.BgColor.CurrentColor; XMBColor start = App.settings.BgColor.CurrentColor;
XMBColor endColor = Color; XMBColor endColor = Color;
if (s_colorChangeTween != null) if (s_colorChangeTween != null)
{ {
s_colorChangeTween.Kill(); s_colorChangeTween.Kill();
s_colorChangeTween = null; s_colorChangeTween = null;
} }
s_colorChangeTween = DOTween.To(() => progress, (x) => s_colorChangeTween = DOTween.To(() => progress, (x) =>
{ {
progress = x; progress = x;
var lerpColor = XMBColor.Lerp(start, endColor, x); var lerpColor = XMBColor.Lerp(start, endColor, x);
App.settings.BgColor.CurrentColor = lerpColor; App.settings.BgColor.CurrentColor = lerpColor;
}, 1, 1f).SetEase(Ease.OutCubic); }, 1, 1f).SetEase(Ease.OutCubic);
s_colorChangeTween.onComplete = () => s_colorChangeTween.onComplete = () =>
{ {
s_colorChangeTween = null; s_colorChangeTween = null;
}; };
} }
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) { } public override void OnExcute(OptionUI optionUI, ref bool cancelHide) { }
} }
} }
} }

View File

@ -1,16 +1,16 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.UI; using AxibugEmuOnline.Client.UI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
using static AxibugEmuOnline.Client.Settings.FilterManager; using static AxibugEmuOnline.Client.Settings.FilterManager;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
/// <summary> /// <summary>
/// 滤镜预览UI /// 滤镜预览UI
/// </summary> /// </summary>
public class UI_FilterItem : MenuItem, IVirtualItem public class UI_FilterItem : MenuItem, IVirtualItem
{ {
public int Index { get; set; } public int Index { get; set; }
@ -199,5 +199,5 @@ namespace AxibugEmuOnline.Client
} }
} }
} }

View File

@ -1,12 +1,12 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Settings; using AxibugEmuOnline.Client.Settings;
using AxibugEmuOnline.Client.UI; using AxibugEmuOnline.Client.UI;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
/// <summary> /// <summary>
/// 画面比例模式选项UI /// 画面比例模式选项UI
/// </summary> /// </summary>
public class UI_ScalerModeItem : MenuItem, IVirtualItem public class UI_ScalerModeItem : MenuItem, IVirtualItem
{ {
public int Index { get; set; } public int Index { get; set; }
@ -52,5 +52,5 @@ namespace AxibugEmuOnline.Client
{ {
return false; return false;
} }
} }
} }

View File

@ -1,118 +1,118 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class CommandDispatcher : MonoBehaviour public class CommandDispatcher : MonoBehaviour
{ {
public static CommandDispatcher Instance { get; private set; } public static CommandDispatcher Instance { get; private set; }
/// <summary> 平级注册对象,都会响应指令 </summary> /// <summary> 平级注册对象,都会响应指令 </summary>
List<CommandExecuter> m_register = new List<CommandExecuter>(); List<CommandExecuter> m_register = new List<CommandExecuter>();
/// <summary> 独占注册对象,指令会被列表中最后一个对象独占 </summary> /// <summary> 独占注册对象,指令会被列表中最后一个对象独占 </summary>
List<CommandExecuter> m_registerHigh = new List<CommandExecuter>(); List<CommandExecuter> m_registerHigh = new List<CommandExecuter>();
CommandListener m_listener; CommandListener m_listener;
CommandListener.ScheduleType? m_waitMapperSetting = null; CommandListener.ScheduleType? m_waitMapperSetting = null;
public CommandListener.ScheduleType Mode public CommandListener.ScheduleType Mode
{ {
get => m_listener.Schedule; get => m_listener.Schedule;
set => m_waitMapperSetting = value; set => m_waitMapperSetting = value;
} }
private void Awake() private void Awake()
{ {
Instance = this; Instance = this;
//初始化command监视器 //初始化command监视器
m_listener = new CommandListener(); m_listener = new CommandListener();
} }
private void OnDestroy() private void OnDestroy()
{ {
Instance = null; Instance = null;
} }
public bool IsRegisted(CommandExecuter commandExecuter) public bool IsRegisted(CommandExecuter commandExecuter)
{ {
return m_register.Contains(commandExecuter) || m_registerHigh.Contains(commandExecuter); return m_register.Contains(commandExecuter) || m_registerHigh.Contains(commandExecuter);
} }
public void RegistController(CommandExecuter controller) public void RegistController(CommandExecuter controller)
{ {
if (!controller.AloneMode) if (!controller.AloneMode)
{ {
if (m_register.Contains(controller)) { return; } if (m_register.Contains(controller)) { return; }
m_register.Add(controller); m_register.Add(controller);
} }
else else
{ {
if (m_registerHigh.Contains(controller)) { return; } if (m_registerHigh.Contains(controller)) { return; }
m_registerHigh.Add(controller); m_registerHigh.Add(controller);
} }
} }
public void UnRegistController(CommandExecuter menuItemController) public void UnRegistController(CommandExecuter menuItemController)
{ {
if (!menuItemController.AloneMode) if (!menuItemController.AloneMode)
m_register.Remove(menuItemController); m_register.Remove(menuItemController);
else else
m_registerHigh.Remove(menuItemController); m_registerHigh.Remove(menuItemController);
} }
readonly List<CommandExecuter> oneFrameRegister = new List<CommandExecuter>(); readonly List<CommandExecuter> oneFrameRegister = new List<CommandExecuter>();
private void Update() private void Update()
{ {
if (!InputUI.IsInputing) if (!InputUI.IsInputing)
{ {
peekRegister(oneFrameRegister); peekRegister(oneFrameRegister);
m_listener.Update(oneFrameRegister); m_listener.Update(oneFrameRegister);
} }
//键位映射在按键响应的堆栈结束后处理,防止迭代器修改问题 //键位映射在按键响应的堆栈结束后处理,防止迭代器修改问题
if (m_waitMapperSetting != null) if (m_waitMapperSetting != null)
{ {
m_listener.Schedule = m_waitMapperSetting.Value; m_listener.Schedule = m_waitMapperSetting.Value;
m_waitMapperSetting = null; m_waitMapperSetting = null;
} }
} }
private List<CommandExecuter> peekRegister(List<CommandExecuter> results) private List<CommandExecuter> peekRegister(List<CommandExecuter> results)
{ {
results.Clear(); results.Clear();
if (m_registerHigh.Count > 0) if (m_registerHigh.Count > 0)
{ {
for (int i = m_registerHigh.Count - 1; i >= 0; i--) for (int i = m_registerHigh.Count - 1; i >= 0; i--)
{ {
var controller = m_registerHigh[i]; var controller = m_registerHigh[i];
if (controller.Enable) if (controller.Enable)
{ {
results.Add(controller); results.Add(controller);
return results; return results;
} }
} }
} }
foreach (var controller in m_register) foreach (var controller in m_register)
{ {
if (!controller.Enable) continue; if (!controller.Enable) continue;
results.Add(controller); results.Add(controller);
} }
return results; return results;
} }
#if UNITY_EDITOR #if UNITY_EDITOR
public void GetRegisters(out IReadOnlyList<CommandExecuter> normal, out IReadOnlyList<CommandExecuter> alone) public void GetRegisters(out IReadOnlyList<CommandExecuter> normal, out IReadOnlyList<CommandExecuter> alone)
{ {
normal = m_register; normal = m_register;
alone = m_registerHigh; alone = m_registerHigh;
} }
#endif #endif
} }
} }

View File

@ -1,14 +1,14 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class CommandListener public class CommandListener
{ {
EnumCommand[] m_checkCmds; EnumCommand[] m_checkCmds;
List<CommandState> m_commands = new List<CommandState>(); List<CommandState> m_commands = new List<CommandState>();
long CheckFrame = -1; long CheckFrame = -1;
XMBKeyBinding m_keyBinder; XMBKeyBinding m_keyBinder;
public ScheduleType Schedule { get; set; } public ScheduleType Schedule { get; set; }
@ -17,16 +17,16 @@ namespace AxibugEmuOnline.Client
{ {
m_keyBinder = App.settings.KeyMapper.GetBinder<XMBKeyBinding>(); m_keyBinder = App.settings.KeyMapper.GetBinder<XMBKeyBinding>();
m_checkCmds = Enum.GetValues(typeof(EnumCommand)) as EnumCommand[]; m_checkCmds = Enum.GetValues(typeof(EnumCommand)) as EnumCommand[];
} }
IEnumerable<CommandState> GetCommand() IEnumerable<CommandState> GetCommand()
{ {
if (CheckFrame == Time.frameCount) if (CheckFrame == Time.frameCount)
return m_commands; return m_commands;
CheckFrame = Time.frameCount; CheckFrame = Time.frameCount;
m_commands.Clear(); m_commands.Clear();
int controllerIndex = (int)Schedule; int controllerIndex = (int)Schedule;
foreach (var cmd in m_checkCmds) foreach (var cmd in m_checkCmds)
@ -36,25 +36,25 @@ namespace AxibugEmuOnline.Client
} }
return m_commands; return m_commands;
} }
public void Update(IEnumerable<CommandExecuter> executers) public void Update(IEnumerable<CommandExecuter> executers)
{ {
foreach (var cmd in GetCommand()) foreach (var cmd in GetCommand())
{ {
foreach (var executer in executers) foreach (var executer in executers)
{ {
//App.log.Debug($"CommandListener GetCommand | {Time.frameCount}|{executer.name}| {cmd.Cmd}|{cmd.Cancel}"); //App.log.Debug($"CommandListener GetCommand | {Time.frameCount}|{executer.name}| {cmd.Cmd}|{cmd.Cancel}");
executer.ExecuteCommand(cmd.Cmd, cmd.Cancel); executer.ExecuteCommand(cmd.Cmd, cmd.Cancel);
} }
} }
} }
public enum ScheduleType public enum ScheduleType
{ {
Normal, Normal,
Gaming Gaming
} }
} }
} }

View File

@ -1,45 +1,45 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.UI; using AxibugEmuOnline.Client.UI;
using Coffee.UIExtensions; using Coffee.UIExtensions;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class RomItem : MenuItem, IVirtualItem public class RomItem : MenuItem, IVirtualItem
{ {
[SerializeField] [SerializeField]
Image m_romImage; Image m_romImage;
[SerializeField] [SerializeField]
GameObject DownloadingFlag; GameObject DownloadingFlag;
[SerializeField] [SerializeField]
Slider DownProgress; Slider DownProgress;
[SerializeField] [SerializeField]
GameObject FileReadyFlag; GameObject FileReadyFlag;
[SerializeField] [SerializeField]
UIShiny DownloadComplete; UIShiny DownloadComplete;
[SerializeField] [SerializeField]
GameObject Star; GameObject Star;
public int Index { get; set; } public int Index { get; set; }
public bool IsStar public bool IsStar
{ {
get get
{ {
return m_romfile != null && m_romfile.InfoReady ? m_romfile.Star : false; return m_romfile != null && m_romfile.InfoReady ? m_romfile.Star : false;
} }
} }
public int RomID { get { return m_romfile != null && m_romfile.InfoReady ? m_romfile.ID : -1; } } public int RomID { get { return m_romfile != null && m_romfile.InfoReady ? m_romfile.ID : -1; } }
private RomLib m_romlib => App.GetRomLib(m_romfile.Platform); private RomLib m_romlib => App.GetRomLib(m_romfile.Platform);
public bool RomInfoReady => m_romfile != null && m_romfile.InfoReady; public bool RomInfoReady => m_romfile != null && m_romfile.InfoReady;
private RomFile m_romfile; private RomFile m_romfile;
protected override void OnEnable() protected override void OnEnable()
{ {
Eventer.Instance.RegisterEvent<int>(EEvent.OnRomFileDownloaded, OnRomDownloaded); Eventer.Instance.RegisterEvent<int>(EEvent.OnRomFileDownloaded, OnRomDownloaded);
@ -59,103 +59,103 @@ namespace AxibugEmuOnline.Client
DownloadComplete.Play(); DownloadComplete.Play();
} }
public void SetData(object data) public void SetData(object data)
{ {
Reset(); Reset();
m_romfile = (RomFile)data; m_romfile = (RomFile)data;
m_romfile.OnInfoFilled += OnRomInfoFilled; m_romfile.OnInfoFilled += OnRomInfoFilled;
m_romImage.sprite = null; m_romImage.sprite = null;
UpdateView(); UpdateView();
if (!m_romfile.InfoReady) if (!m_romfile.InfoReady)
{ {
m_romlib.BeginFetchRomInfo(m_romfile); m_romlib.BeginFetchRomInfo(m_romfile);
} }
SetSelectState(data is ThirdMenuRoot && ((ThirdMenuRoot)data).SelectIndex == Index); SetSelectState(data is ThirdMenuRoot && ((ThirdMenuRoot)data).SelectIndex == Index);
} }
public void SetDependencyProperty(object data) public void SetDependencyProperty(object data)
{ {
SetSelectState(data is ThirdMenuRoot && ((ThirdMenuRoot)data).SelectIndex == Index); SetSelectState(data is ThirdMenuRoot && ((ThirdMenuRoot)data).SelectIndex == Index);
} }
protected override void OnSelected(float progress) protected override void OnSelected(float progress)
{ {
base.OnSelected(progress); base.OnSelected(progress);
if (m_romImage.sprite == null) LaunchUI.Instance.HideRomPreview(); if (m_romImage.sprite == null) LaunchUI.Instance.HideRomPreview();
else LaunchUI.Instance.SetRomPreview(m_romImage.sprite); else LaunchUI.Instance.SetRomPreview(m_romImage.sprite);
} }
public void Release() public void Release()
{ {
m_romfile.OnInfoFilled -= OnRomInfoFilled; m_romfile.OnInfoFilled -= OnRomInfoFilled;
} }
private void OnRomInfoFilled() private void OnRomInfoFilled()
{ {
UpdateView(); UpdateView();
} }
private void UpdateView() private void UpdateView()
{ {
if (!m_romfile.InfoReady) if (!m_romfile.InfoReady)
{ {
SetBaseInfo("正在拉取", "---", "---"); SetBaseInfo("正在拉取", "---", "---");
} }
else else
{ {
SetBaseInfo(m_romfile.Alias, m_romfile.Descript, m_romfile.GameTypeDes); SetBaseInfo(m_romfile.Alias, m_romfile.Descript, m_romfile.GameTypeDes);
App.CacheMgr.GetSpriteCache(m_romfile.ImageURL, (img, url) => App.CacheMgr.GetSpriteCache(m_romfile.ImageURL, (img, url) =>
{ {
if (!m_romfile.InfoReady || url != m_romfile.ImageURL) return; if (!m_romfile.InfoReady || url != m_romfile.ImageURL) return;
m_romImage.sprite = img; m_romImage.sprite = img;
if (m_select) LaunchUI.Instance.SetRomPreview(img); if (m_select) LaunchUI.Instance.SetRomPreview(img);
}); });
Star.SetActiveEx(m_romfile.Star); Star.SetActiveEx(m_romfile.Star);
} }
} }
public override bool OnEnterItem() public override bool OnEnterItem()
{ {
if (!m_romfile.RomReady) if (!m_romfile.RomReady)
{ {
m_romfile.BeginDownload(); m_romfile.BeginDownload();
return false; return false;
} }
else else
{ {
App.emu.BeginGame(m_romfile); App.emu.BeginGame(m_romfile);
return false; return false;
} }
} }
protected override void Update() protected override void Update()
{ {
DownloadingFlag.SetActiveEx(false); DownloadingFlag.SetActiveEx(false);
FileReadyFlag.SetActiveEx(false); FileReadyFlag.SetActiveEx(false);
Star.SetActiveEx(IsStar); Star.SetActiveEx(IsStar);
if (m_romfile == null) return; if (m_romfile == null) return;
if (!m_romfile.InfoReady) return; if (!m_romfile.InfoReady) return;
if (m_romfile.IsDownloading) if (m_romfile.IsDownloading)
{ {
DownloadingFlag.SetActiveEx(true); DownloadingFlag.SetActiveEx(true);
DownProgress.value = m_romfile.Progress; DownProgress.value = m_romfile.Progress;
} }
else if (m_romfile.RomReady) else if (m_romfile.RomReady)
{ {
FileReadyFlag.SetActiveEx(true); FileReadyFlag.SetActiveEx(true);
} }
base.Update(); base.Update();
} }
} }
} }

View File

@ -1,109 +1,109 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf; using AxibugProtobuf;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class RomListMenuItem : VirtualSubMenuItem public class RomListMenuItem : VirtualSubMenuItem
{ {
[SerializeField] [SerializeField]
protected bool StarRom; protected bool StarRom;
[SerializeField] [SerializeField]
protected RomPlatformType Platform; protected RomPlatformType Platform;
private RomLib RomLib private RomLib RomLib
{
get
{
if (StarRom) return App.starRomLib;
else return App.GetRomLib(Platform);
}
}
private List<InternalOptionMenu> m_options;
protected override void Awake()
{
base.Awake();
m_options = new List<InternalOptionMenu>()
{
new OptMenu_Search(this),
new OptMenu_ShowAll(this),
new OptMenu_Fav(this),
};
}
public string SearchKey;
protected override void GetVirtualListDatas(VirtualListDataHandle callback)
{
RomLib.FetchRomCount((roms) => callback.Invoke(roms, 0), SearchKey);
}
public override bool OnEnterItem()
{
var res = base.OnEnterItem();
if (res) CommandDispatcher.Instance.RegistController(this);
return true;
}
public override bool OnExitItem()
{
var res = base.OnExitItem();
if (res) CommandDispatcher.Instance.UnRegistController(this);
return false;
}
protected override void OnCmdOptionMenu()
{ {
OverlayManager.PopSideBar(m_options); get
} {
if (StarRom) return App.starRomLib;
public class OptMenu_Search : ExecuteMenu else return App.GetRomLib(Platform);
{ }
private RomListMenuItem m_romListUI; }
public override string Name => "搜索";
private List<InternalOptionMenu> m_options;
protected override void Awake()
{
base.Awake();
m_options = new List<InternalOptionMenu>()
{
new OptMenu_Search(this),
new OptMenu_ShowAll(this),
new OptMenu_Fav(this),
};
}
public string SearchKey;
protected override void GetVirtualListDatas(VirtualListDataHandle callback)
{
RomLib.FetchRomCount((roms) => callback.Invoke(roms, 0), SearchKey);
}
public override bool OnEnterItem()
{
var res = base.OnEnterItem();
if (res) CommandDispatcher.Instance.RegistController(this);
return true;
}
public override bool OnExitItem()
{
var res = base.OnExitItem();
if (res) CommandDispatcher.Instance.UnRegistController(this);
return false;
}
protected override void OnCmdOptionMenu()
{
OverlayManager.PopSideBar(m_options);
}
public class OptMenu_Search : ExecuteMenu
{
private RomListMenuItem m_romListUI;
public override string Name => "搜索";
public OptMenu_Search(RomListMenuItem romListUI) public OptMenu_Search(RomListMenuItem romListUI)
{ {
m_romListUI = romListUI; m_romListUI = romListUI;
} }
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) public override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{ {
OverlayManager.Input(OnSearchCommit, "输入Rom名称", m_romListUI.SearchKey); OverlayManager.Input(OnSearchCommit, "输入Rom名称", m_romListUI.SearchKey);
} }
private void OnSearchCommit(string text) private void OnSearchCommit(string text)
{ {
m_romListUI.SearchKey = text; m_romListUI.SearchKey = text;
m_romListUI.RefreshUI(); m_romListUI.RefreshUI();
} }
} }
public class OptMenu_ShowAll : ExecuteMenu public class OptMenu_ShowAll : ExecuteMenu
{ {
private RomListMenuItem m_ui; private RomListMenuItem m_ui;
public override string Name => "显示全部"; public override string Name => "显示全部";
public override bool Visible => !string.IsNullOrWhiteSpace(m_ui.SearchKey); public override bool Visible => !string.IsNullOrWhiteSpace(m_ui.SearchKey);
public OptMenu_ShowAll(RomListMenuItem romListUI) public OptMenu_ShowAll(RomListMenuItem romListUI)
{ {
m_ui = romListUI; m_ui = romListUI;
} }
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) public override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{ {
m_ui.SearchKey = null; m_ui.SearchKey = null;
m_ui.RefreshUI(); m_ui.RefreshUI();
} }
} }
public class OptMenu_Fav : ExecuteMenu public class OptMenu_Fav : ExecuteMenu
{ {
private RomListMenuItem m_romListUI; private RomListMenuItem m_romListUI;
@ -129,6 +129,6 @@ namespace AxibugEmuOnline.Client
else else
App.share.SendGameStar(romItem.RomID, 0); App.share.SendGameStar(romItem.RomID, 0);
} }
} }
} }
} }

View File

@ -1,45 +1,45 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.Network; using AxibugEmuOnline.Client.Network;
using AxibugProtobuf; using AxibugProtobuf;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class InGameUI : CommandExecuter public class InGameUI : CommandExecuter
{ {
private bool m_delayCreateRoom; private bool m_delayCreateRoom;
private object m_state; private object m_state;
private StepPerformer m_stepPerformer; private StepPerformer m_stepPerformer;
private readonly List<InternalOptionMenu> menus = new List<InternalOptionMenu>(); private readonly List<InternalOptionMenu> menus = new List<InternalOptionMenu>();
public static InGameUI Instance { get; private set; } public static InGameUI Instance { get; private set; }
public RomFile RomFile { get; private set; } public RomFile RomFile { get; private set; }
public override bool Enable => gameObject.activeInHierarchy; public override bool Enable => gameObject.activeInHierarchy;
public EmuCore Core { get; private set; } public EmuCore Core { get; private set; }
protected override void Awake() protected override void Awake()
{ {
Instance = this; Instance = this;
gameObject.SetActiveEx(false); gameObject.SetActiveEx(false);
m_stepPerformer = new StepPerformer(this); m_stepPerformer = new StepPerformer(this);
menus.Add(new InGameUI_FilterSetting(this)); menus.Add(new InGameUI_FilterSetting(this));
menus.Add(new InGameUI_Scaler(this)); menus.Add(new InGameUI_Scaler(this));
menus.Add(new InGameUI_Reset(this)); menus.Add(new InGameUI_Reset(this));
menus.Add(new InGameUI_SaveStateQuick(this)); menus.Add(new InGameUI_SaveStateQuick(this));
menus.Add(new InGameUI_LoadStateQuick(this)); menus.Add(new InGameUI_LoadStateQuick(this));
menus.Add(new InGameUI_SaveStateMenu(this)); menus.Add(new InGameUI_SaveStateMenu(this));
menus.Add(new InGameUI_QuitGame(this)); menus.Add(new InGameUI_QuitGame(this));
base.Awake(); base.Awake();
} }
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
@ -48,8 +48,8 @@ namespace AxibugEmuOnline.Client
App.settings.Filter.ExecuteFilterRender(Core.OutputPixel, Core.DrawCanvas); App.settings.Filter.ExecuteFilterRender(Core.OutputPixel, Core.DrawCanvas);
App.settings.ScreenScaler.CalcScale(Core.DrawCanvas, Core.Platform); App.settings.ScreenScaler.CalcScale(Core.DrawCanvas, Core.Platform);
} }
void PushCoreFrame() void PushCoreFrame()
{ {
if (Core == null) return; if (Core == null) return;
@ -57,70 +57,70 @@ namespace AxibugEmuOnline.Client
NetMsg.Instance.DequeueNesMsg(); NetMsg.Instance.DequeueNesMsg();
Core.PushEmulatorFrame(); Core.PushEmulatorFrame();
} }
protected override void OnDestroy() protected override void OnDestroy()
{ {
Instance = null; Instance = null;
base.OnDestroy(); base.OnDestroy();
} }
/// <summary> 保存快速快照 </summary> /// <summary> 保存快速快照 </summary>
public void SaveQuickState(object state) public void SaveQuickState(object state)
{ {
m_state = state; m_state = state;
} }
/// <summary> /// <summary>
/// 读取快速快照 /// 读取快速快照
/// </summary> /// </summary>
public object GetQuickState() public object GetQuickState()
{ {
return m_state; return m_state;
} }
public void Show(RomFile currentRom, EmuCore core) public void Show(RomFile currentRom, EmuCore core)
{ {
m_delayCreateRoom = false; m_delayCreateRoom = false;
m_state = null; //清空游戏快照 m_state = null; //清空游戏快照
CommandDispatcher.Instance.RegistController(this); CommandDispatcher.Instance.RegistController(this);
RomFile = currentRom; RomFile = currentRom;
Core = core; Core = core;
m_stepPerformer.Reset(); m_stepPerformer.Reset();
if (!App.roomMgr.InRoom) if (!App.roomMgr.InRoom)
{ {
if (App.user.IsLoggedIn) if (App.user.IsLoggedIn)
{ {
App.roomMgr.SendCreateRoom(RomFile.ID, RomFile.Hash); App.roomMgr.SendCreateRoom(RomFile.ID, RomFile.Hash);
} }
else else
{ {
m_delayCreateRoom = true; m_delayCreateRoom = true;
OverlayManager.PopTip("稍后将会建立房间"); OverlayManager.PopTip("稍后将会建立房间");
} }
} }
Eventer.Instance.RegisterEvent(EEvent.OnLoginSucceed, OnLoggedIn); Eventer.Instance.RegisterEvent(EEvent.OnLoginSucceed, OnLoggedIn);
Eventer.Instance.RegisterEvent<int>(EEvent.OnRoomWaitStepChange, OnServerStepUpdate); Eventer.Instance.RegisterEvent<int>(EEvent.OnRoomWaitStepChange, OnServerStepUpdate);
Eventer.Instance.RegisterEvent(EEvent.OnMineRoomCreated, OnRoomCreated); Eventer.Instance.RegisterEvent(EEvent.OnMineRoomCreated, OnRoomCreated);
gameObject.SetActiveEx(true); gameObject.SetActiveEx(true);
var filterSetting = App.settings.Filter.GetFilterSetting(currentRom); var filterSetting = App.settings.Filter.GetFilterSetting(currentRom);
if (filterSetting.filter != null) if (filterSetting.filter != null)
{ {
var filter = filterSetting.filter; var filter = filterSetting.filter;
var preset = filterSetting.preset ?? filter.DefaultPreset; var preset = filterSetting.preset ?? filter.DefaultPreset;
filter.ApplyPreset(preset); filter.ApplyPreset(preset);
App.settings.Filter.EnableFilter(filter); App.settings.Filter.EnableFilter(filter);
} }
} }
private void OnRoomCreated() private void OnRoomCreated()
{ {
if (m_delayCreateRoom) if (m_delayCreateRoom)
{ {
m_delayCreateRoom = false; m_delayCreateRoom = false;
@ -138,48 +138,48 @@ namespace AxibugEmuOnline.Client
} }
App.roomMgr.SendChangePlaySlotIdxWithJoyIdx(temp); App.roomMgr.SendChangePlaySlotIdxWithJoyIdx(temp);
} }
} }
private void OnLoggedIn() private void OnLoggedIn()
{ {
if (m_delayCreateRoom) App.roomMgr.SendCreateRoom(RomFile.ID, RomFile.Hash); if (m_delayCreateRoom) App.roomMgr.SendCreateRoom(RomFile.ID, RomFile.Hash);
} }
private void OnServerStepUpdate(int step) private void OnServerStepUpdate(int step)
{ {
m_stepPerformer.Perform(step); m_stepPerformer.Perform(step);
} }
public void Hide() public void Hide()
{ {
CommandDispatcher.Instance.UnRegistController(this); CommandDispatcher.Instance.UnRegistController(this);
gameObject.SetActiveEx(false); gameObject.SetActiveEx(false);
App.settings.Filter.ShutDownFilter(); App.settings.Filter.ShutDownFilter();
} }
protected override void OnCmdOptionMenu() protected override void OnCmdOptionMenu()
{ {
OverlayManager.PopSideBar(menus, 0, PopMenu_OnHide); OverlayManager.PopSideBar(menus, 0, PopMenu_OnHide);
if (!Core.IsNetPlay) //单人模式暂停模拟器 if (!Core.IsNetPlay) //单人模式暂停模拟器
Core.Pause(); Core.Pause();
} }
//菜单关闭时候 //菜单关闭时候
private void PopMenu_OnHide() private void PopMenu_OnHide()
{ {
if (!Core.IsNetPlay) //单人模式恢复模拟器的暂停 if (!Core.IsNetPlay) //单人模式恢复模拟器的暂停
Core.Resume(); Core.Resume();
} }
public void QuitGame() public void QuitGame()
{ {
Eventer.Instance.UnregisterEvent<int>(EEvent.OnRoomWaitStepChange, OnServerStepUpdate); Eventer.Instance.UnregisterEvent<int>(EEvent.OnRoomWaitStepChange, OnServerStepUpdate);
Eventer.Instance.UnregisterEvent(EEvent.OnLoginSucceed, OnLoggedIn); Eventer.Instance.UnregisterEvent(EEvent.OnLoginSucceed, OnLoggedIn);
Eventer.Instance.UnregisterEvent(EEvent.OnMineRoomCreated, OnRoomCreated); Eventer.Instance.UnregisterEvent(EEvent.OnMineRoomCreated, OnRoomCreated);
App.roomMgr.SendLeavnRoom(); App.roomMgr.SendLeavnRoom();
App.emu.StopGame(); App.emu.StopGame();
} }
} }
} }

View File

@ -1,28 +1,28 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using static AxibugEmuOnline.Client.Settings.FilterManager; using static AxibugEmuOnline.Client.Settings.FilterManager;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class InGameUI_FilterSetting : ExpandMenu public class InGameUI_FilterSetting : ExpandMenu
{ {
private InGameUI m_gameUI; private InGameUI m_gameUI;
public override string Name => "滤镜"; public override string Name => "滤镜";
public InGameUI_FilterSetting(InGameUI gameUI) public InGameUI_FilterSetting(InGameUI gameUI)
{ {
m_gameUI = gameUI; m_gameUI = gameUI;
} }
protected override List<InternalOptionMenu> GetOptionMenus() protected override List<InternalOptionMenu> GetOptionMenus()
{ {
List<InternalOptionMenu> menus = new List<InternalOptionMenu>(); List<InternalOptionMenu> menus = new List<InternalOptionMenu>();
menus.Add(new FilterNone(m_gameUI.RomFile)); menus.Add(new FilterNone(m_gameUI.RomFile));
menus.AddRange(App.settings.Filter.Filters.Select(f => new FilterMenu(m_gameUI.RomFile, f) as InternalOptionMenu)); menus.AddRange(App.settings.Filter.Filters.Select(f => new FilterMenu(m_gameUI.RomFile, f) as InternalOptionMenu));
return menus; return menus;
} }
public class FilterNone : ExecuteMenu public class FilterNone : ExecuteMenu
{ {
private RomFile m_rom; private RomFile m_rom;
@ -36,16 +36,16 @@ namespace AxibugEmuOnline.Client
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) public override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{ {
App.settings.Filter.ShutDownFilter(); App.settings.Filter.ShutDownFilter();
App.settings.Filter.SetupFilter(m_rom, null, null); App.settings.Filter.SetupFilter(m_rom, null, null);
} }
} }
public class FilterMenu : ExpandMenu public class FilterMenu : ExpandMenu
{ {
private Filter m_filter; private Filter m_filter;
private List<InternalOptionMenu> m_presetsMenuItems; private List<InternalOptionMenu> m_presetsMenuItems;
public override bool IsApplied public override bool IsApplied
{ {
get get
@ -57,27 +57,27 @@ namespace AxibugEmuOnline.Client
return false; return false;
} }
} }
public override string Name => m_filter.Name; public override string Name => m_filter.Name;
public FilterMenu(RomFile rom, Filter filter) public FilterMenu(RomFile rom, Filter filter)
{ {
m_filter = filter; m_filter = filter;
m_presetsMenuItems = new List<InternalOptionMenu> { new FilterPresetMenu(rom, m_filter, m_filter.DefaultPreset) }; m_presetsMenuItems = new List<InternalOptionMenu> { new FilterPresetMenu(rom, m_filter, m_filter.DefaultPreset) };
m_presetsMenuItems.AddRange(m_filter.Presets.Select(preset => new FilterPresetMenu(rom, m_filter, preset))); m_presetsMenuItems.AddRange(m_filter.Presets.Select(preset => new FilterPresetMenu(rom, m_filter, preset)));
} }
protected override List<InternalOptionMenu> GetOptionMenus() protected override List<InternalOptionMenu> GetOptionMenus()
{ {
return m_presetsMenuItems; return m_presetsMenuItems;
} }
} }
public class FilterPresetMenu : ExecuteMenu public class FilterPresetMenu : ExecuteMenu
{ {
private FilterPreset m_preset; private FilterPreset m_preset;
private RomFile m_rom; private RomFile m_rom;
private Filter m_filter; private Filter m_filter;
public override bool IsApplied public override bool IsApplied
{ {
get get
@ -89,19 +89,19 @@ namespace AxibugEmuOnline.Client
public override string Name => m_preset.Name; public override string Name => m_preset.Name;
public FilterPresetMenu(RomFile rom, Filter filter, FilterPreset preset) public FilterPresetMenu(RomFile rom, Filter filter, FilterPreset preset)
{ {
m_preset = preset; m_preset = preset;
m_rom = rom; m_rom = rom;
m_filter = filter; m_filter = filter;
} }
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) public override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{ {
m_filter.ApplyPreset(m_preset); m_filter.ApplyPreset(m_preset);
App.settings.Filter.EnableFilter(m_filter); App.settings.Filter.EnableFilter(m_filter);
App.settings.Filter.SetupFilter(m_rom, m_filter, m_preset); App.settings.Filter.SetupFilter(m_rom, m_filter, m_preset);
} }
} }
} }
} }

View File

@ -1,25 +1,25 @@
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class InGameUI_LoadStateQuick : ExecuteMenu public class InGameUI_LoadStateQuick : ExecuteMenu
{ {
private InGameUI m_gameUI; private InGameUI m_gameUI;
public override bool Visible => !m_gameUI.Core.IsNetPlay && m_gameUI.GetQuickState() != null; public override bool Visible => !m_gameUI.Core.IsNetPlay && m_gameUI.GetQuickState() != null;
public override string Name => "快速读取"; public override string Name => "快速读取";
public InGameUI_LoadStateQuick(InGameUI gameUI) public InGameUI_LoadStateQuick(InGameUI gameUI)
{ {
m_gameUI = gameUI; m_gameUI = gameUI;
} }
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) public override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{ {
if (m_gameUI.Core.IsNetPlay) return; if (m_gameUI.Core.IsNetPlay) return;
object state = m_gameUI.GetQuickState(); object state = m_gameUI.GetQuickState();
if (state != null) if (state != null)
{ {
m_gameUI.Core.LoadState(state); m_gameUI.Core.LoadState(state);
} }
} }
} }
} }

View File

@ -1,25 +1,25 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class InGameUI_Reset : ExecuteMenu public class InGameUI_Reset : ExecuteMenu
{ {
private InGameUI m_gameUI; private InGameUI m_gameUI;
public override string Name => "复位"; public override string Name => "复位";
public override bool Visible => !m_gameUI.Core.IsNetPlay || App.roomMgr.IsHost; public override bool Visible => !m_gameUI.Core.IsNetPlay || App.roomMgr.IsHost;
public InGameUI_Reset(InGameUI gameUI) public InGameUI_Reset(InGameUI gameUI)
{ {
m_gameUI = gameUI; m_gameUI = gameUI;
} }
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) public override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{ {
if (!m_gameUI.Core.IsNetPlay) if (!m_gameUI.Core.IsNetPlay)
{ {
App.emu.ResetGame(); App.emu.ResetGame();
} }
} }
} }
} }

View File

@ -92,16 +92,18 @@ namespace AxibugEmuOnline.Client
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) public override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{ {
if (m_savFile.IsBusy) //取消同步进程 if (m_savFile.IsBusy)
{ {
m_savFile.FSM.ChangeState<SaveFile.IdleState>(); OverlayManager.PopTip("存档正在同步中");
cancelHide = true;
return;
} }
var stateData = m_ingameUI.Core.GetStateBytes(); var stateData = m_ingameUI.Core.GetStateBytes();
var tex = m_ingameUI.Core.OutputPixel; var tex = m_ingameUI.Core.OutputPixel;
var screenData = tex.ToJPG(m_ingameUI.Core.DrawCanvas.transform.localScale); var screenData = tex.ToJPG(m_ingameUI.Core.DrawCanvas.transform.localScale);
m_savFile.Save(m_savFile.Sequecen + 1, stateData, screenData); m_savFile.Save(m_savFile.Sequecen, stateData, screenData);
} }
} }
@ -165,6 +167,7 @@ namespace AxibugEmuOnline.Client
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) public override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{ {
if (m_savFile.GetCurrentState() is not SaveFile.ConflictState) return; if (m_savFile.GetCurrentState() is not SaveFile.ConflictState) return;
cancelHide = true;
m_savFile.FSM.ChangeState<SaveFile.DownloadingState>(); m_savFile.FSM.ChangeState<SaveFile.DownloadingState>();
} }
} }
@ -184,6 +187,7 @@ namespace AxibugEmuOnline.Client
public override void OnExcute(OptionUI optionUI, ref bool cancelHide) public override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{ {
if (m_savFile.GetCurrentState() is not SaveFile.ConflictState) return; if (m_savFile.GetCurrentState() is not SaveFile.ConflictState) return;
cancelHide = true;
m_savFile.FSM.ChangeState<SaveFile.UploadingState>(); m_savFile.FSM.ChangeState<SaveFile.UploadingState>();
} }
} }

View File

@ -1,59 +1,59 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public static class GameObjectPool public static class GameObjectPool
{ {
private static GameObject PoolAttach; private static GameObject PoolAttach;
private static Dictionary<GameObject, Queue<GameObject>> s_poolMap = new Dictionary<GameObject, Queue<GameObject>>(); private static Dictionary<GameObject, Queue<GameObject>> s_poolMap = new Dictionary<GameObject, Queue<GameObject>>();
private static Dictionary<GameObject, GameObject> s_instanceToSrc = new Dictionary<GameObject, GameObject>(); private static Dictionary<GameObject, GameObject> s_instanceToSrc = new Dictionary<GameObject, GameObject>();
public static GameObject GetInstance(GameObject prefabSrc, Transform parent) public static GameObject GetInstance(GameObject prefabSrc, Transform parent)
{ {
if (PoolAttach == null) if (PoolAttach == null)
{ {
PoolAttach = new GameObject("[GameObjectPool]"); PoolAttach = new GameObject("[GameObjectPool]");
PoolAttach.transform.localScale = Vector3.zero; PoolAttach.transform.localScale = Vector3.zero;
GameObject.DontDestroyOnLoad(PoolAttach); GameObject.DontDestroyOnLoad(PoolAttach);
} }
if (!s_poolMap.ContainsKey(prefabSrc)) s_poolMap[prefabSrc] = new Queue<GameObject>(); if (!s_poolMap.ContainsKey(prefabSrc)) s_poolMap[prefabSrc] = new Queue<GameObject>();
GameObject instance = null; GameObject instance = null;
var pool = s_poolMap[prefabSrc]; var pool = s_poolMap[prefabSrc];
if (pool.Count > 0) if (pool.Count > 0)
{ {
instance = pool.Dequeue(); instance = pool.Dequeue();
instance.transform.SetParent(parent, true); instance.transform.SetParent(parent, true);
instance.transform.localScale = prefabSrc.transform.localScale; instance.transform.localScale = prefabSrc.transform.localScale;
instance.transform.localRotation = prefabSrc.transform.localRotation; instance.transform.localRotation = prefabSrc.transform.localRotation;
instance.transform.localPosition = prefabSrc.transform.localPosition; instance.transform.localPosition = prefabSrc.transform.localPosition;
} }
else else
{ {
instance = GameObject.Instantiate(prefabSrc, parent); instance = GameObject.Instantiate(prefabSrc, parent);
s_instanceToSrc[instance] = prefabSrc; s_instanceToSrc[instance] = prefabSrc;
} }
//instance.SetActive(true); //instance.SetActive(true);
return instance; return instance;
} }
public static void Release(GameObject instance) public static void Release(GameObject instance)
{ {
GameObject src; GameObject src;
Queue<GameObject> pool; Queue<GameObject> pool;
s_instanceToSrc.TryGetValue(instance, out src); s_instanceToSrc.TryGetValue(instance, out src);
if (src != null && s_poolMap.TryGetValue(src, out pool)) if (src != null && s_poolMap.TryGetValue(src, out pool))
{ {
pool.Enqueue(instance); pool.Enqueue(instance);
//instance.SetActive(false); //instance.SetActive(false);
if (instance == null) return; if (instance == null) return;
if (PoolAttach == null) return; if (PoolAttach == null) return;
instance.transform.SetParent(PoolAttach.transform, true); instance.transform.SetParent(PoolAttach.transform, true);
} }
else else
{ {
GameObject.Destroy(instance); GameObject.Destroy(instance);
} }
} }
} }

View File

@ -1,11 +1,11 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
public interface IVirtualLayout public interface IVirtualLayout
{ {
Dictionary<GameObject, ScripteInterface> CacheItemScripts { get; } Dictionary<GameObject, ScripteInterface> CacheItemScripts { get; }
List<object> DataList { get; } List<object> DataList { get; }
@ -18,10 +18,10 @@ public interface IVirtualLayout
void UpdateProxyVisualState(); void UpdateProxyVisualState();
void UpdateDependencyProperty(object dp); void UpdateDependencyProperty(object dp);
void SetData(IEnumerable dataList); void SetData(IEnumerable dataList);
void MoveToScrollViewCenter(ScrollRect scrollRect, int dataIndex); void MoveToScrollViewCenter(ScrollRect scrollRect, int dataIndex);
} }
public class ItemProxy public class ItemProxy
{ {
public bool IsDestroyed; public bool IsDestroyed;
public bool Visible = true; public bool Visible = true;
@ -207,10 +207,10 @@ public class ItemProxy
GameObject.DestroyImmediate(_runtimeInstance.gameObject); GameObject.DestroyImmediate(_runtimeInstance.gameObject);
_runtimeInstance = null; _runtimeInstance = null;
} }
} }
} }
public class ScripteInterface public class ScripteInterface
{ {
private IVirtualItem _itemInstance; private IVirtualItem _itemInstance;
public IVirtualItem ItemInstance => _itemInstance; public IVirtualItem ItemInstance => _itemInstance;
@ -237,15 +237,15 @@ public class ScripteInterface
if (_itemInstance == null) return; if (_itemInstance == null) return;
_itemInstance.SetDependencyProperty(dependencyProperty); _itemInstance.SetDependencyProperty(dependencyProperty);
} }
} }
public interface IVirtualItem public interface IVirtualItem
{ {
GameObject gameObject { get; } GameObject gameObject { get; }
int Index { get; set; } int Index { get; set; }
void SetData(object data); void SetData(object data);
void SetDependencyProperty(object data); void SetDependencyProperty(object data);
void Release(); void Release();
} }

View File

@ -1,131 +1,131 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.UI; using AxibugEmuOnline.Client.UI;
using Coffee.UIExtensions; using Coffee.UIExtensions;
using DG.Tweening; using DG.Tweening;
using DG.Tweening.Core; using DG.Tweening.Core;
using DG.Tweening.Plugins.Options; using DG.Tweening.Plugins.Options;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class LaunchUI : MonoBehaviour public class LaunchUI : MonoBehaviour
{ {
[SerializeField] [SerializeField]
RectTransform MainMenuRoot; RectTransform MainMenuRoot;
[SerializeField] [SerializeField]
MainMenuController MainMenu; MainMenuController MainMenu;
[SerializeField] [SerializeField]
Image XMBBackground; Image XMBBackground;
[SerializeField] [SerializeField]
Image RomPreviewBigPic; Image RomPreviewBigPic;
[SerializeField] [SerializeField]
CanvasGroup XMBCG_For_RomPreviewBigPic; CanvasGroup XMBCG_For_RomPreviewBigPic;
Vector2 m_mainLayoutPosition; Vector2 m_mainLayoutPosition;
[SerializeField] [SerializeField]
float m_detailLayoutPosition_x = 55; float m_detailLayoutPosition_x = 55;
[SerializeField] [SerializeField]
float m_LayoutChangeSpeed = 10; float m_LayoutChangeSpeed = 10;
public static LaunchUI Instance { get; private set; } public static LaunchUI Instance { get; private set; }
TweenerCore<Vector2, Vector2, VectorOptions> m_layoutTween; TweenerCore<Vector2, Vector2, VectorOptions> m_layoutTween;
AlphaWraper romPreviewWraper; AlphaWraper romPreviewWraper;
private void Awake() private void Awake()
{ {
Instance = this; Instance = this;
m_mainLayoutPosition = MainMenuRoot.anchoredPosition; m_mainLayoutPosition = MainMenuRoot.anchoredPosition;
MainMenu.ListenControlAction = true; MainMenu.ListenControlAction = true;
romPreviewWraper = new AlphaWraper(XMBCG_For_RomPreviewBigPic, RomPreviewBigPic.GetComponent<CanvasGroup>(), false); romPreviewWraper = new AlphaWraper(XMBCG_For_RomPreviewBigPic, RomPreviewBigPic.GetComponent<CanvasGroup>(), false);
} }
private void Start() private void Start()
{ {
CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Normal; CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Normal;
} }
private void Update() private void Update()
{ {
if (CommandDispatcher.Instance.Mode == CommandListener.ScheduleType.Gaming && App.emu.Core == null) if (CommandDispatcher.Instance.Mode == CommandListener.ScheduleType.Gaming && App.emu.Core == null)
CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Normal; CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Normal;
} }
public void HideMainMenu() public void HideMainMenu()
{ {
XMBBackground.gameObject.SetActiveEx(false); XMBBackground.gameObject.SetActiveEx(false);
MainMenuRoot.gameObject.SetActiveEx(false); MainMenuRoot.gameObject.SetActiveEx(false);
RomPreviewBigPic.gameObject.SetActiveEx(false); RomPreviewBigPic.gameObject.SetActiveEx(false);
} }
public void ShowMainMenu() public void ShowMainMenu()
{ {
XMBBackground.gameObject.SetActiveEx(true); XMBBackground.gameObject.SetActiveEx(true);
MainMenuRoot.gameObject.SetActiveEx(true); MainMenuRoot.gameObject.SetActiveEx(true);
if (romPreviewWraper.On) if (romPreviewWraper.On)
{ {
XMBCG_For_RomPreviewBigPic.gameObject.SetActive(false); XMBCG_For_RomPreviewBigPic.gameObject.SetActive(false);
RomPreviewBigPic.gameObject.SetActive(true); RomPreviewBigPic.gameObject.SetActive(true);
} }
else if (!romPreviewWraper.On) else if (!romPreviewWraper.On)
{ {
XMBCG_For_RomPreviewBigPic.gameObject.SetActive(true); XMBCG_For_RomPreviewBigPic.gameObject.SetActive(true);
XMBCG_For_RomPreviewBigPic.alpha = 1; XMBCG_For_RomPreviewBigPic.alpha = 1;
RomPreviewBigPic.gameObject.SetActive(false); RomPreviewBigPic.gameObject.SetActive(false);
} }
} }
public void HideRomPreview() public void HideRomPreview()
{ {
romPreviewWraper.On = false; romPreviewWraper.On = false;
} }
public void SetRomPreview(Sprite sp) public void SetRomPreview(Sprite sp)
{ {
if (MainMenu.ListenControlAction) return; if (MainMenu.ListenControlAction) return;
RomPreviewBigPic.sprite = sp; RomPreviewBigPic.sprite = sp;
romPreviewWraper.On = true; romPreviewWraper.On = true;
} }
public void ToDetailMenuLayout() public void ToDetailMenuLayout()
{ {
if (m_layoutTween != null) if (m_layoutTween != null)
{ {
m_layoutTween.Kill(); m_layoutTween.Kill();
m_layoutTween = null; m_layoutTween = null;
} }
m_layoutTween = DOTween m_layoutTween = DOTween
.To( .To(
() => MainMenuRoot.anchoredPosition, () => MainMenuRoot.anchoredPosition,
(x) => MainMenuRoot.anchoredPosition = x, (x) => MainMenuRoot.anchoredPosition = x,
new Vector2(m_detailLayoutPosition_x, MainMenuRoot.anchoredPosition.y), new Vector2(m_detailLayoutPosition_x, MainMenuRoot.anchoredPosition.y),
m_LayoutChangeSpeed) m_LayoutChangeSpeed)
.SetSpeedBased(); .SetSpeedBased();
MainMenu.ListenControlAction = false; MainMenu.ListenControlAction = false;
MainMenu.EnterDetailState(); MainMenu.EnterDetailState();
} }
public void ToMainMenuLayout() public void ToMainMenuLayout()
{ {
if (m_layoutTween != null) if (m_layoutTween != null)
{ {
m_layoutTween.Kill(); m_layoutTween.Kill();
m_layoutTween = null; m_layoutTween = null;
} }
m_layoutTween = DOTween.To( m_layoutTween = DOTween.To(
() => MainMenuRoot.anchoredPosition, () => MainMenuRoot.anchoredPosition,
(x) => MainMenuRoot.anchoredPosition = x, (x) => MainMenuRoot.anchoredPosition = x,
m_mainLayoutPosition, m_mainLayoutPosition,
m_LayoutChangeSpeed) m_LayoutChangeSpeed)
.SetSpeedBased(); .SetSpeedBased();
MainMenu.ListenControlAction = true; MainMenu.ListenControlAction = true;
MainMenu.ExitDetailState(); MainMenu.ExitDetailState();
HideRomPreview(); HideRomPreview();
} }
} }
} }

View File

@ -1,334 +1,332 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using DG.Tweening; using DG.Tweening;
using DG.Tweening.Core; using DG.Tweening.Core;
using DG.Tweening.Plugins.Options; using DG.Tweening.Plugins.Options;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class OptionUI : CommandExecuter public class OptionUI : CommandExecuter
{ {
[SerializeField] [SerializeField]
RectTransform MenuRoot; RectTransform MenuRoot;
[SerializeField] [SerializeField]
Selector SelectBorder; Selector SelectBorder;
Dictionary<Type, OptionUI_MenuItem> m_menuUI_templates = new Dictionary<Type, OptionUI_MenuItem>(); Dictionary<Type, OptionUI_MenuItem> m_menuUI_templates = new Dictionary<Type, OptionUI_MenuItem>();
private OptionUI m_child; private OptionUI m_child;
private OptionUI m_parent; private OptionUI m_parent;
public override bool AloneMode => true; public override bool AloneMode => true;
public override bool Enable => m_bPoped && (!m_child || !m_child.m_bPoped); public override bool Enable => m_bPoped && (!m_child || !m_child.m_bPoped);
private bool m_bPoped; private bool m_bPoped;
private readonly List<OptionUI_MenuItem> m_runtimeMenuItems = new List<OptionUI_MenuItem>(); private readonly List<OptionUI_MenuItem> m_runtimeMenuItems = new List<OptionUI_MenuItem>();
private int m_selectIndex = -1; private int m_selectIndex = -1;
public int SelectIndex public int SelectIndex
{ {
get => m_selectIndex; get => m_selectIndex;
set set
{ {
value = Mathf.Clamp(value, 0, m_runtimeMenuItems.Count - 1); value = Mathf.Clamp(value, 0, m_runtimeMenuItems.Count - 1);
if (m_selectIndex == value) return; if (m_selectIndex == value) return;
var gap = value - m_selectIndex; var gap = value - m_selectIndex;
var temp = value; var temp = value;
while (!m_runtimeMenuItems[value].Visible) while (!m_runtimeMenuItems[value].Visible)
{ {
if (gap > 0) if (gap > 0)
{ {
temp++; temp++;
if (temp >= m_runtimeMenuItems.Count) return; if (temp >= m_runtimeMenuItems.Count) return;
} }
else else
{ {
temp--; temp--;
if (temp < 0) return; if (temp < 0) return;
} }
if (temp >= 0 && temp < m_runtimeMenuItems.Count) if (temp >= 0 && temp < m_runtimeMenuItems.Count)
value = temp; value = temp;
} }
m_selectIndex = value; m_selectIndex = value;
OptionUI_MenuItem optionUI_MenuItem = m_runtimeMenuItems[m_selectIndex]; OptionUI_MenuItem optionUI_MenuItem = m_runtimeMenuItems[m_selectIndex];
optionUI_MenuItem.OnFocus(); optionUI_MenuItem.OnFocus();
var itemUIRect = optionUI_MenuItem.transform as RectTransform; var itemUIRect = optionUI_MenuItem.transform as RectTransform;
SelectBorder.Target = itemUIRect; SelectBorder.Target = itemUIRect;
} }
} }
protected override void Awake() protected override void Awake()
{ {
foreach (var templateIns in GetComponentsInChildren<OptionUI_MenuItem>(true)) foreach (var templateIns in GetComponentsInChildren<OptionUI_MenuItem>(true))
{ {
m_menuUI_templates[templateIns.GetType()] = templateIns; m_menuUI_templates[templateIns.GetType()] = templateIns;
templateIns.gameObject.SetActiveEx(false); templateIns.gameObject.SetActiveEx(false);
} }
SelectBorder.gameObject.SetActiveEx(false); SelectBorder.gameObject.SetActiveEx(false);
base.Awake(); base.Awake();
} }
protected override void Update() protected override void Update()
{ {
SelectBorder.Active = Enable; SelectBorder.Active = Enable;
UpdateMenuState(); UpdateMenuState();
base.Update(); base.Update();
} }
private void UpdateMenuState() private void UpdateMenuState()
{ {
if (!m_bPoped) return; if (!m_bPoped) return;
if (checkDirty()) if (checkDirty())
{ {
Canvas.ForceUpdateCanvases(); Canvas.ForceUpdateCanvases();
var topParent = FindTopOptionUI();
var totalWidth = GetTotalWidth(topParent);
Vector2 end = new Vector2(-totalWidth, MenuRoot.anchoredPosition.y);
if (m_popTween != null) if (m_popTween != null)
{ {
Vector2 end = new Vector2(-MenuRoot.rect.width, MenuRoot.anchoredPosition.y);
m_popTween.ChangeEndValue(end, false); m_popTween.ChangeEndValue(end, false);
} }
else else
{ {
topParent.MenuRoot.anchoredPosition = end; Vector2 end = new Vector2(-MenuRoot.rect.width, MenuRoot.anchoredPosition.y);
var topParent = m_parent;
while (topParent != null && topParent.m_parent != null)
{
topParent = topParent.m_parent;
}
if (topParent != null)
{
topParent.MenuRoot.anchoredPosition = end;
}
else
{
MenuRoot.anchoredPosition = end;
}
} }
RebuildSelectIndex(); RebuildSelectIndex();
} }
}
private void RebuildSelectIndex()
{
Canvas.ForceUpdateCanvases();
SelectIndex = Mathf.Clamp(SelectIndex, 0, m_runtimeMenuItems.Count - 1);
var selectItem = m_runtimeMenuItems[SelectIndex];
if (selectItem.Visible == false)
{
bool find = false;
int currentSelect = SelectIndex;
while (currentSelect > 0)
{
currentSelect--;
if (m_runtimeMenuItems[currentSelect].Visible)
{
find = true;
}
}
if (!find)
{
currentSelect = SelectIndex;
while (currentSelect < m_runtimeMenuItems.Count)
{
if (m_runtimeMenuItems[currentSelect].Visible)
{
find = true;
break;
}
currentSelect++;
}
}
if (find)
SelectIndex = currentSelect;
}
else
{
var itemUIRect = selectItem.transform as RectTransform;
SelectBorder.Target = itemUIRect;
}
}
private bool checkDirty()
{
bool dirty = false;
foreach (var menuItem in m_runtimeMenuItems)
{
if (menuItem.gameObject.activeSelf != menuItem.Visible)
{
dirty = true;
menuItem.gameObject.SetActive(menuItem.Visible);
}
}
return dirty;
} }
private TweenerCore<Vector2, Vector2, VectorOptions> m_popTween; private void RebuildSelectIndex()
private TweenerCore<Vector2, Vector2, VectorOptions> m_hideTween; {
CommandListener.ScheduleType? m_lastCS; Canvas.ForceUpdateCanvases();
private Action m_onClose;
SelectIndex = Mathf.Clamp(SelectIndex, 0, m_runtimeMenuItems.Count - 1);
/// <summary> var selectItem = m_runtimeMenuItems[SelectIndex];
/// 当菜单弹出时,动态添加一个菜单选项
/// </summary> if (selectItem.Visible == false)
/// <param name="menu"></param> {
public void AddOptionMenuWhenPoping(InternalOptionMenu menu) bool find = false;
{ int currentSelect = SelectIndex;
if (!m_bPoped) return; while (currentSelect > 0)
{
CreateRuntimeMenuItem(menu); currentSelect--;
Canvas.ForceUpdateCanvases(); if (m_runtimeMenuItems[currentSelect].Visible)
{
OptionUI_MenuItem optionUI_MenuItem = m_runtimeMenuItems[m_selectIndex]; find = true;
SelectBorder.Target = null; }
SelectBorder.Target = optionUI_MenuItem.transform as RectTransform; }
} if (!find)
{
currentSelect = SelectIndex;
public void Pop<T>(List<T> menus, int defaultIndex = 0, Action onClose = null) where T : InternalOptionMenu while (currentSelect < m_runtimeMenuItems.Count)
{
if (m_runtimeMenuItems[currentSelect].Visible)
{
find = true;
break;
}
currentSelect++;
}
}
if (find)
SelectIndex = currentSelect;
}
else
{
var itemUIRect = selectItem.transform as RectTransform;
SelectBorder.Target = itemUIRect;
}
}
private bool checkDirty()
{
bool dirty = false;
foreach (var menuItem in m_runtimeMenuItems)
{
if (menuItem.gameObject.activeSelf != menuItem.Visible)
{
dirty = true;
menuItem.gameObject.SetActive(menuItem.Visible);
}
}
return dirty;
}
private TweenerCore<Vector2, Vector2, VectorOptions> m_popTween;
private TweenerCore<Vector2, Vector2, VectorOptions> m_hideTween;
CommandListener.ScheduleType? m_lastCS;
private Action m_onClose;
/// <summary>
/// 当菜单弹出时,动态添加一个菜单选项
/// </summary>
/// <param name="menu"></param>
public void AddOptionMenuWhenPoping(InternalOptionMenu menu)
{
if (!m_bPoped) return;
CreateRuntimeMenuItem(menu);
Canvas.ForceUpdateCanvases();
OptionUI_MenuItem optionUI_MenuItem = m_runtimeMenuItems[m_selectIndex];
SelectBorder.Target = null;
SelectBorder.Target = optionUI_MenuItem.transform as RectTransform;
}
public void Pop<T>(List<T> menus, int defaultIndex = 0, Action onClose = null) where T : InternalOptionMenu
{ {
if (m_hideTween != null) if (m_hideTween != null)
{ {
m_hideTween.Kill(true); m_hideTween.Kill(true);
} }
m_onClose = onClose;
ReleaseRuntimeMenus();
foreach (var menu in menus) CreateRuntimeMenuItem(menu);
CommandDispatcher.Instance.RegistController(this);
SelectBorder.gameObject.SetActiveEx(true);
Canvas.ForceUpdateCanvases();
m_selectIndex = defaultIndex;
OptionUI_MenuItem optionUI_MenuItem = m_runtimeMenuItems[defaultIndex];
optionUI_MenuItem.OnFocus();
var itemUIRect = optionUI_MenuItem.transform as RectTransform;
SelectBorder.Target = itemUIRect;
SelectBorder.RefreshPosition();
if (!m_bPoped)
{
m_bPoped = true;
Vector2 start = new Vector2(0, MenuRoot.anchoredPosition.y);
Vector2 end = new Vector2(-MenuRoot.rect.width, MenuRoot.anchoredPosition.y);
m_popTween = DOTween.To(
() => start,
(value) =>
{
var moveDelta = value - start;
start = value;
var topParent = FindTopOptionUI();
topParent.MenuRoot.anchoredPosition += moveDelta;
},
end,
0.3f
).SetEase(Ease.OutCubic);
m_popTween.onComplete = () => m_popTween = null;
m_lastCS = CommandDispatcher.Instance.Mode;
CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Normal;
}
}
OptionUI FindTopOptionUI()
{
if (m_parent == null) return this;
var topParent = m_parent; m_onClose = onClose;
while (topParent != null && topParent.m_parent != null) ReleaseRuntimeMenus();
foreach (var menu in menus) CreateRuntimeMenuItem(menu);
CommandDispatcher.Instance.RegistController(this);
SelectBorder.gameObject.SetActiveEx(true);
Canvas.ForceUpdateCanvases();
m_selectIndex = defaultIndex;
OptionUI_MenuItem optionUI_MenuItem = m_runtimeMenuItems[defaultIndex];
optionUI_MenuItem.OnFocus();
var itemUIRect = optionUI_MenuItem.transform as RectTransform;
SelectBorder.Target = itemUIRect;
SelectBorder.RefreshPosition();
if (!m_bPoped)
{ {
topParent = topParent.m_parent;
} m_bPoped = true;
Vector2 start = new Vector2(0, MenuRoot.anchoredPosition.y);
return topParent; Vector2 end = new Vector2(-MenuRoot.rect.width, MenuRoot.anchoredPosition.y);
} m_popTween = DOTween.To(
() => start,
static float GetTotalWidth(OptionUI root) (value) =>
{ {
float totalWidth = root.MenuRoot.rect.width; var moveDelta = value - start;
if (root.m_child != null) start = value;
{
totalWidth += GetTotalWidth(root.m_child); var topParent = m_parent;
} while (topParent != null && topParent.m_parent != null)
{
return totalWidth; topParent = topParent.m_parent;
} }
if (topParent != null)
{
topParent.MenuRoot.anchoredPosition += moveDelta;
}
else
{
MenuRoot.anchoredPosition += moveDelta;
}
},
end,
0.3f
).SetEase(Ease.OutCubic);
m_popTween.onComplete = () => m_popTween = null;
m_lastCS = CommandDispatcher.Instance.Mode;
CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Normal;
}
}
/// <summary> /// <summary>
/// 关闭这个侧边栏选项UI /// 关闭这个侧边栏选项UI
/// </summary> /// </summary>
public void Hide() public void Hide()
{ {
if (m_bPoped) if (m_bPoped)
{ {
if (m_child != null) if (m_child != null)
{ {
m_child.Hide(); m_child.Hide();
} }
Vector2 start = new Vector2(-MenuRoot.rect.width, MenuRoot.anchoredPosition.y); Vector2 start = new Vector2(-MenuRoot.rect.width, MenuRoot.anchoredPosition.y);
Vector2 end = new Vector2(0, MenuRoot.anchoredPosition.y); Vector2 end = new Vector2(0, MenuRoot.anchoredPosition.y);
SelectBorder.gameObject.SetActiveEx(false); SelectBorder.gameObject.SetActiveEx(false);
CommandDispatcher.Instance.UnRegistController(this); CommandDispatcher.Instance.UnRegistController(this);
Canvas.ForceUpdateCanvases(); Canvas.ForceUpdateCanvases();
if (m_popTween != null) if (m_popTween != null)
{ {
m_popTween.Kill(true); m_popTween.Kill(true);
} }
m_hideTween = DOTween.To( m_hideTween = DOTween.To(
() => start, () => start,
(value) => (value) =>
{ {
var moveDelta = value - start; var moveDelta = value - start;
start = value; start = value;
var topParent = m_parent; var topParent = m_parent;
while (topParent != null && topParent.m_parent != null) while (topParent != null && topParent.m_parent != null)
{ {
topParent = topParent.m_parent; topParent = topParent.m_parent;
} }
if (topParent != null) if (topParent != null)
{ {
topParent.MenuRoot.anchoredPosition += moveDelta; topParent.MenuRoot.anchoredPosition += moveDelta;
} }
else else
{ {
MenuRoot.anchoredPosition += moveDelta; MenuRoot.anchoredPosition += moveDelta;
} }
}, },
end, end,
0.3f 0.3f
).SetEase(Ease.OutCubic); ).SetEase(Ease.OutCubic);
m_hideTween.onComplete = () => m_hideTween.onComplete = () =>
{ {
ReleaseRuntimeMenus(); ReleaseRuntimeMenus();
m_runtimeMenuItems.Clear(); m_runtimeMenuItems.Clear();
m_hideTween = null; m_hideTween = null;
}; };
m_bPoped = false; m_bPoped = false;
CommandDispatcher.Instance.Mode = m_lastCS.Value; CommandDispatcher.Instance.Mode = m_lastCS.Value;
m_onClose?.Invoke(); m_onClose?.Invoke();
m_onClose = null; m_onClose = null;
} }
} }
private void CreateRuntimeMenuItem(InternalOptionMenu menuData) private void CreateRuntimeMenuItem(InternalOptionMenu menuData)
{ {
m_menuUI_templates.TryGetValue(menuData.MenuUITemplateType, out var template); m_menuUI_templates.TryGetValue(menuData.MenuUITemplateType, out var template);
if (template == null) if (template == null)
{ {
throw new NotImplementedException($"{menuData.GetType().Name}指定的MenuUI类型实例未在OptionUI中找到"); throw new NotImplementedException($"{menuData.GetType().Name}指定的MenuUI类型实例未在OptionUI中找到");
@ -338,158 +336,158 @@ namespace AxibugEmuOnline.Client
menuUI.gameObject.SetActive(true); menuUI.gameObject.SetActive(true);
menuUI.SetData(this, menuData); menuUI.SetData(this, menuData);
m_runtimeMenuItems.Add(menuUI); m_runtimeMenuItems.Add(menuUI);
} }
private void ReleaseRuntimeMenus() private void ReleaseRuntimeMenus()
{ {
foreach (var item in m_runtimeMenuItems) foreach (var item in m_runtimeMenuItems)
{ {
item.OnHide(); item.OnHide();
Destroy(item.gameObject); Destroy(item.gameObject);
} }
m_runtimeMenuItems.Clear(); m_runtimeMenuItems.Clear();
} }
protected override void OnCmdSelectItemDown() protected override void OnCmdSelectItemDown()
{ {
int old = SelectIndex; int old = SelectIndex;
SelectIndex++; SelectIndex++;
if (old != SelectIndex) if (old != SelectIndex)
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option); App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option);
} }
protected override void OnCmdSelectItemUp() protected override void OnCmdSelectItemUp()
{ {
int old = SelectIndex; int old = SelectIndex;
SelectIndex--; SelectIndex--;
if (old != SelectIndex) if (old != SelectIndex)
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option); App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option);
} }
protected override void OnCmdBack() protected override void OnCmdBack()
{ {
Hide(); Hide();
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cancel); App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cancel);
} }
protected override void OnCmdSelectItemLeft() protected override void OnCmdSelectItemLeft()
{ {
var executer = m_runtimeMenuItems[SelectIndex]; var executer = m_runtimeMenuItems[SelectIndex];
if (executer) if (executer)
{ {
executer.OnLeft(); executer.OnLeft();
} }
} }
protected override void OnCmdSelectItemRight() protected override void OnCmdSelectItemRight()
{ {
var executer = m_runtimeMenuItems[SelectIndex]; var executer = m_runtimeMenuItems[SelectIndex];
if (!executer.IsExpandMenu) if (!executer.IsExpandMenu)
{ {
executer.OnRight(); executer.OnRight();
return; return;
} }
OnCmdEnter(); OnCmdEnter();
} }
protected override bool OnCmdEnter() protected override bool OnCmdEnter()
{ {
var executer = m_runtimeMenuItems[SelectIndex]; var executer = m_runtimeMenuItems[SelectIndex];
bool cancelHide = false; bool cancelHide = false;
executer.OnExecute(this, ref cancelHide); executer.OnExecute(this, ref cancelHide);
if (!cancelHide) Hide(); if (!cancelHide) Hide();
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option); App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option);
return false; return false;
} }
/// <summary> /// <summary>
/// 展开下级菜单 /// 展开下级菜单
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="menus"></param> /// <param name="menus"></param>
/// <param name="defaultIndex"></param> /// <param name="defaultIndex"></param>
/// <param name="onClose"></param> /// <param name="onClose"></param>
public void ExpandSubMenu<T>(List<T> menus, int defaultIndex = 0, Action onClose = null) where T : InternalOptionMenu public void ExpandSubMenu<T>(List<T> menus, int defaultIndex = 0, Action onClose = null) where T : InternalOptionMenu
{ {
if (m_child == null) if (m_child == null)
{ {
var sourcePrefab = Resources.Load<GameObject>("UIPrefabs/OptionUI"); var sourcePrefab = Resources.Load<GameObject>("UIPrefabs/OptionUI");
m_child = Instantiate(sourcePrefab, transform).GetComponent<OptionUI>(); m_child = Instantiate(sourcePrefab, transform).GetComponent<OptionUI>();
m_child.name = $"{name}_Sub"; m_child.name = $"{name}_Sub";
m_child.m_parent = this; m_child.m_parent = this;
} }
Canvas.ForceUpdateCanvases(); Canvas.ForceUpdateCanvases();
m_child.Pop(menus, 0, onClose); m_child.Pop(menus, 0, onClose);
} }
public void RemoveItem(OptionUI_MenuItem ui) public void RemoveItem(OptionUI_MenuItem ui)
{ {
var index = m_runtimeMenuItems.IndexOf(ui); var index = m_runtimeMenuItems.IndexOf(ui);
if (index == -1) return; if (index == -1) return;
m_runtimeMenuItems.Remove(ui); m_runtimeMenuItems.Remove(ui);
ui.OnHide(); ui.OnHide();
Destroy(ui.gameObject); Destroy(ui.gameObject);
RebuildSelectIndex(); RebuildSelectIndex();
} }
}
/// <summary>
/// 带有执行行为的菜单
/// </summary>
public abstract class ExecuteMenu : InternalOptionMenu
{
public override Type MenuUITemplateType => typeof(OptionUI_ExecuteItem);
/// <summary> 设置这个值以控制菜单中显示"已应用"标记 </summary>
public virtual bool IsApplied { get; }
public abstract void OnExcute(OptionUI optionUI, ref bool cancelHide);
}
/// <summary>
/// 带有展开行为的可执行菜单
/// </summary>
public abstract class ExpandMenu : ExecuteMenu
{
protected ExpandMenu() : base() { }
public sealed override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{
cancelHide = true;
optionUI.ExpandSubMenu(GetOptionMenus());
}
protected abstract List<InternalOptionMenu> GetOptionMenus();
} }
/// <summary>
/// 带有值类型显示和编辑的菜单 /// <summary>
/// </summary> /// 带有执行行为的菜单
public abstract class ValueSetMenu : InternalOptionMenu /// </summary>
{ public abstract class ExecuteMenu : InternalOptionMenu
{
public override Type MenuUITemplateType => typeof(OptionUI_ExecuteItem);
/// <summary> 设置这个值以控制菜单中显示"已应用"标记 </summary>
public virtual bool IsApplied { get; }
public abstract void OnExcute(OptionUI optionUI, ref bool cancelHide);
}
/// <summary>
/// 带有展开行为的可执行菜单
/// </summary>
public abstract class ExpandMenu : ExecuteMenu
{
protected ExpandMenu() : base() { }
public sealed override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{
cancelHide = true;
optionUI.ExpandSubMenu(GetOptionMenus());
}
protected abstract List<InternalOptionMenu> GetOptionMenus();
}
/// <summary>
/// 带有值类型显示和编辑的菜单
/// </summary>
public abstract class ValueSetMenu : InternalOptionMenu
{
public override Type MenuUITemplateType => typeof(OptionUI_ValueEditItem); public override Type MenuUITemplateType => typeof(OptionUI_ValueEditItem);
protected ValueSetMenu() : base() { } protected ValueSetMenu() : base() { }
public abstract Type ValueType { get; } public abstract Type ValueType { get; }
public abstract object ValueRaw { get; } public abstract object ValueRaw { get; }
public abstract void OnValueChanged(object newValue); public abstract void OnValueChanged(object newValue);
public abstract object Min { get; } public abstract object Min { get; }
public abstract object Max { get; } public abstract object Max { get; }
} }
/// <summary> 不要直接继承这个类 </summary> /// <summary> 不要直接继承这个类 </summary>
public abstract class InternalOptionMenu public abstract class InternalOptionMenu
{ {
public abstract Type MenuUITemplateType { get; } public abstract Type MenuUITemplateType { get; }
public abstract string Name { get; } public abstract string Name { get; }
public virtual Sprite Icon { get; } public virtual Sprite Icon { get; }
public virtual bool Visible => true; public virtual bool Visible => true;
public virtual void OnFocus() { } public virtual void OnFocus() { }
public virtual void OnShow(OptionUI_MenuItem ui) { } public virtual void OnShow(OptionUI_MenuItem ui) { }
public virtual void OnHide() { } public virtual void OnHide() { }
} }
} }

View File

@ -1,28 +1,28 @@
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class OptionUI_ExecuteItem : OptionUI_MenuItem<ExecuteMenu> public class OptionUI_ExecuteItem : OptionUI_MenuItem<ExecuteMenu>
{ {
public GameObject ExpandFlag; public GameObject ExpandFlag;
public GameObject ApplyFlag; public GameObject ApplyFlag;
protected override void OnSetData(InternalOptionMenu menuData) protected override void OnSetData(InternalOptionMenu menuData)
{ {
base.OnSetData(menuData); base.OnSetData(menuData);
ExpandFlag.SetActiveEx(IsExpandMenu); ExpandFlag.SetActiveEx(IsExpandMenu);
ApplyFlag.SetActiveEx(IsApplied); ApplyFlag.SetActiveEx(IsApplied);
} }
public override void OnExecute(OptionUI optionUI, ref bool cancelHide) public override void OnExecute(OptionUI optionUI, ref bool cancelHide)
{ {
MenuData.OnExcute(optionUI, ref cancelHide); MenuData.OnExcute(optionUI, ref cancelHide);
} }
protected override void Update() protected override void Update()
{ {
ApplyFlag.SetActiveEx(IsApplied); ApplyFlag.SetActiveEx(IsApplied);
} }
} }
} }

View File

@ -1,13 +1,13 @@
using AxibugEmuOnline.Client.Tools; using AxibugEmuOnline.Client.Tools;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using static AxibugEmuOnline.Client.InGameUI_SaveStateMenu; using static AxibugEmuOnline.Client.InGameUI_SaveStateMenu;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class OptionUI_SavSlotItem : OptionUI_MenuItem<SaveSlotMenu> public class OptionUI_SavSlotItem : OptionUI_MenuItem<SaveSlotMenu>
{ {
public RawImage UI_ScreenShot; public RawImage UI_ScreenShot;
public Image UI_Empty; public Image UI_Empty;
@ -113,5 +113,5 @@ namespace AxibugEmuOnline.Client
{ {
MenuData.OnExcute(optionUI, ref cancelHide); MenuData.OnExcute(optionUI, ref cancelHide);
} }
} }
} }

View File

@ -1,84 +1,84 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class OptionUI_ValueEditItem : OptionUI_MenuItem<ValueSetMenu> public class OptionUI_ValueEditItem : OptionUI_MenuItem<ValueSetMenu>
{ {
[SerializeField] [SerializeField]
OptionUI_ValueEditItem_FloatEdit com_floatEdit; OptionUI_ValueEditItem_FloatEdit com_floatEdit;
[SerializeField] [SerializeField]
OptionUI_ValueEditItem_IntEdit com_intEdit; OptionUI_ValueEditItem_IntEdit com_intEdit;
[SerializeField] [SerializeField]
OptionUI_ValueEditItem_BoolEdit com_boolEdit; OptionUI_ValueEditItem_BoolEdit com_boolEdit;
[SerializeField] [SerializeField]
OptionUI_ValueEditItem_EnumEdit com_enumEdit; OptionUI_ValueEditItem_EnumEdit com_enumEdit;
IValueEditControl m_currentCom; IValueEditControl m_currentCom;
protected override void OnSetData(InternalOptionMenu menuData) protected override void OnSetData(InternalOptionMenu menuData)
{ {
com_floatEdit.gameObject.SetActive(false); com_floatEdit.gameObject.SetActive(false);
com_intEdit.gameObject.SetActive(false); com_intEdit.gameObject.SetActive(false);
com_boolEdit.gameObject.SetActive(false); com_boolEdit.gameObject.SetActive(false);
com_enumEdit.gameObject.SetActive(false); com_enumEdit.gameObject.SetActive(false);
if (menuData is ValueSetMenu) if (menuData is ValueSetMenu)
{ {
var valueMenu = (ValueSetMenu)menuData; var valueMenu = (ValueSetMenu)menuData;
if (valueMenu.ValueType == typeof(float)) if (valueMenu.ValueType == typeof(float))
{ {
m_currentCom = com_floatEdit; m_currentCom = com_floatEdit;
} }
else if (valueMenu.ValueType == typeof(int)) else if (valueMenu.ValueType == typeof(int))
{ {
m_currentCom = com_intEdit; m_currentCom = com_intEdit;
} }
else if (valueMenu.ValueType == typeof(bool)) else if (valueMenu.ValueType == typeof(bool))
{ {
m_currentCom = com_boolEdit; m_currentCom = com_boolEdit;
} }
else if (valueMenu.ValueType.IsEnum) else if (valueMenu.ValueType.IsEnum)
{ {
m_currentCom = com_enumEdit; m_currentCom = com_enumEdit;
} }
else else
{ {
App.log.Error($"尚未支持的数据类型:{valueMenu.ValueType}"); App.log.Error($"尚未支持的数据类型:{valueMenu.ValueType}");
return; return;
} }
m_currentCom.gameObject.SetActiveEx(true); m_currentCom.gameObject.SetActiveEx(true);
m_currentCom.SetData(valueMenu); m_currentCom.SetData(valueMenu);
} }
base.OnSetData(menuData); base.OnSetData(menuData);
} }
public override void OnExecute(OptionUI optionUI, ref bool cancelHide) public override void OnExecute(OptionUI optionUI, ref bool cancelHide)
{ {
cancelHide = true; cancelHide = true;
m_currentCom?.OnExecute(); m_currentCom?.OnExecute();
} }
public override void OnLeft() public override void OnLeft()
{ {
m_currentCom?.OnLeft(); m_currentCom?.OnLeft();
} }
public override void OnRight() public override void OnRight()
{ {
m_currentCom?.OnRight(); m_currentCom?.OnRight();
} }
} }
public interface IValueEditControl public interface IValueEditControl
{ {
void SetData(ValueSetMenu valueMenu); void SetData(ValueSetMenu valueMenu);
GameObject gameObject { get; } GameObject gameObject { get; }
void OnLeft(); void OnLeft();
void OnRight(); void OnRight();
void OnExecute(); void OnExecute();
} }
} }

View File

@ -1,37 +1,37 @@
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class OptionUI_ValueEditItem_BoolEdit : MonoBehaviour, IValueEditControl public class OptionUI_ValueEditItem_BoolEdit : MonoBehaviour, IValueEditControl
{ {
[SerializeField] [SerializeField]
Text txt_value; Text txt_value;
private ValueSetMenu m_valueMenu; private ValueSetMenu m_valueMenu;
public void SetData(ValueSetMenu valueMenu) public void SetData(ValueSetMenu valueMenu)
{ {
m_valueMenu = valueMenu; m_valueMenu = valueMenu;
txt_value.text = valueMenu.ValueRaw.ToString(); txt_value.text = valueMenu.ValueRaw.ToString();
} }
public void OnLeft() public void OnLeft()
{ {
OnExecute(); OnExecute();
} }
public void OnRight() public void OnRight()
{ {
OnExecute(); OnExecute();
} }
public void OnExecute() public void OnExecute()
{ {
var value = (bool)m_valueMenu.ValueRaw; var value = (bool)m_valueMenu.ValueRaw;
value = !value; value = !value;
txt_value.text = value.ToString(); txt_value.text = value.ToString();
m_valueMenu.OnValueChanged(value); m_valueMenu.OnValueChanged(value);
} }
} }
} }

View File

@ -1,15 +1,15 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.Manager; using AxibugEmuOnline.Client.Manager;
using AxibugEmuOnline.Client.UI; using AxibugEmuOnline.Client.UI;
using AxibugProtobuf; using AxibugProtobuf;
using Coffee.UIExtensions; using Coffee.UIExtensions;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using Debug = System.Diagnostics.Debug; using Debug = System.Diagnostics.Debug;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class RoomItem : MenuItem, IVirtualItem public class RoomItem : MenuItem, IVirtualItem
{ {
@ -17,7 +17,7 @@ namespace AxibugEmuOnline.Client
[SerializeField] Slider m_downloadProgress; [SerializeField] Slider m_downloadProgress;
[SerializeField] GameObject m_downloadingFlag; [SerializeField] GameObject m_downloadingFlag;
[SerializeField] GameObject m_romReadyFlag; [SerializeField] GameObject m_romReadyFlag;
[SerializeField] [SerializeField]
UIShiny DownloadComplete; UIShiny DownloadComplete;
private RomFile m_romFile; private RomFile m_romFile;
@ -172,5 +172,5 @@ namespace AxibugEmuOnline.Client
{ {
Reset(); Reset();
} }
} }
} }

View File

@ -1,235 +1,235 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.UI; using AxibugEmuOnline.Client.UI;
using DG.Tweening; using DG.Tweening;
using DG.Tweening.Core; using DG.Tweening.Core;
using DG.Tweening.Plugins.Options; using DG.Tweening.Plugins.Options;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class SubMenuItemGroup : MenuItemController<MenuData> public class SubMenuItemGroup : MenuItemController<MenuData>
{ {
[SerializeField] [SerializeField]
MenuItem SubMenuItemTemplate; MenuItem SubMenuItemTemplate;
[SerializeField] [SerializeField]
CanvasGroup alphaGroup; CanvasGroup alphaGroup;
private TweenerCore<float, float, FloatOptions> selectTween; private TweenerCore<float, float, FloatOptions> selectTween;
private bool m_selected; private bool m_selected;
private TweenerCore<int, int, NoOptions> rollTween; private TweenerCore<int, int, NoOptions> rollTween;
protected override void Awake() protected override void Awake()
{
m_selected = false;
if (alphaGroup != null) alphaGroup.alpha = 0;
base.Awake();
}
public override void Init(List<MenuData> menuDataList)
{
#if UNITY_EDITOR
while (transform.childCount > 0)
{
DestroyImmediate(transform.GetChild(0).gameObject);
}
#else
for (int i = 0; i < transform.childCount; i++)
{
Destroy(transform.GetChild(i).gameObject);
}
#endif
m_runtimeMenuUI.Clear();
foreach (MenuData menuData in menuDataList)
{
var template = menuData.OverrideTemplate != null ? menuData.OverrideTemplate : SubMenuItemTemplate;
var item = Clone(template, transform);
item.SetData(menuData);
m_runtimeMenuUI.Add(item);
}
calcItemPosition();
for (var i = 0; i < m_runtimeMenuUI.Count; i++)
{
var item = m_runtimeMenuUI[i];
var needPos = m_itemUIPosition[i];
item.Rect.anchoredPosition = needPos;
}
}
protected override bool OnCmdEnter()
{
base.OnCmdEnter();
LaunchUI.Instance.ToDetailMenuLayout();
var item = GetItemUIByIndex(SelectIndex);
item.SetSelectState(false);
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option);
return true;
}
protected override void OnCmdBack()
{ {
if (m_enteredItem != null) m_selected = false;
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cancel); if (alphaGroup != null) alphaGroup.alpha = 0;
base.OnCmdBack(); base.Awake();
}
LaunchUI.Instance.ToMainMenuLayout();
var item = GetItemUIByIndex(SelectIndex); public override void Init(List<MenuData> menuDataList)
{
#if UNITY_EDITOR
while (transform.childCount > 0)
{
DestroyImmediate(transform.GetChild(0).gameObject);
}
#else
for (int i = 0; i < transform.childCount; i++)
{
Destroy(transform.GetChild(i).gameObject);
}
#endif
m_runtimeMenuUI.Clear();
foreach (MenuData menuData in menuDataList)
{
var template = menuData.OverrideTemplate != null ? menuData.OverrideTemplate : SubMenuItemTemplate;
var item = Clone(template, transform);
item.SetData(menuData);
m_runtimeMenuUI.Add(item);
}
calcItemPosition();
for (var i = 0; i < m_runtimeMenuUI.Count; i++)
{
var item = m_runtimeMenuUI[i];
var needPos = m_itemUIPosition[i];
item.Rect.anchoredPosition = needPos;
}
}
protected override bool OnCmdEnter()
{
base.OnCmdEnter();
LaunchUI.Instance.ToDetailMenuLayout();
var item = GetItemUIByIndex(SelectIndex);
item.SetSelectState(false);
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option);
return true;
}
protected override void OnCmdBack()
{
if (m_enteredItem != null)
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cancel);
base.OnCmdBack();
LaunchUI.Instance.ToMainMenuLayout();
var item = GetItemUIByIndex(SelectIndex);
item.SetSelectState(true); item.SetSelectState(true);
} }
protected override void OnCmdSelectItemUp() protected override void OnCmdSelectItemUp()
{ {
if (m_enteredItem == null) if (m_enteredItem == null)
{ {
int old = SelectIndex; int old = SelectIndex;
SelectIndex--; SelectIndex--;
if (old != SelectIndex) if (old != SelectIndex)
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cursor); App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cursor);
} }
} }
protected override void OnCmdSelectItemDown() protected override void OnCmdSelectItemDown()
{ {
if (m_enteredItem == null) if (m_enteredItem == null)
{ {
int old = SelectIndex; int old = SelectIndex;
SelectIndex++; SelectIndex++;
if (old != SelectIndex) if (old != SelectIndex)
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cursor); App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cursor);
} }
} }
public virtual void SetSelect(bool select) public virtual void SetSelect(bool select)
{ {
if (m_selected == select) return; if (m_selected == select) return;
m_selected = select; m_selected = select;
if (selectTween != null) if (selectTween != null)
{ {
selectTween.Kill(); selectTween.Kill();
selectTween = null; selectTween = null;
} }
if (select) if (select)
{ {
selectTween = DOTween.To(() => alphaGroup.alpha, (x) => alphaGroup.alpha = x, 1, 10).SetSpeedBased(); selectTween = DOTween.To(() => alphaGroup.alpha, (x) => alphaGroup.alpha = x, 1, 10).SetSpeedBased();
} }
else else
{ {
selectTween = DOTween.To(() => alphaGroup.alpha, (x) => alphaGroup.alpha = x, 0, 10).SetSpeedBased(); selectTween = DOTween.To(() => alphaGroup.alpha, (x) => alphaGroup.alpha = x, 0, 10).SetSpeedBased();
} }
ListenControlAction = m_selected; ListenControlAction = m_selected;
} }
protected override void OnCmdSelectItemLeft() protected override void OnCmdSelectItemLeft()
{ {
if(m_enteredItem != null) if(m_enteredItem != null)
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cancel); App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Cancel);
else else
App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option); App.audioMgr.PlaySFX(AudioMgr.E_SFXTYPE.Option);
base.OnCmdSelectItemLeft(); base.OnCmdSelectItemLeft();
OnCmdBack(); OnCmdBack();
} }
protected override void OnSelectMenuChanged() protected override void OnSelectMenuChanged()
{
if (rollTween != null) { rollTween.Kill(); rollTween = null; }
float duration = 0.5f;
calcItemPosition();
for (var i = 0; i < m_runtimeMenuUI.Count; i++)
{
var item = m_runtimeMenuUI[i];
bool isSelectItem = i == SelectIndex;
item.SetSelectState(isSelectItem);
}
rollTween = DOTween.To(() => 1, (x) => { }, 1, duration).OnUpdate(() =>
{
var tweenProgress = rollTween.position / rollTween.Duration();
for (var i = 0; i < m_runtimeMenuUI.Count; i++)
{
var item = m_runtimeMenuUI[i];
var needPos = m_itemUIPosition[i];
item.Rect.anchoredPosition = Vector2.Lerp(item.Rect.anchoredPosition, needPos, tweenProgress);
}
}).OnComplete(() =>
{
for (var i = 0; i < m_runtimeMenuUI.Count; i++)
{
var item = m_runtimeMenuUI[i];
var needPos = m_itemUIPosition[i];
item.Rect.anchoredPosition = needPos;
}
});
}
[SerializeField]
Vector2 m_selectItemPosition = new Vector2(50, -51);
[SerializeField]
float step = 50f;
[SerializeField]
float splitStep = 200f;
List<Vector2> m_itemUIPosition = new List<Vector2>();
private void calcItemPosition()
{
m_itemUIPosition.Clear();
for (int i = 0; i < m_runtimeMenuUI.Count; i++)
{
var gap = SelectIndex - i;
var start = m_selectItemPosition;
start.y += step * gap;
if (i < SelectIndex) start.y += splitStep;
m_itemUIPosition.Add(start);
}
}
private MenuItem Clone(MenuItem template, Transform parent)
{ {
#if UNITY_EDITOR if (rollTween != null) { rollTween.Kill(); rollTween = null; }
float duration = 0.5f;
calcItemPosition();
for (var i = 0; i < m_runtimeMenuUI.Count; i++)
{
var item = m_runtimeMenuUI[i];
bool isSelectItem = i == SelectIndex;
item.SetSelectState(isSelectItem);
}
rollTween = DOTween.To(() => 1, (x) => { }, 1, duration).OnUpdate(() =>
{
var tweenProgress = rollTween.position / rollTween.Duration();
for (var i = 0; i < m_runtimeMenuUI.Count; i++)
{
var item = m_runtimeMenuUI[i];
var needPos = m_itemUIPosition[i];
item.Rect.anchoredPosition = Vector2.Lerp(item.Rect.anchoredPosition, needPos, tweenProgress);
}
}).OnComplete(() =>
{
for (var i = 0; i < m_runtimeMenuUI.Count; i++)
{
var item = m_runtimeMenuUI[i];
var needPos = m_itemUIPosition[i];
item.Rect.anchoredPosition = needPos;
}
});
}
[SerializeField]
Vector2 m_selectItemPosition = new Vector2(50, -51);
[SerializeField]
float step = 50f;
[SerializeField]
float splitStep = 200f;
List<Vector2> m_itemUIPosition = new List<Vector2>();
private void calcItemPosition()
{
m_itemUIPosition.Clear();
for (int i = 0; i < m_runtimeMenuUI.Count; i++)
{
var gap = SelectIndex - i;
var start = m_selectItemPosition;
start.y += step * gap;
if (i < SelectIndex) start.y += splitStep;
m_itemUIPosition.Add(start);
}
}
private MenuItem Clone(MenuItem template, Transform parent)
{
#if UNITY_EDITOR
//========================套娃宏======================== //========================套娃宏========================
#if UNITY_2019_1_OR_NEWER //新版Unity因UNITY2018.2用不了这玩意儿,编辑器也罢 #if UNITY_2019_1_OR_NEWER //新版Unity因UNITY2018.2用不了这玩意儿,编辑器也罢
if (Application.isPlaying) if (Application.isPlaying)
{ {
var item = GameObject.Instantiate(template.gameObject, parent).GetComponent<MenuItem>(); var item = GameObject.Instantiate(template.gameObject, parent).GetComponent<MenuItem>();
item.transform.localPosition = Vector3.zero; item.transform.localPosition = Vector3.zero;
return item; return item;
}
else
{
var clone = UnityEditor.PrefabUtility.InstantiatePrefab(template.gameObject, parent) as GameObject;
clone.transform.localPosition = Vector3.zero;
return clone.GetComponent<MenuItem>();
} }
#else else
var item = GameObject.Instantiate(template.gameObject, parent).GetComponent<MenuItem>(); {
item.transform.localPosition = Vector3.zero; var clone = UnityEditor.PrefabUtility.InstantiatePrefab(template.gameObject, parent) as GameObject;
return item; clone.transform.localPosition = Vector3.zero;
#endif return clone.GetComponent<MenuItem>();
}
#else
var item = GameObject.Instantiate(template.gameObject, parent).GetComponent<MenuItem>();
item.transform.localPosition = Vector3.zero;
return item;
#endif
//========================套娃宏 End======================== //========================套娃宏 End========================
#else #else
return GameObject.Instantiate(SubMenuItemTemplate.gameObject, parent).GetComponent<MenuItem>(); return GameObject.Instantiate(SubMenuItemTemplate.gameObject, parent).GetComponent<MenuItem>();
#endif #endif
} }
} }
} }

View File

@ -1,94 +1,94 @@
using DG.Tweening; using DG.Tweening;
using DG.Tweening.Core; using DG.Tweening.Core;
using DG.Tweening.Plugins.Options; using DG.Tweening.Plugins.Options;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
/// <summary> /// <summary>
/// 用于指定一对CanvasGroup,做透明度切换 /// 用于指定一对CanvasGroup,做透明度切换
/// </summary> /// </summary>
public class AlphaWraper public class AlphaWraper
{ {
private bool m_on; private bool m_on;
private CanvasGroup m_offUI; private CanvasGroup m_offUI;
private CanvasGroup m_onUI; private CanvasGroup m_onUI;
private TweenerCore<float, float, FloatOptions> m_onTween; private TweenerCore<float, float, FloatOptions> m_onTween;
private TweenerCore<float, float, FloatOptions> m_offTween; private TweenerCore<float, float, FloatOptions> m_offTween;
public bool On public bool On
{ {
get => m_on; get => m_on;
set set
{ {
if (m_on == value) return; if (m_on == value) return;
m_on = value; m_on = value;
if (m_onTween != null) if (m_onTween != null)
{ {
m_onTween.Kill(); m_onTween.Kill();
m_onTween = null; m_onTween = null;
} }
if (m_offTween != null) if (m_offTween != null)
{ {
m_offTween.Kill(); m_offTween.Kill();
m_offTween = null; m_offTween = null;
} }
m_onUI.gameObject.SetActiveEx(true); m_onUI.gameObject.SetActiveEx(true);
m_offUI.gameObject.SetActiveEx(true); m_offUI.gameObject.SetActiveEx(true);
if (On) if (On)
{ {
float progress = 0f; float progress = 0f;
m_onTween = DOTween.To(() => progress, (x) => m_onTween = DOTween.To(() => progress, (x) =>
{ {
progress = x; progress = x;
m_onUI.alpha = progress; m_onUI.alpha = progress;
m_offUI.alpha = 1 - progress; m_offUI.alpha = 1 - progress;
}, 1f, 0.3f); }, 1f, 0.3f);
m_onTween.onComplete = () => m_onTween.onComplete = () =>
{ {
m_offUI.gameObject.SetActiveEx(false); m_offUI.gameObject.SetActiveEx(false);
}; };
} }
else else
{ {
float progress = 0f; float progress = 0f;
m_offTween = DOTween.To(() => progress, (x) => m_offTween = DOTween.To(() => progress, (x) =>
{ {
progress = x; progress = x;
m_onUI.alpha = 1 - progress; m_onUI.alpha = 1 - progress;
m_offUI.alpha = progress; m_offUI.alpha = progress;
}, 1f, 0.3f); }, 1f, 0.3f);
m_offTween.onComplete = () => m_offTween.onComplete = () =>
{ {
m_onUI.gameObject.SetActiveEx(false); m_onUI.gameObject.SetActiveEx(false);
}; };
} }
} }
} }
public AlphaWraper(CanvasGroup offUI, CanvasGroup onUI, bool defaultOn) public AlphaWraper(CanvasGroup offUI, CanvasGroup onUI, bool defaultOn)
{ {
m_offUI = offUI; m_offUI = offUI;
m_onUI = onUI; m_onUI = onUI;
m_on = defaultOn; m_on = defaultOn;
if (On) if (On)
{ {
onUI.alpha = 1; onUI.alpha = 1;
onUI.gameObject.SetActiveEx(true); onUI.gameObject.SetActiveEx(true);
offUI.alpha = 0; offUI.alpha = 0;
offUI.gameObject.SetActiveEx(false); offUI.gameObject.SetActiveEx(false);
} }
else else
{ {
onUI.alpha = 0; onUI.alpha = 0;
onUI.gameObject.SetActiveEx(false); onUI.gameObject.SetActiveEx(false);
offUI.alpha = 1; offUI.alpha = 1;
offUI.gameObject.SetActiveEx(true); offUI.gameObject.SetActiveEx(true);
} }
} }
} }
} }

View File

@ -1,19 +1,19 @@
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
/// <summary> /// <summary>
/// 自动根据canvasgroup的alpha控制blocksRaycasts的开启状态 /// 自动根据canvasgroup的alpha控制blocksRaycasts的开启状态
/// </summary> /// </summary>
[RequireComponent(typeof(CanvasGroup))] [RequireComponent(typeof(CanvasGroup))]
public class AutoRaycastCanvasGroup : MonoBehaviour public class AutoRaycastCanvasGroup : MonoBehaviour
{ {
private CanvasGroup canvasGroup; private CanvasGroup canvasGroup;
private void Update() private void Update()
{ {
if (canvasGroup == null) canvasGroup = gameObject.GetComponent<CanvasGroup>(); if (canvasGroup == null) canvasGroup = gameObject.GetComponent<CanvasGroup>();
canvasGroup.blocksRaycasts = canvasGroup.alpha == 0 ? false : true; canvasGroup.blocksRaycasts = canvasGroup.alpha == 0 ? false : true;
} }
} }
} }

View File

@ -1,62 +1,62 @@
using System; using System;
namespace AxibugEmuOnline.Client.UI namespace AxibugEmuOnline.Client.UI
{ {
/// <summary> /// <summary>
/// 用于周期性触发回调的工具,带有触发周期和延迟触发的参数可调 /// 用于周期性触发回调的工具,带有触发周期和延迟触发的参数可调
/// </summary> /// </summary>
public class PulseInvoker public class PulseInvoker
{ {
private Action _action; private Action _action;
private float _interval; private float _interval;
private float _delay; private float _delay;
private float _elapsedTime; private float _elapsedTime;
private bool _isActive; private bool _isActive;
private bool _isDelayed; private bool _isDelayed;
public PulseInvoker(Action action, float delay, float interval) public PulseInvoker(Action action, float delay, float interval)
{ {
_action = action; _action = action;
_delay = delay; _delay = delay;
_interval = interval; _interval = interval;
} }
public void SetActive() public void SetActive()
{ {
_elapsedTime = 0f; _elapsedTime = 0f;
_isActive = true; _isActive = true;
_isDelayed = true; _isDelayed = true;
} }
public void DisActive() public void DisActive()
{ {
_isActive = false; _isActive = false;
} }
public void Update(float deltaTime) public void Update(float deltaTime)
{ {
if (!_isActive) return; if (!_isActive) return;
_elapsedTime += deltaTime; _elapsedTime += deltaTime;
if (_isDelayed) if (_isDelayed)
{ {
if (_elapsedTime >= _delay) if (_elapsedTime >= _delay)
{ {
_elapsedTime -= _delay; _elapsedTime -= _delay;
_isDelayed = false; _isDelayed = false;
_action?.Invoke(); _action?.Invoke();
} }
} }
else else
{ {
if (_elapsedTime >= _interval) if (_elapsedTime >= _interval)
{ {
_elapsedTime -= _interval; _elapsedTime -= _interval;
_action?.Invoke(); _action?.Invoke();
} }
} }
} }
} }
} }

View File

@ -21,6 +21,8 @@ namespace AxibugEmuOnline.Client
get => m_target; get => m_target;
set set
{ {
if (m_target == value) return;
m_target = value; m_target = value;
if (m_target == null) if (m_target == null)
{ {

View File

@ -1,38 +1,38 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public static class UITool public static class UITool
{ {
private static Dictionary<Graphic, Material> _caches = new Dictionary<Graphic, Material>(); private static Dictionary<Graphic, Material> _caches = new Dictionary<Graphic, Material>();
public static Material GetMaterial(this Graphic graphic) public static Material GetMaterial(this Graphic graphic)
{ {
Material material; Material material;
if (_caches.TryGetValue(graphic, out material)) if (_caches.TryGetValue(graphic, out material))
{ {
return material; return material;
} }
else else
{ {
var cloneMat = Material.Instantiate(graphic.material); var cloneMat = Material.Instantiate(graphic.material);
_caches[graphic] = cloneMat; _caches[graphic] = cloneMat;
graphic.material = cloneMat; graphic.material = cloneMat;
return cloneMat; return cloneMat;
} }
} }
public static void SetMaterial(this Graphic graphic, Material material) public static void SetMaterial(this Graphic graphic, Material material)
{ {
graphic.material = material; graphic.material = material;
_caches.Remove(graphic); _caches.Remove(graphic);
} }
public static void SetAlpha(this Graphic graphic, float alpha) public static void SetAlpha(this Graphic graphic, float alpha)
{ {
var temp = graphic.color; var temp = graphic.color;
temp.a = alpha; temp.a = alpha;
graphic.color = temp; graphic.color = temp;
} }
} }
} }

View File

@ -1,102 +1,102 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.UI; using AxibugEmuOnline.Client.UI;
using DG.Tweening; using DG.Tweening;
using DG.Tweening.Core; using DG.Tweening.Core;
using DG.Tweening.Plugins.Options; using DG.Tweening.Plugins.Options;
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public abstract class VirtualSubMenuItem : MenuItem public abstract class VirtualSubMenuItem : MenuItem
{ {
[SerializeField] [SerializeField]
protected CanvasGroup RomGroupRoot; protected CanvasGroup RomGroupRoot;
private TweenerCore<float, float, FloatOptions> m_showTween; private TweenerCore<float, float, FloatOptions> m_showTween;
protected override void Awake() protected override void Awake()
{ {
base.Awake(); base.Awake();
RomGroupRoot.gameObject.SetActive(false); RomGroupRoot.gameObject.SetActive(false);
RomGroupRoot.alpha = 0; RomGroupRoot.alpha = 0;
} }
public override void SetSelectState(bool selected) public override void SetSelectState(bool selected)
{ {
if (m_select == selected) return; if (m_select == selected) return;
m_select = selected; m_select = selected;
if (ShadowIcon != null) ShadowIcon.gameObject.SetActiveEx(selected); if (ShadowIcon != null) ShadowIcon.gameObject.SetActiveEx(selected);
if (progressTween != null) { progressTween.Kill(); progressTween = null; } if (progressTween != null) { progressTween.Kill(); progressTween = null; }
progressTween = DOTween.To(() => m_progress, (x) => m_progress = x, m_select ? 1 : 0, 5) progressTween = DOTween.To(() => m_progress, (x) => m_progress = x, m_select ? 1 : 0, 5)
.SetSpeedBased().OnUpdate(() => .SetSpeedBased().OnUpdate(() =>
{ {
if (InfoNode != null) InfoNode.alpha = m_progress; if (InfoNode != null) InfoNode.alpha = m_progress;
Root.localScale = Vector3.one * Mathf.Lerp(UnSelectScale, SelectScale, m_progress); Root.localScale = Vector3.one * Mathf.Lerp(UnSelectScale, SelectScale, m_progress);
}); });
} }
public override bool OnEnterItem() public override bool OnEnterItem()
{ {
RomGroupRoot.gameObject.SetActive(true); RomGroupRoot.gameObject.SetActive(true);
RomGroupRoot.alpha = 0; RomGroupRoot.alpha = 0;
if (m_showTween != null) if (m_showTween != null)
{ {
m_showTween.Kill(); m_showTween.Kill();
m_showTween = null; m_showTween = null;
} }
m_showTween = DOTween.To(() => RomGroupRoot.alpha, (x) => RomGroupRoot.alpha = x, 1, 0.2f); m_showTween = DOTween.To(() => RomGroupRoot.alpha, (x) => RomGroupRoot.alpha = x, 1, 0.2f);
var thirdMenuGroup = SubMenuItemGroup as ThirdMenuRoot; var thirdMenuGroup = SubMenuItemGroup as ThirdMenuRoot;
thirdMenuGroup.itemGroup.Clear(); thirdMenuGroup.itemGroup.Clear();
RefreshUI(); RefreshUI();
if (SubMenuItemGroup != null) SubMenuItemGroup.SetSelect(true); if (SubMenuItemGroup != null) SubMenuItemGroup.SetSelect(true);
return true; return true;
} }
public delegate void VirtualListDataHandle(IEnumerable data, int initialIndex); public delegate void VirtualListDataHandle(IEnumerable data, int initialIndex);
protected void RefreshUI() protected void RefreshUI()
{ {
GetVirtualListDatas((datas, initialIndex) => GetVirtualListDatas((datas, initialIndex) =>
{ {
var thirdMenuGroup = SubMenuItemGroup as ThirdMenuRoot; var thirdMenuGroup = SubMenuItemGroup as ThirdMenuRoot;
thirdMenuGroup.itemGroup.UpdateDependencyProperty(thirdMenuGroup); thirdMenuGroup.itemGroup.UpdateDependencyProperty(thirdMenuGroup);
thirdMenuGroup.itemGroup.SetData(datas); thirdMenuGroup.itemGroup.SetData(datas);
thirdMenuGroup.itemGroup.UpdateProxyVisualState(); thirdMenuGroup.itemGroup.UpdateProxyVisualState();
thirdMenuGroup.ResetToIndex(initialIndex); thirdMenuGroup.ResetToIndex(initialIndex);
}); });
} }
protected abstract void GetVirtualListDatas(VirtualListDataHandle callback); protected abstract void GetVirtualListDatas(VirtualListDataHandle callback);
public override bool OnExitItem() public override bool OnExitItem()
{ {
if (m_showTween != null) if (m_showTween != null)
{ {
m_showTween.Kill(); m_showTween.Kill();
m_showTween = null; m_showTween = null;
} }
m_showTween = DOTween.To(() => RomGroupRoot.alpha, (x) => RomGroupRoot.alpha = x, 0, 0.2f) m_showTween = DOTween.To(() => RomGroupRoot.alpha, (x) => RomGroupRoot.alpha = x, 0, 0.2f)
.OnComplete(() => .OnComplete(() =>
{ {
RomGroupRoot.gameObject.SetActive(false); RomGroupRoot.gameObject.SetActive(false);
}); });
if (SubMenuItemGroup != null) SubMenuItemGroup.SetSelect(false); if (SubMenuItemGroup != null) SubMenuItemGroup.SetSelect(false);
return true; return true;
} }
} }
} }

View File

@ -1,137 +1,137 @@
using AxibugEmuOnline.Client; using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using System; using System;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
public class XMBInfoBar : MonoBehaviour public class XMBInfoBar : MonoBehaviour
{ {
public Text txtDateTime; public Text txtDateTime;
public Image imgPowerRoot; public Image imgPowerRoot;
public Image imgPower1; public Image imgPower1;
public Image imgPower2; public Image imgPower2;
public Image imgPower3; public Image imgPower3;
public Text DelayValue; public Text DelayValue;
public Text OnlinePlayerCount; public Text OnlinePlayerCount;
public Text FPS; public Text FPS;
public GameObject ControlSlotInfoNode; public GameObject ControlSlotInfoNode;
void OnEnable() void OnEnable()
{ {
TickLoop.LoopAction_1s += RefreshAll; TickLoop.LoopAction_1s += RefreshAll;
RefreshAll(); RefreshAll();
} }
private void Update() private void Update()
{ {
ControlSlotInfoNode.SetActiveEx(App.emu.Core != null); ControlSlotInfoNode.SetActiveEx(App.emu.Core != null);
}
void OnDisable()
{
TickLoop.LoopAction_1s -= RefreshAll;
}
void RefreshAll()
{
RefreshTime();
RefreshPower();
RefreshDelay();
RefreshFps();
} }
/// <summary> void OnDisable()
/// (uint lastFrame, float lastTime) {
/// </summary> TickLoop.LoopAction_1s -= RefreshAll;
ValueTuple<uint, float> m_lastFrameInfo; }
private void RefreshFps()
{ void RefreshAll()
if (App.emu.Core == null) {
FPS.gameObject.SetActiveEx(false); RefreshTime();
else RefreshPower();
{ RefreshDelay();
RefreshFps();
}
/// <summary>
/// (uint lastFrame, float lastTime)
/// </summary>
ValueTuple<uint, float> m_lastFrameInfo;
private void RefreshFps()
{
if (App.emu.Core == null)
FPS.gameObject.SetActiveEx(false);
else
{
FPS.gameObject.SetActiveEx(true); FPS.gameObject.SetActiveEx(true);
//var gap = App.emu.Core.Frame - m_lastFrameInfo.lastFrame; //var gap = App.emu.Core.Frame - m_lastFrameInfo.lastFrame;
//var time = Time.realtimeSinceStartup - m_lastFrameInfo.lastTime; //var time = Time.realtimeSinceStartup - m_lastFrameInfo.lastTime;
var gap = App.emu.Core.Frame - m_lastFrameInfo.Item1; var gap = App.emu.Core.Frame - m_lastFrameInfo.Item1;
var time = Time.realtimeSinceStartup - m_lastFrameInfo.Item2; var time = Time.realtimeSinceStartup - m_lastFrameInfo.Item2;
var fps = gap / time; var fps = gap / time;
FPS.text = $"FPS:{fps:.#}"; FPS.text = $"FPS:{fps:.#}";
//m_lastFrameInfo.lastFrame = App.emu.Core.Frame; //m_lastFrameInfo.lastFrame = App.emu.Core.Frame;
//m_lastFrameInfo.lastTime = Time.realtimeSinceStartup; //m_lastFrameInfo.lastTime = Time.realtimeSinceStartup;
m_lastFrameInfo.Item1 = App.emu.Core.Frame; m_lastFrameInfo.Item1 = App.emu.Core.Frame;
m_lastFrameInfo.Item2 = Time.realtimeSinceStartup; m_lastFrameInfo.Item2 = Time.realtimeSinceStartup;
} }
} }
private void RefreshDelay() private void RefreshDelay()
{ {
if (App.user == null) if (App.user == null)
{ {
DelayValue.text = $"-"; DelayValue.text = $"-";
OnlinePlayerCount.text = $"-"; OnlinePlayerCount.text = $"-";
return; return;
} }
else else
{ {
if (App.user.IsLoggedIn) if (App.user.IsLoggedIn)
{ {
DelayValue.text = $"{App.tick.AveNetDelay * 1000:0}ms"; DelayValue.text = $"{App.tick.AveNetDelay * 1000:0}ms";
OnlinePlayerCount.text = App.user.OnlinePlayerCount.ToString(); OnlinePlayerCount.text = App.user.OnlinePlayerCount.ToString();
} }
else else
{ {
DelayValue.text = "-"; DelayValue.text = "-";
OnlinePlayerCount.text = $"-"; OnlinePlayerCount.text = $"-";
} }
} }
} }
void RefreshTime() void RefreshTime()
{ {
txtDateTime.text = DateTime.Now.ToString("MM/dd HH:mm"); txtDateTime.text = DateTime.Now.ToString("MM/dd HH:mm");
} }
void RefreshPower() void RefreshPower()
{ {
float battery = SystemInfo.batteryLevel; float battery = SystemInfo.batteryLevel;
if (Application.platform == RuntimePlatform.WindowsPlayer if (Application.platform == RuntimePlatform.WindowsPlayer
|| ||
Application.platform == RuntimePlatform.WindowsEditor Application.platform == RuntimePlatform.WindowsEditor
|| ||
Application.platform == RuntimePlatform.OSXPlayer Application.platform == RuntimePlatform.OSXPlayer
|| ||
Application.platform == RuntimePlatform.OSXEditor Application.platform == RuntimePlatform.OSXEditor
) )
{ {
battery = 1f; battery = 1f;
} }
if (battery > 0.80f) if (battery > 0.80f)
{ {
imgPower1.gameObject.SetActive(true); imgPower1.gameObject.SetActive(true);
imgPower2.gameObject.SetActive(true); imgPower2.gameObject.SetActive(true);
imgPower2.gameObject.SetActive(true); imgPower2.gameObject.SetActive(true);
} }
else if (battery > 0.50f) else if (battery > 0.50f)
{ {
imgPower1.gameObject.SetActive(false); imgPower1.gameObject.SetActive(false);
imgPower2.gameObject.SetActive(true); imgPower2.gameObject.SetActive(true);
imgPower2.gameObject.SetActive(true); imgPower2.gameObject.SetActive(true);
} }
else if (battery > 0.20f) else if (battery > 0.20f)
{ {
imgPower1.gameObject.SetActive(false); imgPower1.gameObject.SetActive(false);
imgPower2.gameObject.SetActive(false); imgPower2.gameObject.SetActive(false);
imgPower2.gameObject.SetActive(true); imgPower2.gameObject.SetActive(true);
} }
else else
{ {
imgPower1.gameObject.SetActive(false); imgPower1.gameObject.SetActive(false);
imgPower2.gameObject.SetActive(false); imgPower2.gameObject.SetActive(false);
imgPower2.gameObject.SetActive(false); imgPower2.gameObject.SetActive(false);
} }
} }
} }

View File

@ -1,47 +1,47 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf; using AxibugProtobuf;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public static class Utility public static class Utility
{ {
public static void SetActiveEx(this GameObject go, bool active) public static void SetActiveEx(this GameObject go, bool active)
{ {
if (active && go.activeSelf) return; if (active && go.activeSelf) return;
if (!active && !go.activeSelf) return; if (!active && !go.activeSelf) return;
go.SetActive(active); go.SetActive(active);
} }
public static string GetHostNickName(this Protobuf_Room_MiniInfo roomInfo) public static string GetHostNickName(this Protobuf_Room_MiniInfo roomInfo)
{ {
var hostUID = roomInfo.HostPlayerUID; var hostUID = roomInfo.HostPlayerUID;
Protobuf_Room_GamePlaySlot slotdata = roomInfo.GamePlaySlotList.FirstOrDefault(w => w.PlayerUID == hostUID); Protobuf_Room_GamePlaySlot slotdata = roomInfo.GamePlaySlotList.FirstOrDefault(w => w.PlayerUID == hostUID);
if (slotdata != null) if (slotdata != null)
return slotdata.PlayerNickName; return slotdata.PlayerNickName;
else else
return string.Empty; return string.Empty;
} }
public static void GetRoomPlayers(this Protobuf_Room_MiniInfo roomInfo, out int current, out int max) public static void GetRoomPlayers(this Protobuf_Room_MiniInfo roomInfo, out int current, out int max)
{ {
current = 0; max = 4; current = 0; max = 4;
current = roomInfo.GamePlaySlotList.Count(w => w.PlayerUID > 0); current = roomInfo.GamePlaySlotList.Count(w => w.PlayerUID > 0);
} }
private static Dictionary<int, RomFile> s_RomFileCahcesInRoomInfo = new Dictionary<int, RomFile>(); private static Dictionary<int, RomFile> s_RomFileCahcesInRoomInfo = new Dictionary<int, RomFile>();
public static void FetchRomFileInRoomInfo(this Protobuf_Room_MiniInfo roomInfo, Action<Protobuf_Room_MiniInfo, RomFile> callback) public static void FetchRomFileInRoomInfo(this Protobuf_Room_MiniInfo roomInfo, Action<Protobuf_Room_MiniInfo, RomFile> callback)
{ {
RomFile romFile; RomFile romFile;
if (s_RomFileCahcesInRoomInfo.TryGetValue(roomInfo.GameRomID, out romFile)) if (s_RomFileCahcesInRoomInfo.TryGetValue(roomInfo.GameRomID, out romFile))
{ {
callback.Invoke(roomInfo, romFile); callback.Invoke(roomInfo, romFile);
return; return;
} }
App.StartCoroutine(App.httpAPI.GetRomInfo(roomInfo.GameRomID, (romWebData) => App.StartCoroutine(App.httpAPI.GetRomInfo(roomInfo.GameRomID, (romWebData) =>
@ -51,17 +51,17 @@ namespace AxibugEmuOnline.Client
s_RomFileCahcesInRoomInfo[roomInfo.GameRomID] = _romFile; s_RomFileCahcesInRoomInfo[roomInfo.GameRomID] = _romFile;
callback.Invoke(roomInfo, _romFile); callback.Invoke(roomInfo, _romFile);
})); }));
} }
public static byte[] ToJPG(this Texture texture, Vector2 scale) public static byte[] ToJPG(this Texture texture, Vector2 scale)
{ {
Texture2D outputTex = ConvertFromRenderTexture(texture, scale); Texture2D outputTex = ConvertFromRenderTexture(texture, scale);
return outputTex.EncodeToJPG(); return outputTex.EncodeToJPG();
} }
private static Texture2D ConvertFromRenderTexture(Texture src, Vector2 scale) private static Texture2D ConvertFromRenderTexture(Texture src, Vector2 scale)
{ {
float offsetX = (scale.x < 0) ? 1 : 0; float offsetX = (scale.x < 0) ? 1 : 0;
@ -83,6 +83,6 @@ namespace AxibugEmuOnline.Client
RenderTexture.active = null; RenderTexture.active = null;
RenderTexture.ReleaseTemporary(tempRT); RenderTexture.ReleaseTemporary(tempRT);
return tex; return tex;
} }
} }
} }