diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs index e24e9f6..74a9e28 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs @@ -4,7 +4,7 @@ namespace AxiReplay { public class NetReplay { - int mCurrPlayFrame = -1; + public int mCurrPlayFrame = -1; Queue mQueueReplay; ReplayStep mNextReplay; ReplayStep mCurrReplay; diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.prefab b/AxibugEmuOnline.Client/Assets/Resources/NES/NesEmulator.prefab similarity index 98% rename from AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.prefab rename to AxibugEmuOnline.Client/Assets/Resources/NES/NesEmulator.prefab index 4bef424..6d24d5d 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.prefab +++ b/AxibugEmuOnline.Client/Assets/Resources/NES/NesEmulator.prefab @@ -441,10 +441,10 @@ RectTransform: m_Father: {fileID: 4232056520494431727} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 180, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 272, y: 240} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &4232056521759880273 CanvasRenderer: @@ -466,7 +466,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} m_Name: m_EditorClassIdentifier: - m_Material: {fileID: 0} + m_Material: {fileID: 2100000, guid: 07e28fcb992bc124e986f9d8ff3beb97, type: 2} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} @@ -474,7 +474,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Texture: {fileID: 8400000, guid: ffe34aaf87e4b9942b4c2ac05943d444, type: 2} + m_Texture: {fileID: 0} m_UVRect: serializedVersion: 2 x: 0 diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.prefab.meta b/AxibugEmuOnline.Client/Assets/Resources/NES/NesEmulator.prefab.meta similarity index 100% rename from AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.prefab.meta rename to AxibugEmuOnline.Client/Assets/Resources/NES/NesEmulator.prefab.meta diff --git a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/OptionUI.prefab b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/OptionUI.prefab index 2cdea5c..8cef0dd 100644 --- a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/OptionUI.prefab +++ b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/OptionUI.prefab @@ -229,7 +229,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} + m_AnchoredPosition: {x: 204, y: 488} m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &2800056879890978085 diff --git a/AxibugEmuOnline.Client/Assets/Scene/Emu_NES.unity b/AxibugEmuOnline.Client/Assets/Scene/Emu_NES.unity index f8d05ee..0c2051e 100644 --- a/AxibugEmuOnline.Client/Assets/Scene/Emu_NES.unity +++ b/AxibugEmuOnline.Client/Assets/Scene/Emu_NES.unity @@ -174,53 +174,9 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} - - target: {fileID: 4232056521131536012, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: RomName - value: mario.nes - objectReference: {fileID: 0} - target: {fileID: 4232056521131536013, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} propertyPath: m_Name value: NesEmulator objectReference: {fileID: 0} - - target: {fileID: 4232056521759880274, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_Enabled - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4232056521759880274, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_Texture - value: - objectReference: {fileID: 0} - - target: {fileID: 4232056521759880274, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_Material - value: - objectReference: {fileID: 2100000, guid: 07e28fcb992bc124e986f9d8ff3beb97, type: 2} - - target: {fileID: 4232056521759880275, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_AnchorMax.x - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4232056521759880275, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4232056521759880275, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_AnchorMin.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4232056521759880275, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_AnchorMin.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4232056521759880275, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_SizeDelta.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4232056521759880275, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_SizeDelta.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4232056521759880276, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} - propertyPath: m_IsActive - value: 1 - objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} diff --git a/AxibugEmuOnline.Client/Assets/Script/Event/EventSystem.cs b/AxibugEmuOnline.Client/Assets/Script/Event/EventSystem.cs index c742461..da07fda 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Event/EventSystem.cs +++ b/AxibugEmuOnline.Client/Assets/Script/Event/EventSystem.cs @@ -29,14 +29,14 @@ namespace AxibugEmuOnline.Client.Event } } - public class EventSystem + public class Eventer { - private static EventSystem instance = new EventSystem(); - public static EventSystem Instance { get { return instance; } } + private static Eventer instance = new Eventer(); + public static Eventer Instance { get { return instance; } } private Dictionary> eventDic = new Dictionary>(128); - private EventSystem() { } + private Eventer() { } #region RegisterEvent diff --git a/AxibugEmuOnline.Client/Assets/Script/Manager/AppChat.cs b/AxibugEmuOnline.Client/Assets/Script/Manager/AppChat.cs index 4ab2e28..c3b2634 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Manager/AppChat.cs +++ b/AxibugEmuOnline.Client/Assets/Script/Manager/AppChat.cs @@ -26,7 +26,7 @@ namespace AxibugEmuOnline.Client.Manager public void RecvChatMsg(byte[] reqData) { Protobuf_ChatMsg_RESP msg = ProtoBufHelper.DeSerizlize(reqData); - EventSystem.Instance.PostEvent(EEvent.OnChatMsg, msg.NickName, msg.ChatMsg); + Eventer.Instance.PostEvent(EEvent.OnChatMsg, msg.NickName, msg.ChatMsg); } } } diff --git a/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs b/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs index c07def7..6517770 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs +++ b/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs @@ -5,34 +5,33 @@ namespace AxibugEmuOnline.Client.Manager { public class AppEmu { + private GameObject m_emuInstance; + public void BeginGame(RomFile romFile) { - if (InGameUI.Instance.Enable) return; + if (m_emuInstance != null) return; switch (romFile.Platform) { case EnumPlatform.NES: - App.SceneLoader.BeginLoad("Scene/Emu_NES", () => - { - var nesEmu = GameObject.FindObjectOfType(); - nesEmu.StartGame(romFile); + var nesEmu = GameObject.Instantiate(Resources.Load("NES/NesEmulator")).GetComponent(); + m_emuInstance = nesEmu.gameObject; - LaunchUI.Instance.HideMainMenu(); - InGameUI.Instance.Show(romFile, nesEmu); - }); + nesEmu.StartGame(romFile); + LaunchUI.Instance.HideMainMenu(); + InGameUI.Instance.Show(romFile, nesEmu); break; } } public void StopGame() { - if (!InGameUI.Instance.enabled) return; + if (m_emuInstance == null) return; + GameObject.Destroy(m_emuInstance); + m_emuInstance = null; - App.SceneLoader.BeginLoad("Scene/AxibugEmuOnline.Client", () => - { - InGameUI.Instance.Hide(); - LaunchUI.Instance.ShowMainMenu(); - }); + InGameUI.Instance.Hide(); + LaunchUI.Instance.ShowMainMenu(); } } } diff --git a/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs b/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs index 95a2ba4..5cb7458 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs +++ b/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs @@ -5,6 +5,7 @@ using AxibugEmuOnline.Client.Network; using AxibugProtobuf; using AxiReplay; using Google.Protobuf; +using System; using System.Collections.Generic; using System.Linq; @@ -182,7 +183,7 @@ namespace AxibugEmuOnline.Client.Manager Protobuf_Room_List_RESP msg = ProtoBufHelper.DeSerizlize(reqData); for (int i = 0; i < msg.RoomMiniInfoList.Count; i++) AddOrUpdateRoomList(msg.RoomMiniInfoList[i]); - EventSystem.Instance.PostEvent(EEvent.OnRoomListAllUpdate); + Eventer.Instance.PostEvent(EEvent.OnRoomListAllUpdate); } /// @@ -194,7 +195,7 @@ namespace AxibugEmuOnline.Client.Manager App.log.Debug("单个房间状态更新"); Protobuf_Room_Update_RESP msg = ProtoBufHelper.DeSerizlize(reqData); AddOrUpdateRoomList(msg.RoomMiniInfo); - EventSystem.Instance.PostEvent(EEvent.OnRoomListSingleUpdate, msg.RoomMiniInfo.GameRomID); + Eventer.Instance.PostEvent(EEvent.OnRoomListSingleUpdate, msg.RoomMiniInfo.GameRomID); } /// @@ -247,16 +248,18 @@ namespace AxibugEmuOnline.Client.Manager Protobuf_Room_Join_RESP msg = ProtoBufHelper.DeSerizlize(reqData); mineRoomMiniInfo = msg.RoomMiniInfo; InitRePlay(); - EventSystem.Instance.PostEvent(EEvent.OnMineJoinRoom); + Eventer.Instance.PostEvent(EEvent.OnMineJoinRoom); } /// /// 离开房间 /// /// - public void SendLeavnRoom(int RoomID) + public void SendLeavnRoom() { - _Protobuf_Room_Leave.RoomID = RoomID; + if (!InRoom) + return; + _Protobuf_Room_Leave.RoomID = mineRoomMiniInfo.RoomID; App.log.Info($"创建房间"); App.network.SendToServer((int)CommandID.CmdRoomLeave, ProtoBufHelper.Serizlize(_Protobuf_Room_Leave)); } @@ -271,7 +274,7 @@ namespace AxibugEmuOnline.Client.Manager Protobuf_Room_Leave_RESP msg = ProtoBufHelper.DeSerizlize(reqData); ReleaseRePlay(); mineRoomMiniInfo = null; - EventSystem.Instance.PostEvent(EEvent.OnMineLeavnRoom); + Eventer.Instance.PostEvent(EEvent.OnMineLeavnRoom); } void RecvRoomMyRoomStateChange(byte[] reqData) @@ -289,12 +292,12 @@ namespace AxibugEmuOnline.Client.Manager //位置之前有人,但是离开了 if (OldPlayer > 0) { - EventSystem.Instance.PostEvent(EEvent.OnOtherPlayerLeavnRoom, i, OldPlayer); + Eventer.Instance.PostEvent(EEvent.OnOtherPlayerLeavnRoom, i, OldPlayer); if (NewPlayer > 0)//而且害换了一个玩家 - EventSystem.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer); + Eventer.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer); } else //之前没人 - EventSystem.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer); + Eventer.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer); } } @@ -320,7 +323,7 @@ namespace AxibugEmuOnline.Client.Manager if (WaitStep != msg.WaitStep) { WaitStep = msg.WaitStep; - EventSystem.Instance.PostEvent(EEvent.OnRoomWaitStepChange, WaitStep); + Eventer.Instance.PostEvent(EEvent.OnRoomWaitStepChange, WaitStep); if (WaitStep == 1) { byte[] decompressRawData = Helper.DecompressByteArray(msg.LoadStateRaw.ToByteArray()); @@ -375,6 +378,6 @@ namespace AxibugEmuOnline.Client.Manager Protobuf_Screnn_Frame msg = ProtoBufHelper.DeSerizlize(reqData); //解压 byte[] data = Helper.DecompressByteArray(msg.RawBitmap.ToArray()); - } + } } } \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Script/Manager/RomLib/RomFile.cs b/AxibugEmuOnline.Client/Assets/Script/Manager/RomLib/RomFile.cs index bde787d..5dc30e9 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Manager/RomLib/RomFile.cs +++ b/AxibugEmuOnline.Client/Assets/Script/Manager/RomLib/RomFile.cs @@ -41,6 +41,7 @@ namespace AxibugEmuOnline.Client public int Index { get; private set; } /// 在查询结果中的所在页 public int Page { get; private set; } + public string Hash => webData != null ? webData.hash : string.Empty; public event Action OnDownloadOver; public event Action OnInfoFilled; diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/CoreSupporter.cs b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/CoreSupporter.cs index 959e513..e37caf3 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/CoreSupporter.cs +++ b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/CoreSupporter.cs @@ -1,6 +1,8 @@ using AxibugEmuOnline.Client.ClientCore; +using AxiReplay; using System; using System.IO; +using System.Runtime.InteropServices; using UnityEngine; using VirtualNes.Core; @@ -90,10 +92,79 @@ namespace AxibugEmuOnline.Client return db.GetMapperNo(rom.GetPROM_CRC(), out mapperNo); } + private ControllerState m_sampledState; public ControllerState GetControllerState() { - var mapper = NesControllerMapper.Get(); - return mapper.CreateState(); + if (!InGameUI.Instance.IsOnline) + { + return m_sampledState; + } + else + { + //todo : ӷȡ֡ + return default; + } + } + + public void SampleInput() + { + if (InGameUI.Instance.IsOnline) + { + if (App.roomMgr.netReplay.NextFrame(out var replayData, out int _)) + { + m_sampledState = FromNet(replayData); + var localState = NesControllerMapper.Get().CreateState(); + var rawData = ToNet(localState); + App.roomMgr.SendRoomSingelPlayerInput((uint)App.roomMgr.netReplay.mCurrPlayFrame, rawData); + } + else + { + m_sampledState = default; + } + } + else + { + m_sampledState = NesControllerMapper.Get().CreateState(); + } + } + + public ControllerState FromNet(AxiReplay.ReplayStep step) + { + var temp = new ServerInputSnapShot(); + var result = new ControllerState(); + temp.all = step.InPut; + result.raw0 = temp.p1; + result.raw1 = temp.p2; + result.raw2 = temp.p3; + result.raw3 = temp.p4; + result.valid = true; + + return result; + } + + public uint ToNet(ControllerState state) + { + var temp = new ServerInputSnapShot(); + temp.p1 = (byte)state.raw0; + temp.p2 = (byte)state.raw1; + temp.p3 = (byte)state.raw2; + temp.p4 = (byte)state.raw3; + return (uint)temp.all; + } + + [StructLayout(LayoutKind.Explicit, Size = 8)] + struct ServerInputSnapShot + { + [FieldOffset(0)] + public UInt64 all; + [FieldOffset(0)] + public byte p1; + [FieldOffset(1)] + public byte p2; + [FieldOffset(2)] + public byte p3; + [FieldOffset(3)] + public byte p4; } } } diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesControllerMapper.cs b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesControllerMapper.cs index 867ae99..e6adeee 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesControllerMapper.cs +++ b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesControllerMapper.cs @@ -87,6 +87,8 @@ namespace AxibugEmuOnline.Client public Mapper START = new Mapper(EnumButtonType.START); public Mapper MIC = new Mapper(EnumButtonType.MIC); + + public EnumButtonType GetButtons() { EnumButtonType res = 0; diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs index 67371d2..5d458ab 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs +++ b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs @@ -8,14 +8,13 @@ using VirtualNes.Core.Debug; namespace AxibugEmuOnline.Client { - public class NesEmulator : MonoBehaviour - { + { public NES NesCore { get; private set; } public VideoProvider VideoProvider; public AudioProvider AudioProvider; - + public bool m_bPause; private void Start() { @@ -50,9 +49,16 @@ namespace AxibugEmuOnline.Client private void Update() { + if (m_bPause) return; + if (NesCore != null) { + Supporter.SampleInput(); var controlState = Supporter.GetControllerState(); + + //δյInput,֡ƽ + if (!controlState.valid) return; + NesCore.pad.Sync(controlState); NesCore.EmulateFrame(true); @@ -62,6 +68,17 @@ namespace AxibugEmuOnline.Client } } + + public void Pause() + { + m_bPause = true; + } + + public void Resume() + { + m_bPause = false; + } + #if UNITY_EDITOR [ContextMenu("ImportNesDB")] public void ImportNesDB() diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs index f99d8e8..5cd0b30 100644 --- a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs @@ -1,5 +1,9 @@ +using AxibugEmuOnline.Client.ClientCore; +using AxibugEmuOnline.Client.Event; +using AxibugEmuOnline.Client.Manager; using System; using System.Collections.Generic; +using VirtualNes.Core; namespace AxibugEmuOnline.Client { @@ -9,17 +13,28 @@ namespace AxibugEmuOnline.Client public RomFile RomFile => m_rom; public override bool Enable => gameObject.activeInHierarchy; + + /// ָʾϷʵǷģʽ + public bool IsOnline => App.roomMgr.RoomState > AxibugProtobuf.RoomGameState.OnlyHost; + private RomFile m_rom; private object m_core; private object m_state; - private InGameUI_SaveState m_saveStateMenu; - private InGameUI_LoadState m_loadStateMenu; + private List menus = new List(); + private StepPerformer m_stepPerformer; protected override void Awake() { Instance = this; gameObject.SetActiveEx(false); + + m_stepPerformer = new StepPerformer(this); + + menus.Add(new InGameUI_SaveState(this)); + menus.Add(new InGameUI_LoadState(this)); + menus.Add(new InGameUI_QuitGame(this)); + base.Awake(); } @@ -56,22 +71,31 @@ namespace AxibugEmuOnline.Client { return false; } - } public void Show(RomFile currentRom, object core) { CommandDispatcher.Instance.RegistController(this); - m_saveStateMenu = new InGameUI_SaveState(this); - m_loadStateMenu = new InGameUI_LoadState(this); - m_rom = currentRom; m_core = core; + m_stepPerformer.Reset(); + + if (App.user.IsLoggedIn) + { + App.roomMgr.SendCreateRoom(m_rom.ID, 0, m_rom.Hash); + } + + Eventer.Instance.RegisterEvent(EEvent.OnRoomWaitStepChange, OnServerStepUpdate); gameObject.SetActiveEx(true); } + private void OnServerStepUpdate(int step) + { + m_stepPerformer.Perform(step); + } + public void Hide() { CommandDispatcher.Instance.UnRegistController(this); @@ -81,7 +105,14 @@ namespace AxibugEmuOnline.Client protected override void OnCmdOptionMenu() { - OptionUI.Instance.Pop(new List { m_saveStateMenu, m_loadStateMenu }); + OptionUI.Instance.Pop(menus); + } + + public void QuitGame() + { + Eventer.Instance.UnregisterEvent(EEvent.OnRoomWaitStepChange, OnServerStepUpdate); + App.roomMgr.SendLeavnRoom(); + App.emu.StopGame(); } } } diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs index 8a4863d..e36a63b 100644 --- a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs @@ -7,6 +7,7 @@ namespace AxibugEmuOnline.Client public class InGameUI_LoadState : ExecuteMenu { private InGameUI m_gameUI; + public override bool Visible => !m_gameUI.IsOnline; public InGameUI_LoadState(InGameUI gameUI) : base("ȡ", null) { diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_QuitGame.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_QuitGame.cs new file mode 100644 index 0000000..f16faca --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_QuitGame.cs @@ -0,0 +1,18 @@ +namespace AxibugEmuOnline.Client +{ + public class InGameUI_QuitGame : ExecuteMenu + { + private InGameUI m_gameUI; + + + public InGameUI_QuitGame(InGameUI gameUI) : base("˳", null) + { + m_gameUI = gameUI; + } + + public override void OnExcute() + { + m_gameUI.QuitGame(); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_QuitGame.cs.meta b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_QuitGame.cs.meta new file mode 100644 index 0000000..9cc1510 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_QuitGame.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7689fa8f7ddd5654f914b93a4f0efada +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 4bfc095..871873c 100644 --- a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs @@ -1,5 +1,7 @@ using AxibugEmuOnline.Client.ClientCore; using System.Diagnostics; +using System.Security.Cryptography; +using System.Text; namespace AxibugEmuOnline.Client { @@ -7,6 +9,8 @@ namespace AxibugEmuOnline.Client { private InGameUI m_gameUI; + public override bool Visible => !m_gameUI.IsOnline; + public InGameUI_SaveState(InGameUI gameUI) : base("", null) { m_gameUI = gameUI; @@ -20,7 +24,6 @@ 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; } sw.Stop(); diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/StepPerformer.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/StepPerformer.cs new file mode 100644 index 0000000..90a595f --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/StepPerformer.cs @@ -0,0 +1,75 @@ +using AxibugEmuOnline.Client.ClientCore; +using System; +using VirtualNes.Core; + +namespace AxibugEmuOnline.Client +{ + public class StepPerformer + { + private InGameUI m_inGameUI; + private int m_step = -1; + + public StepPerformer(InGameUI inGameUI) + { + m_inGameUI = inGameUI; + } + + public void Perform(int step) + { + m_step = step; + + + switch (m_step) + { + //等待主机上报快照 + case 0: + PauseCore(); + if (App.roomMgr.IsHost) + { + if (m_inGameUI.RomFile.Platform == EnumPlatform.NES) + { + var stateRaw = m_inGameUI.GetCore().NesCore.GetState().ToBytes(); + App.roomMgr.SendHostRaw(stateRaw); + } + } + break; + //加载存档并发送Ready通知 + case 1: + PauseCore(); + var state = new State(); + state.FromByte(App.roomMgr.RawData); + if (m_inGameUI.RomFile.Platform == EnumPlatform.NES) + { + m_inGameUI.GetCore().NesCore.LoadState(state); + } + App.roomMgr.SendRoomPlayerReady(); + break; + case 2: + m_step = -1; + ResumeCore(); + break; + } + } + + private void PauseCore() + { + if (m_inGameUI.RomFile.Platform == EnumPlatform.NES) + { + m_inGameUI.GetCore().Pause(); + } + } + + private void ResumeCore() + { + if (m_inGameUI.RomFile.Platform == EnumPlatform.NES) + { + m_inGameUI.GetCore().Resume(); + } + } + + internal void Reset() + { + m_step = -1; + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/StepPerformer.cs.meta b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/StepPerformer.cs.meta new file mode 100644 index 0000000..3ed241c --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/StepPerformer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6e5033cf98f86804bb50f84e3bbc956a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs b/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs index 46fe147..05f4525 100644 --- a/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs +++ b/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs @@ -62,6 +62,54 @@ namespace AxibugEmuOnline.Client MenuRoot.anchoredPosition = temp; } + protected override void Update() + { + UpdateMenuState(); + } + + private void UpdateMenuState() + { + bool dirty = false; + foreach (var menuItem in m_runtimeMenuItems) + { + if (menuItem.gameObject.activeSelf != menuItem.Visible) + { + dirty = true; + menuItem.gameObject.SetActive(menuItem.Visible); + } + } + if (dirty) + { + if (m_runtimeMenuItems[SelectIndex].Visible == false) + { + bool find = false; + int currentSelect = SelectIndex; + while (currentSelect >= 0) + { + currentSelect--; + if (m_runtimeMenuItems[currentSelect].Visible) + { + find = true; + } + } + if (!find) + { + currentSelect = SelectIndex; + while (currentSelect < m_runtimeMenuItems.Count) + { + if (m_runtimeMenuItems[currentSelect].Visible) + { + find = true; + } + } + } + + if (find) + SelectIndex = currentSelect; + } + } + } + public void Pop(List menus, int defaultIndex = 0) { ReleaseRuntimeMenus(); @@ -83,6 +131,7 @@ namespace AxibugEmuOnline.Client if (!m_bPoped) { m_bPoped = true; + DOTween.To( () => MenuRoot.anchoredPosition.x, (value) => @@ -94,6 +143,7 @@ namespace AxibugEmuOnline.Client 0, 0.3f ).SetEase(Ease.OutCubic); + } } @@ -101,10 +151,11 @@ namespace AxibugEmuOnline.Client { if (m_bPoped) { + m_runtimeMenuItems.Clear(); + SelectBorder.gameObject.SetActiveEx(false); CommandDispatcher.Instance.UnRegistController(this); - m_bPoped = false; Canvas.ForceUpdateCanvases(); var width = MenuRoot.rect.width; DOTween.To( @@ -118,6 +169,8 @@ namespace AxibugEmuOnline.Client width, 0.3f ).SetEase(Ease.OutCubic); + + m_bPoped = false; } } diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI_MenuItem.cs b/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI_MenuItem.cs index c9e82b0..7115085 100644 --- a/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI_MenuItem.cs +++ b/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI_MenuItem.cs @@ -12,6 +12,8 @@ namespace AxibugEmuOnline.Client [SerializeField] Text m_MenuNameTxt; [SerializeField] Image m_Icon; + public bool Visible => m_Menu.Visible; + protected OptionMenu m_Menu; public void SetData(OptionMenu menuData) diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs index c9003cb..4fe612a 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs @@ -1,4 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Serialization.Formatters.Binary; namespace VirtualNes.Core { @@ -42,20 +46,25 @@ namespace VirtualNes.Core HEADER.SaveState(buffer); + buffer.Write(WRAM != null ? WRAM.Length : 0); + buffer.Write(CPU_MEM_BANK != null ? CPU_MEM_BANK.Count : 0); + buffer.Write(VRAM != null ? VRAM.Length : 0); + buffer.Write(CRAM != null ? CRAM.Count : 0); + buffer.Write(dskdata != null ? dskdata.Count : 0); + if (regBLOCK.Valid) { regBLOCK.SaveState(buffer); reg.SaveState(buffer); } - if (regBLOCK.Valid) + if (ramBLOCK.Valid) { ramBLOCK.SaveState(buffer); ram.SaveState(buffer); + if (WRAM != null) buffer.Write(WRAM); } - if (WRAM != null) buffer.Write(WRAM); - if (mmuBLOCK.Valid) { mmuBLOCK.SaveState(buffer); @@ -101,5 +110,69 @@ namespace VirtualNes.Core return buffer.Data.ToArray(); } + public void FromByte(byte[] data) + { + StateReader buffer = new StateReader(data); + + HEADER.LoadState(buffer); + + var WRAM_Length = buffer.Read_int(); + var CPU_MEM_BANK_Length = buffer.Read_int(); + var VRAM_Length = buffer.Read_int(); + var CRAM_Length = buffer.Read_int(); + var dskdata_Length = buffer.Read_int(); + + while (buffer.Remain > 0) + { + BLOCKHDR block = new BLOCKHDR(); + block.LoadState(buffer); + + switch (block.ID) + { + case "REG DATA": + regBLOCK = block; + reg.LoadState(buffer); + break; + case "RAM DATA": + ramBLOCK = block; + ram.LoadState(buffer); + if (WRAM_Length > 0) + WRAM = buffer.Read_bytes(WRAM_Length); + break; + case "MMU DATA": + mmuBLOCK = block; + mmu.LoadState(buffer); + if (CPU_MEM_BANK_Length > 0) + CPU_MEM_BANK = new List(buffer.Read_bytes(CPU_MEM_BANK_Length)); + if (VRAM_Length > 0) + VRAM = buffer.Read_bytes(VRAM_Length); + if (CRAM_Length > 0) + CRAM = new List(buffer.Read_bytes(CRAM_Length)); + break; + case "MMC DATA": + mmcBLOCK = block; + mmc.LoadState(buffer); + break; + case "CTR DATA": + ctrBLOCK = block; + ctr.LoadState(buffer); + break; + case "SND DATA": + sndBLOCK = block; + snd.LoadState(buffer); + break; + case "DISKDATA": + dskBLOCK = block; + dsk.LoadState(buffer); + if (dskdata_Length > 0) + dskdata = new List(buffer.Read_uints(dskdata_Length)); + break; + case "EXCTRDAT": + exctrBLOCK = block; + exctr.LoadState(buffer); + break; + } + } + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs index e496cc3..a419ed2 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs @@ -85,6 +85,9 @@ namespace VirtualNes.Core public class StateReader { private MemoryStream m_dataStream; + + public long Remain => m_dataStream.Length - 1 - m_dataStream.Position; + public StateReader(byte[] bytes) { m_dataStream = new MemoryStream(bytes); @@ -125,10 +128,10 @@ namespace VirtualNes.Core ushort[] result = new ushort[length]; for (int i = 0; i < length; i++) { - int byte1 = m_dataStream.ReadByte(); - int byte2 = m_dataStream.ReadByte(); + TEMP[0] = (byte)m_dataStream.ReadByte(); + TEMP[1] = (byte)m_dataStream.ReadByte(); - result[i] = (ushort)(byte1 << 8 | byte2); + result[i] = BitConverter.ToUInt16(TEMP, 0); } return result; @@ -138,12 +141,12 @@ namespace VirtualNes.Core 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(); + TEMP[0] = (byte)m_dataStream.ReadByte(); + TEMP[1] = (byte)m_dataStream.ReadByte(); + TEMP[2] = (byte)m_dataStream.ReadByte(); + TEMP[3] = (byte)m_dataStream.ReadByte(); - result[i] = byte1 << 24 | byte2 << 16 | byte3 << 8 | byte4; + result[i] = BitConverter.ToInt32(TEMP, 0); } return result; @@ -160,21 +163,23 @@ namespace VirtualNes.Core var result = Read_bytes(4); return BitConverter.ToDouble(result, 0); } + + byte[] TEMP = new byte[8]; + public ushort Read_ushort() { - var b1 = Read_byte(); - var b2 = Read_byte(); - return (ushort)(b1 << 8 | b2); + TEMP[0] = Read_byte(); + TEMP[1] = Read_byte(); + return BitConverter.ToUInt16(TEMP, 0); } 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; + TEMP[0] = Read_byte(); + TEMP[1] = Read_byte(); + TEMP[2] = Read_byte(); + TEMP[3] = Read_byte(); + return BitConverter.ToInt32(TEMP, 0); } public sbyte Read_sbyte(sbyte value) @@ -183,22 +188,32 @@ namespace VirtualNes.Core } 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(); + TEMP[0] = Read_byte(); + TEMP[1] = Read_byte(); + TEMP[2] = Read_byte(); + TEMP[3] = Read_byte(); + TEMP[4] = Read_byte(); + TEMP[5] = Read_byte(); + TEMP[6] = Read_byte(); + TEMP[7] = Read_byte(); - return b1 << 56 | b2 << 48 | b3 << 40 | b4 << 32 | b5 << 24 | b6 << 16 | b7 << 8 | b8; + return BitConverter.ToInt64(TEMP, 0); } public uint Read_uint() { return (uint)Read_int(); } + + public uint[] Read_uints(int length) + { + uint[] ret = new uint[length]; + for (int i = 0; i < length; i++) + { + ret[i] = Read_uint(); + } + return ret; + } } public interface IStateBufferObject diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Supporter/ControllerState.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Supporter/ControllerState.cs index 418e35c..642b198 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Supporter/ControllerState.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Supporter/ControllerState.cs @@ -4,10 +4,12 @@ namespace VirtualNes.Core { public struct ControllerState { - private uint raw0; - private uint raw1; - private uint raw2; - private uint raw3; + public uint raw0; + public uint raw1; + public uint raw2; + public uint raw3; + + public bool valid; public ControllerState( EnumButtonType player0_buttons, @@ -19,6 +21,7 @@ namespace VirtualNes.Core raw1 = (uint)player1_buttons; raw2 = (uint)player2_buttons; raw3 = (uint)player3_buttons; + valid = true; } public bool HasButton(int player, EnumButtonType button) diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Supporter/Supporter.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Supporter/Supporter.cs index eb5a91f..3ecd65c 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Supporter/Supporter.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Supporter/Supporter.cs @@ -59,6 +59,11 @@ namespace VirtualNes.Core return s_support.GetControllerState(); } + public static void SampleInput() + { + s_support.SampleInput(); + } + public static EmulatorConfig Config => s_support.Config; } @@ -76,5 +81,6 @@ namespace VirtualNes.Core Stream OpenFile(string directPath, string fileName); bool TryGetMapperNo(ROM rom, out int mapperNo); ControllerState GetControllerState(); + void SampleInput(); } } diff --git a/AxibugEmuOnline.Server/Manager/RoomManager.cs b/AxibugEmuOnline.Server/Manager/RoomManager.cs index 71b4fc7..466bcd5 100644 --- a/AxibugEmuOnline.Server/Manager/RoomManager.cs +++ b/AxibugEmuOnline.Server/Manager/RoomManager.cs @@ -275,7 +275,7 @@ namespace AxibugEmuOnline.Server ServerInputSnapShot temp = new ServerInputSnapShot(); temp.all = msg.InputData; - room.SetPlayerInput(_c.RoomState.PlayerIdx, msg.FrameID, temp.p1); + room.SetPlayerInput(_c.RoomState.PlayerIdx, msg.FrameID, temp.p1_byte); } public void OnCmdScreen(Socket sk, byte[] reqData) @@ -560,10 +560,10 @@ namespace AxibugEmuOnline.Server { switch (PlayerIdx) { - case 0: mCurrInputData.p1 = 0; break; - case 1: mCurrInputData.p2 = 0; break; - case 2: mCurrInputData.p3 = 0; break; - case 3: mCurrInputData.p4 = 0; break; + case 0: mCurrInputData.p1_byte = 0; break; + case 1: mCurrInputData.p2_byte = 0; break; + case 2: mCurrInputData.p3_byte = 0; break; + case 3: mCurrInputData.p4_byte = 0; break; } } diff --git a/AxibugEmuOnline.Server/Program.cs b/AxibugEmuOnline.Server/Program.cs index 5bd6188..09bd0d3 100644 --- a/AxibugEmuOnline.Server/Program.cs +++ b/AxibugEmuOnline.Server/Program.cs @@ -29,10 +29,10 @@ namespace AxibugEmuOnline.Server AppSrv.g_Log.Info($"HostUID:{room.HostUID}"); AppSrv.g_Log.Info($"mCurrFrameId:{room.mCurrFrameId}"); AppSrv.g_Log.Info($"input all:{room.mCurrInputData.all}"); - AppSrv.g_Log.Info($"input p1:{room.mCurrInputData.p1}"); - AppSrv.g_Log.Info($"input p2:{room.mCurrInputData.p2}"); - AppSrv.g_Log.Info($"input p3:{room.mCurrInputData.p3}"); - AppSrv.g_Log.Info($"input p4:{room.mCurrInputData.p4}"); + AppSrv.g_Log.Info($"input p1:{room.mCurrInputData.p1_byte}"); + AppSrv.g_Log.Info($"input p2:{room.mCurrInputData.p2_byte}"); + AppSrv.g_Log.Info($"input p3:{room.mCurrInputData.p3_byte}"); + AppSrv.g_Log.Info($"input p4:{room.mCurrInputData.p4_byte}"); AppSrv.g_Log.Info($"GetPlayerCount:{room.GetPlayerCount()}"); for (int i = 0; i < 4; i++) { diff --git a/ProtobufCore/proto/protobuf_AxibugEmuOnline.proto b/ProtobufCore/proto/protobuf_AxibugEmuOnline.proto index 070dec0..4eb8666 100644 --- a/ProtobufCore/proto/protobuf_AxibugEmuOnline.proto +++ b/ProtobufCore/proto/protobuf_AxibugEmuOnline.proto @@ -34,7 +34,7 @@ enum CommandID // 主机玩家 上行 CMD_Room_HostPlayer_UpdateStateRaw消息,上传即时存档 // 主机玩家上传完毕之后,服务器会通知进入Step1 // - // Step1:服务器广播"等待-全员加载即时存档" CMD_Room_WaitStep WaitStep=[1] 附带即时存档 ---> 客户端:全员等待(主机玩家一人上传) + // Step1:服务器广播"等待-全员加载即时存档" CMD_Room_WaitStep WaitStep=[1] 附带即时存档 ---> 客户端:全员等待 // 所有玩家确保加载ROM和即时存档,并保持模拟器暂停,准备完毕后 发送 CMD_Room_Player_Ready // 所有玩家Ready之后,服务器会根据所有玩家延迟提前跑若干Frame,通知进入Step2 //