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

Reviewed-on: sin365/AxibugEmuOnline#37
This commit is contained in:
sin365 2024-09-14 17:38:09 +08:00
commit 7aa07500b2
27 changed files with 486 additions and 131 deletions

View File

@ -5,7 +5,7 @@ namespace AxiReplay
public class NetReplay
{
int MaxInFrame = 0;
int mCurrPlayFrame = -1;
public int mCurrPlayFrame = -1;
Queue<ReplayStep> mQueueReplay;
ReplayStep mNextReplay;
ReplayStep mCurrReplay;

View File

@ -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

View File

@ -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

View File

@ -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}

View File

@ -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<EEvent, List<Delegate>> eventDic = new Dictionary<EEvent, List<Delegate>>(128);
private EventSystem() { }
private Eventer() { }
#region RegisterEvent

View File

@ -26,7 +26,7 @@ namespace AxibugEmuOnline.Client.Manager
public void RecvChatMsg(byte[] reqData)
{
Protobuf_ChatMsg_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_ChatMsg_RESP>(reqData);
EventSystem.Instance.PostEvent(EEvent.OnChatMsg, msg.NickName, msg.ChatMsg);
Eventer.Instance.PostEvent(EEvent.OnChatMsg, msg.NickName, msg.ChatMsg);
}
}
}

View File

@ -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<NesEmulator>();
nesEmu.StartGame(romFile);
var nesEmu = GameObject.Instantiate(Resources.Load<GameObject>("NES/NesEmulator")).GetComponent<NesEmulator>();
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();
}
}
}

View File

@ -5,9 +5,9 @@ using AxibugEmuOnline.Client.Network;
using AxibugProtobuf;
using AxiReplay;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace AxibugEmuOnline.Client.Manager
{
@ -182,7 +182,7 @@ namespace AxibugEmuOnline.Client.Manager
Protobuf_Room_List_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_List_RESP>(reqData);
for (int i = 0; i < msg.RoomMiniInfoList.Count; i++)
AddOrUpdateRoomList(msg.RoomMiniInfoList[i]);
EventSystem.Instance.PostEvent(EEvent.OnRoomListAllUpdate);
Eventer.Instance.PostEvent(EEvent.OnRoomListAllUpdate);
}
/// <summary>
@ -194,7 +194,7 @@ namespace AxibugEmuOnline.Client.Manager
App.log.Debug("单个房间状态更新");
Protobuf_Room_Update_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Update_RESP>(reqData);
AddOrUpdateRoomList(msg.RoomMiniInfo);
EventSystem.Instance.PostEvent(EEvent.OnRoomListSingleUpdate, msg.RoomMiniInfo.GameRomID);
Eventer.Instance.PostEvent(EEvent.OnRoomListSingleUpdate, msg.RoomMiniInfo.GameRomID);
}
/// <summary>
@ -247,16 +247,18 @@ namespace AxibugEmuOnline.Client.Manager
Protobuf_Room_Join_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Join_RESP>(reqData);
mineRoomMiniInfo = msg.RoomMiniInfo;
InitRePlay();
EventSystem.Instance.PostEvent(EEvent.OnMineJoinRoom);
Eventer.Instance.PostEvent(EEvent.OnMineJoinRoom);
}
/// <summary>
/// 离开房间
/// </summary>
/// <param name="RoomID"></param>
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 +273,7 @@ namespace AxibugEmuOnline.Client.Manager
Protobuf_Room_Leave_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Leave_RESP>(reqData);
ReleaseRePlay();
mineRoomMiniInfo = null;
EventSystem.Instance.PostEvent(EEvent.OnMineLeavnRoom);
Eventer.Instance.PostEvent(EEvent.OnMineLeavnRoom);
}
void RecvRoomMyRoomStateChange(byte[] reqData)
@ -289,12 +291,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 +322,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());
@ -376,6 +378,11 @@ namespace AxibugEmuOnline.Client.Manager
Protobuf_Screnn_Frame msg = ProtoBufHelper.DeSerizlize<Protobuf_Screnn_Frame>(reqData);
//解压
byte[] data = Helper.DecompressByteArray(msg.RawBitmap.ToArray());
}
}
internal void SendHostRaw(byte[] stateRaw)
{
throw new NotImplementedException();
}
}
}

View File

@ -41,6 +41,7 @@ namespace AxibugEmuOnline.Client
public int Index { get; private set; }
/// <summary> 在查询结果中的所在页 </summary>
public int Page { get; private set; }
public string Hash => webData != null ? webData.hash : string.Empty;
public event Action OnDownloadOver;
public event Action OnInfoFilled;

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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()

View File

@ -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;
/// <summary> 指示该游戏实例是否处于联网模式 </summary>
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<OptionMenu> menus = new List<OptionMenu>();
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<int>(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<OptionMenu> { m_saveStateMenu, m_loadStateMenu });
OptionUI.Instance.Pop(menus);
}
public void QuitGame()
{
Eventer.Instance.UnregisterEvent<int>(EEvent.OnRoomWaitStepChange, OnServerStepUpdate);
App.roomMgr.SendLeavnRoom();
App.emu.StopGame();
}
}
}

View File

@ -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)
{

View File

@ -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();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7689fa8f7ddd5654f914b93a4f0efada
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<NesEmulator>().NesCore.GetState();
m_gameUI.SaveQuickState(state);
App.log.Info($"{m_gameUI.RomFile.Platform}===>快照大小{state.ToBytes().Length}");
break;
}
sw.Stop();

View File

@ -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<NesEmulator>().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<NesEmulator>().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<NesEmulator>().Pause();
}
}
private void ResumeCore()
{
if (m_inGameUI.RomFile.Platform == EnumPlatform.NES)
{
m_inGameUI.GetCore<NesEmulator>().Resume();
}
}
internal void Reset()
{
m_step = -1;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e5033cf98f86804bb50f84e3bbc956a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<OptionMenu> 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;
}
}

View File

@ -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)

View File

@ -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<byte>(buffer.Read_bytes(CPU_MEM_BANK_Length));
if (VRAM_Length > 0)
VRAM = buffer.Read_bytes(VRAM_Length);
if (CRAM_Length > 0)
CRAM = new List<byte>(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<uint>(buffer.Read_uints(dskdata_Length));
break;
case "EXCTRDAT":
exctrBLOCK = block;
exctr.LoadState(buffer);
break;
}
}
}
}
}

View File

@ -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

View File

@ -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)

View File

@ -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();
}
}

View File

@ -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之后FrameStep2
//