diff --git a/EXILED/EXILED.sln b/EXILED/EXILED.sln index 60b7f5f72c..6c48410428 100644 --- a/EXILED/EXILED.sln +++ b/EXILED/EXILED.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.4.33205.214 +# Visual Studio Version 18 +VisualStudioVersion = 18.3.11512.155 d18.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exiled.Events", "Exiled.Events\Exiled.Events.csproj", "{1E6C4350-5067-4CE7-91DB-6420D027A4FC}" EndProject @@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exiled.CustomRoles", "Exile EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "docs", "docs\docs.csproj", "{BE130A80-6819-44C6-AA1B-BF068DEA67FF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Exiled.Utility", "Exiled.Utility\Exiled.Utility.csproj", "{70A4E012-0DBB-18AA-A972-770281EEF726}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -82,6 +84,12 @@ Global {BE130A80-6819-44C6-AA1B-BF068DEA67FF}.Installer|Any CPU.Build.0 = Installer|Any CPU {BE130A80-6819-44C6-AA1B-BF068DEA67FF}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE130A80-6819-44C6-AA1B-BF068DEA67FF}.Release|Any CPU.Build.0 = Release|Any CPU + {70A4E012-0DBB-18AA-A972-770281EEF726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70A4E012-0DBB-18AA-A972-770281EEF726}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70A4E012-0DBB-18AA-A972-770281EEF726}.Installer|Any CPU.ActiveCfg = Installer|Any CPU + {70A4E012-0DBB-18AA-A972-770281EEF726}.Installer|Any CPU.Build.0 = Installer|Any CPU + {70A4E012-0DBB-18AA-A972-770281EEF726}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70A4E012-0DBB-18AA-A972-770281EEF726}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/EXILED/Exiled.API/Enums/PrefabType.cs b/EXILED/Exiled.API/Enums/PrefabType.cs index 43936f1d80..c3ce00898d 100644 --- a/EXILED/Exiled.API/Enums/PrefabType.cs +++ b/EXILED/Exiled.API/Enums/PrefabType.cs @@ -12,6 +12,7 @@ namespace Exiled.API.Enums /// /// Type of prefab. /// + /// public enum PrefabType { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 522a0a2113..9d500ca681 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -1199,6 +1199,11 @@ public bool IsSpectatable /// public Footprint Footprint => new(ReferenceHub); + /// + /// Gets the player's UniqueLifeIdentifier. + /// + public int LifeIdentifier => ReferenceHub.roleManager.CurrentRole.UniqueLifeIdentifier; + /// /// Gets or sets a value indicating whether the player is spawn protected. /// diff --git a/EXILED/Exiled.API/Features/PrefabHelper.cs b/EXILED/Exiled.API/Features/PrefabHelper.cs index 179991e635..22579651ac 100644 --- a/EXILED/Exiled.API/Features/PrefabHelper.cs +++ b/EXILED/Exiled.API/Features/PrefabHelper.cs @@ -14,8 +14,8 @@ namespace Exiled.API.Features using Exiled.API.Enums; using Exiled.API.Features.Attributes; - using MapGeneration.Distributors; + using MapGeneration.RoomConnectors; using Mirror; using UnityEngine; @@ -57,6 +57,11 @@ public static PrefabAttribute GetPrefabAttribute(this PrefabType prefabType) /// Returns the . public static GameObject GetPrefab(PrefabType prefabType) { + if (prefabType is PrefabType.HCZOneSided or PrefabType.HCZTwoSided) + { + prefabType = PrefabType.HCZBreakableDoor; + } + if (Prefabs.TryGetValue(prefabType, out (GameObject, Component) prefab)) return prefab.Item1; @@ -112,6 +117,17 @@ public static GameObject Spawn(PrefabType prefabType, Vector3 position = default positionSync.Network_rotationY = (sbyte)Mathf.RoundToInt(rotation.Value.eulerAngles.y / 5.625F); } + if (prefabType is PrefabType.HCZOneSided or PrefabType.HCZTwoSided or PrefabType.HCZBreakableDoor) + { + newGameObject.GetComponent().Network_syncBitmask = prefabType switch + { + PrefabType.HCZTwoSided => 0b00000000, + PrefabType.HCZOneSided => 0b00000001, + PrefabType.HCZBreakableDoor => 0b00000011, + _ => 0 + }; + } + NetworkServer.Spawn(newGameObject); return newGameObject; diff --git a/EXILED/Exiled.API/Features/Roles/Scp0492Role.cs b/EXILED/Exiled.API/Features/Roles/Scp0492Role.cs index 7250aa4662..59aacd81ca 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp0492Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp0492Role.cs @@ -7,6 +7,8 @@ namespace Exiled.API.Features.Roles { + using System.Collections.Generic; + using PlayerRoles; using PlayerRoles.PlayableScps.HumeShield; using PlayerRoles.PlayableScps.Scp049; @@ -45,6 +47,11 @@ internal Scp0492Role(ZombieRole baseRole) ConsumeAbility = zombieConsumeAbility492; } + /// + /// Gets a list of players who are turned away from SCP-049 Sense Ability. + /// + public static HashSet TurnedPlayers { get; } = new(20); + /// public override RoleTypeId Type { get; } = RoleTypeId.Scp0492; diff --git a/EXILED/Exiled.Events/Config.cs b/EXILED/Exiled.Events/Config.cs index fd244f699b..4fea2e64ab 100644 --- a/EXILED/Exiled.Events/Config.cs +++ b/EXILED/Exiled.Events/Config.cs @@ -26,67 +26,18 @@ public sealed class Config : IConfig [Description("Indicates whether events are patched only if they have delegates subscribed to them")] public bool UseDynamicPatching { get; set; } = true; - /// - /// Gets or sets a value indicating whether SCP-173 can be blocked by the tutorial. - /// - [Description("Indicates whether SCP-173 can be blocked by the tutorial")] - public bool CanTutorialBlockScp173 { get; set; } = true; - - /// - /// Gets or sets a value indicating whether SCP-096 can be triggered by the tutorial. - /// - [Description("Indicates whether SCP-096 can be triggered by the tutorial")] - public bool CanTutorialTriggerScp096 { get; set; } = true; - - /// - /// Gets or sets a value indicating whether SCP-049 can activate the sense ability on tutorials. - /// - [Description("Indicates whether SCP-049 can sense tutorial players")] - public bool CanScp049SenseTutorial { get; set; } = true; - - /// - /// Gets or sets a value indicating whether tutorial is affected by SCP-079 scan. - /// - [Description("Indicates whether tutorial is affected by SCP-079 scan.")] - public bool TutorialNotAffectedByScp079Scan { get; set; } = false; - - /// - /// Gets or sets a value indicating whether flashbangs flash original thrower. - /// - [Description("Indicates whether flashbangs flash original thrower.")] - public bool CanFlashbangsAffectThrower { get; set; } = false; - /// /// Gets or sets a value indicating whether the name tracking (invisible EXILED version string added to the end of the server name) is enabled or not. /// [Description("Indicates whether the name tracking (invisible EXILED version string added to the end of the server name) is enabled or not")] public bool IsNameTrackingEnabled { get; set; } = true; - /// - /// Gets or sets a value indicating whether the inventory should be dropped before being set as spectator, through commands or plugins. - /// - [Description("Indicates whether the inventory should be dropped before being set as spectator, through commands or plugins")] - public bool ShouldDropInventory { get; set; } = true; - - /// - /// Gets or sets a value indicating whether the blood can be spawned. - /// - [Description("Indicates whether the blood can be spawned")] - public bool CanSpawnBlood { get; set; } = true; - /// /// Gets or sets a value indicating whether keycard throw can affect basic doors. /// - /// TODO: Make a poll about removing this config. (unimplemented since 9.6.0-beta7) [Description("Indicates whether thrown keycards can affect doors that don't require any permissions")] public bool CanKeycardThrowAffectDoors { get; set; } = false; - /// - /// Gets or sets a value indicating whether the SCP079 will recontained if there are no SCPs left. - /// - [Description("Indicates whether the SCP079 will recontained if there are no SCPs left.")] - public bool RecontainScp079IfNoScpsLeft { get; set; } = true; - /// /// Gets or sets a value indicating whether configs has to be reloaded every time a round restarts. /// diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index f01919aff5..fb3cbdaa20 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -65,7 +65,6 @@ public override void OnEnabled() Handlers.Server.WaitingForPlayers += Handlers.Internal.Round.OnWaitingForPlayers; Handlers.Server.RestartingRound += Handlers.Internal.Round.OnRestartingRound; Handlers.Server.RoundStarted += Handlers.Internal.Round.OnRoundStarted; - Handlers.Player.ChangingRole += Handlers.Internal.Round.OnChangingRole; Handlers.Player.SpawningRagdoll += Handlers.Internal.Round.OnSpawningRagdoll; Handlers.Scp049.ActivatingSense += Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified += Handlers.Internal.Round.OnVerified; @@ -113,7 +112,6 @@ public override void OnDisabled() Handlers.Server.WaitingForPlayers -= Handlers.Internal.Round.OnWaitingForPlayers; Handlers.Server.RestartingRound -= Handlers.Internal.Round.OnRestartingRound; Handlers.Server.RoundStarted -= Handlers.Internal.Round.OnRoundStarted; - Handlers.Player.ChangingRole -= Handlers.Internal.Round.OnChangingRole; Handlers.Player.SpawningRagdoll -= Handlers.Internal.Round.OnSpawningRagdoll; Handlers.Scp049.ActivatingSense -= Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified -= Handlers.Internal.Round.OnVerified; diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index cebcffa749..015a9fe7d8 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -82,13 +82,6 @@ public static void OnRestartingRound() /// public static void OnRoundStarted() => MultiAdminFeatures.CallEvent(MultiAdminFeatures.EventType.ROUND_START); - /// - public static void OnChangingRole(ChangingRoleEventArgs ev) - { - if (!ev.Player.IsHost && ev.NewRole == RoleTypeId.Spectator && ev.Reason is not SpawnReason.Destroyed && Events.Instance.Config.ShouldDropInventory) - ev.Player.Inventory.ServerDropEverything(); - } - /// public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { @@ -104,7 +97,7 @@ public static void OnActivatingSense(ActivatingSenseEventArgs ev) { if (ev.Target is null) return; - if ((Events.Instance.Config.CanScp049SenseTutorial || ev.Target.Role.Type is not RoleTypeId.Tutorial) && !Scp049Role.TurnedPlayers.Contains(ev.Target)) + if (!Scp049Role.TurnedPlayers.Contains(ev.Target)) return; ev.Target = ev.Scp049.SenseAbility.CanFindTarget(out ReferenceHub hub) ? Player.Get(hub) : null; } diff --git a/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFlashGrenade.cs b/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFlashGrenade.cs index 88549bc13a..f376123a9e 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFlashGrenade.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFlashGrenade.cs @@ -26,7 +26,7 @@ namespace Exiled.Events.Patches.Events.Map /// /// Patches . - /// Adds the event and . + /// Adds the event"/>. /// [HarmonyPatch(typeof(FlashbangGrenade), nameof(FlashbangGrenade.ServerFuseEnd))] internal static class ExplodingFlashGrenade @@ -69,10 +69,8 @@ private static void ProcessEvent(FlashbangGrenade instance, float distance) if ((instance.transform.position - player.Position).sqrMagnitude > distance) continue; - if (!ExiledEvents.Instance.Config.CanFlashbangsAffectThrower && instance.PreviousOwner.CompareLife(player.ReferenceHub)) - continue; - - if (!IndividualFriendlyFire.CheckFriendlyFirePlayer(instance.PreviousOwner, player.ReferenceHub) && !instance.PreviousOwner.CompareLife(player.ReferenceHub)) + // LifeIdentifier check is needed to fix NW Bug https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/2811 + if (!IndividualFriendlyFire.CheckFriendlyFirePlayer(instance.PreviousOwner, player.ReferenceHub) && instance.PreviousOwner.LifeIdentifier == player.Footprint.LifeIdentifier) continue; if (Physics.Linecast(instance.transform.position, player.CameraTransform.position, instance.BlindingMask)) diff --git a/EXILED/Exiled.Events/Patches/Events/Scp0492/TriggeringBloodlustEvent.cs b/EXILED/Exiled.Events/Patches/Events/Scp0492/TriggeringBloodlustEvent.cs index 32cd7264d0..722e94f1e6 100644 --- a/EXILED/Exiled.Events/Patches/Events/Scp0492/TriggeringBloodlustEvent.cs +++ b/EXILED/Exiled.Events/Patches/Events/Scp0492/TriggeringBloodlustEvent.cs @@ -12,6 +12,7 @@ namespace Exiled.Events.Patches.Events.Scp0492 using Exiled.API.Features; using Exiled.API.Features.Pools; + using Exiled.API.Features.Roles; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Scp0492; @@ -38,17 +39,31 @@ private static IEnumerable Transpiler(IEnumerable), nameof(HashSet.Contains))), + new(OpCodes.Brfalse_S, continueLabel), }); for (int z = 0; z < newInstructions.Count; z++) diff --git a/EXILED/Exiled.Events/Patches/Generic/CanScp049SenseTutorial.cs b/EXILED/Exiled.Events/Patches/Generic/CanScp049SenseTutorial.cs index 01d7daaee5..222d4ecd73 100644 --- a/EXILED/Exiled.Events/Patches/Generic/CanScp049SenseTutorial.cs +++ b/EXILED/Exiled.Events/Patches/Generic/CanScp049SenseTutorial.cs @@ -20,11 +20,9 @@ namespace Exiled.Events.Patches.Generic using static HarmonyLib.AccessTools; - using ExiledEvents = Exiled.Events.Events; - /// /// Patches . - /// . + /// . /// [HarmonyPatch(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.CanFindTarget))] internal static class CanScp049SenseTutorial @@ -36,7 +34,6 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Brfalse); Label continueLabel = (Label)newInstructions[index].operand; - Label skip = generator.DefineLabel(); index += 1; @@ -46,22 +43,8 @@ private static IEnumerable Transpiler(IEnumerable), nameof(Plugin.Config))), - new(OpCodes.Callvirt, PropertyGetter(typeof(Config), nameof(Config.CanScp049SenseTutorial))), - new(OpCodes.Brfalse_S, continueLabel), - // if (Scp049Role.TurnedPlayers.Contains(Player.Get(referenceHub))) - new CodeInstruction(OpCodes.Call, PropertyGetter(typeof(API.Features.Roles.Scp049Role), nameof(API.Features.Roles.Scp049Role.TurnedPlayers))).WithLabels(skip), + new CodeInstruction(OpCodes.Call, PropertyGetter(typeof(API.Features.Roles.Scp049Role), nameof(API.Features.Roles.Scp049Role.TurnedPlayers))), new(OpCodes.Ldloc_S, 6), new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), new(OpCodes.Callvirt, Method(typeof(HashSet), nameof(HashSet.Contains))), diff --git a/EXILED/Exiled.Events/Patches/Generic/ParseVisionInformation.cs b/EXILED/Exiled.Events/Patches/Generic/ParseVisionInformation.cs index 42e6c1013d..86b2bd91de 100644 --- a/EXILED/Exiled.Events/Patches/Generic/ParseVisionInformation.cs +++ b/EXILED/Exiled.Events/Patches/Generic/ParseVisionInformation.cs @@ -38,37 +38,16 @@ private static IEnumerable Transpiler(IEnumerable), nameof(Plugin.Config))), - new(OpCodes.Callvirt, PropertyGetter(typeof(Config), nameof(Config.CanTutorialTriggerScp096))), - new(OpCodes.Brfalse_S, returnLabel), - - // || Scp096Role.TurnedPlayers.Contains(Player.Get(referenceHub)) - new CodeInstruction(OpCodes.Call, PropertyGetter(typeof(Scp096Role), nameof(Scp096Role.TurnedPlayers))).WithLabels(secondCheckPointer), + // if (!Scp096Role.TurnedPlayers.Contains(Player.Get(referenceHub))) + new CodeInstruction(OpCodes.Call, PropertyGetter(typeof(Scp096Role), nameof(Scp096Role.TurnedPlayers))), new(OpCodes.Ldarg_1), new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), new(OpCodes.Callvirt, Method(typeof(HashSet), nameof(HashSet.Contains))), diff --git a/EXILED/Exiled.Events/Patches/Generic/Scp079Scan.cs b/EXILED/Exiled.Events/Patches/Generic/Scp079Scan.cs index 6b4b93e406..b3bd692607 100644 --- a/EXILED/Exiled.Events/Patches/Generic/Scp079Scan.cs +++ b/EXILED/Exiled.Events/Patches/Generic/Scp079Scan.cs @@ -41,20 +41,6 @@ private static IEnumerable Transpiler(IEnumerable), nameof(Plugin.Config))), - new(OpCodes.Callvirt, PropertyGetter(typeof(Config), nameof(Config.TutorialNotAffectedByScp079Scan))), - new(OpCodes.Brfalse_S, returnLabel), - // if (Scp079Role.TurnedPlayers.Contains(Player.Get(referenceHub))) new CodeInstruction(OpCodes.Call, PropertyGetter(typeof(API.Features.Roles.Scp079Role), nameof(API.Features.Roles.Scp079Role.TurnedPlayers))).WithLabels(skip), new(OpCodes.Ldarg_1), diff --git a/EXILED/Exiled.Events/Patches/Generic/Scp173BeingLooked.cs b/EXILED/Exiled.Events/Patches/Generic/Scp173BeingLooked.cs index aadad0c087..763b23f88c 100644 --- a/EXILED/Exiled.Events/Patches/Generic/Scp173BeingLooked.cs +++ b/EXILED/Exiled.Events/Patches/Generic/Scp173BeingLooked.cs @@ -69,7 +69,7 @@ private static IEnumerable Transpiler(IEnumerable +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Utility.Commands +{ + using System; + using System.Linq; + + using CommandSystem; + using Exiled.API.Enums; + using Exiled.API.Features; + + /// + /// Command for spawning . + /// + [CommandHandler(typeof(RemoteAdminCommandHandler))] + public class SpawnPrefabType : ICommand, IUsageProvider + { + /// + public string Command { get; } = "PrefabType"; + + /// + public string[] Aliases { get; } = Array.Empty(); + + /// + public string Description { get; } = "Spawning PrefabType"; + + /// + public string[] Usage { get; } = new string[] { $"{string.Join(", ", EnumUtils.Names)}", }; + + /// + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + if (!sender.CheckPermission(PlayerPermissions.FacilityManagement, out response)) + { + return false; + } + + Player.TryGet(sender, out Player player); + if (player is null) + { + response = "You must be a player to use this command."; + return false; + } + + if (arguments.Count < 1) + { + response = $"Please, use: {Command} {string.Join(", ", EnumUtils.Names)}"; + return false; + } + + if (!Enum.TryParse(arguments.At(0), out PrefabType prefabType)) + { + response = $"\"{arguments.At(0)}\" is not a valid prefab type."; + return false; + } + + PrefabHelper.Spawn(prefabType, player.Position, player.Rotation); + + response = "Spawning prefab type..."; + return true; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Commands/TpsCommand.cs b/EXILED/Exiled.Utility/Commands/TpsCommand.cs similarity index 97% rename from EXILED/Exiled.Events/Commands/TpsCommand.cs rename to EXILED/Exiled.Utility/Commands/TpsCommand.cs index 14c0def05e..dcbe781824 100644 --- a/EXILED/Exiled.Events/Commands/TpsCommand.cs +++ b/EXILED/Exiled.Utility/Commands/TpsCommand.cs @@ -5,7 +5,7 @@ // // ----------------------------------------------------------------------- -namespace Exiled.Events.Commands +namespace Exiled.Utility.Commands { using System; diff --git a/EXILED/Exiled.Utility/Config.cs b/EXILED/Exiled.Utility/Config.cs new file mode 100644 index 0000000000..2d3bccebab --- /dev/null +++ b/EXILED/Exiled.Utility/Config.cs @@ -0,0 +1,60 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Utility +{ + using System.Collections.Generic; + using System.ComponentModel; + + using API.Interfaces; + using Decals; + using Exiled.Utility.Enums; + using PlayerRoles; + + /// + public sealed class Config : IConfig + { + /// + public bool IsEnabled { get; set; } = true; + + /// + public bool Debug { get; set; } + + /// + /// Gets or sets a value indicating whether SCP-173 can be blocked by the tutorial. + /// + [Description("Indicates whether RoleTypeId or CustomRole(Name or Id) prevented behaviours")] + public Dictionary NewStuffThatWasAboutTutorial { get; set; } = new() + { + { RoleTypeId.Tutorial.ToString(), NewEnumForAllStuffThatWasAboutTutorial.None }, + }; + + /// + /// Gets or sets a value indicating whether flashbangs flash original thrower. + /// + [Description("Indicates whether flashbangs flash original thrower.")] + public bool CanFlashbangsAffectThrower { get; set; } = false; + + /// + /// Gets or sets a value indicating whether the inventory should be dropped before being set as spectator, through commands or plugins. + /// + [Description("Indicates whether the inventory should be dropped before being set as spectator, through commands or plugins")] + public bool ShouldDropInventory { get; set; } = false; + + /// + /// Gets or sets a value indicating whether Decal spawned. + /// + [Description("Indicates whether the Decal (Blood, Bullet, Buckshot, GlassCrack) can be spawned")] + public List PreventDecalSpawn { get; set; } = new() { }; + + /// + /// Gets or sets a value indicating whether the SCP079 will recontained if there are no SCPs left. + /// + [Description("Indicates whether the SCP079 will recontained if there are no SCPs left.")] + public bool RecontainScp079IfNoScpsLeft { get; set; } = true; + } +} diff --git a/EXILED/Exiled.Utility/Enums/NewEnumForAllStuffThatWasAboutTutorial.cs b/EXILED/Exiled.Utility/Enums/NewEnumForAllStuffThatWasAboutTutorial.cs new file mode 100644 index 0000000000..d16b35ac30 --- /dev/null +++ b/EXILED/Exiled.Utility/Enums/NewEnumForAllStuffThatWasAboutTutorial.cs @@ -0,0 +1,53 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Utility.Enums +{ + using System; + + /// + /// All available screen aspect ratio types. + /// + [Flags] + public enum NewEnumForAllStuffThatWasAboutTutorial + { + /// + /// All. + /// + All = -1, + + /// + /// None. + /// + None = 0, + + /// + /// Prevent from blocking Scp173. + /// + CanBlockScp173 = 1, + + /// + /// Prevent from being target of Scp096. + /// + CanTriggerScp096 = 2, + + /// + /// Prevent from being target of Scp049 and stagger Scp0492. + /// + CanScp049Sense = 4, + + /// + /// Prevent from being target of Scp049 and stagger Scp0492. + /// + CanScp0492Sense = 4, + + /// + /// Prevent Player to be Alarmed by Scp079. + /// + NotAffectedByScp079Scan = 16, + } +} diff --git a/EXILED/Exiled.Utility/EventHandler.cs b/EXILED/Exiled.Utility/EventHandler.cs new file mode 100644 index 0000000000..7f1e958720 --- /dev/null +++ b/EXILED/Exiled.Utility/EventHandler.cs @@ -0,0 +1,112 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Utility +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + using Decals; + using Exiled.API.Enums; + using Exiled.API.Features; + using Exiled.API.Features.Roles; + using Exiled.CustomRoles.API.Features; + using Exiled.Events.EventArgs.Map; + using Exiled.Events.EventArgs.Player; + using Exiled.Utility.Enums; + using InventorySystem; + using InventorySystem.Items.Firearms.Modules; + using PlayerRoles; + +#pragma warning disable CS1591 // Commentaire XML manquant pour le type ou le membre visible publiquement +#pragma warning disable SA1600 // Elements should be documented + public class EventHandler + { + public Config Config { get; internal set; } + + public void OnWaitingForPlayers() + { + if (!Config.RecontainScp079IfNoScpsLeft) + PlayerRoleManager.OnServerRoleSet -= Recontainer.Base.OnServerRoleChanged; + } + + /// + public void OnChangingRole(ChangingRoleEventArgs ev) + { + if (!ev.Player.IsHost && ev.NewRole == RoleTypeId.Spectator && ev.Reason is not SpawnReason.Destroyed && Config.ShouldDropInventory) + ev.Player.Inventory.ServerDropEverything(); + } + + public void OnSpawned(SpawnedEventArgs ev) + { + Scp173Role.TurnedPlayers.Remove(ev.Player); + Scp096Role.TurnedPlayers.Remove(ev.Player); + Scp049Role.TurnedPlayers.Remove(ev.Player); + Scp0492Role.TurnedPlayers.Remove(ev.Player); + Scp079Role.TurnedPlayers.Remove(ev.Player); + string role = ev.Player.Role.Type.ToString(); + foreach (CustomRole customRole in CustomRole.Registered) + { + if (customRole.Check(ev.Player)) + { + role = customRole.Name; + break; + } + } + + if (Config.NewStuffThatWasAboutTutorial.TryGetValue(role, out NewEnumForAllStuffThatWasAboutTutorial bruh)) + { + if (bruh.HasFlag(NewEnumForAllStuffThatWasAboutTutorial.CanBlockScp173)) + { + Scp173Role.TurnedPlayers.Add(ev.Player); + } + + if (bruh.HasFlag(NewEnumForAllStuffThatWasAboutTutorial.CanTriggerScp096)) + { + Scp096Role.TurnedPlayers.Add(ev.Player); + } + + if (bruh.HasFlag(NewEnumForAllStuffThatWasAboutTutorial.CanScp049Sense)) + { + Scp049Role.TurnedPlayers.Add(ev.Player); + } + + if (bruh.HasFlag(NewEnumForAllStuffThatWasAboutTutorial.CanScp0492Sense)) + { + Scp0492Role.TurnedPlayers.Add(ev.Player); + } + + if (bruh.HasFlag(NewEnumForAllStuffThatWasAboutTutorial.NotAffectedByScp079Scan)) + { + Scp079Role.TurnedPlayers.Add(ev.Player); + } + } + } + + public void OnPlacingBulletHole(PlacingBulletHoleEventArgs ev) + { + ImpactEffectsModule impactEffectsModule = ev.Firearm.HitscanHitregModule._impactEffectsModule; + int? num = null; + for (int i = 0; i < impactEffectsModule.AttachmentOverrides.Length; i++) + { + if (impactEffectsModule.AttachmentOverrides[i].GetEnabled(ev.Firearm.Base)) + { + num = new int?(i); + break; + } + } + + DecalPoolType decalPoolType = ev.Firearm.HitscanHitregModule._impactEffectsModule.GetSettings(num).BulletholeDecal; + + if (Config.PreventDecalSpawn.Contains(decalPoolType)) + ev.IsAllowed = false; + } + } +} diff --git a/EXILED/Exiled.Utility/Exiled.Utility.csproj b/EXILED/Exiled.Utility/Exiled.Utility.csproj new file mode 100644 index 0000000000..fb8692eb27 --- /dev/null +++ b/EXILED/Exiled.Utility/Exiled.Utility.csproj @@ -0,0 +1,57 @@ + + + + + Library + Exiled.Utility + true + Debug;Release;Installer + AnyCPU + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + if not "$(EXILED_DEV_REFERENCES)"=="" copy /y "$(OutputPath)$(AssemblyName).dll" "$(EXILED_DEV_REFERENCES)\Plugins\" + + + if [[ ! -z "$EXILED_DEV_REFERENCES" ]]; then cp "$(OutputPath)$(AssemblyName).dll" "$EXILED_DEV_REFERENCES/Plugins/"; fi + + + diff --git a/EXILED/Exiled.Events/Patches/Generic/Scp079Recontain.cs b/EXILED/Exiled.Utility/Patches/Scp079Recontain.cs similarity index 91% rename from EXILED/Exiled.Events/Patches/Generic/Scp079Recontain.cs rename to EXILED/Exiled.Utility/Patches/Scp079Recontain.cs index f92a59482f..3ce9e801dc 100644 --- a/EXILED/Exiled.Events/Patches/Generic/Scp079Recontain.cs +++ b/EXILED/Exiled.Utility/Patches/Scp079Recontain.cs @@ -5,7 +5,7 @@ // // ----------------------------------------------------------------------- -namespace Exiled.Events.Patches.Generic +namespace Exiled.Utility.Patches { using System.Collections.Generic; using System.Reflection.Emit; @@ -37,8 +37,8 @@ private static IEnumerable Transpiler(IEnumerable +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Utility +{ + using System; + + using API.Enums; + using Exiled.API.Features; + using HarmonyLib; + + /// + /// Patch and unpatch events into the game. + /// + public sealed class Utility : Plugin + { + /// + /// Gets the plugin instance. + /// + public static Utility Instance { get; private set; } + + /// + /// Gets the eventHandler. + /// + public static EventHandler EventHandler { get; private set; } + + /// + /// Gets the Harmony instance. + /// + public static Harmony Harmony { get; private set; } + + /// + public override PluginPriority Priority { get; } = PluginPriority.Higher; + + /// + public override void OnEnabled() + { + Instance = this; + EventHandler = new EventHandler + { + Config = Config, + }; + Events.Handlers.Player.ChangingRole += EventHandler.OnChangingRole; + Events.Handlers.Server.WaitingForPlayers += EventHandler.OnWaitingForPlayers; + Events.Handlers.Map.PlacingBulletHole += EventHandler.OnPlacingBulletHole; + + // BloodDecal is Missing + Patch(); + base.OnEnabled(); + } + + /// + public override void OnDisabled() + { + base.OnDisabled(); + Events.Handlers.Player.ChangingRole += EventHandler.OnChangingRole; + Events.Handlers.Server.WaitingForPlayers += EventHandler.OnWaitingForPlayers; + Events.Handlers.Map.PlacingBulletHole += EventHandler.OnPlacingBulletHole; + Unpatch(); + } + + /// + /// Patches all events. + /// + public void Patch() + { + Harmony = new Harmony($"com.{nameof(Utility)}.ExiledTeam-{DateTime.Now.Ticks}"); + GlobalPatchProcessor.PatchAll(Harmony, out int failedPatch); + if (failedPatch != 0) + Log.Error($"Patching failed! There are {failedPatch} broken patches."); + } + + /// + /// Unpatches all events. + /// + public void Unpatch() + { + Harmony.UnpatchAll(Harmony.Id); + Harmony = null; + } + } +} diff --git a/EXILED/build.ps1 b/EXILED/build.ps1 index 2b4f5a54c8..07b30ee294 100644 --- a/EXILED/build.ps1 +++ b/EXILED/build.ps1 @@ -9,6 +9,7 @@ $Projects = @( 'Exiled.API', 'Exiled.Permissions', 'Exiled.Events', + 'Exiled.Utility', 'Exiled.CreditTags', 'Exiled.Example', 'Exiled.CustomItems',