重构代码,解耦上层逻辑强依赖virtualnes核心逻辑

This commit is contained in:
ALIENJACK\alien 2024-12-25 20:48:26 +08:00
parent 13cadd90a0
commit c0af4d4009
21 changed files with 165 additions and 189 deletions

View File

@ -1,4 +1,4 @@
using UnityEngine; using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
@ -14,7 +14,9 @@ namespace AxibugEmuOnline.Client
void Resume(); void Resume();
void SetupScheme(); void SetupScheme();
void StartGame(RomFile romFile); void StartGame(RomFile romFile);
void DoReset(); void DoReset();
IControllerSetuper GetControllerSetuper();
EnumPlatform Platform { get; } EnumPlatform Platform { get; }
uint Frame { get; } uint Frame { get; }
} }

View File

@ -13,7 +13,7 @@ namespace AxibugEmuOnline.Client.Manager
/// </summary> /// </summary>
private IEmuCore m_emuCore; private IEmuCore m_emuCore;
private VirtualNes.Core.IControllerSetuper m_controllerSetuper; private IControllerSetuper m_controllerSetuper;
/// <summary> /// <summary>
/// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符 /// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符
@ -63,7 +63,7 @@ namespace AxibugEmuOnline.Client.Manager
m_emuCore.SetupScheme(); m_emuCore.SetupScheme();
m_controllerSetuper = Supporter.GetControllerSetuper(); m_controllerSetuper = m_emuCore.GetControllerSetuper();
//自动分配0号手柄到0号手柄位 //自动分配0号手柄到0号手柄位
m_controllerSetuper.SetConnect(con0ToSlot: 0); m_controllerSetuper.SetConnect(con0ToSlot: 0);

View File

@ -0,0 +1,39 @@
/// <summary>
/// 负责管理本地控制器与具体游戏之间的槽位分配
/// </summary>
public interface IControllerSetuper
{
/// <summary>
/// 设置本地手柄与游戏手柄槽位的映射,这个方法是一个全量更新手柄插入设置的方法
/// </summary>
void SetConnect(
uint? con0ToSlot = null,
uint? con1ToSlot = null,
uint? con2ToSlot = null,
uint? con3ToSlot = null);
/// <summary>
/// 指定手柄插槽位,获取当前槽位连接的本地手柄序号
/// </summary>
/// <param name="slotIndex"></param>
/// <returns></returns>
int? GetSlotConnectingControllerIndex(int slotIndex);
IController GetSlotConnectingController(int slotIndex);
/// <summary>
/// 获得一个空的槽位
/// </summary>
/// <returns></returns>
uint? GetFreeSlotIndex();
/// <summary>
/// 增量式的修改一个手柄和一个槽位的连接关系
/// </summary>
/// <param name="conIndex"></param>
/// <param name="slotIndex"></param>
void LetControllerConnect(int conIndex, uint slotIndex);
}
public interface IController
{
bool AnyButtonDown();
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f567cb126b157854e9f9b2c71f8cda8e

View File

@ -1,4 +1,4 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxiReplay; using AxiReplay;
using System; using System;
using System.IO; using System.IO;
@ -10,6 +10,12 @@ namespace AxibugEmuOnline.Client
{ {
public class CoreSupporter : ISupporterImpl public class CoreSupporter : ISupporterImpl
{ {
private NesControllerMapper m_controllerMapper;
public CoreSupporter(NesControllerMapper conMapper)
{
m_controllerMapper = conMapper;
}
public Stream OpenRom(string fname) public Stream OpenRom(string fname)
{ {
try try
@ -57,7 +63,6 @@ namespace AxibugEmuOnline.Client
} }
public EmulatorConfig Config { get; private set; } = new EmulatorConfig(); public EmulatorConfig Config { get; private set; } = new EmulatorConfig();
public NesControllerMapper ControllerMapper { get; private set; } = new NesControllerMapper();
public void PrepareDirectory(string directPath) public void PrepareDirectory(string directPath)
{ {
Directory.CreateDirectory($"{App.PersistentDataPath}/{directPath}"); Directory.CreateDirectory($"{App.PersistentDataPath}/{directPath}");
@ -116,7 +121,7 @@ namespace AxibugEmuOnline.Client
} }
else m_sampledState = default(ControllerState); else m_sampledState = default(ControllerState);
var localState = ControllerMapper.CreateState(); var localState = m_controllerMapper.CreateState();
var rawData = ToNet(localState); var rawData = ToNet(localState);
if (LastTestInput != rawData) if (LastTestInput != rawData)
{ {
@ -127,15 +132,10 @@ namespace AxibugEmuOnline.Client
} }
else else
{ {
m_sampledState = ControllerMapper.CreateState(); m_sampledState = m_controllerMapper.CreateState();
} }
} }
public IControllerSetuper GetControllerSetuper()
{
return ControllerMapper;
}
public ControllerState FromNet(AxiReplay.ReplayStep step) public ControllerState FromNet(AxiReplay.ReplayStep step)
{ {
var temp = new ServerInputSnapShot(); var temp = new ServerInputSnapShot();

View File

@ -46,7 +46,7 @@ namespace AxibugEmuOnline.Client
Controller3.ConnectSlot = con3ToSlot; Controller3.ConnectSlot = con3ToSlot;
} }
public int? GetSlotConnectingController(int slotIndex) public int? GetSlotConnectingControllerIndex(int slotIndex)
{ {
if (Controller0.ConnectSlot.HasValue && Controller0.ConnectSlot.Value == slotIndex) return 0; if (Controller0.ConnectSlot.HasValue && Controller0.ConnectSlot.Value == slotIndex) return 0;
else if (Controller1.ConnectSlot.HasValue && Controller1.ConnectSlot.Value == slotIndex) return 1; else if (Controller1.ConnectSlot.HasValue && Controller1.ConnectSlot.Value == slotIndex) return 1;
@ -55,6 +55,15 @@ namespace AxibugEmuOnline.Client
else return null; else return null;
} }
public IController GetSlotConnectingController(int slotIndex)
{
if (Controller0.ConnectSlot.HasValue && Controller0.ConnectSlot.Value == slotIndex) return Controller0;
else if (Controller1.ConnectSlot.HasValue && Controller1.ConnectSlot.Value == slotIndex) return Controller1;
else if (Controller2.ConnectSlot.HasValue && Controller2.ConnectSlot.Value == slotIndex) return Controller2;
else if (Controller3.ConnectSlot.HasValue && Controller3.ConnectSlot.Value == slotIndex) return Controller3;
else return null;
}
static HashSet<uint> s_temp = new HashSet<uint>(4); static HashSet<uint> s_temp = new HashSet<uint>(4);
public uint? GetFreeSlotIndex() public uint? GetFreeSlotIndex()
{ {
@ -94,7 +103,7 @@ namespace AxibugEmuOnline.Client
/// <summary> /// <summary>
/// Nes控制器 /// Nes控制器
/// </summary> /// </summary>
public class Controller public class Controller : IController
{ {
/// <summary> /// <summary>
/// 控制器编号 /// 控制器编号

View File

@ -21,7 +21,13 @@ namespace AxibugEmuOnline.Client
public NES NesCore { get; private set; } public NES NesCore { get; private set; }
/// <summary> 是否暂停 </summary> /// <summary> 是否暂停 </summary>
public bool IsPause { get; private set; } public bool IsPause { get; private set; }
public NesControllerMapper ControllerMapper { get; private set; }
private void Awake()
{
ControllerMapper = new NesControllerMapper();
}
private void Start() private void Start()
{ {
@ -48,12 +54,11 @@ namespace AxibugEmuOnline.Client
VideoProvider.SetDrawData(screenBuffer); VideoProvider.SetDrawData(screenBuffer);
} }
VideoProvider.ApplyFilterEffect(); VideoProvider.ApplyFilterEffect();
} }
public EnumPlatform Platform => EnumPlatform.NES; public EnumPlatform Platform => EnumPlatform.NES;
private CoreSupporter m_coreSupporter;
/// <summary> /// <summary>
/// 指定ROM开始游戏 /// 指定ROM开始游戏
/// </summary> /// </summary>
@ -61,7 +66,8 @@ namespace AxibugEmuOnline.Client
{ {
StopGame(); StopGame();
Supporter.Setup(new CoreSupporter()); m_coreSupporter = new CoreSupporter(ControllerMapper);
Supporter.Setup(m_coreSupporter);
Debuger.Setup(new CoreDebuger()); Debuger.Setup(new CoreDebuger());
App.nesRomLib.AddRomFile(rom); App.nesRomLib.AddRomFile(rom);
@ -159,8 +165,8 @@ namespace AxibugEmuOnline.Client
//推进帧 //推进帧
private bool PushEmulatorFrame() private bool PushEmulatorFrame()
{ {
Supporter.SampleInput(NesCore.FrameCount); m_coreSupporter.SampleInput(NesCore.FrameCount);
var controlState = Supporter.GetControllerState(); var controlState = m_coreSupporter.GetControllerState();
//如果未收到Input数据,核心帧不推进 //如果未收到Input数据,核心帧不推进
if (!controlState.valid) return false; if (!controlState.valid) return false;
@ -205,8 +211,13 @@ namespace AxibugEmuOnline.Client
EditorUtility.SetDirty(db); EditorUtility.SetDirty(db);
AssetDatabase.SaveAssets(); AssetDatabase.SaveAssets();
} }
public IControllerSetuper GetControllerSetuper()
{
return ControllerMapper;
}
#endif #endif
} }
} }

View File

@ -27,7 +27,7 @@ namespace AxibugEmuOnline.Client
} }
// スキャンラインカラー // スキャンラインカラー
private static int m_nScanlineColor => Supporter.Config.graphics.nScanlineColor; private static int m_nScanlineColor => 75; //patternViewer调试器用的,参照EmulatorConfig.graphics.nScanlineColor的值
public static float[][] PalConvTbl = new float[8][] public static float[][] PalConvTbl = new float[8][]
{ {

View File

@ -117,10 +117,10 @@ namespace AxibugEmuOnline.Client
m_delayCreateRoom = false; m_delayCreateRoom = false;
//延迟创建房间成功后,同步本地手柄连接状态 //延迟创建房间成功后,同步本地手柄连接状态
Dictionary<uint, uint> temp = new Dictionary<uint, uint>(); Dictionary<uint, uint> temp = new Dictionary<uint, uint>();
var setuper = Supporter.GetControllerSetuper(); var setuper = App.emu.Core.GetControllerSetuper();
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
var joyIndex = setuper.GetSlotConnectingController(i); var joyIndex = setuper.GetSlotConnectingControllerIndex(i);
if (joyIndex != null) temp[(uint)i] = (uint)joyIndex.Value; if (joyIndex != null) temp[(uint)i] = (uint)joyIndex.Value;
} }
App.roomMgr.SendChangePlaySlotIdxWithJoyIdx(temp); App.roomMgr.SendChangePlaySlotIdxWithJoyIdx(temp);

View File

@ -1,6 +1,7 @@
using AxibugEmuOnline.Client; using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using DG.Tweening;
using System; using System;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
@ -18,9 +19,7 @@ public class ControllerInfo : MonoBehaviour
Image m_indexIcon; Image m_indexIcon;
[SerializeField] [SerializeField]
Text m_playerName; Text m_playerName;
private bool m_islocal;
int m_localJoyIndex;
bool m_isLocal;
public int SlotIndex public int SlotIndex
{ {
@ -60,6 +59,18 @@ public class ControllerInfo : MonoBehaviour
Eventer.Instance.UnregisterEvent(EEvent.OnControllerConnectChanged, OnControlConnectChanged); Eventer.Instance.UnregisterEvent(EEvent.OnControllerConnectChanged, OnControlConnectChanged);
} }
private void Update()
{
if (m_islocal)
{
var controller = App.emu.Core.GetControllerSetuper().GetSlotConnectingController(m_slotIndex);
if (controller == null) return;
if (!controller.AnyButtonDown()) return;
m_indexIcon.rectTransform.DOShakePosition(0.1f);
}
}
private void OnMineRoomCreated() => UpdateConnectInfo(); private void OnMineRoomCreated() => UpdateConnectInfo();
private void OnJoinRoom() => UpdateConnectInfo(); private void OnJoinRoom() => UpdateConnectInfo();
private void OnLeaveRoom() => UpdateConnectInfo(); private void OnLeaveRoom() => UpdateConnectInfo();
@ -79,14 +90,15 @@ public class ControllerInfo : MonoBehaviour
} }
else else
{ {
var connecter = Supporter.GetControllerSetuper(); if (App.emu.Core.IsNull())
if (connecter == null)
{ {
SetDisconnect(); SetDisconnect();
return; return;
}
var localControlIndex = connecter.GetSlotConnectingController(SlotIndex); }
var connecter = App.emu.Core.GetControllerSetuper();
var localControlIndex = connecter.GetSlotConnectingControllerIndex(SlotIndex);
if (localControlIndex == null) if (localControlIndex == null)
SetDisconnect(); SetDisconnect();
else else
@ -101,8 +113,7 @@ public class ControllerInfo : MonoBehaviour
private void UpdateStateView(bool isLocal, string playerName, int slotIndex) private void UpdateStateView(bool isLocal, string playerName, int slotIndex)
{ {
m_localJoyIndex = slotIndex; m_islocal = isLocal;
m_isLocal = isLocal;
m_connectInfoNode.SetActiveEx(true); m_connectInfoNode.SetActiveEx(true);
m_playerName.text = playerName; m_playerName.text = playerName;
@ -110,11 +121,9 @@ public class ControllerInfo : MonoBehaviour
private void SetDisconnect() private void SetDisconnect()
{ {
m_localJoyIndex = -1;
m_isLocal = false;
m_connectInfoNode.SetActiveEx(false); m_connectInfoNode.SetActiveEx(false);
m_playerName.text = null; m_playerName.text = null;
m_islocal = false;
} }
private void UpdateIndexIcon() private void UpdateIndexIcon()

View File

@ -1,4 +1,5 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.Manager; using AxibugEmuOnline.Client.Manager;
using System; using System;
@ -31,7 +32,8 @@ public class ControllerInfoPanel : MonoBehaviour
} }
else //不在房间中,直接设置 else //不在房间中,直接设置
{ {
var setuper = Supporter.GetControllerSetuper(); if (App.emu.Core.IsNull()) return;
var setuper = App.emu.Core.GetControllerSetuper();
if (setuper == null) return; if (setuper == null) return;
var freeSlotIndex = setuper.GetFreeSlotIndex(); var freeSlotIndex = setuper.GetFreeSlotIndex();

View File

@ -73,7 +73,7 @@ namespace VirtualNes.Core
public void Process(ISoundDataBuffer lpBuffer, uint dwSize) public void Process(ISoundDataBuffer lpBuffer, uint dwSize)
{ {
int nBits = Supporter.Config.sound.nBits; int nBits = Supporter.S.Config.sound.nBits;
uint dwLength = (uint)(dwSize / (nBits / 8)); uint dwLength = (uint)(dwSize / (nBits / 8));
int output; int output;
QUEUEDATA q = new QUEUEDATA(); QUEUEDATA q = new QUEUEDATA();
@ -82,11 +82,11 @@ namespace VirtualNes.Core
var pSoundBuf = m_SoundBuffer; var pSoundBuf = m_SoundBuffer;
int nCcount = 0; int nCcount = 0;
int nFilterType = Supporter.Config.sound.nFilterType; int nFilterType = Supporter.S.Config.sound.nFilterType;
if (!Supporter.Config.sound.bEnable) if (!Supporter.S.Config.sound.bEnable)
{ {
byte empty = (byte)(Supporter.Config.sound.nRate == 8 ? 128 : 0); byte empty = (byte)(Supporter.S.Config.sound.nRate == 8 ? 128 : 0);
for (int i = 0; i < dwSize; i++) for (int i = 0; i < dwSize; i++)
lpBuffer.WriteByte(empty); lpBuffer.WriteByte(empty);
return; return;
@ -108,7 +108,7 @@ namespace VirtualNes.Core
MemoryUtility.ZEROMEMORY(vol, vol.Length); MemoryUtility.ZEROMEMORY(vol, vol.Length);
var bMute = m_bMute; var bMute = m_bMute;
var nVolume = Supporter.Config.sound.nVolume; var nVolume = Supporter.S.Config.sound.nVolume;
int nMasterVolume = bMute[0] ? nVolume[0] : 0; int nMasterVolume = bMute[0] ? nVolume[0] : 0;
@ -151,7 +151,7 @@ namespace VirtualNes.Core
vol[23] = (int)(bMute[8] ? (FME7_VOL * nVolume[11] * nMasterVolume) / (100 * 100) : 0); vol[23] = (int)(bMute[8] ? (FME7_VOL * nVolume[11] * nMasterVolume) / (100 * 100) : 0);
// double cycle_rate = ((double)FRAME_CYCLES*60.0/12.0)/(double)Config.sound.nRate; // double cycle_rate = ((double)FRAME_CYCLES*60.0/12.0)/(double)Config.sound.nRate;
double cycle_rate = (nes.nescfg.FrameCycles * 60.0 / 12.0) / Supporter.Config.sound.nRate; double cycle_rate = (nes.nescfg.FrameCycles * 60.0 / 12.0) / Supporter.S.Config.sound.nRate;
// CPUサイクル数がループしてしまった時の対策処理 // CPUサイクル数がループしてしまった時の対策処理
if (elapsed_time > nes.cpu.GetTotalCycles()) if (elapsed_time > nes.cpu.GetTotalCycles())
@ -253,7 +253,7 @@ namespace VirtualNes.Core
// DC成分のカット(HPF TEST) // DC成分のカット(HPF TEST)
{ {
// static double cutoff = (2.0*3.141592653579*40.0/44100.0); // static double cutoff = (2.0*3.141592653579*40.0/44100.0);
double cutoff = cutofftemp / Supporter.Config.sound.nRate; double cutoff = cutofftemp / Supporter.S.Config.sound.nRate;
double @in, @out; double @in, @out;
@in = output; @in = output;
@ -436,7 +436,7 @@ namespace VirtualNes.Core
public void SoundSetup() public void SoundSetup()
{ {
float fClock = nes.nescfg.CpuClock; float fClock = nes.nescfg.CpuClock;
int nRate = Supporter.Config.sound.nRate; int nRate = Supporter.S.Config.sound.nRate;
@internal.Setup(fClock, nRate); @internal.Setup(fClock, nRate);
vrc6.Setup(fClock, nRate); vrc6.Setup(fClock, nRate);
@ -460,7 +460,7 @@ namespace VirtualNes.Core
elapsed_time = 0; elapsed_time = 0;
float fClock = nes.nescfg.CpuClock; float fClock = nes.nescfg.CpuClock;
int nRate = Supporter.Config.sound.nRate; int nRate = Supporter.S.Config.sound.nRate;
@internal.Reset(fClock, nRate); @internal.Reset(fClock, nRate);
vrc6.Reset(fClock, nRate); vrc6.Reset(fClock, nRate);

View File

@ -1,4 +1,4 @@

using System; using System;
namespace VirtualNes.Core namespace VirtualNes.Core
@ -184,15 +184,15 @@ namespace VirtualNes.Core
Setup(fClock, nRate); Setup(fClock, nRate);
// $4011反場ヽ趙仄卅中 // $4011は初期化しない
ushort addr; ushort addr;
for (addr = 0x4000; addr <= 0x4010; addr++) for (addr = 0x4000; addr <= 0x4010; addr++)
{ {
Write(addr, 0x00); Write(addr, 0x00);
SyncWrite(addr, 0x00); SyncWrite(addr, 0x00);
} }
// Write( 0x4001, 0x08 ); // Reset媆反inc乒奈玉卞卅月? // Write( 0x4001, 0x08 ); // Reset時はincモードになる?
// Write( 0x4005, 0x08 ); // Reset媆反inc乒奈玉卞卅月? // Write( 0x4005, 0x08 ); // Reset時はincモードになる?
Write(0x4012, 0x00); Write(0x4012, 0x00);
Write(0x4013, 0x00); Write(0x4013, 0x00);
Write(0x4015, 0x00); Write(0x4015, 0x00);
@ -200,7 +200,7 @@ namespace VirtualNes.Core
SyncWrite(0x4013, 0x00); SyncWrite(0x4013, 0x00);
SyncWrite(0x4015, 0x00); SyncWrite(0x4015, 0x00);
// $4017反𤩸五煋心匹場ヽ趙仄卅中(場ヽ乒奈玉互0匹丐月及毛ヽ渾仄凶末白玄互丐月鮋) // $4017は書き込みで初期化しない(初期モードが0であるのを期待したソフトがある為)
FrameIRQ = 0xC0; FrameIRQ = 0xC0;
FrameCycle = 0; FrameCycle = 0;
FrameIRQoccur = 0; FrameIRQoccur = 0;
@ -301,7 +301,7 @@ namespace VirtualNes.Core
case 0x4017: case 0x4017:
break; break;
// VirtuaNES嘐衄禾奈玄 // VirtuaNES固有ポート
case 0x4018: case 0x4018:
UpdateRectangle(ch0, data); UpdateRectangle(ch0, data);
UpdateRectangle(ch1, data); UpdateRectangle(ch1, data);
@ -635,7 +635,7 @@ namespace VirtualNes.Core
} }
} }
// 奶件民平堪中皿民用奶朮市永玄(TEST) // インチキ臭いプチノイズカット(TEST)
ch4.dpcm_output_real = ((ch4.reg[1] & 0x01) + ch4.dpcm_value * 2) - 0x40; ch4.dpcm_output_real = ((ch4.reg[1] & 0x01) + ch4.dpcm_value * 2) - 0x40;
if (Math.Abs(ch4.dpcm_output_real - ch4.dpcm_output_fake) <= 8) if (Math.Abs(ch4.dpcm_output_real - ch4.dpcm_output_fake) <= 8)
{ {
@ -712,7 +712,7 @@ namespace VirtualNes.Core
private int RenderTriangle() private int RenderTriangle()
{ {
int vol; int vol;
if (Supporter.Config.sound.bDisableVolumeEffect) if (Supporter.S.Config.sound.bDisableVolumeEffect)
{ {
vol = 256; vol = 256;
} }
@ -731,7 +731,7 @@ namespace VirtualNes.Core
return ch2.nowvolume * vol / 256; return ch2.nowvolume * vol / 256;
} }
if (!(Supporter.Config.sound.bChangeTone && ChannelTone[2, 0] != 0)) if (!(Supporter.S.Config.sound.bChangeTone && ChannelTone[2, 0] != 0))
{ {
ch2.phaseacc -= cycle_rate; ch2.phaseacc -= cycle_rate;
if (ch2.phaseacc >= 0) if (ch2.phaseacc >= 0)
@ -756,7 +756,7 @@ namespace VirtualNes.Core
return ch2.nowvolume * vol / 256; return ch2.nowvolume * vol / 256;
} }
// 樓笭ⅸ歙 // 加重平均
int num_times, total; int num_times, total;
num_times = total = 0; num_times = total = 0;
while (ch2.phaseacc < 0) while (ch2.phaseacc < 0)
@ -799,7 +799,7 @@ namespace VirtualNes.Core
return ch2.nowvolume * vol / 256; return ch2.nowvolume * vol / 256;
} }
// 樓笭ⅸ歙 // 加重平均
int num_times, total; int num_times, total;
num_times = total = 0; num_times = total = 0;
while (ch2.phaseacc < 0) while (ch2.phaseacc < 0)
@ -832,9 +832,9 @@ namespace VirtualNes.Core
} }
int volume = ch.nowvolume; int volume = ch.nowvolume;
if (!(Supporter.Config.sound.bChangeTone && (ChannelTone[(ch.complement == 0) ? 0 : 1, ch.reg[0] >> 6]) != 0)) if (!(Supporter.S.Config.sound.bChangeTone && (ChannelTone[(ch.complement == 0) ? 0 : 1, ch.reg[0] >> 6]) != 0))
{ {
// 娗嶲<EFBFBD> // 補間処理
double total; double total;
double sample_weight = ch.phaseacc; double sample_weight = ch.phaseacc;
if (sample_weight > cycle_rate) if (sample_weight > cycle_rate)
@ -864,7 +864,7 @@ namespace VirtualNes.Core
int x = ChannelTone[(ch.complement == 0) ? 0 : 1, ch.reg[0] >> 6] - 1; int x = ChannelTone[(ch.complement == 0) ? 0 : 1, ch.reg[0] >> 6] - 1;
int pTone = 0; int pTone = 0;
// 載陔剠仄 // 更新無し
ch.phaseacc -= cycle_rate * 2; ch.phaseacc -= cycle_rate * 2;
if (ch.phaseacc >= 0) if (ch.phaseacc >= 0)
{ {
@ -872,7 +872,7 @@ namespace VirtualNes.Core
return temp * volume / ((1 << RECTANGLE_VOL_SHIFT) / 2); return temp * volume / ((1 << RECTANGLE_VOL_SHIFT) / 2);
} }
// 1旦氾永皿分仃載陔 // 1ステップだけ更新
int freq = INT2FIX(ch.freq + 1); int freq = INT2FIX(ch.freq + 1);
if (freq > cycle_rate * 2) if (freq > cycle_rate * 2)
{ {
@ -882,7 +882,7 @@ namespace VirtualNes.Core
return temp * volume / ((1 << RECTANGLE_VOL_SHIFT) / 2); return temp * volume / ((1 << RECTANGLE_VOL_SHIFT) / 2);
} }
// 樓笭ⅸ歙 // 加重平均
int num_times, total; int num_times, total;
num_times = total = 0; num_times = total = 0;
while (ch.phaseacc < 0) while (ch.phaseacc < 0)
@ -1015,7 +1015,7 @@ namespace VirtualNes.Core
SyncWrite4017(data); SyncWrite4017(data);
break; break;
// VirtuaNES娚葲<EFBFBD><EFBFBD><EFBFBD> // VirtuaNES屌桳億乕僩
case 0x4018: case 0x4018:
SyncUpdateRectangle(ch0, data); SyncUpdateRectangle(ch0, data);
SyncUpdateRectangle(ch1, data); SyncUpdateRectangle(ch1, data);

View File

@ -1110,7 +1110,7 @@ namespace VirtualNes.Core
case 0xD2: /* JAM */ case 0xD2: /* JAM */
case 0xF2: /* JAM */ case 0xF2: /* JAM */
default: default:
if (!Supporter.Config.emulator.bIllegalOp) if (!Supporter.S.Config.emulator.bIllegalOp)
{ {
throw new Exception("IllegalOp"); throw new Exception("IllegalOp");
} }

View File

@ -40,7 +40,7 @@ namespace VirtualNes.Core
Debuger.Log($"SOUND CODE:{addr & 0x1F:X2}"); Debuger.Log($"SOUND CODE:{addr & 0x1F:X2}");
// OSDにするべきか… // OSDにするべきか…
if (Supporter.Config.sound.bExtraSoundEnable) if (Supporter.S.Config.sound.bExtraSoundEnable)
{ {
//TODO : 似乎VirtuaNES有直接播放某个音频文件的功能 //TODO : 似乎VirtuaNES有直接播放某个音频文件的功能
//DirectSound.EsfAllStop(); //DirectSound.EsfAllStop();

View File

@ -43,7 +43,7 @@ namespace VirtualNes.Core
} }
// OSDにするべきか… // OSDにするべきか…
if (Supporter.Config.sound.bExtraSoundEnable) if (Supporter.S.Config.sound.bExtraSoundEnable)
{ {
//TODO : 似乎VirtuaNES有直接播放某个音频文件的功能 //TODO : 似乎VirtuaNES有直接播放某个音频文件的功能
//DirectSound.EsfAllStop(); //DirectSound.EsfAllStop();

View File

@ -57,7 +57,7 @@ namespace VirtualNes.Core
9,10, 8,11,13,12,14,15 }; 9,10, 8,11,13,12,14,15 };
// OSDにするべきか… // OSDにするべきか…
if (Supporter.Config.sound.bExtraSoundEnable) if (Supporter.S.Config.sound.bExtraSoundEnable)
{ {
//TODO : 似乎VirtuaNES有直接播放某个音频文件的功能 //TODO : 似乎VirtuaNES有直接播放某个音频文件的功能
Debuger.Log($"CODE {data:X2}"); Debuger.Log($"CODE {data:X2}");

View File

@ -326,7 +326,7 @@ namespace VirtualNes.Core
if (pad.GetExController() != (int)EXCONTROLLER.EXCONTROLLER_TURBOFILE) if (pad.GetExController() != (int)EXCONTROLLER.EXCONTROLLER_TURBOFILE)
return; return;
var fp = Supporter.OpenFile(Supporter.Config.path.szSavePath, "TurboFile.vtf"); var fp = Supporter.S.OpenFile(Supporter.S.Config.path.szSavePath, "TurboFile.vtf");
try try
{ {
if (fp == null) if (fp == null)
@ -367,10 +367,10 @@ namespace VirtualNes.Core
if (!rom.IsSAVERAM()) if (!rom.IsSAVERAM())
return; return;
var saveFileDir = Supporter.Config.path.szSavePath; var saveFileDir = Supporter.S.Config.path.szSavePath;
var saveFileName = $"{rom.GetRomName()}.sav"; var saveFileName = $"{rom.GetRomName()}.sav";
var fp = Supporter.OpenFile(saveFileDir, saveFileName); var fp = Supporter.S.OpenFile(saveFileDir, saveFileName);
try try
{ {
@ -502,13 +502,13 @@ namespace VirtualNes.Core
EmulationCPU(nescfg.ScanlineCycles); EmulationCPU(nescfg.ScanlineCycles);
if (bDraw) if (bDraw)
{ {
ppu.Scanline(scanline, Supporter.Config.graphics.bAllSprite, Supporter.Config.graphics.bLeftClip); ppu.Scanline(scanline, Supporter.S.Config.graphics.bAllSprite, Supporter.S.Config.graphics.bLeftClip);
} }
else else
{ {
if (pad.IsZapperMode() && scanline == ZapperY) if (pad.IsZapperMode() && scanline == ZapperY)
{ {
ppu.Scanline(scanline, Supporter.Config.graphics.bAllSprite, Supporter.Config.graphics.bLeftClip); ppu.Scanline(scanline, Supporter.S.Config.graphics.bAllSprite, Supporter.S.Config.graphics.bLeftClip);
} }
else else
{ {
@ -518,7 +518,7 @@ namespace VirtualNes.Core
} }
else else
{ {
ppu.Scanline(scanline, Supporter.Config.graphics.bAllSprite, Supporter.Config.graphics.bLeftClip); ppu.Scanline(scanline, Supporter.S.Config.graphics.bAllSprite, Supporter.S.Config.graphics.bLeftClip);
} }
} }
} }
@ -535,13 +535,13 @@ namespace VirtualNes.Core
EmulationCPU(nescfg.HDrawCycles); EmulationCPU(nescfg.HDrawCycles);
if (bDraw) if (bDraw)
{ {
ppu.Scanline(scanline, Supporter.Config.graphics.bAllSprite, Supporter.Config.graphics.bLeftClip); ppu.Scanline(scanline, Supporter.S.Config.graphics.bAllSprite, Supporter.S.Config.graphics.bLeftClip);
} }
else else
{ {
if (pad.IsZapperMode() && scanline == ZapperY) if (pad.IsZapperMode() && scanline == ZapperY)
{ {
ppu.Scanline(scanline, Supporter.Config.graphics.bAllSprite, Supporter.Config.graphics.bLeftClip); ppu.Scanline(scanline, Supporter.S.Config.graphics.bAllSprite, Supporter.S.Config.graphics.bLeftClip);
} }
else else
{ {
@ -551,7 +551,7 @@ namespace VirtualNes.Core
} }
else else
{ {
ppu.Scanline(scanline, Supporter.Config.graphics.bAllSprite, Supporter.Config.graphics.bLeftClip); ppu.Scanline(scanline, Supporter.S.Config.graphics.bAllSprite, Supporter.S.Config.graphics.bLeftClip);
} }
} }
} }
@ -658,7 +658,7 @@ namespace VirtualNes.Core
// 僗僋儕乕儞昤夋(Scanline 1乣239) // 僗僋儕乕儞昤夋(Scanline 1乣239)
if (bDraw) if (bDraw)
{ {
ppu.Scanline(scanline, Supporter.Config.graphics.bAllSprite, Supporter.Config.graphics.bLeftClip); ppu.Scanline(scanline, Supporter.S.Config.graphics.bAllSprite, Supporter.S.Config.graphics.bLeftClip);
ppu.ScanlineNext(); ppu.ScanlineNext();
EmulationCPU(FETCH_CYCLES * 10); EmulationCPU(FETCH_CYCLES * 10);
mapper.HSync(scanline); mapper.HSync(scanline);
@ -670,7 +670,7 @@ namespace VirtualNes.Core
{ {
if (pad.IsZapperMode() && scanline == ZapperY) if (pad.IsZapperMode() && scanline == ZapperY)
{ {
ppu.Scanline(scanline, Supporter.Config.graphics.bAllSprite, Supporter.Config.graphics.bLeftClip); ppu.Scanline(scanline, Supporter.S.Config.graphics.bAllSprite, Supporter.S.Config.graphics.bLeftClip);
ppu.ScanlineNext(); ppu.ScanlineNext();
EmulationCPU(FETCH_CYCLES * 10); EmulationCPU(FETCH_CYCLES * 10);
mapper.HSync(scanline); mapper.HSync(scanline);
@ -694,7 +694,7 @@ namespace VirtualNes.Core
} }
else else
{ {
ppu.Scanline(scanline, Supporter.Config.graphics.bAllSprite, Supporter.Config.graphics.bLeftClip); ppu.Scanline(scanline, Supporter.S.Config.graphics.bAllSprite, Supporter.S.Config.graphics.bLeftClip);
ppu.ScanlineNext(); ppu.ScanlineNext();
EmulationCPU(FETCH_CYCLES * 10); EmulationCPU(FETCH_CYCLES * 10);
mapper.HSync(scanline); mapper.HSync(scanline);
@ -1095,7 +1095,7 @@ namespace VirtualNes.Core
Debuger.Log($"Saving SAVERAM...[{romName}]"); Debuger.Log($"Saving SAVERAM...[{romName}]");
Supporter.SaveSRAMToFile(MMU.WRAM, romName); Supporter.S.SaveSRAMToFile(MMU.WRAM, romName);
} }
} }
@ -1143,7 +1143,7 @@ namespace VirtualNes.Core
} }
} }
Supporter.SaveDISKToFile(contents.ToArray(), rom.GetRomName()); Supporter.S.SaveDISKToFile(contents.ToArray(), rom.GetRomName());
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1168,7 +1168,7 @@ namespace VirtualNes.Core
{ {
Debuger.Log("Saving TURBOFILE..."); Debuger.Log("Saving TURBOFILE...");
Supporter.SaveFile(MMU.ERAM, Supporter.Config.path.szSavePath, "TurboFile.vtf"); Supporter.S.SaveFile(MMU.ERAM, Supporter.S.Config.path.szSavePath, "TurboFile.vtf");
} }
} }

View File

@ -181,7 +181,7 @@ namespace VirtualNes.Core
} }
else else
{ {
if (Supporter.Config.emulator.bFourPlayer) if (Supporter.S.Config.emulator.bFourPlayer)
{ {
// NES type // NES type
pad1bit = padbitsync[0] | ((uint)padbitsync[2] << 8) | 0x00080000; pad1bit = padbitsync[0] | ((uint)padbitsync[2] << 8) | 0x00080000;

View File

@ -50,7 +50,7 @@ namespace VirtualNes.Core
try try
{ {
fp = Supporter.OpenRom(fname); fp = Supporter.S.OpenRom(fname);
if (fp == null) if (fp == null)
{ {
throw new System.Exception($"Open Rom Failed:[{fname}]"); throw new System.Exception($"Open Rom Failed:[{fname}]");
@ -167,7 +167,7 @@ namespace VirtualNes.Core
lpPRG[3] = 0x1A; lpPRG[3] = 0x1A;
lpPRG[4] = (byte)diskno; lpPRG[4] = (byte)diskno;
fp = Supporter.OpenFile_DISKSYS(); fp = Supporter.S.OpenFile_DISKSYS();
if (fp == null) if (fp == null)
{ {
throw new Exception($"Not found DISKSYS.ROM for [{fname}]"); throw new Exception($"Not found DISKSYS.ROM for [{fname}]");
@ -217,7 +217,7 @@ namespace VirtualNes.Core
throw new Exception($"Unsupport format:[{fname}]"); throw new Exception($"Unsupport format:[{fname}]");
} }
Supporter.GetFilePathInfo(fname, out fullpath, out path); Supporter.S.GetRomPathInfo(fname, out fullpath, out path);
name = Path.GetFileNameWithoutExtension(fullpath); name = Path.GetFileNameWithoutExtension(fullpath);
if (!bNSF) if (!bNSF)
{ {
@ -244,7 +244,7 @@ namespace VirtualNes.Core
FileNameCheck(fname); FileNameCheck(fname);
if (Supporter.TryGetMapperNo(this, out int mapperNo)) if (Supporter.S.TryGetMapperNo(this, out int mapperNo))
{ {
Debuger.Log($"ROMDB Set Mapper #{mapper:000} to #{mapperNo:000}"); Debuger.Log($"ROMDB Set Mapper #{mapper:000} to #{mapperNo:000}");
mapper = mapperNo; mapper = mapperNo;

View File

@ -5,73 +5,12 @@ namespace VirtualNes.Core
public static class Supporter public static class Supporter
{ {
private static ISupporterImpl s_support; private static ISupporterImpl s_support;
internal static ISupporterImpl S => s_support;
public static void Setup(ISupporterImpl supporter) public static void Setup(ISupporterImpl supporter)
{ {
s_support = supporter; s_support = supporter;
} }
public static Stream OpenRom(string fname)
{
return s_support.OpenRom(fname);
}
public static void GetFilePathInfo(string fname, out string fullPath, out string directPath)
{
s_support.GetRomPathInfo(fname, out fullPath, out directPath);
}
public static Stream OpenFile_DISKSYS()
{
return s_support.OpenFile_DISKSYS();
}
public static void SaveSRAMToFile(byte[] sramContent, string romName)
{
s_support.SaveSRAMToFile(sramContent, romName);
}
public static void SaveDISKToFile(byte[] diskFileContent, string romName)
{
s_support.SaveDISKToFile(diskFileContent, romName);
}
public static void PrepareDirectory(string directPath)
{
s_support.PrepareDirectory(directPath);
}
public static void SaveFile(byte[] fileData, string directPath, string fileName)
{
s_support.SaveFile(fileData, directPath, fileName);
}
public static Stream OpenFile(string directPath, string fileName)
{
return s_support.OpenFile(directPath, fileName);
}
public static bool TryGetMapperNo(ROM rom, out int mapperNo)
{
return s_support.TryGetMapperNo(rom, out mapperNo);
}
public static ControllerState GetControllerState()
{
return s_support.GetControllerState();
}
public static void SampleInput(uint frameCount)
{
s_support.SampleInput(frameCount);
}
public static IControllerSetuper GetControllerSetuper()
{
return s_support?.GetControllerSetuper();
}
public static EmulatorConfig Config => s_support.Config;
} }
public interface ISupporterImpl public interface ISupporterImpl
@ -82,48 +21,11 @@ namespace VirtualNes.Core
void SaveSRAMToFile(byte[] sramContent, string romName); void SaveSRAMToFile(byte[] sramContent, string romName);
void SaveDISKToFile(byte[] diskFileContent, string romName); void SaveDISKToFile(byte[] diskFileContent, string romName);
EmulatorConfig Config { get; } EmulatorConfig Config { get; }
void PrepareDirectory(string directPath); void PrepareDirectory(string directPath);
void SaveFile(byte[] fileData, string directPath, string fileName); void SaveFile(byte[] fileData, string directPath, string fileName);
Stream OpenFile(string directPath, string fileName); Stream OpenFile(string directPath, string fileName);
bool TryGetMapperNo(ROM rom, out int mapperNo); bool TryGetMapperNo(ROM rom, out int mapperNo);
ControllerState GetControllerState(); ControllerState GetControllerState();
void SampleInput(uint frameCount); void SampleInput(uint frameCount);
IControllerSetuper GetControllerSetuper();
}
/// <summary>
/// 负责管理本地控制器与具体游戏之间的槽位分配
/// </summary>
public interface IControllerSetuper
{
/// <summary>
/// 设置本地手柄与游戏手柄槽位的映射,这个方法是一个全量更新手柄插入设置的方法
/// </summary>
void SetConnect(
uint? con0ToSlot = null,
uint? con1ToSlot = null,
uint? con2ToSlot = null,
uint? con3ToSlot = null);
/// <summary>
/// 指定手柄插槽位,获取当前槽位连接的本地手柄序号
/// </summary>
/// <param name="slotIndex"></param>
/// <returns></returns>
int? GetSlotConnectingController(int slotIndex);
/// <summary>
/// 获得一个空的槽位
/// </summary>
/// <returns></returns>
uint? GetFreeSlotIndex();
/// <summary>
/// 增量式的修改一个手柄和一个槽位的连接关系
/// </summary>
/// <param name="conIndex"></param>
/// <param name="slotIndex"></param>
void LetControllerConnect(int conIndex, uint slotIndex);
} }
} }