using AxibugEmuOnline.Client.ClientCore; using AxibugProtobuf; using AxiReplay; using System; using UnityEngine; using UnityEngine.SocialPlatforms.Impl; using UnityEngine.UI; namespace AxibugEmuOnline.Client { public abstract class EmuCore : MonoBehaviour { /// 获得模拟器核心中的状态快照对象 public abstract object GetState(); /// 获得模拟器核心中的状态快照字节数据 public abstract byte[] GetStateBytes(); /// 加载状态快照 /// 该对象应该来自核心的方法的返回值,或是从返回的byte数组构建 public abstract void LoadState(object state); /// 加载状态快照 /// 该对象应该来自核心的返回的byte数组 public abstract void LoadStateFromBytes(byte[] data); /// 暂停核心推帧 public abstract void Pause(); /// 恢复核心推帧(从Pause状态恢复) public abstract void Resume(); /// 启动模拟器逻辑 public abstract MsgBool StartGame(RomFile romFile); /// 释放模拟器核心 public abstract void Dispose(); /// 重置核心,通常由模拟器核心提供的功能 public abstract void DoReset(); /// 获得模拟器核心的控制器设置器 /// public abstract IControllerSetuper GetControllerSetuper(); /// 核心所属平台 public abstract RomPlatformType Platform { get; } /// 获取当前模拟器帧序号,在加载快照和Reset后,应当重置为0 public abstract uint Frame { get; } public abstract void PushEmulatorFrame(); /// 模拟器核心推帧结束 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 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 : EmuCore { 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 (IsNetPlay) { 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(m_replayData); result = true; } else { result = false; } } 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); } }