AxibugEmuOnline/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs

204 lines
5.3 KiB
C#
Raw Normal View History

using AxibugEmuOnline.Client.ClientCore;
2024-11-13 18:42:30 +08:00
using AxibugEmuOnline.Client.Common;
2024-07-30 11:57:09 +08:00
using System;
2024-09-23 18:15:34 +08:00
using System.Diagnostics;
using System.IO;
using System.Xml.Linq;
2024-07-24 14:27:10 +08:00
using UnityEngine;
using VirtualNes.Core;
using VirtualNes.Core.Debug;
namespace AxibugEmuOnline.Client
{
2024-09-23 18:15:34 +08:00
public class NesEmulator : MonoBehaviour, IEmuCore
2024-09-14 17:22:01 +08:00
{
2024-11-19 13:52:37 +08:00
//ģ<><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2024-08-06 16:03:17 +08:00
public NES NesCore { get; private set; }
2024-07-25 11:03:58 +08:00
2024-11-19 13:52:37 +08:00
//<2F><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Unity<74><79><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵIJ<DDB5><C4B2><EFBFBD>Ⱦ<EFBFBD><C8BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>֣<EFBFBD>
2024-07-30 11:57:09 +08:00
public VideoProvider VideoProvider;
2024-11-19 13:52:37 +08:00
//<2F><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Unity<74><79><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD>ݵIJ<DDB5><C4B2><EFBFBD><EFBFBD>ų<EFBFBD><C5B3><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>֣<EFBFBD>
2024-08-02 16:50:16 +08:00
public AudioProvider AudioProvider;
2024-11-19 13:52:37 +08:00
//<2F>Ƿ<EFBFBD><C7B7><EFBFBD>ͣ
2024-09-14 17:22:01 +08:00
public bool m_bPause;
2024-07-30 11:57:09 +08:00
2024-07-24 14:27:10 +08:00
private void Start()
{
Application.targetFrameRate = 60;
2024-08-06 16:03:17 +08:00
VideoProvider.NesEmu = this;
AudioProvider.NesEmu = this;
2024-07-24 14:27:10 +08:00
}
2024-11-19 13:52:37 +08:00
/// <summary>
/// ָ<><D6B8>ROM<4F><4D>ʼ<EFBFBD><CABC>Ϸ
/// </summary>
/// <param name="rom"></param>
2024-08-14 13:09:22 +08:00
public void StartGame(RomFile rom)
2024-07-24 14:27:10 +08:00
{
2024-07-25 11:03:58 +08:00
StopGame();
2024-07-24 14:27:10 +08:00
Supporter.Setup(new CoreSupporter());
Debuger.Setup(new CoreDebuger());
2024-07-30 11:57:09 +08:00
2024-11-08 13:48:53 +08:00
App.nesRomLib.AddRomFile(rom);
2024-07-30 11:57:09 +08:00
try
{
2024-08-14 13:09:22 +08:00
NesCore = new NES(rom.FileName);
2024-07-30 11:57:09 +08:00
}
catch (Exception ex)
{
2024-08-06 16:03:17 +08:00
NesCore = null;
2024-09-23 18:15:34 +08:00
App.log.Error(ex.ToString());
2024-07-30 11:57:09 +08:00
}
2024-07-25 11:03:58 +08:00
}
2024-11-19 13:52:37 +08:00
/// <summary>
/// ֹͣ<CDA3><D6B9>Ϸ
/// </summary>
2024-07-25 11:03:58 +08:00
public void StopGame()
{
2024-08-06 16:03:17 +08:00
NesCore?.Dispose();
NesCore = null;
2024-07-25 11:03:58 +08:00
}
2024-11-19 13:52:37 +08:00
/// <summary>
/// Unity<74><79><EFBFBD><EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD>
/// </summary>
2024-11-14 11:17:17 +08:00
private unsafe void Update()
2024-07-25 11:03:58 +08:00
{
2024-09-14 17:22:01 +08:00
if (m_bPause) return;
2024-08-06 16:03:17 +08:00
if (NesCore != null)
2024-07-30 11:57:09 +08:00
{
2024-11-11 20:09:54 +08:00
PushEmulatorFrame();
if (InGameUI.Instance.IsNetPlay)
FixEmulatorFrame();
2024-07-30 18:53:36 +08:00
2024-08-06 16:03:17 +08:00
var screenBuffer = NesCore.ppu.GetScreenPtr();
VideoProvider.SetDrawData(screenBuffer);
2024-07-30 11:57:09 +08:00
}
2024-07-24 14:27:10 +08:00
}
2024-11-19 13:52:37 +08:00
//<2F>Ƿ<EFBFBD><C7B7><EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч
2024-11-11 20:09:54 +08:00
private void FixEmulatorFrame()
{
2024-11-12 14:55:45 +08:00
var skipFrameCount = App.roomMgr.netReplay.GetSkipFrameCount();
2024-11-11 20:09:54 +08:00
if (skipFrameCount > 0) App.log.Debug($"SKIP FRAME : {skipFrameCount}");
for (int i = 0; i < skipFrameCount; i++)
{
if (!PushEmulatorFrame()) break;
}
}
2024-11-12 09:58:30 +08:00
ControllerState lastState;
2024-11-19 13:54:23 +08:00
//<2F>ƽ<EFBFBD>֡
2024-11-11 20:09:54 +08:00
private bool PushEmulatorFrame()
{
2024-11-12 09:58:30 +08:00
Supporter.SampleInput(NesCore.FrameCount);
2024-11-11 20:09:54 +08:00
var controlState = Supporter.GetControllerState();
//<2F><><EFBFBD><EFBFBD>δ<EFBFBD>յ<EFBFBD>Input<75><74><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD>֡<EFBFBD><D6A1><EFBFBD>ƽ<EFBFBD>
if (!controlState.valid) return false;
2024-11-12 12:49:58 +08:00
#if UNITY_EDITOR
2024-11-12 09:58:30 +08:00
if (controlState != lastState)
{
App.log.Info($"[LOCALDEBUG]{NesCore.FrameCount}-->{controlState}");
}
2024-11-12 12:49:58 +08:00
#endif
2024-11-12 09:58:30 +08:00
2024-11-11 20:09:54 +08:00
NesCore.pad.Sync(controlState);
NesCore.EmulateFrame(true);
2024-11-12 09:58:30 +08:00
lastState = controlState;
2024-11-11 20:09:54 +08:00
return true;
}
2024-09-14 17:22:01 +08:00
public void Pause()
{
m_bPause = true;
}
public void Resume()
{
m_bPause = false;
}
2024-09-23 18:15:34 +08:00
2024-11-13 18:42:30 +08:00
public void DoReset()
{
2024-11-13 18:42:30 +08:00
NesCore.Reset();
}
2024-09-23 18:15:34 +08:00
public void SetupScheme()
{
ControlScheme.Current = ControlSchemeSetts.NES;
}
public void LoadState(object state)
{
NesCore.LoadState((State)state);
}
public object GetState()
{
return NesCore.GetState();
}
2024-11-19 13:52:37 +08:00
/// <summary>
/// <20><>ȡ<EFBFBD><C8A1>ʱ<EFBFBD>
/// </summary>
/// <returns></returns>
2024-09-23 18:15:34 +08:00
public byte[] GetStateBytes()
{
return NesCore.GetState().ToBytes();
}
2024-11-19 13:52:37 +08:00
/// <summary>
/// <20><><EFBFBD>ؼ<EFBFBD>ʱ<EFBFBD>
/// </summary>
/// <param name="data"></param>
2024-09-23 18:15:34 +08:00
public void LoadStateFromBytes(byte[] data)
{
State st = new State();
st.FromByte(data);
NesCore.LoadState(st);
}
2024-11-13 18:42:30 +08:00
2024-11-21 17:18:15 +08:00
#if UNITY_EDITOR
2024-11-19 13:52:37 +08:00
/// <summary>
/// <20><EFBFBD><E0BCAD><EFBFBD><EFBFBD>
/// </summary>
2024-11-13 18:42:30 +08:00
[Conditional("UNITY_EDITOR")]
[ContextMenu("ImportNesDB")]
public void ImportNesDB()
{
var db = Resources.Load<RomDB>("NES/ROMDB");
db.Clear();
var xmlStr = File.ReadAllText("nes20db.xml");
var xml = XDocument.Parse(xmlStr);
var games = xml.Element("nes20db").Elements("game");
foreach (var game in games)
{
var crcStr = game.Element("rom").Attribute("crc32").Value;
var crc = uint.Parse($"{crcStr}", System.Globalization.NumberStyles.HexNumber);
var mapper = int.Parse($"{game.Element("pcb").Attribute("mapper").Value}");
if (mapper > 255) continue;
db.AddInfo(new RomDB.RomInfo { CRC = crc, Mapper = mapper });
}
UnityEditor.EditorUtility.SetDirty(db);
UnityEditor.AssetDatabase.SaveAssets();
}
2024-11-21 17:18:15 +08:00
#endif
2024-11-19 13:09:53 +08:00
public uint Frame => NesCore.FrameCount;
2024-07-24 14:27:10 +08:00
}
}