diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs index f7656a0e..ce7a74b7 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs @@ -65,7 +65,7 @@ namespace AxiReplay frameProfiler.InputHead(inputData.FrameStartID); } - public bool TryGetNextFrame(out ReplayStep data, out int frameDiff, out bool inputDiff) + public bool TryGetNextFrame(int targetFrame, bool indirectGet, out ReplayStep data, out int frameDiff, out bool inputDiff) { if (!bNetInit) { @@ -74,37 +74,27 @@ namespace AxiReplay inputDiff = false; return false; } - TakeFrame(1, out data, out frameDiff, out inputDiff); - return frameDiff > 0; + return TakeFrameToTargetFrame(targetFrame, indirectGet, out data, out frameDiff, out inputDiff); } - public bool TryGetNextFrame(int targetFrame, out ReplayStep data, out int frameDiff, out bool inputDiff) - { - if (!bNetInit) - { - data = default(ReplayStep); - frameDiff = default(int); - inputDiff = false; - return false; - } - return TakeFrameToTargetFrame(targetFrame, out data, out frameDiff, out inputDiff); + bool checkCanGetFrame(int targetFrame, bool indirectGet) + { + if (indirectGet) + { + return targetFrame == mNextReplay.FrameStartID && targetFrame <= mRemoteFrameIdx; + } + else + { + return targetFrame == mNextReplay.FrameStartID && targetFrame <= mRemoteFrameIdx && mNetReplayQueue.Count >= frameProfiler.TempFrameCount(mRemoteForwardCount); + } } - void TakeFrame(int addFrame, out ReplayStep data, out int bFrameDiff, out bool inputDiff) - { - int targetFrame = mCurrClientFrameIdx + addFrame; - TakeFrameToTargetFrame(targetFrame, out data, out bFrameDiff, out inputDiff); - } - - bool TakeFrameToTargetFrame(int targetFrame, out ReplayStep data, out int bFrameDiff, out bool inputDiff) + bool TakeFrameToTargetFrame(int targetFrame, bool indirectGet, out ReplayStep data, out int bFrameDiff, out bool inputDiff) { bool result; inputDiff = false; - - //if (targetFrame == mNextReplay.FrameStartID && targetFrame <= mRemoteFrameIdx && mNetReplayQueue.Count > 0) - //if (targetFrame == mNextReplay.FrameStartID && targetFrame <= mRemoteFrameIdx && mNetReplayQueue.Count >= mRemoteForwardCount) - if (targetFrame == mNextReplay.FrameStartID && targetFrame <= mRemoteFrameIdx && mNetReplayQueue.Count >= frameProfiler.TempFrameCount(mRemoteForwardCount)) + if (checkCanGetFrame(targetFrame, indirectGet)) { //当前帧追加 mCurrClientFrameIdx = targetFrame; diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IEmuCore.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/EmuCore.cs similarity index 56% rename from AxibugEmuOnline.Client/Assets/Script/AppMain/IEmuCore.cs rename to AxibugEmuOnline.Client/Assets/Script/AppMain/EmuCore.cs index 1be8dfe4..ef893e45 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IEmuCore.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/EmuCore.cs @@ -1,19 +1,14 @@ -#pragma warning disable CS0618 // 类型或成员已过时 - -using AxibugEmuOnline.Client.ClientCore; +using AxibugEmuOnline.Client.ClientCore; using AxibugProtobuf; using AxiReplay; using System; using UnityEngine; +using UnityEngine.SocialPlatforms.Impl; using UnityEngine.UI; namespace AxibugEmuOnline.Client -{ - /// - /// use instead - /// - [Obsolete("不可直接继承,需要继承EmuCore类型")] - public abstract class IEmuCore : MonoBehaviour +{ + public abstract class EmuCore : MonoBehaviour { /// 获得模拟器核心中的状态快照对象 public abstract object GetState(); @@ -43,62 +38,101 @@ namespace AxibugEmuOnline.Client /// 获取当前模拟器帧序号,在加载快照和Reset后,应当重置为0 public abstract uint Frame { get; } - public abstract bool PushEmulatorFrame(); + public abstract void PushEmulatorFrame(); /// 模拟器核心推帧结束 - public abstract void AfterPushFrame(); + protected 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 RawImage DrawCanvas { get; } + + + /// 指示该游戏实例是否处于联机模式 + public bool IsNetPlay + { + get + { + if (!App.user.IsLoggedIn) return false; + if (App.roomMgr.mineRoomMiniInfo == null) return false; + if (App.roomMgr.RoomState <= RoomGameState.OnlyHost) return false; + + return true; + } + } } - public abstract class EmuCore : IEmuCore + /// 输入数据类型 + public abstract class EmuCore : EmuCore { - public sealed override bool PushEmulatorFrame() + protected virtual bool EnableRollbackNetCode => false; + + public sealed override void PushEmulatorFrame() + { + if (!TryPushEmulatorFrame()) return; + + if (IsNetPlay) //skip frame handle + { + var skipFrameCount = App.roomMgr.netReplay.GetSkipFrameCount(); + if (skipFrameCount > 0) App.log.Debug($"SKIP FRAME : {skipFrameCount} ,CF:{App.roomMgr.netReplay.mCurrClientFrameIdx},RFIdx:{App.roomMgr.netReplay.mRemoteFrameIdx},RForward:{App.roomMgr.netReplay.mRemoteForwardCount} ,queue:{App.roomMgr.netReplay.mNetReplayQueue.Count}"); + for (var i = 0; i < skipFrameCount; i++) + { + if (!TryPushEmulatorFrame()) break; + } + } + + AfterPushFrame(); + } + + bool TryPushEmulatorFrame() { if (SampleInputData(out var inputData)) { + if (IsNetPlay) SendLocalInput(); + return OnPushEmulatorFrame(inputData); } return false; } + private void SendLocalInput() + { + var localState = GetLocalInput(); + var rawData = InputDataToNet(localState); + App.roomMgr.SendRoomSingelPlayerInput(Frame, rawData); + + 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}"); + } + } + ulong m_lastTestInput; + ReplayStep m_replayData; + int m_frameDiff; + bool m_inputDiff; protected bool SampleInputData(out INPUTDATA inputData) { bool result = false; inputData = default(INPUTDATA); - if (InGameUI.Instance.IsNetPlay) + if (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}"); + if (App.roomMgr.netReplay.TryGetNextFrame((int)Frame, EnableRollbackNetCode ? true : false, out m_replayData, out m_frameDiff, out m_inputDiff)) + { + if (m_inputDiff) + { + 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}"); } - inputData = ConvertInputDataFromNet(replayData); + inputData = ConvertInputDataFromNet(m_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//单机模式 { @@ -116,4 +150,3 @@ namespace AxibugEmuOnline.Client protected abstract bool OnPushEmulatorFrame(INPUTDATA InputData); } } -#pragma warning restore CS0618 // 类型或成员已过时 diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IEmuCore.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/EmuCore.cs.meta similarity index 100% rename from AxibugEmuOnline.Client/Assets/Script/AppMain/IEmuCore.cs.meta rename to AxibugEmuOnline.Client/Assets/Script/AppMain/EmuCore.cs.meta diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgee.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgee.cs index 69ef9530..4945f129 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgee.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgee.cs @@ -167,7 +167,7 @@ public class UEssgee : EmuCore return mUniKeyboard.DoLocalPressedKeys(); } - public override void AfterPushFrame() + protected override void AfterPushFrame() { } diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UMAME.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UMAME.cs index 253836be..13e0eb28 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UMAME.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UMAME.cs @@ -179,7 +179,7 @@ public class UMAME : EmuCore return mUniKeyboard.DoLocalPressedKeys(); } - public 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}"); } diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs index 92b63622..924701bb 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs @@ -65,7 +65,7 @@ public class UniKeyboard : MonoBehaviour, IKeyboard public ulong GetPressedKeys() { - if (InGameUI.Instance.IsNetPlay) + if (InGameUI.Instance.Core.IsNetPlay) return CurrRemoteInpuAllData; else return CurrLocalInpuAllData; diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesEmulator.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesEmulator.cs index 69cf14d7..e5f8062b 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesEmulator.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesEmulator.cs @@ -149,7 +149,7 @@ namespace AxibugEmuOnline.Client } - public override unsafe void AfterPushFrame() + protected override unsafe void AfterPushFrame() { var screenBuffer = NesCore.ppu.GetScreenPtr(); VideoProvider.SetDrawData(screenBuffer); diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs index 7ec435cb..5d1705e3 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs @@ -145,7 +145,7 @@ public class UStoicGoose : EmuCore throw new NotImplementedException(); } - public override void AfterPushFrame() + protected override void AfterPushFrame() { throw new NotImplementedException(); } diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs index d53608f6..52332280 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs @@ -11,7 +11,7 @@ namespace AxibugEmuOnline.Client.Manager /// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符 /// 但是Equals方法可以,所以,这个接口判断为空请使用Equals /// - private IEmuCore m_emuCore; + private EmuCore m_emuCore; private IControllerSetuper m_controllerSetuper; @@ -19,7 +19,7 @@ namespace AxibugEmuOnline.Client.Manager /// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符 /// 但是Equals方法可以,所以,这个接口判断为空请使用Equals /// - public IEmuCore Core => m_emuCore; + public EmuCore Core => m_emuCore; public AppEmu() { @@ -53,14 +53,14 @@ namespace AxibugEmuOnline.Client.Manager switch (romFile.Platform) { case RomPlatformType.Nes: - m_emuCore = GameObject.Instantiate(Resources.Load("NES/NesEmulator")).GetComponent(); + m_emuCore = GameObject.Instantiate(Resources.Load("NES/NesEmulator")).GetComponent(); break; case RomPlatformType.Cps1: case RomPlatformType.Cps2: case RomPlatformType.Igs: case RomPlatformType.Neogeo: case RomPlatformType.ArcadeOld: - m_emuCore = GameObject.Instantiate(Resources.Load("MAME/UMAME")).GetComponent(); + m_emuCore = GameObject.Instantiate(Resources.Load("MAME/UMAME")).GetComponent(); break; case RomPlatformType.MasterSystem: case RomPlatformType.GameGear: @@ -69,11 +69,11 @@ namespace AxibugEmuOnline.Client.Manager case RomPlatformType.ColecoVision: case RomPlatformType.Sc3000: case RomPlatformType.Sg1000: - m_emuCore = GameObject.Instantiate(Resources.Load("EssgeeUnity/EssgeeUnity")).GetComponent(); + m_emuCore = GameObject.Instantiate(Resources.Load("EssgeeUnity/EssgeeUnity")).GetComponent(); break; case RomPlatformType.WonderSwan: case RomPlatformType.WonderSwanColor: - m_emuCore = GameObject.Instantiate(Resources.Load("StoicGooseUnity/StoicGooseUnity")).GetComponent(); + m_emuCore = GameObject.Instantiate(Resources.Load("StoicGooseUnity/StoicGooseUnity")).GetComponent(); break; } diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI.cs index 6a8b0dea..3ed9dd31 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI.cs @@ -20,20 +20,7 @@ namespace AxibugEmuOnline.Client public override bool Enable => gameObject.activeInHierarchy; - /// 指示该游戏实例是否处于联机模式 - public bool IsNetPlay - { - get - { - if (!App.user.IsLoggedIn) return false; - if (App.roomMgr.mineRoomMiniInfo == null) return false; - if (App.roomMgr.RoomState <= RoomGameState.OnlyHost) return false; - - return true; - } - } - - public IEmuCore Core { get; private set; } + public EmuCore Core { get; private set; } protected override void Awake() { @@ -69,18 +56,7 @@ namespace AxibugEmuOnline.Client //fluash netMsg NetMsg.Instance.DequeueNesMsg(); - if (!Core.PushEmulatorFrame()) return; - - if (IsNetPlay) //skip frame handle - { - var skipFrameCount = App.roomMgr.netReplay.GetSkipFrameCount(); - if (skipFrameCount > 0) App.log.Debug($"SKIP FRAME : {skipFrameCount} ,CF:{App.roomMgr.netReplay.mCurrClientFrameIdx},RFIdx:{App.roomMgr.netReplay.mRemoteFrameIdx},RForward:{App.roomMgr.netReplay.mRemoteForwardCount} ,queue:{App.roomMgr.netReplay.mNetReplayQueue.Count}"); - for (var i = 0; i < skipFrameCount; i++) - if (!Core.PushEmulatorFrame()) - break; - } - - Core.AfterPushFrame(); + Core.PushEmulatorFrame(); } protected override void OnDestroy() @@ -103,7 +79,7 @@ namespace AxibugEmuOnline.Client return m_state; } - public void Show(RomFile currentRom, IEmuCore core) + public void Show(RomFile currentRom, EmuCore core) { m_delayCreateRoom = false; m_state = null; //清空游戏快照 @@ -186,14 +162,14 @@ namespace AxibugEmuOnline.Client { OverlayManager.PopSideBar(menus, 0, PopMenu_OnHide); - if (!IsNetPlay) //单人模式暂停模拟器 + if (!Core.IsNetPlay) //单人模式暂停模拟器 Core.Pause(); } //菜单关闭时候 private void PopMenu_OnHide() { - if (!IsNetPlay) //单人模式恢复模拟器的暂停 + if (!Core.IsNetPlay) //单人模式恢复模拟器的暂停 Core.Resume(); } diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_LoadStateQuick.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_LoadStateQuick.cs index b4b39e24..0fa39a39 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_LoadStateQuick.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_LoadStateQuick.cs @@ -3,7 +3,7 @@ public class InGameUI_LoadStateQuick : ExecuteMenu { private InGameUI m_gameUI; - public override bool Visible => !m_gameUI.IsNetPlay && m_gameUI.GetQuickState() != null; + public override bool Visible => !m_gameUI.Core.IsNetPlay && m_gameUI.GetQuickState() != null; public override string Name => "快速读取"; public InGameUI_LoadStateQuick(InGameUI gameUI) @@ -13,7 +13,7 @@ public override void OnExcute(OptionUI optionUI, ref bool cancelHide) { - if (m_gameUI.IsNetPlay) return; + if (m_gameUI.Core.IsNetPlay) return; object state = m_gameUI.GetQuickState(); if (state != null) diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_Reset.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_Reset.cs index a804dd66..32db8a89 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_Reset.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_Reset.cs @@ -6,7 +6,7 @@ namespace AxibugEmuOnline.Client { private InGameUI m_gameUI; public override string Name => "复位"; - public override bool Visible => !m_gameUI.IsNetPlay || App.roomMgr.IsHost; + public override bool Visible => !m_gameUI.Core.IsNetPlay || App.roomMgr.IsHost; public InGameUI_Reset(InGameUI gameUI) { @@ -15,7 +15,7 @@ namespace AxibugEmuOnline.Client public override void OnExcute(OptionUI optionUI, ref bool cancelHide) { - if (!m_gameUI.IsNetPlay) + if (!m_gameUI.Core.IsNetPlay) { App.emu.ResetGame(); } diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_SaveStateQuick.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_SaveStateQuick.cs index f8a51a1b..c8e5c506 100644 --- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_SaveStateQuick.cs +++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_SaveStateQuick.cs @@ -7,7 +7,7 @@ namespace AxibugEmuOnline.Client { private InGameUI m_gameUI; - public override bool Visible => !m_gameUI.IsNetPlay; + public override bool Visible => !m_gameUI.Core.IsNetPlay; public override string Name => "快速保存"; public InGameUI_SaveStateQuick(InGameUI gameUI) @@ -17,7 +17,7 @@ namespace AxibugEmuOnline.Client public override void OnExcute(OptionUI optionUI, ref bool cancelHide) { - if (m_gameUI.IsNetPlay) return; + if (m_gameUI.Core.IsNetPlay) return; Stopwatch sw = Stopwatch.StartNew(); object state = m_gameUI.Core.GetState();