diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesEmulator.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesEmulator.cs index 2f318b37..0f706a8a 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesEmulator.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesEmulator.cs @@ -1,5 +1,6 @@ using AxibugEmuOnline.Client.ClientCore; using AxibugProtobuf; +using AxiReplay; using System; using System.Diagnostics; using System.Globalization; @@ -11,7 +12,7 @@ using VirtualNes.Core.Debug; namespace AxibugEmuOnline.Client { - public class NesEmulator : IEmuCore + public class NesEmulator : EmuCore { public VideoProvider VideoProvider; public AudioProvider AudioProvider; @@ -122,32 +123,31 @@ namespace AxibugEmuOnline.Client NesCore = null; } - -#if UNITY_EDITOR - private ControllerState m_lastState; -#endif //推进帧 - public override bool PushEmulatorFrame() + protected override bool OnPushEmulatorFrame(ControllerState inputData) { if (NesCore == null || IsPause) return false; - m_coreSupporter.SampleInput(NesCore.FrameCount); - var controlState = m_coreSupporter.GetControllerState(); - - //如果未收到Input数据,核心帧不推进 - if (!controlState.valid) return false; - -#if UNITY_EDITOR - if (controlState != m_lastState) App.log.Info($"[LOCALDEBUG]{NesCore.FrameCount}-->{controlState}"); - m_lastState = controlState; -#endif - - NesCore.pad.Sync(controlState); + NesCore.pad.Sync(inputData); NesCore.EmulateFrame(true); return true; } + protected override ControllerState ConvertInputDataFromNet(ReplayStep step) + { + return m_coreSupporter.FromNet(step); + } + protected override ulong InputDataToNet(ControllerState inputData) + { + return m_coreSupporter.ToNet(inputData); + } + + protected override ControllerState GetLocalInput() + { + return m_coreSupporter.GetControllerState(); + } + public override unsafe void AfterPushFrame() { @@ -164,6 +164,13 @@ namespace AxibugEmuOnline.Client { StopGame(); } + + public override Texture OutputPixel => VideoProvider.OutputPixel; + public override RawImage DrawCanvas => VideoProvider.Drawer; + public override void GetAudioParams(out int frequency, out int channels) + { + AudioProvider.GetAudioParams(out frequency, out channels); + } #if UNITY_EDITOR /// @@ -195,13 +202,5 @@ namespace AxibugEmuOnline.Client UnityEditor.AssetDatabase.SaveAssets(); } #endif - - public override Texture OutputPixel => VideoProvider.OutputPixel; - public override RawImage DrawCanvas => VideoProvider.Drawer; - public override void GetAudioParams(out int frequency, out int channels) - { - AudioProvider.GetAudioParams(out frequency, out channels); - } - } } \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IEmuCore.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/IEmuCore.cs index 37d36f94..aebf176c 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IEmuCore.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/IEmuCore.cs @@ -1,9 +1,18 @@ -using AxibugProtobuf; +#pragma warning disable CS0618 // 类型或成员已过时 + +using AxibugEmuOnline.Client.ClientCore; +using AxibugProtobuf; +using AxiReplay; +using System; using UnityEngine; using UnityEngine.UI; namespace AxibugEmuOnline.Client { + /// + /// use instead + /// + [Obsolete("不可直接继承,需要继承EmuCore类型")] public abstract class IEmuCore : MonoBehaviour { /// 获得模拟器核心中的状态快照对象 @@ -33,12 +42,79 @@ namespace AxibugEmuOnline.Client public abstract RomPlatformType Platform { get; } /// 获取当前模拟器帧序号,在加载快照和Reset后,应当重置为0 public abstract uint Frame { get; } - /// 模拟器核心推帧 + public abstract bool PushEmulatorFrame(); /// 模拟器核心推帧结束 public abstract void AfterPushFrame(); public abstract void GetAudioParams(out int frequency, out int channels); public abstract Texture OutputPixel { get; } public abstract RawImage DrawCanvas { get; } + } + + public abstract class EmuCore : IEmuCore + { + public sealed override bool PushEmulatorFrame() + { + if (SampleInputData(out var inputData)) + { + return OnPushEmulatorFrame(inputData); + } + + return false; + } + + ulong m_lastTestInput; + protected bool SampleInputData(out INPUTDATA inputData) + { + bool result = false; + inputData = default(INPUTDATA); + + if (InGameUI.Instance.IsNetPlay) + { + ReplayStep replayData; + int frameDiff; + bool inputDiff; + + if (App.roomMgr.netReplay.TryGetNextFrame((int)Frame, out replayData, out frameDiff, out inputDiff)) + { + if (inputDiff) + { + App.log.Debug($"{DateTime.Now.ToString("hh:mm:ss.fff")} TryGetNextFrame remoteFrame->{App.roomMgr.netReplay.mRemoteFrameIdx} diff->{frameDiff} " + + $"frame=>{replayData.FrameStartID} InPut=>{replayData.InPut}"); + } + + inputData = ConvertInputDataFromNet(replayData); + result = true; + } + else + { + result = false; + } + + var localState = GetLocalInput(); + var rawData = InputDataToNet(localState); + if (m_lastTestInput != rawData) + { + m_lastTestInput = rawData; + App.log.Debug($"{DateTime.Now.ToString("hh:mm:ss.fff")} Input F:{App.roomMgr.netReplay.mCurrClientFrameIdx} | I:{rawData}"); + } + App.roomMgr.SendRoomSingelPlayerInput(Frame, rawData); + } + //单机模式 + else + { + inputData = GetLocalInput(); + result = true; + } + + return result; + } + + protected abstract INPUTDATA GetLocalInput(); + protected abstract INPUTDATA ConvertInputDataFromNet(ReplayStep step); + protected abstract ulong InputDataToNet(INPUTDATA inputData); + /// 模拟器核心推帧 + protected abstract bool OnPushEmulatorFrame(INPUTDATA InputData); } } +#pragma warning restore CS0618 // 类型或成员已过时