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 { 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)) { return OnPushEmulatorFrame(inputData); } return false; } ulong m_lastTestInput; protected bool SampleInputData(out INPUTDATA inputData) { bool result = false; inputData = default(INPUTDATA); 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}"); } 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); } }