From f951ea364c05a8e1e4644b0ecc5f6f9ba073ffce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20SAVA=C5=9E?= Date: Fri, 15 May 2026 00:48:53 +0300 Subject: [PATCH 01/11] update add reverse method & property for events & new Player::Playgunsound helper method --- .github/README.md | 147 +++---- EXILED/Exiled.API/Enums/GunSoundType.cs | 180 ++++++++ .../Exiled.API/Extensions/ItemExtensions.cs | 411 ++++++++++++++++++ .../Exiled.API/Extensions/MirrorExtensions.cs | 20 + .../Features/Pickups/JailbirdPickup.cs | 3 + .../API/Features/CustomGoggles.cs | 7 + .../EventArgs/Player/ChangingRoleEventArgs.cs | 14 +- .../Player/ReceivingGunSoundEventArgs.cs | 21 + .../Player/SendingGunSoundEventArgs.cs | 21 + .../Server/RoundStartingEventArgs.cs | 62 +++ .../Exiled.Events/Handlers/Internal/Round.cs | 10 +- EXILED/Exiled.Events/Handlers/Server.cs | 11 + .../Events/Player/ChangingRoleAndSpawned.cs | 3 + .../Events/Player/PreAuthenticating.cs | 12 +- .../Patches/Events/Player/TriggeringTesla.cs | 16 +- .../Patches/Events/Server/RoundStarting.cs | 118 +++++ .../Patches/Fixes/Fix106ItemManager.cs | 2 +- 17 files changed, 947 insertions(+), 111 deletions(-) create mode 100644 EXILED/Exiled.API/Enums/GunSoundType.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Server/RoundStartingEventArgs.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Server/RoundStarting.cs diff --git a/.github/README.md b/.github/README.md index 7ced9a1c45..51318f9ca0 100644 --- a/.github/README.md +++ b/.github/README.md @@ -26,91 +26,68 @@ Localized READMEs -
-
- -
- English -
-
-
- -
- Русский -
-
-
- -
- 中文 -
-
-
- -
- Español -
-
-
- -
- Polski -
-
-
- -
- Português-BR -
-
-
- -
- Italiano -
-
-
- -
- Čeština -
-
-
- -
- Dansk -
-
-
- -
- Türkçe -
-
-
- -
- Deutsch -
-
-
- -
- Français -
-
-
- -
- 한국어 -
-
-
- -
- ไทย -
-
+ + + + + + + + + + + + + + + + + + + +
+
+ English +
+
+ Русский +
+
+ 中文 +
+
+ Español +
+
+ Polski +
+
+ Português-BR +
+
+ Italiano +
+
+ Čeština +
+
+ Dansk +
+
+ Türkçe +
+
+ Deutsch +
+
+ Français +
+
+ 한국어 +
+
+ ไทย +
This repo is a fork of Exiled-Team/EXILED after changes in project leadership.
You can access the commit this update was forked from here.
diff --git a/EXILED/Exiled.API/Enums/GunSoundType.cs b/EXILED/Exiled.API/Enums/GunSoundType.cs new file mode 100644 index 0000000000..ce80d261eb --- /dev/null +++ b/EXILED/Exiled.API/Enums/GunSoundType.cs @@ -0,0 +1,180 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- +namespace Exiled.API.Enums +{ + /// + /// Represents the type of sound a firearm can produce. + /// + /// + public enum GunSoundType + { + /// + /// Unknown or unmapped sound. + /// + Unknown, + + /// + /// Sound of a gunshot. + /// + Fire, + + /// + /// Sound of a suppressed gunshot. + /// + SuppressedFire, + + /// + /// Sound of a dry fire (trigger pulled with an empty chamber). + /// + DryFire, + + /// + /// Sound of a firearm being equipped or drawn. + /// + Equip, + + /// + /// Sound of a rare or special equip animation. + /// + EquipRare, + + /// + /// Sound of a firearm being cocked or charged. + /// + Cock, + + /// + /// Sound of an initial or special cocking animation. + /// + CockInitial, + + /// + /// Sound of a magazine being inserted. + /// + ReloadInsert, + + /// + /// Sound of a magazine being ejected. + /// + ReloadEject, + + /// + /// Sound of a general reload action (often used for revolvers or shotguns). + /// + Reload, + + /// + /// Sound of a bolt or slide being pulled back. + /// + BoltOpen, + + /// + /// Sound of a bolt or slide releasing forward. + /// + BoltClose, + + /// + /// Sound of a round being ejected from the chamber. + /// + ChamberEject, + + /// + /// Sound of a revolver's cylinder rotating. + /// + CylinderRotate, + + /// + /// Sound of a revolver's cylinder being spun playfully. + /// + CylinderSpin, + + /// + /// Sound of a gunshot using special buckshot ammunition. + /// + FireBuckshot, + + /// + /// Sound of loading buckshot ammunition into an empty firearm. + /// + ReloadBuckshotEmpty, + + /// + /// Sound of ejecting or emptying buckshot ammunition. + /// + EjectBuckshot, + + /// + /// Sound of the weapon being inspected. + /// + Inspect, + + /// + /// Sound of a single shot in Disintegrator mode. + /// + FireDisintegrator, + + /// + /// Sound of the last shot in Disintegrator mode. + /// + FireDisintegratorLast, + + /// + /// Sound of a shot in 3x Burst mode. + /// + FireBurst3x, + + /// + /// Sound of the last shot in a 3x Burst sequence. + /// + FireBurst3xLast, + + /// + /// Sound of general weapon handling, rustling, or adjusting grip. + /// + WeaponHandling, + + /// + /// Sound of a weapon's stock being extended or adjusted. + /// + StockExtend, + + /// + /// Sound of the second sequential shot, often used in double-shot shotgun modes. + /// + FireDouble, + + /// + /// Sound of a single shotgun shell being ejected during unload. + /// + ShellEject, + + /// + /// Sound indicating the completion of a shotgun unload sequence. + /// + UnloadComplete, + + /// + /// Sound of a magazine being firmly tapped or locked into the firearm. + /// + ReloadLock, + + /// + /// Sound of a drum or extended magazine being ejected. + /// + ReloadEjectDrum, + + /// + /// Sound of a drum or extended magazine being inserted. + /// + ReloadInsertDrum, + + /// + /// Sound of a drum or extended magazine being firmly tapped or locked into place. + /// + ReloadLockDrum, + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Extensions/ItemExtensions.cs b/EXILED/Exiled.API/Extensions/ItemExtensions.cs index 80c77a4c37..34e51d1c52 100644 --- a/EXILED/Exiled.API/Extensions/ItemExtensions.cs +++ b/EXILED/Exiled.API/Extensions/ItemExtensions.cs @@ -20,6 +20,7 @@ namespace Exiled.API.Extensions using InventorySystem.Items.Firearms.Attachments; using InventorySystem.Items.Firearms.Modules; using InventorySystem.Items.Pickups; + using Structs; /// @@ -345,6 +346,416 @@ public static uint GetBaseCode(this FirearmType type) /// of the specified . public static ItemCategory GetCategory(this ItemType type) => GetItemBase(type).Category; + /// + /// Gets the associated with a specific and sound index. + /// + /// The of the firearm. + /// The mapped index of the sound. + /// The mapped , or if not found. + public static GunSoundType GetSoundType(this ItemType type, int index) => type switch + { + ItemType.GunCOM15 => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.SuppressedFire, + 4 => GunSoundType.Equip, + 5 => GunSoundType.ReloadInsert, + 6 => GunSoundType.ReloadEject, + 7 => GunSoundType.Cock, + 8 => GunSoundType.BoltOpen, + 9 => GunSoundType.BoltClose, + 11 => GunSoundType.ChamberEject, + _ => GunSoundType.Unknown + }, + + ItemType.GunCOM18 => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.SuppressedFire, + 3 => GunSoundType.Equip, + 4 => GunSoundType.ReloadInsert, + 5 => GunSoundType.ReloadEject, + 6 => GunSoundType.BoltOpen, + 7 => GunSoundType.BoltClose, + 8 => GunSoundType.ChamberEject, + 9 => GunSoundType.EquipRare, + _ => GunSoundType.Unknown + }, + + ItemType.GunRevolver => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.CylinderRotate, + 4 => GunSoundType.Fire, + 5 => GunSoundType.FireBuckshot, + 7 => GunSoundType.Equip, + 8 => GunSoundType.CylinderSpin, + 9 => GunSoundType.CockInitial, + 11 => GunSoundType.ReloadBuckshotEmpty, + 14 => GunSoundType.Reload, + 15 => GunSoundType.EquipRare, + 16 => GunSoundType.EjectBuckshot, + _ => GunSoundType.Unknown + }, + + ItemType.GunCom45 => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.Equip, + 3 => GunSoundType.CockInitial, + 4 => GunSoundType.ReloadInsert, + 5 => GunSoundType.ReloadEject, + 6 => GunSoundType.BoltOpen, + 7 => GunSoundType.BoltClose, + _ => GunSoundType.Unknown + }, + + ItemType.ParticleDisruptor => index switch + { + 0 => GunSoundType.Reload, + 2 => GunSoundType.CockInitial, + 3 => GunSoundType.Inspect, + 4 => GunSoundType.Inspect, + 5 => GunSoundType.Inspect, + 6 => GunSoundType.Equip, + 7 => GunSoundType.FireDisintegrator, + 9 => GunSoundType.FireDisintegrator, + 8 => GunSoundType.FireDisintegratorLast, + 10 => GunSoundType.FireDisintegratorLast, + 11 => GunSoundType.FireBurst3x, + 13 => GunSoundType.FireBurst3x, + 12 => GunSoundType.FireBurst3xLast, + 14 => GunSoundType.FireBurst3xLast, + _ => GunSoundType.Unknown + }, + + ItemType.GunFSP9 => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.SuppressedFire, + 3 => GunSoundType.WeaponHandling, + 4 => GunSoundType.Equip, + 5 => GunSoundType.WeaponHandling, + 7 => GunSoundType.ReloadEject, + 8 => GunSoundType.BoltOpen, + 9 => GunSoundType.StockExtend, + 11 => GunSoundType.BoltClose, + 12 => GunSoundType.ReloadInsert, + 13 => GunSoundType.ChamberEject, + _ => GunSoundType.Unknown + }, + + ItemType.GunShotgun => index switch + { + 0 => GunSoundType.FireDouble, + 1 => GunSoundType.Fire, + 2 => GunSoundType.DryFire, + 3 => GunSoundType.WeaponHandling, + 4 => GunSoundType.ReloadInsert, + 5 => GunSoundType.ReloadInsert, + 6 => GunSoundType.BoltOpen, + 7 => GunSoundType.BoltClose, + 8 => GunSoundType.UnloadComplete, + 9 => GunSoundType.ShellEject, + 10 => GunSoundType.Equip, + _ => GunSoundType.Unknown + }, + + ItemType.GunFRMG0 => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.SuppressedFire, + 5 => GunSoundType.Equip, + 7 => GunSoundType.ReloadEject, + 8 => GunSoundType.ReloadEjectDrum, + 9 => GunSoundType.Cock, + 10 => GunSoundType.ReloadInsert, + 11 => GunSoundType.ReloadInsertDrum, + 13 => GunSoundType.ReloadLock, + 14 => GunSoundType.ReloadLockDrum, + 16 => GunSoundType.ChamberEject, + _ => GunSoundType.Unknown + }, + + ItemType.GunAK => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.SuppressedFire, + 6 => GunSoundType.Equip, + 7 => GunSoundType.ReloadEject, + 8 => GunSoundType.ReloadEjectDrum, + 10 => GunSoundType.Cock, + 11 => GunSoundType.CockInitial, + 12 => GunSoundType.ReloadInsertDrum, + 14 => GunSoundType.ReloadInsert, + 19 => GunSoundType.ChamberEject, + _ => GunSoundType.Unknown + }, + + ItemType.GunA7 => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.CockInitial, + 3 => GunSoundType.Equip, + 5 => GunSoundType.ReloadEject, + 6 => GunSoundType.WeaponHandling, + 7 => GunSoundType.ReloadInsert, + 8 => GunSoundType.ChamberEject, + _ => GunSoundType.Unknown + }, + + ItemType.GunSCP127 => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.CockInitial, + 4 => GunSoundType.Equip, + 5 => GunSoundType.Cock, + 6 => GunSoundType.WeaponHandling, + _ => GunSoundType.Unknown + }, + + ItemType.GunLogicer => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.Equip, + 3 => GunSoundType.Cock, + 4 => GunSoundType.BoltOpen, + 5 => GunSoundType.ReloadEject, + 6 => GunSoundType.ReloadInsert, + 7 => GunSoundType.BoltClose, + 8 => GunSoundType.WeaponHandling, + _ => GunSoundType.Unknown + }, + + ItemType.GunCrossvec => index switch + { + 0 => GunSoundType.DryFire, + 1 => GunSoundType.Fire, + 2 => GunSoundType.SuppressedFire, + 4 => GunSoundType.Equip, + 5 => GunSoundType.StockExtend, + 6 => GunSoundType.BoltOpen, + 7 => GunSoundType.BoltClose, + 8 => GunSoundType.ReloadEject, + 9 => GunSoundType.ReloadInsert, + 10 => GunSoundType.WeaponHandling, + 15 => GunSoundType.ChamberEject, + _ => GunSoundType.Unknown + }, + + _ => GunSoundType.Unknown + }; + + /// + /// Gets the mapped index associated with a specific and . + /// + /// The of the firearm. + /// The to find the index for. + /// The mapped index, or 0 if not found. + public static int GetGunSoundTypeIndex(this ItemType type, GunSoundType soundType) => type switch + { + ItemType.GunCOM15 => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.SuppressedFire => 2, + GunSoundType.Equip => 4, + GunSoundType.ReloadInsert => 5, + GunSoundType.ReloadEject => 6, + GunSoundType.Cock => 7, + GunSoundType.BoltOpen => 8, + GunSoundType.BoltClose => 9, + GunSoundType.ChamberEject => 11, + _ => -1 + }, + + ItemType.GunCOM18 => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.SuppressedFire => 2, + GunSoundType.Equip => 3, + GunSoundType.ReloadInsert => 4, + GunSoundType.ReloadEject => 5, + GunSoundType.BoltOpen => 6, + GunSoundType.BoltClose => 7, + GunSoundType.ChamberEject => 8, + GunSoundType.EquipRare => 9, + _ => -1 + }, + + ItemType.GunRevolver => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.CylinderRotate => 1, + GunSoundType.Fire => 4, + GunSoundType.FireBuckshot => 5, + GunSoundType.Equip => 7, + GunSoundType.CylinderSpin => 8, + GunSoundType.CockInitial => 9, + GunSoundType.ReloadBuckshotEmpty => 11, + GunSoundType.Reload => 14, + GunSoundType.EquipRare => 15, + GunSoundType.EjectBuckshot => 16, + _ => -1 + }, + + ItemType.GunCom45 => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.Equip => 2, + GunSoundType.CockInitial => 3, + GunSoundType.ReloadInsert => 4, + GunSoundType.ReloadEject => 5, + GunSoundType.BoltOpen => 6, + GunSoundType.BoltClose => 7, + _ => -1 + }, + + ItemType.ParticleDisruptor => soundType switch + { + GunSoundType.Reload => 0, + GunSoundType.CockInitial => 2, + GunSoundType.Inspect => 3, + GunSoundType.Equip => 6, + GunSoundType.FireDisintegrator => 7, + GunSoundType.FireDisintegratorLast => 8, + GunSoundType.FireBurst3x => 11, + GunSoundType.FireBurst3xLast => 12, + _ => -1 + }, + + ItemType.GunFSP9 => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.SuppressedFire => 2, + GunSoundType.WeaponHandling => 3, + GunSoundType.Equip => 4, + GunSoundType.ReloadEject => 7, + GunSoundType.BoltOpen => 8, + GunSoundType.StockExtend => 9, + GunSoundType.BoltClose => 11, + GunSoundType.ReloadInsert => 12, + GunSoundType.ChamberEject => 13, + _ => -1 + }, + + ItemType.GunShotgun => soundType switch + { + GunSoundType.FireDouble => 0, + GunSoundType.Fire => 1, + GunSoundType.DryFire => 2, + GunSoundType.WeaponHandling => 3, + GunSoundType.ReloadInsert => 4, + GunSoundType.BoltOpen => 6, + GunSoundType.BoltClose => 7, + GunSoundType.UnloadComplete => 8, + GunSoundType.ShellEject => 9, + GunSoundType.Equip => 10, + _ => -1 + }, + + ItemType.GunFRMG0 => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.SuppressedFire => 2, + GunSoundType.Equip => 5, + GunSoundType.ReloadEject => 7, + GunSoundType.ReloadEjectDrum => 8, + GunSoundType.Cock => 9, + GunSoundType.ReloadInsert => 10, + GunSoundType.ReloadInsertDrum => 11, + GunSoundType.ReloadLock => 13, + GunSoundType.ReloadLockDrum => 14, + GunSoundType.ChamberEject => 16, + _ => -1 + }, + + ItemType.GunAK => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.SuppressedFire => 2, + GunSoundType.Equip => 6, + GunSoundType.ReloadEject => 7, + GunSoundType.ReloadEjectDrum => 8, + GunSoundType.Cock => 10, + GunSoundType.CockInitial => 11, + GunSoundType.ReloadInsertDrum => 12, + GunSoundType.ReloadInsert => 14, + GunSoundType.ChamberEject => 19, + _ => -1 + }, + + ItemType.GunA7 => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.CockInitial => 2, + GunSoundType.Equip => 3, + GunSoundType.ReloadEject => 5, + GunSoundType.WeaponHandling => 6, + GunSoundType.ReloadInsert => 7, + GunSoundType.ChamberEject => 8, + _ => -1 + }, + + ItemType.GunSCP127 => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.CockInitial => 2, + GunSoundType.Equip => 4, + GunSoundType.Cock => 5, + GunSoundType.WeaponHandling => 6, + _ => -1 + }, + + ItemType.GunLogicer => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.Equip => 2, + GunSoundType.Cock => 3, + GunSoundType.BoltOpen => 4, + GunSoundType.ReloadEject => 5, + GunSoundType.ReloadInsert => 6, + GunSoundType.BoltClose => 7, + GunSoundType.WeaponHandling => 8, + _ => -1 + }, + + ItemType.GunCrossvec => soundType switch + { + GunSoundType.DryFire => 0, + GunSoundType.Fire => 1, + GunSoundType.SuppressedFire => 2, + GunSoundType.Equip => 4, + GunSoundType.StockExtend => 5, + GunSoundType.BoltOpen => 6, + GunSoundType.BoltClose => 7, + GunSoundType.ReloadEject => 8, + GunSoundType.ReloadInsert => 9, + GunSoundType.WeaponHandling => 10, + GunSoundType.ChamberEject => 15, + _ => -1 + }, + + _ => -1 + }; + /// /// Checks if the specified has the specified . /// diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs index 20f5b1a376..e1650fb514 100644 --- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs +++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs @@ -188,6 +188,26 @@ public static ReadOnlyDictionary RpcFullNames public static void PlayGunSound(this Player player, Vector3 position, ItemType itemType, byte volume, byte audioClipId = 0) => PlayGunSound(player, position, itemType.GetFirearmType(), volume, audioClipId); + /// + /// Plays a gun sound for a specific player at a given position using the specified firearm type. + /// + /// The player who will hear the sound. + /// World position where the sound will be played. + /// Type of firearm whose sound set will be used. + /// Playback pitch for the sound. Default is 1. + /// Which sound from the firearm's sound set to play (for example Fire, Cock, etc.). + public static void PlayGunSound(this Player player, Vector3 position, FirearmType firearmType, float pitch = 1, GunSoundType soundType = GunSoundType.Fire) + { + int index = firearmType.GetItemType().GetGunSoundTypeIndex(soundType); + if (index == -1) + { + Log.Warn($"Failed to find gun sound for {firearmType} with sound type {soundType}."); + return; + } + + player.PlayGunSound(position, firearmType, pitch, index); + } + /// /// Plays a gun sound that only the can hear. /// diff --git a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs index eaaf77cb7a..93c18ff7bf 100644 --- a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs @@ -109,6 +109,9 @@ internal override void ReadItemInfo(Item item) if (item is Jailbird jailBirditem) { + // TODO: Remove if this is fixed https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/2816 + jailBirditem.Base._deterioration.RecheckUsage(); + MeleeDamage = jailBirditem.MeleeDamage; ChargeDamage = jailBirditem.ChargeDamage; FlashDuration = jailBirditem.FlashDuration; diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomGoggles.cs b/EXILED/Exiled.CustomItems/API/Features/CustomGoggles.cs index 60d1046227..68f8d07818 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomGoggles.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomGoggles.cs @@ -8,6 +8,7 @@ namespace Exiled.CustomItems.API.Features { using EventArgs; + using Exiled.API.Enums; using Exiled.API.Features; using Exiled.API.Features.Items; @@ -18,6 +19,8 @@ namespace Exiled.CustomItems.API.Features using PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.Wearables; + using PlayerStatsSystem; + /// /// The Custom Goggles base class. /// @@ -56,6 +59,7 @@ public override ItemType Type /// protected override void SubscribeEvents() { + PlayerStats.OnAnyPlayerDied += OnOwnerDied; InventorySystem.InventoryExtensions.OnInventoryDropped += RemoveSafely; Exiled.Events.Handlers.Player.UsingItem += OnInternalUsingItem; Exiled.Events.Handlers.Player.ItemRemoved += OnInternalItemRemoved; @@ -68,6 +72,7 @@ protected override void SubscribeEvents() /// protected override void UnsubscribeEvents() { + PlayerStats.OnAnyPlayerDied -= OnOwnerDied; InventorySystem.InventoryExtensions.OnInventoryDropped -= RemoveSafely; Exiled.Events.Handlers.Player.UsingItem -= OnInternalUsingItem; Exiled.Events.Handlers.Player.ItemRemoved -= OnInternalItemRemoved; @@ -214,6 +219,8 @@ private void OnInternalChangingStatus(ChangingStatusEventArgs ev) InternalRemove(ev.Player, ev.Scp1344); } + private void OnOwnerDied(ReferenceHub hub, DamageHandlerBase handler) => RemoveSafely(hub); + private void RemoveSafely(ReferenceHub hub) { if (!Player.TryGet(hub, out Player owner)) diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingRoleEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingRoleEventArgs.cs index 052fff48c6..92adf3b91a 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ChangingRoleEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingRoleEventArgs.cs @@ -8,6 +8,7 @@ namespace Exiled.Events.EventArgs.Player { using System.Collections.Generic; + using System.Linq; using API.Enums; using API.Features; @@ -15,6 +16,8 @@ namespace Exiled.Events.EventArgs.Player using Exiled.API.Features.Pools; using Interfaces; using InventorySystem; + using LabApi.Events.Arguments.PlayerEvents; + using LabApi.Events.Handlers; using PlayerRoles; /// @@ -72,10 +75,17 @@ public RoleTypeId NewRole Items.Clear(); Ammo.Clear(); - foreach (ItemType itemType in inventory.Items) + PlayerReceivingLoadoutEventArgs playerReceivingLoadoutEventArgs = new(Player.ReferenceHub, inventory.Items.ToList(), inventory.Ammo, !ShouldPreserveInventory); + PlayerEvents.OnReceivingLoadout(playerReceivingLoadoutEventArgs); + if (!playerReceivingLoadoutEventArgs.IsAllowed) + { + return; + } + + foreach (ItemType itemType in playerReceivingLoadoutEventArgs.Items) Items.Add(itemType); - foreach (KeyValuePair ammoPair in inventory.Ammo) + foreach (KeyValuePair ammoPair in playerReceivingLoadoutEventArgs.Ammo) Ammo.Add(ammoPair.Key, ammoPair.Value); field = value; diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReceivingGunSoundEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReceivingGunSoundEventArgs.cs index b12fe11972..499675c069 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ReceivingGunSoundEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ReceivingGunSoundEventArgs.cs @@ -12,6 +12,8 @@ namespace Exiled.Events.EventArgs.Player using AudioPooling; + using Exiled.API.Enums; + using Exiled.API.Extensions; using Exiled.Events.EventArgs.Interfaces; using UnityEngine; @@ -68,6 +70,25 @@ public ReceivingGunSoundEventArgs(ReferenceHub hub, InventorySystem.Items.Firear /// public int AudioIndex { get; set; } + /// + /// Gets or sets or set the type of the gun sound. + /// + public GunSoundType SoundType + { + get => Firearm.Type.GetSoundType(AudioIndex); + set + { + int index = Firearm.Type.GetGunSoundTypeIndex(value); + if (index == -1) + { + Log.Warn($"The firearm {Firearm} doesn't have a sound of type {value}."); + return; + } + + AudioIndex = index; + } + } + /// /// Gets or sets the mixer channel through which the sound will be played. /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/SendingGunSoundEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/SendingGunSoundEventArgs.cs index c1041453ab..07a4d38bdc 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/SendingGunSoundEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/SendingGunSoundEventArgs.cs @@ -11,6 +11,8 @@ namespace Exiled.Events.EventArgs.Player using AudioPooling; + using Exiled.API.Enums; + using Exiled.API.Extensions; using Exiled.Events.EventArgs.Interfaces; using UnityEngine; @@ -58,6 +60,25 @@ public SendingGunSoundEventArgs(InventorySystem.Items.Firearms.Firearm firearm, /// public int AudioIndex { get; set; } + /// + /// Gets or sets or set the type of the gun sound. + /// + public GunSoundType SoundType + { + get => Firearm.Type.GetSoundType(AudioIndex); + set + { + int index = Firearm.Type.GetGunSoundTypeIndex(value); + if (index == -1) + { + Log.Warn($"The firearm {Firearm} doesn't have a sound of type {value}."); + return; + } + + AudioIndex = index; + } + } + /// /// Gets or sets the mixer channel through which the sound will be played. /// diff --git a/EXILED/Exiled.Events/EventArgs/Server/RoundStartingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/RoundStartingEventArgs.cs new file mode 100644 index 0000000000..b97f309edf --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Server/RoundStartingEventArgs.cs @@ -0,0 +1,62 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Server +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information before the start of a round. + /// + public class RoundStartingEventArgs : IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + public RoundStartingEventArgs(short timeLeft, short originalTimeLeft, int topPlayer, int playerCount) + { + TimeLeft = timeLeft; + OriginalTimeLeft = originalTimeLeft; + TopPlayer = topPlayer; + PlayerCount = playerCount; + IsAllowed = TimeLeft == -1; + } + + /// + /// Gets or sets the time before the start of the Round. + /// + public int TimeLeft { get; set; } + + /// + /// Gets or sets the time before the start of the Round. + /// + public int OriginalTimeLeft { get; set; } + + /// + /// Gets or sets the maximum number of Player on the server since restart. + /// + public int TopPlayer { get; set; } + + /// + /// Gets the number of Player. + /// + public int PlayerCount { get; } + + /// + public bool IsAllowed { get; set; } + } +} diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 4ec235db18..ac058b4629 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -15,6 +15,7 @@ namespace Exiled.Events.Handlers.Internal using Exiled.API.Extensions; using Exiled.API.Features; using Exiled.API.Features.Core.UserSettings; + using Exiled.API.Features.Doors; using Exiled.API.Features.Items; using Exiled.API.Features.Pools; using Exiled.API.Features.Roles; @@ -23,17 +24,14 @@ namespace Exiled.Events.Handlers.Internal using Exiled.Events.EventArgs.Scp049; using Exiled.Loader; using Exiled.Loader.Features; + using Interactables.Interobjects.DoorUtils; using InventorySystem; using InventorySystem.Items.Firearms.Attachments; using InventorySystem.Items.Firearms.Attachments.Components; using InventorySystem.Items.Usables; - using InventorySystem.Items.Usables.Scp244.Hypothermia; using InventorySystem.Items.Usables.Scp330; using PlayerRoles; - using PlayerRoles.FirstPersonControl; using PlayerRoles.RoleAssign; - using UnityEngine; - using Utils.Networking; using Utils.NonAllocLINQ; /// @@ -60,6 +58,10 @@ public static void OnWaitingForPlayers() if (Events.Instance.Config.Debug) Patches.Events.Map.Generating.Benchmark(); + + // TODO: Remove when this has been fixed https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/1560 + Door door = Door.Get(DoorType.Scp079Armory); + door.AllowsScp106 = false; } /// diff --git a/EXILED/Exiled.Events/Handlers/Server.cs b/EXILED/Exiled.Events/Handlers/Server.cs index 80453625bb..caef937bff 100644 --- a/EXILED/Exiled.Events/Handlers/Server.cs +++ b/EXILED/Exiled.Events/Handlers/Server.cs @@ -32,6 +32,11 @@ public static class Server /// public static Event RoundStarted { get; set; } = new(); + /// + /// Invoked after the start of a new round. + /// + public static Event RoundStarting { get; set; } = new(); + /// /// Invoked after all players have spawned at the start of a new round. /// @@ -137,6 +142,12 @@ public static class Server /// public static void OnWaitingForPlayers() => WaitingForPlayers.InvokeSafely(); + /// + /// Called before the start of a new round. + /// + /// The instance. + public static void OnRoundStarting(RoundStartingEventArgs ev) => RoundStarting.InvokeSafely(ev); + /// /// Called after the start of a new round. /// diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ChangingRoleAndSpawned.cs b/EXILED/Exiled.Events/Patches/Events/Player/ChangingRoleAndSpawned.cs index ae3bf2a26e..5a0768d7f8 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/ChangingRoleAndSpawned.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/ChangingRoleAndSpawned.cs @@ -23,6 +23,8 @@ namespace Exiled.Events.Patches.Events.Player using InventorySystem.Items.Armor; using InventorySystem.Items.Pickups; using InventorySystem.Items.Usables.Scp1344; + using LabApi.Events.Arguments.PlayerEvents; + using LabApi.Events.Handlers; using Mirror; using PlayerRoles; @@ -230,6 +232,7 @@ private static void ChangeInventory(ChangingRoleEventArgs ev) InventoryItemProvider.OnItemProvided?.Invoke(ev.Player.ReferenceHub, itemBase); } + PlayerEvents.OnReceivedLoadout(new PlayerReceivedLoadoutEventArgs(ev.Player.ReferenceHub, ev.Items, ev.Ammo, !ev.ShouldPreserveInventory)); InventoryItemProvider.InventoriesToReplenish.Enqueue(ev.Player.ReferenceHub); } catch (Exception exception) diff --git a/EXILED/Exiled.Events/Patches/Events/Player/PreAuthenticating.cs b/EXILED/Exiled.Events/Patches/Events/Player/PreAuthenticating.cs index 160b2992bc..10386c48d1 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/PreAuthenticating.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/PreAuthenticating.cs @@ -7,7 +7,6 @@ namespace Exiled.Events.Patches.Events.Player { - using System; using System.Collections.Generic; using System.Reflection.Emit; @@ -17,7 +16,6 @@ namespace Exiled.Events.Patches.Events.Player using HarmonyLib; - using Hazards; using LiteNetLib; using static HarmonyLib.AccessTools; @@ -34,13 +32,7 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); - Label ret = generator.DefineLabel(); - newInstructions[newInstructions.Count - 1].labels.Add(ret); - LocalBuilder ev = generator.DeclareLocal(typeof(PreAuthenticatingEventArgs)); - int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ldstr && instruction.operand == (object)"{0};{1};{2};{3}"); - - Label cont = generator.DefineLabel(); - newInstructions[index].labels.Add(cont); + int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ldstr && instruction.operand == (object)"{0};{1};{2};{3}"); newInstructions.InsertRange( index, @@ -72,8 +64,6 @@ private static IEnumerable Transpiler(IEnumerable +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Server +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using System.Reflection.Emit; + + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.Events.EventArgs.Server; + using HarmonyLib; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// Adds the event. + /// + [HarmonyPatch] + internal class RoundStarting + { + #pragma warning disable SA1600 // Elements should be documented + public static Type PrivateType { get; internal set; } + + private static MethodInfo TargetMethod() + { + PrivateType = typeof(CharacterClassManager).GetNestedTypes(all) + .FirstOrDefault(currentType => currentType.Name.Contains("Init")); + if (PrivateType == null) + throw new Exception("State machine type for Init not found."); + MethodInfo moveNextMethod = PrivateType.GetMethod("MoveNext", all); + + if (moveNextMethod == null) + throw new Exception("MoveNext method not found in the state machine type."); + return moveNextMethod; + } + + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + const string TimeLeft = "5__3"; + const string OriginalTimeLeft = "5__2"; + const string TopPlayer = "5__4"; + + LocalBuilder ev = generator.DeclareLocal(typeof(RoundStartingEventArgs)); + int offset = -4; + int index = newInstructions.FindLastIndex(x => x.Calls(Method(typeof(CharacterClassManager), nameof(CharacterClassManager.ForceRoundStart)))) + offset; + + List