using System.Threading.Tasks; using Sandbox.UI; using Sasalka; namespace Sandbox.Weapons; public sealed class Weapon : AmmoUseableBase { [Property] public SkinnedModelRenderer GunRenderer { get; private set; } [Property] public GameObject MuzzleLight { get; private set; } [Property] public GameObject particlePrefab { get; set; } [Property] public GameObject bloodParticle { get; set; } [Property] public WeaponItemDefinition WeaponDefinition { get; set; } private SoundPointComponent _sound; private Rigidbody _rigidbody; protected override void OnStart() { base.OnStart(); _sound = GameObject.GetComponent(true); } public override void OnEquipped() { _rigidbody = GameObject.Components.Get(); _rigidbody.Enabled = false; GameObject.Components.Get().Enabled = false; } protected override WeaponItemDefinition GetWeaponDefinition() { return WeaponDefinition; } public void Attack() { AttackEffects(); Vector3 startPos = Scene.Camera.WorldPosition; Vector3 dir = Scene.Camera.WorldRotation.Forward; float maxDistance = WeaponDefinition?.Range ?? 1000f; var tr = Scene.Trace .Ray(startPos, startPos + dir * maxDistance) .IgnoreGameObjectHierarchy(Dedugan.Local.GameObject) .WithoutTags("weapon") .UseHitboxes() .Run(); if (tr.Hit) { if (tr.Hitbox != null) { var boneIndex = tr.Hitbox.Bone.Index; var components = tr.GameObject.Components; // Кэшируем компоненты для избежания повторных поисков var dedugan = components.Get(); var enemy = components.Get(); var hasTarget = dedugan.IsValid() || enemy.IsValid(); if (hasTarget) { CreateHitEffects(tr.EndPosition, tr.Normal, true); } if (dedugan.IsValid()) { dedugan.ReportHit(dir, boneIndex); } if (enemy.IsValid()) { enemy.ReportHit(dir, boneIndex); } } else { CreateHitEffects(tr.EndPosition, tr.Normal); } } } [Rpc.Broadcast] private void CreateHitEffects(Vector3 position, Vector3 normal, bool blood = false) { var rot = Rotation.LookAt(normal); DestroyAsync( blood ? bloodParticle.Clone(position, rot) : particlePrefab.Clone(position, rot), 0.5f); } async void DestroyAsync(GameObject go, float delay) { await GameTask.DelaySeconds(delay); go.Destroy(); } [Rpc.Broadcast] public void AttackEffects() { _sound?.StartSound(); MuzzleLight.Enabled = true; GunRenderer.Set("Fire", true); GameTask.DelaySeconds(0.05f).ContinueWith((_) => { MuzzleLight.Enabled = false; }); } protected override void OnUse() { Attack(); } }