diff --git a/Fika.Core/Console/FikaCommands.cs b/Fika.Core/Console/FikaCommands.cs index a0a85fdb..169ccf9b 100644 --- a/Fika.Core/Console/FikaCommands.cs +++ b/Fika.Core/Console/FikaCommands.cs @@ -6,6 +6,7 @@ using Fika.Core.Coop.GameMode; using Fika.Core.Coop.Players; using Fika.Core.Coop.Utils; +using System.Collections.Generic; namespace Fika.Core.Console { @@ -113,6 +114,36 @@ public static void Extract() coopGame.Extract(localPlayer, null); } + + [ConsoleCommand("despawnallai", "", null, "Despawns all AI Bots", [])] + public static void DespawnAllAI() + { + if (Singleton.Instance is CoopGame game) + { + if (!FikaBackendUtils.IsServer) + { + ConsoleScreen.LogWarning("You are not the host."); + return; + } + + CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler); + + List Bots = new List(game.BotsController.Players); + + foreach (Player bot in Bots) + { + if (bot.AIData.BotOwner == null) + { + continue; + } + + ConsoleScreen.Log($"Despawning: {bot.Profile.Nickname}"); + + game.DespawnBot(coopHandler, bot); + } + } + } + #endif [ConsoleCommand("debug", "", null, "Toggle debug window", [])] diff --git a/Fika.Core/Coop/Airdrops/FikaAirdropBox.cs b/Fika.Core/Coop/Airdrops/FikaAirdropBox.cs deleted file mode 100644 index 1be4574e..00000000 --- a/Fika.Core/Coop/Airdrops/FikaAirdropBox.cs +++ /dev/null @@ -1,260 +0,0 @@ -using Comfort.Common; -using EFT.Airdrop; -using EFT.Interactive; -using EFT.SynchronizableObjects; -using Fika.Core.Coop.Utils; -using System.Collections; -using System.Collections.Generic; -using System.Threading.Tasks; -using UnityEngine; -using UnityEngine.AI; - -namespace Fika.Core.Coop.Airdrops -{ - /// - /// Created by: SPT team - /// Link: https://dev.sp-tarkov.com/SPT/Modules/src/branch/master/project/SPT.Custom/Airdrops/AirdropBox.cs - /// - public class FikaAirdropBox : MonoBehaviour - { - private const string CRATE_PATH = "assets/content/location_objects/lootable/prefab/scontainer_crate.bundle"; - private const string AIRDROP_SOUNDS_PATH = "assets/content/audio/prefabs/airdrop/airdropsounds.bundle"; - private readonly int CROSSFADE = Shader.PropertyToID("_Crossfade"); - private readonly int COLLISION = Animator.StringToHash("collision"); - - public LootableContainer Container { get; set; } - private float fallSpeed; - private AirdropSynchronizableObject boxSync; - private AirdropLogicClass boxLogic; - private Material paraMaterial; - private Animator paraAnimator; - private AirdropSurfaceSet surfaceSet; - private Dictionary soundsDictionary; - private BetterSource audioSource; - - private BetterSource AudioSource - { - get - { - if (audioSource != null) return audioSource; - - audioSource = Singleton.Instance.GetSource(BetterAudio.AudioSourceGroupType.Environment, false); - audioSource.transform.parent = transform; - audioSource.transform.localPosition = Vector3.up; - - return audioSource; - } - } - - public static async Task Init(float crateFallSpeed) - { - FikaAirdropBox instance = (await LoadCrate()).AddComponent(); - instance.soundsDictionary = await LoadSounds(); - - instance.Container = instance.GetComponentInChildren(); - instance.Container.Id = "FikaAirdropContainer"; - - instance.boxSync = instance.GetComponent(); - instance.boxLogic = new AirdropLogicClass(); - instance.boxSync.SetLogic(instance.boxLogic); - - instance.paraAnimator = instance.boxSync.Parachute.GetComponent(); - instance.paraMaterial = instance.boxSync.Parachute.GetComponentInChildren().material; - instance.fallSpeed = crateFallSpeed; - return instance; - } - - private static async Task LoadCrate() - { - IEasyAssets easyAssets = Singleton.Instance.EasyAssets; - await easyAssets.Retain(CRATE_PATH, null, null).LoadingJob; - - GameObject crate = Instantiate(easyAssets.GetAsset(CRATE_PATH)); - crate.SetActive(false); - return crate; - } - - private static async Task> LoadSounds() - { - IEasyAssets easyAssets = Singleton.Instance.EasyAssets; - await easyAssets.Retain(AIRDROP_SOUNDS_PATH, null, null).LoadingJob; - - Dictionary soundsDictionary = new(); - AirdropSurfaceSet[] sets = easyAssets.GetAsset(AIRDROP_SOUNDS_PATH).Sets; - foreach (AirdropSurfaceSet set in sets) - { - if (!soundsDictionary.ContainsKey(set.Surface)) - { - soundsDictionary.Add(set.Surface, set); - } - else - { - Debug.LogError(set.Surface + " surface sounds are duplicated"); - } - } - - return soundsDictionary; - } - - public IEnumerator DropCrate(Vector3 position) - { - RaycastBoxDistance(LayerMaskClass.TerrainLowPoly, out RaycastHit hitInfo, position); - SetLandingSound(); - boxSync.Init(1, position, Vector3.zero); - PlayAudioClip(boxSync.SqueakClip, true); - - if (hitInfo.distance < 155f) - { - for (float i = 0; i < 1; i += Time.deltaTime / 6f) - { - transform.position = Vector3.Lerp(position, hitInfo.point, i * i); - yield return null; - } - - transform.position = hitInfo.point; - } - else - { - Vector3 parachuteOpenPos = position + new Vector3(0f, -148.2f, 0f); - for (float i = 0; i < 1; i += Time.deltaTime / 5.5f) - { - transform.position = Vector3.Lerp(position, parachuteOpenPos, i * i); - yield return null; - } - OpenParachute(); - while (RaycastBoxDistance(LayerMaskClass.TerrainLowPoly, out _)) - { - transform.Translate(Vector3.down * (Time.deltaTime * fallSpeed)); - transform.Rotate(Vector3.up, Time.deltaTime * 6f); - yield return null; - } - transform.position = hitInfo.point; - CloseParachute(); - } - - OnBoxLand(out float clipLength); - yield return new WaitForSecondsRealtime(clipLength + 0.5f); - ReleaseAudioSource(); - } - - private void OnBoxLand(out float clipLength) - { - AudioClip landingClip = surfaceSet.LandingSoundBank.PickSingleClip(surfaceSet.LandingSoundBank.GetRandomClipIndex(2)); - clipLength = landingClip.length; - boxSync.AirdropDust.SetActive(true); - boxSync.AirdropDust.GetComponent().Play(); - AudioSource.source1.Stop(); - PlayAudioClip(new TaggedClip - { - Clip = landingClip, - Falloff = (int)surfaceSet.LandingSoundBank.Rolloff, - Volume = surfaceSet.LandingSoundBank.BaseVolume - }); - - if (FikaBackendUtils.IsServer) - { - AddNavMeshObstacle(); - } - } - - private void AddNavMeshObstacle() - { - NavMeshObstacle navMeshObstacle = this.GetOrAddComponent(); - navMeshObstacle.size = boxSync.CollisionCollider.bounds.size; - navMeshObstacle.carving = true; - } - - private bool RaycastBoxDistance(LayerMask layerMask, out RaycastHit hitInfo) - { - return RaycastBoxDistance(layerMask, out hitInfo, transform.position); - } - - private bool RaycastBoxDistance(LayerMask layerMask, out RaycastHit hitInfo, Vector3 origin) - { - Ray ray = new(origin, Vector3.down); - - bool raycast = Physics.Raycast(ray, out hitInfo, Mathf.Infinity, layerMask); - if (!raycast) return false; - - return hitInfo.distance > 0.05f; - } - - private void SetLandingSound() - { - if (!RaycastBoxDistance(LayerMaskClass.AudioControllerStepLayerMask, out RaycastHit raycast)) - { - Debug.LogError("Raycast to ground returns no hit. Choose Concrete sound landing set"); - surfaceSet = soundsDictionary[BaseBallistic.ESurfaceSound.Concrete]; - } - else - { - if (raycast.collider.TryGetComponent(out BaseBallistic component)) - { - BaseBallistic.ESurfaceSound surfaceSound = component.GetSurfaceSound(raycast.point); - if (soundsDictionary.ContainsKey(surfaceSound)) - { - surfaceSet = soundsDictionary[surfaceSound]; - return; - } - } - - surfaceSet = soundsDictionary[BaseBallistic.ESurfaceSound.Concrete]; - } - } - - private void PlayAudioClip(TaggedClip clip, bool looped = false) - { - float volume = clip.Volume; - UnityEngine.Audio.AudioMixerGroup occlusionGroupSimple = Singleton.Instance.GetOcclusionGroupSimple(transform.position, ref volume); - AudioSource.gameObject.SetActive(true); - AudioSource.source1.outputAudioMixerGroup = occlusionGroupSimple; - AudioSource.source1.spatialBlend = 1f; - AudioSource.SetRolloff(clip.Falloff); - AudioSource.source1.volume = volume; - - if (AudioSource.source1.isPlaying) return; - - AudioSource.source1.clip = clip.Clip; - AudioSource.source1.loop = looped; - AudioSource.source1.Play(); - } - - private void OpenParachute() - { - boxSync.Parachute.SetActive(true); - paraAnimator.SetBool(COLLISION, false); - StartCoroutine(CrossFadeAnimation(1f)); - } - - private void CloseParachute() - { - paraAnimator.SetBool(COLLISION, true); - StartCoroutine(CrossFadeAnimation(0f)); - } - - private IEnumerator CrossFadeAnimation(float targetFadeValue) - { - float curFadeValue = paraMaterial.GetFloat(CROSSFADE); - for (float i = 0; i < 1; i += Time.deltaTime / 2f) - { - paraMaterial.SetFloat(CROSSFADE, Mathf.Lerp(curFadeValue, targetFadeValue, i * i)); - yield return null; - } - paraMaterial.SetFloat(CROSSFADE, targetFadeValue); - - if (targetFadeValue == 0f) - { - boxSync.Parachute.SetActive(false); - } - } - - private void ReleaseAudioSource() - { - if (audioSource == null) return; - - audioSource.transform.parent = null; - audioSource.Release(); - audioSource = null; - } - } -} \ No newline at end of file diff --git a/Fika.Core/Coop/Airdrops/FikaAirdropsManager.cs b/Fika.Core/Coop/Airdrops/FikaAirdropsManager.cs index 596b3fc7..62075618 100644 --- a/Fika.Core/Coop/Airdrops/FikaAirdropsManager.cs +++ b/Fika.Core/Coop/Airdrops/FikaAirdropsManager.cs @@ -11,6 +11,7 @@ using Fika.Core.Networking; using LiteNetLib; using LiteNetLib.Utils; +using SPT.Custom.Airdrops; using System; using System.Collections; using UnityEngine; @@ -25,7 +26,7 @@ namespace Coop.Airdrops public class FikaAirdropsManager : MonoBehaviour { private FikaAirdropPlane airdropPlane; - private FikaAirdropBox AirdropBox; + private AirdropBox AirdropBox; private FikaItemFactoryUtil factory; public bool isFlareDrop; public FikaAirdropParametersModel AirdropParameters { get; set; } @@ -111,7 +112,7 @@ protected async void Start() airdropPlane = await FikaAirdropPlane.Init(AirdropParameters.RandomAirdropPoint, AirdropParameters.DropHeight, AirdropParameters.Config.PlaneVolume, AirdropParameters.Config.PlaneSpeed); - AirdropBox = await FikaAirdropBox.Init(AirdropParameters.Config.CrateFallSpeed); + AirdropBox = await AirdropBox.Init(AirdropParameters.Config.CrateFallSpeed); factory = new FikaItemFactoryUtil(); } catch @@ -177,18 +178,18 @@ protected async void FixedUpdate() airdropPlane = await FikaAirdropPlane.Init(AirdropParameters.SpawnPoint, AirdropParameters.DropHeight, AirdropParameters.Config.PlaneVolume, AirdropParameters.Config.PlaneSpeed, true, AirdropParameters.LookPoint); - AirdropBox = await FikaAirdropBox.Init(AirdropParameters.Config.CrateFallSpeed); + AirdropBox = await AirdropBox.Init(AirdropParameters.Config.CrateFallSpeed); factory = new FikaItemFactoryUtil(); - factory.BuildClientContainer(AirdropBox.Container, rootItem); + factory.BuildClientContainer(AirdropBox.container, rootItem); - if (AirdropBox.Container != null && CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler)) + if (AirdropBox.container != null && CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler)) { if (!string.IsNullOrEmpty(ContainerId)) { - AirdropBox.Container.Id = ContainerId; - coopHandler.ListOfInteractiveObjects.Add(ContainerId, AirdropBox.Container); - Logger.LogInfo($"Adding AirdropBox {AirdropBox.Container.Id} to interactive objects."); + AirdropBox.container.Id = ContainerId; + coopHandler.ListOfInteractiveObjects.Add(ContainerId, AirdropBox.container); + Logger.LogInfo($"Adding AirdropBox {AirdropBox.container.Id} to interactive objects."); } else { @@ -281,19 +282,19 @@ private void BuildLootContainer(FikaAirdropConfigModel config) throw new Exception("Airdrops. Tried to BuildLootContainer without any Loot."); } - factory.BuildContainer(AirdropBox.Container, config, lootData.DropType); - factory.AddLoot(AirdropBox.Container, lootData); + factory.BuildContainer(AirdropBox.container, config, lootData.DropType); + factory.AddLoot(AirdropBox.container, lootData); - if (AirdropBox.Container != null && CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler)) + if (AirdropBox.container != null && CoopHandler.TryGetCoopHandler(out CoopHandler coopHandler)) { - if (coopHandler.GetInteractiveObject(AirdropBox.Container.Id, out _)) + if (coopHandler.GetInteractiveObject(AirdropBox.container.Id, out _)) { Logger.LogInfo("Existing crate already exists, setting value to " + ContainerCount); - AirdropBox.Container.Id = AirdropBox.Container.Id + $"_{ContainerCount}"; + AirdropBox.container.Id = AirdropBox.container.Id + $"_{ContainerCount}"; ContainerCount++; } - coopHandler.ListOfInteractiveObjects.Add(AirdropBox.Container.Id, AirdropBox.Container); - Logger.LogInfo($"Adding AirdropBox {AirdropBox.Container.Id} to interactive objects."); + coopHandler.ListOfInteractiveObjects.Add(AirdropBox.container.Id, AirdropBox.container); + Logger.LogInfo($"Adding AirdropBox {AirdropBox.container.Id} to interactive objects."); } // Get the lootData. Send to clients. @@ -343,12 +344,12 @@ private IEnumerator SendLootToClients(bool isFlare = false) Logger.LogInfo("Sending Airdrop Loot to clients."); - Item rootItem = AirdropBox.Container.ItemOwner.RootItem; + Item rootItem = AirdropBox.container.ItemOwner.RootItem; AirdropLootPacket lootPacket = new() { RootItem = rootItem, - ContainerId = AirdropBox.Container.Id + ContainerId = AirdropBox.container.Id }; NetDataWriter writer = new(); diff --git a/Fika.Core/Coop/BTR/FikaBTRManager_Client.cs b/Fika.Core/Coop/BTR/FikaBTRManager_Client.cs index a3db1287..9a543e1b 100644 --- a/Fika.Core/Coop/BTR/FikaBTRManager_Client.cs +++ b/Fika.Core/Coop/BTR/FikaBTRManager_Client.cs @@ -40,7 +40,9 @@ internal class FikaBTRManager_Client : MonoBehaviour private BTRVehicle btrServerSide; public BTRView btrClientSide; private BTRDataPacket btrDataPacket = default; +#pragma warning disable CS0414 // The field 'FikaBTRManager_Client.btrInitialized' is assigned but its value is never used private bool btrInitialized = false; +#pragma warning restore CS0414 // The field 'FikaBTRManager_Client.btrInitialized' is assigned but its value is never used private bool btrBotShooterInitialized = false; private BTRTurretServer btrTurretServer; diff --git a/Fika.Core/Coop/BTR/FikaBTRManager_Host.cs b/Fika.Core/Coop/BTR/FikaBTRManager_Host.cs index fa9dfa96..0cc810f4 100644 --- a/Fika.Core/Coop/BTR/FikaBTRManager_Host.cs +++ b/Fika.Core/Coop/BTR/FikaBTRManager_Host.cs @@ -40,7 +40,9 @@ internal class FikaBTRManager_Host : MonoBehaviour private BTRView btrClientSide; private BotOwner btrBotShooter; private BTRDataPacket btrDataPacket = default; +#pragma warning disable CS0414 // The field 'FikaBTRManager_Host.btrInitialized' is assigned but its value is never used private bool btrInitialized = false; +#pragma warning restore CS0414 // The field 'FikaBTRManager_Host.btrInitialized' is assigned but its value is never used private bool btrBotShooterInitialized = false; private float coverFireTime = 90f; diff --git a/Fika.Core/Coop/ClientClasses/CoopClientSharedQuestController.cs b/Fika.Core/Coop/ClientClasses/CoopClientSharedQuestController.cs index 56380e36..eca329ce 100644 --- a/Fika.Core/Coop/ClientClasses/CoopClientSharedQuestController.cs +++ b/Fika.Core/Coop/ClientClasses/CoopClientSharedQuestController.cs @@ -3,6 +3,7 @@ using EFT.Quests; using Fika.Core.Coop.Players; using Fika.Core.Networking.Packets; +using SPT.Custom.BTR.Patches; using System; using System.Collections.Generic; @@ -15,6 +16,7 @@ public sealed class CoopClientSharedQuestController(Profile profile, InventoryCo private readonly List lastFromNetwork = []; private readonly HashSet acceptedTypes = []; private readonly HashSet lootedTemplateIds = []; + private bool canSendAndReceive = true; public override void Init() { @@ -49,6 +51,12 @@ public override void Init() public override void OnConditionValueChanged(IConditionCounter conditional, EQuestStatus status, Condition condition, bool notify = true) { base.OnConditionValueChanged(conditional, status, condition, notify); + + if (!canSendAndReceive) + { + return; + } + if (lastFromNetwork.Contains(condition.id)) { lastFromNetwork.Remove(condition.id); @@ -78,6 +86,11 @@ public bool CheckForTemplateId(string templateId) return lootedTemplateIds.Contains(templateId); } + public void ToggleQuestSharing(bool state) + { + canSendAndReceive = state; + } + private void SendQuestPacket(IConditionCounter conditional, Condition condition) { if (conditional is QuestClass quest) @@ -101,6 +114,11 @@ private void SendQuestPacket(IConditionCounter conditional, Condition condition) internal void ReceiveQuestPacket(ref QuestConditionPacket packet) { + if (!canSendAndReceive) + { + return; + } + AddNetworkId(packet.Id); foreach (QuestClass quest in Quests) { @@ -115,8 +133,11 @@ internal void ReceiveQuestPacket(ref QuestConditionPacket packet) } counter.Value++; - NotificationManagerClass.DisplayMessageNotification($"Received shared quest progression from {packet.Nickname}", - iconType: EFT.Communications.ENotificationIconType.Quest); + if (FikaPlugin.QuestSharingNotifications.Value) + { + NotificationManagerClass.DisplayMessageNotification($"Received shared quest progression from {packet.Nickname}", + iconType: EFT.Communications.ENotificationIconType.Quest); + } } } } @@ -124,6 +145,11 @@ internal void ReceiveQuestPacket(ref QuestConditionPacket packet) internal void ReceiveQuestItemPacket(ref QuestItemPacket packet) { + if (!canSendAndReceive) + { + return; + } + if (!string.IsNullOrEmpty(packet.ItemId)) { Item item = player.FindItem(packet.ItemId, true); @@ -138,8 +164,11 @@ internal void ReceiveQuestItemPacket(ref QuestItemPacket packet) { AddLootedTemplateId(item.TemplateId); playerInventory.RunNetworkTransaction(pickupResult.Value); - NotificationManagerClass.DisplayMessageNotification($"{packet.Nickname} picked up {item.Name.Localized()}", - iconType: EFT.Communications.ENotificationIconType.Quest); + if (FikaPlugin.QuestSharingNotifications.Value) + { + NotificationManagerClass.DisplayMessageNotification($"{packet.Nickname} picked up {item.Name.Localized()}", + iconType: EFT.Communications.ENotificationIconType.Quest); + } } } } diff --git a/Fika.Core/Coop/ClientClasses/NoInertiaMovementContext.cs b/Fika.Core/Coop/ClientClasses/NoInertiaMovementContext.cs new file mode 100644 index 00000000..0d39124d --- /dev/null +++ b/Fika.Core/Coop/ClientClasses/NoInertiaMovementContext.cs @@ -0,0 +1,57 @@ +using Comfort.Common; +using EFT; +using System; +using UnityEngine; + +namespace Fika.Core.Coop.ClientClasses +{ + /// + /// Used to simulate having near no inertia + /// + public class NoInertiaMovementContext : MovementContext + { + public new static NoInertiaMovementContext Create(Player player, Func animatorGetter, Func characterControllerGetter, LayerMask groundMask) + { + NoInertiaMovementContext movementContext = Create(player, animatorGetter, characterControllerGetter, groundMask); + return movementContext; + } + + public override void Init() + { + base.Init(); + TiltInertia = 0.22f; + WalkInertia = 0.005f; + SprintBrakeInertia = 0f; + } + + public override void WeightRelatedValuesUpdated() + { + if (_player.ProceduralWeaponAnimation != null) + { + _player.ProceduralWeaponAnimation.Overweight = _player.Physical.Overweight; + _player.ProceduralWeaponAnimation.UpdateSwayFactors(); + _player.ProceduralWeaponAnimation.UpdateSwaySettings(); + _player.ProceduralWeaponAnimation.WeaponFlipSpeed = InertiaSettings.WeaponFlipSpeed.Evaluate(_player.Physical.Inertia); + } + UpdateCovertEfficiency(_player.MovementContext.ClampedSpeed, true); + _player.UpdateStepSoundRolloff(); + _player.HealthController.FallSafeHeight = Mathf.Lerp(Singleton.Instance.Health.Falling.SafeHeight, Singleton.Instance.Stamina.SafeHeightOverweight, _player.Physical.Overweight); + PlayerAnimatorTransitionSpeed = TransitionSpeed; + if (PoseLevel > _player.Physical.MaxPoseLevel && CurrentState is MovementState movementState) + { + movementState.ChangePose(_player.Physical.MaxPoseLevel - PoseLevel); + } + if (_player.PoseMemo > _player.Physical.MaxPoseLevel) + { + _player.PoseMemo = _player.Physical.MaxPoseLevel; + } + float walkSpeedLimit = _player.Physical.WalkSpeedLimit; + RemoveStateSpeedLimit(Player.ESpeedLimit.Weight); + if (walkSpeedLimit < 1f) + { + AddStateSpeedLimit(walkSpeedLimit * MaxSpeed, Player.ESpeedLimit.Weight); + } + UpdateCharacterControllerSpeedLimit(); + } + } +} diff --git a/Fika.Core/Coop/ClientClasses/NoInertiaPhysical.cs b/Fika.Core/Coop/ClientClasses/NoInertiaPhysical.cs index 6b0d1792..41718af3 100644 --- a/Fika.Core/Coop/ClientClasses/NoInertiaPhysical.cs +++ b/Fika.Core/Coop/ClientClasses/NoInertiaPhysical.cs @@ -5,6 +5,9 @@ namespace Fika.Core.Coop.ClientClasses { + /// + /// Currently unused + /// public class NoInertiaPhysical : PlayerPhysicalClass { private CoopPlayer coopPlayer; diff --git a/Fika.Core/Coop/Components/CoopHandler.cs b/Fika.Core/Coop/Components/CoopHandler.cs index 83061f09..71fcbfdf 100644 --- a/Fika.Core/Coop/Components/CoopHandler.cs +++ b/Fika.Core/Coop/Components/CoopHandler.cs @@ -3,6 +3,7 @@ using EFT; using EFT.Interactive; using EFT.InventoryLogic; +using EFT.UI; using Fika.Core.Coop.BTR; using Fika.Core.Coop.GameMode; using Fika.Core.Coop.Players; @@ -196,6 +197,10 @@ void ProcessQuitting() if (FikaPlugin.ExtractKey.Value.IsDown() && quitState != EQuitState.NONE && !requestQuitGame) { + //Log to both the in-game console as well as into the BepInEx logfile + ConsoleScreen.Log($"{FikaPlugin.ExtractKey.Value} pressed, attempting to extract!"); + Logger.LogInfo($"{FikaPlugin.ExtractKey.Value} pressed, attempting to extract!"); + requestQuitGame = true; CoopGame coopGame = (CoopGame)Singleton.Instance; diff --git a/Fika.Core/Coop/Custom/FikaDynamicAI.cs b/Fika.Core/Coop/Custom/FikaDynamicAI.cs index 4eafb7a4..3a917ff1 100644 --- a/Fika.Core/Coop/Custom/FikaDynamicAI.cs +++ b/Fika.Core/Coop/Custom/FikaDynamicAI.cs @@ -77,6 +77,14 @@ private void Spawner_OnBotCreated(BotOwner botOwner) return; } + if (FikaPlugin.DynamicAIIgnoreSnipers.Value) + { + if (botOwner.IsRole(WildSpawnType.marksman)) + { + return; + } + } + bots.Add((CoopBot)botOwner.GetPlayer); } diff --git a/Fika.Core/Coop/GameMode/CoopGame.cs b/Fika.Core/Coop/GameMode/CoopGame.cs index f4c0b6fb..e7bfb30e 100644 --- a/Fika.Core/Coop/GameMode/CoopGame.cs +++ b/Fika.Core/Coop/GameMode/CoopGame.cs @@ -55,7 +55,6 @@ namespace Fika.Core.Coop.GameMode public sealed class CoopGame : BaseLocalGame, IBotGame, IFikaGame { public string InfiltrationPoint; - public bool HasAddedFenceRep = false; public ExitStatus MyExitStatus { get; set; } = ExitStatus.Survived; public string MyExitLocation { get; set; } = null; public ISpawnSystem SpawnSystem; @@ -641,9 +640,8 @@ private bool TryDespawnFurthestBot(Profile profile, Vector3 position, CoopHandle /// /// /// The bot to despawn - private void DespawnBot(CoopHandler coopHandler, Player bot) + internal void DespawnBot(CoopHandler coopHandler, Player bot) { - IBotGame botGame = Singleton.Instance; BotOwner botOwner = bot.AIData.BotOwner; BotsController.Bots.Remove(botOwner); @@ -665,6 +663,29 @@ private void DespawnBot(CoopHandler coopHandler, Player bot) /// public override IEnumerator vmethod_1() { + if (!isServer) + { + FikaBackendUtils.ScreenController.ChangeStatus("Waiting for host to finish raid initialization..."); + + FikaClient fikaClient = Singleton.Instance; + do + { + yield return new WaitForEndOfFrame(); + } while (!fikaClient.HostReady); + } + else + { + FikaServer fikaServer = Singleton.Instance; + InformationPacket packet = new(false) + { + NumberOfPlayers = fikaServer.NetServer.ConnectedPeersCount, + ReadyPlayers = fikaServer.ReadyClients, + HostReady = true + }; + + fikaServer.SendDataToAll(new(), ref packet, LiteNetLib.DeliveryMethod.ReliableUnordered); + } + CoopPlayer coopPlayer = (CoopPlayer)PlayerOwner.Player; coopPlayer.PacketSender.Init(); @@ -707,9 +728,8 @@ private IEnumerator WaitForOtherPlayers() NetDataWriter writer = new(); - FikaBackendUtils.ScreenController.ChangeStatus("Waiting for other players to finish loading..."); - - int expectedPlayers = FikaBackendUtils.HostExpectedNumberOfPlayers; + float expectedPlayers = FikaBackendUtils.HostExpectedNumberOfPlayers; + FikaBackendUtils.ScreenController.ChangeStatus("Waiting for other players to finish loading...", (float)(1 / expectedPlayers)); if (isServer) { @@ -738,7 +758,7 @@ private IEnumerator WaitForOtherPlayers() do { - FikaBackendUtils.ScreenController.ChangeStatus("Waiting for other players to finish loading...", server.ReadyClients / expectedPlayers); + FikaBackendUtils.ScreenController.ChangeStatus("Waiting for other players to finish loading...", (float)server.ReadyClients / expectedPlayers); yield return new WaitForEndOfFrame(); } while (server.ReadyClients < expectedPlayers); @@ -772,7 +792,7 @@ private IEnumerator WaitForOtherPlayers() do { - FikaBackendUtils.ScreenController.ChangeStatus("Waiting for other players to finish loading...", client.ReadyClients / expectedPlayers); + FikaBackendUtils.ScreenController.ChangeStatus("Waiting for other players to finish loading...", (float)client.ReadyClients / expectedPlayers); yield return new WaitForEndOfFrame(); } while (client.ReadyClients < expectedPlayers); } @@ -930,6 +950,11 @@ public override async Task vmethod_2(int playerId, Vector3 position /// private GameObject CreateCancelButton(LocalPlayer myPlayer, CoopPlayer coopPlayer, GameObject customButton) { + if (myPlayer.Side is EPlayerSide.Savage) + { + return null; + } + if (MenuUI.Instantiated) { MenuUI menuUI = MenuUI.Instance; @@ -1219,10 +1244,10 @@ public override IEnumerator vmethod_4(BotControllerSettings controllerSettings, GClass814 botCreator = new(this, botsPresets, CreateBot); BotZone[] botZones = LocationScene.GetAllObjects(false).ToArray(); - bool enableWaves = controllerSettings.BotAmount == EBotAmount.Horde; + bool useWaveControl = controllerSettings.BotAmount == EBotAmount.Horde; botsController_0.Init(this, botCreator, botZones, spawnSystem, wavesSpawnScenario_0.BotLocationModifier, - controllerSettings.IsEnabled, controllerSettings.IsScavWars, enableWaves, false, + controllerSettings.IsEnabled, controllerSettings.IsScavWars, useWaveControl, false, BossSpawnWaveManagerClass.HaveSectants, Singleton.Instance, Location_0.OpenZones); Logger.LogInfo($"Location: {Location_0.Name}"); @@ -1354,6 +1379,8 @@ public override IEnumerator vmethod_4(BotControllerSettings controllerSettings, Singleton.Instance.TimeBeforeDeployLocal = Math.Max(Singleton.Instance.TimeBeforeDeployLocal, 5); + FikaBackendUtils.ScreenController.ChangeStatus("Finishing raid initialization..."); + yield return base.vmethod_4(controllerSettings, spawnSystem, runCallback); yield break; } @@ -1474,6 +1501,8 @@ private void OnMineExplode(MineDirectional directional) /// public override void vmethod_5() { + + GameTimer.Start(null, null); gparam_0.Player.HealthController.DiedEvent += HealthController_DiedEvent; gparam_0.vmethod_0(); @@ -1580,6 +1609,11 @@ public void Extract(CoopPlayer player, ExfiltrationPoint point) NotificationManagerClass.DisplayMessageNotification("You have gone missing in action...", iconType: EFT.Communications.ENotificationIconType.Alert, textColor: Color.red); } + if (player.AbstractQuestControllerClass is CoopClientSharedQuestController sharedQuestController) + { + sharedQuestController.ToggleQuestSharing(false); + } + BackendConfigSettingsClass.GClass1361.GClass1367 matchEndConfig = Singleton.Instance.Experience.MatchEnd; if (player.Profile.EftStats.SessionCounters.GetAllInt([CounterTag.Exp]) < matchEndConfig.SurvivedExpRequirement && PastTime < matchEndConfig.SurvivedTimeRequirement) { @@ -1592,10 +1626,10 @@ public void Extract(CoopPlayer player, ExfiltrationPoint point) if (point.HasRequirements && point.TransferItemRequirement != null) { - if (point.TransferItemRequirement.Met(player, point) && player.IsYourPlayer && !HasAddedFenceRep) + if (point.TransferItemRequirement.Met(player, point) && player.IsYourPlayer) { + // Seems to already be handled by SPT so we only add it visibly player.Profile.EftStats.SessionCounters.AddDouble(0.2, [CounterTag.FenceStanding, EFenceStandingSource.ExitStanding]); - HasAddedFenceRep = true; } } } @@ -1604,7 +1638,6 @@ public void Extract(CoopPlayer player, ExfiltrationPoint point) { // Seems to already be handled by SPT so we only add it visibly player.Profile.EftStats.SessionCounters.AddDouble(0.01, [CounterTag.FenceStanding, EFenceStandingSource.ExitStanding]); - //player.Profile.FenceInfo.AddStanding(0.1, EFenceStandingSource.ExitStanding); } GenericPacket genericPacket = new() diff --git a/Fika.Core/Coop/Patches/Airdrop/AirdropBox_Patch.cs b/Fika.Core/Coop/Patches/Airdrop/AirdropBox_Patch.cs new file mode 100644 index 00000000..7307babd --- /dev/null +++ b/Fika.Core/Coop/Patches/Airdrop/AirdropBox_Patch.cs @@ -0,0 +1,26 @@ +using Fika.Core.Coop.Utils; +using HarmonyLib; +using SPT.Custom.Airdrops; +using SPT.Reflection.Patching; +using System.Reflection; + +namespace Fika.Core.Coop.Patches.Airdrop +{ + public class AirdropBox_Patch : ModulePatch + { + protected override MethodBase GetTargetMethod() => AccessTools.Method(typeof(AirdropBox), "AddNavMeshObstacle"); + + [PatchPrefix] + public static bool PatchPrefix(AirdropBox __instance) + { + //Allow method to go through + if(FikaBackendUtils.IsServer) + { + return true; + } + + //Stop running method. + return false; + } + } +} diff --git a/Fika.Core/Coop/Patches/LocalGame/TarkovApplication_LocalGameCreator_Patch.cs b/Fika.Core/Coop/Patches/LocalGame/TarkovApplication_LocalGameCreator_Patch.cs index 4756e10d..54b844a1 100644 --- a/Fika.Core/Coop/Patches/LocalGame/TarkovApplication_LocalGameCreator_Patch.cs +++ b/Fika.Core/Coop/Patches/LocalGame/TarkovApplication_LocalGameCreator_Patch.cs @@ -25,8 +25,6 @@ internal class TarkovApplication_LocalGameCreator_Patch : ModulePatch { protected override MethodBase GetTargetMethod() => typeof(TarkovApplication).GetMethod(nameof(TarkovApplication.method_47)); - static ISession CurrentSession { get; set; } - [PatchPrefix] public static bool Prefix(TarkovApplication __instance) { @@ -37,15 +35,6 @@ public static bool Prefix(TarkovApplication __instance) return true; } - ISession session = __instance.GetClientBackEndSession(); - if (session == null) - { - Logger.LogError("Session is NULL. Continuing as Single-player."); - return true; - } - - CurrentSession = session; - return false; } @@ -58,11 +47,6 @@ public static async Task Postfix(Task __result, TarkovApplication __instance, Ti return; } - if (CurrentSession == null) - { - return; - } - if (____raidSettings == null) { Logger.LogError("RaidSettings is Null"); @@ -92,7 +76,12 @@ public static async Task Postfix(Task __result, TarkovApplication __instance, Ti NetManagerUtils.StartPinger(); } - ISession session = CurrentSession; + ISession session = __instance.GetClientBackEndSession(); + + if (session == null) + { + throw new NullReferenceException("Backend session was null when initializing game!"); + } Profile profile = session.GetProfileBySide(____raidSettings.Side); diff --git a/Fika.Core/Coop/Players/CoopBot.cs b/Fika.Core/Coop/Players/CoopBot.cs index ae914c58..5afc3376 100644 --- a/Fika.Core/Coop/Players/CoopBot.cs +++ b/Fika.Core/Coop/Players/CoopBot.cs @@ -182,7 +182,7 @@ public override void OnDead(EDamageType damageType) } } - if (Side == EPlayerSide.Savage) + /*if (Side == EPlayerSide.Savage) { if (LastAggressor != null) { @@ -213,7 +213,7 @@ public override void OnDead(EDamageType damageType) } } } - } + }*/ CoopGame coopGame = (CoopGame)Singleton.Instance; if (coopGame.Bots.ContainsKey(ProfileId)) diff --git a/Fika.Core/Coop/Players/CoopPlayer.cs b/Fika.Core/Coop/Players/CoopPlayer.cs index e1d2414c..d6d4fe23 100644 --- a/Fika.Core/Coop/Players/CoopPlayer.cs +++ b/Fika.Core/Coop/Players/CoopPlayer.cs @@ -39,7 +39,8 @@ public class CoopPlayer : LocalPlayer public PacketReceiver PacketReceiver; public IPacketSender PacketSender; private DateTime lastPingTime; - public bool hasKilledScav = false; + public bool hasSkilledScav = false; + //public bool hasKilledScav = false; public float observedOverlap = 0f; public bool leftStanceDisabled = false; public Vector2 LastDirection = Vector2.zero; @@ -118,16 +119,29 @@ await player.Init(rotation, layerName, pointOfView, profile, inventoryController return player; } - public override BasePhysicalClass CreatePhysical() + /*public override BasePhysicalClass CreatePhysical() { return FikaPlugin.Instance.UseInertia ? new PlayerPhysicalClass() : new NoInertiaPhysical(); + }*/ + + public override void CreateMovementContext() + { + LayerMask movement_MASK = EFTHardSettings.Instance.MOVEMENT_MASK; + if (FikaPlugin.Instance.UseInertia) + { + MovementContext = MovementContext.Create(this, new Func(GetBodyAnimatorCommon), + new Func(GetCharacterControllerCommon), movement_MASK); + } + else + { + MovementContext = NoInertiaMovementContext.Create(this, new Func(GetBodyAnimatorCommon), + new Func(GetCharacterControllerCommon), movement_MASK); + } } public override void OnSkillLevelChanged(GClass1778 skill) { - NotificationManagerClass.DisplayMessageNotification(string.Format("SkillLevelUpMessage".Localized(null), - skill.Id.ToString().Localized(null), - skill.Level.ToString()), ENotificationDurationType.Default, ENotificationIconType.Default, null); + NotificationManagerClass.DisplayNotification(new GClass2044(skill)); } public override bool CheckSurface() @@ -280,6 +294,7 @@ private ShotInfoClass SimulatedApplyShot(DamageInfo damageInfo, EBodyPart bodyPa return gclass; } + #region Proceed public override void Proceed(bool withNetwork, Callback callback, bool scheduled = true) { base.Proceed(withNetwork, callback, scheduled); @@ -383,7 +398,8 @@ public override void Proceed(Item item, Callback callback, boo { // what is this base.Proceed(item, callback, scheduled); - } + } + #endregion public override void DropCurrentController(Action callback, bool fastDrop, Item nextControllerItem = null) { @@ -400,6 +416,41 @@ public override void DropCurrentController(Action callback, bool fastDrop, Item });*/ } + public override void OnBeenKilledByAggressor(IPlayer aggressor, DamageInfo damageInfo, EBodyPart bodyPart, EDamageType lethalDamageType) + { + base.OnBeenKilledByAggressor(aggressor, damageInfo, bodyPart, lethalDamageType); + + // Handle 'Help Scav' rep gains + if (aggressor is CoopPlayer coopPlayer) + { + if (coopPlayer.Side == EPlayerSide.Savage) + { + coopPlayer.Loyalty.method_1(this); + } + + if (Side == EPlayerSide.Savage && coopPlayer.Side != EPlayerSide.Savage && !coopPlayer.hasSkilledScav) + { + coopPlayer.hasSkilledScav = true; + return; + } + else if (Side != EPlayerSide.Savage && hasSkilledScav && aggressor.Side == EPlayerSide.Savage) + { + coopPlayer.Profile?.FenceInfo?.AddStanding(Profile.Info.Settings.StandingForKill, EFT.Counters.EFenceStandingSource.ScavHelp); + } + } + } + +#if DEBUG + public override void ShowStringNotification(string message) + { + if (IsYourPlayer) + { + ConsoleScreen.Log(message); + FikaPlugin.Instance.FikaLogger.LogInfo(message); + } + } +#endif + public override void SetInventoryOpened(bool opened) { if (this is ObservedCoopPlayer) diff --git a/Fika.Core/Coop/Players/ObservedCoopPlayer.cs b/Fika.Core/Coop/Players/ObservedCoopPlayer.cs index 1e6cde64..55b8b152 100644 --- a/Fika.Core/Coop/Players/ObservedCoopPlayer.cs +++ b/Fika.Core/Coop/Players/ObservedCoopPlayer.cs @@ -662,7 +662,7 @@ public override void OnDead(EDamageType damageType) } } - if (Side == EPlayerSide.Savage) + /*if (Side == EPlayerSide.Savage) { if (LastAggressor != null) { @@ -693,7 +693,7 @@ public override void OnDead(EDamageType damageType) } } } - } + }*/ Singleton.Instance.ProtagonistHearingChanged -= SetSoundRollOff; /*if (FikaPlugin.CullPlayers.Value) diff --git a/Fika.Core/Coop/Utils/FikaBackendUtils.cs b/Fika.Core/Coop/Utils/FikaBackendUtils.cs index 61cb69b8..42d181dc 100644 --- a/Fika.Core/Coop/Utils/FikaBackendUtils.cs +++ b/Fika.Core/Coop/Utils/FikaBackendUtils.cs @@ -1,5 +1,7 @@ -using EFT; +using Comfort.Common; +using EFT; using EFT.UI.Matchmaker; +using Fika.Core.Networking; using Fika.Core.Networking.Http; using Fika.Core.Networking.Http.Models; using System; @@ -22,7 +24,15 @@ public static class FikaBackendUtils public static EMatchmakerType MatchingType = EMatchmakerType.Single; public static bool IsServer => MatchingType == EMatchmakerType.GroupLeader; public static bool IsClient => MatchingType == EMatchmakerType.GroupPlayer; - public static bool IsSinglePlayer => MatchingType == EMatchmakerType.Single; + public static bool IsSinglePlayer + { + get + { + return Singleton.Instantiated + && Singleton.Instance.NetServer.ConnectedPeersCount == 0; + } + } + public static bool IsDedicated = false; public static PlayersRaidReadyPanel PlayersRaidReadyPanel; public static MatchMakerGroupPreview MatchMakerGroupPreview; public static int HostExpectedNumberOfPlayers = 1; diff --git a/Fika.Core/FikaPlugin.cs b/Fika.Core/FikaPlugin.cs index aafb8e5c..46ff0054 100644 --- a/Fika.Core/FikaPlugin.cs +++ b/Fika.Core/FikaPlugin.cs @@ -99,9 +99,10 @@ public class FikaPlugin : BaseUnityPlugin public static ConfigEntry ShowNotifications { get; set; } public static ConfigEntry AutoExtract { get; set; } public static ConfigEntry ShowExtractMessage { get; set; } - public static ConfigEntry FasterInventoryScroll { get; set; } - public static ConfigEntry FasterInventoryScrollSpeed { get; set; } + //public static ConfigEntry FasterInventoryScroll { get; set; } + //public static ConfigEntry FasterInventoryScrollSpeed { get; set; } public static ConfigEntry ExtractKey { get; set; } + public static ConfigEntry EnableChat { get; set; } public static ConfigEntry ChatKey { get; set; } // Coop | Name Plates @@ -120,6 +121,7 @@ public class FikaPlugin : BaseUnityPlugin // Coop | Quest Sharing public static ConfigEntry QuestTypesToShareAndReceive { get; set; } + public static ConfigEntry QuestSharingNotifications { get; set; } // Coop | Custom public static ConfigEntry UsePingSystem { get; set; } @@ -142,6 +144,7 @@ public class FikaPlugin : BaseUnityPlugin public static ConfigEntry DynamicAI { get; set; } public static ConfigEntry DynamicAIRange { get; set; } public static ConfigEntry DynamicAIRate { get; set; } + public static ConfigEntry DynamicAIIgnoreSnipers { get; set; } //public static ConfigEntry CullPlayers { get; set; } //public static ConfigEntry CullingRange { get; set; } @@ -218,7 +221,7 @@ protected void Awake() new MatchmakerAcceptScreen_Show_Patch().Enable(); new Minefield_method_2_Patch().Enable(); new BotCacher_Patch().Enable(); - new InventoryScroll_Patch().Enable(); + //new InventoryScroll_Patch().Enable(); new AbstractGame_InRaid_Patch().Enable(); new DisconnectButton_Patch().Enable(); new ChangeGameModeButton_Patch().Enable(); @@ -302,17 +305,19 @@ private void SetupConfig() // Coop - ShowNotifications = Instance.Config.Bind("Coop", "Show Feed", true, new ConfigDescription("Enable custom notifications when a player dies, extracts, kills a boss, etc.", tags: new ConfigurationManagerAttributes() { Order = 6 })); + ShowNotifications = Instance.Config.Bind("Coop", "Show Feed", true, new ConfigDescription("Enable custom notifications when a player dies, extracts, kills a boss, etc.", tags: new ConfigurationManagerAttributes() { Order = 7 })); - AutoExtract = Config.Bind("Coop", "Auto Extract", false, new ConfigDescription("Automatically extracts after the extraction countdown. As a host, this will only work if there are no clients connected.", tags: new ConfigurationManagerAttributes() { Order = 5 })); + AutoExtract = Config.Bind("Coop", "Auto Extract", false, new ConfigDescription("Automatically extracts after the extraction countdown. As a host, this will only work if there are no clients connected.", tags: new ConfigurationManagerAttributes() { Order = 6 })); - ShowExtractMessage = Config.Bind("Coop", "Show Extract Message", true, new ConfigDescription("Whether to show the extract message after dying/extracting.", tags: new ConfigurationManagerAttributes() { Order = 4 })); + ShowExtractMessage = Config.Bind("Coop", "Show Extract Message", true, new ConfigDescription("Whether to show the extract message after dying/extracting.", tags: new ConfigurationManagerAttributes() { Order = 5 })); - FasterInventoryScroll = Config.Bind("Coop", "Faster Inventory Scroll", false, new ConfigDescription("Toggle to increase the inventory scroll speed", tags: new ConfigurationManagerAttributes() { Order = 3 })); + //FasterInventoryScroll = Config.Bind("Coop", "Faster Inventory Scroll", false, new ConfigDescription("Toggle to increase the inventory scroll speed", tags: new ConfigurationManagerAttributes() { Order = 4 })); - FasterInventoryScrollSpeed = Config.Bind("Coop", "Faster Inventory Scroll Speed", 63, new ConfigDescription("The speed at which the inventory scrolls at. Default is 63.", new AcceptableValueRange(63, 500), new ConfigurationManagerAttributes() { Order = 2 })); + //FasterInventoryScrollSpeed = Config.Bind("Coop", "Faster Inventory Scroll Speed", 63, new ConfigDescription("The speed at which the inventory scrolls at. Default is 63.", new AcceptableValueRange(63, 500), new ConfigurationManagerAttributes() { Order = 3 })); - 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 })); + ExtractKey = Config.Bind("Coop", "Extract Key", new KeyboardShortcut(KeyCode.F8), new ConfigDescription("The key used to extract from the raid.", tags: new ConfigurationManagerAttributes() { Order = 2 })); + + EnableChat = Config.Bind("Coop", "Enable Chat", false, new ConfigDescription("Toggle to enable chat in game. Cannot be change mid raid", tags: new ConfigurationManagerAttributes() { Order = 1 })); ChatKey = Config.Bind("Coop", "Chat Key", new KeyboardShortcut(KeyCode.RightControl), new ConfigDescription("The key used to open the chat window.", tags: new ConfigurationManagerAttributes() { Order = 0 })); @@ -344,7 +349,9 @@ private void SetupConfig() // Coop | Quest Sharing - QuestTypesToShareAndReceive = Config.Bind("Coop | Quest Sharing", "Quest Types", EQuestSharingTypes.All, new ConfigDescription("Which quest types to receive and send.", tags: new ConfigurationManagerAttributes() { Order = 8 })); + QuestTypesToShareAndReceive = Config.Bind("Coop | Quest Sharing", "Quest Types", EQuestSharingTypes.All, new ConfigDescription("Which quest types to receive and send.", tags: new ConfigurationManagerAttributes() { Order = 2 })); + + QuestSharingNotifications = Config.Bind("Coop | Quest Sharing", "Show Notifications", true, new ConfigDescription("If a notification should be shown when quest progress is shared with out.", tags: new ConfigurationManagerAttributes() { Order = 1 })); // Coop | Custom @@ -378,11 +385,13 @@ private void SetupConfig() // Performance - DynamicAI = Config.Bind("Performance", "Dynamic AI", false, new ConfigDescription("Use the dynamic AI system, disabling AI when they are outside of any player's range.", tags: new ConfigurationManagerAttributes() { Order = 5 })); + DynamicAI = Config.Bind("Performance", "Dynamic AI", false, new ConfigDescription("Use the dynamic AI system, disabling AI when they are outside of any player's range.", tags: new ConfigurationManagerAttributes() { Order = 3 })); + + DynamicAIRange = Config.Bind("Performance", "Dynamic AI Range", 100f, new ConfigDescription("The range at which AI will be disabled dynamically.", new AcceptableValueRange(150f, 1000f), new ConfigurationManagerAttributes() { Order = 2 })); - DynamicAIRange = Config.Bind("Performance", "Dynamic AI Range", 100f, new ConfigDescription("The range at which AI will be disabled dynamically.", new AcceptableValueRange(150f, 1000f), new ConfigurationManagerAttributes() { Order = 4 })); + DynamicAIRate = Config.Bind("Performance", "Dynamic AI Rate", EDynamicAIRates.Medium, new ConfigDescription("How often DynamicAI should scan for the range from all players.", tags: new ConfigurationManagerAttributes() { Order = 1 })); - DynamicAIRate = Config.Bind("Performance", "Dynamic AI Rate", EDynamicAIRates.Medium, new ConfigDescription("How often DynamicAI should scan for the range from all players.", tags: new ConfigurationManagerAttributes() { Order = 3 })); + DynamicAIIgnoreSnipers = Config.Bind("Performance", "Dynamic AI - Ignore Snipers", true, new ConfigDescription("Whether Dynamic AI should ignore sniper scavs.", tags: new ConfigurationManagerAttributes() { Order = 0 })); //CullPlayers = Config.Bind("Performance", "Culling System", true, new ConfigDescription("Whether to use the culling system or not. When players are outside of the culling range, their animations will be simplified. This can dramatically improve performance in certain scenarios.", tags: new ConfigurationManagerAttributes() { Order = 2 })); @@ -521,6 +530,7 @@ private void EnableOverridePatches() new BotTemplateLimitPatch_Override().Enable(); new OfflineRaidSettingsMenuPatch_Override().Enable(); new AddEnemyToAllGroupsInBotZonePatch_Override().Enable(); + new AirdropBox_Patch().Enable(); new FikaAirdropFlare_Patch().Enable(); } diff --git a/Fika.Core/Networking/FikaClient.cs b/Fika.Core/Networking/FikaClient.cs index 8fb72c10..cd65db1f 100644 --- a/Fika.Core/Networking/FikaClient.cs +++ b/Fika.Core/Networking/FikaClient.cs @@ -44,6 +44,7 @@ public class FikaClient : MonoBehaviour, INetEventListener public int Ping = 0; public int ConnectedClients = 0; public int ReadyClients = 0; + public bool HostReady = false; public NetManager NetClient { get @@ -165,7 +166,10 @@ public void SetupGameVariables(CoopPlayer coopPlayer) { coopHandler = CoopHandler.CoopHandlerParent.GetComponent(); MyPlayer = coopPlayer; - fikaChat = gameObject.AddComponent(); + if (FikaPlugin.EnableChat.Value) + { + fikaChat = gameObject.AddComponent(); + } } private void OnOperationCallbackPacketReceived(OperationCallbackPacket packet) @@ -604,6 +608,7 @@ private void OnInformationPacketReceived(InformationPacket packet) { ConnectedClients = packet.NumberOfPlayers; ReadyClients = packet.ReadyPlayers; + HostReady = packet.HostReady; } } diff --git a/Fika.Core/Networking/FikaServer.cs b/Fika.Core/Networking/FikaServer.cs index 7a69e051..1bf5a15e 100644 --- a/Fika.Core/Networking/FikaServer.cs +++ b/Fika.Core/Networking/FikaServer.cs @@ -193,7 +193,7 @@ public async Task Init() foreach (string ip in FikaPlugin.Instance.LocalIPs) { - if (ip.StartsWith("192.168")) // need to add more cases here later, for now only check normal range... + if (ValidateLocalIP(ip)) { Ips = [MyExternalIP, ip]; } @@ -212,6 +212,24 @@ public async Task Init() FikaEventDispatcher.DispatchEvent(new FikaServerCreatedEvent(this)); } + private bool ValidateLocalIP(string LocalIP) + { + if(LocalIP.StartsWith("192.168") || LocalIP.StartsWith("10")) + { + return true; + } + + //Check for RFC1918's 20 bit block. + int[] ip = Array.ConvertAll(LocalIP.Split('.'), int.Parse); + + if (ip[0] == 172 && (ip[1] >= 16 && ip[1] <= 31)) + { + return true; + } + + return false; + } + private async void NatIntroduceRoutine(string natPunchServerIP, int natPunchServerPort, string token, CancellationToken ct) { logger.LogInfo("NatIntroduceRoutine started."); @@ -281,7 +299,10 @@ public void SetupGameVariables(CoopPlayer coopPlayer) { coopHandler = CoopHandler.CoopHandlerParent.GetComponent(); MyPlayer = coopPlayer; - fikaChat = gameObject.AddComponent(); + if (FikaPlugin.EnableChat.Value) + { + fikaChat = gameObject.AddComponent(); + } } private void OnSendCharacterPacketReceived(SendCharacterPacket packet, NetPeer peer) diff --git a/Fika.Core/Networking/Packets/Backend/InformationPacket.cs b/Fika.Core/Networking/Packets/Backend/InformationPacket.cs index 3868c8a7..d2ebd63d 100644 --- a/Fika.Core/Networking/Packets/Backend/InformationPacket.cs +++ b/Fika.Core/Networking/Packets/Backend/InformationPacket.cs @@ -9,13 +9,14 @@ public struct InformationPacket(bool isRequest) : INetSerializable public bool IsRequest = isRequest; public int NumberOfPlayers = 0; public int ReadyPlayers = 0; - + public bool HostReady = false; public void Deserialize(NetDataReader reader) { IsRequest = reader.GetBool(); NumberOfPlayers = reader.GetInt(); ReadyPlayers = reader.GetInt(); + HostReady = reader.GetBool(); } public void Serialize(NetDataWriter writer) @@ -23,6 +24,7 @@ public void Serialize(NetDataWriter writer) writer.Put(IsRequest); writer.Put(NumberOfPlayers); writer.Put(ReadyPlayers); + writer.Put(HostReady); } } } diff --git a/Fika.Core/UI/Patches/InventoryScroll_Patch.cs b/Fika.Core/UI/Patches/InventoryScroll_Patch.cs deleted file mode 100644 index 2998303e..00000000 --- a/Fika.Core/UI/Patches/InventoryScroll_Patch.cs +++ /dev/null @@ -1,31 +0,0 @@ -using EFT.UI; -using SPT.Reflection.Patching; -using System.Reflection; -using UnityEngine.UI; - -namespace Fika.Core.UI.Patches -{ - public class InventoryScroll_Patch : ModulePatch - { - protected override MethodBase GetTargetMethod() - { - return typeof(SimpleStashPanel).GetMethod(nameof(SimpleStashPanel.Show)); - } - - [PatchPrefix] - public static void Prefix(ScrollRect ____stashScroll) - { - if (____stashScroll != null) - { - if (FikaPlugin.FasterInventoryScroll.Value) - { - ____stashScroll.scrollSensitivity = FikaPlugin.FasterInventoryScrollSpeed.Value; - } - else - { - ____stashScroll.scrollSensitivity = 63; - } - } - } - } -} diff --git a/Fika.Core/UI/Patches/MenuTaskBar_Patch.cs b/Fika.Core/UI/Patches/MenuTaskBar_Patch.cs index d5387525..98d72180 100644 --- a/Fika.Core/UI/Patches/MenuTaskBar_Patch.cs +++ b/Fika.Core/UI/Patches/MenuTaskBar_Patch.cs @@ -69,7 +69,7 @@ public static void Postfix(MenuTaskBar __instance) { Singleton.Instance.PlayUISound(EUISoundType.ButtonBottomBarClick); string installDir = Environment.CurrentDirectory; - string fikaDir = installDir + @"/user/fika"; + string fikaDir = installDir + @"\user\fika"; if (!string.IsNullOrEmpty(installDir)) { @@ -80,12 +80,12 @@ public static void Postfix(MenuTaskBar __instance) string profileId = Singleton>.Instance.Session.Profile.ProfileId; - if (File.Exists(@$"{fikaDir}/{profileId}.json")) + if (File.Exists(@$"{fikaDir}\{profileId}.json")) { - File.Copy(@$"{fikaDir}/{profileId}.json", @$"{fikaDir}/{profileId}.json.BAK", true); + File.Copy(@$"{fikaDir}\{profileId}.json", @$"{fikaDir}\{profileId}.json.BAK", true); } - File.WriteAllText(@$"{fikaDir}/{profileId}.json", profile.ToString()); + File.WriteAllText(@$"{fikaDir}\{profileId}.json", profile.ToString()); NotificationManagerClass.DisplayMessageNotification($"Saved profile '{profileId}' to {fikaDir}"); GameObject.Destroy(downloadProfileGameObject);