From 5f685d0af1038626bc2efff98f0fedfd76c12b66 Mon Sep 17 00:00:00 2001 From: Extremelyd1 <10898310+Extremelyd1@users.noreply.github.com> Date: Sat, 20 Jul 2024 13:51:02 +0200 Subject: [PATCH] Improve save data handling for in-game hosting --- HKMP/Game/Client/ClientManager.cs | 6 ++ HKMP/Game/Client/Save/SaveManager.cs | 104 +++++++++++++++++++++------ HKMP/Resource/save-data.json | 3 +- 3 files changed, 92 insertions(+), 21 deletions(-) diff --git a/HKMP/Game/Client/ClientManager.cs b/HKMP/Game/Client/ClientManager.cs index 8fbdc33..5fd35e2 100644 --- a/HKMP/Game/Client/ClientManager.cs +++ b/HKMP/Game/Client/ClientManager.cs @@ -247,6 +247,12 @@ ModSettings modSettings Connect(address, port, username); }; uiManager.RequestClientDisconnectEvent += Disconnect; + uiManager.RequestServerStartHostEvent += _ => { + _saveManager.IsHostingServer = true; + }; + uiManager.RequestServerStopHostEvent += () => { + _saveManager.IsHostingServer = false; + }; UiManager.InternalChatBox.ChatInputEvent += OnChatInput; diff --git a/HKMP/Game/Client/Save/SaveManager.cs b/HKMP/Game/Client/Save/SaveManager.cs index 0f28ac4..4a8bfd2 100644 --- a/HKMP/Game/Client/Save/SaveManager.cs +++ b/HKMP/Game/Client/Save/SaveManager.cs @@ -59,6 +59,12 @@ internal class SaveManager { /// private readonly Dictionary _bsCompHashes; + /// + /// Whether the player is hosting the server, which means that player specific save data is not networked + /// to the server. + /// + public bool IsHostingServer { get; set; } + public SaveManager(NetClient netClient, PacketManager packetManager, EntityManager entityManager) { _netClient = netClient; _packetManager = packetManager; @@ -391,6 +397,11 @@ private void CheckSendSaveUpdate(string name, Func encodeFunc) { return; } + if (syncProps.SyncType == SaveDataMapping.SyncType.Player && IsHostingServer) { + Logger.Debug("Player specific save data, but player is hosting the server, not sending save update"); + return; + } + if (!SaveDataMapping.PlayerDataIndices.TryGetValue(name, out var index)) { Logger.Info($"Cannot find save data index, not sending save update ({name})"); return; @@ -458,10 +469,15 @@ private void OnUpdatePersistents() { // If we should do the scene host check and the player is not scene host, skip sending if (!syncProps.IgnoreSceneHost && !_entityManager.IsSceneHost) { Logger.Info( - $"Not scene host, not sending geo rock save update ({itemData.Id}, {itemData.SceneName})"); + $"Not scene host, not sending persistent int save update ({itemData.Id}, {itemData.SceneName})"); continue; } - + + if (syncProps.SyncType == SaveDataMapping.SyncType.Player && IsHostingServer) { + Logger.Debug("Player specific save data, but player is hosting the server, not sending persistent int save update"); + continue; + } + if (!SaveDataMapping.PersistentIntDataIndices.TryGetValue(itemData, out var index)) { Logger.Info( $"Cannot find persistent int save data index, not sending save update ({itemData.Id}, {itemData.SceneName})"); @@ -507,6 +523,11 @@ private void OnUpdatePersistents() { continue; } + if (syncProps.SyncType == SaveDataMapping.SyncType.Player && IsHostingServer) { + Logger.Debug("Player specific save data, but player is hosting the server, not sending persistent bool save update"); + continue; + } + if (!SaveDataMapping.PersistentBoolDataIndices.TryGetValue(itemData, out var index)) { Logger.Info( $"Cannot find persistent bool save data index, not sending save update ({itemData.Id}, {itemData.SceneName})"); @@ -534,41 +555,48 @@ void CheckUpdates( Func changeFunc ) { foreach (var varName in variableNames) { - if (!SaveDataMapping.PlayerDataBools.TryGetValue(varName, out var syncProps)) { + var variable = (TVar) typeof(PlayerData).GetField(varName).GetValue(PlayerData.instance); + var newCheck = newCheckFunc.Invoke(variable); + + if (!checkDict.TryGetValue(varName, out var check)) { + checkDict[varName] = newCheck; continue; } - if (!syncProps.Sync) { + if (!changeFunc(newCheck, check)) { continue; } - if (!syncProps.IgnoreSceneHost && !_entityManager.IsSceneHost) { + Logger.Info($"Compound variable ({varName}) changed value"); + + checkDict[varName] = newCheck; + + if (!SaveDataMapping.PlayerDataBools.TryGetValue(varName, out var syncProps)) { continue; } - if (!SaveDataMapping.PlayerDataIndices.TryGetValue(varName, out var index)) { + if (!syncProps.Sync) { continue; } - var variable = (TVar) typeof(PlayerData).GetField(varName).GetValue(PlayerData.instance); - var newCheck = newCheckFunc.Invoke(variable); - - if (!checkDict.TryGetValue(varName, out var check)) { - checkDict[varName] = newCheck; + if (!syncProps.IgnoreSceneHost && !_entityManager.IsSceneHost) { continue; } - if (changeFunc(newCheck, check)) { - Logger.Info($"Compound variable ({varName}) changed value"); + if (syncProps.SyncType == SaveDataMapping.SyncType.Player && IsHostingServer) { + Logger.Debug("Player specific save data, but player is hosting the server, not sending compound save update"); + return; + } - checkDict[varName] = newCheck; + if (!SaveDataMapping.PlayerDataIndices.TryGetValue(varName, out var index)) { + continue; + } - if (_netClient.IsConnected) { - _netClient.UpdateManager.SetSaveUpdate( - index, - EncodeValue(variable) - ); - } + if (_netClient.IsConnected) { + _netClient.UpdateManager.SetSaveUpdate( + index, + EncodeValue(variable) + ); } } } @@ -629,6 +657,11 @@ private void UpdateSaveWithData(SaveUpdate saveUpdate) { /// /// The save data to set. public void SetSaveWithData(CurrentSave currentSave) { + if (IsHostingServer) { + Logger.Info("Received current save, but player is hosting, not updating"); + return; + } + Logger.Info("Received current save, updating..."); foreach (var keyValuePair in currentSave.SaveData) { @@ -651,6 +684,10 @@ private void UpdateSaveWithData(ushort index, byte[] encodedValue) { var sceneData = SceneData.instance; if (SaveDataMapping.PlayerDataIndices.TryGetValue(index, out var name)) { + if (CheckPlayerSpecificHosting(SaveDataMapping.PlayerDataBools, name)) { + return; + } + Logger.Info($"Received save update ({index}, {name})"); var fieldInfo = typeof(PlayerData).GetField(name); @@ -781,6 +818,10 @@ private void UpdateSaveWithData(ushort index, byte[] encodedValue) { hitsLeft = value }); } else if (SaveDataMapping.PersistentBoolDataIndices.TryGetValue(index, out itemData)) { + if (CheckPlayerSpecificHosting(SaveDataMapping.PersistentBoolDataBools, itemData)) { + return; + } + var value = encodedValue[0] == 1; Logger.Info($"Received persistent bool save update: {itemData.Id}, {itemData.SceneName}, {value}"); @@ -800,6 +841,10 @@ private void UpdateSaveWithData(ushort index, byte[] encodedValue) { activated = value }); } else if (SaveDataMapping.PersistentIntDataIndices.TryGetValue(index, out itemData)) { + if (CheckPlayerSpecificHosting(SaveDataMapping.PersistentIntDataBools, itemData)) { + return; + } + var value = (int) encodedValue[0]; // Add a special case for the -1 value that some persistent ints might have // 255 is never used in the byte space, so we use it for compact networking @@ -835,6 +880,25 @@ string DecodeString(byte[] encoded, int startIndex) { return value; } + + // Do the checks for whether the player is hosting and the received save data is player specific and should + // thus be ignored. Returns true if the data should be ignored, false otherwise. + bool CheckPlayerSpecificHosting(Dictionary dict, TKey value) { + if (!IsHostingServer) { + return false; + } + + if (!dict.TryGetValue(value, out var syncProps)) { + return true; + } + + if (syncProps.SyncType != SaveDataMapping.SyncType.Player) { + return false; + } + + Logger.Info($"Received player specific save update ({index}, {name}), but player is hosting"); + return true; + } } /// diff --git a/HKMP/Resource/save-data.json b/HKMP/Resource/save-data.json index 1836a48..f89ecde 100644 --- a/HKMP/Resource/save-data.json +++ b/HKMP/Resource/save-data.json @@ -1009,7 +1009,8 @@ }, "shaman": { "Sync": true, - "SyncType": "Server" + "SyncType": "Player", + "IgnoreSceneHost": true }, "shamanScreamConvo": { "Sync": true,