实现完美Replay

This commit is contained in:
sin365 2025-01-16 17:12:35 +08:00
parent c1f23ea66f
commit ea7e065b79
7 changed files with 230 additions and 209 deletions

View File

@ -82,6 +82,7 @@ namespace AxiReplay
void UpdateNextFrame(int targetFrame) void UpdateNextFrame(int targetFrame)
{ {
int LastNextFrameStartID = nextStep.FrameStartID;
//如果已经超过 //如果已经超过
while (targetFrame >= nextStep.FrameStartID) while (targetFrame >= nextStep.FrameStartID)
{ {
@ -117,6 +118,12 @@ namespace AxiReplay
} }
dbgList.Add($"{nextStep.FrameStartID} | {nextStep.InPut}"); dbgList.Add($"{nextStep.FrameStartID} | {nextStep.InPut}");
//如果这次的NextStep1只推进了1帧则跳过交给下一帧判断
if (nextStep.FrameStartID - LastNextFrameStartID == 1)
{
break;
}
targetFrame++; targetFrame++;
} }
} }
@ -159,10 +166,12 @@ namespace AxiReplay
/// </summary> /// </summary>
public bool NextFramebyFrameIdx(int FrameID, out ReplayStep data) public bool NextFramebyFrameIdx(int FrameID, out ReplayStep data)
{ {
if (FrameID - lastTest != 1)
{
}
lastTest = FrameID; lastTest = FrameID;
if (FrameID == 3360)
{
}
bool res = TakeFrame(FrameID - byFrameIdx, out data); bool res = TakeFrame(FrameID - byFrameIdx, out data);
byFrameIdx = FrameID; byFrameIdx = FrameID;
return res; return res;

View File

@ -20,7 +20,8 @@ namespace MAME.Core
} }
public static PlayState playState; public static PlayState playState;
public static bool is_foreground; public static bool is_foreground;
public static bool paused, exit_pending; public static bool paused;
public static bool exit_pending;
public static EmuTimer.emu_timer soft_reset_timer; public static EmuTimer.emu_timer soft_reset_timer;
public static BinaryReader brRecord = null; public static BinaryReader brRecord = null;
public static BinaryWriter bwRecord = null; public static BinaryWriter bwRecord = null;
@ -57,7 +58,8 @@ namespace MAME.Core
} }
else else
{ {
Video.video_frame_update(); //TODO 暂停时,不应该更新画面帧
//Video.video_frame_update();
} }
/*if (bPP) /*if (bPP)
{ {

View File

@ -845,6 +845,7 @@ namespace MAME.Core
screenstate.vblank_start_time = EmuTimer.global_basetime;// Timer.get_current_time(); screenstate.vblank_start_time = EmuTimer.global_basetime;// Timer.get_current_time();
screenstate.vblank_end_time = Attotime.attotime_add_attoseconds(screenstate.vblank_start_time, screenstate.vblank_period); screenstate.vblank_end_time = Attotime.attotime_add_attoseconds(screenstate.vblank_start_time, screenstate.vblank_period);
Cpuexec.on_vblank(); Cpuexec.on_vblank();
//垂直同步
if ((video_attributes & VIDEO_UPDATE_AFTER_VBLANK) == 0) if ((video_attributes & VIDEO_UPDATE_AFTER_VBLANK) == 0)
{ {
video_frame_update(); video_frame_update();
@ -862,6 +863,7 @@ namespace MAME.Core
public static void vblank_end_callback() public static void vblank_end_callback()
{ {
int i; int i;
//垂直同步
if ((video_attributes & VIDEO_UPDATE_AFTER_VBLANK) != 0) if ((video_attributes & VIDEO_UPDATE_AFTER_VBLANK) != 0)
{ {
video_frame_update(); video_frame_update();

View File

@ -75,7 +75,7 @@ public class UMAME : MonoBehaviour
mChangeRomName = UniMAMESetting.instance.LastGameRom; mChangeRomName = UniMAMESetting.instance.LastGameRom;
mTimeSpan = new UniTimeSpan(); mTimeSpan = new UniTimeSpan();
emu.Init(RomPath, mUniLog, mUniResources, mUniVideoPlayer, mUniSoundPlayer, mUniKeyboard.mKeyCodeCore, mUniMouse, mTimeSpan); emu.Init(RomPath, mUniLog, mUniResources, mUniVideoPlayer, mUniSoundPlayer, mUniKeyboard, mUniMouse, mTimeSpan);
ALLGame = emu.GetGameList(); ALLGame = emu.GetGameList();
Debug.Log($"ALLGame:{ALLGame.Count}"); Debug.Log($"ALLGame:{ALLGame.Count}");
@ -125,7 +125,7 @@ public class UMAME : MonoBehaviour
{ {
string Path = SavePath + Machine.sName + ".rp"; string Path = SavePath + Machine.sName + ".rp";
mReplayReader = new ReplayReader(Path); mReplayReader = new ReplayReader(Path);
mUniKeyboard.mKeyCodeCore.SetRePlay(true); mUniKeyboard.SetRePlay(true);
} }
//读取ROM之后获得宽高初始化画面 //读取ROM之后获得宽高初始化画面
@ -168,7 +168,7 @@ public class UMAME : MonoBehaviour
string Path = SavePath + Machine.sName + ".rp"; string Path = SavePath + Machine.sName + ".rp";
string dbgPath = SavePath + Machine.sName + ".rpread"; string dbgPath = SavePath + Machine.sName + ".rpread";
mReplayReader = new ReplayReader(Path, true, dbgPath); mReplayReader = new ReplayReader(Path, true, dbgPath);
mUniKeyboard.mKeyCodeCore.Init(mUniKeyboard, true); mUniKeyboard.Init(true);
} }
} }

View File

@ -1,183 +0,0 @@
using MAME.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class KeyCodeCore : IKeyboard
{
public Dictionary<KeyCode, MotionKey> dictKeyCfgs = new Dictionary<KeyCode, MotionKey>();
public KeyCode[] CheckList;
public MotionKey[] mCurrKey = new MotionKey[0];
public ulong CurryInpuAllData = 0;
List<MotionKey> temp = new List<MotionKey>();
ulong tempInputAllData = 0;
UniKeyboard mUniKeyboard;
bool bReplayMode;
List<MotionKey> ReplayCheckKey = new List<MotionKey>();
ulong last_CurryInpuAllData_test = 0;
public MotionKey[] GetPressedKeys()
{
if (!bReplayMode)
{
//UMAME.instance.mReplayWriter.NextFramebyFrameIdx((int)UMAME.instance.mUniVideoPlayer.mFrame, CurryInpuAllData);
UMAME.instance.mReplayWriter.NextFramebyFrameIdx((int)UMAME.instance.mUniVideoPlayer.mFrame, CurryInpuAllData);
#if UNITY_EDITOR
if (last_CurryInpuAllData_test != CurryInpuAllData)
{
last_CurryInpuAllData_test = CurryInpuAllData;
string TempStr = "";
foreach (var item in mCurrKey)
{
TempStr += $"{item.ToString()}|";
}
if (!string.IsNullOrEmpty(TempStr))
Debug.Log($"{UMAME.instance.mUniVideoPlayer.mFrame} | Input-> {TempStr}");
else
Debug.Log($"{UMAME.instance.mUniVideoPlayer.mFrame} | Input-> 0");
}
#endif
return mCurrKey;
}
else
{
//有变化
//if (UMAME.instance.mReplayReader.NextFrame(out AxiReplay.ReplayStep stepData))
if (UMAME.instance.mReplayReader.NextFramebyFrameIdx((int)UMAME.instance.mUniVideoPlayer.mFrame, out AxiReplay.ReplayStep stepData))
{
temp.Clear();
//有数据
for (int i = 0; i < ReplayCheckKey.Count; i++)
{
if ((stepData.InPut & (ulong)ReplayCheckKey[i]) > 0)
temp.Add(ReplayCheckKey[i]);
}
mCurrKey = temp.ToArray();
#if UNITY_EDITOR
string TempStr = "";
foreach (var item in mCurrKey)
{
TempStr += $"{item.ToString()}|";
}
if (!string.IsNullOrEmpty(TempStr))
Debug.Log($"{UMAME.instance.mUniVideoPlayer.mFrame} | Input-> {TempStr}");
else
Debug.Log($"{UMAME.instance.mUniVideoPlayer.mFrame} | Input-> 0");
#endif
}
return mCurrKey;
}
}
public void SetRePlay(bool IsReplay)
{
bReplayMode = IsReplay;
}
public void Init(UniKeyboard uniKeyboard, bool IsReplay)
{
bReplayMode = IsReplay;
mUniKeyboard = uniKeyboard;
foreach (MotionKey mkey in Enum.GetValues(typeof(MotionKey)))
{
ReplayCheckKey.Add(mkey);
}
dictKeyCfgs.Clear();
//dictKeyCfgs.Add(KeyCode.P, MotionKey.EMU_PAUSED);
dictKeyCfgs.Add(KeyCode.Alpha1, MotionKey.P1_GAMESTART);
dictKeyCfgs.Add(KeyCode.Alpha5, MotionKey.P1_INSERT_COIN);
dictKeyCfgs.Add(KeyCode.W, MotionKey.P1_UP);
dictKeyCfgs.Add(KeyCode.S, MotionKey.P1_DOWN);
dictKeyCfgs.Add(KeyCode.A, MotionKey.P1_LEFT);
dictKeyCfgs.Add(KeyCode.D, MotionKey.P1_RIGHT);
dictKeyCfgs.Add(KeyCode.J, MotionKey.P1_BTN_1);
dictKeyCfgs.Add(KeyCode.K, MotionKey.P1_BTN_2);
dictKeyCfgs.Add(KeyCode.L, MotionKey.P1_BTN_3);
dictKeyCfgs.Add(KeyCode.U, MotionKey.P1_BTN_4);
dictKeyCfgs.Add(KeyCode.KeypadDivide, MotionKey.P2_GAMESTART);
dictKeyCfgs.Add(KeyCode.KeypadMultiply, MotionKey.P2_INSERT_COIN);
dictKeyCfgs.Add(KeyCode.UpArrow, MotionKey.P2_UP);
dictKeyCfgs.Add(KeyCode.DownArrow, MotionKey.P2_DOWN);
dictKeyCfgs.Add(KeyCode.LeftArrow, MotionKey.P2_LEFT);
dictKeyCfgs.Add(KeyCode.RightArrow, MotionKey.P2_RIGHT);
dictKeyCfgs.Add(KeyCode.Keypad1, MotionKey.P2_BTN_1);
dictKeyCfgs.Add(KeyCode.Keypad2, MotionKey.P2_BTN_2);
dictKeyCfgs.Add(KeyCode.Keypad3, MotionKey.P2_BTN_3);
dictKeyCfgs.Add(KeyCode.Keypad4, MotionKey.P2_BTN_4);
CheckList = dictKeyCfgs.Keys.ToArray();
mUniKeyboard.btnP1.Key = new long[] { (long)MotionKey.P1_GAMESTART };
mUniKeyboard.btnCoin1.Key = new long[] { (long)MotionKey.P1_INSERT_COIN };
mUniKeyboard.btnA.Key = new long[] { (long)MotionKey.P1_BTN_1 };
mUniKeyboard.btnB.Key = new long[] { (long)MotionKey.P1_BTN_2 };
mUniKeyboard.btnC.Key = new long[] { (long)MotionKey.P1_BTN_3 };
mUniKeyboard.btnD.Key = new long[] { (long)MotionKey.P1_BTN_4 };
//mUniKeyboard.btnE.Key = new long[] { (long)MotionKey.P1_BTN_5 };
//mUniKeyboard.btnF.Key = new long[] { (long)MotionKey.P1_BTN_6 };
mUniKeyboard.btnAB.Key = new long[] { (long)MotionKey.P1_BTN_1, (long)MotionKey.P1_BTN_2 };
mUniKeyboard.btnCD.Key = new long[] { (long)MotionKey.P1_BTN_3, (long)MotionKey.P1_BTN_4 };
mUniKeyboard.btnABC.Key = new long[] { (long)MotionKey.P1_BTN_1, (long)MotionKey.P1_BTN_2, (long)MotionKey.P1_BTN_3 };
}
public void UpdateLogic()
{
if (bReplayMode) return;
tempInputAllData = 0;
temp.Clear();
for (int i = 0; i < CheckList.Length; i++)
{
if (Input.GetKey(CheckList[i]))
{
MotionKey mk = dictKeyCfgs[CheckList[i]];
temp.Add(mk);
tempInputAllData |= (ulong)mk;
}
}
for (int i = 0; i < mUniKeyboard.mUIBtns.Count; i++)
{
if (mUniKeyboard.mUIBtns[i].bHotKey)
{
for (int j = 0; j < mUniKeyboard.mUIBtns[i].Key.Length; j++)
{
MotionKey mk = (MotionKey)mUniKeyboard.mUIBtns[i].Key[j];
temp.Add(mk);
tempInputAllData |= (ulong)mk;
}
}
}
Vector2Int inputV2 = mUniKeyboard.mJoystick.RawInputV2;
//Debug.Log($"{inputV2.x},{inputV2.y}");
if (inputV2.x > 0)
{
temp.Add(MotionKey.P1_RIGHT);
tempInputAllData |= (ulong)MotionKey.P1_RIGHT;
}
else if (inputV2.x < 0)
{
temp.Add(MotionKey.P1_LEFT);
tempInputAllData |= (ulong)MotionKey.P1_LEFT;
}
if (inputV2.y > 0)
{
temp.Add(MotionKey.P1_UP);
tempInputAllData |= (ulong)MotionKey.P1_UP;
}
else if (inputV2.y < 0)
{
temp.Add(MotionKey.P1_DOWN);
tempInputAllData |= (ulong)MotionKey.P1_DOWN;
}
CurryInpuAllData = tempInputAllData;
mCurrKey = temp.ToArray();
}
}

View File

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

View File

@ -1,10 +1,11 @@
using MAME.Core;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using UnityEngine; using UnityEngine;
public class UniKeyboard : MonoBehaviour public class UniKeyboard : MonoBehaviour, IKeyboard
{ {
public KeyCodeCore mKeyCodeCore = new KeyCodeCore(); #region UIButton
#region
public UILongClickButton btnP1; public UILongClickButton btnP1;
public UILongClickButton btnCoin1; public UILongClickButton btnCoin1;
public UILongClickButton btnA; public UILongClickButton btnA;
@ -18,9 +19,15 @@ public class UniKeyboard : MonoBehaviour
public UILongClickButton btnABC; public UILongClickButton btnABC;
public Transform tfKeyPad; public Transform tfKeyPad;
public FloatingJoystick mJoystick; public FloatingJoystick mJoystick;
public List<UILongClickButton> mUIBtns = new List<UILongClickButton>();
#endregion #endregion
public List<UILongClickButton> mUIBtns = new List<UILongClickButton>(); public static Dictionary<KeyCode, MotionKey> dictKeyCfgs = new Dictionary<KeyCode, MotionKey>();
public static KeyCode[] CheckList;
bool bReplayMode;
PlayMode mPlayMode;
ReplayMode mReplayMode;
ulong last_CurryInpuAllData_test = 0;
void Awake() void Awake()
{ {
@ -59,16 +66,211 @@ public class UniKeyboard : MonoBehaviour
// btnF.gameObject.SetActive(false); // btnF.gameObject.SetActive(false);
//} //}
#if UNITY_STANDALONE_WIN || UNITY_EDITOR #if UNITY_STANDALONE_WIN || UNITY_EDITOR
tfKeyPad.gameObject.SetActive(false); tfKeyPad.gameObject.SetActive(false);
#endif #endif
mKeyCodeCore.Init(this,false); Init(false);
} }
public MotionKey[] GetPressedKeys()
{
MotionKey[] currkey;
ulong InputData;
if (!bReplayMode)
currkey = mPlayMode.GetPressedKeys(out InputData);
else
currkey = mReplayMode.GetPressedKeys(out InputData);
#if UNITY_EDITOR
if (last_CurryInpuAllData_test != InputData)
{
string TempStr = "";
foreach (var item in currkey)
{
TempStr += $"{item.ToString()}|";
}
Debug.Log($"{UMAME.instance.mUniVideoPlayer.mFrame} | {EmuTimer.get_current_time().attoseconds} |{EmuTimer.get_current_time().seconds} | {InputData} | {TempStr}");
last_CurryInpuAllData_test = InputData;
}
#endif
return currkey;
}
public void UpdateInputKey() public void UpdateInputKey()
{ {
mKeyCodeCore.UpdateLogic(); UpdateLogic();
}
#region
public void SetRePlay(bool IsReplay)
{
bReplayMode = IsReplay;
}
public void Init(bool IsReplay)
{
bReplayMode = IsReplay;
dictKeyCfgs.Clear();
//dictKeyCfgs.Add(KeyCode.P, MotionKey.EMU_PAUSED);
dictKeyCfgs.Add(KeyCode.Alpha1, MotionKey.P1_GAMESTART);
dictKeyCfgs.Add(KeyCode.Alpha5, MotionKey.P1_INSERT_COIN);
dictKeyCfgs.Add(KeyCode.W, MotionKey.P1_UP);
dictKeyCfgs.Add(KeyCode.S, MotionKey.P1_DOWN);
dictKeyCfgs.Add(KeyCode.A, MotionKey.P1_LEFT);
dictKeyCfgs.Add(KeyCode.D, MotionKey.P1_RIGHT);
dictKeyCfgs.Add(KeyCode.J, MotionKey.P1_BTN_1);
dictKeyCfgs.Add(KeyCode.K, MotionKey.P1_BTN_2);
dictKeyCfgs.Add(KeyCode.L, MotionKey.P1_BTN_3);
dictKeyCfgs.Add(KeyCode.U, MotionKey.P1_BTN_4);
dictKeyCfgs.Add(KeyCode.KeypadDivide, MotionKey.P2_GAMESTART);
dictKeyCfgs.Add(KeyCode.KeypadMultiply, MotionKey.P2_INSERT_COIN);
dictKeyCfgs.Add(KeyCode.UpArrow, MotionKey.P2_UP);
dictKeyCfgs.Add(KeyCode.DownArrow, MotionKey.P2_DOWN);
dictKeyCfgs.Add(KeyCode.LeftArrow, MotionKey.P2_LEFT);
dictKeyCfgs.Add(KeyCode.RightArrow, MotionKey.P2_RIGHT);
dictKeyCfgs.Add(KeyCode.Keypad1, MotionKey.P2_BTN_1);
dictKeyCfgs.Add(KeyCode.Keypad2, MotionKey.P2_BTN_2);
dictKeyCfgs.Add(KeyCode.Keypad3, MotionKey.P2_BTN_3);
dictKeyCfgs.Add(KeyCode.Keypad4, MotionKey.P2_BTN_4);
CheckList = dictKeyCfgs.Keys.ToArray();
btnP1.Key = new long[] { (long)MotionKey.P1_GAMESTART };
btnCoin1.Key = new long[] { (long)MotionKey.P1_INSERT_COIN };
btnA.Key = new long[] { (long)MotionKey.P1_BTN_1 };
btnB.Key = new long[] { (long)MotionKey.P1_BTN_2 };
btnC.Key = new long[] { (long)MotionKey.P1_BTN_3 };
btnD.Key = new long[] { (long)MotionKey.P1_BTN_4 };
//btnE.Key = new long[] { (long)MotionKey.P1_BTN_5 };
//btnF.Key = new long[] { (long)MotionKey.P1_BTN_6 };
btnAB.Key = new long[] { (long)MotionKey.P1_BTN_1, (long)MotionKey.P1_BTN_2 };
btnCD.Key = new long[] { (long)MotionKey.P1_BTN_3, (long)MotionKey.P1_BTN_4 };
btnABC.Key = new long[] { (long)MotionKey.P1_BTN_1, (long)MotionKey.P1_BTN_2, (long)MotionKey.P1_BTN_3 };
mPlayMode = new PlayMode(this);
mReplayMode = new ReplayMode();
}
public void UpdateLogic()
{
if (bReplayMode) return;
mPlayMode.UpdateLogic();
}
public class PlayMode
{
Dictionary<KeyCode, MotionKey> dictKeyCfgs => UniKeyboard.dictKeyCfgs;
UniKeyboard mUniKeyboard;
KeyCode[] CheckList => UniKeyboard.CheckList;
ulong tempInputAllData = 0;
List<MotionKey> temp = new List<MotionKey>();
public ulong CurryInpuAllData = 0;
public MotionKey[] mCurrKey = new MotionKey[0];
public PlayMode(UniKeyboard uniKeyboard)
{
this.mUniKeyboard = uniKeyboard;
}
public void UpdateLogic()
{
tempInputAllData = 0;
temp.Clear();
for (int i = 0; i < CheckList.Length; i++)
{
if (Input.GetKey(CheckList[i]))
{
MotionKey mk = dictKeyCfgs[CheckList[i]];
temp.Add(mk);
tempInputAllData |= (ulong)mk;
} }
} }
for (int i = 0; i < mUniKeyboard.mUIBtns.Count; i++)
{
if (mUniKeyboard.mUIBtns[i].bHotKey)
{
for (int j = 0; j < mUniKeyboard.mUIBtns[i].Key.Length; j++)
{
MotionKey mk = (MotionKey)mUniKeyboard.mUIBtns[i].Key[j];
temp.Add(mk);
tempInputAllData |= (ulong)mk;
}
}
}
Vector2Int inputV2 = mUniKeyboard.mJoystick.RawInputV2;
//Debug.Log($"{inputV2.x},{inputV2.y}");
if (inputV2.x > 0)
{
temp.Add(MotionKey.P1_RIGHT);
tempInputAllData |= (ulong)MotionKey.P1_RIGHT;
}
else if (inputV2.x < 0)
{
temp.Add(MotionKey.P1_LEFT);
tempInputAllData |= (ulong)MotionKey.P1_LEFT;
}
if (inputV2.y > 0)
{
temp.Add(MotionKey.P1_UP);
tempInputAllData |= (ulong)MotionKey.P1_UP;
}
else if (inputV2.y < 0)
{
temp.Add(MotionKey.P1_DOWN);
tempInputAllData |= (ulong)MotionKey.P1_DOWN;
}
CurryInpuAllData = tempInputAllData;
mCurrKey = temp.ToArray();
}
public MotionKey[] GetPressedKeys(out ulong InputData)
{
//UMAME.instance.mReplayWriter.NextFramebyFrameIdx((int)UMAME.instance.mUniVideoPlayer.mFrame, CurryInpuAllData);
UMAME.instance.mReplayWriter.NextFramebyFrameIdx((int)UMAME.instance.mUniVideoPlayer.mFrame, CurryInpuAllData);
InputData = CurryInpuAllData;
return mCurrKey;
}
}
public class ReplayMode
{
public MotionKey[] mCurrKey = new MotionKey[0];
MotionKey[] ReplayCheckKey;
public ReplayMode()
{
ReplayCheckKey = dictKeyCfgs.Values.ToArray();
}
public MotionKey[] GetPressedKeys(out ulong InputData)
{
List<MotionKey> temp = new List<MotionKey>();
//Óб仯
//if (UMAME.instance.mReplayReader.NextFrame(out AxiReplay.ReplayStep stepData))
int targetFrame = (int)UMAME.instance.mUniVideoPlayer.mFrame;
//if (UMAME.instance.mReplayReader.NextFramebyFrameIdx(targetFrame, out AxiReplay.ReplayStep stepData))
//{
// temp.Clear();
// //ÓÐÊý¾Ý
// for (int i = 0; i < ReplayCheckKey.Length; i++)
// {
// if ((stepData.InPut & (ulong)ReplayCheckKey[i]) > 0)
// temp.Add(ReplayCheckKey[i]);
// }
// mCurrKey = temp.ToArray();
//}
UMAME.instance.mReplayReader.NextFramebyFrameIdx(targetFrame, out AxiReplay.ReplayStep stepData);
temp.Clear();
//ÓÐÊý¾Ý
for (int i = 0; i < ReplayCheckKey.Length; i++)
{
if ((stepData.InPut & (ulong)ReplayCheckKey[i]) > 0)
temp.Add(ReplayCheckKey[i]);
}
mCurrKey = temp.ToArray();
InputData = stepData.InPut;
return mCurrKey;
}
}
#endregion
}