联网代码上传

This commit is contained in:
ALIENJACK\alien 2024-09-14 17:22:01 +08:00
parent fa8c642a69
commit 0babeed270
14 changed files with 239 additions and 29 deletions

View File

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

View File

@ -29,14 +29,14 @@ namespace AxibugEmuOnline.Client.Event
} }
} }
public class EventSystem public class Eventer
{ {
private static EventSystem instance = new EventSystem(); private static Eventer instance = new Eventer();
public static EventSystem Instance { get { return instance; } } public static Eventer Instance { get { return instance; } }
private Dictionary<EEvent, List<Delegate>> eventDic = new Dictionary<EEvent, List<Delegate>>(128); private Dictionary<EEvent, List<Delegate>> eventDic = new Dictionary<EEvent, List<Delegate>>(128);
private EventSystem() { } private Eventer() { }
#region RegisterEvent #region RegisterEvent

View File

@ -26,7 +26,7 @@ namespace AxibugEmuOnline.Client.Manager
public void RecvChatMsg(byte[] reqData) public void RecvChatMsg(byte[] reqData)
{ {
Protobuf_ChatMsg_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_ChatMsg_RESP>(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,9 +5,9 @@ using AxibugEmuOnline.Client.Network;
using AxibugProtobuf; using AxibugProtobuf;
using AxiReplay; using AxiReplay;
using Google.Protobuf; using Google.Protobuf;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine;
namespace AxibugEmuOnline.Client.Manager namespace AxibugEmuOnline.Client.Manager
{ {
@ -182,7 +182,7 @@ namespace AxibugEmuOnline.Client.Manager
Protobuf_Room_List_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_List_RESP>(reqData); Protobuf_Room_List_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_List_RESP>(reqData);
for (int i = 0; i < msg.RoomMiniInfoList.Count; i++) for (int i = 0; i < msg.RoomMiniInfoList.Count; i++)
AddOrUpdateRoomList(msg.RoomMiniInfoList[i]); AddOrUpdateRoomList(msg.RoomMiniInfoList[i]);
EventSystem.Instance.PostEvent(EEvent.OnRoomListAllUpdate); Eventer.Instance.PostEvent(EEvent.OnRoomListAllUpdate);
} }
/// <summary> /// <summary>
@ -194,7 +194,7 @@ namespace AxibugEmuOnline.Client.Manager
App.log.Debug("单个房间状态更新"); App.log.Debug("单个房间状态更新");
Protobuf_Room_Update_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Update_RESP>(reqData); Protobuf_Room_Update_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Update_RESP>(reqData);
AddOrUpdateRoomList(msg.RoomMiniInfo); AddOrUpdateRoomList(msg.RoomMiniInfo);
EventSystem.Instance.PostEvent(EEvent.OnRoomListSingleUpdate, msg.RoomMiniInfo.GameRomID); Eventer.Instance.PostEvent(EEvent.OnRoomListSingleUpdate, msg.RoomMiniInfo.GameRomID);
} }
/// <summary> /// <summary>
@ -247,7 +247,7 @@ namespace AxibugEmuOnline.Client.Manager
Protobuf_Room_Join_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Join_RESP>(reqData); Protobuf_Room_Join_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Join_RESP>(reqData);
mineRoomMiniInfo = msg.RoomMiniInfo; mineRoomMiniInfo = msg.RoomMiniInfo;
InitRePlay(); InitRePlay();
EventSystem.Instance.PostEvent(EEvent.OnMineJoinRoom); Eventer.Instance.PostEvent(EEvent.OnMineJoinRoom);
} }
/// <summary> /// <summary>
@ -273,7 +273,7 @@ namespace AxibugEmuOnline.Client.Manager
Protobuf_Room_Leave_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Leave_RESP>(reqData); Protobuf_Room_Leave_RESP msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Leave_RESP>(reqData);
ReleaseRePlay(); ReleaseRePlay();
mineRoomMiniInfo = null; mineRoomMiniInfo = null;
EventSystem.Instance.PostEvent(EEvent.OnMineLeavnRoom); Eventer.Instance.PostEvent(EEvent.OnMineLeavnRoom);
} }
void RecvRoomMyRoomStateChange(byte[] reqData) void RecvRoomMyRoomStateChange(byte[] reqData)
@ -291,12 +291,12 @@ namespace AxibugEmuOnline.Client.Manager
//位置之前有人,但是离开了 //位置之前有人,但是离开了
if (OldPlayer > 0) if (OldPlayer > 0)
{ {
EventSystem.Instance.PostEvent(EEvent.OnOtherPlayerLeavnRoom, i, OldPlayer); Eventer.Instance.PostEvent(EEvent.OnOtherPlayerLeavnRoom, i, OldPlayer);
if (NewPlayer > 0)//而且害换了一个玩家 if (NewPlayer > 0)//而且害换了一个玩家
EventSystem.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer); Eventer.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer);
} }
else //之前没人 else //之前没人
EventSystem.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer); Eventer.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer);
} }
} }
@ -322,7 +322,7 @@ namespace AxibugEmuOnline.Client.Manager
if (WaitStep != msg.WaitStep) if (WaitStep != msg.WaitStep)
{ {
WaitStep = msg.WaitStep; WaitStep = msg.WaitStep;
EventSystem.Instance.PostEvent(EEvent.OnRoomWaitStepChange, WaitStep); Eventer.Instance.PostEvent(EEvent.OnRoomWaitStepChange, WaitStep);
if (WaitStep == 1) if (WaitStep == 1)
{ {
byte[] decompressRawData = Helper.DecompressByteArray(msg.LoadStateRaw.ToByteArray()); byte[] decompressRawData = Helper.DecompressByteArray(msg.LoadStateRaw.ToByteArray());
@ -378,6 +378,11 @@ namespace AxibugEmuOnline.Client.Manager
Protobuf_Screnn_Frame msg = ProtoBufHelper.DeSerizlize<Protobuf_Screnn_Frame>(reqData); Protobuf_Screnn_Frame msg = ProtoBufHelper.DeSerizlize<Protobuf_Screnn_Frame>(reqData);
//解压 //解压
byte[] data = Helper.DecompressByteArray(msg.RawBitmap.ToArray()); byte[] data = Helper.DecompressByteArray(msg.RawBitmap.ToArray());
} }
internal void SendHostRaw(byte[] stateRaw)
{
throw new NotImplementedException();
}
} }
} }

View File

@ -1,6 +1,8 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxiReplay;
using System; using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using VirtualNes.Core; using VirtualNes.Core;
@ -90,10 +92,79 @@ namespace AxibugEmuOnline.Client
return db.GetMapperNo(rom.GetPROM_CRC(), out mapperNo); return db.GetMapperNo(rom.GetPROM_CRC(), out mapperNo);
} }
private ControllerState m_sampledState;
public ControllerState GetControllerState() public ControllerState GetControllerState()
{ {
var mapper = NesControllerMapper.Get(); if (!InGameUI.Instance.IsOnline)
return mapper.CreateState(); {
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 START = new Mapper(EnumButtonType.START);
public Mapper MIC = new Mapper(EnumButtonType.MIC); public Mapper MIC = new Mapper(EnumButtonType.MIC);
public EnumButtonType GetButtons() public EnumButtonType GetButtons()
{ {
EnumButtonType res = 0; EnumButtonType res = 0;

View File

@ -8,14 +8,13 @@ using VirtualNes.Core.Debug;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class NesEmulator : MonoBehaviour public class NesEmulator : MonoBehaviour
{ {
public NES NesCore { get; private set; } public NES NesCore { get; private set; }
public VideoProvider VideoProvider; public VideoProvider VideoProvider;
public AudioProvider AudioProvider; public AudioProvider AudioProvider;
public bool m_bPause;
private void Start() private void Start()
{ {
@ -50,9 +49,16 @@ namespace AxibugEmuOnline.Client
private void Update() private void Update()
{ {
if (m_bPause) return;
if (NesCore != null) if (NesCore != null)
{ {
Supporter.SampleInput();
var controlState = Supporter.GetControllerState(); var controlState = Supporter.GetControllerState();
//如果未收到Input数据,核心帧不推进
if (!controlState.valid) return;
NesCore.pad.Sync(controlState); NesCore.pad.Sync(controlState);
NesCore.EmulateFrame(true); 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 #if UNITY_EDITOR
[ContextMenu("ImportNesDB")] [ContextMenu("ImportNesDB")]
public void ImportNesDB() public void ImportNesDB()

View File

@ -1,7 +1,9 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.Manager; using AxibugEmuOnline.Client.Manager;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using VirtualNes.Core;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
@ -13,22 +15,26 @@ namespace AxibugEmuOnline.Client
public override bool Enable => gameObject.activeInHierarchy; public override bool Enable => gameObject.activeInHierarchy;
/// <summary> 指示该游戏实例是否处于联网模式 </summary> /// <summary> 指示该游戏实例是否处于联网模式 </summary>
public bool IsOnline => App.roomMgr.RoomState <= AxibugProtobuf.RoomGameState.OnlyHost; public bool IsOnline => App.roomMgr.RoomState > AxibugProtobuf.RoomGameState.OnlyHost;
private RomFile m_rom; private RomFile m_rom;
private object m_core; private object m_core;
private object m_state; private object m_state;
private List<OptionMenu> menus = new List<OptionMenu>(); private List<OptionMenu> menus = new List<OptionMenu>();
private StepPerformer m_stepPerformer;
protected override void Awake() protected override void Awake()
{ {
Instance = this; Instance = this;
gameObject.SetActiveEx(false); gameObject.SetActiveEx(false);
m_stepPerformer = new StepPerformer(this);
menus.Add(new InGameUI_SaveState(this)); menus.Add(new InGameUI_SaveState(this));
menus.Add(new InGameUI_LoadState(this)); menus.Add(new InGameUI_LoadState(this));
menus.Add(new InGameUI_QuitGame(this)); menus.Add(new InGameUI_QuitGame(this));
base.Awake(); base.Awake();
} }
@ -73,15 +79,23 @@ namespace AxibugEmuOnline.Client
m_rom = currentRom; m_rom = currentRom;
m_core = core; m_core = core;
m_stepPerformer.Reset();
if (App.user.IsLoggedIn) if (App.user.IsLoggedIn)
{ {
App.roomMgr.SendCreateRoom(m_rom.ID, 0, m_rom.Hash); App.roomMgr.SendCreateRoom(m_rom.ID, 0, m_rom.Hash);
} }
Eventer.Instance.RegisterEvent<int>(EEvent.OnRoomWaitStepChange, OnServerStepUpdate);
gameObject.SetActiveEx(true); gameObject.SetActiveEx(true);
} }
private void OnServerStepUpdate(int step)
{
m_stepPerformer.Perform(step);
}
public void Hide() public void Hide()
{ {
CommandDispatcher.Instance.UnRegistController(this); CommandDispatcher.Instance.UnRegistController(this);
@ -96,6 +110,7 @@ namespace AxibugEmuOnline.Client
public void QuitGame() public void QuitGame()
{ {
Eventer.Instance.UnregisterEvent<int>(EEvent.OnRoomWaitStepChange, OnServerStepUpdate);
App.roomMgr.SendLeavnRoom(); App.roomMgr.SendLeavnRoom();
App.emu.StopGame(); App.emu.StopGame();
} }

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

@ -131,6 +131,7 @@ namespace AxibugEmuOnline.Client
if (!m_bPoped) if (!m_bPoped)
{ {
m_bPoped = true; m_bPoped = true;
DOTween.To( DOTween.To(
() => MenuRoot.anchoredPosition.x, () => MenuRoot.anchoredPosition.x,
(value) => (value) =>
@ -142,6 +143,7 @@ namespace AxibugEmuOnline.Client
0, 0,
0.3f 0.3f
).SetEase(Ease.OutCubic); ).SetEase(Ease.OutCubic);
} }
} }
@ -149,10 +151,11 @@ namespace AxibugEmuOnline.Client
{ {
if (m_bPoped) if (m_bPoped)
{ {
m_runtimeMenuItems.Clear();
SelectBorder.gameObject.SetActiveEx(false); SelectBorder.gameObject.SetActiveEx(false);
CommandDispatcher.Instance.UnRegistController(this); CommandDispatcher.Instance.UnRegistController(this);
m_bPoped = false;
Canvas.ForceUpdateCanvases(); Canvas.ForceUpdateCanvases();
var width = MenuRoot.rect.width; var width = MenuRoot.rect.width;
DOTween.To( DOTween.To(
@ -166,6 +169,8 @@ namespace AxibugEmuOnline.Client
width, width,
0.3f 0.3f
).SetEase(Ease.OutCubic); ).SetEase(Ease.OutCubic);
m_bPoped = false;
} }
} }

View File

@ -4,10 +4,12 @@ namespace VirtualNes.Core
{ {
public struct ControllerState public struct ControllerState
{ {
private uint raw0; public uint raw0;
private uint raw1; public uint raw1;
private uint raw2; public uint raw2;
private uint raw3; public uint raw3;
public bool valid;
public ControllerState( public ControllerState(
EnumButtonType player0_buttons, EnumButtonType player0_buttons,
@ -19,6 +21,7 @@ namespace VirtualNes.Core
raw1 = (uint)player1_buttons; raw1 = (uint)player1_buttons;
raw2 = (uint)player2_buttons; raw2 = (uint)player2_buttons;
raw3 = (uint)player3_buttons; raw3 = (uint)player3_buttons;
valid = true;
} }
public bool HasButton(int player, EnumButtonType button) public bool HasButton(int player, EnumButtonType button)

View File

@ -59,6 +59,11 @@ namespace VirtualNes.Core
return s_support.GetControllerState(); return s_support.GetControllerState();
} }
public static void SampleInput()
{
s_support.SampleInput();
}
public static EmulatorConfig Config => s_support.Config; public static EmulatorConfig Config => s_support.Config;
} }
@ -76,5 +81,6 @@ namespace VirtualNes.Core
Stream OpenFile(string directPath, string fileName); Stream OpenFile(string directPath, string fileName);
bool TryGetMapperNo(ROM rom, out int mapperNo); bool TryGetMapperNo(ROM rom, out int mapperNo);
ControllerState GetControllerState(); ControllerState GetControllerState();
void SampleInput();
} }
} }

View File

@ -34,7 +34,7 @@ enum CommandID
// CMD_Room_HostPlayer_UpdateStateRaw消息 // CMD_Room_HostPlayer_UpdateStateRaw消息
// Step1 // Step1
// //
// Step1广"等待-全员加载即时存档" CMD_Room_WaitStep WaitStep=[1] ---> ) // Step1广"等待-全员加载即时存档" CMD_Room_WaitStep WaitStep=[1] --->
// ROM和即时存档 CMD_Room_Player_Ready // ROM和即时存档 CMD_Room_Player_Ready
// Ready之后FrameStep2 // Ready之后FrameStep2
// //