diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs index 1dee7cf..0db022f 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiReplay/NetReplay.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using UnityEngine; namespace AxiReplay { @@ -113,7 +114,7 @@ namespace AxiReplay if (frameGap > 10000) return 0; int skip = 0; - + if (frameGap <= 2) skip = 0; if (frameGap > 2 && frameGap < 6) skip = 1 + 1; else if (frameGap > 7 && frameGap < 12) skip = 2 + 1; diff --git a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/XMBTopGroup.prefab b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/XMBTopGroup.prefab index 8cdad0a..9baf683 100644 --- a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/XMBTopGroup.prefab +++ b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/XMBTopGroup.prefab @@ -265,6 +265,7 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: + - {fileID: 4541943946029862829} - {fileID: 2005113594707322973} - {fileID: 4195056312044822544} - {fileID: 1746243318642131728} @@ -320,6 +321,7 @@ MonoBehaviour: imgPower2: {fileID: 7232861150095392420} imgPower3: {fileID: 6694955234077232327} DelayValue: {fileID: 6486398873987280650} + FPS: {fileID: 2545793518460288919} --- !u!1 &5629957813601835122 GameObject: m_ObjectHideFlags: 0 @@ -352,7 +354,7 @@ RectTransform: m_Children: - {fileID: 1735688216191931001} m_Father: {fileID: 5353336693430589123} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -417,6 +419,85 @@ MonoBehaviour: m_FlexibleWidth: -1 m_FlexibleHeight: -1 m_LayoutPriority: 1 +--- !u!1 &5634255875545658264 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4541943946029862829} + - component: {fileID: 3282993275160308839} + - component: {fileID: 2545793518460288919} + m_Layer: 5 + m_Name: FPS + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4541943946029862829 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5634255875545658264} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5353336693430589123} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 53} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3282993275160308839 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5634255875545658264} + m_CullTransparentMesh: 1 +--- !u!114 &2545793518460288919 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5634255875545658264} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 55 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: FPS:60 --- !u!1 &6140890295709974557 GameObject: m_ObjectHideFlags: 0 @@ -523,7 +604,7 @@ RectTransform: - {fileID: 1777012203952456443} - {fileID: 7158194035478552859} m_Father: {fileID: 5353336693430589123} - m_RootOrder: 0 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -586,7 +667,7 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 5353336693430589123} - m_RootOrder: 1 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} diff --git a/AxibugEmuOnline.Client/Assets/Script/IEmuCore.cs b/AxibugEmuOnline.Client/Assets/Script/IEmuCore.cs index 1a8d20e..68a5df8 100644 --- a/AxibugEmuOnline.Client/Assets/Script/IEmuCore.cs +++ b/AxibugEmuOnline.Client/Assets/Script/IEmuCore.cs @@ -15,6 +15,7 @@ namespace AxibugEmuOnline.Client void SetupScheme(); void StartGame(RomFile romFile); void DoReset(); + uint Frame { get; } } public static class IEnumCoreTool diff --git a/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs b/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs index 3a7df7d..b16b04f 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs +++ b/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs @@ -13,6 +13,11 @@ namespace AxibugEmuOnline.Client.Manager /// 但是Equals方法可以,所以,这个接口判断为空请使用Equals /// private IEmuCore m_emuCore; + /// + /// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符 + /// 但是Equals方法可以,所以,这个接口判断为空请使用Equals + /// + public IEmuCore Core => m_emuCore; public AppEmu() { diff --git a/AxibugEmuOnline.Client/Assets/Script/Manager/AppSettings/BgColorSettings.cs b/AxibugEmuOnline.Client/Assets/Script/Manager/AppSettings/BgColorSettings.cs index 8d0ac3f..4055080 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Manager/AppSettings/BgColorSettings.cs +++ b/AxibugEmuOnline.Client/Assets/Script/Manager/AppSettings/BgColorSettings.cs @@ -5,6 +5,7 @@ using UnityEngine; namespace AxibugEmuOnline.Client { + /// 颜色设置 public class BgColorSettings { public delegate void OnColorChangedHandle(XMBColor color); diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/CoreSupporter.cs b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/CoreSupporter.cs index 1d325f0..bd6fc1d 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/CoreSupporter.cs +++ b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/CoreSupporter.cs @@ -112,21 +112,17 @@ namespace AxibugEmuOnline.Client } m_sampledState = FromNet(replayData); - var localState = NesControllerMapper.Get().CreateState(); - var rawData = ToNet(localState); - if (LastTestInput != rawData) - { - LastTestInput = rawData; - App.log.Debug($"{DateTime.Now.ToString("hh:mm:ss.fff")} Input F:{App.roomMgr.netReplay.mCurrClientFrameIdx} | I:{rawData}"); - } - App.roomMgr.SendRoomSingelPlayerInput(frameIndex, rawData); } - else + else m_sampledState = default; + + var localState = NesControllerMapper.Get().CreateState(); + var rawData = ToNet(localState); + if (LastTestInput != rawData) { - //App.log.Error($"Server Lag remoteFrame->{App.roomMgr.netReplay.mRemoteFrameIdx} diff->{frameDiff} " + - // $"frame=>{replayData.FrameStartID} InPut=>{replayData.InPut}"); - m_sampledState = default; + LastTestInput = rawData; + App.log.Debug($"{DateTime.Now.ToString("hh:mm:ss.fff")} Input F:{App.roomMgr.netReplay.mCurrClientFrameIdx} | I:{rawData}"); } + App.roomMgr.SendRoomSingelPlayerInput(frameIndex, rawData); } else { diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs index 8991bb1..5ff5c18 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs +++ b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs @@ -76,8 +76,7 @@ namespace AxibugEmuOnline.Client FixEmulatorFrame(); var screenBuffer = NesCore.ppu.GetScreenPtr(); - var lineColorMode = NesCore.ppu.GetLineColorMode(); - VideoProvider.SetDrawData(screenBuffer, lineColorMode, 277, 240); + VideoProvider.SetDrawData(screenBuffer); } } @@ -197,5 +196,7 @@ namespace AxibugEmuOnline.Client UnityEditor.EditorUtility.SetDirty(db); UnityEditor.AssetDatabase.SaveAssets(); } + + public uint Frame => NesCore.FrameCount; } } diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/VideoProvider.cs b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/VideoProvider.cs index 6d4196f..72de272 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/VideoProvider.cs +++ b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/VideoProvider.cs @@ -1,5 +1,7 @@ +using AxibugEmuOnline.Client.Common; using System; using System.Runtime.InteropServices; +using System.Text; using UnityEngine; using UnityEngine.UI; @@ -23,11 +25,10 @@ namespace AxibugEmuOnline.Client DrawCanvas.worldCamera = Camera.main; } - public unsafe void SetDrawData(uint* screenData, byte[] lineColorMode, int screenWidth, int screenHeight) + public unsafe void SetDrawData(uint* screenData) { if (wrapTex == null) { - //wrapTex = new Texture2D(272, 240, TextureFormat.BGRA32, false); wrapTex = new Texture2D(272, 240, TextureFormat.RGBA32, false); wrapTex.filterMode = FilterMode.Point; @@ -36,7 +37,7 @@ namespace AxibugEmuOnline.Client Image.texture = wrapTex; Image.material.SetTexture("_MainTex", wrapTex); - TexBufferSize = screenWidth * screenHeight * 4; + TexBufferSize = wrapTex.width * wrapTex.height * 4; var palRaw = PaletteDefine.m_cnPalette[0]; pPal = new Texture2D(palRaw.Length, 1, TextureFormat.RGBA32, false); diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/XMBTopGroupUI/XMBTopGroup.cs b/AxibugEmuOnline.Client/Assets/Script/UI/XMBTopGroupUI/XMBTopGroup.cs index 2076b6d..811a23d 100644 --- a/AxibugEmuOnline.Client/Assets/Script/UI/XMBTopGroupUI/XMBTopGroup.cs +++ b/AxibugEmuOnline.Client/Assets/Script/UI/XMBTopGroupUI/XMBTopGroup.cs @@ -12,6 +12,7 @@ public class XMBTopGroup : MonoBehaviour public Image imgPower2; public Image imgPower3; public Text DelayValue; + public Text FPS; void OnEnable() { @@ -29,6 +30,25 @@ public class XMBTopGroup : MonoBehaviour RefreshTime(); RefreshPower(); RefreshDelay(); + RefreshFps(); + } + + (uint lastFrame, float lastTime) m_lastFrameInfo; + private void RefreshFps() + { + if (App.emu.Core.IsNull()) + FPS.gameObject.SetActiveEx(false); + else + { + FPS.gameObject.SetActiveEx(true); + var gap = App.emu.Core.Frame - m_lastFrameInfo.lastFrame; + var time = Time.realtimeSinceStartup - m_lastFrameInfo.lastTime; + var fps = gap / time; + FPS.text = $"FPS:{fps:.#}"; + + m_lastFrameInfo.lastFrame = App.emu.Core.Frame; + m_lastFrameInfo.lastTime = Time.realtimeSinceStartup; + } } private void RefreshDelay() diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/MemoryUtility.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/MemoryUtility.cs index 1f9b1a1..f0bf58a 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/MemoryUtility.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/MemoryUtility.cs @@ -41,6 +41,34 @@ namespace VirtualNes.Core } } + public unsafe static void memset(byte* ptr, int offset, byte value, int length) + { + var offsetptr = ptr + offset; + for (int i = 0; i < length; i++) + { + offsetptr[i] = value; + } + } + + public unsafe static void memset(byte* ptr, byte value, int length) + { + memset(ptr, 0, value, length); + } + + public unsafe static void memset(uint* ptr, int offset, uint value, int length) + { + var offsetptr = ptr + offset; + for (int i = 0; i < length; i++) + { + offsetptr[i] = value; + } + } + + public unsafe static void memset(uint* ptr, uint value, int length) + { + memset(ptr, 0, value, length); + } + public static void memcpy(Array dst, Array src, int length) { Array.Copy(src, dst, length); diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs index 276aa57..7303287 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs @@ -221,10 +221,7 @@ namespace VirtualNes.Core Debuger.Log("Allocating PPU..."); ppu = new PPU(this); - var screenBuffer = new uint[PPU.SCREEN_WIDTH * PPU.SCREEN_HEIGHT]; - var colormode = new byte[PPU.SCREEN_HEIGHT]; - - ppu.SetScreenPtr(screenBuffer, colormode); + ppu.InitBuffer(); Debuger.Log("Allocating APU..."); apu = new APU(this); @@ -766,71 +763,9 @@ namespace VirtualNes.Core } } - if (bDraw) - { - DrawPad(); - } - FrameCount++; } - private void DrawPad() - { - if (m_bMoviePlay) - { - int offset_h = 12; - int offset_v = Supporter.Config.graphics.bAllLine ? (240 - 18) : (240 - 22); - - if (Supporter.Config.movie.bPadDisplay) - { - uint dwData = pad.GetSyncData(); - for (int i = 0; i < 4; i++) - { - byte Data = (byte)(dwData >> (i * 8)); - if ((m_MovieControl & (1 << i)) != 0) - { - DrawBitmap(offset_h, offset_v, m_PadImg); - - // KEY - if ((Data & (1 << 4)) != 0) DrawBitmap(offset_h + 3, offset_v + 1, m_KeyImg0); // U - if ((Data & (1 << 5)) != 0) DrawBitmap(offset_h + 3, offset_v + 5, m_KeyImg0); // D - if ((Data & (1 << 6)) != 0) DrawBitmap(offset_h + 1, offset_v + 3, m_KeyImg0); // L - if ((Data & (1 << 7)) != 0) DrawBitmap(offset_h + 5, offset_v + 3, m_KeyImg0); // R - - // START,SELECT - if ((Data & (1 << 2)) != 0) DrawBitmap(offset_h + 9, offset_v + 5, m_KeyImg1); // SELECT - if ((Data & (1 << 3)) != 0) DrawBitmap(offset_h + 13, offset_v + 5, m_KeyImg1); // START - - // A,B - if ((Data & (1 << 0)) != 0) DrawBitmap(offset_h + 23, offset_v + 3, m_KeyImg2); // A - if ((Data & (1 << 1)) != 0) DrawBitmap(offset_h + 18, offset_v + 3, m_KeyImg2); // B - - offset_h += 30; - } - } - } - - if (Supporter.Config.movie.bTimeDisplay) - { - // Time display - int t = m_MovieStep; - int h = t / 216000; - t -= h * 216000; - int m = t / 3600; - t -= m * 3600; - int s = t / 60; - t -= s * 60; - - string szTemp = $"{h:00}:{m:00}:{s:00}.{t * 100 / 60:00}"; - DrawString(256 - 80 + 0, offset_v - 1, szTemp, 0x1F); - DrawString(256 - 80 + 0, offset_v + 1, szTemp, 0x1F); - DrawString(256 - 80 - 1, offset_v + 0, szTemp, 0x1F); - DrawString(256 - 80 + 1, offset_v + 0, szTemp, 0x1F); - DrawString(256 - 80, offset_v, szTemp, 0x30); - } - } - } - internal void DrawString(int x, int y, string str, byte col) { foreach (var @char in str) @@ -866,33 +801,6 @@ namespace VirtualNes.Core } } - private unsafe void DrawBitmap(int x, int y, byte[] bitMap) - { - int i, j; - int h, v; - var Scn = ppu.GetScreenPtr(); - int pScn = 8 + (256 + 16) * y + x; - int pPtr; - - int lpBitmap = 0; - h = bitMap[lpBitmap++]; - v = bitMap[lpBitmap++]; - - for (j = 0; j < v; j++) - { - pPtr = pScn; - for (i = 0; i < h; i++) - { - if (bitMap[lpBitmap] != 0xFF) - { - Scn[pPtr] = bitMap[lpBitmap]; - } - lpBitmap++; - pPtr++; - } - pScn += 256 + 16; - } - } int CPU_CALL_COUNT = 0; internal void EmulationCPU(int basecycles) diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PPU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PPU.cs index 3c7ca00..c26f10c 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PPU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PPU.cs @@ -386,7 +386,7 @@ namespace VirtualNes.Core loopy_shift = 0; if (lpScreen != null) - Unsafe.InitBlockUnaligned(lpScreen, 0, SCREEN_WIDTH * SCREEN_HEIGHT); + MemoryUtility.memset(lpScreen, 0, 0, SCREEN_WIDTH * SCREEN_HEIGHT); if (lpColormode != null) MemoryUtility.memset(lpColormode, 0, SCREEN_HEIGHT); } @@ -402,7 +402,7 @@ namespace VirtualNes.Core if (lpScreen != null) { - Unsafe.InitBlockUnaligned(lpScreen, 0x3F, SCREEN_WIDTH); + MemoryUtility.memset(lpScreen, 0, 0x3f, SCREEN_WIDTH); } if (lpColormode != null) { @@ -457,8 +457,8 @@ namespace VirtualNes.Core { byte chr_h = 0, chr_l = 0, attr = 0; - Unsafe.InitBlockUnaligned(BGwrite, 0, 34); - Unsafe.InitBlockUnaligned(BGmono, 0, 34); + MemoryUtility.memset(BGwrite, 0, 34); + MemoryUtility.memset(BGmono, 0, 34); // Linecolor mode lpColormode[scanline] = (byte)(((MMU.PPUREG[1] & PPU_BGCOLOR_BIT) >> 5) | ((MMU.PPUREG[1] & PPU_COLORMODE_BIT) << 7)); @@ -466,7 +466,7 @@ namespace VirtualNes.Core // Render BG if ((MMU.PPUREG[1] & PPU_BGDISP_BIT) == 0) { - Unsafe.InitBlockUnaligned(lpScanline, MMU.BGPAL[0], SCREEN_WIDTH); + MemoryUtility.memset(lpScanline, MMU.BGPAL[0], SCREEN_WIDTH); if (nes.GetRenderMethod() == EnumRenderMethod.TILE_RENDER) { nes.EmulationCPU(NES.FETCH_CYCLES * 4 * 32); @@ -869,7 +869,7 @@ namespace VirtualNes.Core { byte* pBGw = BGwrite; byte* pSPw = SPwrite; - Unsafe.InitBlockUnaligned(pSPw, 0, 34); + MemoryUtility.memset(pSPw, 0, 34); spmax = 0; Sprite sp = new Sprite(MMU.SPRAM, 0); @@ -1092,8 +1092,11 @@ namespace VirtualNes.Core return lpColormode; } - internal void SetScreenPtr(uint[] screenBuffer, byte[] colormode) + internal void InitBuffer() { + var screenBuffer = new uint[SCREEN_WIDTH * SCREEN_HEIGHT]; + var colormode = new byte[SCREEN_HEIGHT]; + lpScreenGCH = GCHandle.Alloc(screenBuffer, GCHandleType.Pinned); lpScreen = (uint*)lpScreenGCH.AddrOfPinnedObject(); lpColormode = colormode; @@ -1180,11 +1183,16 @@ namespace VirtualNes.Core } } + [StructLayout(LayoutKind.Explicit, Size = 16)] public struct UInt128 { + [FieldOffset(0)] public UInt32 a; + [FieldOffset(4)] public UInt32 b; + [FieldOffset(8)] public UInt32 c; + [FieldOffset(12)] public UInt32 d; } }