Skip to content

Commit

Permalink
Improve save data handling for in-game hosting
Browse files Browse the repository at this point in the history
  • Loading branch information
Extremelyd1 committed Jul 20, 2024
1 parent e8e5aee commit 5f685d0
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 21 deletions.
6 changes: 6 additions & 0 deletions HKMP/Game/Client/ClientManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
104 changes: 84 additions & 20 deletions HKMP/Game/Client/Save/SaveManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ internal class SaveManager {
/// </summary>
private readonly Dictionary<string, BossStatue.Completion> _bsCompHashes;

/// <summary>
/// Whether the player is hosting the server, which means that player specific save data is not networked
/// to the server.
/// </summary>
public bool IsHostingServer { get; set; }

public SaveManager(NetClient netClient, PacketManager packetManager, EntityManager entityManager) {
_netClient = netClient;
_packetManager = packetManager;
Expand Down Expand Up @@ -391,6 +397,11 @@ private void CheckSendSaveUpdate(string name, Func<byte[]> 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;
Expand Down Expand Up @@ -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})");
Expand Down Expand Up @@ -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})");
Expand Down Expand Up @@ -534,41 +555,48 @@ void CheckUpdates<TVar, TCheck>(
Func<TCheck, TCheck, bool> 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)
);
}
}
}
Expand Down Expand Up @@ -629,6 +657,11 @@ private void UpdateSaveWithData(SaveUpdate saveUpdate) {
/// </summary>
/// <param name="currentSave">The save data to set.</param>
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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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}");
Expand All @@ -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
Expand Down Expand Up @@ -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<TKey>(Dictionary<TKey, SaveDataMapping.SyncProperties> 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;
}
}

/// <summary>
Expand Down
3 changes: 2 additions & 1 deletion HKMP/Resource/save-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,8 @@
},
"shaman": {
"Sync": true,
"SyncType": "Server"
"SyncType": "Player",
"IgnoreSceneHost": true
},
"shamanScreamConvo": {
"Sync": true,
Expand Down

0 comments on commit 5f685d0

Please sign in to comment.