Merge pull request 'master' (#54) from Alienjack/AxibugEmuOnline:master into master

Reviewed-on: #54
This commit is contained in:
sin365 2024-11-20 19:37:05 +08:00
commit a91d404944
12 changed files with 172 additions and 121 deletions

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine;
namespace AxiReplay namespace AxiReplay
{ {
@ -113,7 +114,7 @@ namespace AxiReplay
if (frameGap > 10000) return 0; if (frameGap > 10000) return 0;
int skip = 0; int skip = 0;
if (frameGap <= 2) skip = 0; if (frameGap <= 2) skip = 0;
if (frameGap > 2 && frameGap < 6) skip = 1 + 1; if (frameGap > 2 && frameGap < 6) skip = 1 + 1;
else if (frameGap > 7 && frameGap < 12) skip = 2 + 1; else if (frameGap > 7 && frameGap < 12) skip = 2 + 1;

View File

@ -265,6 +265,7 @@ RectTransform:
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: m_Children:
- {fileID: 4541943946029862829}
- {fileID: 2005113594707322973} - {fileID: 2005113594707322973}
- {fileID: 4195056312044822544} - {fileID: 4195056312044822544}
- {fileID: 1746243318642131728} - {fileID: 1746243318642131728}
@ -320,6 +321,7 @@ MonoBehaviour:
imgPower2: {fileID: 7232861150095392420} imgPower2: {fileID: 7232861150095392420}
imgPower3: {fileID: 6694955234077232327} imgPower3: {fileID: 6694955234077232327}
DelayValue: {fileID: 6486398873987280650} DelayValue: {fileID: 6486398873987280650}
FPS: {fileID: 2545793518460288919}
--- !u!1 &5629957813601835122 --- !u!1 &5629957813601835122
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -352,7 +354,7 @@ RectTransform:
m_Children: m_Children:
- {fileID: 1735688216191931001} - {fileID: 1735688216191931001}
m_Father: {fileID: 5353336693430589123} m_Father: {fileID: 5353336693430589123}
m_RootOrder: 2 m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0}
@ -417,6 +419,85 @@ MonoBehaviour:
m_FlexibleWidth: -1 m_FlexibleWidth: -1
m_FlexibleHeight: -1 m_FlexibleHeight: -1
m_LayoutPriority: 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 --- !u!1 &6140890295709974557
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -523,7 +604,7 @@ RectTransform:
- {fileID: 1777012203952456443} - {fileID: 1777012203952456443}
- {fileID: 7158194035478552859} - {fileID: 7158194035478552859}
m_Father: {fileID: 5353336693430589123} m_Father: {fileID: 5353336693430589123}
m_RootOrder: 0 m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0}
@ -586,7 +667,7 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: [] m_Children: []
m_Father: {fileID: 5353336693430589123} m_Father: {fileID: 5353336693430589123}
m_RootOrder: 1 m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0}

View File

@ -15,6 +15,7 @@ namespace AxibugEmuOnline.Client
void SetupScheme(); void SetupScheme();
void StartGame(RomFile romFile); void StartGame(RomFile romFile);
void DoReset(); void DoReset();
uint Frame { get; }
} }
public static class IEnumCoreTool public static class IEnumCoreTool

View File

@ -13,6 +13,11 @@ namespace AxibugEmuOnline.Client.Manager
/// 但是Equals方法可以,所以,这个接口判断为空请使用Equals /// 但是Equals方法可以,所以,这个接口判断为空请使用Equals
/// </summary> /// </summary>
private IEmuCore m_emuCore; private IEmuCore m_emuCore;
/// <summary>
/// unity的c#实现有bug,以接口类型保存的monobehaviour引用,!=和==运算符没有调用到monobehaviour重写过的运算符
/// 但是Equals方法可以,所以,这个接口判断为空请使用Equals
/// </summary>
public IEmuCore Core => m_emuCore;
public AppEmu() public AppEmu()
{ {

View File

@ -5,6 +5,7 @@ using UnityEngine;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
/// <summary> 颜色设置 </summary>
public class BgColorSettings public class BgColorSettings
{ {
public delegate void OnColorChangedHandle(XMBColor color); public delegate void OnColorChangedHandle(XMBColor color);

View File

@ -112,21 +112,17 @@ namespace AxibugEmuOnline.Client
} }
m_sampledState = FromNet(replayData); 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} " + LastTestInput = rawData;
// $"frame=>{replayData.FrameStartID} InPut=>{replayData.InPut}"); App.log.Debug($"{DateTime.Now.ToString("hh:mm:ss.fff")} Input F:{App.roomMgr.netReplay.mCurrClientFrameIdx} | I:{rawData}");
m_sampledState = default;
} }
App.roomMgr.SendRoomSingelPlayerInput(frameIndex, rawData);
} }
else else
{ {

View File

@ -76,8 +76,7 @@ namespace AxibugEmuOnline.Client
FixEmulatorFrame(); FixEmulatorFrame();
var screenBuffer = NesCore.ppu.GetScreenPtr(); var screenBuffer = NesCore.ppu.GetScreenPtr();
var lineColorMode = NesCore.ppu.GetLineColorMode(); VideoProvider.SetDrawData(screenBuffer);
VideoProvider.SetDrawData(screenBuffer, lineColorMode, 277, 240);
} }
} }
@ -197,5 +196,7 @@ namespace AxibugEmuOnline.Client
UnityEditor.EditorUtility.SetDirty(db); UnityEditor.EditorUtility.SetDirty(db);
UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.SaveAssets();
} }
public uint Frame => NesCore.FrameCount;
} }
} }

View File

@ -1,5 +1,7 @@
using AxibugEmuOnline.Client.Common;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
@ -23,11 +25,10 @@ namespace AxibugEmuOnline.Client
DrawCanvas.worldCamera = Camera.main; 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) if (wrapTex == null)
{ {
//wrapTex = new Texture2D(272, 240, TextureFormat.BGRA32, false);
wrapTex = new Texture2D(272, 240, TextureFormat.RGBA32, false); wrapTex = new Texture2D(272, 240, TextureFormat.RGBA32, false);
wrapTex.filterMode = FilterMode.Point; wrapTex.filterMode = FilterMode.Point;
@ -36,7 +37,7 @@ namespace AxibugEmuOnline.Client
Image.texture = wrapTex; Image.texture = wrapTex;
Image.material.SetTexture("_MainTex", wrapTex); Image.material.SetTexture("_MainTex", wrapTex);
TexBufferSize = screenWidth * screenHeight * 4; TexBufferSize = wrapTex.width * wrapTex.height * 4;
var palRaw = PaletteDefine.m_cnPalette[0]; var palRaw = PaletteDefine.m_cnPalette[0];
pPal = new Texture2D(palRaw.Length, 1, TextureFormat.RGBA32, false); pPal = new Texture2D(palRaw.Length, 1, TextureFormat.RGBA32, false);

View File

@ -12,6 +12,7 @@ public class XMBTopGroup : MonoBehaviour
public Image imgPower2; public Image imgPower2;
public Image imgPower3; public Image imgPower3;
public Text DelayValue; public Text DelayValue;
public Text FPS;
void OnEnable() void OnEnable()
{ {
@ -29,6 +30,25 @@ public class XMBTopGroup : MonoBehaviour
RefreshTime(); RefreshTime();
RefreshPower(); RefreshPower();
RefreshDelay(); 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() private void RefreshDelay()

View File

@ -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) public static void memcpy(Array dst, Array src, int length)
{ {
Array.Copy(src, dst, length); Array.Copy(src, dst, length);

View File

@ -221,10 +221,7 @@ namespace VirtualNes.Core
Debuger.Log("Allocating PPU..."); Debuger.Log("Allocating PPU...");
ppu = new PPU(this); ppu = new PPU(this);
var screenBuffer = new uint[PPU.SCREEN_WIDTH * PPU.SCREEN_HEIGHT]; ppu.InitBuffer();
var colormode = new byte[PPU.SCREEN_HEIGHT];
ppu.SetScreenPtr(screenBuffer, colormode);
Debuger.Log("Allocating APU..."); Debuger.Log("Allocating APU...");
apu = new APU(this); apu = new APU(this);
@ -766,71 +763,9 @@ namespace VirtualNes.Core
} }
} }
if (bDraw)
{
DrawPad();
}
FrameCount++; 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) internal void DrawString(int x, int y, string str, byte col)
{ {
foreach (var @char in str) 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; int CPU_CALL_COUNT = 0;
internal void EmulationCPU(int basecycles) internal void EmulationCPU(int basecycles)

View File

@ -386,7 +386,7 @@ namespace VirtualNes.Core
loopy_shift = 0; loopy_shift = 0;
if (lpScreen != null) if (lpScreen != null)
Unsafe.InitBlockUnaligned(lpScreen, 0, SCREEN_WIDTH * SCREEN_HEIGHT); MemoryUtility.memset(lpScreen, 0, 0, SCREEN_WIDTH * SCREEN_HEIGHT);
if (lpColormode != null) if (lpColormode != null)
MemoryUtility.memset(lpColormode, 0, SCREEN_HEIGHT); MemoryUtility.memset(lpColormode, 0, SCREEN_HEIGHT);
} }
@ -402,7 +402,7 @@ namespace VirtualNes.Core
if (lpScreen != null) if (lpScreen != null)
{ {
Unsafe.InitBlockUnaligned(lpScreen, 0x3F, SCREEN_WIDTH); MemoryUtility.memset(lpScreen, 0, 0x3f, SCREEN_WIDTH);
} }
if (lpColormode != null) if (lpColormode != null)
{ {
@ -457,8 +457,8 @@ namespace VirtualNes.Core
{ {
byte chr_h = 0, chr_l = 0, attr = 0; byte chr_h = 0, chr_l = 0, attr = 0;
Unsafe.InitBlockUnaligned(BGwrite, 0, 34); MemoryUtility.memset(BGwrite, 0, 34);
Unsafe.InitBlockUnaligned(BGmono, 0, 34); MemoryUtility.memset(BGmono, 0, 34);
// Linecolor mode // Linecolor mode
lpColormode[scanline] = (byte)(((MMU.PPUREG[1] & PPU_BGCOLOR_BIT) >> 5) | ((MMU.PPUREG[1] & PPU_COLORMODE_BIT) << 7)); 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 // Render BG
if ((MMU.PPUREG[1] & PPU_BGDISP_BIT) == 0) 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) if (nes.GetRenderMethod() == EnumRenderMethod.TILE_RENDER)
{ {
nes.EmulationCPU(NES.FETCH_CYCLES * 4 * 32); nes.EmulationCPU(NES.FETCH_CYCLES * 4 * 32);
@ -869,7 +869,7 @@ namespace VirtualNes.Core
{ {
byte* pBGw = BGwrite; byte* pBGw = BGwrite;
byte* pSPw = SPwrite; byte* pSPw = SPwrite;
Unsafe.InitBlockUnaligned(pSPw, 0, 34); MemoryUtility.memset(pSPw, 0, 34);
spmax = 0; spmax = 0;
Sprite sp = new Sprite(MMU.SPRAM, 0); Sprite sp = new Sprite(MMU.SPRAM, 0);
@ -1092,8 +1092,11 @@ namespace VirtualNes.Core
return lpColormode; 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); lpScreenGCH = GCHandle.Alloc(screenBuffer, GCHandleType.Pinned);
lpScreen = (uint*)lpScreenGCH.AddrOfPinnedObject(); lpScreen = (uint*)lpScreenGCH.AddrOfPinnedObject();
lpColormode = colormode; lpColormode = colormode;
@ -1180,11 +1183,16 @@ namespace VirtualNes.Core
} }
} }
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct UInt128 public struct UInt128
{ {
[FieldOffset(0)]
public UInt32 a; public UInt32 a;
[FieldOffset(4)]
public UInt32 b; public UInt32 b;
[FieldOffset(8)]
public UInt32 c; public UInt32 c;
[FieldOffset(12)]
public UInt32 d; public UInt32 d;
} }
} }