From 2cadbf3864730c9b4aac52e32baebf6cc92dcb5b Mon Sep 17 00:00:00 2001 From: Riccardo Bovo Date: Sun, 5 Jan 2025 18:21:08 +0000 Subject: [PATCH 1/2] Make Room Name Persistent. Ensure that the room name the user chooses persists across sessions in multiplayer mode --- Assets/Scripts/GUI/MultiplayerPanel.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Assets/Scripts/GUI/MultiplayerPanel.cs b/Assets/Scripts/GUI/MultiplayerPanel.cs index 6e70a0d5c..0fc3e6c47 100644 --- a/Assets/Scripts/GUI/MultiplayerPanel.cs +++ b/Assets/Scripts/GUI/MultiplayerPanel.cs @@ -49,6 +49,7 @@ public string RoomName { data.roomName = value; UpdateDisplay(); + SaveRoomName(value); } } @@ -82,7 +83,7 @@ public void Awake() { data = new RoomCreateData { - roomName = GenerateUniqueRoomName(), + roomName = "default room", @private = false, maxPlayers = 4, voiceDisabled = false @@ -111,13 +112,23 @@ private void OnLanguageChanged(Locale newLocale) updateDisplay = true; } + public async void RetrieveRoomName() + { + var storedRoomName = await m_multiplayer.GetAsync("roomname"); + RoomName = storedRoomName ?? GenerateUniqueRoomName(); + } + + private async void SaveRoomName(string roomName) + { + await m_multiplayer.StoreAsync("roomname", roomName); + } + public async void RetrieveUsername() { var storedNickname = await m_multiplayer.GetAsync("nickname"); NickName = storedNickname ?? "Unnamed"; } - private async void SaveNickname(string nickname) { await m_multiplayer.StoreAsync("nickname", nickname); @@ -129,6 +140,7 @@ protected override void OnEnablePanel() m_multiplayer = new PlayerPrefsDataStore("Multiplayer"); RetrieveUsername(); + RetrieveRoomName(); if (MultiplayerManager.m_Instance == null) return; if (MultiplayerManager.m_Instance.State == ConnectionState.INITIALIZED || MultiplayerManager.m_Instance.State == ConnectionState.DISCONNECTED) From 91b99b86d89c17dd065fb17300d402cb8de87d35 Mon Sep 17 00:00:00 2001 From: Riccardo Bovo Date: Mon, 6 Jan 2025 21:31:04 +0000 Subject: [PATCH 2/2] Fix sync percentage tracking Revised percentage tracking to embed the progress directly into the ReliableKey, streamlining the process and simplifying debugging. --- .../Multiplayer/MultiplayerInterfaces.cs | 5 +- .../Scripts/Multiplayer/MultiplayerManager.cs | 31 +------ .../Multiplayer/MultiplayerSceneSync.cs | 80 +++---------------- .../Multiplayer/Photon/PhotonManager.cs | 38 ++------- .../Scripts/Multiplayer/Photon/PhotonRPC.cs | 20 ----- Assets/Scripts/SketchControlsScript.cs | 12 --- 6 files changed, 22 insertions(+), 164 deletions(-) diff --git a/Assets/Scripts/Multiplayer/MultiplayerInterfaces.cs b/Assets/Scripts/Multiplayer/MultiplayerInterfaces.cs index 3edab1b39..06770f229 100644 --- a/Assets/Scripts/Multiplayer/MultiplayerInterfaces.cs +++ b/Assets/Scripts/Multiplayer/MultiplayerInterfaces.cs @@ -36,7 +36,7 @@ public interface IDataConnectionHandler : IConnectionHandler int GetPlayerCount(); int GetNetworkedTimestampMilliseconds(); bool GetPlayerRoomOwnershipStatus(int playerId); - void SendLargeDataToPlayer(int playerId, byte[] largeData); + void SendLargeDataToPlayer(int playerId, byte[] largeData, int percentage); Task PerformCommand(BaseCommand command); Task SendCommandToPlayer(BaseCommand command, int playerId); Task CheckCommandReception(BaseCommand command, int playerId); @@ -44,9 +44,6 @@ public interface IDataConnectionHandler : IConnectionHandler Task UndoCommand(BaseCommand command); Task RedoCommand(BaseCommand command); Task RpcSyncToSharedAnchor(string uuid); - Task RpcStartSyncHistory(int id); - Task RpcSyncHistoryPercentage(int id, int exp, int snt); - Task RpcHistorySyncComplete(int id); event Action Disconnected; diff --git a/Assets/Scripts/Multiplayer/MultiplayerManager.cs b/Assets/Scripts/Multiplayer/MultiplayerManager.cs index 2293913e0..4f4c47474 100644 --- a/Assets/Scripts/Multiplayer/MultiplayerManager.cs +++ b/Assets/Scripts/Multiplayer/MultiplayerManager.cs @@ -420,14 +420,11 @@ void OnRemotePlayerJoined(int id, ITransientData playerData) } } - public void SendLargeDataToPlayer(int playerId, byte[] Data) + public void SendLargeDataToPlayer(int playerId, byte[] Data, int percentage) { - m_Manager.SendLargeDataToPlayer(playerId, Data); + m_Manager.SendLargeDataToPlayer(playerId, Data, percentage); } - - - void OnPlayerLeft(int id) { if (m_LocalPlayer.PlayerId == id) @@ -525,30 +522,6 @@ public void OnCommandRedo(BaseCommand command) } } - public async void StartSynchHistory(int id) - { - if (State == ConnectionState.IN_ROOM) - { - await m_Manager.RpcStartSyncHistory(id); - } - } - - public async void SynchHistoryPercentage(int id, int expected, int sent) - { - if (State == ConnectionState.IN_ROOM) - { - await m_Manager.RpcSyncHistoryPercentage(id, expected, sent); - } - } - - public async void SynchHistoryComplete(int id) - { - if (State == ConnectionState.IN_ROOM) - { - await m_Manager.RpcHistorySyncComplete(id); - } - } - async void ShareAnchors() { #if OCULUS_SUPPORTED diff --git a/Assets/Scripts/Multiplayer/MultiplayerSceneSync.cs b/Assets/Scripts/Multiplayer/MultiplayerSceneSync.cs index 9c4518556..4092830d2 100644 --- a/Assets/Scripts/Multiplayer/MultiplayerSceneSync.cs +++ b/Assets/Scripts/Multiplayer/MultiplayerSceneSync.cs @@ -28,7 +28,7 @@ namespace OpenBrush.Multiplayer public class MultiplayerSceneSync : MonoBehaviour { public static MultiplayerSceneSync m_Instance; - public Action onLargeDataReceived; + public Action onLargeDataReceived; [HideInInspector] public int batchSize = 10; [HideInInspector] public float delayBetweenBatches = 0.05f; public SyncType m_SyncType = SyncType.Strokes; @@ -75,6 +75,7 @@ public void StartSyncronizationForUser(int id) } #region Syncronization Logic Strokes + async void SendStrokesToPlayer(int id) { LinkedList strokes = SketchMemoryScript.m_Instance.GetMemoryList; @@ -82,22 +83,23 @@ async void SendStrokesToPlayer(int id) if (strokes.Count == 0) return; SendCurrentTargetEnvironmentCommand(); - StartSyncProgressDisplayForSrokes(id, strokes); + const int chunkSize = 5; List strokeList = strokes.ToList(); int counter = 0; for (int i = 0; i < strokeList.Count; i += chunkSize) { + int percentage = (int)((counter / (float)strokeList.Count) * 100); var chunk = strokeList.Skip(i).Take(chunkSize).ToList(); byte[] strokesData = await MultiplayerStrokeSerialization.SerializeAndCompressMemoryListAsync(chunk); - MultiplayerManager.m_Instance.SendLargeDataToPlayer(id, strokesData); + MultiplayerManager.m_Instance.SendLargeDataToPlayer(id, strokesData, percentage); counter += chunk.Count; //Debug.Log($"Sent {strokesData.Length} bytes of serialized stroke data (batch {(i / chunkSize) + 1}) to player {id}."); } } - async void DeserializeReceivedStrokes(byte[] largeData) + async void DeserializeReceivedStrokes(byte[] largeData, int percentage) { // Decompress and deserialize strokes asynchronously @@ -115,11 +117,12 @@ async void DeserializeReceivedStrokes(byte[] largeData) } - void OnLargeDataReceived(byte[] largeData) + void OnLargeDataReceived(byte[] largeData, int percentage) { //Debug.Log($"[Multiplayer Scene Sync]Successfully received {largeData.Length} bytes from the autosave."); - DeserializeReceivedStrokes(largeData); + SynchInfoPercentageUpdate(percentage); + DeserializeReceivedStrokes(largeData, percentage); } #endregion @@ -164,8 +167,6 @@ public IEnumerator SendCommandHistory(int id) SendCurrentTargetEnvironmentCommand(); - StartSyncProgressDisplayForCommands(id, commands.ToList()); - foreach (BaseCommand command in commands) MultiplayerManager.m_Instance.OnCommandPerformed(command); _isSendingCommandHistory = false; @@ -200,65 +201,6 @@ private void CreateBrushStrokeCommands(List strokes, int LastTimestamp) } } - #endregion - - #region Remote infoCard commands - - public async void StartSyncProgressDisplayForSrokes(int TargetPlayerId, LinkedList strokes) - { - StartSynchHistory(TargetPlayerId); - - int sentStrokes = 0; - - foreach (var stroke in strokes) - { - - while (await MultiplayerManager.m_Instance.CheckStrokeReception(stroke, TargetPlayerId)) - { - await Task.Delay(200); - } - - sentStrokes++; - SynchHistoryPercentage(TargetPlayerId, strokes.Count, sentStrokes); - } - - SynchHistoryComplete(TargetPlayerId); - } - - public async void StartSyncProgressDisplayForCommands(int TargetPlayerId, List commands) - { - StartSynchHistory(TargetPlayerId); - - int sentStrokes = 0; - foreach (var command in commands) - { - while (await MultiplayerManager.m_Instance.CheckCommandReception(command, TargetPlayerId)) - { - await Task.Delay(200); - } - sentStrokes++; - SynchHistoryPercentage(TargetPlayerId, commands.Count, sentStrokes); - } - - SynchHistoryComplete(TargetPlayerId); - } - - private void StartSynchHistory(int id) - { - MultiplayerManager.m_Instance.StartSynchHistory(id); - } - - private void SynchHistoryPercentage(int id, int expected, int sent) - { - MultiplayerManager.m_Instance.SynchHistoryPercentage(id, expected, sent); - } - - private void SynchHistoryComplete(int id) - { - MultiplayerManager.m_Instance.SynchHistoryComplete(id); - } - - #endregion #region Local infoCard commands @@ -328,9 +270,9 @@ public void StartSynchInfo() { EnqueueMessage("Sync Started!"); } - public void SynchInfoPercentageUpdate() + + public void SynchInfoPercentageUpdate(int percentage) { - int percentage = (int)((float)SketchMemoryScript.AllStrokesCount() / numberOfCommandsExpected * 100); EnqueueMessage($"Sync {percentage}%"); } diff --git a/Assets/Scripts/Multiplayer/Photon/PhotonManager.cs b/Assets/Scripts/Multiplayer/Photon/PhotonManager.cs index dbcea03c3..68cb695f5 100644 --- a/Assets/Scripts/Multiplayer/Photon/PhotonManager.cs +++ b/Assets/Scripts/Multiplayer/Photon/PhotonManager.cs @@ -324,39 +324,12 @@ public async Task RpcSyncToSharedAnchor(string uuid) return true; } - public async Task RpcStartSyncHistory(int id) - { - PlayerRef playerRef = PlayerRef.FromEncoded(id); - PhotonRPCBatcher.EnqueueRPC(() => - { PhotonRPC.RPC_StartHistorySync(m_Runner, playerRef); }); - await Task.Yield(); - return true; - } - - public async Task RpcHistorySyncComplete(int id) - { - PlayerRef playerRef = PlayerRef.FromEncoded(id); - PhotonRPCBatcher.EnqueueRPC(() => - { PhotonRPC.RPC_HistorySyncCompleted(m_Runner, playerRef);}); - await Task.Yield(); - return true; - } - - public async Task RpcSyncHistoryPercentage(int id, int exp, int snt) - { - PlayerRef playerRef = PlayerRef.FromEncoded(id); - PhotonRPCBatcher.EnqueueRPC(() => - { PhotonRPC.RPC_HistoryPercentageUpdate(m_Runner, playerRef, exp, snt);}); - await Task.Yield(); - return true; - } - - public void SendLargeDataToPlayer(int playerId, byte[] largeData) + public void SendLargeDataToPlayer(int playerId, byte[] largeData, int percentage) { sequenceNumber++; PlayerRef playerRef = PlayerRef.FromEncoded(playerId); int dataHash = largeData.GetHashCode(); - var key = ReliableKey.FromInts(playerId, sequenceNumber, dataHash, 0); + var key = ReliableKey.FromInts(playerId, sequenceNumber, dataHash, percentage); m_Runner.SendReliableDataToPlayer(playerRef, key, largeData); } @@ -549,6 +522,10 @@ public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, Relia { //Debug.Log("Server received complete reliable data"); + int percentage; + key.GetInts(out _, out _, out _, out percentage); + //Debug.Log($"Data received with percentage: {percentage}%"); + byte[] receivedData = data.Array; if (receivedData == null || receivedData.Length == 0) { @@ -556,9 +533,10 @@ public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, Relia return; } - MultiplayerSceneSync.m_Instance.onLargeDataReceived?.Invoke(receivedData); + MultiplayerSceneSync.m_Instance.onLargeDataReceived?.Invoke(receivedData,percentage); } + public void OnReliableDataProgress(NetworkRunner runner, PlayerRef player, ReliableKey key, float progress) { diff --git a/Assets/Scripts/Multiplayer/Photon/PhotonRPC.cs b/Assets/Scripts/Multiplayer/Photon/PhotonRPC.cs index 5f0ef5108..84d1f1e83 100644 --- a/Assets/Scripts/Multiplayer/Photon/PhotonRPC.cs +++ b/Assets/Scripts/Multiplayer/Photon/PhotonRPC.cs @@ -539,26 +539,6 @@ private static void RPC_SwitchEnvironment(NetworkRunner runner, Guid environment SwitchEnvironment(environmentGuid, commandGuid, timestamp, parentGuid, childCount); } - [Rpc(InvokeLocal = false)] - public static void RPC_StartHistorySync(NetworkRunner runner, [RpcTarget] PlayerRef targetPlayer) - { - m_Instance.IssueGlobalCommand(GlobalCommands.DisplaySynchInfo); - } - - [Rpc(InvokeLocal = false)] - public static void RPC_HistoryPercentageUpdate(NetworkRunner runner, [RpcTarget] PlayerRef targetPlayer, int expected, int sent) - { - MultiplayerSceneSync.m_Instance.numberOfCommandsExpected = expected; - MultiplayerSceneSync.m_Instance.numberOfCommandsSent = sent; - m_Instance.IssueGlobalCommand(GlobalCommands.SynchInfoPercentageUpdate); - } - - [Rpc(InvokeLocal = false)] - public static void RPC_HistorySyncCompleted(NetworkRunner runner, [RpcTarget] PlayerRef targetPlayer) - { - m_Instance.IssueGlobalCommand(GlobalCommands.HideSynchInfo); - } - [Rpc(InvokeLocal = false)] public static void RPC_CheckCommand(NetworkRunner runner, Guid commandGuid, PlayerRef initiatorPlayer, [RpcTarget] PlayerRef targetPlayer) { diff --git a/Assets/Scripts/SketchControlsScript.cs b/Assets/Scripts/SketchControlsScript.cs index cfdab9e63..b32a8f2c6 100644 --- a/Assets/Scripts/SketchControlsScript.cs +++ b/Assets/Scripts/SketchControlsScript.cs @@ -156,9 +156,6 @@ public enum GlobalCommands MultiplayerConnect = 1007, MultiplayerDisconnect = 1008, EditMultiplayerNickName = 1009, - DisplaySynchInfo = 1010, - SynchInfoPercentageUpdate = 1011, - HideSynchInfo = 1012, RenameSketch = 5200, OpenLayerOptionsPopup = 5201, @@ -4861,15 +4858,6 @@ public void IssueGlobalCommand(GlobalCommands rEnum, int iParam1 = -1, PointerManager.m_Instance.EatLineEnabledInput(); SketchSurfacePanel.m_Instance.EatToolsInput(); break; - case GlobalCommands.DisplaySynchInfo: - MultiplayerSceneSync.m_Instance.StartSynchInfo(); - break; - case GlobalCommands.SynchInfoPercentageUpdate: - MultiplayerSceneSync.m_Instance.SynchInfoPercentageUpdate(); - break; - case GlobalCommands.HideSynchInfo: - MultiplayerSceneSync.m_Instance.HideSynchInfo(); - break; case GlobalCommands.RepaintOptions: break; // Intentionally blank. case GlobalCommands.Null: break; // Intentionally blank. case GlobalCommands.MultiplayerPanelOptions: break; // Intentionally blank.