diff --git a/Fika.Core/AkiSupport/Airdrops/Utils/FikaItemFactoryUtil.cs b/Fika.Core/AkiSupport/Airdrops/Utils/FikaItemFactoryUtil.cs index 38ebd293..3257c561 100644 --- a/Fika.Core/AkiSupport/Airdrops/Utils/FikaItemFactoryUtil.cs +++ b/Fika.Core/AkiSupport/Airdrops/Utils/FikaItemFactoryUtil.cs @@ -19,7 +19,7 @@ public class FikaItemFactoryUtil public FikaItemFactoryUtil() { itemFactory = Singleton.Instance; - logSource = new("ItemFactoryUtil"); + logSource = Logger.CreateLogSource("ItemFactoryUtil"); } public void BuildContainer(LootableContainer container, FikaAirdropConfigModel config, string dropType) diff --git a/Fika.Core/Coop/BTR/FikaBTRManager_Client.cs b/Fika.Core/Coop/BTR/FikaBTRManager_Client.cs index c3276968..1f06af9d 100644 --- a/Fika.Core/Coop/BTR/FikaBTRManager_Client.cs +++ b/Fika.Core/Coop/BTR/FikaBTRManager_Client.cs @@ -61,7 +61,7 @@ internal class FikaBTRManager_Client : MonoBehaviour Type btrControllerType = typeof(BTRControllerClass); _updateTaxiPriceMethod = AccessTools.GetDeclaredMethods(btrControllerType).Single(IsUpdateTaxiPriceMethod); client = Singleton.Instance; - btrLogger = new("BTR Client"); + btrLogger = BepInEx.Logging.Logger.CreateLogSource("BTR Client"); } private void Awake() diff --git a/Fika.Core/Coop/BTR/FikaBTRManager_Host.cs b/Fika.Core/Coop/BTR/FikaBTRManager_Host.cs index a96ac738..e0ef2313 100644 --- a/Fika.Core/Coop/BTR/FikaBTRManager_Host.cs +++ b/Fika.Core/Coop/BTR/FikaBTRManager_Host.cs @@ -71,7 +71,7 @@ internal class FikaBTRManager_Host : MonoBehaviour Type btrControllerType = typeof(BTRControllerClass); _updateTaxiPriceMethod = AccessTools.GetDeclaredMethods(btrControllerType).Single(IsUpdateTaxiPriceMethod); server = Singleton.Instance; - btrLogger = new("BTR Host"); + btrLogger = BepInEx.Logging.Logger.CreateLogSource("BTR Host"); } public bool CanPlayerEnter(IPlayer player) diff --git a/Fika.Core/Coop/Components/CoopHandler.cs b/Fika.Core/Coop/Components/CoopHandler.cs index cb8d9434..fd367537 100644 --- a/Fika.Core/Coop/Components/CoopHandler.cs +++ b/Fika.Core/Coop/Components/CoopHandler.cs @@ -183,7 +183,7 @@ protected void OnDestroy() StopCoroutine(ProcessSpawnQueue()); if (PingRoutine != null) { - StopCoroutine(PingRoutine); + StopCoroutine(PingRoutine); } } @@ -493,13 +493,20 @@ private LocalPlayer SpawnObservedPlayer(Profile profile, Vector3 position, int p return null; ((CoopPlayer)otherPlayer).NetId = netId; + Logger.LogInfo($"SpawnObservedPlayer: {profile.Nickname} spawning with NetId {netId}"); if (!isAI) + { HumanPlayers++; + } if (!Players.ContainsKey(netId)) { Players.Add(netId, (CoopPlayer)otherPlayer); } + else + { + Logger.LogError($"Trying to add {otherPlayer.Profile.Nickname} to list of players but it was already there!"); + } if (!Singleton.Instance.RegisteredPlayers.Any(x => x.Profile.ProfileId == profile.ProfileId)) Singleton.Instance.RegisteredPlayers.Add(otherPlayer); @@ -507,7 +514,9 @@ private LocalPlayer SpawnObservedPlayer(Profile profile, Vector3 position, int p foreach (CoopPlayer player in Players.Values) { if (player is not ObservedCoopPlayer) + { continue; + } Collider playerCollider = otherPlayer.GetCharacterControllerCommon().GetCollider(); Collider otherCollider = player.GetCharacterControllerCommon().GetCollider(); diff --git a/Fika.Core/Coop/Custom/FikaHealthBar.cs b/Fika.Core/Coop/Custom/FikaHealthBar.cs index 1b8cca51..48efef20 100644 --- a/Fika.Core/Coop/Custom/FikaHealthBar.cs +++ b/Fika.Core/Coop/Custom/FikaHealthBar.cs @@ -2,6 +2,7 @@ using Comfort.Common; using EFT; +using EFT.Animations; using EFT.UI; using Fika.Core.Bundles; using Fika.Core.Coop.Players; @@ -21,6 +22,8 @@ public class FikaHealthBar : MonoBehaviour private CoopPlayer mainPlayer; private PlayerPlateUI playerPlate; private float screenScale = 1f; + private int frameCounter = 0; + private readonly int throttleInterval = 60; // throttle to 1 update per 60 frames protected void Awake() { @@ -33,40 +36,25 @@ protected void Update() { if (currentPlayer != null) { - if (!FikaPlugin.UseNamePlates.Value) + bool throttleUpdate = IsThrottleUpdate(); + if (throttleUpdate) { - playerPlate.gameObject.SetActive(false); - return; - } - else if (playerPlate.gameObject.active == false) - { - playerPlate.gameObject.SetActive(true); - } - UpdateScreenSpacePosition(); - float currentHealth = currentPlayer.HealthController.GetBodyPartHealth(EBodyPart.Common, true).Current; - float maxHealth = currentPlayer.HealthController.GetBodyPartHealth(EBodyPart.Common, true).Maximum; - if (FikaPlugin.UseHealthNumber.Value) - { - if (!playerPlate.healthNumberBackgroundScreen.gameObject.activeSelf) + // Handling the visibility of elements + if (!FikaPlugin.UseNamePlates.Value) { - playerPlate.healthNumberBackgroundScreen.gameObject.SetActive(true); - playerPlate.healthBarBackgroundScreen.gameObject.SetActive(false); + playerPlate.gameObject.SetActive(false); + return; } - int healthNumberPercentage = (int)Math.Round((currentHealth / maxHealth) * 100); - playerPlate.SetHealthNumberText($"{healthNumberPercentage}%"); - } - else - { - if (!playerPlate.healthBarBackgroundScreen.gameObject.active) + else if (playerPlate.gameObject.active == false) { - playerPlate.healthNumberBackgroundScreen.gameObject.SetActive(false); - playerPlate.healthBarBackgroundScreen.gameObject.SetActive(true); + playerPlate.gameObject.SetActive(true); } - - float normalizedHealth = Mathf.Clamp01(currentHealth / maxHealth); - playerPlate.healthBarScreen.fillAmount = normalizedHealth; - UpdateHealthBarColor(normalizedHealth); + SetPlayerPlateFactionVisibility(FikaPlugin.UsePlateFactionSide.Value); + SetPlayerPlateHealthVisibility(FikaPlugin.HideHealthBar.Value); } + // Finally, update the screen space position + UpdateScreenSpacePosition(throttleUpdate); + // Destroy if this player is dead if (!currentPlayer.HealthController.IsAlive) { Destroy(this); @@ -78,79 +66,99 @@ protected void Update() } } - private void UpdateScreenSpacePosition() + private void UpdateScreenSpacePosition(bool throttleUpdate) { - if (mainPlayer.HealthController.IsAlive && mainPlayer.ProceduralWeaponAnimation.IsAiming) + // ADS opacity handling + float opacityMultiplier = 1f; + ProceduralWeaponAnimation proceduralWeaponAnimation = mainPlayer.ProceduralWeaponAnimation; + if (mainPlayer.HealthController.IsAlive && proceduralWeaponAnimation.IsAiming) { - if (mainPlayer.ProceduralWeaponAnimation.CurrentScope.IsOptic) + if (proceduralWeaponAnimation.CurrentScope.IsOptic && FikaPlugin.HideNamePlateInOptic.Value) { playerPlate.ScalarObjectScreen.active = false; return; } + opacityMultiplier = FikaPlugin.OpacityInADS.Value; } - else if (playerPlate.ScalarObjectScreen.active == false) + CameraClass cameraInstance = CameraClass.Instance; + Camera camera = cameraInstance.Camera; + + // Distance check + Vector3 direction = camera.transform.position - currentPlayer.Position; + float sqrDistance = direction.sqrMagnitude; + float maxDistanceToShow = FikaPlugin.MaxDistanceToShow.Value * FikaPlugin.MaxDistanceToShow.Value; + if (sqrDistance > maxDistanceToShow) { - playerPlate.ScalarObjectScreen.active = true; + playerPlate.ScalarObjectScreen.active = false; + return; } - Camera camera = CameraClass.Instance.Camera; + // If we're here, we can show the name plate + playerPlate.ScalarObjectScreen.active = true; + + float processedDistance = Mathf.Clamp(sqrDistance / 625, 0.6f, 1f); + Vector3 position = new(currentPlayer.PlayerBones.Neck.position.x, currentPlayer.PlayerBones.Neck.position.y + (1f * processedDistance), currentPlayer.PlayerBones.Neck.position.z); + Vector3 screenPoint = camera.WorldToScreenPoint(position); + + if (screenPoint.z <= 0) + { + UpdateColorTextMeshProUGUI(playerPlate.playerNameScreen, 0); + UpdateColorImage(playerPlate.healthBarScreen, 0); + UpdateColorTextMeshProUGUI(playerPlate.healthNumberScreen, 0); + UpdateColorImage(playerPlate.healthBarBackgroundScreen, 0); + UpdateColorImage(playerPlate.healthNumberBackgroundScreen, 0); + UpdateColorImage(playerPlate.usecPlateScreen, 0); + UpdateColorImage(playerPlate.bearPlateScreen, 0); + return; + } - if (CameraClass.Instance.SSAA != null && CameraClass.Instance.SSAA.isActiveAndEnabled) + SSAA ssaa = cameraInstance.SSAA; + bool isSSAAEnabled = ssaa != null && ssaa.isActiveAndEnabled; + if (isSSAAEnabled) { - int outputWidth = CameraClass.Instance.SSAA.GetOutputWidth(); - float inputWidth = CameraClass.Instance.SSAA.GetInputWidth(); + int outputWidth = ssaa.GetOutputWidth(); + float inputWidth = ssaa.GetInputWidth(); screenScale = outputWidth / inputWidth; } - float distance = Vector3.Distance(CameraClass.Instance.Camera.transform.position, currentPlayer.Position) / 25; - distance = Mathf.Clamp(distance, 0.6f, 1f); - Vector3 position; + playerPlate.ScalarObjectScreen.transform.position = screenScale < 1 ? screenPoint : screenPoint * screenScale; - position = new(currentPlayer.PlayerBones.Neck.position.x, currentPlayer.PlayerBones.Neck.position.y + (1f * distance), currentPlayer.PlayerBones.Neck.position.z); + float distFromCenterMultiplier = 1f; + if (FikaPlugin.DecreaseOpacityNotLookingAt.Value) + { + float screenWidth = isSSAAEnabled ? ssaa.GetOutputWidth() : Screen.width; + float screenHeight = isSSAAEnabled ? ssaa.GetOutputHeight() : Screen.height; + Vector3 screenCenter = new(screenWidth / 2, screenHeight / 2, 0); + Vector3 playerPosition = playerPlate.ScalarObjectScreen.transform.position; + float sqrDistFromCenter = (screenCenter - playerPosition).sqrMagnitude; + float minScreenSizeHalf = Mathf.Min(screenWidth, screenHeight) / 2; + float maxSqrDistFromCenter = minScreenSizeHalf * minScreenSizeHalf; + distFromCenterMultiplier = Mathf.Clamp01(1 - (sqrDistFromCenter / maxSqrDistFromCenter)); + } - Vector3 screenPoint = camera.WorldToScreenPoint(position); + float alpha = 1f; + float halfMaxDistanceToShow = maxDistanceToShow / 2; + float lerpValue = Mathf.Clamp01((sqrDistance - halfMaxDistanceToShow) / (halfMaxDistanceToShow)); + alpha = Mathf.LerpUnclamped(alpha, 0, lerpValue); + float namePlateScaleMult = Mathf.LerpUnclamped(1f, 0.5f, lerpValue); + namePlateScaleMult = Mathf.Clamp(namePlateScaleMult * FikaPlugin.NamePlateScale.Value, FikaPlugin.MinimumNamePlateScale.Value * FikaPlugin.NamePlateScale.Value, FikaPlugin.NamePlateScale.Value); - if (screenPoint.z > 0) - { - playerPlate.ScalarObjectScreen.transform.position = screenScale < 1 ? screenPoint : screenPoint * screenScale; - playerPlate.ScalarObjectScreen.transform.localScale = (Vector3.one / distance) * FikaPlugin.NamePlateScale.Value; + playerPlate.ScalarObjectScreen.transform.localScale = (Vector3.one / processedDistance) * namePlateScaleMult; - float distanceToCenter = Vector3.Distance(screenPoint, new Vector3(Screen.width, Screen.height, 0) / 2); + alpha *= opacityMultiplier; + alpha *= distFromCenterMultiplier; + alpha = Mathf.Max(FikaPlugin.MinimumOpacity.Value, alpha); - #region Alpha Control for Health Bars. This code is ugly so its getting regioned so I can hide my shame. - if (distanceToCenter < 200) - { - playerPlate.playerNameScreen.color = new Color(playerPlate.playerNameScreen.color.r, playerPlate.playerNameScreen.color.g, playerPlate.playerNameScreen.color.b, Mathf.Max(0.1f, distanceToCenter / 200)); - playerPlate.healthBarScreen.color = new Color(playerPlate.healthBarScreen.color.r, playerPlate.healthBarScreen.color.g, playerPlate.healthBarScreen.color.b, Mathf.Max(0.1f, distanceToCenter / 200)); - playerPlate.healthBarBackgroundScreen.color = new Color(playerPlate.healthBarBackgroundScreen.color.r, playerPlate.healthBarBackgroundScreen.color.g, playerPlate.healthBarBackgroundScreen.color.b, Mathf.Clamp(Mathf.Max(0.1f, distanceToCenter / 200), 0f, 0.4392157f)); - playerPlate.healthNumberBackgroundScreen.color = new Color(playerPlate.healthNumberBackgroundScreen.color.r, playerPlate.healthNumberBackgroundScreen.color.g, playerPlate.healthNumberBackgroundScreen.color.b, Mathf.Clamp(Mathf.Max(0.1f, distanceToCenter / 200), 0f, 0.4392157f)); - playerPlate.healthNumberScreen.color = new Color(playerPlate.healthNumberScreen.color.r, playerPlate.healthNumberScreen.color.g, playerPlate.healthNumberScreen.color.b, Mathf.Max(0.1f, distanceToCenter / 200)); - playerPlate.usecPlateScreen.color = new Color(playerPlate.usecPlateScreen.color.r, playerPlate.usecPlateScreen.color.g, playerPlate.usecPlateScreen.color.b, Mathf.Max(0.1f, distanceToCenter / 200)); - playerPlate.bearPlateScreen.color = new Color(playerPlate.bearPlateScreen.color.r, playerPlate.bearPlateScreen.color.g, playerPlate.bearPlateScreen.color.b, Mathf.Max(0.1f, distanceToCenter / 200)); + float backgroundOpacity = Mathf.Clamp(alpha, 0f, 0.44f); + float healthAlphaMultiplier = FikaPlugin.HideHealthBar.Value ? 0 : 1f; - } - else - { - playerPlate.playerNameScreen.color = new Color(playerPlate.playerNameScreen.color.r, playerPlate.playerNameScreen.color.g, playerPlate.playerNameScreen.color.b, 1); - playerPlate.healthBarScreen.color = new Color(playerPlate.healthBarScreen.color.r, playerPlate.healthBarScreen.color.g, playerPlate.healthBarScreen.color.b, 1); - playerPlate.healthBarBackgroundScreen.color = new Color(playerPlate.healthBarBackgroundScreen.color.r, playerPlate.healthBarBackgroundScreen.color.g, playerPlate.healthBarBackgroundScreen.color.b, 1); - playerPlate.healthNumberBackgroundScreen.color = new Color(playerPlate.healthNumberBackgroundScreen.color.r, playerPlate.healthNumberBackgroundScreen.color.g, playerPlate.healthNumberBackgroundScreen.color.b, 1); - playerPlate.healthNumberScreen.color = new Color(playerPlate.healthNumberScreen.color.r, playerPlate.healthNumberScreen.color.g, playerPlate.healthNumberScreen.color.b, 1); - playerPlate.usecPlateScreen.color = new Color(playerPlate.usecPlateScreen.color.r, playerPlate.usecPlateScreen.color.g, playerPlate.usecPlateScreen.color.b, 1); - playerPlate.bearPlateScreen.color = new Color(playerPlate.bearPlateScreen.color.r, playerPlate.bearPlateScreen.color.g, playerPlate.bearPlateScreen.color.b, 1); - } - } - else - { - playerPlate.playerNameScreen.color = new Color(playerPlate.playerNameScreen.color.r, playerPlate.playerNameScreen.color.g, playerPlate.playerNameScreen.color.b, 0); - playerPlate.healthBarScreen.color = new Color(playerPlate.healthBarScreen.color.r, playerPlate.healthBarScreen.color.g, playerPlate.healthBarScreen.color.b, 0); - playerPlate.healthBarBackgroundScreen.color = new Color(playerPlate.healthBarBackgroundScreen.color.r, playerPlate.healthBarBackgroundScreen.color.g, playerPlate.healthBarBackgroundScreen.color.b, 0); - playerPlate.healthNumberBackgroundScreen.color = new Color(playerPlate.healthNumberBackgroundScreen.color.r, playerPlate.healthNumberBackgroundScreen.color.g, playerPlate.healthNumberBackgroundScreen.color.b, 0); - playerPlate.healthNumberScreen.color = new Color(playerPlate.healthNumberScreen.color.r, playerPlate.healthNumberScreen.color.g, playerPlate.healthNumberScreen.color.b, 0); - playerPlate.usecPlateScreen.color = new Color(playerPlate.usecPlateScreen.color.r, playerPlate.usecPlateScreen.color.g, playerPlate.usecPlateScreen.color.b, 0); - playerPlate.bearPlateScreen.color = new Color(playerPlate.bearPlateScreen.color.r, playerPlate.bearPlateScreen.color.g, playerPlate.bearPlateScreen.color.b, 0); - } - #endregion + UpdateColorTextMeshProUGUI(playerPlate.playerNameScreen, alpha); + UpdateColorImage(playerPlate.healthBarScreen, alpha * healthAlphaMultiplier); + UpdateColorTextMeshProUGUI(playerPlate.healthNumberScreen, alpha * healthAlphaMultiplier); + UpdateColorImage(playerPlate.healthBarBackgroundScreen, backgroundOpacity * healthAlphaMultiplier); + UpdateColorImage(playerPlate.healthNumberBackgroundScreen, backgroundOpacity * healthAlphaMultiplier); + UpdateColorImage(playerPlate.usecPlateScreen, alpha); + UpdateColorImage(playerPlate.bearPlateScreen, alpha); } private void CreateHealthBar() @@ -161,17 +169,6 @@ private void CreateHealthBar() GameObject uiGameObj = Instantiate(uiPrefab); playerPlate = uiGameObj.GetComponent(); playerPlate.SetNameText(currentPlayer.Profile.Info.MainProfileNickname); - if (FikaPlugin.UsePlateFactionSide.Value) - { - if (currentPlayer.Profile.Side == EPlayerSide.Usec) - { - playerPlate.usecPlateScreen.gameObject.SetActive(true); - } - else if (currentPlayer.Profile.Side == EPlayerSide.Bear) - { - playerPlate.bearPlateScreen.gameObject.SetActive(true); - } - } if (FikaPlugin.DevelopersList.ContainsKey(currentPlayer.Profile.Nickname.ToLower())) { playerPlate.playerNameScreen.color = new Color(0, 0.6091f, 1, 1); @@ -190,6 +187,62 @@ private void CreateHealthBar() playerPlate.usecPlateScreen.GetComponent().sprite = specialIcons.IconsSettings[2].IconSprite; playerPlate.usecPlateScreen.transform.localPosition = new Vector3(0f, 24.9f, 0); } + // Start the plates both disabled, the visibility will be set in the update loop + playerPlate.usecPlateScreen.gameObject.SetActive(false); + playerPlate.bearPlateScreen.gameObject.SetActive(false); + } + + currentPlayer.HealthController.HealthChangedEvent += HealthController_HealthChangedEvent; + currentPlayer.HealthController.BodyPartDestroyedEvent += HealthController_BodyPartDestroyedEvent; + currentPlayer.HealthController.BodyPartRestoredEvent += HealthController_BodyPartRestoredEvent; + } + + private void HealthController_BodyPartRestoredEvent(EBodyPart arg1, EFT.HealthSystem.ValueStruct arg2) + { + UpdateHealth(); + } + + private void HealthController_BodyPartDestroyedEvent(EBodyPart arg1, EDamageType arg2) + { + UpdateHealth(); + } + + private void HealthController_HealthChangedEvent(EBodyPart arg1, float arg2, DamageInfo arg3) + { + UpdateHealth(); + } + + /// + /// Updates the health on the HealthBar, this is invoked from events on the healthcontroller + /// + private void UpdateHealth() + { + if (playerPlate.healthBarScreen.gameObject.activeSelf) + { + float currentHealth = currentPlayer.HealthController.GetBodyPartHealth(EBodyPart.Common, true).Current; + float maxHealth = currentPlayer.HealthController.GetBodyPartHealth(EBodyPart.Common, true).Maximum; + if (FikaPlugin.UseHealthNumber.Value) + { + if (!playerPlate.healthNumberBackgroundScreen.gameObject.activeSelf) + { + playerPlate.healthNumberBackgroundScreen.gameObject.SetActive(true); + playerPlate.healthBarBackgroundScreen.gameObject.SetActive(false); + } + int healthNumberPercentage = (int)Math.Round((currentHealth / maxHealth) * 100); + playerPlate.SetHealthNumberText($"{healthNumberPercentage}%"); + } + else + { + if (!playerPlate.healthBarBackgroundScreen.gameObject.active) + { + playerPlate.healthNumberBackgroundScreen.gameObject.SetActive(false); + playerPlate.healthBarBackgroundScreen.gameObject.SetActive(true); + } + + float normalizedHealth = Mathf.Clamp01(currentHealth / maxHealth); + playerPlate.healthBarScreen.fillAmount = normalizedHealth; + UpdateHealthBarColor(normalizedHealth); + } } } @@ -200,8 +253,64 @@ private void UpdateHealthBarColor(float normalizedHealth) playerPlate.healthBarScreen.color = color; } + private void UpdateColorImage(Image screenObject, float alpha) + { + if (screenObject.gameObject.activeInHierarchy) + { + Color color = screenObject.color; + color.a = alpha; + screenObject.color = color; + } + } + + private void UpdateColorTextMeshProUGUI(TMPro.TextMeshProUGUI screenObject, float alpha) + { + if (screenObject.gameObject.activeInHierarchy) + { + Color color = screenObject.color; + color.a = alpha; + screenObject.color = color; + } + } + + private void SetPlayerPlateHealthVisibility(bool hidden) + { + playerPlate.healthNumberScreen.gameObject.SetActive(!hidden && FikaPlugin.UseHealthNumber.Value); + playerPlate.healthNumberBackgroundScreen.gameObject.SetActive(!hidden && FikaPlugin.UseHealthNumber.Value); + playerPlate.healthBarScreen.gameObject.SetActive(!hidden && !FikaPlugin.UseHealthNumber.Value); + playerPlate.healthBarBackgroundScreen.gameObject.SetActive(!hidden && !FikaPlugin.UseHealthNumber.Value); + } + + + private void SetPlayerPlateFactionVisibility(bool visible) + { + if (currentPlayer.Profile.Side == EPlayerSide.Usec) + { + playerPlate.usecPlateScreen.gameObject.SetActive(visible); + } + else if (currentPlayer.Profile.Side == EPlayerSide.Bear) + { + playerPlate.bearPlateScreen.gameObject.SetActive(visible); + } + } + + private bool IsThrottleUpdate() + { + // For throttling updates to various elements + frameCounter++; + bool throttleUpdate = frameCounter >= throttleInterval; + if (throttleUpdate) + { + frameCounter = 0; + } + return throttleUpdate; + } + private void OnDestroy() { + currentPlayer.HealthController.HealthChangedEvent -= HealthController_HealthChangedEvent; + currentPlayer.HealthController.BodyPartDestroyedEvent -= HealthController_BodyPartDestroyedEvent; + currentPlayer.HealthController.BodyPartRestoredEvent -= HealthController_BodyPartRestoredEvent; playerPlate.gameObject.SetActive(false); Destroy(this); } diff --git a/Fika.Core/Coop/FreeCamera/FreeCameraController.cs b/Fika.Core/Coop/FreeCamera/FreeCameraController.cs index 29750ec4..f1cd7c20 100644 --- a/Fika.Core/Coop/FreeCamera/FreeCameraController.cs +++ b/Fika.Core/Coop/FreeCamera/FreeCameraController.cs @@ -236,7 +236,7 @@ private void ShowExtractMessage() if (FikaPlugin.ExtractKey.Value.Modifiers.Count() > 0) { string modifiers = string.Join("+", FikaPlugin.ExtractKey.Value.Modifiers); - text = modifiers + "+" + text; + text = modifiers + " + " + text; } extractText = FikaUIUtils.CreateOverlayText($"Press '{text}' to extract"); } diff --git a/Fika.Core/Coop/GameMode/CoopGame.cs b/Fika.Core/Coop/GameMode/CoopGame.cs index 4dda819f..fa8dfbd2 100644 --- a/Fika.Core/Coop/GameMode/CoopGame.cs +++ b/Fika.Core/Coop/GameMode/CoopGame.cs @@ -31,7 +31,6 @@ using HarmonyLib; using JsonType; using LiteNetLib.Utils; -using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; @@ -483,33 +482,31 @@ public override void vmethod_1(float timeBeforeDeploy) /// Time in seconds to count down private async void DeployScreen(float timeBeforeDeploy) { - if (MatchmakerAcceptPatches.IsServer && MatchmakerAcceptPatches.HostExpectedNumberOfPlayers <= 1) + if (CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler)) { - if (fikaStartButton != null) + if (MatchmakerAcceptPatches.IsServer && MatchmakerAcceptPatches.HostExpectedNumberOfPlayers <= 1) { - Destroy(fikaStartButton); - } + if (fikaStartButton != null) + { + Destroy(fikaStartButton); + } - if (CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler)) - { SetStatusModel status = new SetStatusModel(coopHandler.MyPlayer.ProfileId, LobbyEntry.ELobbyStatus.IN_GAME); await FikaRequestHandler.UpdateSetStatus(status); - } - Singleton.Instance.ReadyClients++; - base.vmethod_1(timeBeforeDeploy); - return; - } + Singleton.Instance.ReadyClients++; + base.vmethod_1(timeBeforeDeploy); + return; + } - forceStart = false; + NetDataWriter writer = new(); + forceStart = false; - MatchmakerAcceptPatches.GClass3163.ChangeStatus("Waiting for other players to finish loading..."); + MatchmakerAcceptPatches.GClass3163.ChangeStatus("Waiting for other players to finish loading..."); - fikaStartButton?.SetActive(true); + fikaStartButton?.SetActive(true); - if (MatchmakerAcceptPatches.IsServer) - { - if (CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler)) + if (MatchmakerAcceptPatches.IsServer) { SetStatusModel status = new SetStatusModel(coopHandler.MyPlayer.ProfileId, LobbyEntry.ELobbyStatus.IN_GAME); await FikaRequestHandler.UpdateSetStatus(status); @@ -518,52 +515,56 @@ private async void DeployScreen(float timeBeforeDeploy) { await Task.Delay(100); } while (coopHandler.HumanPlayers < MatchmakerAcceptPatches.HostExpectedNumberOfPlayers && !forceStart); - } - FikaServer server = Singleton.Instance; - server.ReadyClients++; - InformationPacket packet = new() - { - NumberOfPlayers = server.NetServer.ConnectedPeersCount, - ReadyPlayers = server.ReadyClients - }; - NetDataWriter writer = new(); - writer.Reset(); - server.SendDataToAll(writer, ref packet, LiteNetLib.DeliveryMethod.ReliableOrdered); + FikaServer server = Singleton.Instance; + server.ReadyClients++; + InformationPacket packet = new() + { + NumberOfPlayers = server.NetServer.ConnectedPeersCount, + ReadyPlayers = server.ReadyClients + }; + writer.Reset(); + server.SendDataToAll(writer, ref packet, LiteNetLib.DeliveryMethod.ReliableOrdered); - do - { - await Task.Delay(250); - } while (Singleton.Instance.ReadyClients < MatchmakerAcceptPatches.HostExpectedNumberOfPlayers && !forceStart); - } - else if (MatchmakerAcceptPatches.IsClient) - { - if (CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler)) + do + { + await Task.Delay(250); + } while (Singleton.Instance.ReadyClients < MatchmakerAcceptPatches.HostExpectedNumberOfPlayers && !forceStart); + + foreach (CoopPlayer player in coopHandler.Players.Values) + { + SyncNetIdPacket syncPacket = new(player.ProfileId, player.NetId); + + writer.Reset(); + Singleton.Instance.SendDataToAll(writer, ref syncPacket, LiteNetLib.DeliveryMethod.ReliableUnordered); + } + } + else if (MatchmakerAcceptPatches.IsClient) { do { await Task.Delay(100); } while (coopHandler.HumanPlayers < MatchmakerAcceptPatches.HostExpectedNumberOfPlayers && !forceStart); - } - FikaClient client = Singleton.Instance; - InformationPacket packet = new(true) - { - ReadyPlayers = 1 - }; - NetDataWriter writer = new(); - writer.Reset(); - client.SendData(writer, ref packet, LiteNetLib.DeliveryMethod.ReliableOrdered); + FikaClient client = Singleton.Instance; + InformationPacket packet = new(true) + { + ReadyPlayers = 1 + }; + writer.Reset(); + client.SendData(writer, ref packet, LiteNetLib.DeliveryMethod.ReliableOrdered); - do + do + { + await Task.Delay(250); + } while (Singleton.Instance.ReadyClients < MatchmakerAcceptPatches.HostExpectedNumberOfPlayers && !forceStart); + } + + if (fikaStartButton != null) { - await Task.Delay(250); - } while (Singleton.Instance.ReadyClients < MatchmakerAcceptPatches.HostExpectedNumberOfPlayers && !forceStart); - } + Destroy(fikaStartButton); + } - if (fikaStartButton != null) - { - Destroy(fikaStartButton); } base.vmethod_1(timeBeforeDeploy); @@ -653,7 +654,7 @@ public override async Task vmethod_2(int playerId, Vector3 position LocalPlayer myPlayer = await CoopPlayer.Create(playerId, spawnPoint.Position, spawnPoint.Rotation, "Player", "Main_", EPointOfView.FirstPerson, profile, false, UpdateQueue, Player.EUpdateMode.Auto, Player.EUpdateMode.Auto, GClass549.Config.CharacterController.ClientPlayerMode, () => Singleton.Instance.Control.Settings.MouseSensitivity, - () => Singleton.Instance.Control.Settings.MouseAimingSensitivity, new GClass1445(), 0, questController); + () => Singleton.Instance.Control.Settings.MouseAimingSensitivity, new GClass1445(), MatchmakerAcceptPatches.IsServer ? 0 : 1000, questController); profile.SetSpawnedInSession(profile.Side == EPlayerSide.Savage); @@ -1374,8 +1375,15 @@ public override void Stop(string profileId, ExitStatus exitStatus, string exitNa wavesSpawnScenario_0?.Stop(); - PlayerLeftRequest body = new PlayerLeftRequest(myPlayer.ProfileId); - FikaRequestHandler.RaidLeave(body); + try + { + PlayerLeftRequest body = new(myPlayer.ProfileId); + FikaRequestHandler.RaidLeave(body); + } + catch (Exception) + { + FikaPlugin.Instance.FikaLogger.LogError("Unable to send RaidLeave request to server."); + } if (CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler)) { diff --git a/Fika.Core/Coop/PacketHandlers/ClientPacketSender.cs b/Fika.Core/Coop/PacketHandlers/ClientPacketSender.cs index ded2b67c..2c69f0dd 100644 --- a/Fika.Core/Coop/PacketHandlers/ClientPacketSender.cs +++ b/Fika.Core/Coop/PacketHandlers/ClientPacketSender.cs @@ -10,6 +10,7 @@ using LiteNetLib.Utils; using System.Collections; using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace Fika.Core.Coop.PacketHandlers @@ -121,7 +122,11 @@ private void Update() Client?.SendData(Writer, ref healthSyncPacket, DeliveryMethod.ReliableOrdered); } } - if (FikaPlugin.PingButton.Value.IsPressed() && player.IsYourPlayer && player.HealthController.IsAlive && FikaPlugin.UsePingSystem.Value) + if (Input.GetKey(FikaPlugin.PingButton.Value.MainKey) + && FikaPlugin.PingButton.Value.Modifiers.All(Input.GetKey) + && player.IsYourPlayer + && player.HealthController.IsAlive + && FikaPlugin.UsePingSystem.Value) { player?.Ping(); } diff --git a/Fika.Core/Coop/PacketHandlers/ServerPacketSender.cs b/Fika.Core/Coop/PacketHandlers/ServerPacketSender.cs index 35230e19..21258714 100644 --- a/Fika.Core/Coop/PacketHandlers/ServerPacketSender.cs +++ b/Fika.Core/Coop/PacketHandlers/ServerPacketSender.cs @@ -13,6 +13,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace Fika.Core.Coop.PacketHandlers @@ -34,7 +35,7 @@ public class ServerPacketSender : MonoBehaviour, IPacketSender private void Awake() { - logger = new("ServerPacketSender"); + logger = BepInEx.Logging.Logger.CreateLogSource("ServerPacketSender"); player = GetComponent(); } @@ -128,7 +129,11 @@ private void Update() Server?.SendDataToAll(Writer, ref healthSyncPacket, DeliveryMethod.ReliableOrdered); } } - if (FikaPlugin.PingButton.Value.IsPressed() && player.IsYourPlayer && player.HealthController.IsAlive && FikaPlugin.UsePingSystem.Value) + if (Input.GetKey(FikaPlugin.PingButton.Value.MainKey) + && FikaPlugin.PingButton.Value.Modifiers.All(Input.GetKey) + && player.IsYourPlayer + && player.HealthController.IsAlive + && FikaPlugin.UsePingSystem.Value) { player?.Ping(); } diff --git a/Fika.Core/Coop/Players/CoopPlayer.cs b/Fika.Core/Coop/Players/CoopPlayer.cs index be5e81c2..6a58cfe4 100644 --- a/Fika.Core/Coop/Players/CoopPlayer.cs +++ b/Fika.Core/Coop/Players/CoopPlayer.cs @@ -200,6 +200,13 @@ public override void ApplyDamageInfo(DamageInfo damageInfo, EBodyPart bodyPartTy { if (IsYourPlayer) { + if (damageInfo.Player != null) + { + if (!FikaPlugin.Instance.FriendlyFire && damageInfo.Player.iPlayer is ObservedCoopPlayer observedCoopPlayer && !observedCoopPlayer.IsObservedAI) + { + return; + } + } if (colliderType == EBodyPartColliderType.HeadCommon) { damageInfo.Damage *= FikaPlugin.HeadDamageMultiplier.Value; @@ -221,7 +228,7 @@ public override GClass1676 ApplyShot(DamageInfo damageInfo, EBodyPart bodyPartTy return base.ApplyShot(damageInfo, bodyPartType, colliderType, armorPlateCollider, shotId); } - return null; + return null; } public override void Proceed(bool withNetwork, Callback callback, bool scheduled = true) @@ -1280,7 +1287,7 @@ public virtual void HandleDamagePacket(DamagePacket packet) if (!FikaPlugin.Instance.FriendlyFire && damageInfo.Player.iPlayer is ObservedCoopPlayer observedCoopPlayer && !observedCoopPlayer.IsObservedAI) { return; - } + } } } diff --git a/Fika.Core/Coop/Players/ObservedCoopPlayer.cs b/Fika.Core/Coop/Players/ObservedCoopPlayer.cs index 4307efc4..e69a00c7 100644 --- a/Fika.Core/Coop/Players/ObservedCoopPlayer.cs +++ b/Fika.Core/Coop/Players/ObservedCoopPlayer.cs @@ -889,7 +889,7 @@ protected override async void Start() { IsObservedAI = true; } - + PacketSender = gameObject.AddComponent(); if (IsObservedAI) diff --git a/Fika.Core/FikaPlugin.cs b/Fika.Core/FikaPlugin.cs index e733f8b7..3667d613 100644 --- a/Fika.Core/FikaPlugin.cs +++ b/Fika.Core/FikaPlugin.cs @@ -106,11 +106,20 @@ public class FikaPlugin : BaseUnityPlugin public static ConfigEntry FasterInventoryScrollSpeed { get; set; } public static ConfigEntry ExtractKey { get; set; } - // Coop | Custom + // Coop | Name Plates public static ConfigEntry UseNamePlates { get; set; } + public static ConfigEntry HideHealthBar { get; set; } public static ConfigEntry UseHealthNumber { get; set; } public static ConfigEntry UsePlateFactionSide { get; set; } + public static ConfigEntry HideNamePlateInOptic { get; set; } + public static ConfigEntry DecreaseOpacityNotLookingAt { get; set; } public static ConfigEntry NamePlateScale { get; set; } + public static ConfigEntry OpacityInADS { get; set; } + public static ConfigEntry MaxDistanceToShow { get; set; } + public static ConfigEntry MinimumOpacity { get; set; } + public static ConfigEntry MinimumNamePlateScale { get; set; } + + // Coop | Custom public static ConfigEntry UsePingSystem { get; set; } public static ConfigEntry PingButton { get; set; } public static ConfigEntry PingColor { get; set; } @@ -127,6 +136,7 @@ public class FikaPlugin : BaseUnityPlugin public static ConfigEntry DynamicAIRate { get; set; } public static ConfigEntry CullPlayers { get; set; } public static ConfigEntry CullingRange { get; set; } + // Performance | Bot Limits public static ConfigEntry EnforcedSpawnLimits { get; set; } public static ConfigEntry DespawnFurthest { get; set; } @@ -255,15 +265,31 @@ private void SetupConfig() ExtractKey = Config.Bind("Coop", "Extract Key", new KeyboardShortcut(KeyCode.F8), new ConfigDescription("The key used to extract from the raid.", tags: new ConfigurationManagerAttributes() { Order = 1 })); - // Coop | Custom + // Coop | Name Plates + + UseNamePlates = Config.Bind("Coop | Name Plates", "Show Player Name Plates", false, new ConfigDescription("Toggle Health-Bars & Names.", tags: new ConfigurationManagerAttributes() { Order = 10 })); + + HideHealthBar = Config.Bind("Coop | Name Plates", "Hide Health Bar", false, new ConfigDescription("Completely hides the health bar.", tags: new ConfigurationManagerAttributes() { Order = 9 })); - UseNamePlates = Config.Bind("Coop | Custom", "Show Player Name Plates", false, new ConfigDescription("Toggle Health-Bars & Names.", tags: new ConfigurationManagerAttributes() { Order = 10 })); + UseHealthNumber = Config.Bind("Coop | Name Plates", "Show HP% instead of bar", false, new ConfigDescription("Shows health in % amount instead of using the bar.", tags: new ConfigurationManagerAttributes() { Order = 8 })); - UseHealthNumber = Config.Bind("Coop | Custom", "Show HP% instead of bar", false, new ConfigDescription("Shows health in % amount instead of using the bar.", tags: new ConfigurationManagerAttributes() { Order = 9 })); + UsePlateFactionSide = Config.Bind("Coop | Name Plates", "Show Player Faction Icon", true, new ConfigDescription("Shows the player faction icon next to the HP bar.", tags: new ConfigurationManagerAttributes() { Order = 7 })); - UsePlateFactionSide = Config.Bind("Coop | Custom", "Show Player Faction Icon", true, new ConfigDescription("Shows the player faction icon next to the HP bar.", tags: new ConfigurationManagerAttributes() { Order = 8 })); + HideNamePlateInOptic = Config.Bind("Coop | Name Plates", "Hide Name Plate in Optic", true, new ConfigDescription("Hides the name plate when viewing through PiP scopes since it's kinda janky.", tags: new ConfigurationManagerAttributes() { Order = 6 })); - NamePlateScale = Config.Bind("Coop | Custom", "Name Plate Scale", 0.22f, new ConfigDescription("Size of the name plates", new AcceptableValueRange(0.05f, 1f), new ConfigurationManagerAttributes() { Order = 7 })); + DecreaseOpacityNotLookingAt = Config.Bind("Coop | Name Plates", "Decrease Opacity In Peripheral", true, new ConfigDescription("Decreases the opacity of the name plates when not looking at a player.", tags: new ConfigurationManagerAttributes() { Order = 5 })); + + NamePlateScale = Config.Bind("Coop | Name Plates", "Name Plate Scale", 0.22f, new ConfigDescription("Size of the name plates", new AcceptableValueRange(0.05f, 1f), new ConfigurationManagerAttributes() { Order = 4 })); + + OpacityInADS = Config.Bind("Coop | Name Plates", "Opacity in ADS", 0.75f, new ConfigDescription("The opacity of the name plates when aiming down sights.", new AcceptableValueRange(0.1f, 1f), new ConfigurationManagerAttributes() { Order = 3 })); + + MaxDistanceToShow = Config.Bind("Coop | Name Plates", "Max Distance to Show", 500f, new ConfigDescription("The maximum distance at which name plates will become invisible, starts to fade at half the input value.", new AcceptableValueRange(10f, 1000f), new ConfigurationManagerAttributes() { Order = 2 })); + + MinimumOpacity = Config.Bind("Coop | Name Plates", "Minimum Opacity", 0.1f, new ConfigDescription("The minimum opacity of the name plates.", new AcceptableValueRange(0.0f, 1f), new ConfigurationManagerAttributes() { Order = 1 })); + + MinimumNamePlateScale = Config.Bind("Coop | Name Plates", "Minimum Name Plate Scale", 0.01f, new ConfigDescription("The minimum scale of the name plates.", new AcceptableValueRange(0.0f, 1f), new ConfigurationManagerAttributes() { Order = 0 })); + + // Coop | Custom UsePingSystem = Config.Bind("Coop | Custom", "Ping System", false, new ConfigDescription("Toggle Ping System. If enabled you can receive and send pings by pressing the ping key.", tags: new ConfigurationManagerAttributes() { Order = 6 })); diff --git a/Fika.Core/Networking/FikaClient.cs b/Fika.Core/Networking/FikaClient.cs index 4899f4f2..203be287 100644 --- a/Fika.Core/Networking/FikaClient.cs +++ b/Fika.Core/Networking/FikaClient.cs @@ -52,12 +52,11 @@ public NetManager NetClient public string IP { get; private set; } public int Port { get; private set; } public bool SpawnPointsReceived { get; private set; } = false; - private ManualLogSource clientLogger; + private readonly ManualLogSource clientLogger = BepInEx.Logging.Logger.CreateLogSource("Fika.Client"); public bool ClientReady = false; - public void Start() + protected void Start() { - clientLogger = new("Fika Client"); packetProcessor.SubscribeNetSerializable(OnPlayerStatePacketReceived); packetProcessor.SubscribeNetSerializable(OnGameTimerPacketReceived); @@ -80,6 +79,7 @@ public void Start() packetProcessor.SubscribeNetSerializable(OnBorderZonePacketReceived); packetProcessor.SubscribeNetSerializable(OnSendCharacterPacketReceived); packetProcessor.SubscribeNetSerializable(OnAssignNetIdPacketReceived); + packetProcessor.SubscribeNetSerializable(OnSyncNetIdPacketReceived); _netClient = new NetManager(this) { @@ -94,7 +94,7 @@ public void Start() _netClient.Start(); - GetHostRequest body = new GetHostRequest(); + GetHostRequest body = new(CoopHandler.GetServerId()); GetHostResponse result = FikaRequestHandler.GetHost(body); IP = result.Ip; @@ -114,8 +114,38 @@ public void Start() ClientReady = true; } + private void OnSyncNetIdPacketReceived(SyncNetIdPacket packet, NetPeer peer) + { + Dictionary newPlayers = Players; + if (Players.TryGetValue(packet.NetId, out CoopPlayer player)) + { + if (player.ProfileId != packet.ProfileId) + { + FikaPlugin.Instance.FikaLogger.LogWarning($"OnSyncNetIdPacketReceived: {packet.ProfileId} had the wrong NetId: {Players[packet.NetId].NetId}, should be {packet.NetId}"); + for (int i = 0; i < Players.Count; i++) + { + KeyValuePair playerToReorganize = Players.Where(x => x.Value.ProfileId == packet.ProfileId).First(); + Players.Remove(playerToReorganize.Key); + Players[packet.NetId] = playerToReorganize.Value; + } + } + } + else + { + FikaPlugin.Instance.FikaLogger.LogError($"OnSyncNetIdPacketReceived: Could not find NetId {packet.NetId} in player list!"); + string allPlayers = ""; + foreach (KeyValuePair kvp in CoopHandler.Players) + { + string toAdd = $"Key: {kvp.Key}, Nickname: {kvp.Value.Profile.Nickname}, NetId: {kvp.Value.NetId}"; + allPlayers = string.Join(", ", allPlayers + toAdd); + } + FikaPlugin.Instance.FikaLogger.LogError(allPlayers); + } + } + private void OnAssignNetIdPacketReceived(AssignNetIdPacket packet, NetPeer peer) { + FikaPlugin.Instance.FikaLogger.LogInfo($"OnAssignNetIdPacketReceived: Assigned NetId {packet.NetId} to my own client."); MyPlayer.NetId = packet.NetId; int i = -1; foreach (var player in Players) @@ -130,6 +160,7 @@ private void OnAssignNetIdPacketReceived(AssignNetIdPacket packet, NetPeer peer) if (i == -1) { + FikaPlugin.Instance.FikaLogger.LogError("OnAssignNetIdPacketReceived: Could not find own player among players list"); return; } diff --git a/Fika.Core/Networking/FikaPingingClient.cs b/Fika.Core/Networking/FikaPingingClient.cs new file mode 100644 index 00000000..ef77fa1a --- /dev/null +++ b/Fika.Core/Networking/FikaPingingClient.cs @@ -0,0 +1,119 @@ +using BepInEx.Logging; +using Fika.Core.Networking.Http; +using Fika.Core.Networking.Http.Models; +using LiteNetLib; +using LiteNetLib.Utils; +using System.Net; +using System.Net.Sockets; + +namespace Fika.Core.Networking +{ + internal class FikaPingingClient(string serverId) : INetEventListener + { + public NetManager NetClient; + private readonly ManualLogSource _logger = Logger.CreateLogSource("Fika.PingingClient"); + private readonly string serverId = serverId; + private IPEndPoint remoteEndPoint; + public bool Received = false; + + public bool Init() + { + NetClient = new(this) + { + UnconnectedMessagesEnabled = true + }; + + GetHostRequest body = new(serverId); + GetHostResponse result = FikaRequestHandler.GetHost(body); + + string ip = result.Ip; + int port = result.Port; + + if (string.IsNullOrEmpty(ip)) + { + _logger.LogError("IP was empty when pinging!"); + return false; + } + + if (port == default) + { + _logger.LogError("Port was empty when pinging!"); + return false; + } + + remoteEndPoint = new(IPAddress.Parse(ip), port); + + NetClient.Start(); + + return true; + } + + public bool PingEndPoint() + { + if (Received) + { + return true; + } + + NetDataWriter writer = new(); + writer.Put("fika.hello"); + + return NetClient.SendUnconnectedMessage(writer, remoteEndPoint); + } + + public void OnConnectionRequest(ConnectionRequest request) + { + // Do nothing + } + + public void OnNetworkError(IPEndPoint endPoint, SocketError socketError) + { + // Do nothing + } + + public void OnNetworkLatencyUpdate(NetPeer peer, int latency) + { + // Do nothing + } + + public void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod) + { + // Do nothing + } + + public void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType) + { + if (Received) + { + return; + } + _logger.LogInfo("Received response from server, parsing..."); + + if (reader.TryGetString(out string result)) + { + if (result == "fika.hello") + { + Received = true; + } + else + { + _logger.LogError("Data was not as expected"); + } + } + else + { + _logger.LogError("Could not parse string"); + } + } + + public void OnPeerConnected(NetPeer peer) + { + // Do nothing + } + + public void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo) + { + // Do nothing + } + } +} diff --git a/Fika.Core/Networking/FikaServer.cs b/Fika.Core/Networking/FikaServer.cs index db488ecd..38701df8 100644 --- a/Fika.Core/Networking/FikaServer.cs +++ b/Fika.Core/Networking/FikaServer.cs @@ -34,7 +34,7 @@ public class FikaServer : MonoBehaviour, INetEventListener, INetLogger { private NetManager _netServer; public NetPacketProcessor packetProcessor = new(); - private NetDataWriter _dataWriter = new(); + private readonly NetDataWriter _dataWriter = new(); public CoopPlayer MyPlayer => (CoopPlayer)Singleton.Instance.MainPlayer; public Dictionary Players => CoopHandler.Players; public List PlayersMissing = []; @@ -51,7 +51,7 @@ public NetManager NetServer } public DateTime timeSinceLastPeerDisconnected = DateTime.Now.AddDays(1); public bool hasHadPeer = false; - private ManualLogSource serverLogger; + private readonly ManualLogSource serverLogger = BepInEx.Logging.Logger.CreateLogSource("Fika.Server"); public bool ServerReady = false; private int _currentNetId; @@ -61,7 +61,6 @@ public async void Start() _currentNetId = 1; NetDebug.Logger = this; - serverLogger = new("Fika Server"); packetProcessor.SubscribeNetSerializable(OnPlayerStatePacketReceived); packetProcessor.SubscribeNetSerializable(OnGameTimerPacketReceived); @@ -85,6 +84,7 @@ public async void Start() _netServer = new NetManager(this) { BroadcastReceiveEnabled = true, + UnconnectedMessagesEnabled = true, UpdateTime = 15, AutoRecycle = true, IPv6Enabled = false, @@ -607,6 +607,27 @@ public void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketRead resp.Put(1); _netServer.SendUnconnectedMessage(resp, remoteEndPoint); } + else + { + if (reader.TryGetString(out string data)) + { + if (data == "fika.hello") + { + NetDataWriter resp = new(); + resp.Put(data); + _netServer.SendUnconnectedMessage(resp, remoteEndPoint); + serverLogger.LogInfo("PingingRequest: Correct ping query, sending response"); + } + else + { + serverLogger.LogError("PingingRequest: Data was not as expected"); + } + } + else + { + serverLogger.LogError("PingingRequest: Could not parse string"); + } + } } public void OnNetworkLatencyUpdate(NetPeer peer, int latency) diff --git a/Fika.Core/Networking/Models/GetHostRequest.cs b/Fika.Core/Networking/Models/GetHostRequest.cs index cd19b884..8ce16366 100644 --- a/Fika.Core/Networking/Models/GetHostRequest.cs +++ b/Fika.Core/Networking/Models/GetHostRequest.cs @@ -1,4 +1,3 @@ -using Fika.Core.Coop.Components; using System.Runtime.Serialization; namespace Fika.Core.Networking.Http.Models @@ -9,9 +8,9 @@ public struct GetHostRequest [DataMember(Name = "serverId")] public string ServerId; - public GetHostRequest() + public GetHostRequest(string serverId) { - ServerId = CoopHandler.GetServerId(); + ServerId = serverId; } } } \ No newline at end of file diff --git a/Fika.Core/Networking/Packets/Communication/SyncNetIdPacket.cs b/Fika.Core/Networking/Packets/Communication/SyncNetIdPacket.cs new file mode 100644 index 00000000..3f9590b9 --- /dev/null +++ b/Fika.Core/Networking/Packets/Communication/SyncNetIdPacket.cs @@ -0,0 +1,22 @@ +using LiteNetLib.Utils; + +namespace Fika.Core.Networking +{ + public struct SyncNetIdPacket(string profileId, int netId) : INetSerializable + { + public string ProfileId = profileId; + public int NetId = netId; + + public void Deserialize(NetDataReader reader) + { + ProfileId = reader.GetString(); + NetId = reader.GetInt(); + } + + public void Serialize(NetDataWriter writer) + { + writer.Put(ProfileId); + writer.Put(NetId); + } + } +} diff --git a/Fika.Core/UI/Custom/MatchMakerUIScript.cs b/Fika.Core/UI/Custom/MatchMakerUIScript.cs index 71d1adc5..3e2205dd 100644 --- a/Fika.Core/UI/Custom/MatchMakerUIScript.cs +++ b/Fika.Core/UI/Custom/MatchMakerUIScript.cs @@ -3,11 +3,11 @@ using EFT.UI; using Fika.Core.Bundles; using Fika.Core.Coop.Matchmaker; +using Fika.Core.Networking; using Fika.Core.Networking.Http; using Fika.Core.Networking.Http.Models; using Fika.Core.UI.Models; using HarmonyLib; -using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; @@ -142,8 +142,48 @@ private void ManualRefresh() RefreshUI(); } - private void JoinMatch(string profileId, string serverId) + private IEnumerator JoinMatch(string profileId, string serverId, Button button) { + button.enabled = false; + + NotificationManagerClass.DisplayMessageNotification("Connecting to server...", iconType: EFT.Communications.ENotificationIconType.EntryPoint); + + FikaPingingClient pingingClient = new(serverId); + if (pingingClient.Init()) + { + int attempts = 0; + bool success = false; + + do + { + attempts++; + if (pingingClient.PingEndPoint()) + { + pingingClient.NetClient.PollEvents(); + success = pingingClient.Received; + } + yield return new WaitForSeconds(0.1f); + } while (!success && attempts < 50); + + if (!success) + { + Singleton.Instance.ShowCriticalErrorScreen( + "ERROR CONNECTING", + "Unable to connect to the server. Make sure that all ports are open and that all settings are configured correctly.", + ErrorScreen.EButtonType.OkButton, 10f, null, null); + + button.enabled = true; + yield break; + } + } + else + { + ConsoleScreen.Log("ERROR"); + } + + pingingClient.NetClient?.Stop(); + pingingClient = null; + if (MatchmakerAcceptPatches.JoinMatch(RaidSettings, profileId, serverId, out CreateMatch result, out string errorMessage)) { MatchmakerAcceptPatches.SetGroupId(result.ServerId); @@ -212,7 +252,7 @@ private void RefreshUI() } Singleton.Instance.PlayUISound(EUISoundType.ButtonClick); - JoinMatch(ProfileId, server.name); + StartCoroutine(JoinMatch(ProfileId, server.name, button)); }); TooltipTextGetter tooltipTextGetter; diff --git a/Fika.Core/UI/FikaUIUtils.cs b/Fika.Core/UI/FikaUIUtils.cs index 3a96d603..957870d9 100644 --- a/Fika.Core/UI/FikaUIUtils.cs +++ b/Fika.Core/UI/FikaUIUtils.cs @@ -10,22 +10,22 @@ internal class FikaUIUtils { public static TextMeshProUGUI CreateOverlayText(string overlayText) { - var obj = GameObject.Find("/Preloader UI/Preloader UI/Watermark"); - var labelObj = GameObject.Find("/Preloader UI/Preloader UI/Watermark/Label"); + GameObject obj = GameObject.Find("/Preloader UI/Preloader UI/Watermark"); + GameObject labelObj = GameObject.Find("/Preloader UI/Preloader UI/Watermark/Label"); if (labelObj != null) { Object.Destroy(labelObj); } - var watermarkText = obj.GetComponent(); + ClientWatermark watermarkText = obj.GetComponent(); if (watermarkText != null) { Object.Destroy(watermarkText); } obj.active = true; - var text = obj.AddComponent(); + TextMeshProUGUI text = obj.AddComponent(); text.horizontalAlignment = HorizontalAlignmentOptions.Center; text.verticalAlignment = VerticalAlignmentOptions.Bottom; text.margin = new Vector4(0, 0, 0, -350); diff --git a/Fika.Core/UI/Patches/ItemContextPatch.cs b/Fika.Core/UI/Patches/ItemContextPatch.cs index 53de2019..cc877167 100644 --- a/Fika.Core/UI/Patches/ItemContextPatch.cs +++ b/Fika.Core/UI/Patches/ItemContextPatch.cs @@ -7,7 +7,6 @@ using Fika.Core.Networking.Http; using Fika.Core.UI.Models; using HarmonyLib; -using Newtonsoft.Json; using System.Collections.Generic; using System.Linq; using System.Reflection;