diff --git a/Exiled.API/Features/Npc.cs b/Exiled.API/Features/Npc.cs index a272fd3445..66e43baf78 100644 --- a/Exiled.API/Features/Npc.cs +++ b/Exiled.API/Features/Npc.cs @@ -13,21 +13,24 @@ namespace Exiled.API.Features using System.Linq; using System.Reflection; + using CentralAuth; using CommandSystem; using Exiled.API.Enums; using Exiled.API.Features.Components; - + using Exiled.API.Features.Roles; using Footprinting; - + using InventorySystem.Items.Firearms.BasicMessages; + using InventorySystem.Items.Firearms.Modules; using MEC; - using Mirror; using PlayerRoles; - + using PlayerRoles.FirstPersonControl; + using RelativePositioning; using UnityEngine; + using Firearm = Items.Firearm; using Object = UnityEngine.Object; /// @@ -137,7 +140,7 @@ public static Npc Spawn(string name, RoleTypeId role, int id = 0, string userId Npc npc = new(newObject) { - IsVerified = true, + IsVerified = userId != PlayerAuthenticationManager.DedicatedId && userId != null, IsNPC = true, }; @@ -161,7 +164,22 @@ public static Npc Spawn(string name, RoleTypeId role, int id = 0, string userId try { - npc.ReferenceHub.authManager.UserId = string.IsNullOrEmpty(userId) ? $"Dummy@localhost" : userId; + if (userId == PlayerAuthenticationManager.DedicatedId) + { + npc.ReferenceHub.authManager.SyncedUserId = userId; + try + { + npc.ReferenceHub.authManager.InstanceMode = ClientInstanceMode.DedicatedServer; + } + catch (Exception e) + { + Log.Debug($"Ignore: {e}"); + } + } + else + { + npc.ReferenceHub.authManager.UserId = userId == string.Empty ? $"Dummy@localhost" : userId; + } } catch (Exception e) { @@ -193,5 +211,95 @@ public void Destroy() Dictionary.Remove(GameObject); Object.Destroy(GameObject); } + + /// + /// Forces the NPC to look in the specified rotation. + /// + /// The position to look at. + public void LookAt(Vector3 position) + { + if (Role is FpcRole fpc) + { + Vector3 direction = position - Position; + Quaternion quat = Quaternion.LookRotation(direction, Vector3.up); + LookAt(quat); + } + } + + /// + /// Forces the NPC to look in the specified rotation. + /// + /// The rotation to look towards. + public void LookAt(Quaternion rotation) + { + if (Role is not FpcRole fpc) + return; + + if (rotation.eulerAngles.z != 0f) + rotation = Quaternion.LookRotation(rotation * Vector3.forward, Vector3.up); + + Vector2 angles = new Vector2(-rotation.eulerAngles.x, rotation.eulerAngles.y); + + ushort hor = (ushort)Mathf.RoundToInt(Mathf.Repeat(angles.y, 360f) * (ushort.MaxValue / 360f)); + ushort vert = (ushort)Mathf.RoundToInt(Mathf.Clamp(Mathf.Repeat(angles.x + 90f, 360f) - 2f, 0f, 176f) * (ushort.MaxValue / 176f)); + + fpc.FirstPersonController.FpcModule.MouseLook.ApplySyncValues(hor, vert); + } + + /// + /// Forces the NPC to shoot their current . + /// + /// if the weapon shot request is received. Returns otherwise, or if the player is not an or is not holding a . + public bool ShootWeapon() + { + if (CurrentItem is not Firearm firearm) + return false; + + if (!firearm.Base.ActionModule.ServerAuthorizeShot()) + return false; + + ShotMessage message = new ShotMessage() + { + ShooterCameraRotation = CameraTransform.rotation, + ShooterPosition = new RelativePosition(Transform.position), + ShooterWeaponSerial = CurrentItem.Serial, + TargetNetId = 0, + TargetPosition = default, + TargetRotation = Quaternion.identity, + }; + + Physics.Raycast(CameraTransform.position, CameraTransform.forward, out RaycastHit hit, firearm.Base.BaseStats.MaxDistance(), StandardHitregBase.HitregMask); + + if (hit.transform && hit.collider.TryGetComponent(out IDestructible destructible) && destructible != null) + { + message.TargetNetId = destructible.NetworkId; + message.TargetPosition = new RelativePosition(hit.transform.position); + message.TargetRotation = hit.transform.rotation; + } + else if (hit.transform) + { + message.TargetPosition = new RelativePosition(hit.transform.position); + message.TargetRotation = hit.transform.rotation; + } + + FirearmBasicMessagesHandler.ServerShotReceived(ReferenceHub.connectionToClient, message); + return true; + } + + /// + /// Sets the NPC's current status for Aiming Down Sights. + /// + /// Should the player be aiming down sights. + /// if the weapon Aim Down Sights request is received. Returns otherwise, or if the player is not an or is not holding a . + public bool SetAimDownSight(bool shouldADS) + { + if (CurrentItem is Firearm firearm) + { + FirearmBasicMessagesHandler.ServerRequestReceived(ReferenceHub.connectionToClient, new RequestMessage(firearm.Serial, shouldADS ? RequestType.AdsIn : RequestType.AdsOut)); + return true; + } + + return false; + } } } diff --git a/Exiled.API/Features/Player.cs b/Exiled.API/Features/Player.cs index 668de9ca2d..fbf49e8f4f 100644 --- a/Exiled.API/Features/Player.cs +++ b/Exiled.API/Features/Player.cs @@ -1762,7 +1762,7 @@ public void TrySetCustomRoleFriendlyFire(string roleTypeId, Dictionary CustomRoleFriendlyFireMultiplier.Remove(role); /// - /// Forces the player to reload their current weapon. + /// Forces the player to reload their current . /// /// if firearm was successfully reloaded. Otherwise, . public bool ReloadWeapon() @@ -1770,13 +1770,45 @@ public bool ReloadWeapon() if (CurrentItem is Firearm firearm) { bool result = firearm.Base.AmmoManagerModule.ServerTryReload(); - Connection.Send(new RequestMessage(firearm.Serial, RequestType.Reload)); + if (result) + Connection.Send(new RequestMessage(firearm.Serial, RequestType.Reload)); return result; } return false; } + /// + /// Forces the player to unload their current . + /// + /// if the weapon unload request is received. Returns otherwise, or if the player is not an or is not holding a . + public bool UnloadWeapon() + { + if (CurrentItem is Firearm firearm) + { + bool result = firearm.Base.AmmoManagerModule.ServerTryUnload(); + if (result) + Connection.Send(new RequestMessage(firearm.Serial, RequestType.Unload)); + return result; + } + + return true; + } + + /// + /// Forces the player to toggle the Flashlight Attachment on their current . + /// + /// if the weapon flashlight toggle request is received. Returns otherwise, or if the player is not an or is not holding a . + public bool ToggleWeaponFlashlight() + { + if (RoleManager.CurrentRole is not IFpcRole fpc || CurrentItem is not Firearm firearm) + return false; + + bool oldCheck = firearm.FlashlightEnabled; // Temporary Solution + FirearmBasicMessagesHandler.ServerRequestReceived(ReferenceHub.connectionToClient, new RequestMessage(firearm.Serial, RequestType.ToggleFlashlight)); + return oldCheck != firearm.FlashlightEnabled; + } + /// /// Tries to get an item from a player's inventory. ///