diff --git a/HKMP/Fsm/FsmPatcher.cs b/HKMP/Fsm/FsmPatcher.cs index b53951b..c7e1cd4 100644 --- a/HKMP/Fsm/FsmPatcher.cs +++ b/HKMP/Fsm/FsmPatcher.cs @@ -86,21 +86,38 @@ private void OnFsmEnable(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) // Remove the original watch animation action self.RemoveFirstAction("End Challenge"); } + + // Patch the Toll Machine FSM to set the 'activated' bool earlier in the FSM so that it synchronises better + if (self.name.StartsWith("Toll Gate Machine") && self.Fsm.Name.Equals("Toll Machine")) { + var setBoolAction = self.GetFirstAction("Open Gates"); + if (setBoolAction == null) { + return; + } + + self.InsertAction("Box Disappear Anim", setBoolAction, 0); + self.RemoveFirstAction("Open Gates"); + } + + // Patch the tutorial collapser FSMs to set the 'activated' bool earlier in the FSM so that it synchronises better + if (self.name == "Collapser Tute 01" && self.Fsm.Name.Equals("collapse tute")) { + var setBoolAction = self.GetFirstAction("Break"); + if (setBoolAction == null) { + return; + } + + self.InsertAction("Crumble", setBoolAction, 0); + self.RemoveFirstAction("Break"); + } - // Code for modifying the collision check on collapsing floors to include remote players (not working) - // if (self.name.Equals("Collapser Small") && self.Fsm.Name.Equals("collapse small")) { - // self.InsertAction("Idle", new Collision2dEventLayer { - // Enabled = true, - // collideLayer = 9, - // collideTag = new FsmString(), - // sendEvent = FsmEvent.GetFsmEvent("BREAK"), - // storeCollider = new FsmGameObject(), - // storeForce = new FsmFloat() - // }, 7); - // self.RemoveFirstAction("Idle"); - // - // var rigidbody = self.gameObject.AddComponent(); - // rigidbody.isKinematic = true; - // } + // Patch the collapser FSMs to set the 'activated' bool earlier in the FSM so that it synchronises better + if (self.name.StartsWith("Collapser Small") && self.Fsm.Name.Equals("collapse small")) { + var setBoolAction = self.GetFirstAction("Break"); + if (setBoolAction == null) { + return; + } + + self.InsertAction("Split", setBoolAction, 0); + self.RemoveFirstAction("Break"); + } } } diff --git a/HKMP/Game/Client/Save/PersistentFsmData.cs b/HKMP/Game/Client/Save/PersistentFsmData.cs index 83e27c1..91029a1 100644 --- a/HKMP/Game/Client/Save/PersistentFsmData.cs +++ b/HKMP/Game/Client/Save/PersistentFsmData.cs @@ -1,5 +1,4 @@ using System; -using HutongGames.PlayMaker; namespace Hkmp.Game.Client.Save; @@ -10,16 +9,24 @@ internal class PersistentFsmData { /// /// The persistent item data with the ID and scene name. /// - public PersistentItemData PersistentItemData { get; set; } + public PersistentItemData PersistentItemData { get; init; } /// - /// The function to get the current integer value. Could be null if a boolean is used instead. + /// Function to get the current integer value. Could be null if a boolean is used instead. /// - public Func CurrentInt { get; set; } + public Func GetCurrentInt { get; init; } /// - /// The function to get the current boolean value. Could be null if an integer is used instead. + /// Action to set the current integer value. Could be null if a boolean is used instead. /// - public Func CurrentBool { get; set; } + public Action SetCurrentInt { get; init; } + /// + /// Function to get the current boolean value. Could be null if an integer is used instead. + /// + public Func GetCurrentBool { get; init; } + /// + /// Action to set the current boolean value. Could be null if an integer is used instead. + /// + public Action SetCurrentBool { get; init; } /// /// The last value for the integer if used. @@ -33,5 +40,5 @@ internal class PersistentFsmData { /// /// Whether an int is stored for this data. /// - public bool IsInt => CurrentInt != null; + public bool IsInt => GetCurrentInt != null; } diff --git a/HKMP/Game/Client/Save/SaveChanges.cs b/HKMP/Game/Client/Save/SaveChanges.cs new file mode 100644 index 0000000..4cd988e --- /dev/null +++ b/HKMP/Game/Client/Save/SaveChanges.cs @@ -0,0 +1,265 @@ +using Hkmp.Util; +using HutongGames.PlayMaker.Actions; +using UnityEngine; +using Logger = Hkmp.Logging.Logger; + +namespace Hkmp.Game.Client.Save; + +/// +/// Class that handles incoming save changes that have an immediate effect in the current scene for the local player. +/// E.g. breakable walls that also break in another scene, tollgates that are being paid, stag station being bought. +/// +internal class SaveChanges { + /// + /// Apply a change in player data from a save update for the given name immediately. This checks whether + /// the local player is in a scene where the changes in player data have an effect on the environment. + /// For example, a breakable wall that also opens up in another scene or a stag station being bought. + /// + /// The name of the PlayerData entry. + public void ApplyPlayerDataSaveChange(string name) { + Logger.Debug($"ApplyPlayerData for name: {name}"); + + var currentScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; + + if (name == "crossroadsMawlekWall" && currentScene == "Crossroads_33") { + GameObject breakWall = null; + PlayMakerFSM breakWallFsm = null; + PlayMakerFSM fullWallFsm = null; + + var found = 0; + + var fsms = Object.FindObjectsOfType(true); + foreach (var fsm in fsms) { + if (fsm.Fsm.Name.Equals("playerdata_activation")) { + if (fsm.name.Equals("break_wall_left")) { + breakWall = fsm.gameObject; + breakWallFsm = fsm; + + found++; + if (found == 2) { + break; + } + } else if (fsm.name.Equals("full_wall_left")) { + fullWallFsm = fsm; + + found++; + if (found == 2) { + break; + } + } + } + } + + if (found < 2) { + Logger.Error("Could not find breakable wall objects for 'crossroadsMawlekWall' player data change"); + return; + } + + // Activate the breakWall object and set variable and state in the FSM + breakWall!.SetActive(true); + breakWallFsm.FsmVariables.GetFsmBool("Activate").Value = true; + breakWallFsm.SetState("Check Activation"); + + // Disable the full wall + fullWallFsm!.SetState("Check Activation"); + return; + } + + if (name == "dungDefenderWallBroken" && currentScene == "Abyss_01") { + GameObject wall = null; + GameObject wallBroken = null; + + var found = 0; + + var fsms = Object.FindObjectsOfType(true); + foreach (var fsm in fsms) { + if (fsm.name.Equals("dung_defender_wall")) { + wall = fsm.gameObject; + + found++; + if (found == 2) { + break; + } + } else if (fsm.name.Equals("dung_defender_wall_broken")) { + wallBroken = fsm.gameObject; + + found++; + if (found == 2) { + break; + } + } + } + + if (found < 2) { + Logger.Error("Could not find breakable wall objects for 'dungDefenderWallBroken' player data change"); + return; + } + + wall!.SetActive(false); + wallBroken!.SetActive(true); + return; + } + + if ( + name == "openedCrossroads" && currentScene == "Crossroads_47" || + name == "openedGreenpath" && currentScene == "Fungus1_16_alt" || + name == "openedFungalWastes" && currentScene == "Fungus2_02" || + name == "openedRuins1" && currentScene == "Ruins1_29" || + name == "openedRuins2" && currentScene == "Ruins2_08" || + name == "openedDeepnest" && currentScene == "Deepnest_09" || + name == "openedRoyalGardens" && currentScene == "Fungus3_40" || + name == "openedHiddenStation" && currentScene == "Abyss_22" + ) { + var go = GameObject.Find("Station Bell"); + var fsm = go.LocateMyFSM("Stag Bell"); + + fsm.SetState("Box Disappear Anim"); + return; + } + + if ( + name == "tollBenchCity" && currentScene == "Ruins1_31" || + name == "tollBenchAbyss" && currentScene == "Abyss_18" || + name == "tollBenchQueensGardens" && currentScene == "Fungus3_50" + ) { + var go = GameObject.Find("Toll Machine Bench"); + var fsm = go.LocateMyFSM("Toll Machine Bench"); + + fsm.SetState("Box Down"); + return; + } + + if (name == "openedRestingGrounds02" && currentScene == "RestingGrounds_02") { + var go = GameObject.Find("Bottom Gate Collider"); + if (go == null) { + return; + } + + var fsm = go.LocateMyFSM("FSM"); + fsm.SetState("Destroy"); + return; + } + + if (name == "waterwaysGate" && currentScene == "Fungus2_23") { + var go = GameObject.Find("Waterways Gate"); + if (go == null) { + return; + } + + var fsm = go.LocateMyFSM("Gate Control"); + fsm.SetState("Destroy"); + return; + } + + if (name == "deepnestWall") { + GameObject go = null; + if (currentScene == "Deepnest_01") { + go = GameObject.Find("Breakable Wall"); + } else if (currentScene == "Fungus2_20") { + go = GameObject.Find("Breakable Wall Waterways"); + } + + if (go == null) { + return; + } + + var fsm = go.LocateMyFSM("breakable_wall_v2"); + fsm.SetState("Pause Frame"); + return; + } + + if (name == "oneWayArchive" && currentScene == "Fungus3_02") { + var go = GameObject.Find("One Way Wall Exit"); + if (go == null) { + return; + } + + var fsm = go.LocateMyFSM("FSM"); + fsm.SetState("Destroy"); + return; + } + + if (name == "openedGardensStagStation" && currentScene == "Fungus3_13") { + var go = GameObject.Find("royal_garden_slide_door"); + if (go == null) { + return; + } + + var fsm = go.LocateMyFSM("FSM"); + fsm.SetState("Destroy"); + } + } + + /// + /// Apply a change in persistent values from a save update for the given name immediately. This checks whether + /// the local player is in a scene where the changes in player data have an effect on the environment. + /// For example, a breakable wall that also opens up in another scene or a stag station being bought. + /// + /// The persistent item data containing the ID and scene name of the changed object. + public void ApplyPersistentValueSaveChange(PersistentItemData itemData) { + Logger.Debug($"ApplyPersistent for item data: {itemData}"); + + var currentScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; + + if ( + itemData.Id.StartsWith("Toll Gate Machine") && ( + itemData.SceneName == "Mines_33" && currentScene == "Mines_33" || + itemData.SceneName == "Fungus1_31" && currentScene == "Fungus1_31" + )) { + var go = GameObject.Find("Toll Gate Machine"); + var fsm = go.LocateMyFSM("Toll Machine"); + + fsm.RemoveFirstAction("Open Gates"); + + fsm.SetState("Box Disappear Anim"); + return; + } + + if (itemData.Id == "Collapser Tute 01" && itemData.SceneName == "Tutorial_01" && currentScene == "Tutorial_01") { + var go = GameObject.Find("Collapser Tute 01"); + if (go == null) { + return; + } + + var fsm = go.LocateMyFSM("collapse tute"); + fsm.RemoveFirstAction("Force Hard Landing"); + fsm.SetState("Crumble"); + return; + } + + if (itemData.Id.StartsWith("Collapser Small") && ( + itemData.SceneName == "Crossroads_21" && currentScene == "Crossroads_21" || + itemData.SceneName == "Crossroads_36" && currentScene == "Crossroads_36" || + itemData.SceneName == "Fungus1_24" && currentScene == "Fungus1_24" || + itemData.SceneName == "Fungus2_23" && currentScene == "Fungus2_23" || + itemData.SceneName == "Fungus3_28" && currentScene == "Fungus3_28" || + itemData.SceneName == "Fungus2_25" && currentScene == "Fungus2_25" || + itemData.SceneName == "Mines_06" && currentScene == "Mines_06" || + itemData.SceneName == "Deepnest_02" && currentScene == "Deepnest_02" || + itemData.SceneName == "Deepnest_03" && currentScene == "Deepnest_03" || + itemData.SceneName == "Deepnest_14" && currentScene == "Deepnest_14" || + itemData.SceneName == "Deepnest_16" && currentScene == "Deepnest_16" || + itemData.SceneName == "Deepnest_30" && currentScene == "Deepnest_30" || + itemData.SceneName == "Deepnest_33" && currentScene == "Deepnest_33" || + itemData.SceneName == "Deepnest_38" && currentScene == "Deepnest_38" || + itemData.SceneName == "Deepnest_39" && currentScene == "Deepnest_39" || + itemData.SceneName == "Deepnest_41" && currentScene == "Deepnest_41" || + itemData.SceneName == "Deepnest_45_v02" && currentScene == "Deepnest_45_v02" || + itemData.SceneName == "RestingGrounds_10" && currentScene == "RestingGrounds_10" || + itemData.SceneName == "Deepnest_Spider_Town" && currentScene == "Deepnest_Spider_Town" || + itemData.SceneName == "Waterways_09" && currentScene == "Waterways_09" || + itemData.SceneName == "Waterways_14" && currentScene == "Waterways_14" || + itemData.SceneName == "GG_Pipeway" && currentScene == "GG_Pipeway" || + itemData.SceneName == "White_Palace_02" && currentScene == "White_Palace_02" || + itemData.SceneName == "White_Palace_17" && currentScene == "White_Palace_17" + )) { + var go = GameObject.Find(itemData.Id); + if (go == null) { + return; + } + + var fsm = go.LocateMyFSM("collapse small"); + fsm.SetState("Split"); + } + } +} diff --git a/HKMP/Game/Client/Save/SaveManager.cs b/HKMP/Game/Client/Save/SaveManager.cs index 4a8bfd2..4620fcf 100644 --- a/HKMP/Game/Client/Save/SaveManager.cs +++ b/HKMP/Game/Client/Save/SaveManager.cs @@ -39,6 +39,11 @@ internal class SaveManager { /// private readonly EntityManager _entityManager; + /// + /// The save changes instance to apply immediate in-world changes from received save data. + /// + private readonly SaveChanges _saveChanges; + /// /// List of data classes for each FSM that has a persistent int/bool or geo rock attached to it. /// @@ -69,6 +74,7 @@ public SaveManager(NetClient netClient, PacketManager packetManager, EntityManag _netClient = netClient; _packetManager = packetManager; _entityManager = entityManager; + _saveChanges = new SaveChanges(); _persistentFsmData = new List(); _stringListHashes = new Dictionary(); @@ -291,7 +297,8 @@ private void OnSceneChanged(Scene oldScene, Scene newScene) { var persistentFsmData = new PersistentFsmData { PersistentItemData = persistentItemData, - CurrentInt = () => fsmInt.Value, + GetCurrentInt = () => fsmInt.Value, + SetCurrentInt = value => fsmInt.Value = value, LastIntValue = fsmInt.Value }; @@ -312,27 +319,31 @@ private void OnSceneChanged(Scene oldScene, Scene newScene) { Logger.Info($"Found persistent bool in scene: {persistentItemData}"); - Func currentBoolFunc = null; + Func getCurrentBoolFunc = null; + Action setCurrentBoolAction = null; var fsm = FSMUtility.FindFSMWithPersistentBool(itemObject.GetComponents()); if (fsm != null) { var fsmBool = fsm.FsmVariables.GetFsmBool("Activated"); - currentBoolFunc = () => fsmBool.Value; + getCurrentBoolFunc = () => fsmBool.Value; + setCurrentBoolAction = value => fsmBool.Value = value; } var vinePlatform = itemObject.GetComponent(); if (vinePlatform != null) { - currentBoolFunc = () => ReflectionHelper.GetField(vinePlatform, "activated"); + getCurrentBoolFunc = () => ReflectionHelper.GetField(vinePlatform, "activated"); + setCurrentBoolAction = value => ReflectionHelper.SetField(vinePlatform, "activated", value); } - if (currentBoolFunc == null) { + if (getCurrentBoolFunc == null) { continue; } var persistentFsmData = new PersistentFsmData { PersistentItemData = persistentItemData, - CurrentBool = currentBoolFunc, - LastBoolValue = currentBoolFunc.Invoke() + GetCurrentBool = getCurrentBoolFunc, + SetCurrentBool = setCurrentBoolAction, + LastBoolValue = getCurrentBoolFunc.Invoke() }; _persistentFsmData.Add(persistentFsmData); @@ -362,7 +373,8 @@ private void OnSceneChanged(Scene oldScene, Scene newScene) { var persistentFsmData = new PersistentFsmData { PersistentItemData = persistentItemData, - CurrentInt = () => fsmInt.Value, + GetCurrentInt = () => fsmInt.Value, + SetCurrentInt = value => fsmInt.Value = value, LastIntValue = fsmInt.Value }; @@ -428,7 +440,7 @@ private void OnUpdatePersistents() { } if (persistentFsmData.IsInt) { - var value = persistentFsmData.CurrentInt.Invoke(); + var value = persistentFsmData.GetCurrentInt.Invoke(); if (value == persistentFsmData.LastIntValue) { continue; } @@ -494,7 +506,7 @@ private void OnUpdatePersistents() { Logger.Info("Cannot find persistent int/geo rock data bool, not sending save update"); } } else { - var value = persistentFsmData.CurrentBool.Invoke(); + var value = persistentFsmData.GetCurrentBool.Invoke(); if (value == persistentFsmData.LastBoolValue) { continue; } @@ -796,6 +808,8 @@ private void UpdateSaveWithData(ushort index, byte[] encodedValue) { } else { throw new NotImplementedException($"Could not decode type: {type}"); } + + _saveChanges.ApplyPlayerDataSaveChange(name); } if (SaveDataMapping.GeoRockDataIndices.TryGetValue(index, out var itemData)) { @@ -803,11 +817,11 @@ private void UpdateSaveWithData(ushort index, byte[] encodedValue) { Logger.Info($"Received geo rock save update: {itemData.Id}, {itemData.SceneName}, {value}"); - // TODO: make the _persistentFsmData a dictionary for quicker lookups foreach (var persistentFsmData in _persistentFsmData) { var existingItemData = persistentFsmData.PersistentItemData; if (existingItemData.Id == itemData.Id && existingItemData.SceneName == itemData.SceneName) { + persistentFsmData.SetCurrentInt.Invoke(value); persistentFsmData.LastIntValue = value; } } @@ -826,11 +840,12 @@ private void UpdateSaveWithData(ushort index, byte[] encodedValue) { Logger.Info($"Received persistent bool save update: {itemData.Id}, {itemData.SceneName}, {value}"); - // TODO: make the _persistentFsmData a dictionary for quicker lookups foreach (var persistentFsmData in _persistentFsmData) { var existingItemData = persistentFsmData.PersistentItemData; if (existingItemData.Id == itemData.Id && existingItemData.SceneName == itemData.SceneName) { + Logger.Debug($"Setting last bool value for {existingItemData} to {value}"); + persistentFsmData.SetCurrentBool.Invoke(value); persistentFsmData.LastBoolValue = value; } } @@ -840,6 +855,8 @@ private void UpdateSaveWithData(ushort index, byte[] encodedValue) { sceneName = itemData.SceneName, activated = value }); + + _saveChanges.ApplyPersistentValueSaveChange(itemData); } else if (SaveDataMapping.PersistentIntDataIndices.TryGetValue(index, out itemData)) { if (CheckPlayerSpecificHosting(SaveDataMapping.PersistentIntDataBools, itemData)) { return; @@ -859,6 +876,7 @@ private void UpdateSaveWithData(ushort index, byte[] encodedValue) { var existingItemData = persistentFsmData.PersistentItemData; if (existingItemData.Id == itemData.Id && existingItemData.SceneName == itemData.SceneName) { + persistentFsmData.SetCurrentInt.Invoke(value); persistentFsmData.LastIntValue = value; } } @@ -868,6 +886,8 @@ private void UpdateSaveWithData(ushort index, byte[] encodedValue) { sceneName = itemData.SceneName, value = value }); + + _saveChanges.ApplyPersistentValueSaveChange(itemData); } // Decode a string from the given byte array and start index in that array using the EncodeUtil diff --git a/HKMP/Resource/save-data.json b/HKMP/Resource/save-data.json index 73d2765..3f280bc 100644 --- a/HKMP/Resource/save-data.json +++ b/HKMP/Resource/save-data.json @@ -1873,27 +1873,33 @@ }, "openedCrossroads": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "openedGreenpath": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "openedRuins1": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "openedRuins2": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "openedFungalWastes": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "openedRoyalGardens": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "openedRestingGrounds": { "Sync": true, @@ -1901,7 +1907,8 @@ }, "openedDeepnest": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "openedStagNest": { "Sync": true, @@ -1909,7 +1916,8 @@ }, "openedHiddenStation": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "charmSlots": { "Sync": true, @@ -4959,7 +4967,8 @@ }, "tollBenchCity": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "waterwaysGate": { "Sync": true, @@ -5057,7 +5066,8 @@ }, "tollBenchQueensGardens": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "blizzardEnded": { "Sync": true, @@ -5093,7 +5103,8 @@ }, "tollBenchAbyss": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "fountainGeo": { "Sync": true, @@ -7152,7 +7163,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -8051,7 +8063,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -9105,7 +9118,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -9115,7 +9129,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -14661,7 +14676,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -15945,7 +15961,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16069,7 +16086,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16079,7 +16097,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16089,7 +16108,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16099,7 +16119,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16210,7 +16231,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16230,7 +16252,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16250,7 +16273,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16260,7 +16284,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16270,7 +16295,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16300,7 +16326,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16601,7 +16628,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16655,7 +16683,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16741,7 +16770,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16762,7 +16792,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16815,7 +16846,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -16997,7 +17029,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17062,7 +17095,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17072,7 +17106,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17166,7 +17201,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17196,7 +17232,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17236,7 +17273,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17246,7 +17284,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17276,7 +17315,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17316,7 +17356,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17346,7 +17387,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17376,7 +17418,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17426,7 +17469,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17446,7 +17490,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17456,7 +17501,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17476,7 +17522,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17496,7 +17543,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -17516,7 +17564,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -20096,7 +20145,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -20208,7 +20258,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -20258,7 +20309,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -20278,7 +20330,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -20288,7 +20341,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -20298,7 +20352,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -20318,7 +20373,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -20338,7 +20394,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -20348,7 +20405,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -21500,7 +21558,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -21510,7 +21569,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -22074,7 +22134,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -22235,7 +22296,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -22589,7 +22651,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -22733,7 +22796,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -22904,7 +22968,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -25921,7 +25986,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -27514,7 +27580,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -28813,7 +28880,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -28944,7 +29012,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -29268,7 +29337,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -29288,7 +29358,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -29368,7 +29439,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, { @@ -29579,7 +29651,8 @@ }, "Value": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true } }, {