From 07c90cbc3e3bc35cba1d1cf98869cc2cae5931e0 Mon Sep 17 00:00:00 2001 From: tornac1234 Date: Wed, 7 Dec 2022 20:12:32 +0100 Subject: [PATCH 1/9] Revert #1717 cinematic sync --- NitroxClient/ClientAutoFacRegistrar.cs | 2 - .../PlayerCinematicControllerCallProcessor.cs | 41 -- NitroxClient/Debuggers/NetworkDebugger.cs | 2 +- NitroxClient/GameLogic/EscapePodManager.cs | 7 - .../GameLogic/PlayerLogic/PlayerCinematics.cs | 25 - .../MultiplayerCinematicController.cs | 156 ------ .../MultiplayerCinematicReference.cs | 70 --- .../RemotePlayerCinematicController.cs | 471 ------------------ .../Packets/PlayerCinematicControllerCall.cs | 23 - ...ntroller_OnPlayerCinematicModeEnd_Patch.cs | 44 -- ...aticController_StartCinematicMode_Patch.cs | 46 -- .../PlayerCinematicController_Start_Patch.cs | 37 -- .../DefaultServerPacketProcessor.cs | 3 +- 13 files changed, 2 insertions(+), 925 deletions(-) delete mode 100644 NitroxClient/Communication/Packets/Processors/PlayerCinematicControllerCallProcessor.cs delete mode 100644 NitroxClient/GameLogic/PlayerLogic/PlayerCinematics.cs delete mode 100644 NitroxClient/MonoBehaviours/CinematicController/MultiplayerCinematicController.cs delete mode 100644 NitroxClient/MonoBehaviours/CinematicController/MultiplayerCinematicReference.cs delete mode 100644 NitroxClient/MonoBehaviours/Overrides/RemotePlayerCinematicController.cs delete mode 100644 NitroxModel/Packets/PlayerCinematicControllerCall.cs delete mode 100644 NitroxPatcher/Patches/Dynamic/PlayerCinematicController_OnPlayerCinematicModeEnd_Patch.cs delete mode 100644 NitroxPatcher/Patches/Dynamic/PlayerCinematicController_StartCinematicMode_Patch.cs delete mode 100644 NitroxPatcher/Patches/Dynamic/PlayerCinematicController_Start_Patch.cs diff --git a/NitroxClient/ClientAutoFacRegistrar.cs b/NitroxClient/ClientAutoFacRegistrar.cs index 5236c43c2b..24e54cb3c6 100644 --- a/NitroxClient/ClientAutoFacRegistrar.cs +++ b/NitroxClient/ClientAutoFacRegistrar.cs @@ -16,7 +16,6 @@ using NitroxClient.GameLogic.FMOD; using NitroxClient.GameLogic.HUD; using NitroxClient.GameLogic.InitialSync.Base; -using NitroxClient.GameLogic.PlayerLogic; using NitroxClient.GameLogic.PlayerLogic.PlayerModel; using NitroxClient.GameLogic.PlayerLogic.PlayerModel.Abstract; using NitroxClient.GameLogic.PlayerLogic.PlayerPreferences; @@ -141,7 +140,6 @@ private static void RegisterCoreDependencies(ContainerBuilder containerBuilder) containerBuilder.RegisterType().InstancePerLifetimeScope(); containerBuilder.RegisterType().InstancePerLifetimeScope(); containerBuilder.RegisterType().InstancePerLifetimeScope(); - containerBuilder.RegisterType().InstancePerLifetimeScope(); containerBuilder.RegisterType().InstancePerLifetimeScope(); } diff --git a/NitroxClient/Communication/Packets/Processors/PlayerCinematicControllerCallProcessor.cs b/NitroxClient/Communication/Packets/Processors/PlayerCinematicControllerCallProcessor.cs deleted file mode 100644 index ac97d22b3a..0000000000 --- a/NitroxClient/Communication/Packets/Processors/PlayerCinematicControllerCallProcessor.cs +++ /dev/null @@ -1,41 +0,0 @@ -using NitroxClient.Communication.Packets.Processors.Abstract; -using NitroxClient.GameLogic; -using NitroxClient.MonoBehaviours; -using NitroxClient.MonoBehaviours.Overrides; -using NitroxModel.DataStructures.Util; -using NitroxModel.Helper; -using NitroxModel.Packets; -using UnityEngine; - -namespace NitroxClient.Communication.Packets.Processors; - -public class PlayerCinematicControllerCallProcessor : ClientPacketProcessor -{ - private readonly PlayerManager playerManager; - - public PlayerCinematicControllerCallProcessor(PlayerManager playerManager) - { - this.playerManager = playerManager; - } - - public override void Process(PlayerCinematicControllerCall packet) - { - Optional opEntity = NitroxEntity.GetObjectFrom(packet.ControllerID); - Validate.IsPresent(opEntity); - - MultiplayerCinematicReference reference = opEntity.Value.GetComponent(); - Validate.IsTrue(reference); - - Optional opPlayer = playerManager.Find(packet.PlayerId); - Validate.IsPresent(opPlayer); - - if (packet.StartPlaying) - { - reference.CallStartCinematicMode(packet.Key, packet.ControllerNameHash, opPlayer.Value); - } - else - { - reference.CallCinematicModeEnd(packet.Key, packet.ControllerNameHash, opPlayer.Value); - } - } -} diff --git a/NitroxClient/Debuggers/NetworkDebugger.cs b/NitroxClient/Debuggers/NetworkDebugger.cs index 10f7ea37e7..d050fb9e1a 100644 --- a/NitroxClient/Debuggers/NetworkDebugger.cs +++ b/NitroxClient/Debuggers/NetworkDebugger.cs @@ -16,7 +16,7 @@ public class NetworkDebugger : BaseDebugger, INetworkDebugger private readonly List filter = new() { - nameof(PlayerMovement), nameof(EntityTransformUpdates), nameof(PlayerStats), nameof(CellEntities), nameof(VehicleMovement), nameof(PlayerCinematicControllerCall), + nameof(PlayerMovement), nameof(EntityTransformUpdates), nameof(PlayerStats), nameof(CellEntities), nameof(VehicleMovement), nameof(PlayFMODAsset), nameof(PlayFMODCustomEmitter), nameof(PlayFMODStudioEmitter), nameof(PlayFMODCustomLoopingEmitter) }; private readonly List packets = new List(PACKET_STORED_COUNT); diff --git a/NitroxClient/GameLogic/EscapePodManager.cs b/NitroxClient/GameLogic/EscapePodManager.cs index 89e39d7f12..ed60564bd5 100644 --- a/NitroxClient/GameLogic/EscapePodManager.cs +++ b/NitroxClient/GameLogic/EscapePodManager.cs @@ -122,13 +122,6 @@ public GameObject CreateNewEscapePod(EscapePodModel model) DamageEscapePod(model.Damaged, model.RadioDamaged); FixStartMethods(escapePod); - // Start() isn't executed for the EscapePod, why? Idk, maybe because it's a scene... - MultiplayerCinematicReference reference = escapePod.AddComponent(); - foreach (PlayerCinematicController controller in escapePod.GetComponentsInChildren()) - { - reference.AddController(controller); - } - SURPRESS_ESCAPE_POD_AWAKE_METHOD = false; return escapePod; diff --git a/NitroxClient/GameLogic/PlayerLogic/PlayerCinematics.cs b/NitroxClient/GameLogic/PlayerLogic/PlayerCinematics.cs deleted file mode 100644 index 74f3dc2835..0000000000 --- a/NitroxClient/GameLogic/PlayerLogic/PlayerCinematics.cs +++ /dev/null @@ -1,25 +0,0 @@ -using NitroxClient.Communication.Abstract; -using NitroxModel.DataStructures; -using NitroxModel.Packets; - -namespace NitroxClient.GameLogic.PlayerLogic; - -public class PlayerCinematics -{ - private readonly IPacketSender packetSender; - - public PlayerCinematics(IPacketSender packetSender) - { - this.packetSender = packetSender; - } - - public void StartCinematicMode(ushort playerId, NitroxId controllerID, int controllerNameHash, string key) - { - packetSender.Send(new PlayerCinematicControllerCall(playerId, controllerID, controllerNameHash, key, true)); - } - - public void EndCinematicMode(ushort playerId, NitroxId controllerID, int controllerNameHash, string key) - { - packetSender.Send(new PlayerCinematicControllerCall(playerId, controllerID, controllerNameHash, key, false)); - } -} diff --git a/NitroxClient/MonoBehaviours/CinematicController/MultiplayerCinematicController.cs b/NitroxClient/MonoBehaviours/CinematicController/MultiplayerCinematicController.cs deleted file mode 100644 index ceaee3e572..0000000000 --- a/NitroxClient/MonoBehaviours/CinematicController/MultiplayerCinematicController.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System.Collections.Generic; -using NitroxClient.GameLogic; -using UnityEngine; - -namespace NitroxClient.MonoBehaviours.Overrides; - -public class MultiplayerCinematicController : MonoBehaviour -{ - private readonly Dictionary controllerByPlayerId = new(); - - /// - /// MCCs with the same Animator to reset state if needed. - /// - private readonly List multiplayerControllerSameAnimator = new(); - - private CinematicControllerPrefab controllerPrefab; - private PlayerCinematicController playerController; - - public void CallStartCinematicMode(RemotePlayer player) - { - if (!playerController.cinematicModeActive) // Check if local player is occupying the animator. - { - GetController(player).StartCinematicMode(player); - } - } - - public void CallCinematicModeEnd(RemotePlayer player) - { - if (!playerController.cinematicModeActive) // Check if local player is occupying the animator. - { - GetController(player).OnPlayerCinematicModeEnd(); - } - } - - public void CallAllCinematicModeEnd() - { - foreach (RemotePlayerCinematicController remoteController in controllerByPlayerId.Values) - { - remoteController.EndCinematicMode(true); - } - - foreach (MultiplayerCinematicController controller in multiplayerControllerSameAnimator) - { - foreach (RemotePlayerCinematicController remoteController in controller.controllerByPlayerId.Values) - { - remoteController.EndCinematicMode(true); - } - } - } - - private RemotePlayerCinematicController GetController(RemotePlayer player) - { - if (controllerByPlayerId.TryGetValue(player.PlayerId, out RemotePlayerCinematicController controller)) - { - return controller; - } - - player.PlayerDisconnectEvent.AddHandler(gameObject, OnPlayerDisconnect); - - controller = CreateNewControllerForPlayer(); - controllerByPlayerId.Add(player.PlayerId, controller); - return controller; - } - - public void OnPlayerDisconnect(RemotePlayer player) - { - if (controllerByPlayerId.TryGetValue(player.PlayerId, out RemotePlayerCinematicController controller)) - { - Destroy(controller); - controllerByPlayerId.Remove(player.PlayerId); - } - } - - private RemotePlayerCinematicController CreateNewControllerForPlayer() - { - RemotePlayerCinematicController controller = gameObject.AddComponent(); - controllerPrefab.PopulateRemoteController(controller); - - return controller; - } - - public void AddOtherControllers(IEnumerable otherControllers) - { - foreach (MultiplayerCinematicController controller in otherControllers) - { - if (controller.playerController.animator == playerController.animator) - { - multiplayerControllerSameAnimator.Add(controller); - } - } - } - - public static MultiplayerCinematicController Initialize(PlayerCinematicController playerController) - { - MultiplayerCinematicController mcp = playerController.gameObject.AddComponent(); - mcp.controllerPrefab = new CinematicControllerPrefab(playerController); - mcp.playerController = playerController; - return mcp; - } -} - -public readonly struct CinematicControllerPrefab -{ - private readonly Transform animatedTransform; - private readonly Transform endTransform; - private readonly bool onlyUseEndTransformInVr; - private readonly bool playInVr; - private readonly string playerViewAnimationName; - private readonly string playerViewInterpolateAnimParam; - private readonly string animParam; - private readonly string interpolateAnimParam; - private readonly float interpolationTime; - private readonly float interpolationTimeOut; - private readonly string receiversAnimParam; - private readonly GameObject[] animParamReceivers; - private readonly bool interpolateDuringAnimation; - private readonly Animator animator; - - // Currently we don't sync playerController.informGameObject but no problem could be found while testing. - public CinematicControllerPrefab(PlayerCinematicController playerController) - { - animatedTransform = playerController.animatedTransform; - endTransform = playerController.endTransform; - onlyUseEndTransformInVr = playerController.onlyUseEndTransformInVr; - playInVr = playerController.playInVr; - playerViewAnimationName = playerController.playerViewAnimationName; - playerViewInterpolateAnimParam = playerController.playerViewInterpolateAnimParam; - animParam = playerController.animParam; - interpolateAnimParam = playerController.interpolateAnimParam; - interpolationTime = playerController.interpolationTime; - interpolationTimeOut = playerController.interpolationTimeOut; - receiversAnimParam = playerController.receiversAnimParam; - animParamReceivers = playerController.animParamReceivers; - interpolateDuringAnimation = playerController.interpolateDuringAnimation; - animator = playerController.animator; - } - - public void PopulateRemoteController(RemotePlayerCinematicController remoteController) - { - remoteController.animatedTransform = animatedTransform; - remoteController.informGameObject = null; - remoteController.endTransform = endTransform; - remoteController.onlyUseEndTransformInVr = onlyUseEndTransformInVr; - remoteController.playInVr = playInVr; - remoteController.playerViewAnimationName = playerViewAnimationName; - remoteController.playerViewInterpolateAnimParam = playerViewInterpolateAnimParam; - remoteController.animParam = animParam; - remoteController.interpolateAnimParam = interpolateAnimParam; - remoteController.interpolationTime = interpolationTime; - remoteController.interpolationTimeOut = interpolationTimeOut; - remoteController.receiversAnimParam = receiversAnimParam; - remoteController.animParamReceivers = animParamReceivers; - remoteController.interpolateDuringAnimation = interpolateDuringAnimation; - remoteController.animator = animator; - } -} diff --git a/NitroxClient/MonoBehaviours/CinematicController/MultiplayerCinematicReference.cs b/NitroxClient/MonoBehaviours/CinematicController/MultiplayerCinematicReference.cs deleted file mode 100644 index 4dcd165ad0..0000000000 --- a/NitroxClient/MonoBehaviours/CinematicController/MultiplayerCinematicReference.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using NitroxClient.GameLogic; -using NitroxClient.Unity.Helper; -using UnityEngine; - -namespace NitroxClient.MonoBehaviours.Overrides; - -public class MultiplayerCinematicReference : MonoBehaviour -{ - private readonly Dictionary> controllerByKey = new(); - - public void CallStartCinematicMode(string key, int identifier, RemotePlayer player) - { - if (!controllerByKey.TryGetValue(key, out Dictionary controllers)) - { - throw new KeyNotFoundException($"There was no entry for the key {key} at {gameObject.GetFullHierarchyPath()}"); - } - - if (!controllers.TryGetValue(identifier, out MultiplayerCinematicController controller)) - { - throw new KeyNotFoundException($"There was no entry for the identifier {identifier} at {gameObject.GetFullHierarchyPath()}"); - } - - controller.CallStartCinematicMode(player); - } - - public void CallCinematicModeEnd(string key, int identifier, RemotePlayer player) - { - if (!controllerByKey.TryGetValue(key, out Dictionary controllers)) - { - throw new KeyNotFoundException($"There was no entry for the key {key} at {gameObject.GetFullHierarchyPath()}"); - } - - if (!controllers.TryGetValue(identifier, out MultiplayerCinematicController controller)) - { - throw new KeyNotFoundException($"There was no entry for the identifier {identifier} at {gameObject.GetFullHierarchyPath()}"); - } - - controller.CallCinematicModeEnd(player); - } - - public static int GetCinematicControllerIdentifier(GameObject controller, GameObject reference) => controller.gameObject.GetHierarchyPath(reference).GetHashCode(); - - public void AddController(PlayerCinematicController playerController) - { - - MultiplayerCinematicController[] allControllers = controllerByKey.SelectMany(n => n.Value.Select(x => x.Value)).ToArray(); - - if (!controllerByKey.TryGetValue(playerController.playerViewAnimationName, out Dictionary controllers)) - { - controllers = new Dictionary(); - controllerByKey.Add(playerController.playerViewAnimationName, controllers); - } - - int identifier = GetCinematicControllerIdentifier(playerController.gameObject, gameObject); - - if (controllers.ContainsKey(identifier)) - { - return; - } - - MultiplayerCinematicController controller = MultiplayerCinematicController.Initialize(playerController); - controller.AddOtherControllers(allControllers); - allControllers.ForEach(x => x.AddOtherControllers(new[] { controller })); - - controllers.Add(identifier, controller); - } -} diff --git a/NitroxClient/MonoBehaviours/Overrides/RemotePlayerCinematicController.cs b/NitroxClient/MonoBehaviours/Overrides/RemotePlayerCinematicController.cs deleted file mode 100644 index c95bd3990a..0000000000 --- a/NitroxClient/MonoBehaviours/Overrides/RemotePlayerCinematicController.cs +++ /dev/null @@ -1,471 +0,0 @@ -using System; -using NitroxClient.GameLogic; -using UnityEngine; -using static PlayerCinematicController; - -namespace NitroxClient.MonoBehaviours.Overrides; - -/// -/// Override for -/// -public class RemotePlayerCinematicController : MonoBehaviour, IManagedUpdateBehaviour, IManagedLateUpdateBehaviour -{ - [AssertNotNull] public Transform animatedTransform; - - public GameObject informGameObject; - - public Transform endTransform; - - public bool onlyUseEndTransformInVr; - - public bool playInVr; - - public string playerViewAnimationName = ""; - - public string playerViewInterpolateAnimParam = ""; - - public string animParam = "cinematicMode"; - - public string interpolateAnimParam = ""; - - public float interpolationTime = 0.25f; - - public float interpolationTimeOut = 0.25f; - - public string receiversAnimParam = ""; - - public GameObject[] animParamReceivers; - - public bool interpolateDuringAnimation; - - public bool debug; - - public Animator animator; - - [NonSerialized] public bool cinematicModeActive; - - private Vector3 playerFromPosition = Vector3.zero; - - private Quaternion playerFromRotation = Quaternion.identity; - - private bool onCinematicModeEndCall; - - private float timeStateChanged; - - private State _state; - - private RemotePlayer player; - - private bool subscribed; - - private bool _animState; - - public static int cinematicModeCount { get; private set; } - - public static float cinematicActivityStart { get; private set; } - - private State state - { - get => _state; - set - { - timeStateChanged = Time.time; - _state = value; - } - } - - public bool animState - { - get => _animState; - private set - { - if (value == _animState) - { - return; - } - - if (debug) - { - Debug.Log($"setting cinematic controller {gameObject.name} to: {value}"); - } - - _animState = value; - if (animParam.Length > 0) - { - SafeAnimator.SetBool(animator, animParam, value); - } - - if (receiversAnimParam.Length > 0) - { - for (int i = 0; i < animParamReceivers.Length; i++) - { - animParamReceivers[i].GetComponent()?.ForwardAnimationParameterBool(receiversAnimParam, value); - } - } - - if (playerViewAnimationName.Length > 0 && player != null) - { - Animator componentInChildren = player.Body.GetComponentInChildren(); - if (componentInChildren != null && componentInChildren.gameObject.activeInHierarchy) - { - SafeAnimator.SetBool(componentInChildren, playerViewAnimationName, value); - } - } - - SetVrActiveParam(); - } - } - - public int managedUpdateIndex { get; set; } - - public int managedLateUpdateIndex { get; set; } - - public string GetProfileTag() - { - return nameof(RemotePlayerCinematicController); - } - - public void SetPlayer(RemotePlayer setplayer) - { - if (subscribed && player != setplayer) - { - Subscribe(player, false); - Subscribe(setplayer, true); - } - - player = setplayer; - } - - public RemotePlayer GetPlayer() - { - return player; - } - - private void AddToUpdateManager() - { - BehaviourUpdateUtils.Register((IManagedUpdateBehaviour)this); - BehaviourUpdateUtils.Register((IManagedLateUpdateBehaviour)this); - } - - private void RemoveFromUpdateManager() - { - BehaviourUpdateUtils.Deregister((IManagedUpdateBehaviour)this); - BehaviourUpdateUtils.Deregister((IManagedLateUpdateBehaviour)this); - } - - private void OnEnable() - { - AddToUpdateManager(); - } - - private void OnDestroy() - { - RemoveFromUpdateManager(); - } - - private void Start() - { - SetVrActiveParam(); - } - - private void SetVrActiveParam() - { - string paramaterName = "vr_active"; - bool vrAnimationMode = GameOptions.GetVrAnimationMode(); - if (animator != null) - { - animator.SetBool(paramaterName, vrAnimationMode); - } - - foreach (GameObject animatedObject in animParamReceivers) - { - animatedObject.GetComponent()?.ForwardAnimationParameterBool(paramaterName, vrAnimationMode); - } - } - - private bool UseEndTransform() - { - if (endTransform == null) - { - return false; - } - - if (onlyUseEndTransformInVr) - { - return GameOptions.GetVrAnimationMode(); - } - - return true; - } - - private void SkipCinematic(RemotePlayer player) - { - this.player = player; - if (player != null) - { - Transform component = player.Body.GetComponent(); - if (UseEndTransform()) - { - component.position = endTransform.position; - component.rotation = endTransform.rotation; - } - } - - if (informGameObject != null) - { - informGameObject.SendMessage(nameof(CinematicModeTriggerBase.OnPlayerCinematicModeEnd), this, SendMessageOptions.DontRequireReceiver); - } - } - - public void StartCinematicMode(RemotePlayer setplayer) - { - if (debug) - { - Debug.Log($"{gameObject.name}.StartCinematicMode"); - } - - if (!cinematicModeActive) - { - player = null; - if (!playInVr && GameOptions.GetVrAnimationMode()) - { - if (debug) - { - Debug.Log($"{gameObject.name} skip cinematic"); - } - - SkipCinematic(setplayer); - return; - } - - animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; - cinematicModeActive = true; - if (setplayer != null) - { - SetPlayer(setplayer); - Subscribe(player, true); - } - - state = State.In; - if (informGameObject != null) - { - informGameObject.SendMessage(nameof(DockedVehicleHandTarget.OnPlayerCinematicModeStart), this, SendMessageOptions.DontRequireReceiver); - } - - if (player != null) - { - Transform component = player.Body.GetComponent(); - playerFromPosition = component.position; - playerFromRotation = component.rotation; - if (playerViewInterpolateAnimParam.Length > 0) - { - SafeAnimator.SetBool(player.Body.GetComponentInChildren(), playerViewInterpolateAnimParam, true); - } - } - - if (interpolateAnimParam.Length > 0) - { - SafeAnimator.SetBool(animator, interpolateAnimParam, true); - } - - if (interpolateDuringAnimation) - { - animState = true; - } - - if (debug) - { - Debug.Log($"{gameObject.name} successfully started cinematic"); - } - - if (cinematicModeCount == 0) - { - cinematicActivityStart = Time.time; - } - - cinematicModeCount++; - } - else if (debug) - { - Debug.Log($"{gameObject.name} cinematic already active!"); - } - } - - public void EndCinematicMode(bool reset = false) - { - if (cinematicModeActive) - { - if (reset) // Added by us - { - animator.Rebind(); - animator.Update(0f); - } - - animator.cullingMode = AnimatorCullingMode.CullCompletely; - animState = false; - state = State.None; - cinematicModeActive = false; - cinematicModeCount--; - } - } - - public void OnPlayerCinematicModeEnd() - { - if (!cinematicModeActive || onCinematicModeEndCall) - { - return; - } - - if (player != null) - { - UpdatePlayerPosition(); - } - - animState = false; - if (UseEndTransform()) - { - state = State.Out; - if (player != null) - { - Transform component = player.Body.GetComponent(); - playerFromPosition = component.position; - playerFromRotation = component.rotation; - } - } - else - { - EndCinematicMode(); - } - - if (informGameObject != null) - { - onCinematicModeEndCall = true; - informGameObject.SendMessage(nameof(DockedVehicleHandTarget.OnPlayerCinematicModeEnd), this, SendMessageOptions.DontRequireReceiver); - onCinematicModeEndCall = false; - } - } - - private void UpdatePlayerPosition() - { - Transform component = player.Body.GetComponent(); - component.position = animatedTransform.position; - component.rotation = animatedTransform.rotation; - } - - public void ManagedLateUpdate() - { - if (!cinematicModeActive) - { - return; - } - - float num = Time.time - timeStateChanged; - float timedOutScalar; - Transform transform = null; - if (player != null) - { - transform = player.Body.GetComponent(); - } - - bool isVrAnimationMode = !GameOptions.GetVrAnimationMode(); - switch (state) - { - case State.In: - timedOutScalar = interpolationTime != 0f && isVrAnimationMode ? Mathf.Clamp01(num / interpolationTime) : 1f; - if (player != null) - { - transform.position = Vector3.Lerp(playerFromPosition, animatedTransform.position, timedOutScalar); - transform.rotation = Quaternion.Slerp(playerFromRotation, animatedTransform.rotation, timedOutScalar); - } - - if (timedOutScalar == 1f) - { - state = State.Update; - animState = true; - if (interpolateAnimParam.Length > 0) - { - SafeAnimator.SetBool(animator, interpolateAnimParam, false); - } - - if (playerViewInterpolateAnimParam.Length > 0 && player != null) - { - SafeAnimator.SetBool(player.Body.GetComponentInChildren(), playerViewInterpolateAnimParam, false); - } - } - - break; - case State.Update: - if (player != null) - { - UpdatePlayerPosition(); - } - - break; - case State.Out: - timedOutScalar = interpolationTimeOut != 0f && isVrAnimationMode ? Mathf.Clamp01(num / interpolationTimeOut) : 1f; - if (player != null) - { - transform.position = Vector3.Lerp(playerFromPosition, endTransform.position, timedOutScalar); - transform.rotation = Quaternion.Slerp(playerFromRotation, endTransform.rotation, timedOutScalar); - } - - if (timedOutScalar == 1f) - { - EndCinematicMode(); - } - - break; - } - } - - public bool IsCinematicModeActive() - { - return cinematicModeActive; - } - - private void OnDisable() - { - RemoveFromUpdateManager(); - if (subscribed) - { - Subscribe(player, false); - } - - EndCinematicMode(); - } - - private void OnPlayerDeath(RemotePlayer player) - { - EndCinematicMode(); - animator.Rebind(); - } - - private void Subscribe(RemotePlayer player, bool state) - { - if (player == null) - { - subscribed = false; - } - else if (subscribed != state) - { - if (state) - { - player.PlayerDeathEvent.AddHandler(gameObject, OnPlayerDeath); - } - else - { - player.PlayerDeathEvent.RemoveHandler(gameObject, OnPlayerDeath); - } - - subscribed = state; - } - } - - public void ManagedUpdate() - { - if (!cinematicModeActive && subscribed) - { - Subscribe(player, false); - } - } -} diff --git a/NitroxModel/Packets/PlayerCinematicControllerCall.cs b/NitroxModel/Packets/PlayerCinematicControllerCall.cs deleted file mode 100644 index 9f129d6581..0000000000 --- a/NitroxModel/Packets/PlayerCinematicControllerCall.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using NitroxModel.DataStructures; - -namespace NitroxModel.Packets; - -[Serializable] -public class PlayerCinematicControllerCall : Packet -{ - public ushort PlayerId { get; } - public NitroxId ControllerID { get; } - public int ControllerNameHash { get; } - public string Key { get; } - public bool StartPlaying { get; } - - public PlayerCinematicControllerCall(ushort playerId, NitroxId controllerID, int controllerNameHash, string key, bool startPlaying) - { - PlayerId = playerId; - ControllerID = controllerID; - ControllerNameHash = controllerNameHash; - Key = key; - StartPlaying = startPlaying; - } -} diff --git a/NitroxPatcher/Patches/Dynamic/PlayerCinematicController_OnPlayerCinematicModeEnd_Patch.cs b/NitroxPatcher/Patches/Dynamic/PlayerCinematicController_OnPlayerCinematicModeEnd_Patch.cs deleted file mode 100644 index f6aa5bfbff..0000000000 --- a/NitroxPatcher/Patches/Dynamic/PlayerCinematicController_OnPlayerCinematicModeEnd_Patch.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Reflection; -using HarmonyLib; -using NitroxClient.Communication.Abstract; -using NitroxClient.GameLogic.PlayerLogic; -using NitroxClient.MonoBehaviours; -using NitroxClient.MonoBehaviours.Overrides; -using NitroxClient.Unity.Helper; -using NitroxModel.Helper; - -namespace NitroxPatcher.Patches.Dynamic; - -public class PlayerCinematicController_OnPlayerCinematicModeEnd_Patch : NitroxPatch, IDynamicPatch -{ - private static readonly MethodInfo targetMethod = Reflect.Method((PlayerCinematicController t) => t.OnPlayerCinematicModeEnd()); - - private static ushort playerId; - - public static void Prefix(PlayerCinematicController __instance) - { - if (!__instance.cinematicModeActive) - { - return; - } - - if (!__instance.TryGetComponent(out NitroxEntity entity)) - { - entity = __instance.GetComponentInParent(); - if (!entity) - { - Log.Warn($"[{nameof(PlayerCinematicController_OnPlayerCinematicModeEnd_Patch)}] - No NitroxEntity for \"{__instance.GetFullHierarchyPath()}\" found!"); - return; - } - } - - int identifier = MultiplayerCinematicReference.GetCinematicControllerIdentifier(__instance.gameObject, entity.gameObject); - Resolve().EndCinematicMode(playerId, entity.Id, identifier, __instance.playerViewAnimationName); - } - - public override void Patch(Harmony harmony) - { - playerId = Resolve().Reservation.PlayerId; - PatchPrefix(harmony, targetMethod); - } -} diff --git a/NitroxPatcher/Patches/Dynamic/PlayerCinematicController_StartCinematicMode_Patch.cs b/NitroxPatcher/Patches/Dynamic/PlayerCinematicController_StartCinematicMode_Patch.cs deleted file mode 100644 index a51047089f..0000000000 --- a/NitroxPatcher/Patches/Dynamic/PlayerCinematicController_StartCinematicMode_Patch.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Reflection; -using HarmonyLib; -using NitroxClient.Communication.Abstract; -using NitroxClient.GameLogic.PlayerLogic; -using NitroxClient.MonoBehaviours; -using NitroxClient.MonoBehaviours.Overrides; -using NitroxClient.Unity.Helper; -using NitroxModel.Helper; - -namespace NitroxPatcher.Patches.Dynamic; - -public class PlayerCinematicController_StartCinematicMode_Patch : NitroxPatch, IDynamicPatch -{ - private static readonly MethodInfo targetMethod = Reflect.Method((PlayerCinematicController t) => t.StartCinematicMode(default)); - - private static ushort playerId; - - public static void Prefix(PlayerCinematicController __instance) - { - if (__instance.cinematicModeActive) - { - return; - } - - if (!__instance.TryGetComponent(out NitroxEntity entity)) - { - entity = __instance.GetComponentInParent(); - if (!entity) - { - Log.Warn($"[{nameof(PlayerCinematicController_StartCinematicMode_Patch)}] - No NitroxEntity for \"{__instance.GetFullHierarchyPath()}\" found!"); - return; - } - } - - __instance.GetComponent().CallAllCinematicModeEnd(); - - int identifier = MultiplayerCinematicReference.GetCinematicControllerIdentifier(__instance.gameObject, entity.gameObject); - Resolve().StartCinematicMode(playerId, entity.Id, identifier, __instance.playerViewAnimationName); - } - - public override void Patch(Harmony harmony) - { - playerId = Resolve().Reservation.PlayerId; - PatchPrefix(harmony, targetMethod); - } -} diff --git a/NitroxPatcher/Patches/Dynamic/PlayerCinematicController_Start_Patch.cs b/NitroxPatcher/Patches/Dynamic/PlayerCinematicController_Start_Patch.cs deleted file mode 100644 index 46cf27fb00..0000000000 --- a/NitroxPatcher/Patches/Dynamic/PlayerCinematicController_Start_Patch.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Reflection; -using HarmonyLib; -using NitroxClient.MonoBehaviours; -using NitroxClient.MonoBehaviours.Overrides; -using NitroxClient.Unity.Helper; -using NitroxModel.Helper; - -namespace NitroxPatcher.Patches.Dynamic; - -public class PlayerCinematicController_Start_Patch : NitroxPatch, IDynamicPatch -{ - private static readonly MethodInfo targetMethod = Reflect.Method((PlayerCinematicController t) => t.Start()); - - public static void Postfix(PlayerCinematicController __instance) - { - if (!__instance.TryGetComponent(out NitroxEntity entity)) - { - if (!__instance.TryGetComponentInParent(out entity)) - { - Log.Warn($"[PlayerCinematicController_Start_Patch] - No NitroxEntity for \"{__instance.GetFullHierarchyPath()}\" found!"); - return; - } - } - - if (!entity.gameObject.TryGetComponent(out MultiplayerCinematicReference reference)) - { - reference = entity.gameObject.AddComponent(); - } - - reference.AddController(__instance); - } - - public override void Patch(Harmony harmony) - { - PatchPostfix(harmony, targetMethod); - } -} diff --git a/NitroxServer/Communication/Packets/Processors/DefaultServerPacketProcessor.cs b/NitroxServer/Communication/Packets/Processors/DefaultServerPacketProcessor.cs index 3e0bb682f6..8eec6d3544 100644 --- a/NitroxServer/Communication/Packets/Processors/DefaultServerPacketProcessor.cs +++ b/NitroxServer/Communication/Packets/Processors/DefaultServerPacketProcessor.cs @@ -22,8 +22,7 @@ public class DefaultServerPacketProcessor : AuthenticatedPacketProcessor typeof(PlayFMODAsset), typeof(PlayFMODCustomEmitter), typeof(PlayFMODCustomLoopingEmitter), - typeof(PlayFMODStudioEmitter), - typeof(PlayerCinematicControllerCall) + typeof(PlayFMODStudioEmitter) }; public DefaultServerPacketProcessor(PlayerManager playerManager) From aa6aa64dd1130f6f42a084dd6cfb4dc4bab1a703 Mon Sep 17 00:00:00 2001 From: tornac1234 Date: Wed, 7 Dec 2022 20:25:59 +0100 Subject: [PATCH 2/9] Revert "Fixed blog page loading (#1895)" This reverts commit c7577af0be013739f9052ff1e48f694a6afaf8bd. --- .../Assets/Images/{blog/vines.png => old/Vines.png} | Bin NitroxLauncher/Pages/BlogPage.xaml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename NitroxLauncher/Assets/Images/{blog/vines.png => old/Vines.png} (100%) diff --git a/NitroxLauncher/Assets/Images/blog/vines.png b/NitroxLauncher/Assets/Images/old/Vines.png similarity index 100% rename from NitroxLauncher/Assets/Images/blog/vines.png rename to NitroxLauncher/Assets/Images/old/Vines.png diff --git a/NitroxLauncher/Pages/BlogPage.xaml b/NitroxLauncher/Pages/BlogPage.xaml index 0f83878ced..0bad39eed8 100644 --- a/NitroxLauncher/Pages/BlogPage.xaml +++ b/NitroxLauncher/Pages/BlogPage.xaml @@ -11,7 +11,7 @@ Title="BlogPage"> - + From 1ceb93cfd3ee57e99d501ad4ef69398d0109f74d Mon Sep 17 00:00:00 2001 From: tornac1234 Date: Wed, 7 Dec 2022 20:26:26 +0100 Subject: [PATCH 3/9] Revert "Fixed world list not focusing correctly on the items (#1879)" This reverts commit cfd79abc3a00c578e9f52d03f123a8ac85cb83ce. --- NitroxLauncher/Models/WpfControlHelper.cs | 23 -- NitroxLauncher/Pages/ServerPage.xaml | 314 ++++++++++++------ NitroxLauncher/Pages/ServerPage.xaml.cs | 270 ++++++++------- .../Serialization/World/WorldManager.cs | 18 +- NitroxServer/Server.cs | 14 +- 5 files changed, 363 insertions(+), 276 deletions(-) delete mode 100644 NitroxLauncher/Models/WpfControlHelper.cs diff --git a/NitroxLauncher/Models/WpfControlHelper.cs b/NitroxLauncher/Models/WpfControlHelper.cs deleted file mode 100644 index e58a14d3d8..0000000000 --- a/NitroxLauncher/Models/WpfControlHelper.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Windows.Controls; -using System.Windows.Media; - -namespace NitroxLauncher.Models -{ - public static class WpfControlHelper - { - public static T FindDataContextInAncestors(this Control control) - { - do - { - if (control.DataContext is T) - { - return (T)control.DataContext; - } - control = VisualTreeHelper.GetParent(control) as Control; - } while (control != null); - - return default; - } - } -} diff --git a/NitroxLauncher/Pages/ServerPage.xaml b/NitroxLauncher/Pages/ServerPage.xaml index 41506c8e3f..3269ee63c1 100644 --- a/NitroxLauncher/Pages/ServerPage.xaml +++ b/NitroxLauncher/Pages/ServerPage.xaml @@ -287,106 +287,211 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -536,7 +641,8 @@ Background="{x:Null}" BorderBrush="{x:Null}" Margin="13,4,13,4" VerticalAlignment="Center" BorderThickness="0" - CaretBrush="White" MaxLength="40" Text="World name" LostKeyboardFocus="TBWorldName_Input" /> + CaretBrush="White" MaxLength="40" Text="World name" LostKeyboardFocus="TBWorldName_Input"> + @@ -572,7 +678,7 @@ - + @@ -639,7 +745,8 @@ Background="{x:Null}" BorderBrush="{x:Null}" Margin="4" SelectionBrush="#FF007BFF" VerticalAlignment="Center" BorderThickness="0" - CaretBrush="White" Width="Auto" Text="100" LostKeyboardFocus="TBMaxPlayerCap_Input" /> + CaretBrush="White" Width="Auto" Text="100" LostKeyboardFocus="TBMaxPlayerCap_Input"> + @@ -722,7 +829,8 @@ Background="{x:Null}" BorderBrush="{x:Null}" Margin="4" SelectionBrush="#FF007BFF" VerticalAlignment="Center" BorderThickness="0" - CaretBrush="White" Width="Auto" Text="120" LostKeyboardFocus="TBSaveInterval_Input" /> + CaretBrush="White" Width="Auto" Text="120" LostKeyboardFocus="TBSaveInterval_Input"> + @@ -733,7 +841,8 @@ Background="{x:Null}" BorderBrush="{x:Null}" Margin="4" SelectionBrush="#FF007BFF" VerticalAlignment="Center" BorderThickness="0" - CaretBrush="White" Width="Auto" LostKeyboardFocus="TBJoinPassword_Input" /> + CaretBrush="White" Width="Auto" LostKeyboardFocus="TBJoinPassword_Input"> + @@ -745,7 +854,8 @@ Background="{x:Null}" BorderBrush="{x:Null}" Margin="4" SelectionBrush="#FF007BFF" VerticalAlignment="Center" BorderThickness="0" - CaretBrush="White" Width="Auto" MaxLength="5" Text="11000" LostKeyboardFocus="TBWorldServerPort_Input" /> + CaretBrush="White" Width="Auto" MaxLength="5" Text="11000" LostKeyboardFocus="TBWorldServerPort_Input"> + @@ -789,6 +899,7 @@ - @@ -616,46 +617,39 @@ - - + - - - + + - - - - - - - - - - - + + + + - - - - - - - + + + + + + + + + - + VerticalAlignment="Center" BorderThickness="0" CaretBrush="White" Width="155" MaxLength="10" Text="WorldSeed" LostKeyboardFocus="TBWorldSeed_Input" IsReadOnly="{Binding IsNewWorld, FallbackValue=False, Mode=OneWay}"/> + + @@ -870,6 +864,64 @@ + + + + + + + + + + + + + + + + + + diff --git a/NitroxLauncher/Pages/ServerPage.xaml.cs b/NitroxLauncher/Pages/ServerPage.xaml.cs index 69ff584602..b2e2b33b92 100644 --- a/NitroxLauncher/Pages/ServerPage.xaml.cs +++ b/NitroxLauncher/Pages/ServerPage.xaml.cs @@ -18,6 +18,12 @@ namespace NitroxLauncher.Pages { public partial class ServerPage : PageBase { + public bool IsServerExternal + { + get => LauncherLogic.Config.IsExternalServer; + set => LauncherLogic.Config.IsExternalServer = value; + } + public ServerConfig Config; public bool IsNewWorld { get; private set; } @@ -32,10 +38,10 @@ public partial class ServerPage : PageBase public ServerPage() { InitializeComponent(); - InitializeWorldListing(); - RBIsDocked.IsChecked = !LauncherLogic.Config.IsExternalServer; - RBIsExternal.IsChecked = LauncherLogic.Config.IsExternalServer; + + RBIsDocked.IsChecked = !IsServerExternal; + RBIsExternal.IsChecked = IsServerExternal; } private void RBServer_Clicked(object sender, RoutedEventArgs e) @@ -49,6 +55,7 @@ public void InitializeWorldListing() NoWorldsBackground.Opacity = WorldManager.GetSaves().Any() ? 0 : 1; + // Bind the list data to be used in XAML WorldListingContainer.ItemsSource = null; WorldListingContainer.ItemsSource = WorldManager.GetSaves(); } @@ -268,9 +275,19 @@ private void DeleteWorld_Click(object sender, RoutedEventArgs e) { LauncherNotifier.Error($"This save does not exist or is not valid."); InitializeWorldListing(); + if (e.OriginalSource == DeleteWorldBtn) + { + Storyboard GoBackAnimationStoryboard = (Storyboard)FindResource("GoBackAnimation"); + GoBackAnimationStoryboard.Begin(); + } return; } + if (e.OriginalSource == DeleteWorldBtn) + { + isInSettings = true; + } + ConfirmationBox.Opacity = 1; ConfirmationBox.IsHitTestVisible = true; } @@ -845,20 +862,12 @@ private void StartServer_Click(object sender, RoutedEventArgs e) } - [Serializable] - internal class WorldListing + // OPTIONAL - Only used to view world listings in intellisense, in addition to the lines that are in the ListView definition in ServerPage.xaml + public class WorldListing { public string WorldName { get; set; } - public string WorldGamemode { get; set; } - public string WorldVersion { get; set; } - public bool IsValidSave { get; set; } - - public override string ToString() - { - return $"[{nameof(WorldListing)}: WorldName: {WorldName}, WorldGamemode: {WorldGamemode}, WorldVersion: {WorldVersion}, IsValidSave: {IsValidSave}]"; - } } } diff --git a/NitroxLauncher/Pages/UpdatePage.xaml b/NitroxLauncher/Pages/UpdatePage.xaml index 35b7b6b11a..a8d77b57c4 100644 --- a/NitroxLauncher/Pages/UpdatePage.xaml +++ b/NitroxLauncher/Pages/UpdatePage.xaml @@ -12,7 +12,7 @@ Title="UpdatePage"> - + From 5dd66bb13b735ab0c55c458cde80e4ddc4506599 Mon Sep 17 00:00:00 2001 From: tornac1234 Date: Wed, 7 Dec 2022 20:28:26 +0100 Subject: [PATCH 5/9] Revert "Fixing variable access error in launcher" This reverts commit 66d9b821cecaf8a4156294843937dec5296d5312. --- NitroxLauncher/Pages/ServerPage.xaml | 4 ++-- NitroxLauncher/Pages/ServerPage.xaml.cs | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/NitroxLauncher/Pages/ServerPage.xaml b/NitroxLauncher/Pages/ServerPage.xaml index a4d0c67bb0..927b5f7b8a 100644 --- a/NitroxLauncher/Pages/ServerPage.xaml +++ b/NitroxLauncher/Pages/ServerPage.xaml @@ -647,7 +647,7 @@ Foreground="#8A8A8A" TextAlignment="Left" Background="{x:Null}" BorderBrush="{x:Null}" Margin="13,4,13,4" SelectionBrush="#FF007BFF" - VerticalAlignment="Center" BorderThickness="0" CaretBrush="White" Width="155" MaxLength="10" Text="WorldSeed" LostKeyboardFocus="TBWorldSeed_Input" IsReadOnly="{Binding IsNewWorld, FallbackValue=False, Mode=OneWay}"/> + VerticalAlignment="Center" BorderThickness="0" CaretBrush="White" Width="155" MaxLength="10" Text="WorldSeed" LostKeyboardFocus="TBWorldSeed_Input" IsReadOnly="{Binding isNewWorld, FallbackValue=False, Mode=OneWay}"/> @@ -1148,4 +1148,4 @@ - + \ No newline at end of file diff --git a/NitroxLauncher/Pages/ServerPage.xaml.cs b/NitroxLauncher/Pages/ServerPage.xaml.cs index b2e2b33b92..6065c7c855 100644 --- a/NitroxLauncher/Pages/ServerPage.xaml.cs +++ b/NitroxLauncher/Pages/ServerPage.xaml.cs @@ -26,7 +26,7 @@ public bool IsServerExternal public ServerConfig Config; - public bool IsNewWorld { get; private set; } + private bool isNewWorld { get; set; } private bool isInSettings { get; set; } private string selectedWorldDirectory { get; set; } @@ -76,7 +76,7 @@ public void SaveConfigSettings() Config.Update(selectedWorldDirectory, c => { c.SaveName = TBWorldName.Text; - if (IsNewWorld) { c.Seed = TBWorldSeed.Text; } + if (isNewWorld) { c.Seed = TBWorldSeed.Text; } if (RBFreedom.IsChecked == true) { c.GameMode = ServerGameMode.FREEDOM; } else if (RBSurvival.IsChecked == true) { c.GameMode = ServerGameMode.SURVIVAL; } else if (RBCreative.IsChecked == true) { c.GameMode = ServerGameMode.CREATIVE; } @@ -160,7 +160,7 @@ public void UpdateVisualWorldSettings() public void AddWorld_Click(object sender, RoutedEventArgs e) { Log.Info($"Adding new world"); - IsNewWorld = true; + isNewWorld = true; TBWorldSeed.IsReadOnly = false; ImportSaveBtnBorder.Opacity = 1; @@ -181,7 +181,7 @@ private void RefreshListing_Click(object sender, RoutedEventArgs e) private void GoBack_Click(object sender, RoutedEventArgs e) { - if (!IsNewWorld) + if (!isNewWorld) { selectedWorldDirectory = WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir; } @@ -195,7 +195,7 @@ private void GoBack_Click(object sender, RoutedEventArgs e) { SaveConfigSettings(); InitializeWorldListing(); - IsNewWorld = false; + isNewWorld = false; isInSettings = false; ImportSaveBtnBorder.Opacity = 0; @@ -261,7 +261,7 @@ private void RestoreBackup_Click(object sender, RoutedEventArgs e) private void DeleteWorld_Click(object sender, RoutedEventArgs e) { - if (!IsNewWorld) + if (!isNewWorld) { selectedWorldDirectory = WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir; } @@ -294,11 +294,11 @@ private void DeleteWorld_Click(object sender, RoutedEventArgs e) private void YesConfirmBtn_Click(object sender, RoutedEventArgs e) { - if (!IsNewWorld) + if (!isNewWorld) { selectedWorldDirectory = WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir ?? ""; } - IsNewWorld = false; + isNewWorld = false; try { @@ -317,7 +317,7 @@ private void YesConfirmBtn_Click(object sender, RoutedEventArgs e) if (isInSettings) { - IsNewWorld = false; + isNewWorld = false; ImportSaveBtnBorder.Opacity = 0; ImportSaveBtn.IsEnabled = false; From c4903d0cb1a04202f53f345df412555f422971c9 Mon Sep 17 00:00:00 2001 From: tornac1234 Date: Wed, 7 Dec 2022 20:32:06 +0100 Subject: [PATCH 6/9] Revert "Add a World manager to the launcher (#1808)" This reverts commit 76458a617e030643abf90fe849e7d7c0ba1e0524. --- NitroxLauncher/App.xaml | 195 +-- .../material-design-icons/add_server.png | Bin 20324 -> 0 bytes .../material-design-icons/docked-icon.png | Bin 63711 -> 0 bytes .../material-design-icons/external-icon.jpg | Bin 7701 -> 0 bytes .../Images/material-design-icons/go_back.png | Bin 18425 -> 0 bytes .../Images/material-design-icons/refresh.png | Bin 37477 -> 0 bytes .../restore-backup-icon.png | Bin 4158 -> 0 bytes .../material-design-icons/trashcan_icon.png | Bin 5207 -> 0 bytes NitroxLauncher/LauncherLogic.cs | 2 +- NitroxLauncher/NitroxLauncher.csproj | 5 - NitroxLauncher/Pages/OptionPage.xaml | 37 +- NitroxLauncher/Pages/OptionPage.xaml.cs | 8 - NitroxLauncher/Pages/ServerPage.xaml | 1163 +---------------- NitroxLauncher/Pages/ServerPage.xaml.cs | 850 +----------- NitroxLauncher/ServerLogic.cs | 4 +- NitroxModel/Serialization/NitroxConfig.cs | 20 +- NitroxModel/Serialization/ServerList.cs | 2 +- NitroxServer-Subnautica/Program.cs | 1 + .../ConsoleCommands/AutosaveCommand.cs | 7 +- .../ChangeAdminPasswordCommand.cs | 7 +- .../ChangeServerGamemodeCommand.cs | 7 +- .../ChangeServerPasswordCommand.cs | 7 +- NitroxServer/ConsoleCommands/ConfigCommand.cs | 9 +- NitroxServer/ConsoleCommands/StopCommand.cs | 2 +- .../ConsoleCommands/SwapSerializerCommand.cs | 5 +- NitroxServer/Serialization/ServerConfig.cs | 8 +- .../Serialization/World/SaveFileVersion.cs | 5 - .../Serialization/World/WorldManager.cs | 176 --- .../Serialization/World/WorldPersistence.cs | 28 +- NitroxServer/Server.cs | 49 +- NitroxServer/ServerAutoFacRegistrar.cs | 3 +- 31 files changed, 103 insertions(+), 2497 deletions(-) delete mode 100644 NitroxLauncher/Images/material-design-icons/add_server.png delete mode 100644 NitroxLauncher/Images/material-design-icons/docked-icon.png delete mode 100644 NitroxLauncher/Images/material-design-icons/external-icon.jpg delete mode 100644 NitroxLauncher/Images/material-design-icons/go_back.png delete mode 100644 NitroxLauncher/Images/material-design-icons/refresh.png delete mode 100644 NitroxLauncher/Images/material-design-icons/restore-backup-icon.png delete mode 100644 NitroxLauncher/Images/material-design-icons/trashcan_icon.png delete mode 100644 NitroxServer/Serialization/World/WorldManager.cs diff --git a/NitroxLauncher/App.xaml b/NitroxLauncher/App.xaml index 408b3afa6d..68c2d64fe5 100644 --- a/NitroxLauncher/App.xaml +++ b/NitroxLauncher/App.xaml @@ -2,8 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ap="clr-namespace:NitroxLauncher.Models.Properties" - xmlns:pages="clr-namespace:NitroxLauncher.Pages" xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero2" - xmlns:converters="clr-namespace:NitroxLauncher.Models.Converters" + xmlns:pages="clr-namespace:NitroxLauncher.Pages" StartupUri="MainWindow.xaml" DispatcherUnhandledException="Application_DispatcherUnhandledException"> @@ -132,192 +131,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Welcome to your Nitrox server! For more information, please refer to the Wiki - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - + \ No newline at end of file diff --git a/NitroxLauncher/Pages/ServerPage.xaml.cs b/NitroxLauncher/Pages/ServerPage.xaml.cs index 6065c7c855..a957667ce4 100644 --- a/NitroxLauncher/Pages/ServerPage.xaml.cs +++ b/NitroxLauncher/Pages/ServerPage.xaml.cs @@ -1,873 +1,37 @@ using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text.RegularExpressions; using System.Windows; -using System.Windows.Input; -using System.Windows.Media.Animation; -using Microsoft.WindowsAPICodePack.Dialogs; using NitroxLauncher.Models; -using NitroxModel.DataStructures.GameLogic; -using NitroxModel.Server; -using NitroxServer.Serialization; -using NitroxServer.Serialization.World; -using Microsoft.VisualBasic.FileIO; namespace NitroxLauncher.Pages { public partial class ServerPage : PageBase { - public bool IsServerExternal - { - get => LauncherLogic.Config.IsExternalServer; - set => LauncherLogic.Config.IsExternalServer = value; - } - - public ServerConfig Config; - - private bool isNewWorld { get; set; } - private bool isInSettings { get; set; } - - private string selectedWorldDirectory { get; set; } - private string worldDirCurrentlyUsed { get; set; } - private string importedWorldName { get; set; } - private string selectedWorldImportDirectory { get; set; } - private string selectedServerCfgImportDirectory { get; set; } + public string StartButtonSubtitle => $"NITROX {LauncherLogic.ReleasePhase} {LauncherLogic.Version}"; + private bool IsServerExternal => LauncherLogic.Config.IsExternalServer; public ServerPage() { InitializeComponent(); - InitializeWorldListing(); RBIsDocked.IsChecked = !IsServerExternal; RBIsExternal.IsChecked = IsServerExternal; } - private void RBServer_Clicked(object sender, RoutedEventArgs e) - { - LauncherLogic.Config.IsExternalServer = RBIsExternal.IsChecked ?? true; - } - - public void InitializeWorldListing() - { - WorldManager.Refresh(); - - NoWorldsBackground.Opacity = WorldManager.GetSaves().Any() ? 0 : 1; - - // Bind the list data to be used in XAML - WorldListingContainer.ItemsSource = null; - WorldListingContainer.ItemsSource = WorldManager.GetSaves(); - } - - // File Management - public void SaveConfigSettings() - { - // If world name was changed, rename save folder to match it - string dest = Path.Combine(Path.GetDirectoryName(selectedWorldDirectory) ?? throw new Exception("Selected world is empty"), TBWorldName.Text); - if (selectedWorldDirectory != dest) - { - Directory.Move(selectedWorldDirectory, dest+" temp"); // These two lines are needed to handle names that change in capitalization, - Directory.Move(dest+" temp", dest); // since Windows still thinks of the two names as the same. - selectedWorldDirectory = dest; - } - - Config = ServerConfig.Load(selectedWorldDirectory); - Config.Update(selectedWorldDirectory, c => - { - c.SaveName = TBWorldName.Text; - if (isNewWorld) { c.Seed = TBWorldSeed.Text; } - if (RBFreedom.IsChecked == true) { c.GameMode = ServerGameMode.FREEDOM; } - else if (RBSurvival.IsChecked == true) { c.GameMode = ServerGameMode.SURVIVAL; } - else if (RBCreative.IsChecked == true) { c.GameMode = ServerGameMode.CREATIVE; } - else if (RBHardcore.IsChecked == true) { c.GameMode = ServerGameMode.HARDCORE; } - - c.DisableConsole = !CBCheats.IsChecked ?? c.DisableConsole; - c.MaxConnections = Convert.ToInt32(TBMaxPlayerCap.Text); - c.DefaultPlayerPerm = CBBDefaultPerms.SelectedIndex switch - { - 0 => Perms.PLAYER, - 1 => Perms.MODERATOR, - 2 => Perms.ADMIN, - _ => c.DefaultPlayerPerm - }; - c.CreateFullEntityCache = CBCreateFullEntityCache.IsChecked ?? c.CreateFullEntityCache; - c.DisableAutoSave = !CBAutoSave.IsChecked ?? c.DisableAutoSave; - c.AutoPortForward = CBAutoPortForward.IsChecked ?? c.AutoPortForward; - c.SaveInterval = Convert.ToInt32(TBSaveInterval.Text)*1000; // Convert seconds to milliseconds - if (CBEnableJoinPassword.IsChecked ?? false) - { - c.ServerPassword = TBJoinPassword.Text; - } - else { c.ServerPassword = string.Empty; } - c.ServerPort = Convert.ToInt32(TBWorldServerPort.Text); - c.LANDiscoveryEnabled = CBLanDiscovery.IsChecked ?? c.LANDiscoveryEnabled; - }); - - } - - public void UpdateVisualWorldSettings() - { - Config = ServerConfig.Load(selectedWorldDirectory); - - // Set the world settings values to the server.cfg values - TBWorldName.Text = Path.GetFileName(selectedWorldDirectory); - TBWorldSeed.Text = Config.Seed; - switch (Config.GameMode) - { - case ServerGameMode.FREEDOM: - RBFreedom.IsChecked = true; - break; - case ServerGameMode.SURVIVAL: - RBSurvival.IsChecked = true; - break; - case ServerGameMode.CREATIVE: - RBCreative.IsChecked = true; - break; - case ServerGameMode.HARDCORE: - RBHardcore.IsChecked = true; - break; - } - CBCheats.IsChecked = !Config.DisableConsole; - TBMaxPlayerCap.Text = Convert.ToString(Config.MaxConnections); - CBBDefaultPerms.SelectedIndex = Config.DefaultPlayerPerm switch - { - Perms.PLAYER => 0, - Perms.MODERATOR => 1, - Perms.ADMIN => 2, - _ => CBBDefaultPerms.SelectedIndex - }; - CBCreateFullEntityCache.IsChecked = Config.CreateFullEntityCache; - CBAutoSave.IsChecked = !Config.DisableAutoSave; - CBEnableJoinPassword.IsChecked = Config.IsPasswordRequired; - CBAutoPortForward.IsChecked = Config.AutoPortForward; - TBSaveInterval.Text = Convert.ToString(Config.SaveInterval/1000); // Convert milliseconds to seconds - TBJoinPassword.Text = Config.ServerPassword; - if (string.IsNullOrEmpty(Config.ServerPassword)) { TBJoinPassword.IsEnabled = false; JoinPasswordTitle.Opacity = .6; } - TBWorldServerPort.Text = Convert.ToString(Config.ServerPort); - CBLanDiscovery.IsChecked = Config.LANDiscoveryEnabled; - - if (Config.IsPasswordRequired) - { - TBJoinPassword.Opacity = 1; - JoinPasswordTitle.Opacity = 1; - TBJoinPassword.IsEnabled = true; - } - - } - - // Pane Buttons - public void AddWorld_Click(object sender, RoutedEventArgs e) - { - Log.Info($"Adding new world"); - isNewWorld = true; - TBWorldSeed.IsReadOnly = false; - - ImportSaveBtnBorder.Opacity = 1; - ImportSaveBtn.IsEnabled = true; - - selectedWorldDirectory = WorldManager.CreateEmptySave("My World"); - UpdateVisualWorldSettings(); - - Storyboard WorldSelectedAnimationStoryboard = (Storyboard)FindResource("WorldSelectedAnimation"); - WorldSelectedAnimationStoryboard.Begin(); - - } - - private void RefreshListing_Click(object sender, RoutedEventArgs e) - { - InitializeWorldListing(); - } - - private void GoBack_Click(object sender, RoutedEventArgs e) - { - if (!isNewWorld) - { - selectedWorldDirectory = WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir; - } - - if (!Directory.Exists(selectedWorldDirectory)) - { - LauncherNotifier.Error($"This save does not exist or is not valid."); - InitializeWorldListing(); - } - else - { - SaveConfigSettings(); - InitializeWorldListing(); - isNewWorld = false; - isInSettings = false; - - ImportSaveBtnBorder.Opacity = 0; - ImportSaveBtn.IsEnabled = false; - } - - Storyboard GoBackAnimationStoryboard = (Storyboard)FindResource("GoBackAnimation"); - GoBackAnimationStoryboard.Begin(); - } - - private void ImportSaveBtn_Click(object sender, RoutedEventArgs e) - { - importedWorldName = string.Empty; - selectedWorldImportDirectory = string.Empty; - selectedServerCfgImportDirectory = string.Empty; - TBImportedWorldName.Text = string.Empty; - TBSelectedSaveImportDir.Text = "Select the save file to import"; - TBSelectedServerCfgImportDir.Text = "Select the server.cfg file to import"; - - ImportWorldBox.Opacity = 1; - ImportWorldBox.IsHitTestVisible = true; - SelectImportedServerCfgBtn.IsEnabled = false; - SelectImportedServerCfgBtn.Opacity = .6; - ImportWorldBtn.IsEnabled = false; - ImportWorldBtn.Opacity = .6; - } - - // World management - private void SelectedWorldSettings_Click(object sender, RoutedEventArgs e) - { - if (LauncherLogic.Server.IsServerRunning && worldDirCurrentlyUsed == WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir) - { - LauncherNotifier.Error("This world is currently being used. Stop the server to edit the settings of this world"); - return; - } - else if (!Directory.Exists(WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir)) - { - LauncherNotifier.Error($"This save does not exist or is not valid."); - InitializeWorldListing(); - return; - } - else if (!WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex).IsValidSave) - { - LauncherNotifier.Error($"This save is an invalid version."); - return; - } - - TBWorldSeed.IsReadOnly = true; - - selectedWorldDirectory = WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir ?? ""; - - UpdateVisualWorldSettings(); - - Storyboard WorldSelectedAnimationStoryboard = (Storyboard)FindResource("WorldSelectedAnimation"); - WorldSelectedAnimationStoryboard.Begin(); - } - - // Restore Backup Button (TODO) - private void RestoreBackup_Click(object sender, RoutedEventArgs e) - { - throw new NotImplementedException(); - } - - private void DeleteWorld_Click(object sender, RoutedEventArgs e) - { - if (!isNewWorld) - { - selectedWorldDirectory = WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir; - } - - if (LauncherLogic.Server.IsServerRunning && worldDirCurrentlyUsed == WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir) - { - LauncherNotifier.Error("This world is currently being used. Stop the server to delete this world"); - return; - } - else if (!Directory.Exists(selectedWorldDirectory)) - { - LauncherNotifier.Error($"This save does not exist or is not valid."); - InitializeWorldListing(); - if (e.OriginalSource == DeleteWorldBtn) - { - Storyboard GoBackAnimationStoryboard = (Storyboard)FindResource("GoBackAnimation"); - GoBackAnimationStoryboard.Begin(); - } - return; - } - - if (e.OriginalSource == DeleteWorldBtn) - { - isInSettings = true; - } - - ConfirmationBox.Opacity = 1; - ConfirmationBox.IsHitTestVisible = true; - } - - private void YesConfirmBtn_Click(object sender, RoutedEventArgs e) - { - if (!isNewWorld) - { - selectedWorldDirectory = WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir ?? ""; - } - isNewWorld = false; - - try - { - FileSystem.DeleteDirectory(selectedWorldDirectory, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin); - Log.Info($"Moving world \"{Path.GetFileName(selectedWorldDirectory)}\" to the recyling bin."); - LauncherNotifier.Success($"Successfully moved save \"{Path.GetFileName(selectedWorldDirectory)}\" to the recycling bin"); - } - catch (Exception ex) - { - LauncherNotifier.Error("Error: Could not move the selected save to the recycling bin. Try deleting any remaining files manually."); - Log.Error($"Could not move save \"{Path.GetFileName(selectedWorldDirectory)}\" to the recycling bin : {ex.GetType()} {ex.Message}"); - } - - ConfirmationBox.Opacity = 0; - ConfirmationBox.IsHitTestVisible = false; - - if (isInSettings) - { - isNewWorld = false; - ImportSaveBtnBorder.Opacity = 0; - ImportSaveBtn.IsEnabled = false; - - Storyboard GoBackAnimationStoryboard = (Storyboard)FindResource("GoBackAnimation"); - GoBackAnimationStoryboard.Begin(); - } - isInSettings = false; - - InitializeWorldListing(); - } - - private void NoConfirmBtn_Click(object sender, RoutedEventArgs e) - { - ConfirmationBox.Opacity = 0; - ConfirmationBox.IsHitTestVisible = false; - InitializeWorldListing(); - } - - // World settings management - private void TBWorldName_Input(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e) - { - string originalName = Path.GetFileName(selectedWorldDirectory); - - TBWorldName.Text = TBWorldName.Text.TrimStart(); - TBWorldName.Text = TBWorldName.Text.TrimEnd(); - - // Make sure the string isn't empty - if (!string.IsNullOrEmpty(TBWorldName.Text)) - { - // Make sure the world name is valid as a file name - bool isIllegalName = false; - char[] illegalChars = Path.GetInvalidFileNameChars(); - for (int i = 0; !isIllegalName && i < illegalChars.Length; i++) - { - isIllegalName = TBWorldName.Text.Contains(illegalChars[i]); - } - - if (isIllegalName) - { - TBWorldName.Text = string.Join("_", TBWorldName.Text.Split(Path.GetInvalidFileNameChars())); - LauncherNotifier.Error("World names cannot contain these characters: < > : \" / \\ | ? *"); - } - - // Check that name is not a duplicate if it was changed - string newSelectedWorldDirectory = Path.Combine(Path.GetDirectoryName(selectedWorldDirectory) ?? throw new Exception("Selected world is empty"), TBWorldName.Text); - if (!newSelectedWorldDirectory.Equals(selectedWorldDirectory, StringComparison.OrdinalIgnoreCase) && Directory.Exists(newSelectedWorldDirectory)) - { - if (WorldManager.ValidateSave(newSelectedWorldDirectory)) - { - LauncherNotifier.Error($"World name \"{TBWorldName.Text}\" already exists."); - } - else - { - LauncherNotifier.Error($"A folder named \"{TBWorldName.Text}\" already exists in the saves folder."); - } - - int i = 1; - Regex rx = new(@"\((\d+)\)$"); - if (!rx.IsMatch(TBWorldName.Text)) - { - originalName = TBWorldName.Text + $" ({i})"; - newSelectedWorldDirectory = Path.Combine(Path.GetDirectoryName(selectedWorldDirectory) ?? throw new Exception("Selected world is empty"), originalName); - } - - while (Directory.Exists(newSelectedWorldDirectory) && !newSelectedWorldDirectory.Equals(selectedWorldDirectory, StringComparison.OrdinalIgnoreCase)) - { - // Increment the number to the end of the name until it reaches an available filename - originalName = rx.Replace(originalName, $"({i})", 1); - newSelectedWorldDirectory = Path.Combine(Path.GetDirectoryName(selectedWorldDirectory) ?? throw new Exception("Selected world is empty"), originalName); - i++; - } - - TBWorldName.Text = originalName; - } - - } - else - { - TBWorldName.Text = originalName; - LauncherNotifier.Error($"An empty world name is not valid."); - } - } - - private void TBWorldSeed_Input(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e) - { - TBWorldSeed.Text = TBWorldSeed.Text.TrimStart(); - TBWorldSeed.Text = TBWorldSeed.Text.TrimEnd(); - - if (!string.IsNullOrEmpty(TBWorldSeed.Text)) - { - string originalSeed = Config.Seed; - - TBWorldSeed.Text = TBWorldSeed.Text.ToUpper(); - - if (TBWorldSeed.Text.Length != 10 || !Regex.IsMatch(TBWorldSeed.Text, @"^[a-zA-Z]+$")) - { - TBWorldSeed.Text = originalSeed; - LauncherNotifier.Error($"World Seeds should contain 10 alphabetical characters (A-Z)."); - } - } - - Config.Seed = TBWorldSeed.Text; - } - - private void TBMaxPlayerCap_Input(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e) - { - string originalMaxPlayerCap = Convert.ToString(Config.MaxConnections); - - TBMaxPlayerCap.Text = TBMaxPlayerCap.Text.TrimStart(); - TBMaxPlayerCap.Text = TBMaxPlayerCap.Text.TrimEnd(); - - if (string.IsNullOrEmpty(TBMaxPlayerCap.Text)) - { - TBMaxPlayerCap.Text = originalMaxPlayerCap; - LauncherNotifier.Error($"An empty Max Player Cap value is not valid."); - return; - } - - int maxPlayerCapNum; - try - { - maxPlayerCapNum = Convert.ToInt32(TBMaxPlayerCap.Text); - } - catch - { - TBMaxPlayerCap.Text = originalMaxPlayerCap; - LauncherNotifier.Error($"Max Player Cap input should only contain numbers."); - return; - } - - // Limit save interval value to numbers greater than 0 - if (maxPlayerCapNum <= 0) - { - TBMaxPlayerCap.Text = originalMaxPlayerCap; - LauncherNotifier.Error($"The Max Player Cap value cannot be zero or negative."); - return; - } - - Config.MaxConnections = maxPlayerCapNum; - } - - private void CBEnableJoinPassword_Clicked(object sender, RoutedEventArgs e) - { - if (CBEnableJoinPassword.IsChecked ?? false) - { - TBJoinPassword.Opacity = 1; - JoinPasswordTitle.Opacity = 1; - TBJoinPassword.IsEnabled = true; - Keyboard.Focus(TBJoinPassword); - } - else - { - TBJoinPassword.Opacity = .7; - JoinPasswordTitle.Opacity = .6; - TBJoinPassword.IsEnabled = false; - } - } - - private void TBSaveInterval_Input(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e) - { - string originalSaveInterval = Convert.ToString(Config.SaveInterval/1000); - - TBSaveInterval.Text = TBSaveInterval.Text.TrimStart(); - TBSaveInterval.Text = TBSaveInterval.Text.TrimEnd(); - - if (string.IsNullOrEmpty(TBSaveInterval.Text)) - { - TBSaveInterval.Text = originalSaveInterval; - LauncherNotifier.Error($"An empty Save Interval value is not valid."); - return; - } - - int saveIntervalNum; - try - { - saveIntervalNum = Convert.ToInt32(TBSaveInterval.Text)*1000; - } - catch - { - TBSaveInterval.Text = originalSaveInterval; - LauncherNotifier.Error($"Save Interval input should only contain numbers."); - return; - } - - // Limit save interval value to numbers greater than 1 - if (saveIntervalNum < 1) - { - TBSaveInterval.Text = originalSaveInterval; - LauncherNotifier.Error($"The Save Interval value must be greater than 1."); - return; - } - - Config.SaveInterval = saveIntervalNum; - } - - private void TBJoinPassword_Input(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e) - { - TBJoinPassword.Text = TBJoinPassword.Text.TrimStart(); - TBJoinPassword.Text = TBJoinPassword.Text.TrimEnd(); - - if (string.IsNullOrEmpty(TBJoinPassword.Text) && CBEnableJoinPassword.IsMouseOver == false) - { - CBEnableJoinPassword.IsChecked = false; - TBJoinPassword.IsEnabled = false; - JoinPasswordTitle.Opacity = .6; - } - } - - private void TBWorldServerPort_Input(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e) - { - string originalServerPort = Convert.ToString(Config.ServerPort); - - TBWorldServerPort.Text = TBWorldServerPort.Text.TrimStart(); - TBWorldServerPort.Text = TBWorldServerPort.Text.TrimEnd(); - - if (string.IsNullOrEmpty(TBWorldServerPort.Text)) - { - TBWorldServerPort.Text = originalServerPort; - LauncherNotifier.Error($"An empty Server Port value is not valid."); - return; - } - - int serverPortNum; - try - { - serverPortNum = Convert.ToInt32(TBWorldServerPort.Text); - } - catch - { - TBWorldServerPort.Text = originalServerPort; - LauncherNotifier.Error($"Server Port input should only contain numbers."); - return; - } - - // Limit the input to numbers in between ports 1024 and 65535 - if (serverPortNum < 1024 || serverPortNum > 65535) - { - TBWorldServerPort.Text = originalServerPort; - LauncherNotifier.Error($"Only port numbers between 1024 and 65535 are allowed."); - return; - } - - Config.ServerPort = serverPortNum; - } - - // TODO: Redirect user to the "Mods/Plugins" tab of the launcher (for future reference if mod support is added) so that they can enable/disable mods - private void ViewModsPlugins_Click(object sender, RoutedEventArgs e) - { - throw new NotImplementedException(); - } - - // Save File Import - private void TBImportedWorldName_Input(object sender, KeyboardFocusChangedEventArgs e) // UX TODO: Set this textbox to be the same as the original world name - { - TBImportedWorldName.Text = TBImportedWorldName.Text.TrimStart(); - TBImportedWorldName.Text = TBImportedWorldName.Text.TrimEnd(); - - // Make sure the string isn't empty - if (!string.IsNullOrEmpty(TBImportedWorldName.Text)) - { - // Make sure the world name is valid as a file name - bool isIllegalName = false; - char[] illegalChars = Path.GetInvalidFileNameChars(); - for (int i = 0; !isIllegalName && i < illegalChars.Length; i++) - { - isIllegalName = TBImportedWorldName.Text.Contains(illegalChars[i]); - } - - if (isIllegalName) - { - TBImportedWorldName.Text = string.Join("_", TBImportedWorldName.Text.Split(Path.GetInvalidFileNameChars())); - LauncherNotifier.Error("World names cannot contain these characters: < > : \" / \\ | ? *"); - } - - // Check that name is not a duplicate if it was changed - string newSelectedWorldDirectory = Path.Combine(WorldManager.SavesFolderDir, TBImportedWorldName.Text); - if (!TBImportedWorldName.Text.Equals(importedWorldName, StringComparison.OrdinalIgnoreCase) && Directory.Exists(newSelectedWorldDirectory)) - { - if (WorldManager.ValidateSave(newSelectedWorldDirectory)) - { - LauncherNotifier.Error($"World name \"{TBImportedWorldName.Text}\" already exists."); - } - else - { - LauncherNotifier.Error($"A folder named \"{TBImportedWorldName.Text}\" already exists in the saves folder."); - } - - int i = 1; - Regex rx = new(@"\((\d+)\)$"); - if (!rx.IsMatch(TBImportedWorldName.Text)) - { - importedWorldName = TBImportedWorldName.Text + $" ({i})"; - newSelectedWorldDirectory = Path.Combine(WorldManager.SavesFolderDir, importedWorldName); - } - - // If save name still exists, increment the number to the end of the name until it reaches an available filename - while (Directory.Exists(newSelectedWorldDirectory)) - { - importedWorldName = rx.Replace(importedWorldName, $"({i})", 1); - newSelectedWorldDirectory = Path.Combine(WorldManager.SavesFolderDir, importedWorldName); - i++; - } - - TBImportedWorldName.Text = importedWorldName; - } - - importedWorldName = TBImportedWorldName.Text; - - // Enable the "Import" button if user has selected a save file and a server.cfg file - if (!string.IsNullOrEmpty(selectedWorldImportDirectory) && !string.IsNullOrEmpty(selectedServerCfgImportDirectory)) - { - ImportWorldBtn.IsEnabled = true; - ImportWorldBtn.Opacity = 1; - } - - } - else - { - ImportWorldBtn.IsEnabled = false; - ImportWorldBtn.Opacity = .6; - } - } - - private void SelectImportedSaveFileBtn_Click(object sender, RoutedEventArgs e) - { - using (CommonOpenFileDialog dialog = new() - { - Multiselect = false, - InitialDirectory = System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), - EnsurePathExists = true, - IsFolderPicker = true, - Title = "Select the save file to import" - }) - { - if (dialog.ShowDialog() != CommonFileDialogResult.Ok) - { - return; - } - selectedWorldImportDirectory = Path.GetFullPath(dialog.FileName); - } - if (Convert.ToString(Directory.GetParent(selectedWorldImportDirectory)) == WorldManager.SavesFolderDir) - { - LauncherNotifier.Error("There is no point in importing a save file you already have in the saves directory. Please select a different save file to import."); - return; - } - if (!WorldManager.ValidateSave(selectedWorldImportDirectory)) - { - // Give special warning if game save file is selected - if (File.Exists(Path.Combine(selectedWorldImportDirectory, "gameinfo.json")) && File.Exists(Path.Combine(selectedWorldImportDirectory, "global-objects.bin")) && File.Exists(Path.Combine(selectedWorldImportDirectory, "scene-objects.bin"))) - { - LauncherNotifier.Error("Singleplayer saves cannot be imported and used by Nitrox: Save formats are incompatible."); - } - else if (File.Exists(Path.Combine(selectedWorldImportDirectory, "WorldData.nitrox")) && !File.Exists(Path.Combine(selectedWorldImportDirectory, "WorldData.json"))) - { - LauncherNotifier.Error("Protobuf saves are no longer supported and cannot be imported. Please run the \"swapserializer json\" command on server of the previous Nitrox version you used to change it to JSON."); - } - else - { - LauncherNotifier.Error("Invalid save file selected."); - } - return; - } - - TBSelectedSaveImportDir.Text = selectedWorldImportDirectory; - - // Check if the selected save file has a server.cfg file already inside of it, and set that path in the server.cfg panel. If not, clear the server.cfg panel - if (File.Exists(Path.Combine(selectedWorldImportDirectory, Config.FileName))) - { - selectedServerCfgImportDirectory = Path.Combine(selectedWorldImportDirectory, Config.FileName); - TBSelectedServerCfgImportDir.Text = selectedServerCfgImportDirectory; - - LauncherNotifier.Info("A server.cfg file was detected inside the selected save file"); - } - else - { - selectedServerCfgImportDirectory = string.Empty; - TBSelectedServerCfgImportDir.Text = "Select the server.cfg file to import"; - } - - // Enable the "Import" button if user has set a save name and selected a server.cfg file - if (!string.IsNullOrEmpty(importedWorldName) && !string.IsNullOrEmpty(selectedServerCfgImportDirectory)) - { - ImportWorldBtn.IsEnabled = true; - ImportWorldBtn.Opacity = 1; - } - SelectImportedServerCfgBtn.IsEnabled = true; - SelectImportedServerCfgBtn.Opacity = 1; - - } - - private void SelectImportedServerCfgBtn_Click(object sender, RoutedEventArgs e) - { - using (CommonOpenFileDialog dialog = new() - { - Multiselect = false, - EnsurePathExists = true, - Title = "Select the server.cfg file to import", - }) - { - if (dialog.ShowDialog() != CommonFileDialogResult.Ok) - { - return; - } - selectedServerCfgImportDirectory = Path.GetFullPath(dialog.FileName); - } - if (Path.GetFileName(selectedServerCfgImportDirectory) != "server.cfg") - { - LauncherNotifier.Error("Invalid file selected. Please select a valid server.cfg file"); - return; - } - - TBSelectedServerCfgImportDir.Text = selectedServerCfgImportDirectory; - - // Enable the "Import" button if user has set a save name and selected a save file - if (!string.IsNullOrEmpty(importedWorldName) && !string.IsNullOrEmpty(selectedWorldImportDirectory)) - { - ImportWorldBtn.IsEnabled = true; - ImportWorldBtn.Opacity = 1; - } - } - - private void ImportWorldBtn_Click(object sender, RoutedEventArgs e) + private void StartServer_Click(object sender, RoutedEventArgs e) { - if (Directory.Exists(selectedWorldDirectory)) - { - try - { - FileSystem.DeleteDirectory(selectedWorldDirectory, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin); - } - catch (Exception ex) - { - LauncherNotifier.Info("Could not delete the originally created world. You can manually delete this world separately if desired."); - Log.Error($"Could not move save \"{Path.GetFileName(selectedWorldDirectory)}\" to the recycling bin : {ex.GetType()} {ex.Message}"); - } - } - selectedWorldDirectory = Path.Combine(WorldManager.SavesFolderDir, importedWorldName); - try { - // Create save folder - Directory.CreateDirectory(selectedWorldDirectory); - - // Copy over targeted server.cfg file and ensure its serializer is set to JSON to prevent future errors - FileSystem.CopyFile(selectedServerCfgImportDirectory, Path.Combine(selectedWorldDirectory, "server.cfg")); - ServerConfig importedServerConfig = ServerConfig.Load(Path.Combine(selectedWorldDirectory)); - if (importedServerConfig.SerializerMode != ServerSerializerMode.JSON) - { - importedServerConfig.Update(selectedWorldDirectory, c => - { - c.SerializerMode = ServerSerializerMode.JSON; - }); - } - - // Copy over specific save files from within the targeted folder - foreach (string file in Directory.EnumerateFiles(selectedWorldImportDirectory)) - { - string targetFileDir = Path.Combine(selectedWorldImportDirectory, file); - string destFileDir = Path.Combine(selectedWorldDirectory, Path.GetFileName(file)); - - if (Path.GetExtension(targetFileDir) != ".json") - { - continue; - } - - FileSystem.CopyFile(targetFileDir, destFileDir); - File.SetLastWriteTime(destFileDir, DateTime.Now); - } - - UpdateVisualWorldSettings(); - - ImportSaveBtnBorder.Opacity = 0; - ImportSaveBtn.IsEnabled = false; - ImportWorldBox.Opacity = 0; - ImportWorldBox.IsHitTestVisible = false; - TBWorldSeed.IsReadOnly = true; - - LauncherNotifier.Success("Successfully imported the selected save file"); + LauncherLogic.Server.StartServer(RBIsExternal.IsChecked == true); } catch (Exception ex) { - LauncherNotifier.Error("Failed to import the selected save file. Please check your log for details."); - Log.Error($"Could not import save \"{Path.GetFileName(selectedWorldDirectory)}\" : {ex.GetType()} {ex.Message}"); + MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } - private void ImportWorldCancelBtn_Click(object sender, RoutedEventArgs e) - { - ImportWorldBox.Opacity = 0; - ImportWorldBox.IsHitTestVisible = false; - } - - // Start Server button - private void StartServer_Click(object sender, RoutedEventArgs e) + private void RBServer_Clicked(object sender, RoutedEventArgs e) { - try - { - selectedWorldDirectory = WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir ?? ""; - - if (!WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex).IsValidSave) // UX TODO: Handle world selection before starting the server for better UX - { - LauncherNotifier.Error($"This save is of an unsupported version of Nitrox."); - return; - } - else if (!Directory.Exists(WorldManager.GetSaves().ElementAtOrDefault(WorldListingContainer.SelectedIndex)?.WorldSaveDir)) - { - LauncherNotifier.Error($"This save does not exist or is not valid."); - InitializeWorldListing(); - return; - } - - try - { - LauncherLogic.Server.StartServer(RBIsExternal.IsChecked == true, selectedWorldDirectory); - } - catch (Exception ex) - { - if (ex.ToString().Contains("An instance of Nitrox Server is already running")) - { - LauncherNotifier.Error("An instance of the Nitrox server is already running, please close it to start another server."); - } - else - { - MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error); - } - return; - } - - if (File.Exists(Path.Combine(selectedWorldDirectory, "WorldData.json"))) - { - File.SetLastWriteTime(Path.Combine(selectedWorldDirectory, "WorldData.json"), DateTime.Now); - } - } - catch (Exception ex) - { - MessageBox.Show(ex.ToString(), "Error while starting server", MessageBoxButton.OK, MessageBoxImage.Error); - return; - } - - worldDirCurrentlyUsed = selectedWorldDirectory; - InitializeWorldListing(); + LauncherLogic.Config.IsExternalServer = RBIsExternal.IsChecked ?? true; } - - } - - // OPTIONAL - Only used to view world listings in intellisense, in addition to the lines that are in the ListView definition in ServerPage.xaml - public class WorldListing - { - public string WorldName { get; set; } - public string WorldGamemode { get; set; } - public string WorldVersion { get; set; } - public bool IsValidSave { get; set; } } } diff --git a/NitroxLauncher/ServerLogic.cs b/NitroxLauncher/ServerLogic.cs index a7b28c3599..c885b68ac6 100644 --- a/NitroxLauncher/ServerLogic.cs +++ b/NitroxLauncher/ServerLogic.cs @@ -31,7 +31,7 @@ public void Dispose() serverProcess = null; } - internal Process StartServer(bool standalone, string saveDir) + internal Process StartServer(bool standalone) { if (IsServerRunning) { @@ -51,8 +51,6 @@ internal Process StartServer(bool standalone, string saveDir) startInfo.CreateNoWindow = true; } - startInfo.Arguments = $@"""{saveDir}"""; - serverProcess = Process.Start(startInfo); if (serverProcess != null) { diff --git a/NitroxModel/Serialization/NitroxConfig.cs b/NitroxModel/Serialization/NitroxConfig.cs index b9baa4502b..ab0f5d14df 100644 --- a/NitroxModel/Serialization/NitroxConfig.cs +++ b/NitroxModel/Serialization/NitroxConfig.cs @@ -17,9 +17,11 @@ public abstract class NitroxConfig where T : NitroxConfig public abstract string FileName { get; } - public void Deserialize(string saveDir) + public bool ConfigFileExists => File.Exists(FileName); + + public void Deserialize() { - if (!File.Exists(Path.Combine(saveDir, FileName))) + if (!ConfigFileExists) { return; } @@ -28,7 +30,7 @@ public void Deserialize(string saveDir) { Type type = GetType(); Dictionary typeCachedDict = GetTypeCacheDictionary(); - using StreamReader reader = new(new FileStream(Path.Combine(saveDir, FileName), FileMode.Open, FileAccess.Read, FileShare.Read), Encoding.UTF8); + using StreamReader reader = new(new FileStream(FileName, FileMode.Open), Encoding.UTF8); HashSet unserializedMembers = new(typeCachedDict.Values); char[] lineSeparator = { '=' }; @@ -68,7 +70,7 @@ public void Deserialize(string saveDir) } else { - Log.Error($"Incorrect format detected on line {lineNum} in {Path.GetFullPath(Path.Combine(saveDir, FileName))}:{Environment.NewLine}{readLine}"); + Log.Error($"Incorrect format detected on line {lineNum} in {Path.GetFullPath(FileName)}:{Environment.NewLine}{readLine}"); } } @@ -94,7 +96,7 @@ public void Deserialize(string saveDir) } } - public void Serialize(string saveDir) + public void Serialize() { lock (locker) { @@ -102,7 +104,7 @@ public void Serialize(string saveDir) Dictionary typeCachedDict = GetTypeCacheDictionary(); try { - using StreamWriter stream = new(new FileStream(Path.Combine(saveDir, FileName), FileMode.Create, FileAccess.Write), Encoding.UTF8); + using StreamWriter stream = new(new FileStream(FileName, FileMode.Create), Encoding.UTF8); WritePropertyDescription(type, stream); foreach (string name in typeCachedDict.Keys) @@ -135,16 +137,16 @@ public void Serialize(string saveDir) /// Ensures updates are properly persisted to the backing config file without overwriting user edits. /// /// - public void Update(string saveDir, Action config = null) + public void Update(Action config = null) { try { - Deserialize(saveDir); + Deserialize(); config?.Invoke(this as T); } finally { - Serialize(saveDir); + Serialize(); } } diff --git a/NitroxModel/Serialization/ServerList.cs b/NitroxModel/Serialization/ServerList.cs index 7192f5c069..559ef92047 100644 --- a/NitroxModel/Serialization/ServerList.cs +++ b/NitroxModel/Serialization/ServerList.cs @@ -26,7 +26,7 @@ private static ServerList Default } } - public static string DefaultFile => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Nitrox", SERVERS_FILE_NAME); + public static string DefaultFile => Path.Combine(NitroxUser.LauncherPath, SERVERS_FILE_NAME); public IEnumerable Entries => entries; diff --git a/NitroxServer-Subnautica/Program.cs b/NitroxServer-Subnautica/Program.cs index f61fed6903..42f2034b7d 100644 --- a/NitroxServer-Subnautica/Program.cs +++ b/NitroxServer-Subnautica/Program.cs @@ -15,6 +15,7 @@ using NitroxModel.Core; using NitroxModel.DataStructures.GameLogic; using NitroxModel.DataStructures.Util; +using NitroxModel.Discovery; using NitroxModel.Helper; using NitroxModel.Platforms.OS.Shared; using NitroxModel_Subnautica.DataStructures.GameLogic; diff --git a/NitroxServer/ConsoleCommands/AutosaveCommand.cs b/NitroxServer/ConsoleCommands/AutosaveCommand.cs index 1c6f15a755..9dfe5228a1 100644 --- a/NitroxServer/ConsoleCommands/AutosaveCommand.cs +++ b/NitroxServer/ConsoleCommands/AutosaveCommand.cs @@ -1,10 +1,7 @@ -using System; -using System.IO; -using NitroxModel.DataStructures.GameLogic; +using NitroxModel.DataStructures.GameLogic; using NitroxServer.ConsoleCommands.Abstract; using NitroxServer.ConsoleCommands.Abstract.Type; using NitroxServer.Serialization; -using NitroxServer.Serialization.World; namespace NitroxServer.ConsoleCommands { @@ -23,7 +20,7 @@ protected override void Execute(CallArgs args) { bool toggle = args.Get(0); - serverConfig.Update(Path.Combine(WorldManager.SavesFolderDir, serverConfig.SaveName), c => + serverConfig.Update(c => { if (toggle) { diff --git a/NitroxServer/ConsoleCommands/ChangeAdminPasswordCommand.cs b/NitroxServer/ConsoleCommands/ChangeAdminPasswordCommand.cs index 3c1d37e7a1..53881ba274 100644 --- a/NitroxServer/ConsoleCommands/ChangeAdminPasswordCommand.cs +++ b/NitroxServer/ConsoleCommands/ChangeAdminPasswordCommand.cs @@ -1,10 +1,7 @@ -using System; -using System.IO; -using NitroxModel.DataStructures.GameLogic; +using NitroxModel.DataStructures.GameLogic; using NitroxServer.ConsoleCommands.Abstract; using NitroxServer.ConsoleCommands.Abstract.Type; using NitroxServer.Serialization; -using NitroxServer.Serialization.World; namespace NitroxServer.ConsoleCommands { @@ -21,7 +18,7 @@ public ChangeAdminPasswordCommand(ServerConfig serverConfig) : base("changeadmin protected override void Execute(CallArgs args) { - serverConfig.Update(Path.Combine(WorldManager.SavesFolderDir, serverConfig.SaveName), c => + serverConfig.Update(c => { string newPassword = args.Get(0); c.AdminPassword = newPassword; diff --git a/NitroxServer/ConsoleCommands/ChangeServerGamemodeCommand.cs b/NitroxServer/ConsoleCommands/ChangeServerGamemodeCommand.cs index c7d0bea36a..96c3106611 100644 --- a/NitroxServer/ConsoleCommands/ChangeServerGamemodeCommand.cs +++ b/NitroxServer/ConsoleCommands/ChangeServerGamemodeCommand.cs @@ -1,13 +1,10 @@ -using System; -using System.IO; -using NitroxModel.DataStructures.GameLogic; +using NitroxModel.DataStructures.GameLogic; using NitroxModel.Packets; using NitroxModel.Server; using NitroxServer.ConsoleCommands.Abstract; using NitroxServer.ConsoleCommands.Abstract.Type; using NitroxServer.GameLogic; using NitroxServer.Serialization; -using NitroxServer.Serialization.World; namespace NitroxServer.ConsoleCommands { @@ -28,7 +25,7 @@ protected override void Execute(CallArgs args) { ServerGameMode sgm = args.Get(0); - serverConfig.Update(Path.Combine(WorldManager.SavesFolderDir, serverConfig.SaveName), c => + serverConfig.Update(c => { if (c.GameMode != sgm) { diff --git a/NitroxServer/ConsoleCommands/ChangeServerPasswordCommand.cs b/NitroxServer/ConsoleCommands/ChangeServerPasswordCommand.cs index 22d9945878..3ee8b11da5 100644 --- a/NitroxServer/ConsoleCommands/ChangeServerPasswordCommand.cs +++ b/NitroxServer/ConsoleCommands/ChangeServerPasswordCommand.cs @@ -1,10 +1,7 @@ -using System; -using System.IO; -using NitroxModel.DataStructures.GameLogic; +using NitroxModel.DataStructures.GameLogic; using NitroxServer.ConsoleCommands.Abstract; using NitroxServer.ConsoleCommands.Abstract.Type; using NitroxServer.Serialization; -using NitroxServer.Serialization.World; namespace NitroxServer.ConsoleCommands { @@ -23,7 +20,7 @@ protected override void Execute(CallArgs args) { string password = args.Get(0) ?? string.Empty; - serverConfig.Update(Path.Combine(WorldManager.SavesFolderDir, serverConfig.SaveName), c => c.ServerPassword = password); + serverConfig.Update(c => c.ServerPassword = password); Log.InfoSensitive("Server password changed to \"{password}\" by {playername}", password, args.SenderName); SendMessageToPlayer(args.Sender, "Server password has been updated"); diff --git a/NitroxServer/ConsoleCommands/ConfigCommand.cs b/NitroxServer/ConsoleCommands/ConfigCommand.cs index 622aeb820e..7208cda6cf 100644 --- a/NitroxServer/ConsoleCommands/ConfigCommand.cs +++ b/NitroxServer/ConsoleCommands/ConfigCommand.cs @@ -1,13 +1,13 @@ using System; using System.Diagnostics; using System.IO; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using NitroxModel.DataStructures.GameLogic; using NitroxModel.Platforms.OS.Shared; using NitroxServer.ConsoleCommands.Abstract; using NitroxServer.Serialization; -using NitroxServer.Serialization.World; namespace NitroxServer.ConsoleCommands { @@ -30,11 +30,10 @@ protected override void Execute(CallArgs args) } // Save config file if it doesn't exist yet. - string saveDir = Path.Combine(WorldManager.SavesFolderDir, serverConfig.SaveName); - string configFile = Path.Combine(saveDir, serverConfig.FileName); + string configFile = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location) ?? "", serverConfig.FileName); if (!File.Exists(configFile)) { - serverConfig.Serialize(configFile); + serverConfig.Serialize(); } Task.Run(async () => @@ -47,7 +46,7 @@ protected override void Execute(CallArgs args) { configOpenLock.Release(); } - serverConfig.Deserialize(saveDir); // Notifies user if deserialization failed. + serverConfig.Deserialize(); // Notifies user if deserialization failed. Log.Info("If you made changes, restart the server for them to take effect."); }) .ContinueWith(t => diff --git a/NitroxServer/ConsoleCommands/StopCommand.cs b/NitroxServer/ConsoleCommands/StopCommand.cs index fc29a0294c..d3ab15e842 100644 --- a/NitroxServer/ConsoleCommands/StopCommand.cs +++ b/NitroxServer/ConsoleCommands/StopCommand.cs @@ -6,7 +6,7 @@ namespace NitroxServer.ConsoleCommands { internal class StopCommand : Command { - public override IEnumerable Aliases { get; } = new[] { "exit", "halt", "quit", "close" }; + public override IEnumerable Aliases { get; } = new[] { "exit", "halt", "quit" }; public StopCommand() : base("stop", Perms.ADMIN, "Stops the server") { diff --git a/NitroxServer/ConsoleCommands/SwapSerializerCommand.cs b/NitroxServer/ConsoleCommands/SwapSerializerCommand.cs index 3b2b4cd984..dca97186f3 100644 --- a/NitroxServer/ConsoleCommands/SwapSerializerCommand.cs +++ b/NitroxServer/ConsoleCommands/SwapSerializerCommand.cs @@ -1,5 +1,4 @@ -using System.IO; -using NitroxModel.DataStructures.GameLogic; +using NitroxModel.DataStructures.GameLogic; using NitroxModel.Server; using NitroxServer.ConsoleCommands.Abstract; using NitroxServer.ConsoleCommands.Abstract.Type; @@ -25,7 +24,7 @@ protected override void Execute(CallArgs args) { ServerSerializerMode serializerMode = args.Get(0); - serverConfig.Update(Path.Combine(WorldManager.SavesFolderDir, serverConfig.SaveName), c => + serverConfig.Update(c => { if (serializerMode != c.SerializerMode) { diff --git a/NitroxServer/Serialization/ServerConfig.cs b/NitroxServer/Serialization/ServerConfig.cs index 138e814f66..27af95cfad 100644 --- a/NitroxServer/Serialization/ServerConfig.cs +++ b/NitroxServer/Serialization/ServerConfig.cs @@ -21,7 +21,7 @@ public class ServerConfig : NitroxConfig private string postSaveCommandPath = string.Empty; - private string saveNameSetting = "My World"; + private string saveNameSetting = "world"; public override string FileName => "server.cfg"; [PropertyDescription("Leave blank for a random spawn position")] @@ -40,7 +40,7 @@ public int SaveInterval set { - Validate.IsTrue(value >= 1000, "SaveInterval must be greater than 1000"); + Validate.IsTrue(value > 1000, "SaveInterval must be greater than 1000"); saveIntervalSetting = value; } } @@ -121,10 +121,10 @@ public string SaveName [PropertyDescription("Determines whether the server will listen for and reply to LAN discovery requests.")] public bool LANDiscoveryEnabled { get; set; } = true; - public static ServerConfig Load(string saveDir) + public static ServerConfig Load() { ServerConfig config = new(); - config.Update(saveDir); + config.Update(); return config; } } diff --git a/NitroxServer/Serialization/World/SaveFileVersion.cs b/NitroxServer/Serialization/World/SaveFileVersion.cs index 0a9abb4e89..e577938c26 100644 --- a/NitroxServer/Serialization/World/SaveFileVersion.cs +++ b/NitroxServer/Serialization/World/SaveFileVersion.cs @@ -37,10 +37,5 @@ public SaveFileVersion(Version version) Build = version.Build; Revision = version.Revision; } - - public override string ToString() - { - return $"{Major}.{Minor}.{Build}.{Revision}"; - } } } diff --git a/NitroxServer/Serialization/World/WorldManager.cs b/NitroxServer/Serialization/World/WorldManager.cs deleted file mode 100644 index 4bb3a7aa6a..0000000000 --- a/NitroxServer/Serialization/World/WorldManager.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Windows; -using NitroxModel.Helper; -using NitroxModel.Server; - -namespace NitroxServer.Serialization.World; - -public static class WorldManager -{ - public static readonly string SavesFolderDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Nitrox", "saves"); - - private static readonly List savesCache = new(); - - static WorldManager() - { - try - { - Directory.CreateDirectory(SavesFolderDir); - } - catch (Exception ex) - { - Log.Error(ex, "Couldn't create \"saves\" folder"); - throw new Exception(ex.ToString()); - } - } - - public static IEnumerable GetSaves() - { - if (savesCache.Count != 0) - { - return savesCache; - } - - foreach (string folder in Directory.EnumerateDirectories(SavesFolderDir)) - { - try - { - // Don't add the file to the list if it doesn't validate - if (!ValidateSave(folder)) - { - continue; - } - - Version version; - ServerConfig serverConfig = ServerConfig.Load(folder); - - string fileEnding = "json"; - if (serverConfig.SerializerMode == ServerSerializerMode.PROTOBUF) - { - fileEnding = "nitrox"; - } - - using (FileStream stream = new(Path.Combine(folder, $"Version.{fileEnding}"), FileMode.Open, FileAccess.Read, FileShare.Read)) - { - version = new ServerJsonSerializer().Deserialize(stream)?.Version ?? NitroxEnvironment.Version; - } - - DateTime fileLastAccessedTime; - if (File.Exists(Path.Combine(folder, $"WorldData.{fileEnding}"))) - { - fileLastAccessedTime = File.GetLastWriteTime(Path.Combine(folder, $"WorldData.{fileEnding}")); - } - else - { - fileLastAccessedTime = File.GetLastWriteTime(Path.Combine(folder, $"Version.{fileEnding}")); // This file was created when the save was created, so it can be used as the backup to get this write time if this is a new save (the WorldData file wouldn't exist) - } - - // Change the paramaters here to define what save file versions are eligible for use/upgrade - bool isValidVersion = true; - if (version < new Version(1, 6, 0, 1) || version > NitroxEnvironment.Version) - { - isValidVersion = false; - } - - savesCache.Add(new Listing - { - WorldName = Path.GetFileName(folder), - WorldGamemode = Convert.ToString(serverConfig.GameMode), - WorldVersion = $"v{version}", - WorldSaveDir = folder, - IsValidSave = isValidVersion, - FileLastAccessed = fileLastAccessedTime - }); - - // Set the server.cfg name value to the folder name - if (Path.GetFileName(folder) != serverConfig.SaveName) - { - serverConfig.Update(folder, c => { c.SaveName = Path.GetFileName(folder); }); - } - - } - catch - { - Log.Error($"World \"{folder}\" could not be processed"); - } - } - // Order listing based on FileLastAccessed time - savesCache.Sort((x, y) => y.FileLastAccessed.CompareTo(x.FileLastAccessed)); - - return savesCache; - } - - public static void Refresh() - { - savesCache.Clear(); - GetSaves(); - } - - public static string CreateEmptySave(string name) - { - string saveDir = Path.Combine(SavesFolderDir, name); - - // Check save path for other "My World" files and increment the end value if there is, so as to prevent duplication - if (Directory.Exists(saveDir)) - { - int i = 1; - string newSelectedWorldName = name; - while (Directory.Exists(saveDir)) - { - // Add a number to the end of the name - newSelectedWorldName = name + $" ({i})"; - saveDir = Path.Combine(SavesFolderDir, newSelectedWorldName); - i++; - } - name = newSelectedWorldName; - } - - Directory.CreateDirectory(saveDir); - - ServerConfig serverConfig = ServerConfig.Load(saveDir); - - string fileEnding = "json"; - if (serverConfig.SerializerMode == ServerSerializerMode.PROTOBUF) - { - fileEnding = "nitrox"; - } - File.Create(Path.Combine(saveDir, $"Version.{fileEnding}")).Close(); - - serverConfig.SaveName = name; - - return saveDir; - } - - public static bool ValidateSave(string saveFileDirectory, bool isImporting = false) - { - if (!Directory.Exists(saveFileDirectory)) - { - return false; - } - - // A save file is valid when it has a server.cfg file in it (if not importing a file) and if it has at least a Version.(ext) save file in it - if (isImporting && !File.Exists(Path.Combine(saveFileDirectory, "server.cfg"))) - { - return false; - } - - if (!File.Exists(Path.Combine(saveFileDirectory, $"Version.json"))) - { - return false; - } - - return true; - } - - public class Listing - { - public string WorldName { get; set; } - public string WorldGamemode { get; set; } - public string WorldVersion { get; set; } - public string WorldSaveDir { get; set; } - public bool IsValidSave { get; set; } - public DateTime FileLastAccessed { get; set; } - } -} diff --git a/NitroxServer/Serialization/World/WorldPersistence.cs b/NitroxServer/Serialization/World/WorldPersistence.cs index 740af47369..f39435fe87 100644 --- a/NitroxServer/Serialization/World/WorldPersistence.cs +++ b/NitroxServer/Serialization/World/WorldPersistence.cs @@ -72,8 +72,6 @@ public bool Save(World world, string saveDir) Serializer.Serialize(Path.Combine(saveDir, $"WorldData{FileEnding}"), persistedData.WorldData); Serializer.Serialize(Path.Combine(saveDir, $"EntityData{FileEnding}"), persistedData.EntityData); - config.Update(saveDir, c => c.Seed = persistedData.WorldData.Seed); - Log.Info("World state saved"); return true; } @@ -115,24 +113,20 @@ internal Optional LoadFromFile(string saveDir) } catch (Exception ex) { - // Check if the world was newly created using the world manager - if (new FileInfo(Path.Combine(saveDir, $"Version{FileEnding}")).Length > 0) - { - Log.Error($"Could not load world, creating a new one : {ex.GetType()} {ex.Message}"); + Log.Error($"Could not load world, creating a new one : {ex.GetType()} {ex.Message}"); - // Backup world if loading fails - string outZip = Path.Combine(saveDir, "worldBackup.zip"); - Log.WarnSensitive("Creating a backup at {path}", Path.GetFullPath(outZip)); - FileSystem.Instance.ZipFilesInDirectory(saveDir, outZip, $"*{FileEnding}", true); - } + //Backup world if loading fails + string outZip = Path.Combine(saveDir, "worldBackup.zip"); + Log.WarnSensitive("Creating a backup at {path}", Path.GetFullPath(outZip)); + FileSystem.Instance.ZipFilesInDirectory(saveDir, outZip, $"*{FileEnding}", true); } return Optional.Empty; } - + public World Load() { - Optional fileLoadedWorld = LoadFromFile(Path.Combine(WorldManager.SavesFolderDir, config.SaveName)); + Optional fileLoadedWorld = LoadFromFile(config.SaveName); if (fileLoadedWorld.HasValue) { return fileLoadedWorld.Value; @@ -160,7 +154,11 @@ private World CreateFreshWorld() InventoryData = InventoryData.From(new List(), new List(), new List()), VehicleData = VehicleData.From(new List()), ParsedBatchCells = new List(), +#if DEBUG + Seed = "TCCBIBZXAB" +#else Seed = config.Seed +#endif } }; @@ -172,11 +170,7 @@ public World CreateWorld(PersistedWorldData pWorldData, ServerGameMode gameMode) string seed = pWorldData.WorldData.Seed; if (string.IsNullOrWhiteSpace(seed)) { -#if DEBUG - seed = "TCCBIBZXAB"; -#else seed = StringHelper.GenerateRandomString(10); -#endif } Log.Info($"Loading world with seed {seed}"); diff --git a/NitroxServer/Server.cs b/NitroxServer/Server.cs index cf8f2aa181..b9eb99c2ce 100644 --- a/NitroxServer/Server.cs +++ b/NitroxServer/Server.cs @@ -59,7 +59,7 @@ public string GetSaveSummary(Perms viewerPerms = Perms.CONSOLE) StringBuilder builder = new("\n"); if (viewerPerms is Perms.CONSOLE) { - builder.AppendLine($" - Save location: {Path.Combine(WorldManager.SavesFolderDir, serverConfig.SaveName)}"); + builder.AppendLine($" - Save location: {Path.GetFullPath(serverConfig.SaveName)}"); } builder.AppendLine($" - Aurora's state: {world.EventTriggerer.GetAuroraStateSummary()}"); builder.AppendLine($" - Current time: day {world.EventTriggerer.Day} ({Math.Floor(world.EventTriggerer.ElapsedSeconds)}s)"); @@ -78,51 +78,6 @@ public string GetSaveSummary(Perms viewerPerms = Perms.CONSOLE) return builder.ToString(); } - public static ServerConfig ServerStartHandler() - { - string saveDir = null; - foreach (string arg in Environment.GetCommandLineArgs()) - { - if (arg.StartsWith(WorldManager.SavesFolderDir, StringComparison.OrdinalIgnoreCase) && Directory.Exists(arg)) - { - saveDir = arg; - break; - } - } - if (saveDir == null) - { - // Check if there are any save files - IEnumerable WorldList = WorldManager.GetSaves(); - if (WorldList.Any()) - { - // Get last save file used - string lastSaveAccessed = WorldList.ElementAtOrDefault(0).WorldSaveDir; - if (WorldList.Count() > 1) - { - for (int i = 1; i < WorldList.Count(); i++) - { - if (File.GetLastWriteTime(Path.Combine(WorldList.ElementAtOrDefault(i).WorldSaveDir, "WorldData.json")) > File.GetLastWriteTime(lastSaveAccessed)) - { - lastSaveAccessed = WorldList.ElementAtOrDefault(i).WorldSaveDir; - } - } - } - saveDir = lastSaveAccessed; - } - else - { - // Create new save file - saveDir = Path.Combine(WorldManager.SavesFolderDir, "My World"); - Directory.CreateDirectory(saveDir); - ServerConfig serverConfig = ServerConfig.Load(saveDir); - Log.Debug($"No save file was found, creating a new one..."); - } - - } - - return ServerConfig.Load(saveDir); - } - public void Save() { if (IsSaving) @@ -132,7 +87,7 @@ public void Save() IsSaving = true; - bool savedSuccessfully = worldPersistence.Save(world, Path.Combine(WorldManager.SavesFolderDir, serverConfig.SaveName)); + bool savedSuccessfully = worldPersistence.Save(world, serverConfig.SaveName); if (savedSuccessfully && !string.IsNullOrWhiteSpace(serverConfig.PostSaveCommandPath)) { try diff --git a/NitroxServer/ServerAutoFacRegistrar.cs b/NitroxServer/ServerAutoFacRegistrar.cs index 16846015bb..d586fdf7cf 100644 --- a/NitroxServer/ServerAutoFacRegistrar.cs +++ b/NitroxServer/ServerAutoFacRegistrar.cs @@ -10,6 +10,7 @@ using NitroxServer.ConsoleCommands.Processor; using NitroxServer.GameLogic; using NitroxServer.GameLogic.Entities; +using NitroxServer.Serialization; using NitroxServer.Serialization.Upgrade; using NitroxServer.Serialization.World; @@ -28,7 +29,7 @@ public virtual void RegisterDependencies(ContainerBuilder containerBuilder) private static void RegisterCoreDependencies(ContainerBuilder containerBuilder) { - containerBuilder.Register(c => Server.ServerStartHandler()).SingleInstance(); + containerBuilder.Register(c => ServerConfig.Load()).SingleInstance(); containerBuilder.RegisterType().SingleInstance(); containerBuilder.RegisterType().SingleInstance(); containerBuilder.RegisterType().InstancePerLifetimeScope(); From 5346d0ef6f9cc2ff03a10522838359961b8bc27d Mon Sep 17 00:00:00 2001 From: tornac1234 Date: Sun, 4 Dec 2022 00:11:20 +0100 Subject: [PATCH 7/9] Fix a PositionInitialSync regression where chunks not loading would block the process --- NitroxClient/GameLogic/Terrain.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/NitroxClient/GameLogic/Terrain.cs b/NitroxClient/GameLogic/Terrain.cs index 62248d669c..145e9bbe57 100644 --- a/NitroxClient/GameLogic/Terrain.cs +++ b/NitroxClient/GameLogic/Terrain.cs @@ -1,4 +1,5 @@ -using System.Collections; +using System; +using System.Collections; using System.Collections.Generic; using NitroxClient.Communication.Abstract; using NitroxClient.Map; @@ -103,10 +104,14 @@ public static IEnumerator WaitForWorldLoad() // In WorldStreamer.CreateStreamers() three coroutines are created to constantly call UpdateCenter() on the streamers // We force these updates so that the world streamer gets busy instantly WorldStreamer streamerV2 = LargeWorldStreamer.main.streamerV2; - streamerV2.UpdateStreamingCenter(MainCamera.camera.transform.position); - streamerV2.octreesStreamer.UpdateCenter(streamerV2.streamingCenter); - streamerV2.lowDetailOctreesStreamer.UpdateCenter(streamerV2.streamingCenter); - streamerV2.clipmapStreamer.UpdateCenter(streamerV2.streamingCenter); + // Sometimes, the world streamers can't find any cells to load and will throw an error, in which case we just skip the cell loading + try + { + streamerV2.UpdateStreamingCenter(MainCamera.camera.transform.position); + streamerV2.octreesStreamer.UpdateCenter(streamerV2.streamingCenter); + streamerV2.lowDetailOctreesStreamer.UpdateCenter(streamerV2.streamingCenter); + streamerV2.clipmapStreamer.UpdateCenter(streamerV2.streamingCenter); + } catch (Exception) { } yield return new WaitUntil(() => LargeWorldStreamer.main.IsWorldSettled()); Player.main.cinematicModeActive = false; From eb9a722361b67bcf1027cc71700423bed7544af7 Mon Sep 17 00:00:00 2001 From: tornac1234 Date: Wed, 7 Dec 2022 21:17:47 +0100 Subject: [PATCH 8/9] Reset remote player animation on death --- NitroxClient/GameLogic/RemotePlayer.cs | 2 +- .../MonoBehaviours/AnimationController.cs | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/NitroxClient/GameLogic/RemotePlayer.cs b/NitroxClient/GameLogic/RemotePlayer.cs index c4cbca25e1..6bc68dd6da 100644 --- a/NitroxClient/GameLogic/RemotePlayer.cs +++ b/NitroxClient/GameLogic/RemotePlayer.cs @@ -6,7 +6,6 @@ using NitroxClient.GameLogic.PlayerLogic.PlayerModel.Abstract; using NitroxClient.MonoBehaviours; using NitroxClient.Unity.Helper; -using NitroxModel.Helper; using NitroxModel.MultiplayerSession; using UnityEngine; using UWE; @@ -69,6 +68,7 @@ public RemotePlayer(GameObject playerBody, PlayerContext playerContext, List().enabled = false; AnimationController = PlayerModel.AddComponent(); + AnimationController.Initialize(this); Transform inventoryTransform = new GameObject("Inventory").transform; inventoryTransform.SetParent(Body.transform); diff --git a/NitroxClient/MonoBehaviours/AnimationController.cs b/NitroxClient/MonoBehaviours/AnimationController.cs index 09fde7a211..405077b91c 100644 --- a/NitroxClient/MonoBehaviours/AnimationController.cs +++ b/NitroxClient/MonoBehaviours/AnimationController.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using NitroxClient.GameLogic; +using UnityEngine; namespace NitroxClient.MonoBehaviours { @@ -7,6 +8,7 @@ public class AnimationController : MonoBehaviour { private const float SMOOTHING_SPEED = 4f; private Animator animator; + private RemotePlayer remotePlayer; public bool UpdatePlayerAnimations { get; set; } = true; public Quaternion AimingRotation { get; set; } @@ -23,6 +25,23 @@ public void Awake() this["is_underwater"] = true; } + public void Initialize(RemotePlayer remotePlayer) + { + this.remotePlayer = remotePlayer; + remotePlayer.PlayerDeathEvent.AddHandler(this, Reset); + } + + public void OnDestroy() + { + remotePlayer?.PlayerDeathEvent.RemoveHandler(this, Reset); + } + + private void Reset(RemotePlayer remotePlayer) + { + animator.Rebind(); + animator.Update(0); + } + public void FixedUpdate() { if (UpdatePlayerAnimations) From 104c1d133c0421fa11467df75ab57316e9d07734 Mon Sep 17 00:00:00 2001 From: NinjaPedroX <32976499+NinjaPedroX@users.noreply.github.com> Date: Thu, 8 Dec 2022 18:45:52 +0100 Subject: [PATCH 9/9] Bump assembly version to v1.7.0.0 (#1892) * Bump Assembly Version to v1.7.0.0 * Update the minimum world requirement to reflect the save versions supported --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 6d586b0ba6..86cfd39584 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.6.0.1 + 1.7.0.0 10 false false