diff --git a/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs b/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs index 84f08bf..3e95763 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs +++ b/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs @@ -359,7 +359,7 @@ namespace AxibugEmuOnline.Client.Manager void RecvHostSyn_RoomFrameAllInputData(byte[] reqData) { Protobuf_Room_Syn_RoomFrameAllInputData msg = ProtoBufHelper.DeSerizlize(reqData); - netReplay.InData(new ReplayStep() { FrameStartID = (int)msg.FrameID, InPut = msg.InputData }, (int)msg.ServerFrameID); + //netReplay.InData(new ReplayStep() { FrameStartID = (int)msg.FrameID, InPut = msg.InputData }, (int)msg.ServerFrameID); } public void SendScreen(byte[] RenderBuffer) diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs index 6f5810e..f99d8e8 100644 --- a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs @@ -5,15 +5,16 @@ namespace AxibugEmuOnline.Client { public class InGameUI : CommandExecuter { - public static InGameUI Instance { get; private set; } public RomFile RomFile => m_rom; public override bool Enable => gameObject.activeInHierarchy; private RomFile m_rom; private object m_core; + private object m_state; - private InGameUI_SaveState m_saveMenu; + private InGameUI_SaveState m_saveStateMenu; + private InGameUI_LoadState m_loadStateMenu; protected override void Awake() { @@ -27,15 +28,47 @@ namespace AxibugEmuOnline.Client Instance = null; } + /// + /// 获取模拟器核心对象 + /// + /// 模拟器核心对象类型 public T GetCore() => (T)m_core; + /// 保存快速快照 + public void SaveQuickState(object state) + { + m_state = state; + } + /// + /// 读取快速快照 + /// + /// + /// + public bool GetQuickState(out T state) + { + state = default(T); + + if (m_state is T) + { + state = (T)m_state; + return true; + } + else + { + return false; + } + + } public void Show(RomFile currentRom, object core) { - m_saveMenu = new InGameUI_SaveState(this); CommandDispatcher.Instance.RegistController(this); + m_saveStateMenu = new InGameUI_SaveState(this); + m_loadStateMenu = new InGameUI_LoadState(this); + m_rom = currentRom; m_core = core; + gameObject.SetActiveEx(true); } @@ -43,14 +76,12 @@ namespace AxibugEmuOnline.Client { CommandDispatcher.Instance.UnRegistController(this); - m_rom = null; - m_core = null; gameObject.SetActiveEx(false); } protected override void OnCmdOptionMenu() { - OptionUI.Instance.Pop(new List { m_saveMenu }); + OptionUI.Instance.Pop(new List { m_saveStateMenu, m_loadStateMenu }); } } } diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs new file mode 100644 index 0000000..8a4863d --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs @@ -0,0 +1,32 @@ +using AxibugEmuOnline.Client.ClientCore; +using System.Diagnostics; +using VirtualNes.Core; + +namespace AxibugEmuOnline.Client +{ + public class InGameUI_LoadState : ExecuteMenu + { + private InGameUI m_gameUI; + + public InGameUI_LoadState(InGameUI gameUI) : base("读取快照", null) + { + m_gameUI = gameUI; + } + + public override void OnExcute() + { + Stopwatch sw = Stopwatch.StartNew(); + switch (m_gameUI.RomFile.Platform) + { + case EnumPlatform.NES: + if (m_gameUI.GetQuickState(out var quickState)) + { + m_gameUI.GetCore().NesCore.LoadState(quickState); + } + break; + } + sw.Stop(); + App.log.Info($"{m_gameUI.RomFile.Platform}====>快照加载耗时:{sw.Elapsed.TotalMilliseconds}ms"); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs.meta b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs.meta new file mode 100644 index 0000000..f65bbdb --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 522140a3272d84a40b1ff91a3ebdb1b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs index 3791d53..4bfc095 100644 --- a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs @@ -19,6 +19,7 @@ namespace AxibugEmuOnline.Client { case EnumPlatform.NES: var state = m_gameUI.GetCore().NesCore.GetState(); + m_gameUI.SaveQuickState(state); App.log.Info($"{m_gameUI.RomFile.Platform}===>快照大小{state.ToBytes().Length}"); break; } diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs b/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs index 72135e7..46fe147 100644 --- a/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs +++ b/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs @@ -168,6 +168,9 @@ namespace AxibugEmuOnline.Client { public string Name { get; protected set; } public Sprite Icon { get; protected set; } + public virtual bool Visible => true; + public virtual bool Enable => true; + public OptionMenu(string name, Sprite icon = null) { Name = name; diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs index 0aa713b..fb7e9b5 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs @@ -543,6 +543,11 @@ namespace VirtualNes.Core @internal.GetFrameIRQ(ref Cycle, ref Count, ref Type, ref IRQ, ref Occur); } + internal void SetFrameIRQ(int Cycle, byte Count, byte Type, byte IRQ, byte Occur) + { + @internal.SetFrameIRQ(Cycle, Count, Type, IRQ, Occur); + } + internal void SaveState(StateBuffer buffer) { // 鏅傞枔杌搞倰鍚屾湡銇曘仜銈嬬偤Flush銇欍倠 @@ -579,7 +584,7 @@ namespace VirtualNes.Core // N106 if ((exsound_select & 0x10) != 0) { - n106.SaveState(buffer); + n106.SaveState(buffer); buffer.Position += (n106.GetSize() + 15) & (~0x0F); // Padding } // FME7 @@ -589,6 +594,49 @@ namespace VirtualNes.Core buffer.Position += (fme7.GetSize() + 15) & (~0x0F); // Padding } } + + internal void LoadState(StateReader buffer) + { + @internal.LoadState(buffer); + buffer.Skip((@internal.GetSize() + 15) & (~0x0F)); + + // VRC6 + if ((exsound_select & 0x01) != 0) + { + vrc6.LoadState(buffer); + buffer.Skip((int)((vrc6.GetSize() + 15) & (~0x0F))); // Padding + } + // VRC7 (not support) + if ((exsound_select & 0x02) != 0) + { + vrc7.LoadState(buffer); + buffer.Skip((vrc7.GetSize() + 15) & (~0x0F)); // Padding + } + // FDS + if ((exsound_select & 0x04) != 0) + { + fds.LoadState(buffer); + buffer.Skip((fds.GetSize() + 15) & (~0x0F)); // Padding + } + // MMC5 + if ((exsound_select & 0x08) != 0) + { + mmc5.LoadState(buffer); + buffer.Skip((mmc5.GetSize() + 15) & (~0x0F)); // Padding + } + // N106 + if ((exsound_select & 0x10) != 0) + { + n106.LoadState(buffer); + buffer.Skip((n106.GetSize() + 15) & (~0x0F)); // Padding + } + // FME7 + if ((exsound_select & 0x20) != 0) + { + fme7.LoadState(buffer); + buffer.Skip((fme7.GetSize() + 15) & (~0x0F)); // Padding + } + } } public struct QUEUEDATA diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs index 88566a0..a6b5176 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs @@ -514,6 +514,36 @@ namespace VirtualNes.Core buffer.Write(now_freq); buffer.Write(output); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(0x80); + volenv_mode = buffer.Read_byte(); + volenv_gain = buffer.Read_byte(); + volenv_decay = buffer.Read_byte(); + volenv_phaseacc = buffer.Read_double(); + swpenv_mode = buffer.Read_byte(); + swpenv_gain = buffer.Read_byte(); + swpenv_decay = buffer.Read_byte(); + swpenv_phaseacc = buffer.Read_double(); + envelope_enable = buffer.Read_byte(); + envelope_speed = buffer.Read_byte(); + wave_setup = buffer.Read_byte(); + master_volume = buffer.Read_int(); + main_wavetable = buffer.Read_ints(64); + main_enable = buffer.Read_byte(); + main_frequency = buffer.Read_int(); + main_addr = buffer.Read_int(); + lfo_wavetable = buffer.Read_bytes(64); + lfo_enable = buffer.Read_byte(); + lfo_frequency = buffer.Read_int(); + lfo_addr = buffer.Read_int(); + lfo_phaseacc = buffer.Read_double(); + sweep_bias = buffer.Read_int(); + now_volume = buffer.Read_int(); + now_freq = buffer.Read_int(); + output = buffer.Read_int(); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs index c707084..cbe6696 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs @@ -398,6 +398,17 @@ namespace VirtualNes.Core buffer.Write(envtbl_index); buffer.Write(envstep_index); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(3); + volume = buffer.Read_byte(); + freq = buffer.Read_int(); + phaseacc = buffer.Read_int(); + envadr = buffer.Read_int(); + envtbl_index = buffer.Read_byte(); + envstep_index = buffer.Read_byte(); + } } public class NOISE : IStateBufferObject @@ -424,6 +435,14 @@ namespace VirtualNes.Core buffer.Write(noiserange); buffer.Write(noiseout); } + + public void LoadState(StateReader buffer) + { + freq = buffer.Read_int(); + phaseacc = buffer.Read_int(); + noiserange = buffer.Read_int(); + noiseout = buffer.Read_byte(); + } } public class CHANNEL : IStateBufferObject @@ -469,6 +488,19 @@ namespace VirtualNes.Core buffer.Write(phaseacc); buffer.Write(output_vol); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(3); + enable = buffer.Read_byte(); + env_on = buffer.Read_byte(); + noise_on = buffer.Read_byte(); + adder = buffer.Read_byte(); + volume = buffer.Read_byte(); + freq = buffer.Read_int(); + phaseacc = buffer.Read_int(); + output_vol = buffer.Read_int(); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs index db28ed6..49378ac 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs @@ -23,7 +23,7 @@ namespace VirtualNes.Core public virtual bool Sync(int cycles) { return false; } public virtual int GetFreq(int channel) { return 0; } public virtual void SaveState(StateBuffer buffer) { } - public virtual void LoadState(byte[] p) { } + public virtual void LoadState(StateReader buffer) { } public static int INT2FIX(int x) { diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs index 51c8aef..07d1932 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs @@ -1203,6 +1203,15 @@ namespace VirtualNes.Core occur = FrameIRQoccur; } + internal void SetFrameIRQ(int cycle, byte count, byte type, byte IRQ, byte occur) + { + FrameCycle = cycle; + FrameCount = count; + FrameType = type; + FrameIRQ = IRQ; + FrameIRQoccur = occur; + } + public override uint GetSize() { return sizeof(byte) + @@ -1219,7 +1228,7 @@ namespace VirtualNes.Core ch4.GetSize(); } - public unsafe override void SaveState(StateBuffer p) + public override void SaveState(StateBuffer p) { p.Write(reg4015); p.Write(sync_reg4015); @@ -1352,6 +1361,39 @@ namespace VirtualNes.Core buffer.Write(dummy2); buffer.Write(sync_len_count); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(4); + enable = buffer.Read_byte(); + holdnote = buffer.Read_byte(); + volume = buffer.Read_byte(); + complement = buffer.Read_byte(); + phaseacc = buffer.Read_int(); + freq = buffer.Read_int(); + freqlimit = buffer.Read_int(); + adder = buffer.Read_int(); + duty = buffer.Read_int(); + len_count = buffer.Read_int(); + nowvolume = buffer.Read_int(); + env_fixed = buffer.Read_byte(); + env_decay = buffer.Read_byte(); + env_count = buffer.Read_byte(); + dummy0 = buffer.Read_byte(); + env_vol = buffer.Read_int(); + swp_on = buffer.Read_byte(); + swp_inc = buffer.Read_byte(); + swp_shift = buffer.Read_byte(); + swp_decay = buffer.Read_byte(); + swp_count = buffer.Read_byte(); + dummy1 = buffer.Read_bytes(3); + sync_reg = buffer.Read_bytes(4); + sync_output_enable = buffer.Read_byte(); + sync_enable = buffer.Read_byte(); + sync_holdnote = buffer.Read_byte(); + dummy2 = buffer.Read_byte(); + sync_len_count = buffer.Read_int(); + } } public class TRIANGLE : IStateBufferObject { @@ -1428,6 +1470,27 @@ namespace VirtualNes.Core buffer.Write(sync_len_count); buffer.Write(sync_lin_count); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(4); + enable = buffer.Read_byte(); + holdnote = buffer.Read_byte(); + counter_start = buffer.Read_byte(); + dummy0 = buffer.Read_byte(); + phaseacc = buffer.Read_int(); + freq = buffer.Read_int(); + len_count = buffer.Read_int(); + lin_count = buffer.Read_int(); + adder = buffer.Read_int(); + nowvolume = buffer.Read_int(); + sync_reg = buffer.Read_bytes(4); + sync_enable = buffer.Read_byte(); + sync_holdnote = buffer.Read_byte(); + sync_counter_start = buffer.Read_byte(); + sync_len_count = buffer.Read_int(); + sync_lin_count = buffer.Read_int(); + } } public class DPCM : IStateBufferObject { @@ -1487,6 +1550,35 @@ namespace VirtualNes.Core buffer.Write(sync_dmalength); buffer.Write(sync_cache_dmalength); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(4); + enable = buffer.Read_byte(); + looping = buffer.Read_byte(); + cur_byte = buffer.Read_byte(); + dpcm_value = buffer.Read_byte(); + freq = buffer.Read_int(); + phaseacc = buffer.Read_int(); + output = buffer.Read_int(); + address = buffer.Read_ushort(); + cache_addr = buffer.Read_ushort(); + dmalength = buffer.Read_int(); + cache_dmalength = buffer.Read_int(); + dpcm_output_real = buffer.Read_int(); + dpcm_output_fake = buffer.Read_int(); + dpcm_output_old = buffer.Read_int(); + dpcm_output_offset = buffer.Read_int(); + sync_reg = buffer.Read_bytes(4); + sync_enable = buffer.Read_byte(); + sync_looping = buffer.Read_byte(); + sync_irq_gen = buffer.Read_byte(); + sync_irq_enable = buffer.Read_byte(); + sync_cycles = buffer.Read_int(); + sync_cache_cycles = buffer.Read_int(); + sync_dmalength = buffer.Read_int(); + sync_cache_dmalength = buffer.Read_int(); + } } public class NOISE : IStateBufferObject { @@ -1582,6 +1674,32 @@ namespace VirtualNes.Core buffer.Write(dummy1); buffer.Write(sync_len_count); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(4); + enable = buffer.Read_byte(); + holdnote = buffer.Read_byte(); + volume = buffer.Read_byte(); + xor_tap = buffer.Read_byte(); + shift_reg = buffer.Read_int(); + phaseacc = buffer.Read_int(); + freq = buffer.Read_int(); + len_count = buffer.Read_int(); + nowvolume = buffer.Read_int(); + output = buffer.Read_int(); + env_fixed = buffer.Read_byte(); + env_decay = buffer.Read_byte(); + env_count = buffer.Read_byte(); + dummy0 = buffer.Read_byte(); + env_vol = buffer.Read_int(); + sync_reg = buffer.Read_bytes(4); + sync_output_enable = buffer.Read_byte(); + sync_enable = buffer.Read_byte(); + sync_holdnote = buffer.Read_byte(); + dummy1 = buffer.Read_byte(); + sync_len_count = buffer.Read_int(); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs index f8f5ff0..cf5cc89 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs @@ -421,6 +421,15 @@ namespace VirtualNes.Core buffer.Write(dummy); buffer.Write(vbl_length); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(4); + enable = buffer.Read_byte(); + holdnote = buffer.Read_byte(); + dummy = buffer.Read_bytes(2); + vbl_length = buffer.Read_int(); + } } public class RECTANGLE : IStateBufferObject @@ -467,6 +476,24 @@ namespace VirtualNes.Core buffer.Write(adder); buffer.Write(duty_flip); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(4); + enable = buffer.Read_byte(); + vbl_length = buffer.Read_int(); + phaseacc = buffer.Read_int(); + freq = buffer.Read_int(); + output_vol = buffer.Read_int(); + fixed_envelope = buffer.Read_byte(); + holdnote = buffer.Read_byte(); + volume = buffer.Read_byte(); + env_vol = buffer.Read_byte(); + env_phase = buffer.Read_int(); + env_decay = buffer.Read_int(); + adder = buffer.Read_int(); + duty_flip = buffer.Read_int(); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs index dadd4c7..f9ea4e6 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs @@ -243,6 +243,19 @@ namespace VirtualNes.Core buffer.Write(vol); buffer.Write(databuf); } + + public void LoadState(StateReader buffer) + { + phaseacc = buffer.Read_int(); + freq = buffer.Read_uint(); + phase = buffer.Read_uint(); + tonelen = buffer.Read_uint(); + output = buffer.Read_int(); + toneadr = buffer.Read_byte(); + volupdate = buffer.Read_byte(); + vol = buffer.Read_byte(); + databuf = buffer.Read_byte(); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs index cdc442f..04f2f51 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs @@ -304,6 +304,19 @@ namespace VirtualNes.Core buffer.Write(adder); buffer.Write(duty_pos); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(3); + enable = buffer.Read_byte(); + gate = buffer.Read_byte(); + volume = buffer.Read_byte(); + phaseacc = buffer.Read_int(); + freq = buffer.Read_int(); + output_vol = buffer.Read_int(); + adder = buffer.Read_byte(); + duty_pos = buffer.Read_byte(); + } } public class SAWTOOTH : IStateBufferObject @@ -353,6 +366,19 @@ namespace VirtualNes.Core buffer.Write(accum); buffer.Write(phaseaccum); } + + public void LoadState(StateReader buffer) + { + reg = buffer.Read_bytes(3); + enable = buffer.Read_byte(); + volume = buffer.Read_byte(); + phaseacc = buffer.Read_int(); + freq = buffer.Read_int(); + output_vol = buffer.Read_int(); + adder = buffer.Read_byte(); + accum = buffer.Read_byte(); + phaseaccum = buffer.Read_byte(); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs index be4fc29..a17c7b9 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs @@ -2022,10 +2022,20 @@ namespace VirtualNes.Core r = R; } + internal void SetContext(R6502 r) + { + R = r; + } + internal int GetDmaCycles() { return DMA_cycles; } + + internal void SetDmaCycles(int cycles) + { + DMA_cycles = cycles; + } } public enum StatusFlag6502 : int diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs index c23925c..7a23915 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs @@ -53,6 +53,11 @@ namespace VirtualNes.Core } } + public void WriteTo(T[] source, int start, int length) + { + Array.Copy(source, 0, m_rawArray, Offset + start, length); + } + public Span Span(int start, int length) { return new Span(m_rawArray, start + Offset, length); diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs index 9ea39ef..a66a563 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs @@ -1872,12 +1872,15 @@ namespace VirtualNes.Core state.dskBLOCK.BlockVersion = 0x0210; state.dskBLOCK.BlockSize = 0; + state.dskdata = new List(); + for (int i = 16; i < DiskSize; i++) { if (lpWrite[i] != 0) { - state.dskdata = (uint)(i & 0x00FFFFFF); - state.dskdata |= ((uint)lpDisk[i] & 0xFF) << 24; + uint data = (uint)(i & 0x00FFFFFF); + data |= ((uint)lpDisk[i] & 0xFF) << 24; + state.dskdata.Add(data); } } } @@ -1898,7 +1901,191 @@ namespace VirtualNes.Core public void LoadState(State state) { + //HEADER + { + state.HEADER.ID = "VirtuaNES ST"; + state.HEADER.BlockVersion = 0x0200; + if (rom.GetMapperNo() != 20) + rom.SetPROM_CRC(state.HEADER.Ext0); + else + { + rom.SetGameID(state.HEADER.Ext0); + rom.SetMakerID(state.HEADER.Ext1); + rom.SetDiskNo(state.HEADER.Ext2); + } + } + + //REGISTER STATE + { + R6502 R = new R6502(); + R.PC = state.reg.cpureg.PC; + R.A = state.reg.cpureg.A; + R.X = state.reg.cpureg.X; + R.Y = state.reg.cpureg.Y; + R.S = state.reg.cpureg.S; + R.P = state.reg.cpureg.P; + R.INT_pending = state.reg.cpureg.I; + cpu.SetContext(R); + + apu.SetFrameIRQ( + state.reg.cpureg.FrameIRQ_cycles, + state.reg.cpureg.FrameIRQ_count, + state.reg.cpureg.FrameIRQ_type, + state.reg.cpureg.FrameIRQ, + state.reg.cpureg.FrameIRQ_occur + ); + + + cpu.SetDmaCycles(state.reg.cpureg.DMA_cycles); + emul_cycles = state.reg.cpureg.emul_cycles; + base_cycles = state.reg.cpureg.base_cycles; + + // LOAD PPU STATE + MMU.PPUREG[0] = state.reg.ppureg.reg0; + MMU.PPUREG[1] = state.reg.ppureg.reg1; + MMU.PPUREG[2] = state.reg.ppureg.reg2; + MMU.PPUREG[3] = state.reg.ppureg.reg3; + MMU.PPU7_Temp = state.reg.ppureg.reg7; + MMU.loopy_t = state.reg.ppureg.loopy_t; + MMU.loopy_v = state.reg.ppureg.loopy_v; + MMU.loopy_x = state.reg.ppureg.loopy_x; + MMU.PPU56Toggle = state.reg.ppureg.toggle56; + } + + //RAM STATE + { + // SAVE RAM STATE + MemoryUtility.memcpy(MMU.RAM, state.ram.RAM, state.ram.RAM.Length); + MemoryUtility.memcpy(MMU.BGPAL, state.ram.BGPAL, state.ram.BGPAL.Length); + MemoryUtility.memcpy(MMU.SPPAL, state.ram.SPPAL, state.ram.SPPAL.Length); + MemoryUtility.memcpy(MMU.SPRAM, state.ram.SPRAM, state.ram.SPRAM.Length); + + if (rom.IsSAVERAM()) + { + Array.Copy(state.WRAM, MMU.WRAM, SAVERAM_SIZE); + } + } + + //BANK STATE + { + // SAVE CPU MEMORY BANK DATA + // BANK0,1,2はバンクセーブに関係なし + // VirtuaNES0.30から + // バンク3はSRAM使用に関わらずセーブ + for (int i = 3; i < 8; i++) + { + MMU.CPU_MEM_TYPE[i] = state.mmu.CPU_MEM_TYPE[i]; + MMU.CPU_MEM_PAGE[i] = state.mmu.CPU_MEM_PAGE[i]; + } + + // SAVE VRAM MEMORY DATA + for (int i = 0; i < 12; i++) + { + MMU.PPU_MEM_TYPE[i] = state.mmu.PPU_MEM_TYPE[i]; + MMU.PPU_MEM_PAGE[i] = state.mmu.PPU_MEM_PAGE[i]; + } + + for (int i = 0; i < 8; i++) + { + MMU.CRAM_USED[i] = state.mmu.CRAM_USED[i]; + } + + // WRITE CPU RAM MEMORY BANK + + int stateStep = 0; + var stateCPU_MEM_BANK = state.CPU_MEM_BANK.ToArray(); + + for (int i = 3; i < 8; i++) + { + if (state.mmu.CPU_MEM_TYPE[i] != MMU.BANKTYPE_ROM) + { + var sourceData = new Span(stateCPU_MEM_BANK, stateStep * 8 * 1024, 8 * 1024); + MMU.CPU_MEM_BANK[i].WriteTo(sourceData.ToArray(), 0, 8 * 1024); + stateStep++; + } + } + + Array.Copy(state.VRAM, MMU.VRAM, state.VRAM.Length); + + stateStep = 0; + var stateCRAM = state.CRAM.ToArray(); + // LOAD CRAM MEMORY + for (int i = 0; i < 8; i++) + { + if (MMU.CRAM_USED[i] != 0) + { + var sourceData = stateCRAM.AsSpan(stateStep * 4 * 1024, 4 * 1024).ToArray(); + Array.Copy(sourceData, 0, MMU.CRAM, 0x1000 * i, 4 * 1024); + } + } + } + + // MMC STATE + { + state.mmc = MMCSTAT.GetDefault(); + + // Create Header + state.mmcBLOCK.ID = "MMC DATA"; + state.mmcBLOCK.BlockVersion = 0x0100; + state.mmcBLOCK.BlockSize = state.mmc.GetSize(); + + if (mapper.IsStateSave()) + { + mapper.LoadState(state.mmc.mmcdata); + } + } + + //CONTROLLER STATE + { + pad.pad1bit = state.ctr.pad1bit; + pad.pad2bit = state.ctr.pad2bit; + pad.pad3bit = state.ctr.pad3bit; + pad.pad4bit = state.ctr.pad4bit; + pad.SetStrobe(state.ctr.strobe == 0 ? false : true); + } + + //SND STATE + { + state.snd = SNDSTAT.GetDefault(); + + var buffer = new StateReader(state.snd.snddata); + apu.LoadState(buffer); + } + + // DISKIMAGE STATE + if (rom.GetMapperNo() == 20) + { + var lpDisk = rom.GetPROM(); + var lpWrite = rom.GetDISK(); + int DiskSize = 16 + 65500 * rom.GetDiskNo(); + + Array.Clear(lpWrite, 0, DiskSize); + + for (int i = 0; i < state.dsk.DifferentSize; i++) + { + var pos = state.dskdata[i]; + byte data = (byte)(pos >> 24); + pos &= 0x00FFFFFF; + + if (pos >= 16 && pos < DiskSize) + { + lpDisk[pos] = data; + lpWrite[pos] = 0xFF; + } + } + } + + // EXCTR STATE + if (pad.GetExController() != 0) + { + pad.SetSyncExData(state.exctr.data); + } + } + + internal void SetZapperPos(int x, int y) + { + ZapperX = x; ZapperY = y; } public enum IRQMETHOD diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs index f418d58..0c4acd7 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs @@ -515,6 +515,11 @@ namespace VirtualNes.Core return bStrobe; } + internal void SetStrobe(bool v) + { + bStrobe = v; + } + internal uint GetSyncExData() { uint data = 0; @@ -571,6 +576,63 @@ namespace VirtualNes.Core } return data; } + internal void SetSyncExData(uint data) + { + switch ((EXCONTROLLER)excontroller_select) + { + case EXCONTROLLER.EXCONTROLLER_ZAPPER: + case EXCONTROLLER.EXCONTROLLER_PADDLE: + case EXCONTROLLER.EXCONTROLLER_SPACESHADOWGUN: + case EXCONTROLLER.EXCONTROLLER_OEKAKIDS_TABLET: + case EXCONTROLLER.EXCONTROLLER_VSZAPPER: + { + int x, y; + if ((data & 0x80000000) != 0) + { + x = -1; + y = -1; + } + else + { + x = (int)(data & 0xFF); + y = (int)((data & 0xFF00) >> 8); + } + expad.SetSyncData(0, x); + expad.SetSyncData(1, y); + nes.SetZapperPos(x, y); + } + if (excontroller_select != (int)EXCONTROLLER.EXCONTROLLER_SPACESHADOWGUN) + { + if ((data & 0x0010000) != 0) + expad.SetSyncData(2, 1); + else + expad.SetSyncData(2, 0); + } + else + { + expad.SetSyncData(2, (byte)(data >> 16)); + } + break; + case EXCONTROLLER.EXCONTROLLER_CRAZYCLIMBER: + expad.SetSyncData(0, (int)data); + break; + case EXCONTROLLER.EXCONTROLLER_TOPRIDER: + expad.SetSyncData(0, (int)data); + break; + case EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_A: + case EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_B: + expad.SetSyncData(0, (int)data); + break; + case EXCONTROLLER.EXCONTROLLER_EXCITINGBOXING: + expad.SetSyncData(0, (int)data); + break; + case EXCONTROLLER.EXCONTROLLER_MAHJANG: + expad.SetSyncData(0, (int)data); + break; + default: + break; + } + } } public enum VSType diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs index 9f36391..718c08f 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs @@ -353,16 +353,31 @@ namespace VirtualNes.Core return diskno; } + internal void SetDiskNo(int v) + { + diskno = v; + } + internal uint GetGameID() { return fdsgameID; } + internal void SetGameID(uint id) + { + fdsgameID = id; + } + internal uint GetMakerID() { return fdsmakerID; } + internal void SetMakerID(uint id) + { + fdsmakerID = id; + } + internal bool IsVSUNISYSTEM() { return (header.control2 & (byte)EnumRomControlByte2.ROM_VSUNISYSTEM) != 0; @@ -373,6 +388,11 @@ namespace VirtualNes.Core return crc; } + public void SetPROM_CRC(uint v) + { + crc = v; + } + internal byte GetPROM_SIZE() { return header.PRG_PAGE_SIZE; diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs index 71ba330..f3aafa6 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs @@ -3,11 +3,19 @@ public struct BLOCKHDR : IStateBufferObject { public readonly bool Valid => !string.IsNullOrEmpty(ID); + /// 鎬绘槸8涓瓧鑺 public string ID; public ushort Reserved; public ushort BlockVersion; public uint BlockSize; + + + public readonly uint GetSize() + { + return (uint)(8 + sizeof(ushort) + sizeof(ushort) + sizeof(uint)); + } + public readonly void SaveState(StateBuffer buffer) { if (Valid) @@ -19,9 +27,12 @@ } } - public readonly uint GetSize() + public void LoadState(StateReader buffer) { - return (uint)(ID.Length + sizeof(ushort) + sizeof(ushort) + sizeof(uint)); + ID = buffer.Read_string(8); + Reserved = buffer.Read_ushort(); + BlockVersion = buffer.Read_ushort(); + BlockSize = buffer.Read_uint(); } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs index 950610a..2718c07 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs @@ -24,5 +24,14 @@ namespace VirtualNes.Core buffer.Write(pad4bit); buffer.Write(strobe); } + + public void LoadState(StateReader buffer) + { + pad1bit = buffer.Read_uint(); + pad2bit = buffer.Read_uint(); + pad3bit = buffer.Read_uint(); + pad4bit = buffer.Read_uint(); + strobe = buffer.Read_byte(); + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs index 95e21b6..16b7ae3 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs @@ -13,5 +13,10 @@ { buffer.Write(DifferentSize); } + + public void LoadState(StateReader buffer) + { + DifferentSize = buffer.Read_int(); + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs index 469c414..802a463 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs @@ -13,5 +13,10 @@ { buffer.Write(data); } + + public void LoadState(StateReader buffer) + { + data = buffer.Read_uint(); + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs index 46dc209..c3a451c 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs @@ -16,6 +16,13 @@ namespace VirtualNes.Core /// 2瀛楄妭 public ushort Ext2; + + + public readonly uint GetSize() + { + return (uint)(ID.Length + sizeof(ushort) + sizeof(uint) + sizeof(ushort) + sizeof(ushort)); + } + public readonly void SaveState(StateBuffer buffer) { buffer.Write(ID); @@ -25,9 +32,13 @@ namespace VirtualNes.Core buffer.Write(Ext2); } - public readonly uint GetSize() + public void LoadState(StateReader buffer) { - return (uint)(ID.Length + sizeof(ushort) + sizeof(uint) + sizeof(ushort) + sizeof(ushort)); + ID = buffer.Read_string(12); + BlockVersion = buffer.Read_ushort(); + Ext0 = buffer.Read_uint(); + Ext1 = buffer.Read_ushort(); + Ext2 = buffer.Read_ushort(); } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs index 2f5ada0..e23ed91 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs @@ -9,14 +9,19 @@ return new MMCSTAT() { mmcdata = new byte[256] }; } - public uint GetSize() + public readonly uint GetSize() { - return (uint)mmcdata.Length; + return 256; } - public void SaveState(StateBuffer buffer) + public readonly void SaveState(StateBuffer buffer) { buffer.Write(mmcdata); } + + public void LoadState(StateReader buffer) + { + mmcdata = buffer.Read_bytes(256); + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs index 1109c89..88e45e7 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs @@ -34,5 +34,14 @@ buffer.Write(PPU_MEM_PAGE); buffer.Write(CRAM_USED); } + + public void LoadState(StateReader buffer) + { + CPU_MEM_TYPE = buffer.Read_bytes(8); + CPU_MEM_PAGE = buffer.Read_ushorts(8); + PPU_MEM_TYPE = buffer.Read_bytes(12); + PPU_MEM_PAGE = buffer.Read_ushorts(12); + CRAM_USED = buffer.Read_bytes(8); + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs index f6eec9e..5d3929b 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs @@ -34,5 +34,13 @@ namespace VirtualNes.Core buffer.Write(SPPAL); buffer.Write(SPRAM); } + + public void LoadState(StateReader buffer) + { + RAM = buffer.Read_bytes(2 * 1024); + BGPAL = buffer.Read_bytes(16); + SPPAL = buffer.Read_bytes(16); + SPRAM = buffer.Read_bytes(256); + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs index 52ce17d..13e0e8d 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs @@ -5,15 +5,23 @@ public CPUSTAT cpureg; public PPUSTAT ppureg; - public void SaveState(StateBuffer buffer) + + + public readonly uint GetSize() + { + return cpureg.GetSize() + ppureg.GetSize(); + } + + public readonly void SaveState(StateBuffer buffer) { cpureg.SaveState(buffer); ppureg.SaveState(buffer); } - public uint GetSize() + public void LoadState(StateReader buffer) { - return cpureg.GetSize() + ppureg.GetSize(); + cpureg.LoadState(buffer); + ppureg.LoadState(buffer); } } @@ -60,6 +68,25 @@ buffer.Write(emul_cycles); buffer.Write(base_cycles); } + + public void LoadState(StateReader buffer) + { + PC = buffer.Read_ushort(); + A = buffer.Read_byte(); + X = buffer.Read_byte(); + Y = buffer.Read_byte(); + S = buffer.Read_byte(); + P = buffer.Read_byte(); + I = buffer.Read_byte(); + FrameIRQ = buffer.Read_byte(); + FrameIRQ_occur = buffer.Read_byte(); + FrameIRQ_count = buffer.Read_byte(); + FrameIRQ_type = buffer.Read_byte(); + FrameIRQ_cycles = buffer.Read_int(); + DMA_cycles = buffer.Read_int(); + emul_cycles = buffer.Read_long(); + base_cycles = buffer.Read_long(); + } } public struct PPUSTAT : IStateBufferObject @@ -92,5 +119,18 @@ buffer.Write(loopy_v); buffer.Write(loopy_x); } + + public void LoadState(StateReader buffer) + { + reg0 = buffer.Read_byte(); + reg1 = buffer.Read_byte(); + reg2 = buffer.Read_byte(); + reg3 = buffer.Read_byte(); + reg7 = buffer.Read_byte(); + toggle56 = buffer.Read_byte(); + loopy_t = buffer.Read_ushort(); + loopy_v = buffer.Read_ushort(); + loopy_x = buffer.Read_ushort(); + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs index 38bd9e9..9de7b5b 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs @@ -15,14 +15,19 @@ namespace VirtualNes.Core return new SNDSTAT() { snddata = new byte[0x800] }; } - public uint GetSize() + public readonly uint GetSize() { return (uint)snddata.Length; } - public void SaveState(StateBuffer buffer) + public readonly void SaveState(StateBuffer buffer) { buffer.Write(snddata); } + + public void LoadState(StateReader buffer) + { + snddata = buffer.Read_bytes(0x800); + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs index d5d4609..c9003cb 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs @@ -31,7 +31,7 @@ namespace VirtualNes.Core public BLOCKHDR dskBLOCK; public DISKDATA dsk; - public uint dskdata; + public List dskdata; public BLOCKHDR exctrBLOCK; public EXCTRSTAT exctr; @@ -87,7 +87,10 @@ namespace VirtualNes.Core { dskBLOCK.SaveState(buffer); dsk.SaveState(buffer); - buffer.Write(dskdata); + foreach (var data in dskdata) + { + buffer.Write(data); + } } if (exctrBLOCK.Valid) diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs index d46ed31..e496cc3 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs @@ -1,5 +1,6 @@ 锘縰sing System; using System.Collections.Generic; +using System.IO; using System.Text; namespace VirtualNes.Core @@ -31,15 +32,11 @@ namespace VirtualNes.Core } public void Write(sbyte[] sbytes) { - foreach(var value in sbytes) + foreach (var value in sbytes) { Write(value); } } - public void Write(byte[] bytes, int length) - { - Data.AddRange(bytes); - } public void Write(byte value) { Data.Add(value); @@ -80,11 +77,134 @@ namespace VirtualNes.Core { Write(BitConverter.GetBytes(value)); } + public void Write(uint value) + { + Write(BitConverter.GetBytes(value)); + } + } + public class StateReader + { + private MemoryStream m_dataStream; + public StateReader(byte[] bytes) + { + m_dataStream = new MemoryStream(bytes); + } + + public void Skip(uint count) + { + m_dataStream.Seek(count, SeekOrigin.Current); + } + public void Skip(long count) + { + m_dataStream.Seek(count, SeekOrigin.Current); + } + + public byte[] Read_bytes(int length) + { + var result = new byte[length]; + m_dataStream.Read(result, 0, length); + return result; + } + public sbyte[] Read_sbytes(int length) + { + var result = new sbyte[length]; + for (int i = 0; i < length; i++) + { + result[i] = (sbyte)m_dataStream.ReadByte(); + } + + return result; + } + + public byte Read_byte() + { + return (byte)m_dataStream.ReadByte(); + } + public ushort[] Read_ushorts(int length) + { + ushort[] result = new ushort[length]; + for (int i = 0; i < length; i++) + { + int byte1 = m_dataStream.ReadByte(); + int byte2 = m_dataStream.ReadByte(); + + result[i] = (ushort)(byte1 << 8 | byte2); + } + + return result; + } + public int[] Read_ints(int length) + { + int[] result = new int[length]; + for (int i = 0; i < length; i++) + { + int byte1 = m_dataStream.ReadByte(); + int byte2 = m_dataStream.ReadByte(); + int byte3 = m_dataStream.ReadByte(); + int byte4 = m_dataStream.ReadByte(); + + result[i] = byte1 << 24 | byte2 << 16 | byte3 << 8 | byte4; + } + + return result; + } + + + public string Read_string(int length) + { + var result = Read_bytes(length); + return Encoding.ASCII.GetString(result); + } + public double Read_double() + { + var result = Read_bytes(4); + return BitConverter.ToDouble(result, 0); + } + public ushort Read_ushort() + { + var b1 = Read_byte(); + var b2 = Read_byte(); + return (ushort)(b1 << 8 | b2); + } + + public int Read_int() + { + var b1 = Read_byte(); + var b2 = Read_byte(); + var b3 = Read_byte(); + var b4 = Read_byte(); + + return b1 << 24 | b2 << 16 | b3 << 8 | b4; + } + + public sbyte Read_sbyte(sbyte value) + { + return (sbyte)m_dataStream.ReadByte(); + } + public long Read_long() + { + var b1 = Read_byte(); + var b2 = Read_byte(); + var b3 = Read_byte(); + var b4 = Read_byte(); + var b5 = Read_byte(); + var b6 = Read_byte(); + var b7 = Read_byte(); + var b8 = Read_byte(); + + return b1 << 56 | b2 << 48 | b3 << 40 | b4 << 32 | b5 << 24 | b6 << 16 | b7 << 8 | b8; + } + + public uint Read_uint() + { + return (uint)Read_int(); + } } public interface IStateBufferObject { uint GetSize(); void SaveState(StateBuffer buffer); + void LoadState(StateReader buffer); } }