From d2e3f8cf70e57b49d9a302a7589247a20e3eb83e Mon Sep 17 00:00:00 2001 From: Yamato Date: Mon, 23 Dec 2024 16:40:22 +0100 Subject: [PATCH 01/56] StoredComponent --- EXILED/Exiled.API/Features/PrefabHelper.cs | 12 ++++++------ .../Exiled.Events/Handlers/Internal/ClientStarted.cs | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/EXILED/Exiled.API/Features/PrefabHelper.cs b/EXILED/Exiled.API/Features/PrefabHelper.cs index 82180ac9a6..e51ed94f58 100644 --- a/EXILED/Exiled.API/Features/PrefabHelper.cs +++ b/EXILED/Exiled.API/Features/PrefabHelper.cs @@ -24,12 +24,12 @@ public static class PrefabHelper /// /// A containing all and their corresponding . /// - internal static readonly Dictionary Prefabs = new(Enum.GetValues(typeof(PrefabType)).Length); + internal static readonly Dictionary Prefabs = new(Enum.GetValues(typeof(PrefabType)).Length); /// /// Gets a of and their corresponding . /// - public static IReadOnlyDictionary PrefabToGameObject => Prefabs; + public static IReadOnlyDictionary PrefabToGameObject => Prefabs; /// /// Gets the from a . @@ -49,8 +49,8 @@ public static PrefabAttribute GetPrefabAttribute(this PrefabType prefabType) /// Returns the . public static GameObject GetPrefab(PrefabType prefabType) { - if (Prefabs.TryGetValue(prefabType, out GameObject prefab)) - return prefab; + if (Prefabs.TryGetValue(prefabType, out (GameObject, Component) prefab)) + return prefab.Item1; return null; } @@ -76,8 +76,8 @@ public static bool TryGetPrefab(PrefabType prefabType, out GameObject gameObject public static T GetPrefab(PrefabType prefabType) where T : Component { - if (Prefabs.TryGetValue(prefabType, out GameObject prefab) && prefab.TryGetComponent(out T component)) - return component; + if (Prefabs.TryGetValue(prefabType, out (GameObject, Component) prefab)) + return (T)prefab.Item2; return null; } diff --git a/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs b/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs index a260cf4957..4607dd71f4 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs @@ -29,24 +29,24 @@ public static void OnClientStarted() { PrefabHelper.Prefabs.Clear(); - Dictionary prefabs = new(); + Dictionary prefabs = new(); foreach (KeyValuePair prefab in NetworkClient.prefabs) { - if(!prefabs.ContainsKey(prefab.Key)) - prefabs.Add(prefab.Key, prefab.Value); + if(!prefabs.ContainsKey(prefab.Key) && prefab.Value.TryGetComponent(out Component component)) + prefabs.Add(prefab.Key, (prefab.Value, component)); } foreach (NetworkIdentity ragdollPrefab in RagdollManager.AllRagdollPrefabs) { - if(!prefabs.ContainsKey(ragdollPrefab.assetId)) - prefabs.Add(ragdollPrefab.assetId, ragdollPrefab.gameObject); + if(!prefabs.ContainsKey(ragdollPrefab.assetId) && ragdollPrefab.gameObject.TryGetComponent(out Component component)) + prefabs.Add(ragdollPrefab.assetId, (ragdollPrefab.gameObject, component)); } foreach (PrefabType prefabType in EnumUtils.Values) { PrefabAttribute attribute = prefabType.GetPrefabAttribute(); - PrefabHelper.Prefabs.Add(prefabType, prefabs.FirstOrDefault(prefab => prefab.Key == attribute.AssetId || prefab.Value.name.Contains(attribute.Name)).Value); + PrefabHelper.Prefabs.Add(prefabType, prefabs.FirstOrDefault(prefab => prefab.Key == attribute.AssetId || prefab.Value.Item1.name.Contains(attribute.Name)).Value); } } } From aadc1c40f8928a48389bc18171e0b87c6f163ea8 Mon Sep 17 00:00:00 2001 From: Yamato Date: Mon, 23 Dec 2024 16:57:36 +0100 Subject: [PATCH 02/56] Fix BreakingChange --- EXILED/Exiled.API/Features/PrefabHelper.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/EXILED/Exiled.API/Features/PrefabHelper.cs b/EXILED/Exiled.API/Features/PrefabHelper.cs index e51ed94f58..cb17160b50 100644 --- a/EXILED/Exiled.API/Features/PrefabHelper.cs +++ b/EXILED/Exiled.API/Features/PrefabHelper.cs @@ -9,6 +9,7 @@ namespace Exiled.API.Features { using System; using System.Collections.Generic; + using System.Linq; using System.Reflection; using Exiled.API.Enums; @@ -29,7 +30,12 @@ public static class PrefabHelper /// /// Gets a of and their corresponding . /// - public static IReadOnlyDictionary PrefabToGameObject => Prefabs; + public static IReadOnlyDictionary PrefabToGameObjectAndComponent => Prefabs; + + /// + /// Gets a of and their corresponding . + /// + public static IReadOnlyDictionary PrefabToGameObject => Prefabs.ToDictionary(x => x.Key, x => x.Value.Item1); /// /// Gets the from a . From 431e389c62211fdaf4003a6e7c56cfb5bacf9ba3 Mon Sep 17 00:00:00 2001 From: Bolton <48883340+BoltonDev@users.noreply.github.com> Date: Sun, 18 May 2025 22:23:34 +0200 Subject: [PATCH 03/56] chore: update base game 14.1 (#527) * LabAPI Update (#435) * No error for build * Fix Exiled * Fix RoundEnding * Now is fucking separated by default * CustomSubtitles * Missing IsCustomAnnouncement * Fix 3 patch & removal of CustomHealthStat * Fix UsingAndCancellingItemUse * Fix TogglingFlashlight * La Flemme ? * La flemme 2 * Fix ReservedSlotPatch * Fix PickingUpItem(PickingUpAmmo) * Fix Hurt event * Fix FlippingCoin & EscapingPocketDimension * Fix FailingEscapePocketDimension * EscapingAndEscaped fix patch * Fix UpgradingPlayer patch * Fix BeingObserved * Fix PlacingTantrum * Fix FinishingRecall * ChangingCamera (Not working) * putting again the event than i was lazzy to fix * Rework InteractingDoor Patch missing removing the Prefix part lol & SkillIssueFix * Remove useless using and warning disable * OUPS * if stupidity was me it's here (i am stupid) * Fixing Noclip with breakingchange * CustomHumeShieldStat * Fix InteractingGenerator * Fix ChangingCamera * Not finish * InteractingDoor swap CanInteract & IsAllowed back to normal * Player::Gravity * Gravity in wrong place * IHumeShieldRole for Human * Fix BlastDoors & add OpenBlastDoor * Fix SpawningRagdoll Scale & missing argument when modify * Now fix in LabAPI only * we will keep the funny Ragdoll scale * Fix Merge & Split Command * new workflow for LabAPI * LabAPI Update 14.0.3 (#439) * No error for build * Fix Exiled * Fix RoundEnding * Now is fucking separated by default * CustomSubtitles * Missing IsCustomAnnouncement * Fix 3 patch & removal of CustomHealthStat * Fix UsingAndCancellingItemUse * Fix TogglingFlashlight * La Flemme ? * La flemme 2 * Fix ReservedSlotPatch * Fix PickingUpItem(PickingUpAmmo) * Fix Hurt event * Fix FlippingCoin & EscapingPocketDimension * Fix FailingEscapePocketDimension * EscapingAndEscaped fix patch * Fix UpgradingPlayer patch * Fix BeingObserved * Fix PlacingTantrum * Fix FinishingRecall * ChangingCamera (Not working) * putting again the event than i was lazzy to fix * Rework InteractingDoor Patch missing removing the Prefix part lol & SkillIssueFix * Remove useless using and warning disable * OUPS * if stupidity was me it's here (i am stupid) * Fixing Noclip with breakingchange * CustomHumeShieldStat * Fix InteractingGenerator * Fix ChangingCamera * Not finish * InteractingDoor swap CanInteract & IsAllowed back to normal * Player::Gravity * Gravity in wrong place * IHumeShieldRole for Human * Fix BlastDoors & add OpenBlastDoor * Fix SpawningRagdoll Scale & missing argument when modify * Now fix in LabAPI only * we will keep the funny Ragdoll scale * Fix Merge & Split Command * new workflow for LabAPI * NW_Documentation * SCP:SL LabAPI 14.0.3 * Fix One IL Error Patch (2 remain from previous update) * use Specific build for LabAPI * Miss updating this file * 9.6.0-beta3 * this will need to be revert * push_nuget not working for LabAPI * Fixing RoundEnd Patch * Adding CustomRole::Gravity * Remove Testing Log * fix: Command events fix (#444) command fixes * fix: Fixing UnlockingGenerator * Fix RoundEnd completelly * fix: Hurting event NRE fix (#443) fix: one day i'll kill person who made this Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com> * 9.6.0-beta4 * this will required to be revert * fix: InteractingDoorEvent::CanInteract (#463) * Fix InteractingDoorEvent::CanInteract * Oupsy * Fixed Error & InteractingScp330 IL Code * TODO: Fix THE CRASH ISSUE * Fix Consumed Event - doubt * Fix & Small change on UsingAndCancellingItemUse * Fix an issue where HashSetPool was never return * Fix IL CODE error & remove debug * Add warning in case of missing PrefabType * Capybara Toy * remove using * Fix SpawningRagdoll not setting NetworkInfo * Fix Ragdoll Scale & ConsumingEvent * Missing NetworkInfo.Scale Argument * Fix: Door.Get(GameObject) * TantrumHazard is always null * 9.6.0-beta5 * Update EXILED_DLL_ARCHIVER_URL for LabAPI * fix: use basegame validation for CustomInfo (#452) * Validate using basegame * Update EXILED/Exiled.API/Features/Player.cs --------- Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com> * feat: Custom limits for armor & virtual dmg for customweapon (#477) * fix: activating warhead panel event fix (#504) fix: fix for activating warhead panel * Fix Error (from Conflict) * Fix doc error * Fix few error * refactor!: update to 14.1 (#508) * refactor!: update to 14.1 * fix: few patches fix * feat: new custom keycard logic * fix: ActivatingWarheadPanel event * fix: checkpoint sequence time * fix: Shot event * fix: DroppingCandy event * Fix last Error on Release Build * Update new PrefabType * fix: AnnouncingScpTermination event * fix: SpawningItem event error (require testing) * fix: Shot.cs fix * analysis error * Fix error * Fix build error * NW_Documentation * fix: announcing wave entrance * Reference new Room * Fix Build error * fix: fixes pickingup event * Nameless Skill Issue * fix: locker patch * fix: spawning room connector * CameraToy * Get CameraToy * Finish InteractableToy & fix doc * fix Error for build * Remove todo * fix: generator events * ElevatorType.ServerRoom * Fix a 2 hours loss * Fix NW moment * fix: interacting generator * fix: interacting locker event * fix: missing obstacle shot * fix: KeycardInteracting again * Fix SendingCassieMessage * fix: temp fix interacting door (need to refactor) * refactor: change the property * fix doc * extension for Scp127 & ServerRoom * FirearmType.Scp127 * AdminToyList * fix: camera weren't added * new CameraType * wrong doc * fix: interacting door event (improved) * Invalid Camera * Better doc * fix: interacting door (bolton issue) * FixDamagingWindow index * RemoveBreakingChange * Fix FailingEscapePocketDimensionEventArgs --------- Co-authored-by: Bolton <48883340+BoltonDev@users.noreply.github.com> Co-authored-by: VALERA771 Co-authored-by: VALERA771 <72030575+VALERA771@users.noreply.github.com> * 9.6.0-beta6 * SNOWBALL DO NOT EXIST * fix: ChangingCamera event (#511) * fix: useless fix now & prevent crash (#512) * fix: EndingRound event IsAllowed (#513) fix: EndingRound event isallowed * bump: 9.6.0-beta7 * fix: few fixes (#514) * fix: keycard interacting * fix: EscapingEvent IsAllowed * fix: command type invalid * fix: landing event * fix: EscapingPocketDimension event * fix: Handcuffing / RemovingHandcuff events * fix: sentvalidcommand event * bump: 9.6.0-beta8 * fix: fix AutoUpdater Directory finder (#515) * Update Capybara.cs * Revert "Update Capybara.cs" This reverts commit 6ea4789dc4d8cb8bb7f429281b930133bc9be62c. * fix autoupdater * ok now its fixed 100% * fix: custom weapons not doing default damage when set to below 0 (#518) * fix custom weapons not doing default damage when set to below 0 * make default damage -1 * Workflow fix (#3) * v9.5.2 * Update release.yml * Update main.yml * update nuget * update docs * update dev * Fixing Error & Removing Property that will not be implmented * EffectType.Scp1344Detected * Update labapi.yml * Update labapi.yml * TextToy Implementation API * chore: remove hub (doesn't exist anymore) * fix: update exmod -> exslmod & bump: 9.6.0 * fix: missing some change * missing hub --------- Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com> Co-authored-by: Yamato Co-authored-by: VALERA771 <72030575+VALERA771@users.noreply.github.com> Co-authored-by: Nameless <85962933+Misfiy@users.noreply.github.com> Co-authored-by: SlejmUr Co-authored-by: VALERA771 Co-authored-by: Mike <146554836+MikeSus1@users.noreply.github.com> Co-authored-by: TtroubleTT <121741230+TtroubleTT@users.noreply.github.com> --- .github/workflows/dev.yml | 4 +- .github/workflows/docs.yml | 2 +- .github/workflows/labapi.yml | 74 +++ .github/workflows/main.yml | 2 +- .github/workflows/push_nuget.yml | 2 +- .github/workflows/release.yml | 4 +- EXILED/EXILED.props | 6 +- EXILED/Exiled.API/Enums/AdminToyType.cs | 20 + EXILED/Exiled.API/Enums/CameraType.cs | 14 + EXILED/Exiled.API/Enums/DamageType.cs | 5 + EXILED/Exiled.API/Enums/DoorType.cs | 19 + EXILED/Exiled.API/Enums/EffectType.cs | 5 + EXILED/Exiled.API/Enums/ElevatorType.cs | 5 + EXILED/Exiled.API/Enums/FirearmType.cs | 5 + EXILED/Exiled.API/Enums/GeneratorState.cs | 4 +- EXILED/Exiled.API/Enums/GlassType.cs | 5 + EXILED/Exiled.API/Enums/LockerType.cs | 5 + EXILED/Exiled.API/Enums/PrefabType.cs | 36 ++ EXILED/Exiled.API/Enums/RoomType.cs | 10 + EXILED/Exiled.API/Exiled.API.csproj | 2 +- .../Extensions/DamageTypeExtensions.cs | 1 + .../Extensions/DoorTypeExtensions.cs | 2 +- .../Extensions/EffectTypeExtension.cs | 1 + .../Exiled.API/Extensions/ItemExtensions.cs | 2 + .../Exiled.API/Extensions/LockerExtensions.cs | 1 + .../Exiled.API/Extensions/RoomExtensions.cs | 2 +- .../Extensions/UserGroupExtensions.cs | 4 +- EXILED/Exiled.API/Features/Camera.cs | 21 +- .../Exiled.API/Features/CustomHealthStat.cs | 26 - .../CustomStats/CustomHumeShieldStat.cs | 25 +- .../DamageHandlers/GenericDamageHandler.cs | 3 + EXILED/Exiled.API/Features/Doors/BasicDoor.cs | 6 +- .../Features/Doors/CheckpointDoor.cs | 18 +- EXILED/Exiled.API/Features/Doors/Door.cs | 34 +- .../Exiled.API/Features/Doors/ElevatorDoor.cs | 3 +- EXILED/Exiled.API/Features/Generator.cs | 14 +- .../Features/Hazards/TemporaryHazard.cs | 4 +- EXILED/Exiled.API/Features/Items/Armor.cs | 17 +- EXILED/Exiled.API/Features/Items/Keycard.cs | 45 +- EXILED/Exiled.API/Features/Items/Scp1344.cs | 2 +- EXILED/Exiled.API/Features/Lockers/Chamber.cs | 26 +- EXILED/Exiled.API/Features/Map.cs | 2 +- EXILED/Exiled.API/Features/Npc.cs | 13 +- EXILED/Exiled.API/Features/Paths.cs | 4 +- .../Pickups/ExplosiveGrenadePickup.cs | 4 +- .../Features/Pickups/KeycardPickup.cs | 17 +- .../Projectiles/ExplosionGrenadeProjectile.cs | 8 +- EXILED/Exiled.API/Features/Player.cs | 98 ++-- EXILED/Exiled.API/Features/Ragdoll.cs | 23 +- EXILED/Exiled.API/Features/Roles/FpcRole.cs | 27 +- EXILED/Exiled.API/Features/Roles/HumanRole.cs | 8 +- .../Exiled.API/Features/Roles/Scp049Role.cs | 38 +- .../Exiled.API/Features/Roles/Scp079Role.cs | 2 +- EXILED/Exiled.API/Features/Room.cs | 23 +- EXILED/Exiled.API/Features/Round.cs | 2 +- EXILED/Exiled.API/Features/Scp914.cs | 8 +- EXILED/Exiled.API/Features/Server.cs | 6 +- EXILED/Exiled.API/Features/Toys/AdminToy.cs | 4 + EXILED/Exiled.API/Features/Toys/CameraToy.cs | 83 +++ EXILED/Exiled.API/Features/Toys/Capybara.cs | 45 ++ .../Features/Toys/InteractableToy.cs | 61 +++ EXILED/Exiled.API/Features/Toys/Light.cs | 2 + EXILED/Exiled.API/Features/Toys/Text.cs | 55 ++ EXILED/Exiled.API/Features/Warhead.cs | 17 +- EXILED/Exiled.API/Features/Window.cs | 3 +- .../Exiled.CreditTags.csproj | 4 +- .../Features/DatabaseHandler.cs | 2 +- .../API/EventArgs/OwnerEscapingEventArgs.cs | 2 +- .../API/Features/CustomArmor.cs | 19 + .../API/Features/CustomKeycard.cs | 84 ++- .../API/Features/CustomWeapon.cs | 4 +- .../Exiled.CustomItems.csproj | 2 +- .../API/Features/CustomRole.cs | 9 +- .../Exiled.CustomRoles.csproj | 2 +- EXILED/Exiled.Events/Commands/Config/Merge.cs | 2 +- EXILED/Exiled.Events/Commands/Config/Split.cs | 2 +- EXILED/Exiled.Events/Commands/Hub/Hub.cs | 51 -- .../Commands/Hub/HubApi/ApiProvider.cs | 64 --- .../Commands/Hub/HubApi/Models/HubPlugin.cs | 35 -- EXILED/Exiled.Events/Commands/Hub/Install.cs | 118 ----- EXILED/Exiled.Events/Config.cs | 1 + .../Cassie/SendingCassieMessageEventArgs.cs | 20 +- .../Map/AnnouncingScpTerminationEventArgs.cs | 9 +- .../EventArgs/Map/FillingLockerEventArgs.cs | 2 +- .../Player/ActivatingGeneratorEventArgs.cs | 7 +- .../Player/ActivatingWarheadPanelEventArgs.cs | 2 +- .../Player/CancelledItemUseEventArgs.cs | 13 +- .../Player/CancellingItemUseEventArgs.cs | 8 +- .../Player/ClosingGeneratorEventArgs.cs | 5 +- .../DeactivatingWorkstationEventArgs.cs | 2 +- .../EventArgs/Player/EscapingEventArgs.cs | 8 +- .../EscapingPocketDimensionEventArgs.cs | 15 +- .../FailingEscapePocketDimensionEventArgs.cs | 16 +- .../EventArgs/Player/FlippingCoinEventArgs.cs | 6 +- .../EventArgs/Player/HurtEventArgs.cs | 8 +- .../Player/InteractingDoorEventArgs.cs | 7 +- .../Player/OpeningGeneratorEventArgs.cs | 7 +- .../Player/PickingUpItemEventArgs.cs | 6 +- .../Player/PreAuthenticatingEventArgs.cs | 1 - .../Player/ReservedSlotsCheckEventArgs.cs | 42 +- .../Player/SearchingPickupEventArgs.cs | 4 +- .../Player/SendingValidCommandEventArgs.cs | 2 +- .../Player/SentValidCommandEventArgs.cs | 2 +- .../EventArgs/Player/ShotEventArgs.cs | 5 +- .../Player/SpawningRagdollEventArgs.cs | 25 +- .../Player/StoppingGeneratorEventArgs.cs | 5 +- .../Player/TogglingNoClipEventArgs.cs | 10 +- .../Player/UnlockingGeneratorEventArgs.cs | 2 +- .../EventArgs/Player/UsingItemEventArgs.cs | 8 +- .../Player/UsingRadioBatteryEventArgs.cs | 7 +- .../Scp049/ActivatingSenseEventArgs.cs | 4 +- .../EventArgs/Scp049/SendingCallEventArgs.cs | 2 +- .../Scp0492/ConsumingCorpseEventArgs.cs | 4 +- .../Scp173/PlacingTantrumEventArgs.cs | 5 + .../Scp330/InteractingScp330EventArgs.cs | 28 +- .../EventArgs/Server/EndingRoundEventArgs.cs | 15 +- EXILED/Exiled.Events/Events.cs | 10 +- EXILED/Exiled.Events/Exiled.Events.csproj | 2 +- .../Handlers/Internal/AdminToyList.cs | 27 + .../Handlers/Internal/ClientStarted.cs | 25 +- .../Handlers/Internal/SceneUnloaded.cs | 1 - EXILED/Exiled.Events/Handlers/Player.cs | 4 - .../Events/Cassie/SendingCassieMessage.cs | 47 +- .../Patches/Events/Item/KeycardInteracting.cs | 144 ++--- .../Events/Map/AnnouncingChaosEntrance.cs | 2 +- .../Events/Map/AnnouncingNtfEntrance.cs | 6 +- .../Events/Map/AnnouncingScpTermination.cs | 10 +- .../Events/Map/ExplodingFlashGrenade.cs | 2 +- .../Events/Map/ExplodingFragGrenade.cs | 95 ++-- .../Patches/Events/Map/SpawningItem.cs | 4 +- .../Events/Map/SpawningRoomConnector.cs | 10 +- .../Events/Player/ActivatingWarheadPanel.cs | 74 +-- .../Events/Player/ChangingRoleAndSpawned.cs | 2 - .../Events/Player/DamagingShootingTarget.cs | 2 +- .../Patches/Events/Player/DamagingWindow.cs | 2 +- .../Events/Player/EscapingAndEscaped.cs | 60 +-- .../Events/Player/EscapingPocketDimension.cs | 46 +- .../Player/FailingEscapePocketDimension.cs | 30 +- .../Patches/Events/Player/FlippingCoin.cs | 11 +- .../Patches/Events/Player/Hurting.cs | 23 +- .../Patches/Events/Player/InteractingDoor.cs | 200 ++++--- .../Events/Player/InteractingGenerator.cs | 270 +++------- .../Events/Player/InteractingLocker.cs | 10 +- .../Patches/Events/Player/Landing.cs | 2 +- .../Patches/Events/Player/PickingUp330.cs | 7 +- .../Patches/Events/Player/PickingUpAmmo.cs | 26 +- .../Patches/Events/Player/PickingUpArmor.cs | 13 +- .../Patches/Events/Player/PickingUpItem.cs | 11 +- .../Patches/Events/Player/PickingUpScp244.cs | 14 +- .../Events/Player/ProcessDisarmMessage.cs | 8 +- .../Events/Player/ReservedSlotPatch.cs | 86 +-- .../Player/SendingValidGameConsoleCommand.cs | 106 ++-- .../Events/Player/SendingValidRACommand.cs | 36 +- .../Patches/Events/Player/Shot.cs | 160 +++--- .../Patches/Events/Player/SpawningRagdoll.cs | 19 +- .../Events/Player/TogglingFlashlight.cs | 28 +- .../Patches/Events/Player/TogglingNoClip.cs | 48 +- .../Patches/Events/Player/TogglingRadio.cs | 4 +- .../Player/UsingAndCancellingItemUse.cs | 45 +- .../Events/Player/UsingRadioBattery.cs | 36 +- .../Patches/Events/Scp049/FinishingRecall.cs | 4 +- .../Patches/Events/Scp0492/Consumed.cs | 19 +- .../Patches/Events/Scp0492/Consuming.cs | 15 +- .../Patches/Events/Scp079/ChangingCamera.cs | 22 +- .../Patches/Events/Scp173/BeingObserved.cs | 13 +- .../Patches/Events/Scp173/PlacingTantrum.cs | 14 +- .../Patches/Events/Scp330/DroppingCandy.cs | 35 +- .../Events/Scp330/InteractingScp330.cs | 132 ++--- .../Patches/Events/Scp914/UpgradingPlayer.cs | 23 +- .../Patches/Events/Server/Reporting.cs | 10 +- .../Patches/Events/Server/RoundEnd.cs | 64 +-- .../Patches/Fixes/ArmorDropPatch.cs | 55 -- .../Patches/Fixes/FixNWDisarmCommand.cs | 48 -- .../Patches/Fixes/LockerFixes.cs | 10 +- .../Patches/Fixes/NWFixDetonationTimer.cs | 2 +- ...RemoteAdminNpcCommandAddToDictionaryFix.cs | 1 + .../Patches/Fixes/Scp3114FriendlyFireFix.cs | 6 +- .../Patches/Generic/CameraList.cs | 5 +- .../Patches/Generic/LockerList.cs | 13 +- .../Patches/Generic/OfflineModeIds.cs | 9 +- .../Exiled.Events/Patches/Generic/RoomList.cs | 9 +- .../Patches/Generic/ServerNamePatch.cs | 2 +- EXILED/Exiled.Example/Events/PlayerHandler.cs | 2 +- EXILED/Exiled.Example/Exiled.Example.csproj | 2 +- EXILED/Exiled.Installer/Program.cs | 2 +- EXILED/Exiled.Installer/README.md | 4 +- EXILED/Exiled.Loader/AutoUpdateFiles.cs | 2 +- EXILED/Exiled.Loader/Config.cs | 2 +- EXILED/Exiled.Loader/ConfigManager.cs | 2 +- EXILED/Exiled.Loader/Exiled.Loader.csproj | 2 +- EXILED/Exiled.Loader/Loader.cs | 2 +- EXILED/Exiled.Loader/LoaderPlugin.cs | 64 ++- EXILED/Exiled.Loader/Updater.cs | 6 +- .../Exiled.Permissions.csproj | 2 +- .../Extensions/Permissions.cs | 4 +- EXILED/Exiled/Exiled.nuspec | 8 +- .../SCPSLRessources/NW_Documentation.md | 500 ++++++++++++++++-- EXILED/docs/articles/contributing/index.md | 4 +- .../articles/installation/automatic/linux.md | 2 +- .../installation/automatic/windows.md | 2 +- EXILED/docs/articles/installation/manual.md | 2 +- EXILED/docs/docfx.json | 2 +- EXILED/docs/docs.csproj | 2 +- EXILED/docs/toc.yml | 4 +- 204 files changed, 2496 insertions(+), 2157 deletions(-) create mode 100644 .github/workflows/labapi.yml delete mode 100644 EXILED/Exiled.API/Features/CustomHealthStat.cs create mode 100644 EXILED/Exiled.API/Features/Toys/CameraToy.cs create mode 100644 EXILED/Exiled.API/Features/Toys/Capybara.cs create mode 100644 EXILED/Exiled.API/Features/Toys/InteractableToy.cs create mode 100644 EXILED/Exiled.API/Features/Toys/Text.cs delete mode 100644 EXILED/Exiled.Events/Commands/Hub/Hub.cs delete mode 100644 EXILED/Exiled.Events/Commands/Hub/HubApi/ApiProvider.cs delete mode 100644 EXILED/Exiled.Events/Commands/Hub/HubApi/Models/HubPlugin.cs delete mode 100644 EXILED/Exiled.Events/Commands/Hub/Install.cs create mode 100644 EXILED/Exiled.Events/Handlers/Internal/AdminToyList.cs delete mode 100644 EXILED/Exiled.Events/Patches/Fixes/ArmorDropPatch.cs delete mode 100644 EXILED/Exiled.Events/Patches/Fixes/FixNWDisarmCommand.cs diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 7ee77d48a0..ab7b2d0556 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -16,9 +16,9 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://exmod-team.github.io/SL-References/Dev.zip + EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/Dev.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References - EXILED_DLL_ARCHIVER_URL: https://github.com/ExMod-Team/EXILED-DLL-Archiver/releases/latest/download/EXILED-DLL-Archiver.exe + EXILED_DLL_ARCHIVER_URL: https://github.com/ExSLMod-Team/EXILED-DLL-Archiver/releases/latest/download/EXILED-DLL-Archiver.exe jobs: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index f4d75022e9..728da76f7f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,7 +12,7 @@ permissions: id-token: write env: - EXILED_REFERENCES_URL: https://exmod-team.github.io/SL-References/Master.zip + EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/Master.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. diff --git a/.github/workflows/labapi.yml b/.github/workflows/labapi.yml new file mode 100644 index 0000000000..69cb71f0aa --- /dev/null +++ b/.github/workflows/labapi.yml @@ -0,0 +1,74 @@ +name: Exiled Dev CI + +on: + push: + branches: + - LabAPI + pull_request: + branches: + - LabAPI + workflow_dispatch: + +defaults: + run: + working-directory: ./EXILED + +env: + EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/LabAPI.zip + EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References + EXILED_DLL_ARCHIVER_URL: https://github.com/ExSLMod-Team/EXILED-DLL-Archiver/releases/download/v1.8.2/EXILED-DLL-Archiver.exe + +jobs: + + build: + + runs-on: windows-latest + # Prevent double running for push & pull_request events from the main repo + if: github.event_name != 'push' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + + steps: + + - name: Setup .NET Core SDK + uses: actions/setup-dotnet@v4.0.1 + + - name: Setup Nuget + uses: nuget/setup-nuget@v2 + + - uses: actions/checkout@v4.1.7 + + - name: Get references + shell: pwsh + run: | + Invoke-WebRequest -Uri ${{ env.EXILED_REFERENCES_URL }} -OutFile ${{ github.workspace }}/EXILED/References.zip + Expand-Archive -Path References.zip -DestinationPath ${{ env.EXILED_REFERENCES_PATH }} + + - name: Build + env: + EXILED_REFERENCES: ${{ env.EXILED_REFERENCES_PATH }} + shell: pwsh + run: | + ./build.ps1 -BuildNuGet + $File = (Get-ChildItem -Path . -Include 'ExMod.Exiled.*.nupkg' -Recurse).Name + Out-File -FilePath ${{ github.env }} -InputObject "PackageFile=$File" -Encoding utf-8 -Append + + - name: Upload nuget package + uses: actions/upload-artifact@v4 + with: + name: ${{ env.PackageFile }} + path: EXILED/${{ env.PackageFile }} + + - name: Get references + shell: pwsh + run: | + Invoke-WebRequest -Uri ${{ env.EXILED_DLL_ARCHIVER_URL }} -OutFile ${{ github.workspace }}/EXILED/EXILED-DLL-Archiver.exe + + - name: Packaging results as tar.gz + shell: pwsh + run: ./packaging.ps1 + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: Build Result + path: EXILED/bin/Release/Exiled.tar.gz + diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3c842e3a39..576a58f46b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://exmod-team.github.io/SL-References/Master.zip + EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/Master.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References jobs: diff --git a/.github/workflows/push_nuget.yml b/.github/workflows/push_nuget.yml index 5150b0c7ec..29175ffee8 100644 --- a/.github/workflows/push_nuget.yml +++ b/.github/workflows/push_nuget.yml @@ -10,7 +10,7 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://ExMod-Team.github.io/SL-References/Dev.zip + EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/LabAPI.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References jobs: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ac0937bd69..9b1b16ee05 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,9 +11,9 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://exmod-team.github.io/SL-References/Dev.zip + EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/LabAPI.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References - EXILED_DLL_ARCHIVER_URL: https://github.com/ExMod-Team/EXILED-DLL-Archiver/releases/latest/download/EXILED-DLL-Archiver.exe + EXILED_DLL_ARCHIVER_URL: https://github.com/ExSLMod-Team/EXILED-DLL-Archiver/releases/download/v1.8.1/EXILED-DLL-Archiver.exe jobs: build: diff --git a/EXILED/EXILED.props b/EXILED/EXILED.props index 53be61447a..eefc8a1140 100644 --- a/EXILED/EXILED.props +++ b/EXILED/EXILED.props @@ -15,7 +15,7 @@ - 9.5.2 + 9.6.0 false @@ -25,8 +25,8 @@ Copyright © $(Authors) 2020 - $([System.DateTime]::Now.ToString("yyyy")) Git - https://github.com/ExMod-Team/EXILED - https://github.com/ExMod-Team/EXILED + https://github.com/ExSLMod-Team/EXILED + https://github.com/ExSLMod-Team/EXILED CC-BY-SA-3.0 $(DefineConstants);PUBLIC_BETA diff --git a/EXILED/Exiled.API/Enums/AdminToyType.cs b/EXILED/Exiled.API/Enums/AdminToyType.cs index c7f937721a..0ad8bb43dd 100644 --- a/EXILED/Exiled.API/Enums/AdminToyType.cs +++ b/EXILED/Exiled.API/Enums/AdminToyType.cs @@ -32,5 +32,25 @@ public enum AdminToyType /// Speaker toy. /// Speaker, + + /// + /// Capybara toy. + /// + Capybara, + + /// + /// InvisibleInteractable toy. + /// + InvisibleInteractableToy, + + /// + /// Camera Object toy. + /// + CameraToy, + + /// + /// Text toy. + /// + TextToy, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/CameraType.cs b/EXILED/Exiled.API/Enums/CameraType.cs index 80c1b7cb89..8b064b045f 100644 --- a/EXILED/Exiled.API/Enums/CameraType.cs +++ b/EXILED/Exiled.API/Enums/CameraType.cs @@ -123,6 +123,7 @@ public enum CameraType Hcz173ContChamber, [System.Obsolete("This Camera no longer exist.")] Hcz173Hallway, + [System.Obsolete("This Camera no longer exist.")] HczCurve, HczJunkMain, HczJunkHallway, @@ -137,6 +138,19 @@ public enum CameraType HczWarheadPortElevator, HczMicroHIDLab, HczPipesMain, + HczScp127Lab, + HczScp127Containment, + HczServersUpperStorage, + HczLowerServerStorage, + HczServerStaircase, + #endregion + + #region custom + EzArmCameraToy, + EzCameraToy, + HczCameraToy, + LczCameraToy, + SzCameraToy, #endregion } } diff --git a/EXILED/Exiled.API/Enums/DamageType.cs b/EXILED/Exiled.API/Enums/DamageType.cs index 602ad2f740..ae93c5c020 100644 --- a/EXILED/Exiled.API/Enums/DamageType.cs +++ b/EXILED/Exiled.API/Enums/DamageType.cs @@ -269,5 +269,10 @@ public enum DamageType /// Damage caused by . /// SnowBall, + + /// + /// Damage caused by . + /// + Scp127, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/DoorType.cs b/EXILED/Exiled.API/Enums/DoorType.cs index ee5655f77e..4e3cb644f5 100644 --- a/EXILED/Exiled.API/Enums/DoorType.cs +++ b/EXILED/Exiled.API/Enums/DoorType.cs @@ -167,11 +167,20 @@ public enum DoorType /// /// Represents the HID_UPPER door. /// + [Obsolete("This Door has been renamed too HID_LAB.")] HIDUpper, + /// + /// Represents the HID_LAB door. + /// +#pragma warning disable CS0618 + HIDLab = HIDUpper, +#pragma warning restore CS0618 + /// /// Represents the HID_LOWER door. /// + [Obsolete("This Door has been removed from the game.")] HIDLower, /// @@ -320,5 +329,15 @@ public enum DoorType /// Represents the ESCAPE_FINAL door. /// EscapeFinal, + + /// + /// Represents the Elevator door for . + /// + ElevatorServerRoom, + + /// + /// Represents the HCZ_127_LAB door. + /// + Hcz127Lab, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/EffectType.cs b/EXILED/Exiled.API/Enums/EffectType.cs index 8ac82586aa..b32ba684d8 100644 --- a/EXILED/Exiled.API/Enums/EffectType.cs +++ b/EXILED/Exiled.API/Enums/EffectType.cs @@ -283,5 +283,10 @@ public enum EffectType /// [Obsolete("Only availaible for Christmas and AprilFools.")] Snowed, + + /// + /// . + /// + Scp1344Detected, } } diff --git a/EXILED/Exiled.API/Enums/ElevatorType.cs b/EXILED/Exiled.API/Enums/ElevatorType.cs index 02783b7180..ebccf5b356 100644 --- a/EXILED/Exiled.API/Enums/ElevatorType.cs +++ b/EXILED/Exiled.API/Enums/ElevatorType.cs @@ -48,5 +48,10 @@ public enum ElevatorType : byte /// Light Containment Zone checkpoint B elevator. /// LczB, + + /// + /// Heavy Containment Zone ServerRoom elevator. + /// + ServerRoom, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/FirearmType.cs b/EXILED/Exiled.API/Enums/FirearmType.cs index aa814136fa..05cccf2388 100644 --- a/EXILED/Exiled.API/Enums/FirearmType.cs +++ b/EXILED/Exiled.API/Enums/FirearmType.cs @@ -89,5 +89,10 @@ public enum FirearmType /// Represents the . /// A7, + + /// + /// Represents the . + /// + Scp127, } } diff --git a/EXILED/Exiled.API/Enums/GeneratorState.cs b/EXILED/Exiled.API/Enums/GeneratorState.cs index 1b434908b0..4f0a9b7111 100644 --- a/EXILED/Exiled.API/Enums/GeneratorState.cs +++ b/EXILED/Exiled.API/Enums/GeneratorState.cs @@ -20,9 +20,9 @@ namespace Exiled.API.Enums public enum GeneratorState : byte { /// - /// Generator is locked. + /// Generator is doing nothing. /// - None = 1, + None = 0, /// /// Generator is unlocked. diff --git a/EXILED/Exiled.API/Enums/GlassType.cs b/EXILED/Exiled.API/Enums/GlassType.cs index 9857ed2a82..4144c7fd98 100644 --- a/EXILED/Exiled.API/Enums/GlassType.cs +++ b/EXILED/Exiled.API/Enums/GlassType.cs @@ -69,5 +69,10 @@ public enum GlassType /// Represents the window in . /// TestRoom, + + /// + /// Represents the window in . + /// + Scp127, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/LockerType.cs b/EXILED/Exiled.API/Enums/LockerType.cs index af62a06cb3..14c2f365df 100644 --- a/EXILED/Exiled.API/Enums/LockerType.cs +++ b/EXILED/Exiled.API/Enums/LockerType.cs @@ -115,5 +115,10 @@ public enum LockerType /// SCP-1853 pedestal. /// Scp1853Pedestal, + + /// + /// SCP-127 pedestal. + /// + Scp127Pedestal, } } diff --git a/EXILED/Exiled.API/Enums/PrefabType.cs b/EXILED/Exiled.API/Enums/PrefabType.cs index 7ec8a851c3..f34093aba8 100644 --- a/EXILED/Exiled.API/Enums/PrefabType.cs +++ b/EXILED/Exiled.API/Enums/PrefabType.cs @@ -336,5 +336,41 @@ public enum PrefabType [Prefab(912031041, "ElevatorChamberNuke")] ElevatorChamberNuke, + + [Prefab(3087007600, "CapybaraToy")] + CapybaraToy, + + [Prefab(3539746802, "Sinkhole")] + Sinkhole, + + [Prefab(1548138668, "AutoRagdoll")] + AutoRagdoll, + + [Prefab(1323017091, "ElevatorChamberCargo")] + ElevatorChamberCargo, + + [Prefab(359728307, "InvisibleInteractableToy")] + InvisibleInteractableToy, + + [Prefab(1824808402, "EzArmCameraToy")] + EzArmCameraToy, + + [Prefab(3375932423, "EzCameraToy")] + EzCameraToy, + + [Prefab(144958943, "HczCameraToy")] + HczCameraToy, + + [Prefab(2026969629, "LczCameraToy")] + LczCameraToy, + + [Prefab(1548138668, "SzCameraToy")] + SzCameraToy, + + [Prefab(2842703865, "KeycardPickup_Chaos")] + KeycardPickupChaos, + + [Prefab(162530276, "TextToy")] + TextToy, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/RoomType.cs b/EXILED/Exiled.API/Enums/RoomType.cs index 3cb78e53f2..6e236c25d1 100644 --- a/EXILED/Exiled.API/Enums/RoomType.cs +++ b/EXILED/Exiled.API/Enums/RoomType.cs @@ -328,5 +328,15 @@ public enum RoomType /// Entrance Zone's straight hall with Dr.L's and conference room 9b locked room. /// EzSmallrooms, + + /// + /// Heavy Containment Zone's SCP-330 room. + /// + Hcz127, + + /// + /// Heavy Containment Zone's storage / server room. + /// + HczServerRoom, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Exiled.API.csproj b/EXILED/Exiled.API/Exiled.API.csproj index 961b44e98d..c8737a790c 100644 --- a/EXILED/Exiled.API/Exiled.API.csproj +++ b/EXILED/Exiled.API/Exiled.API.csproj @@ -27,10 +27,10 @@ + - diff --git a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs index 7e496e77ac..6abeea8a2f 100644 --- a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs +++ b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs @@ -102,6 +102,7 @@ public static class DamageTypeExtensions { ItemType.Jailbird, DamageType.Jailbird }, { ItemType.GunFRMG0, DamageType.Frmg0 }, { ItemType.GunA7, DamageType.A7 }, + { ItemType.GunSCP127, DamageType.Scp127 }, }; /// diff --git a/EXILED/Exiled.API/Extensions/DoorTypeExtensions.cs b/EXILED/Exiled.API/Extensions/DoorTypeExtensions.cs index 79164df2b3..a4380d81cf 100644 --- a/EXILED/Exiled.API/Extensions/DoorTypeExtensions.cs +++ b/EXILED/Exiled.API/Extensions/DoorTypeExtensions.cs @@ -35,6 +35,6 @@ public static bool IsGate(this DoorType door) => door is DoorType.GateA or DoorT /// The door to be checked. /// Returns whether the is an elevator. public static bool IsElevator(this DoorType door) => door is DoorType.ElevatorGateA or DoorType.ElevatorGateB - or DoorType.ElevatorLczA or DoorType.ElevatorLczB or DoorType.ElevatorNuke or DoorType.ElevatorScp049; + or DoorType.ElevatorLczA or DoorType.ElevatorLczB or DoorType.ElevatorNuke or DoorType.ElevatorScp049 or DoorType.ElevatorServerRoom; } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs index dc209c3ba0..6f038fd761 100644 --- a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs +++ b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs @@ -75,6 +75,7 @@ public static class EffectTypeExtension { EffectType.SeveredEyes, typeof(SeveredEyes) }, { EffectType.PitDeath, typeof(PitDeath) }, { EffectType.Blurred, typeof(Blurred) }, + { EffectType.Scp1344Detected, typeof(Scp1344Detected) }, #pragma warning disable CS0618 { EffectType.Marshmallow, typeof(MarshmallowEffect) }, { EffectType.BecomingFlamingo, typeof(BecomingFlamingo) }, diff --git a/EXILED/Exiled.API/Extensions/ItemExtensions.cs b/EXILED/Exiled.API/Extensions/ItemExtensions.cs index c169f03011..458fd10bc4 100644 --- a/EXILED/Exiled.API/Extensions/ItemExtensions.cs +++ b/EXILED/Exiled.API/Extensions/ItemExtensions.cs @@ -182,6 +182,7 @@ public static int GetMaxAmmo(this FirearmType item) ItemType.GunCom45 => FirearmType.Com45, ItemType.GunFRMG0 => FirearmType.FRMG0, ItemType.ParticleDisruptor => FirearmType.ParticleDisruptor, + ItemType.GunSCP127 => FirearmType.Scp127, _ => FirearmType.None, }; @@ -220,6 +221,7 @@ public static int GetMaxAmmo(this FirearmType item) FirearmType.Com45 => ItemType.GunCom45, FirearmType.FRMG0 => ItemType.GunFRMG0, FirearmType.ParticleDisruptor => ItemType.ParticleDisruptor, + FirearmType.Scp127 => ItemType.GunSCP127, _ => ItemType.None, }; diff --git a/EXILED/Exiled.API/Extensions/LockerExtensions.cs b/EXILED/Exiled.API/Extensions/LockerExtensions.cs index 4a6466f636..da8b915794 100644 --- a/EXILED/Exiled.API/Extensions/LockerExtensions.cs +++ b/EXILED/Exiled.API/Extensions/LockerExtensions.cs @@ -48,6 +48,7 @@ public static class LockerExtensions "RegularMedkitStructure" => LockerType.Medkit, "AdrenalineMedkitStructure" => LockerType.Adrenaline, "MicroHIDpedestal" => LockerType.MicroHid, + "SCP_127_Container" => LockerType.Scp127Pedestal, _ => LockerType.Unknown, }; } diff --git a/EXILED/Exiled.API/Extensions/RoomExtensions.cs b/EXILED/Exiled.API/Extensions/RoomExtensions.cs index 14141a4422..8d36486505 100644 --- a/EXILED/Exiled.API/Extensions/RoomExtensions.cs +++ b/EXILED/Exiled.API/Extensions/RoomExtensions.cs @@ -52,7 +52,7 @@ public static bool IsCheckpoint(this RoomType room) => room is RoomType.LczCheck /// Returns whether the contains any SCP. public static bool IsScp(this RoomType room) => room is RoomType.Lcz173 or RoomType.Lcz330 or RoomType.Lcz914 or RoomType.Hcz049 or RoomType.Hcz079 or - RoomType.Hcz096 or RoomType.Hcz106 or RoomType.Hcz939; + RoomType.Hcz096 or RoomType.Hcz106 or RoomType.Hcz939 or RoomType.Hcz127; /// /// Converts the provided into the corresponding . diff --git a/EXILED/Exiled.API/Extensions/UserGroupExtensions.cs b/EXILED/Exiled.API/Extensions/UserGroupExtensions.cs index 7b9138618c..41b8523433 100644 --- a/EXILED/Exiled.API/Extensions/UserGroupExtensions.cs +++ b/EXILED/Exiled.API/Extensions/UserGroupExtensions.cs @@ -37,7 +37,7 @@ public static bool EqualsTo(this UserGroup @this, UserGroup other) /// /// The . /// The key of that group, or if not found. - public static string GetKey(this UserGroup @this) => Server.PermissionsHandler._groups + public static string GetKey(this UserGroup @this) => Server.PermissionsHandler.Groups .FirstOrDefault(pair => pair.Value.EqualsTo(@this)).Key; /// @@ -47,7 +47,7 @@ public static string GetKey(this UserGroup @this) => Server.PermissionsHandler._ /// The value of that group, or if not found. public static UserGroup GetValue(string groupName) { - ServerStatic.GetPermissionsHandler().GetAllGroups().TryGetValue(groupName, out UserGroup userGroup); + ServerStatic.PermissionsHandler.GetAllGroups().TryGetValue(groupName, out UserGroup userGroup); return userGroup; } } diff --git a/EXILED/Exiled.API/Features/Camera.cs b/EXILED/Exiled.API/Features/Camera.cs index c794defcd5..da3f73e27b 100644 --- a/EXILED/Exiled.API/Features/Camera.cs +++ b/EXILED/Exiled.API/Features/Camera.cs @@ -70,7 +70,6 @@ public class Camera : IWrapper, IWorldSpace ["HCZ ARMORY"] = CameraType.HczArmory, ["HCZ ARMORY INTERIOR"] = CameraType.HczArmoryInterior, ["HCZ CROSSING"] = CameraType.HczCrossing, - ["HCZ CURVE"] = CameraType.HczCurve, ["HCZ ELEV SYS A"] = CameraType.HczElevSysA, ["HCZ ELEV SYS B"] = CameraType.HczElevSysB, ["HCZ HALLWAY"] = CameraType.HczHallway, @@ -134,6 +133,18 @@ public class Camera : IWrapper, IWorldSpace ["WARHEAD TOP ELEVATORS"] = CameraType.HczWarheadTopElevators, ["WARHEAD CONNECTOR"] = CameraType.HczWarheadConnector, ["WARHEAD PORT ELEVATOR"] = CameraType.HczWarheadPortElevator, + ["HCZ SCP-127 LAB"] = CameraType.HczScp127Lab, + ["HCZ SCP-127 CONTAINMENT"] = CameraType.HczScp127Containment, + ["HCZ SERVERS UPPER STORAGE"] = CameraType.HczServersUpperStorage, + ["HCZ LOWER SERVER STORAGE"] = CameraType.HczLowerServerStorage, + ["HCZ SERVERS STAIRCASE"] = CameraType.HczServerStaircase, + + // CustomCamera + ["EZ ARM CAMERA TOY"] = CameraType.EzArmCameraToy, + ["EZ CAMERA TOY"] = CameraType.EzCameraToy, + ["HCZ CAMERA TOY"] = CameraType.HczCameraToy, + ["LCZ CAMERA TOY"] = CameraType.LczCameraToy, + ["SZ CAMERA TOY"] = CameraType.SzCameraToy, }; private Room room; @@ -147,10 +158,6 @@ internal Camera(Scp079Camera camera079) Base = camera079; Camera079ToCamera.Add(camera079, this); Type = GetCameraType(); -#if DEBUG - if (Type is CameraType.Unknown) - Log.Error($"[CAMERATYPE UNKNOWN] {this} BASE = {Base}"); -#endif } /// @@ -214,8 +221,8 @@ internal Camera(Scp079Camera camera079) /// public Quaternion Rotation { - get => Base._cameraAnchor.rotation; - set => Base._cameraAnchor.rotation = value; + get => Base.CameraAnchor.rotation; + set => Base.CameraAnchor.rotation = value; } /// diff --git a/EXILED/Exiled.API/Features/CustomHealthStat.cs b/EXILED/Exiled.API/Features/CustomHealthStat.cs deleted file mode 100644 index 57f6d31c20..0000000000 --- a/EXILED/Exiled.API/Features/CustomHealthStat.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.API.Features -{ - using PlayerStatsSystem; - - /// - /// A custom version of which allows the player's max amount of health to be changed. - /// TODO: Move to Features.CustomStats. - /// - public class CustomHealthStat : HealthStat - { - /// - public override float MaxValue => CustomMaxValue == default ? base.MaxValue : CustomMaxValue; - - /// - /// Gets or sets the maximum amount of health the player will have. - /// - public float CustomMaxValue { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/CustomStats/CustomHumeShieldStat.cs b/EXILED/Exiled.API/Features/CustomStats/CustomHumeShieldStat.cs index 78c4cd807d..e19ce970f5 100644 --- a/EXILED/Exiled.API/Features/CustomStats/CustomHumeShieldStat.cs +++ b/EXILED/Exiled.API/Features/CustomStats/CustomHumeShieldStat.cs @@ -1,4 +1,4 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- // // Copyright (c) ExMod Team. All rights reserved. // Licensed under the CC BY-SA 3.0 license. @@ -18,25 +18,24 @@ namespace Exiled.API.Features.CustomStats /// public class CustomHumeShieldStat : HumeShieldStat { - /// - public override float MaxValue => CustomMaxValue == -1 ? base.MaxValue : CustomMaxValue; - /// /// Gets or sets the multiplier for gaining HumeShield. /// public float ShieldRegenerationMultiplier { get; set; } = 1; - /// - /// Gets or sets the maximum amount of HumeShield the player can have. - /// - public float CustomMaxValue { get; set; } = -1; - - private float ShieldRegeneration => TryGetHsModule(out HumeShieldModuleBase controller) ? controller.HsRegeneration * ShieldRegenerationMultiplier : 0; + private float ShieldRegeneration + { + get + { + IHumeShieldProvider.GetForHub(Hub, out _, out _, out float hsRegen, out _); + return hsRegen * ShieldRegenerationMultiplier; + } + } /// public override void Update() { - if (MaxValue == -1 && ShieldRegenerationMultiplier is 1) + if (ShieldRegenerationMultiplier is 1) { base.Update(); return; @@ -45,7 +44,7 @@ public override void Update() if (!NetworkServer.active) return; - if (_valueDirty) + if (ValueDirty) { new SyncedStatMessages.StatMessage() { @@ -53,7 +52,7 @@ public override void Update() SyncedValue = CurValue, }.SendToHubsConditionally(CanReceive); _lastSent = CurValue; - _valueDirty = false; + ValueDirty = false; } if (ShieldRegeneration == 0) diff --git a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs index 2008936bea..bd858b3447 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs @@ -155,6 +155,9 @@ public GenericDamageHandler(Player player, Player attacker, float damage, Damage case DamageType.A7: GenericFirearm(player, attacker, damage, damageType, ItemType.GunA7); break; + case DamageType.Scp127: + GenericFirearm(player, attacker, damage, damageType, ItemType.GunSCP127); + break; case DamageType.ParticleDisruptor: Base = new DisruptorDamageHandler(new (Item.Create(ItemType.ParticleDisruptor, attacker).Base as InventorySystem.Items.Firearms.Firearm, InventorySystem.Items.Firearms.Modules.DisruptorActionModule.FiringState.FiringSingle), Vector3.up, damage); break; diff --git a/EXILED/Exiled.API/Features/Doors/BasicDoor.cs b/EXILED/Exiled.API/Features/Doors/BasicDoor.cs index 39316fdd37..5a53caa738 100644 --- a/EXILED/Exiled.API/Features/Doors/BasicDoor.cs +++ b/EXILED/Exiled.API/Features/Doors/BasicDoor.cs @@ -9,6 +9,8 @@ namespace Exiled.API.Features.Doors { using System.Collections.Generic; + using Exiled.API.Enums; + using PlayerRoles; using UnityEngine; using Basegame = Interactables.Interobjects.BasicDoor; @@ -35,9 +37,9 @@ public BasicDoor(Basegame door, List room) public new Basegame Base { get; } /// - /// Gets the list with all SCP-106's colliders. + /// Gets the list with all Ignored's colliders for or . /// - public IEnumerable Scp106Colliders => Base.Scp106Colliders; + public IEnumerable Scp106Colliders => Base.IgnoredColliders; /// /// Gets or sets the total cooldown before door can be triggered again. diff --git a/EXILED/Exiled.API/Features/Doors/CheckpointDoor.cs b/EXILED/Exiled.API/Features/Doors/CheckpointDoor.cs index 837bd5ff72..0fa6ea4139 100644 --- a/EXILED/Exiled.API/Features/Doors/CheckpointDoor.cs +++ b/EXILED/Exiled.API/Features/Doors/CheckpointDoor.cs @@ -42,10 +42,10 @@ internal CheckpointDoor(Interactables.Interobjects.CheckpointDoor door, List /// Gets or sets the current checkpoint stage. /// - public Interactables.Interobjects.CheckpointDoor.CheckpointSequenceStage CurrentStage + public Interactables.Interobjects.CheckpointDoor.SequenceState CurrentStage { - get => Base._currentSequence; - set => Base._currentSequence = value; + get => Base.CurSequence; + set => Base.CurSequence = value; } /// @@ -53,8 +53,8 @@ public Interactables.Interobjects.CheckpointDoor.CheckpointSequenceStage Current /// public float MainTimer { - get => Base._mainTimer; - set => Base._mainTimer = value; + get => Base.SequenceCtrl.RemainingTime; + set => Base.SequenceCtrl.RemainingTime = value; } /// @@ -62,8 +62,8 @@ public float MainTimer /// public float WaitTime { - get => Base._waitTime; - set => Base._waitTime = value; + get => Base.SequenceCtrl.OpenLoopTime; + set => Base.SequenceCtrl.OpenLoopTime = value; } /// @@ -71,8 +71,8 @@ public float WaitTime /// public float WarningTime { - get => Base._warningTime; - set => Base._warningTime = value; + get => Base.SequenceCtrl.WarningTime; + set => Base.SequenceCtrl.WarningTime = value; } /// diff --git a/EXILED/Exiled.API/Features/Doors/Door.cs b/EXILED/Exiled.API/Features/Doors/Door.cs index fb947039dc..c2cea9a761 100644 --- a/EXILED/Exiled.API/Features/Doors/Door.cs +++ b/EXILED/Exiled.API/Features/Doors/Door.cs @@ -22,11 +22,10 @@ namespace Exiled.API.Features.Doors using UnityEngine; using BaseBreakableDoor = Interactables.Interobjects.BreakableDoor; - using BaseKeycardPermissions = Interactables.Interobjects.DoorUtils.KeycardPermissions; using Breakable = BreakableDoor; using Checkpoint = CheckpointDoor; using Elevator = ElevatorDoor; - using KeycardPermissions = Enums.KeycardPermissions; + using KeycardPermissions = Exiled.API.Enums.KeycardPermissions; /// /// A wrapper class for . @@ -55,10 +54,6 @@ internal Door(DoorVariant door, List rooms) } Type = GetDoorType(); -#if DEBUG - if (Type is DoorType.UnknownDoor or DoorType.UnknownGate or DoorType.UnknownElevator) - Log.Error($"[DOORTYPE UNKNOWN] {this} BASE = {Base}"); -#endif } /// @@ -181,8 +176,8 @@ public bool IsOpen /// public KeycardPermissions KeycardPermissions { - get => (KeycardPermissions)RequiredPermissions.RequiredPermissions; - set => RequiredPermissions.RequiredPermissions = (BaseKeycardPermissions)value; + get => (KeycardPermissions)RequiredPermissions; + set => RequiredPermissions = (DoorPermissionFlags)value; } /// @@ -244,10 +239,10 @@ public DoorLockType DoorLockType /// /// Gets or sets the required permissions to open the door. /// - public DoorPermissions RequiredPermissions + public DoorPermissionFlags RequiredPermissions { - get => Base.RequiredPermissions; - set => Base.RequiredPermissions = value; + get => Base.RequiredPermissions.RequiredPermissions; + set => Base.RequiredPermissions.RequiredPermissions = value; } /// @@ -357,7 +352,7 @@ public static T Get(string name) /// /// The base-game . /// The with the given name or if not found. - public static Door Get(GameObject gameObject) => gameObject is null ? null : Get(gameObject.GetComponentInChildren()); + public static Door Get(GameObject gameObject) => gameObject is null ? null : Get(gameObject.GetComponentInParent()); /// /// Returns the closest to the given . @@ -474,11 +469,11 @@ public void PlaySound(DoorBeepType beep) { switch (Base) { - case Interactables.Interobjects.BasicDoor basic: - basic.RpcPlayBeepSound(beep is not DoorBeepType.InteractionAllowed); + case Interactables.Interobjects.BasicDoor basic when beep is not DoorBeepType.InteractionAllowed: + basic.RpcPlayBeepSound(); break; - case Interactables.Interobjects.CheckpointDoor chkPt: - chkPt.RpcPlayBeepSound((byte)Mathf.Min((int)beep, 3)); + case Interactables.Interobjects.CheckpointDoor chkPt when beep is not DoorBeepType.InteractionAllowed: + chkPt.RpcPlayDeniedBeep(); break; } } @@ -553,7 +548,7 @@ public void Lock(DoorLockType lockType) /// Returns the Door in a human-readable format. /// /// A string containing Door-related data. - public override string ToString() => $"{Type} ({Zone}) [{Room}] *{DoorLockType}* ={RequiredPermissions?.RequiredPermissions}="; + public override string ToString() => $"{Type} ({Zone}) [{Room}] *{DoorLockType}* ={KeycardPermissions}="; /// /// Creates the door object associated with a specific . @@ -613,6 +608,7 @@ private DoorType GetDoorType() ElevatorGroup.Scp049 => DoorType.ElevatorScp049, ElevatorGroup.GateB => DoorType.ElevatorGateB, ElevatorGroup.GateA => DoorType.ElevatorGateA, + ElevatorGroup.ServerRoom => DoorType.ElevatorServerRoom, ElevatorGroup.LczA01 or ElevatorGroup.LczA02 => DoorType.ElevatorLczA, ElevatorGroup.LczB01 or ElevatorGroup.LczB02 => DoorType.ElevatorLczB, ElevatorGroup.Nuke01 or ElevatorGroup.Nuke02 => DoorType.ElevatorNuke, @@ -654,8 +650,8 @@ private DoorType GetDoorType() "173_CONNECTOR" => DoorType.Scp173Connector, "LCZ_WC" => DoorType.LczWc, "HID_CHAMBER" => DoorType.HIDChamber, - "HID_UPPER" => DoorType.HIDUpper, - "HID_LOWER" => DoorType.HIDLower, + "HID_LAB" => DoorType.HIDLab, + "HCZ_127_LAB" => DoorType.Hcz127Lab, "173_ARMORY" => DoorType.Scp173Armory, "173_GATE" => DoorType.Scp173Gate, "GR18" => DoorType.GR18Gate, diff --git a/EXILED/Exiled.API/Features/Doors/ElevatorDoor.cs b/EXILED/Exiled.API/Features/Doors/ElevatorDoor.cs index 797378312a..0145e53f84 100644 --- a/EXILED/Exiled.API/Features/Doors/ElevatorDoor.cs +++ b/EXILED/Exiled.API/Features/Doors/ElevatorDoor.cs @@ -30,7 +30,7 @@ internal ElevatorDoor(Interactables.Interobjects.ElevatorDoor door, List r Base = door; Lift = Lift.Get(x => x.Group == Group).FirstOrDefault(); - Panel = Object.FindObjectsOfType().FirstOrDefault(x => x._door == door); + Panel = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None).FirstOrDefault(x => x._door == door); } /// @@ -56,6 +56,7 @@ internal ElevatorDoor(Interactables.Interobjects.ElevatorDoor door, List r ElevatorGroup.Scp049 => ElevatorType.Scp049, ElevatorGroup.GateA => ElevatorType.GateA, ElevatorGroup.GateB => ElevatorType.GateB, + ElevatorGroup.ServerRoom => ElevatorType.ServerRoom, ElevatorGroup.LczA01 or ElevatorGroup.LczA02 => ElevatorType.LczA, ElevatorGroup.LczB01 or ElevatorGroup.LczB02 => ElevatorType.LczB, ElevatorGroup.Nuke01 or ElevatorGroup.Nuke02 => ElevatorType.Nuke, diff --git a/EXILED/Exiled.API/Features/Generator.cs b/EXILED/Exiled.API/Features/Generator.cs index 7b8a6b6baf..b19369208d 100644 --- a/EXILED/Exiled.API/Features/Generator.cs +++ b/EXILED/Exiled.API/Features/Generator.cs @@ -13,7 +13,7 @@ namespace Exiled.API.Features using Enums; using Exiled.API.Interfaces; - + using Interactables.Interobjects.DoorUtils; using MapGeneration.Distributors; using UnityEngine; @@ -216,7 +216,7 @@ public Player LastActivator public KeycardPermissions KeycardPermissions { get => (KeycardPermissions)Base._requiredPermission; - set => Base._requiredPermission = (Interactables.Interobjects.DoorUtils.KeycardPermissions)value; + set => Base._requiredPermission = (DoorPermissionFlags)value; } /// @@ -281,7 +281,13 @@ public static bool TryGet(Func predicate, out IEnumerable /// Denies the unlock. /// - public void DenyUnlock() => Base.RpcDenied(); + public void DenyUnlock() => Base.RpcDenied(DoorPermissionFlags.None); + + /// + /// Denies the unlock. + /// + /// . + public void DenyUnlock(KeycardPermissions doorPermission) => Base.RpcDenied((Interactables.Interobjects.DoorUtils.DoorPermissionFlags)doorPermission); /// /// Denies the unlock and resets the interaction cooldown. @@ -299,7 +305,7 @@ public void DenyUnlockAndResetCooldown() /// A value indicating whether the flag is enabled. public void SetPermissionFlag(KeycardPermissions flag, bool isEnabled) { - Interactables.Interobjects.DoorUtils.KeycardPermissions permission = (Interactables.Interobjects.DoorUtils.KeycardPermissions)flag; + DoorPermissionFlags permission = (DoorPermissionFlags)flag; if (isEnabled) Base._requiredPermission |= permission; diff --git a/EXILED/Exiled.API/Features/Hazards/TemporaryHazard.cs b/EXILED/Exiled.API/Features/Hazards/TemporaryHazard.cs index 0e701a8093..c9dfecb650 100644 --- a/EXILED/Exiled.API/Features/Hazards/TemporaryHazard.cs +++ b/EXILED/Exiled.API/Features/Hazards/TemporaryHazard.cs @@ -56,8 +56,8 @@ public bool IsDestroyed /// public float Duration { - get => Base._elapsed; - set => Base._elapsed = value; + get => Base.Elapsed; + set => Base.Elapsed = value; } /// diff --git a/EXILED/Exiled.API/Features/Items/Armor.cs b/EXILED/Exiled.API/Features/Items/Armor.cs index 238de555ec..344b7a0118 100644 --- a/EXILED/Exiled.API/Features/Items/Armor.cs +++ b/EXILED/Exiled.API/Features/Items/Armor.cs @@ -65,21 +65,22 @@ internal Armor(ItemType type) public bool IsWorn => Base.IsWorn; /// - /// Gets or sets the Weight of the armor. + /// Gets or sets a value indicating whether excess ammo should be removed when the armor is dropped. /// - public new float Weight + [Obsolete("Not functional anymore", true)] + public bool RemoveExcessOnDrop { - get => Base.Weight; - set => Base._weight = value; + get => false; + set => _ = value; } /// - /// Gets or sets a value indicating whether excess ammo should be removed when the armor is dropped. + /// Gets or sets the Weight of the armor. /// - public bool RemoveExcessOnDrop + public new float Weight { - get => !Base.DontRemoveExcessOnDrop; - set => Base.DontRemoveExcessOnDrop = !value; + get => Base.Weight; + set => Base._weight = value; } /// diff --git a/EXILED/Exiled.API/Features/Items/Keycard.cs b/EXILED/Exiled.API/Features/Items/Keycard.cs index 0bd390018b..4e68dd60a5 100644 --- a/EXILED/Exiled.API/Features/Items/Keycard.cs +++ b/EXILED/Exiled.API/Features/Items/Keycard.cs @@ -7,14 +7,12 @@ namespace Exiled.API.Features.Items { + using System; + using Exiled.API.Enums; - using Exiled.API.Features.Pickups; using Exiled.API.Interfaces; - using InventorySystem.Items.Keycards; - using KeycardPickup = Pickups.KeycardPickup; - /// /// A wrapper class for . /// @@ -49,33 +47,30 @@ internal Keycard(ItemType type) /// public KeycardPermissions Permissions { - get => (KeycardPermissions)Base.Permissions; - set => Base.Permissions = (Interactables.Interobjects.DoorUtils.KeycardPermissions)value; - } + get + { + foreach (DetailBase detail in Base.Details) + { + switch (detail) + { + case PredefinedPermsDetail predefinedPermsDetail: + return (KeycardPermissions)predefinedPermsDetail.Levels.Permissions; + case CustomPermsDetail customPermsDetail: + return (KeycardPermissions)customPermsDetail.GetPermissions(null); + } + } - /// - /// Clones current object. - /// - /// New object. - public override Item Clone() => new Keycard(Type) - { - Permissions = Permissions, - }; + return KeycardPermissions.None; + } + + [Obsolete("Not functional anymore", true)] + set => _ = value; + } /// /// Returns the Keycard in a human readable format. /// /// A string containing Keycard-related data. public override string ToString() => $"{Type} ({Serial}) [{Weight}] *{Scale}* |{Permissions}|"; - - /// - internal override void ReadPickupInfoBefore(Pickup pickup) - { - base.ReadPickupInfoBefore(pickup); - if (pickup is KeycardPickup keycardPickup) - { - Permissions = keycardPickup.Permissions; - } - } } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Items/Scp1344.cs b/EXILED/Exiled.API/Features/Items/Scp1344.cs index 460aeb8c06..7f96da8903 100644 --- a/EXILED/Exiled.API/Features/Items/Scp1344.cs +++ b/EXILED/Exiled.API/Features/Items/Scp1344.cs @@ -11,7 +11,7 @@ namespace Exiled.API.Features.Items using InventorySystem.Items.Usables; using InventorySystem.Items.Usables.Scp1344; - using PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers; + using PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.Wearables; /// /// A wrapper class for . diff --git a/EXILED/Exiled.API/Features/Lockers/Chamber.cs b/EXILED/Exiled.API/Features/Lockers/Chamber.cs index af4fba905d..e98281ed5c 100644 --- a/EXILED/Exiled.API/Features/Lockers/Chamber.cs +++ b/EXILED/Exiled.API/Features/Lockers/Chamber.cs @@ -78,13 +78,13 @@ public Chamber(LockerChamber chamber, Locker locker) /// public IEnumerable ToBeSpawned { - get => Base._toBeSpawned.Select(Pickup.Get); + get => Base.ToBeSpawned.Select(Pickup.Get); set { - Base._toBeSpawned.Clear(); + Base.ToBeSpawned.Clear(); foreach (Pickup pickup in value) - Base._toBeSpawned.Add(pickup.Base); + Base.ToBeSpawned.Add(pickup.Base); } } @@ -115,7 +115,7 @@ public IEnumerable AcceptableTypes public KeycardPermissions RequiredPermissions { get => (KeycardPermissions)Base.RequiredPermissions; - set => Base.RequiredPermissions = (Interactables.Interobjects.DoorUtils.KeycardPermissions)value; + set => Base.RequiredPermissions = (Interactables.Interobjects.DoorUtils.DoorPermissionFlags)value; } /// @@ -138,8 +138,8 @@ public bool UseMultipleSpawnpoints /// public Transform Spawnpoint { - get => Base._spawnpoint; - set => Base._spawnpoint = value; + get => Base.Spawnpoint; + set => Base.Spawnpoint = value; } /// @@ -147,8 +147,8 @@ public Transform Spawnpoint /// public bool InitiallySpawn { - get => Base._spawnOnFirstChamberOpening; - set => Base._spawnOnFirstChamberOpening = value; + get => Base.SpawnOnFirstChamberOpening; + set => Base.SpawnOnFirstChamberOpening = value; } /// @@ -156,8 +156,8 @@ public bool InitiallySpawn /// public float Cooldown { - get => Base._targetCooldown; - set => Base._targetCooldown = value; + get => Base.TargetCooldown; + set => Base.TargetCooldown = value; } /// @@ -235,7 +235,7 @@ public void AddItem(Pickup item) Base.Content.Add(item.Base); item.Spawn(); - if (Base._wasEverOpened) + if (Base.WasEverOpened) item.IsLocked = false; } @@ -270,7 +270,7 @@ public void AddItemToSpawn(ItemType itemType, int quantity = 1, bool spawnIfIsOp continue; } - Base._toBeSpawned.Add(pickup.Base); + Base.ToBeSpawned.Add(pickup.Base); } } @@ -296,6 +296,6 @@ public Vector3 GetRandomSpawnPoint() /// /// . /// . - internal static Chamber Get(LockerChamber chamber) => Chambers.TryGetValue(chamber, out Chamber chmb) ? chmb : new(chamber, Locker.Get(x => x.Chambers.Any(x => x.Base == chamber)).FirstOrDefault()); + internal static Chamber Get(LockerChamber chamber) => chamber == null ? null : Chambers.TryGetValue(chamber, out Chamber chmb) ? chmb : new(chamber, Locker.Get(x => x.Chambers.Any(x => x.Base == chamber)).FirstOrDefault()); } } diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs index 95888ddd8b..add2a5123b 100644 --- a/EXILED/Exiled.API/Features/Map.cs +++ b/EXILED/Exiled.API/Features/Map.cs @@ -107,7 +107,7 @@ public static bool IsDecontaminationEnabled /// /// Gets the . /// - public static SqueakSpawner SqueakSpawner => squeakSpawner ??= Object.FindObjectOfType(); + public static SqueakSpawner SqueakSpawner => squeakSpawner ??= Object.FindFirstObjectByType(); /// /// Sends a staff message to all players online with permission. diff --git a/EXILED/Exiled.API/Features/Npc.cs b/EXILED/Exiled.API/Features/Npc.cs index 698b74ad80..7791218042 100644 --- a/EXILED/Exiled.API/Features/Npc.cs +++ b/EXILED/Exiled.API/Features/Npc.cs @@ -11,32 +11,27 @@ namespace Exiled.API.Features using System; using System.Collections.Generic; using System.Linq; - using System.Reflection; - using CentralAuth; using CommandSystem; using CommandSystem.Commands.RemoteAdmin.Dummies; using Exiled.API.Enums; - using Exiled.API.Features.Components; using Exiled.API.Features.CustomStats; using Exiled.API.Features.Roles; using Footprinting; - using GameCore; using MEC; using Mirror; + using NetworkManagerUtils.Dummies; using PlayerRoles; using PlayerStatsSystem; using UnityEngine; - using Object = UnityEngine.Object; - /// /// Wrapper class for handling NPC players. /// public class Npc : Player { /// - /// The time it takes for the NPC to receive its , and . + /// The time it takes for the NPC to receive its and . /// public const float SpawnSetRoleDelay = 0.5f; @@ -263,7 +258,7 @@ public static Npc Spawn(string name, RoleTypeId role, Vector3 position) { npc.Role.Set(role, SpawnReason.ForceClass); npc.Position = position; - npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HealthStat)] = npc.ReferenceHub.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HealthStat))] = npc.CustomHealthStat = new CustomHealthStat { Hub = npc.ReferenceHub }; + npc.CustomHealthStat = (HealthStat)npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HealthStat)]; npc.Health = npc.MaxHealth; // otherwise the npc will spawn with 0 health npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HumeShieldStat)] = npc.ReferenceHub.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HumeShieldStat))] = npc.CustomHumeShieldStat = new CustomHumeShieldStat { Hub = npc.ReferenceHub }; }); @@ -287,7 +282,7 @@ public static Npc Spawn(string name, RoleTypeId role = RoleTypeId.None, bool ign Timing.CallDelayed(SpawnSetRoleDelay, () => { npc.Role.Set(role, SpawnReason.ForceClass, position is null ? RoleSpawnFlags.All : RoleSpawnFlags.AssignInventory); - npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HealthStat)] = npc.ReferenceHub.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HealthStat))] = npc.CustomHealthStat = new CustomHealthStat { Hub = npc.ReferenceHub }; + npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HealthStat)] = npc.ReferenceHub.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HealthStat))] = npc.CustomHealthStat = new HealthStat { Hub = npc.ReferenceHub }; npc.Health = npc.MaxHealth; // otherwise the npc will spawn with 0 health npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HumeShieldStat)] = npc.ReferenceHub.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HumeShieldStat))] = npc.CustomHumeShieldStat = new CustomHumeShieldStat { Hub = npc.ReferenceHub }; diff --git a/EXILED/Exiled.API/Features/Paths.cs b/EXILED/Exiled.API/Features/Paths.cs index 153d8e0bf6..8d99b1a996 100644 --- a/EXILED/Exiled.API/Features/Paths.cs +++ b/EXILED/Exiled.API/Features/Paths.cs @@ -11,6 +11,8 @@ namespace Exiled.API.Features using System.IO; using System.Linq; + using LabApi.Loader; + /// /// A set of useful paths. /// @@ -106,7 +108,7 @@ public static void Reload(string rootDirectory = null) Dependencies = Path.Combine(Plugins, "dependencies"); Configs = Path.Combine(Exiled, "Configs"); IndividualConfigs = Path.Combine(Configs, "Plugins"); - LoaderConfig = PluginAPI.Loader.AssemblyLoader.InstalledPlugins.FirstOrDefault(x => x.PluginName == "Exiled Loader")?.MainConfigPath; + LoaderConfig = LabApi.Loader.PluginLoader.EnabledPlugins.FirstOrDefault(x => x.Name == "Exiled Loader")?.GetConfigPath("Exiled Loader"); Config = Path.Combine(Configs, $"{Server.Port}-config.yml"); BackupConfig = Path.Combine(Configs, $"{Server.Port}-config.yml.old"); IndividualTranslations = Path.Combine(Configs, "Translations"); diff --git a/EXILED/Exiled.API/Features/Pickups/ExplosiveGrenadePickup.cs b/EXILED/Exiled.API/Features/Pickups/ExplosiveGrenadePickup.cs index 061135573d..62484bcceb 100644 --- a/EXILED/Exiled.API/Features/Pickups/ExplosiveGrenadePickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/ExplosiveGrenadePickup.cs @@ -96,8 +96,8 @@ protected override void InitializeProperties(ItemBase itemBase) base.InitializeProperties(itemBase); if (itemBase is ThrowableItem throwable && throwable.Projectile is ExplosionGrenade explosiveGrenade) { - MaxRadius = explosiveGrenade._maxRadius; - ScpDamageMultiplier = explosiveGrenade._scpDamageMultiplier; + MaxRadius = explosiveGrenade.MaxRadius; + ScpDamageMultiplier = explosiveGrenade.ScpDamageMultiplier; BurnDuration = explosiveGrenade._burnedDuration; DeafenDuration = explosiveGrenade._deafenedDuration; ConcussDuration = explosiveGrenade._concussedDuration; diff --git a/EXILED/Exiled.API/Features/Pickups/KeycardPickup.cs b/EXILED/Exiled.API/Features/Pickups/KeycardPickup.cs index 49115119b9..e7e29ff13e 100644 --- a/EXILED/Exiled.API/Features/Pickups/KeycardPickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/KeycardPickup.cs @@ -42,9 +42,9 @@ internal KeycardPickup(ItemType type) } /// - /// Gets or sets the of the keycard. + /// Gets the of the keycard. /// - public KeycardPermissions Permissions { get; set; } + public KeycardPermissions Permissions { get; private set; } /// /// Gets the that this class is encapsulating. @@ -67,7 +67,18 @@ protected override void InitializeProperties(ItemBase itemBase) base.InitializeProperties(itemBase); if (itemBase is KeycardItem keycardItem) { - Permissions = (KeycardPermissions)keycardItem.Permissions; + foreach (DetailBase detail in keycardItem.Details) + { + switch (detail) + { + case PredefinedPermsDetail predefinedPermsDetail: + Permissions = (KeycardPermissions)predefinedPermsDetail.Levels.Permissions; + return; + case CustomPermsDetail customPermsDetail: + Permissions = (KeycardPermissions)customPermsDetail.GetPermissions(null); + return; + } + } } } } diff --git a/EXILED/Exiled.API/Features/Pickups/Projectiles/ExplosionGrenadeProjectile.cs b/EXILED/Exiled.API/Features/Pickups/Projectiles/ExplosionGrenadeProjectile.cs index 70a40ce880..07cdbebefb 100644 --- a/EXILED/Exiled.API/Features/Pickups/Projectiles/ExplosionGrenadeProjectile.cs +++ b/EXILED/Exiled.API/Features/Pickups/Projectiles/ExplosionGrenadeProjectile.cs @@ -49,8 +49,8 @@ internal ExplosionGrenadeProjectile(ItemType type) /// public float MaxRadius { - get => Base._maxRadius; - set => Base._maxRadius = value; + get => Base.MaxRadius; + set => Base.MaxRadius = value; } /// @@ -94,8 +94,8 @@ public float ConcussDuration /// public float ScpDamageMultiplier { - get => Base._scpDamageMultiplier; - set => Base._scpDamageMultiplier = value; + get => Base.ScpDamageMultiplier; + set => Base.ScpDamageMultiplier = value; } /// diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index d13a2265fe..4dfcf09409 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -53,7 +53,6 @@ namespace Exiled.API.Features using PlayerRoles.Spectating; using PlayerRoles.Voice; using PlayerStatsSystem; - using PluginAPI.Core; using RelativePositioning; using RemoteAdmin; using RoundRestarting; @@ -95,6 +94,7 @@ public class Player : TypeCastObject, IEntity, IWorldSpace private readonly HashSet componentsInChildren = new(); private ReferenceHub referenceHub; + private Role role; /// @@ -180,7 +180,7 @@ private set Inventory = value.inventory; CameraTransform = value.PlayerCameraReference; - value.playerStats._dictionarizedTypes[typeof(HealthStat)] = value.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HealthStat))] = CustomHealthStat = new CustomHealthStat { Hub = value }; + CustomHealthStat = (HealthStat)value.playerStats._dictionarizedTypes[typeof(HealthStat)]; value.playerStats._dictionarizedTypes[typeof(HumeShieldStat)] = value.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HumeShieldStat))] = CustomHumeShieldStat = new CustomHumeShieldStat { Hub = value }; } } @@ -351,37 +351,9 @@ public string CustomInfo get => ReferenceHub.nicknameSync.Network_customPlayerInfoString; set { - // NW Client check. - if (value.Contains('<')) + if (!NicknameSync.ValidateCustomInfo(value, out string rejectionText)) { - foreach (string token in value.Split('<')) - { - if (token.StartsWith("/", StringComparison.Ordinal) || - token.StartsWith("b>", StringComparison.Ordinal) || - token.StartsWith("i>", StringComparison.Ordinal) || - token.StartsWith("size=", StringComparison.Ordinal) || - token.Length is 0) - continue; - - if (token.StartsWith("color=", StringComparison.Ordinal)) - { - if (token.Length < 14 || token[13] != '>') - Log.Error($"Custom info of player {Nickname} has been REJECTED. \nreason: (Bad text reject) \ntoken: {token} \nInfo: {value}"); - else if (!Misc.AllowedColors.ContainsValue(token.Substring(6, 7))) - Log.Error($"Custom info of player {Nickname} has been REJECTED. \nreason: (Bad color reject) \ntoken: {token} \nInfo: {value}"); - } - else if (token.StartsWith("#", StringComparison.Ordinal)) - { - if (token.Length < 8 || token[7] != '>') - Log.Error($"Custom info of player {Nickname} has been REJECTED. \nreason: (Bad text reject) \ntoken: {token} \nInfo: {value}"); - else if (!Misc.AllowedColors.ContainsValue(token.Substring(0, 7))) - Log.Error($"Custom info of player {Nickname} has been REJECTED. \nreason: (Bad color reject) \ntoken: {token} \nInfo: {value}"); - } - else - { - Log.Error($"Custom info of player {Nickname} has been REJECTED. \nreason: (Bad color reject) \ntoken: {token} \nInfo: {value}"); - } - } + Log.Error($"Could not set CustomInfo for {Nickname}. Reason: {rejectionText}"); } InfoArea = string.IsNullOrEmpty(value) ? InfoArea & ~PlayerInfoArea.CustomInfo : InfoArea |= PlayerInfoArea.CustomInfo; @@ -424,7 +396,7 @@ public float InfoViewRange /// /// /// - public bool HasReservedSlot => ReservedSlot.HasReservedSlot(UserId, out _); + public bool HasReservedSlot => ReservedSlot.HasReservedSlot(UserId); /// /// Gets a value indicating whether the player is in whitelist. @@ -511,7 +483,7 @@ public Player Cuffer public virtual Vector3 Position { get => Transform.position; - set => ReferenceHub.TryOverridePosition(value, Vector3.zero); + set => ReferenceHub.TryOverridePosition(value); } /// @@ -531,7 +503,7 @@ public RelativePosition RelativePosition public Quaternion Rotation { get => Transform.rotation; - set => ReferenceHub.TryOverridePosition(Position, value.eulerAngles); + set => ReferenceHub.TryOverrideRotation(value.eulerAngles); } /// @@ -885,7 +857,7 @@ public float Health public float MaxHealth { get => CustomHealthStat.MaxValue; - set => CustomHealthStat.CustomMaxValue = value; + set => CustomHealthStat.MaxValue = value; } /// @@ -941,7 +913,7 @@ public float HumeShield public float MaxHumeShield { get => CustomHumeShieldStat.MaxValue; - set => CustomHumeShieldStat.CustomMaxValue = value; + set => CustomHumeShieldStat.MaxValue = value; } /// @@ -1019,8 +991,8 @@ public float Stamina /// public string GroupName { - get => ServerStatic.PermissionsHandler._members.TryGetValue(UserId, out string groupName) ? groupName : null; - set => ServerStatic.PermissionsHandler._members[UserId] = value; + get => ServerStatic.PermissionsHandler.Members.TryGetValue(UserId, out string groupName) ? groupName : null; + set => ServerStatic.PermissionsHandler.Members[UserId] = value; } /// @@ -1189,14 +1161,21 @@ public bool IsSpawnProtected /// /// Gets or sets a . /// - protected CustomHealthStat CustomHealthStat { get; set; } + protected HealthStat CustomHealthStat { get; set; } + + /// + /// Converts LabApi player to EXILED player. + /// + /// The LabApi player. + /// EXILED player. + public static implicit operator Player(LabApi.Features.Wrappers.Player player) => Get(player); /// - /// Converts NwPluginAPI player to EXILED player. + /// Converts LabApi player to EXILED player. /// - /// The NwPluginAPI player. + /// The LabApi player. /// EXILED player. - public static implicit operator Player(PluginAPI.Core.Player player) => Get(player); + public static implicit operator LabApi.Features.Wrappers.Player(Player player) => LabApi.Features.Wrappers.Player.Get(player.ReferenceHub); /// /// Gets a filtered by side. Can be empty. @@ -1387,11 +1366,11 @@ public static Player Get(string args) } /// - /// Gets the from NwPluginAPI class. + /// Gets the from LabApi class. /// - /// The class. + /// The class. /// A or if not found. - public static Player Get(PluginAPI.Core.Player apiPlayer) => Get(apiPlayer.ReferenceHub); + public static Player Get(LabApi.Features.Wrappers.Player apiPlayer) => Get(apiPlayer.ReferenceHub); /// /// Try-get a player given a . @@ -1474,12 +1453,12 @@ public static Player Get(string args) public static bool TryGet(string args, out Player player) => (player = Get(args)) is not null; /// - /// Try-get the from NwPluginAPI class. + /// Try-get the from LabApi class. /// - /// The class. + /// The class. /// The player found or if not found. /// A boolean indicating whether a player was found. - public static bool TryGet(PluginAPI.Core.Player apiPlayer, out Player player) => (player = Get(apiPlayer)) is not null; + public static bool TryGet(LabApi.Features.Wrappers.Player apiPlayer, out Player player) => (player = Get(apiPlayer)) is not null; /// /// Try-get player by . @@ -1518,10 +1497,10 @@ public static bool AddReservedSlot(string userId, bool isPermanent) { if (isPermanent) { - if (ReservedSlots.HasReservedSlot(userId)) + if (LabApi.Features.Wrappers.ReservedSlots.HasReservedSlot(userId)) return false; - ReservedSlots.Add(userId); + LabApi.Features.Wrappers.ReservedSlots.Add(userId); return true; } @@ -1542,7 +1521,7 @@ public static bool AddToWhitelist(string userId, bool isPermanent) if (WhiteList.IsOnWhitelist(userId)) return false; - Whitelist.Add(userId); + LabApi.Features.Wrappers.Whitelist.Add(userId); return true; } @@ -1834,7 +1813,7 @@ public bool TryGetItem(ushort serial, out Item item) /// The group to be set. public void SetRank(string name, UserGroup group) { - if (ServerStatic.GetPermissionsHandler()._groups.TryGetValue(name, out UserGroup userGroup)) + if (ServerStatic.PermissionsHandler.Groups.TryGetValue(name, out UserGroup userGroup)) { userGroup.BadgeColor = group.BadgeColor; userGroup.BadgeText = name; @@ -1845,15 +1824,15 @@ public void SetRank(string name, UserGroup group) } else { - ServerStatic.GetPermissionsHandler()._groups.Add(name, group); + ServerStatic.PermissionsHandler.Groups.Add(name, group); ReferenceHub.serverRoles.SetGroup(group, false, false); } - if (ServerStatic.GetPermissionsHandler()._members.ContainsKey(UserId)) - ServerStatic.GetPermissionsHandler()._members[UserId] = name; + if (ServerStatic.PermissionsHandler.Members.ContainsKey(UserId)) + ServerStatic.PermissionsHandler.Members[UserId] = name; else - ServerStatic.GetPermissionsHandler()._members.Add(UserId, name); + ServerStatic.PermissionsHandler.Members.Add(UserId, name); } /// @@ -2983,9 +2962,6 @@ public void ClearInventory(bool destroy = true) /// public void ClearItems(bool destroy = true) { - if (CurrentArmor is Armor armor) - armor.RemoveExcessOnDrop = false; - while (Items.Count > 0) RemoveItem(Items.ElementAt(0), destroy); } @@ -3609,7 +3585,7 @@ public void Teleport(object obj, Vector3 offset) Teleport(locker.transform.position + Vector3.up + offset); break; case LockerChamber chamber: - Teleport(chamber._spawnpoint.position + Vector3.up + offset); + Teleport(chamber.Spawnpoint.position + Vector3.up + offset); break; case ElevatorChamber elevator: Teleport(elevator.transform.position + Vector3.up + offset); diff --git a/EXILED/Exiled.API/Features/Ragdoll.cs b/EXILED/Exiled.API/Features/Ragdoll.cs index 8cde5d8cb2..011c092248 100644 --- a/EXILED/Exiled.API/Features/Ragdoll.cs +++ b/EXILED/Exiled.API/Features/Ragdoll.cs @@ -101,7 +101,7 @@ public RagdollData NetworkInfo public DamageHandlerBase DamageHandler { get => NetworkInfo.Handler; - set => NetworkInfo = new(NetworkInfo.OwnerHub, value, NetworkInfo.RoleType, NetworkInfo.StartPosition, NetworkInfo.StartRotation, NetworkInfo.Nickname, NetworkInfo.CreationTime); + set => NetworkInfo = new(NetworkInfo.OwnerHub, value, NetworkInfo.RoleType, NetworkInfo.StartPosition, NetworkInfo.StartRotation, NetworkInfo.Scale, NetworkInfo.Nickname, NetworkInfo.CreationTime); } /// @@ -145,7 +145,16 @@ public bool CanBeCleanedUp public string Nickname { get => NetworkInfo.Nickname; - set => NetworkInfo = new(NetworkInfo.OwnerHub, NetworkInfo.Handler, NetworkInfo.RoleType, NetworkInfo.StartPosition, NetworkInfo.StartRotation, value, NetworkInfo.CreationTime); + set => NetworkInfo = new(NetworkInfo.OwnerHub, NetworkInfo.Handler, NetworkInfo.RoleType, NetworkInfo.StartPosition, NetworkInfo.StartRotation, NetworkInfo.Scale, value, NetworkInfo.CreationTime); + } + + /// + /// Gets or sets the ragdoll's Scale with RagdollData. + /// + public Vector3 Scale + { + get => NetworkInfo.Scale; + set => NetworkInfo = new(NetworkInfo.OwnerHub, NetworkInfo.Handler, NetworkInfo.RoleType, NetworkInfo.StartPosition, NetworkInfo.StartRotation, value, NetworkInfo.Nickname, NetworkInfo.CreationTime); } /// @@ -159,7 +168,7 @@ public string Nickname public Player Owner { get => Player.Get(NetworkInfo.OwnerHub); - set => NetworkInfo = new(value.ReferenceHub, NetworkInfo.Handler, NetworkInfo.RoleType, NetworkInfo.StartPosition, NetworkInfo.StartRotation, NetworkInfo.Nickname, NetworkInfo.CreationTime); + set => NetworkInfo = new(value.ReferenceHub, NetworkInfo.Handler, NetworkInfo.RoleType, NetworkInfo.StartPosition, NetworkInfo.StartRotation, NetworkInfo.Scale, NetworkInfo.Nickname, NetworkInfo.CreationTime); } /// @@ -171,7 +180,7 @@ public DateTime CreationTime set { float creationTime = (float)(NetworkTime.time - (DateTime.Now - value).TotalSeconds); - NetworkInfo = new RagdollData(NetworkInfo.OwnerHub, NetworkInfo.Handler, NetworkInfo.RoleType, NetworkInfo.StartPosition, NetworkInfo.StartRotation, NetworkInfo.Nickname, creationTime); + NetworkInfo = new RagdollData(NetworkInfo.OwnerHub, NetworkInfo.Handler, NetworkInfo.RoleType, NetworkInfo.StartPosition, NetworkInfo.StartRotation, NetworkInfo.Scale, NetworkInfo.Nickname, creationTime); } } @@ -181,7 +190,7 @@ public DateTime CreationTime public RoleTypeId Role { get => NetworkInfo.RoleType; - set => NetworkInfo = new(NetworkInfo.OwnerHub, NetworkInfo.Handler, value, NetworkInfo.StartPosition, NetworkInfo.StartRotation, NetworkInfo.Nickname, NetworkInfo.CreationTime); + set => NetworkInfo = new(NetworkInfo.OwnerHub, NetworkInfo.Handler, value, NetworkInfo.StartPosition, NetworkInfo.StartRotation, NetworkInfo.Scale, NetworkInfo.Nickname, NetworkInfo.CreationTime); } /// @@ -248,9 +257,9 @@ public Quaternion Rotation } /// - /// Gets or sets the ragdoll's scale. + /// Gets or sets the ragdoll's as Gameobjectscale. /// - public Vector3 Scale + public Vector3 RagdollScale { get => Base.transform.localScale; set diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs index ecc946c9b7..d1c0a12591 100644 --- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs +++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs @@ -27,7 +27,6 @@ namespace Exiled.API.Features.Roles /// public abstract class FpcRole : Role, IVoiceRole { - private static FieldInfo enableFallDamageField; private bool isUsingStamina = true; /// @@ -68,17 +67,31 @@ public RelativePosition ClientRelativePosition set => FirstPersonController.FpcModule.Motor.ReceivedPosition = value; } + /// + /// Gets or sets the player's gravity. + /// + public Vector3 Gravity + { + get => FirstPersonController.FpcModule.Motor.GravityController.Gravity; + set => FirstPersonController.FpcModule.Motor.GravityController.Gravity = value; + } + /// /// Gets or sets a value indicating whether if the player should get damage. /// public bool IsFallDamageEnable { - get => FirstPersonController.FpcModule.Motor._enableFallDamage; - set - { - enableFallDamageField ??= AccessTools.Field(typeof(FpcMotor), nameof(FpcMotor._enableFallDamage)); - enableFallDamageField.SetValue(FirstPersonController.FpcModule.Motor, value); - } + get => FirstPersonController.FpcModule.Motor._fallDamageSettings.Enabled; + set => FirstPersonController.FpcModule.Motor._fallDamageSettings.Enabled = value; + } + + /// + /// Gets or sets the multiplier of damage. + /// + public float FallDamageMultiplier + { + get => FirstPersonController.FpcModule.Motor._fallDamageSettings.Multiplier; + set => FirstPersonController.FpcModule.Motor._fallDamageSettings.Multiplier = value; } /// diff --git a/EXILED/Exiled.API/Features/Roles/HumanRole.cs b/EXILED/Exiled.API/Features/Roles/HumanRole.cs index 8a238a3e7d..767a010d45 100644 --- a/EXILED/Exiled.API/Features/Roles/HumanRole.cs +++ b/EXILED/Exiled.API/Features/Roles/HumanRole.cs @@ -8,7 +8,7 @@ namespace Exiled.API.Features.Roles { using PlayerRoles; - + using PlayerRoles.PlayableScps.HumeShield; using Respawning; using Respawning.NamingRules; @@ -17,7 +17,7 @@ namespace Exiled.API.Features.Roles /// /// Defines a role that represents a human class. /// - public class HumanRole : FpcRole + public class HumanRole : FpcRole, IHumeShieldRole { /// /// Initializes a new instance of the class. @@ -27,6 +27,7 @@ internal HumanRole(HumanGameRole baseRole) : base(baseRole) { Base = baseRole; + HumeShieldModule = baseRole.HumeShieldModule; } /// @@ -56,6 +57,9 @@ public byte UnitNameId /// public new HumanGameRole Base { get; } + /// + public HumeShieldModuleBase HumeShieldModule { get; } + /// /// Gets the armor efficacy based on a specific and the armor the is wearing. /// diff --git a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs index 9c0ac35eb4..6a58fcd444 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs @@ -118,40 +118,6 @@ internal Scp049Role(Scp049GameRole baseRole) /// public IEnumerable DeadZombies => Scp049ResurrectAbility.DeadZombies.Select(x => Player.Get(x)); - // TODO: ReAdd Setter but before making an propper way to overwrite NW constant only when the propperty has been used -#pragma warning disable SA1623 // Property summary documentation should match accessors -#pragma warning disable SA1202 - /// - /// Gets or sets how mush time the Call Ability will be effective. - /// - internal double CallAbilityDuration { get; } = Scp049CallAbility.EffectDuration; - - /// - /// Gets or sets the Cooldown of the Call Ability. - /// - internal double CallAbilityBaseCooldown { get; } = Scp049CallAbility.BaseCooldown; - - /// - /// Gets or sets the Cooldown of the Sense Ability. - /// - internal double SenseAbilityBaseCooldown { get; } = Scp049SenseAbility.BaseCooldown; - - /// - /// Gets or sets the Cooldown of the Sense Ability when you lost your target. - /// - internal double SenseAbilityReducedCooldown { get; } = Scp049SenseAbility.ReducedCooldown; - - /// - /// Gets or sets the Cooldown of the Sense Ability when it's failed. - /// - internal double SenseAbilityDuration { get; } = Scp049SenseAbility.EffectDuration; - - /// - /// Gets or sets how mush time the Sense Ability will be effective. - /// - internal double SenseAbilityFailCooldown { get; } = Scp049SenseAbility.AttemptFailCooldown; -#pragma warning restore SA1623 // Property summary documentation should match accessors - /// /// Gets all the resurrected players. /// @@ -319,7 +285,7 @@ public void Sense(Player player) if (SenseAbility.Target is null) { - SenseAbility.Cooldown.Trigger(SenseAbilityFailCooldown); + SenseAbility.Cooldown.Trigger(Scp049SenseAbility.AttemptFailCooldown); SenseAbility.ServerSendRpc(true); return; } @@ -332,7 +298,7 @@ public void Sense(Player player) if (!VisionInformation.GetVisionInformation(SenseAbility.Owner, SenseAbility.Owner.PlayerCameraReference, humanRole.CameraPosition, radius, SenseAbility._distanceThreshold).IsLooking) return; - SenseAbility.Duration.Trigger(SenseAbilityDuration); + SenseAbility.Duration.Trigger(Scp049SenseAbility.EffectDuration); SenseAbility.HasTarget = true; SenseAbility.ServerSendRpc(true); } diff --git a/EXILED/Exiled.API/Features/Roles/Scp079Role.cs b/EXILED/Exiled.API/Features/Roles/Scp079Role.cs index 2480ca3d88..c2b8cb70ce 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp079Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp079Role.cs @@ -593,7 +593,7 @@ public void ActivateTesla(bool consumeEnergy = true) Scp079Camera cam = CurrentCameraSync.CurrentCamera; RewardManager.MarkRoom(cam.Room); - if (!global::TeslaGate.AllGates.TryGetFirst(x => RoomIdUtils.IsTheSameRoom(cam.Position, x.transform.position), out global::TeslaGate teslaGate)) + if (!global::TeslaGate.AllGates.TryGetFirst(x => cam.Position.TryGetRoom(out RoomIdentifier camRoom) && x.transform.position.TryGetRoom(out RoomIdentifier teslaRoom) && camRoom == teslaRoom, out global::TeslaGate teslaGate)) return; if (consumeEnergy) diff --git a/EXILED/Exiled.API/Features/Room.cs b/EXILED/Exiled.API/Features/Room.cs index 9fde18957c..e5bcc9c0d5 100644 --- a/EXILED/Exiled.API/Features/Room.cs +++ b/EXILED/Exiled.API/Features/Room.cs @@ -246,7 +246,7 @@ public static Room Get(RoomIdentifier roomIdentifier) => roomIdentifier == null /// /// The to search for. /// The with the given or if not found. - public static Room Get(Vector3 position) => RoomIdUtils.RoomAtPositionRaycasts(position, false) is RoomIdentifier identifier ? Get(identifier) : null; + public static Room Get(Vector3 position) => position.TryGetRoom(out RoomIdentifier room) ? Get(room) : null; /// /// Gets a given the specified . @@ -421,7 +421,7 @@ internal void InternalCreate() Identifier = gameObject.GetComponent(); RoomIdentifierToRoom.Add(Identifier, this); - Zone = FindZone(gameObject); + Zone = Identifier.Zone.GetZone(); #if DEBUG if (Zone is ZoneType.Unspecified) Log.Error($"[ZONETYPE UNKNOWN] {this} Zone : {Identifier?.Zone}"); @@ -496,6 +496,8 @@ private static RoomType FindType(GameObject gameObject) "HCZ_Straight Variant" => RoomType.HczStraightVariant, "HCZ_ChkpA" => RoomType.HczElevatorA, "HCZ_ChkpB" => RoomType.HczElevatorB, + "HCZ_127" => RoomType.Hcz127, + "HCZ_ServerRoom" => RoomType.HczServerRoom, "EZ_GateA" => RoomType.EzGateA, "EZ_GateB" => RoomType.EzGateB, "EZ_ThreeWay" => RoomType.EzTCross, @@ -527,22 +529,5 @@ private static RoomType FindType(GameObject gameObject) _ => RoomType.Unknown, }; } - - private static ZoneType FindZone(GameObject gameObject) - { - Transform transform = gameObject.transform; - - if (gameObject.name == "PocketWorld") - return ZoneType.Pocket; - - return transform.parent?.name.RemoveBracketsOnEndOfName() switch - { - "HeavyRooms" => ZoneType.HeavyContainment, - "LightRooms" => ZoneType.LightContainment, - "EntranceRooms" => ZoneType.Entrance, - "HCZ_EZ_Checkpoint" => ZoneType.HeavyContainment | ZoneType.Entrance, - _ => transform.position.y > 900 ? ZoneType.Surface : ZoneType.Unspecified, - }; - } } } diff --git a/EXILED/Exiled.API/Features/Round.cs b/EXILED/Exiled.API/Features/Round.cs index b6ee2b35fc..a278e169dc 100644 --- a/EXILED/Exiled.API/Features/Round.cs +++ b/EXILED/Exiled.API/Features/Round.cs @@ -54,7 +54,7 @@ public static class Round /// /// Gets a value indicating whether the round is ended. /// - public static bool IsEnded => RoundSummary._singletonSet && RoundSummary.singleton._roundEnded; + public static bool IsEnded => RoundSummary._singletonSet && RoundSummary.singleton.IsRoundEnded; /// /// Gets a value indicating whether the round is lobby. diff --git a/EXILED/Exiled.API/Features/Scp914.cs b/EXILED/Exiled.API/Features/Scp914.cs index 57ee9d366c..7d9ea65818 100644 --- a/EXILED/Exiled.API/Features/Scp914.cs +++ b/EXILED/Exiled.API/Features/Scp914.cs @@ -40,8 +40,8 @@ public static Scp914KnobSetting KnobStatus /// public static Scp914Mode ConfigMode { - get => Scp914Controller._configMode.Value; - set => Scp914Controller._configMode.Value = value; + get => Scp914Controller.ConfigMode.Value; + set => Scp914Controller.ConfigMode.Value = value; } /// @@ -72,7 +72,7 @@ public static Scp914Mode ConfigMode /// /// Gets a value indicating whether SCP-914 is active and currently processing items. /// - public static bool IsWorking => Scp914Controller._isUpgrading; + public static bool IsWorking => Scp914Controller.IsUpgrading; /// /// Gets a value indicating all of the GameObjects currently present inside SCP-914's intake chamber. @@ -92,7 +92,7 @@ public static Scp914Mode ConfigMode /// /// Gets the list with which SCP-914 has. /// - public static IReadOnlyCollection Doors => Scp914Controller._doors.Select(Door.Get).ToList(); + public static IReadOnlyCollection Doors => Scp914Controller.Doors.Select(Door.Get).ToList(); /// /// Filters all GameObjects inside SCP-914's intake chamber into players and items. diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs index 1e41ad0904..5de5dd5655 100644 --- a/EXILED/Exiled.API/Features/Server.cs +++ b/EXILED/Exiled.API/Features/Server.cs @@ -60,11 +60,11 @@ public static class Server /// public static string Name { - get => ServerConsole._serverName; + get => ServerConsole.ServerName; set { - ServerConsole._serverName = value; - ServerConsole.singleton.RefreshServerNameSafe(); + ServerConsole.ServerName = value; + ServerConsole.Singleton.RefreshServerNameSafe(); } } diff --git a/EXILED/Exiled.API/Features/Toys/AdminToy.cs b/EXILED/Exiled.API/Features/Toys/AdminToy.cs index a3ffa539cd..4a82030c8c 100644 --- a/EXILED/Exiled.API/Features/Toys/AdminToy.cs +++ b/EXILED/Exiled.API/Features/Toys/AdminToy.cs @@ -166,6 +166,10 @@ public static AdminToy Get(AdminToyBase adminToyBase) PrimitiveObjectToy primitiveObjectToy => new Primitive(primitiveObjectToy), ShootingTarget shootingTarget => new ShootingTargetToy(shootingTarget), SpeakerToy speakerToy => new Speaker(speakerToy), + CapybaraToy capybaraToy => new Capybara(capybaraToy), + Scp079CameraToy scp079CameraToy => new CameraToy(scp079CameraToy), + InvisibleInteractableToy invisibleInteractableToy => new InteractableToy(invisibleInteractableToy), + TextToy textToy => new Text(textToy), _ => throw new System.NotImplementedException() }; } diff --git a/EXILED/Exiled.API/Features/Toys/CameraToy.cs b/EXILED/Exiled.API/Features/Toys/CameraToy.cs new file mode 100644 index 0000000000..518c4d789a --- /dev/null +++ b/EXILED/Exiled.API/Features/Toys/CameraToy.cs @@ -0,0 +1,83 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Toys +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + using AdminToys; + using Exiled.API.Enums; + using Exiled.API.Interfaces; + using UnityEngine; + + /// + /// A wrapper class for . + /// + internal class CameraToy : AdminToy, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// The of the toy. + internal CameraToy(Scp079CameraToy scp079CameraToy) + : base(scp079CameraToy, AdminToyType.CameraToy) => Base = scp079CameraToy; + + /// + /// Gets the base . + /// + public Scp079CameraToy Base { get; } + + /// + /// Gets or sets the Vertical Restriction. + /// + public Vector2 VerticalConstraint + { + get => Base.NetworkVerticalConstraint; + set => Base.NetworkVerticalConstraint = value; + } + + /// + /// Gets or sets the Horizontal restriction. + /// + public Vector2 HorizontalConstraint + { + get => Base.NetworkHorizontalConstraint; + set => Base.NetworkHorizontalConstraint = value; + } + + /// + /// Gets or sets the Zoom restriction. + /// + public Vector2 ZoomConstraint + { + get => Base.NetworkZoomConstraint; + set => Base.NetworkZoomConstraint = value; + } + + /// + /// Gets or sets the Room where the Camera is associated with. + /// + public Room Room + { + get => Room.Get(Base.NetworkRoom); + set => Base.NetworkRoom = value.Identifier; + } + + /// + /// Gets or sets the Name of the Camera. + /// + public string Name + { + get => Base.NetworkLabel; + set => Base.NetworkLabel = value; + } + } +} diff --git a/EXILED/Exiled.API/Features/Toys/Capybara.cs b/EXILED/Exiled.API/Features/Toys/Capybara.cs new file mode 100644 index 0000000000..b88dbfd9c8 --- /dev/null +++ b/EXILED/Exiled.API/Features/Toys/Capybara.cs @@ -0,0 +1,45 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Toys +{ + using AdminToys; + using Enums; + using Exiled.API.Interfaces; + + /// + /// A wrapper class for . + /// + public class Capybara : AdminToy, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// The of the toy. + internal Capybara(CapybaraToy speakerToy) + : base(speakerToy, AdminToyType.Speaker) => Base = speakerToy; + + /// + /// Gets the prefab. + /// + public static CapybaraToy Prefab => PrefabHelper.GetPrefab(PrefabType.CapybaraToy); + + /// + /// Gets the base . + /// + public CapybaraToy Base { get; } + + /// + /// Gets or sets a value indicating whether the capybara can be collided with. + /// + public bool Collidable + { + get => Base.Network_collisionsEnabled; + set => Base.Network_collisionsEnabled = value; + } + } +} diff --git a/EXILED/Exiled.API/Features/Toys/InteractableToy.cs b/EXILED/Exiled.API/Features/Toys/InteractableToy.cs new file mode 100644 index 0000000000..c6c73936cd --- /dev/null +++ b/EXILED/Exiled.API/Features/Toys/InteractableToy.cs @@ -0,0 +1,61 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Toys +{ + using AdminToys; + using Exiled.API.Enums; + using Exiled.API.Interfaces; + using UnityEngine; + + using static AdminToys.InvisibleInteractableToy; + + /// + /// A wrapper class for . + /// + internal class InteractableToy : AdminToy, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// The of the toy. + internal InteractableToy(InvisibleInteractableToy invisibleInteractableToy) + : base(invisibleInteractableToy, AdminToyType.InvisibleInteractableToy) => Base = invisibleInteractableToy; + + /// + /// Gets the base . + /// + public InvisibleInteractableToy Base { get; } + + /// + /// Gets or sets the Shape of the Interactable. + /// + public ColliderShape Shape + { + get => Base.NetworkShape; + set => Base.NetworkShape = value; + } + + /// + /// Gets or sets the time to interact with the Interactable. + /// + public float InteractionDuration + { + get => Base.NetworkInteractionDuration; + set => Base.NetworkInteractionDuration = value; + } + + /// + /// Gets or sets a value indicating whether the interactable is locked. + /// + public bool IsLocked + { + get => Base.NetworkIsLocked; + set => Base.NetworkIsLocked = value; + } + } +} diff --git a/EXILED/Exiled.API/Features/Toys/Light.cs b/EXILED/Exiled.API/Features/Toys/Light.cs index 9496f6b833..9e167d1bb5 100644 --- a/EXILED/Exiled.API/Features/Toys/Light.cs +++ b/EXILED/Exiled.API/Features/Toys/Light.cs @@ -7,6 +7,7 @@ namespace Exiled.API.Features.Toys { + using System; using System.Linq; using AdminToys; @@ -98,6 +99,7 @@ public Color Color /// /// Gets or sets the shape that the Light emits. /// + [Obsolete("This property has been deprecated. Use LightType.Spot, LightType.Pyramid, or LightType.Box instead.")] public LightShape LightShape { get => Base.NetworkLightShape; diff --git a/EXILED/Exiled.API/Features/Toys/Text.cs b/EXILED/Exiled.API/Features/Toys/Text.cs new file mode 100644 index 0000000000..7c3317cd22 --- /dev/null +++ b/EXILED/Exiled.API/Features/Toys/Text.cs @@ -0,0 +1,55 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Toys +{ + using AdminToys; + using Enums; + using Exiled.API.Interfaces; + using UnityEngine; + + /// + /// A wrapper class for . + /// + public class Text : AdminToy, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// The of the toy. + internal Text(TextToy speakerToy) + : base(speakerToy, AdminToyType.TextToy) => Base = speakerToy; + + /// + /// Gets the prefab. + /// + public static TextToy Prefab => PrefabHelper.GetPrefab(PrefabType.TextToy); + + /// + /// Gets the base . + /// + public TextToy Base { get; } + + /// + /// Gets or sets the Text shown. + /// + public string TextFormat + { + get => Base.Network_textFormat; + set => Base.Network_textFormat = value; + } + + /// + /// Gets or sets the size of the Display Size of the Text. + /// + public Vector2 DisplaySize + { + get => Base.Network_displaySize; + set => Base.Network_displaySize = value; + } + } +} diff --git a/EXILED/Exiled.API/Features/Warhead.cs b/EXILED/Exiled.API/Features/Warhead.cs index 22ccf2207e..97ce5a9cfe 100644 --- a/EXILED/Exiled.API/Features/Warhead.cs +++ b/EXILED/Exiled.API/Features/Warhead.cs @@ -35,7 +35,7 @@ public static class Warhead /// /// Gets the cached component. /// - public static AlphaWarheadOutsitePanel OutsitePanel => alphaWarheadOutsitePanel != null ? alphaWarheadOutsitePanel : (alphaWarheadOutsitePanel = UnityEngine.Object.FindObjectOfType()); + public static AlphaWarheadOutsitePanel OutsitePanel => alphaWarheadOutsitePanel != null ? alphaWarheadOutsitePanel : (alphaWarheadOutsitePanel = UnityEngine.Object.FindFirstObjectByType()); /// /// Gets the of the warhead lever. @@ -84,8 +84,8 @@ public static bool LeverStatus /// public static bool IsKeycardActivated { - get => OutsitePanel.NetworkkeycardEntered; - set => OutsitePanel.NetworkkeycardEntered = value; + get => AlphaWarheadActivationPanel.IsUnlocked; + set => AlphaWarheadActivationPanel.IsUnlocked = value; } /// @@ -168,7 +168,16 @@ public static int Kills public static void CloseBlastDoors() { foreach (BlastDoor door in BlastDoors) - door.SetClosed(false, true); + door.SetDoorState(true, false); + } + + /// + /// Open the surface blast doors. + /// + public static void OpenBlastDoors() + { + foreach (BlastDoor door in BlastDoors) + door.SetDoorState(false, true); } /// diff --git a/EXILED/Exiled.API/Features/Window.cs b/EXILED/Exiled.API/Features/Window.cs index d11fe275ef..892733246b 100644 --- a/EXILED/Exiled.API/Features/Window.cs +++ b/EXILED/Exiled.API/Features/Window.cs @@ -45,7 +45,7 @@ internal Window(BreakableWindow window, Room room) } /// - /// Gets a of which contains all the instances. + /// Gets a of which contains all the instances. /// public static IReadOnlyCollection List => BreakableWindowToWindow.Values; @@ -225,6 +225,7 @@ public void DamageWindow(float amount, DamageHandlerBase handler) RoomType.HczTestRoom => GlassType.TestRoom, RoomType.HczEzCheckpointA => GlassType.HczEzCheckpointA, RoomType.HczEzCheckpointB => GlassType.HczEzCheckpointB, + RoomType.Hcz127 => GlassType.Scp127, _ => GlassType.Unknown, }; } diff --git a/EXILED/Exiled.CreditTags/Exiled.CreditTags.csproj b/EXILED/Exiled.CreditTags/Exiled.CreditTags.csproj index 9382489fb3..a169d69155 100644 --- a/EXILED/Exiled.CreditTags/Exiled.CreditTags.csproj +++ b/EXILED/Exiled.CreditTags/Exiled.CreditTags.csproj @@ -27,13 +27,13 @@ + - - + diff --git a/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs b/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs index 11c6a6c2a1..c2ec515742 100644 --- a/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs +++ b/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs @@ -17,7 +17,7 @@ namespace Exiled.CreditTags.Features public static class DatabaseHandler { - private const string Url = "https://raw.githubusercontent.com/ExMod-Team/CreditTags/main/data.yml"; + private const string Url = "https://raw.githubusercontent.com/ExSLMod-Team/CreditTags/main/data.yml"; private const string ETagCacheFileName = "etag_cache.txt"; private const string DatabaseCacheFileName = "data.yml"; private const int CacheTimeInMinutes = 5; diff --git a/EXILED/Exiled.CustomItems/API/EventArgs/OwnerEscapingEventArgs.cs b/EXILED/Exiled.CustomItems/API/EventArgs/OwnerEscapingEventArgs.cs index 2fc89ef333..54f478d7ce 100644 --- a/EXILED/Exiled.CustomItems/API/EventArgs/OwnerEscapingEventArgs.cs +++ b/EXILED/Exiled.CustomItems/API/EventArgs/OwnerEscapingEventArgs.cs @@ -30,7 +30,7 @@ public class OwnerEscapingEventArgs : EscapingEventArgs /// /// The instance. public OwnerEscapingEventArgs(Item item, EscapingEventArgs ev) - : base(ev.Player, ev.NewRole, ev.EscapeScenario) + : base(ev.Player.ReferenceHub, ev.NewRole, ev.EscapeScenario) { Item = item; } diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomArmor.cs b/EXILED/Exiled.CustomItems/API/Features/CustomArmor.cs index f87d473783..e6f1932905 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomArmor.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomArmor.cs @@ -8,13 +8,16 @@ namespace Exiled.CustomItems.API.Features { using System; + using System.Collections.Generic; using System.ComponentModel; using Exiled.API.Extensions; using Exiled.API.Features; using Exiled.API.Features.Items; + using Exiled.API.Structs; using Exiled.Events.EventArgs.Player; + using InventorySystem.Items.Armor; using MEC; /// @@ -55,6 +58,16 @@ public override ItemType Type [Description("The value must be above 0 and below 100")] public virtual int VestEfficacy { get; set; } = 80; + /// + /// Gets or sets the Ammunition limit the player have. + /// + public virtual List AmmoLimits { get; set; } = new(); + + /// + /// Gets or sets the Item Category limit the player have. + /// + public virtual List CategoryLimits { get; set; } = new(); + /// public override void Give(Player player, bool displayMessage = true) { @@ -66,6 +79,12 @@ public override void Give(Player player, bool displayMessage = true) armor.VestEfficacy = VestEfficacy; armor.HelmetEfficacy = HelmetEfficacy; + if (AmmoLimits.Count != 0) + armor.AmmoLimits = AmmoLimits; + + if (AmmoLimits.Count != 0) + armor.CategoryLimits = CategoryLimits; + player.AddItem(armor); TrackedSerials.Add(armor.Serial); diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomKeycard.cs b/EXILED/Exiled.CustomItems/API/Features/CustomKeycard.cs index e28f1ea3d3..d53846cbb0 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomKeycard.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomKeycard.cs @@ -8,6 +8,7 @@ namespace Exiled.CustomItems.API.Features { using System; + using System.Linq; using Exiled.API.Enums; using Exiled.API.Extensions; @@ -18,6 +19,8 @@ namespace Exiled.CustomItems.API.Features using Exiled.API.Features.Pickups; using Exiled.Events.EventArgs.Item; using Exiled.Events.EventArgs.Player; + using Interactables.Interobjects.DoorUtils; + using InventorySystem.Items.Keycards; using UnityEngine; /// @@ -33,16 +36,41 @@ public override ItemType Type set { if (!value.IsKeycard()) - throw new ArgumentOutOfRangeException("Type", value, "Invalid keycard type."); + throw new ArgumentOutOfRangeException(nameof(Type), value, "Invalid keycard type."); base.Type = value; } } + /// + /// Gets or sets name of keycard holder. + /// + public virtual string KeycardName { get; set; } = string.Empty; + + /// + /// Gets or sets a label for keycard. + /// + public virtual string KeycardLabel { get; set; } = string.Empty; + + /// + /// Gets or sets a color of keycard label. + /// + public virtual Color32? KeycardLabelColor { get; set; } + + /// + /// Gets or sets a tint color. + /// + public virtual Color32? TintColor { get; set; } + /// /// Gets or sets the permissions for custom keycard. /// - public virtual KeycardPermissions Permissions { get; set; } + public virtual KeycardPermissions Permissions { get; set; } = KeycardPermissions.None; + + /// + /// Gets or sets a color of keycard permissions. + /// + public virtual Color32? KeycardPermissionsColor { get; set; } /// public override void Give(Player player, Item item, bool displayMessage = true) @@ -50,18 +78,66 @@ public override void Give(Player player, Item item, bool displayMessage = true) base.Give(player, item, displayMessage); if (item.Is(out Keycard card)) - card.Permissions = Permissions; + SetupKeycard(card); } /// public override Pickup? Spawn(Vector3 position, Item item, Player? previousOwner = null) { if (item.Is(out Keycard card)) - card.Permissions = Permissions; + SetupKeycard(card); return base.Spawn(position, item, previousOwner); } + /// + /// Setups keycard according to this class. + /// + /// Item instance. + protected virtual void SetupKeycard(Keycard keycard) + { + if (!keycard.Base.Customizable) + return; + + DetailBase[] details = keycard.Base.Details; + + NametagDetail? nameDetail = details.OfType().FirstOrDefault(); + + if (nameDetail != null && !string.IsNullOrEmpty(KeycardName)) + NametagDetail._customNametag = KeycardName; + + CustomItemNameDetail? raNameDetail = details.OfType().FirstOrDefault(); + + if (raNameDetail != null) + raNameDetail.Name = Name; + + CustomLabelDetail? labelDetail = details.OfType().FirstOrDefault(); + + if (labelDetail != null) + { + if (!string.IsNullOrEmpty(KeycardLabel)) + CustomLabelDetail._customText = KeycardLabel; + + if (KeycardLabelColor.HasValue) + CustomLabelDetail._customColor = KeycardLabelColor.Value; + } + + CustomPermsDetail? permsDetail = details.OfType().FirstOrDefault(); + + if (permsDetail != null) + { + CustomPermsDetail._customLevels = new((DoorPermissionFlags)Permissions); + CustomPermsDetail._customColor = KeycardPermissionsColor; + } + + CustomTintDetail? tintDetail = details.OfType().FirstOrDefault(); + + if (tintDetail != null && TintColor.HasValue) + { + CustomTintDetail._customColor = TintColor.Value; + } + } + /// /// Called when custom keycard interacts with a door. /// diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs b/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs index e775ee3e9f..277037494e 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs @@ -52,7 +52,7 @@ public override ItemType Type /// /// Gets or sets the weapon damage. /// - public abstract float Damage { get; set; } + public virtual float Damage { get; set; } = -1; /// /// Gets or sets a value indicating how big of a clip the weapon will have. @@ -205,7 +205,7 @@ protected virtual void OnShot(ShotEventArgs ev) /// . protected virtual void OnHurting(HurtingEventArgs ev) { - if (ev.IsAllowed && Damage > 0f) + if (ev.IsAllowed && Damage >= 0) ev.Amount = Damage; } diff --git a/EXILED/Exiled.CustomItems/Exiled.CustomItems.csproj b/EXILED/Exiled.CustomItems/Exiled.CustomItems.csproj index 703a8a7c77..6d45708c17 100644 --- a/EXILED/Exiled.CustomItems/Exiled.CustomItems.csproj +++ b/EXILED/Exiled.CustomItems/Exiled.CustomItems.csproj @@ -28,9 +28,9 @@ + - diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 60d3f44d60..ba6ecc95f8 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -18,6 +18,7 @@ namespace Exiled.CustomRoles.API.Features using Exiled.API.Features; using Exiled.API.Features.Attributes; using Exiled.API.Features.Pools; + using Exiled.API.Features.Roles; using Exiled.API.Features.Spawn; using Exiled.API.Interfaces; using Exiled.CustomItems.API.Features; @@ -155,6 +156,11 @@ public abstract class CustomRole /// public virtual Vector3 Scale { get; set; } = Vector3.one; + /// + /// Gets or sets a value indicating the 's gravity. + /// + public virtual Vector3? Gravity { get; set; } + /// /// Gets or sets a containing cached and their which is cached Role with FF multiplier. /// @@ -553,7 +559,8 @@ public virtual void AddRole(Player player) player.Health = MaxHealth; player.MaxHealth = MaxHealth; player.Scale = Scale; - + if (Gravity.HasValue && player.Role is FpcRole fpcRole) + fpcRole.Gravity = Gravity.Value; Vector3 position = GetSpawnPosition(); if (position != Vector3.zero) { diff --git a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj index d569aacb2c..78b2030580 100644 --- a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj +++ b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj @@ -29,9 +29,9 @@ + - diff --git a/EXILED/Exiled.Events/Commands/Config/Merge.cs b/EXILED/Exiled.Events/Commands/Config/Merge.cs index b9916ede64..c6cf79042d 100644 --- a/EXILED/Exiled.Events/Commands/Config/Merge.cs +++ b/EXILED/Exiled.Events/Commands/Config/Merge.cs @@ -49,8 +49,8 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s SortedDictionary configs = ConfigManager.LoadSorted(ConfigManager.Read()); LoaderPlugin.Config.ConfigType = ConfigType.Default; bool haveBeenSaved = ConfigManager.Save(configs); - PluginAPI.Loader.AssemblyLoader.InstalledPlugins.FirstOrDefault(x => x.PluginName == "Exiled Loader")?.SaveConfig(new LoaderPlugin(), nameof(LoaderPlugin.Config)); + LoaderPlugin.Instance.SaveConfig(); response = $"Configs have been merged successfully! Feel free to remove the directory in the following path:\n\"{Paths.IndividualConfigs}\""; return haveBeenSaved; } diff --git a/EXILED/Exiled.Events/Commands/Config/Split.cs b/EXILED/Exiled.Events/Commands/Config/Split.cs index 9fad9c3e16..34816af579 100644 --- a/EXILED/Exiled.Events/Commands/Config/Split.cs +++ b/EXILED/Exiled.Events/Commands/Config/Split.cs @@ -49,8 +49,8 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s SortedDictionary configs = ConfigManager.LoadSorted(ConfigManager.Read()); LoaderPlugin.Config.ConfigType = ConfigType.Separated; bool haveBeenSaved = ConfigManager.Save(configs); - PluginAPI.Loader.AssemblyLoader.InstalledPlugins.FirstOrDefault(x => x.PluginName == "Exiled Loader")?.SaveConfig(new LoaderPlugin(), nameof(LoaderPlugin.Config)); + LoaderPlugin.Instance.SaveConfig(); response = $"Configs have been merged successfully! Feel free to remove the file in the following path:\n\"{Paths.Config}\""; return haveBeenSaved; } diff --git a/EXILED/Exiled.Events/Commands/Hub/Hub.cs b/EXILED/Exiled.Events/Commands/Hub/Hub.cs deleted file mode 100644 index 5df93df48c..0000000000 --- a/EXILED/Exiled.Events/Commands/Hub/Hub.cs +++ /dev/null @@ -1,51 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Commands.Hub -{ - using System; - - using CommandSystem; - - /// - /// The EXILED hub command. - /// - [CommandHandler(typeof(RemoteAdminCommandHandler))] - [CommandHandler(typeof(GameConsoleCommandHandler))] - public class Hub : ParentCommand - { - /// - /// Initializes a new instance of the class. - /// - public Hub() - { - LoadGeneratedCommands(); - } - - /// - public override string Command { get; } = "hub"; - - /// - public override string[] Aliases { get; } = Array.Empty(); - - /// - public override string Description { get; } = "The EXILED hub command."; - - /// - public override void LoadGeneratedCommands() - { - RegisterCommand(Install.Instance); - } - - /// - protected override bool ExecuteParent(ArraySegment arguments, ICommandSender sender, out string response) - { - response = "Please, specify a valid subcommand! Available ones: install"; - return false; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Commands/Hub/HubApi/ApiProvider.cs b/EXILED/Exiled.Events/Commands/Hub/HubApi/ApiProvider.cs deleted file mode 100644 index 8733468300..0000000000 --- a/EXILED/Exiled.Events/Commands/Hub/HubApi/ApiProvider.cs +++ /dev/null @@ -1,64 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Commands.Hub.HubApi -{ - using System; - using System.IO; - using System.Net.Http; - using System.Reflection; - using System.Threading.Tasks; - - using Exiled.Events.Commands.Hub.HubApi.Models; - - using Utf8Json; - - /// - /// An API bridge to EXILED Hub. - /// - public static class ApiProvider - { - /// - /// The API endpoint to get the plugin installation data. - /// - private const string InstallApiEndpoint = "https://hub.exiled-team.net/api/install?name="; - - /// - /// Gets installation data of the plugin by name. - /// - /// The name of plugin. - /// The . - /// A instance containing installation data. - public static async Task GetInstallationData(string pluginName, HttpClient client) - { - string url = InstallApiEndpoint + pluginName; - using HttpResponseMessage response = await client.GetAsync(url).ConfigureAwait(false); - - if (response.IsSuccessStatusCode) - { - using Stream stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - return JsonSerializer.Deserialize(stream); - } - - return null; - } - - /// - /// Creates a HTTP client for EXILED Hub API. - /// - /// Created HTTP client. - internal static HttpClient CreateClient() - { - HttpClient client = new(); - - client.Timeout = TimeSpan.FromSeconds(460); - client.DefaultRequestHeaders.Add("User-Agent", $"Exiled.Events (https://github.com/ExMod-Team/EXILED, {Assembly.GetExecutingAssembly().GetName().Version.ToString(3)})"); - - return client; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Commands/Hub/HubApi/Models/HubPlugin.cs b/EXILED/Exiled.Events/Commands/Hub/HubApi/Models/HubPlugin.cs deleted file mode 100644 index 7d0a7b8f00..0000000000 --- a/EXILED/Exiled.Events/Commands/Hub/HubApi/Models/HubPlugin.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Commands.Hub.HubApi.Models -{ - using System.Runtime.Serialization; - - using Utf8Json; - - /// - /// A struct containing all hub plugin data. - /// - public readonly struct HubPlugin : IJsonSerializable - { - /// - /// The repository id. - /// - [DataMember(Name = "repositoryId")] - public readonly long RepositoryId; - - /// - /// Initializes a new instance of the struct. - /// - /// - [SerializationConstructor] - public HubPlugin(long repositoryId) - { - RepositoryId = repositoryId; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Commands/Hub/Install.cs b/EXILED/Exiled.Events/Commands/Hub/Install.cs deleted file mode 100644 index 323a230108..0000000000 --- a/EXILED/Exiled.Events/Commands/Hub/Install.cs +++ /dev/null @@ -1,118 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Commands.Hub -{ - using System; - using System.IO; - using System.Linq; - using System.Net.Http; - - using CommandSystem; - - using Exiled.API.Features; - using Exiled.Events.Commands.Hub.HubApi.Models; - using Exiled.Loader; - using Exiled.Loader.GHApi; - using Exiled.Loader.GHApi.Models; - using Exiled.Loader.GHApi.Settings; - using Exiled.Permissions.Extensions; - - using RemoteAdmin; - - /// - /// The command to install a plugin from EXILED Hub. - /// - public class Install : ICommand, IUsageProvider - { - /// - /// Gets static instance of the command. - /// - public static Install Instance { get; } = new(); - - /// - public string Command { get; } = "install"; - - /// - public string[] Aliases { get; } = { "i" }; - - /// - public string[] Usage { get; } = { "Plugin name", "Release tag (optional)" }; - - /// - public string Description { get; } = "Installs a plugin from EXILED Hub."; - - /// - public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) - { - const string permission = "hub.install"; - - if (!sender.CheckPermission(permission) && sender is PlayerCommandSender playerSender && !playerSender.FullPermissions) - { - response = $"You don't have permissions to install the plugins. Required permission node: \"{permission}\"."; - return false; - } - - if (arguments.Count == 0) - { - response = "Missing arguments! Usage: hub install (release tag)"; - return false; - } - - using HttpClient client = HubApi.ApiProvider.CreateClient(); - - HubPlugin? pluginData = HubApi.ApiProvider.GetInstallationData(arguments.At(0), client).GetAwaiter().GetResult(); - - if (pluginData == null) - { - response = "An error has occurred while fetching the plugin data. Please check if the plugin name is correct and try again."; - return false; - } - - Release[] pluginReleases = client.GetReleases(pluginData.Value.RepositoryId, new GetReleasesSettings(50, 1)).GetAwaiter().GetResult(); - Release releaseToDownload = pluginReleases[0]; - - if (arguments.Count > 1) - { - Release foundRelease = pluginReleases.FirstOrDefault(x => x.TagName == arguments.At(1)); - - if (foundRelease.Id == 0) - { - response = "Release with the provided tag not found."; - return false; - } - - releaseToDownload = foundRelease; - } - - ReleaseAsset[] releaseAssets = releaseToDownload.Assets.Where(x => x.Name.IndexOf("nwapi", StringComparison.OrdinalIgnoreCase) == -1).ToArray(); - - Log.Info($"Downloading release \"{releaseToDownload.TagName}\". Found {releaseAssets.Length} asset(s) to download."); - - foreach (ReleaseAsset asset in releaseAssets) - { - Log.Info($"Downloading asset {asset.Name}. Asset size: {Math.Round(asset.Size / 1000f, 2)} KB."); - using HttpResponseMessage assetResponse = client.GetAsync(asset.BrowserDownloadUrl).ConfigureAwait(false).GetAwaiter().GetResult(); - - string pluginPath = Path.Combine(Paths.Plugins, asset.Name); - - if (File.Exists(pluginPath) && Environment.OSVersion.Platform == PlatformID.Unix) - LinuxPermission.SetFileUserAndGroupReadWriteExecutePermissions(pluginPath); - - using Stream stream = assetResponse.Content.ReadAsStreamAsync().ConfigureAwait(false).GetAwaiter().GetResult(); - using FileStream fileStream = new(pluginPath, FileMode.Create, FileAccess.Write, FileShare.None); - stream.CopyToAsync(fileStream).ConfigureAwait(false).GetAwaiter().GetResult(); - - if (Environment.OSVersion.Platform == PlatformID.Unix) - LinuxPermission.SetFileUserAndGroupReadWriteExecutePermissions(pluginPath); - } - - response = $"{arguments.At(0)} has been successfully installed."; - return true; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Config.cs b/EXILED/Exiled.Events/Config.cs index 56a8206e74..fd244f699b 100644 --- a/EXILED/Exiled.Events/Config.cs +++ b/EXILED/Exiled.Events/Config.cs @@ -77,6 +77,7 @@ public sealed class Config : IConfig /// /// 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; diff --git a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs index e39a463c23..a8b986c171 100644 --- a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs @@ -26,12 +26,20 @@ public class SendingCassieMessageEventArgs : IDeniableEvent /// /// /// + /// + /// + /// + /// + /// + /// /// Indicates whether the event can be executed. - public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise, bool isAllowed = true) + public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise, bool customAnnouncement, string customSubtitles, bool isAllowed = true) { Words = words; + CustomSubtitles = customSubtitles; MakeHold = makeHold; MakeNoise = makeNoise; + IsCustomAnnouncement = customAnnouncement; IsAllowed = isAllowed; } @@ -40,6 +48,11 @@ public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise /// public string Words { get; set; } + /// + /// Gets or sets the message subtitles. + /// + public string CustomSubtitles { get; set; } + /// /// Gets or sets a value indicating whether the message should be held. /// @@ -54,5 +67,10 @@ public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise /// Gets or sets a value indicating whether the message can be sent. /// public bool IsAllowed { get; set; } + + /// + /// Gets or sets a value indicating whether the message can be sent. + /// + public bool IsCustomAnnouncement { get; set; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs index a083ac1fa1..4c43eb1df8 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs @@ -30,17 +30,14 @@ public class AnnouncingScpTerminationEventArgs : IAttackerEvent, IDeniableEvent /// /// /// - /// - /// - /// - public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHandlerBase, bool isAllowed = true) + public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHandlerBase) { Player = scp; Role = scp.Role; DamageHandler = new CustomDamageHandler(scp, damageHandlerBase); Attacker = DamageHandler.BaseIs(out CustomAttackerHandler customAttackerHandler) ? customAttackerHandler.Attacker : null; TerminationCause = damageHandlerBase.CassieDeathAnnouncement.Announcement; - IsAllowed = isAllowed; + IsAllowed = true; } /// @@ -71,6 +68,6 @@ public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHan /// /// Gets or sets a value indicating whether the SCP termination will be announced by C.A.S.S.I.E. /// - public bool IsAllowed { get; set; } = true; + public bool IsAllowed { get; set; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs index 66043379d5..205500cf60 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs @@ -41,7 +41,7 @@ public FillingLockerEventArgs(ItemPickupBase pickupBase, LockerChamber lockerCha /// /// Gets a locker which is containing . /// - public API.Features.Lockers.Locker Locker => Chamber.Locker; + public API.Features.Lockers.Locker Locker => Chamber?.Locker; /// /// Gets a chamber which is filling. diff --git a/EXILED/Exiled.Events/EventArgs/Player/ActivatingGeneratorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ActivatingGeneratorEventArgs.cs index 33a6e87ee5..8050e534bf 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ActivatingGeneratorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ActivatingGeneratorEventArgs.cs @@ -27,14 +27,11 @@ public class ActivatingGeneratorEventArgs : IPlayerEvent, IGeneratorEvent, IDeni /// /// /// - /// - /// - /// - public ActivatingGeneratorEventArgs(Player player, Scp079Generator generator, bool isAllowed = true) + public ActivatingGeneratorEventArgs(Player player, Scp079Generator generator) { Player = player; Generator = Generator.Get(generator); - IsAllowed = isAllowed; + IsAllowed = true; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ActivatingWarheadPanelEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ActivatingWarheadPanelEventArgs.cs index f31eded385..65504085ed 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ActivatingWarheadPanelEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ActivatingWarheadPanelEventArgs.cs @@ -25,7 +25,7 @@ public class ActivatingWarheadPanelEventArgs : IPlayerEvent, IDeniableEvent /// /// /// - public ActivatingWarheadPanelEventArgs(Player player, bool isAllowed = true) + public ActivatingWarheadPanelEventArgs(Player player, bool isAllowed) { Player = player; IsAllowed = isAllowed; diff --git a/EXILED/Exiled.Events/EventArgs/Player/CancelledItemUseEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/CancelledItemUseEventArgs.cs index 33719e6217..19435c5250 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/CancelledItemUseEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/CancelledItemUseEventArgs.cs @@ -10,6 +10,7 @@ namespace Exiled.Events.EventArgs.Player using API.Features; using Exiled.API.Features.Items; using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Usables; /// /// Contains all information before a player cancels usage of an item. @@ -19,14 +20,16 @@ public class CancelledItemUseEventArgs : IPlayerEvent, IUsableEvent /// /// Initializes a new instance of the class. /// - /// The player who's stopping the use of an item. - /// + /// + /// + /// + /// /// /// - public CancelledItemUseEventArgs(Player player, Item item) + public CancelledItemUseEventArgs(ReferenceHub hub, UsableItem usableItem) { - Player = player; - Usable = item is Usable usable ? usable : null; + Player = Player.Get(hub); + Usable = Item.Get(usableItem); } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/CancellingItemUseEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/CancellingItemUseEventArgs.cs index 1caaabb0a6..a030f171c2 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/CancellingItemUseEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/CancellingItemUseEventArgs.cs @@ -20,13 +20,15 @@ public class CancellingItemUseEventArgs : IPlayerEvent, IDeniableEvent, IUsableE /// /// Initializes a new instance of the class. /// - /// The player who's stopping the use of an item. + /// + /// + /// /// /// /// - public CancellingItemUseEventArgs(Player player, UsableItem item) + public CancellingItemUseEventArgs(ReferenceHub hub, UsableItem item) { - Player = player; + Player = Player.Get(hub); Usable = Item.Get(item); } diff --git a/EXILED/Exiled.Events/EventArgs/Player/ClosingGeneratorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ClosingGeneratorEventArgs.cs index 9218db494b..c33b0bcc0f 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ClosingGeneratorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ClosingGeneratorEventArgs.cs @@ -21,12 +21,11 @@ public class ClosingGeneratorEventArgs : IPlayerEvent, IDeniableEvent, IGenerato /// /// The player who's closing the generator. /// The instance. - /// Indicates whether the generator can be closed. - public ClosingGeneratorEventArgs(Player player, Scp079Generator generator, bool isAllowed = true) + public ClosingGeneratorEventArgs(Player player, Scp079Generator generator) { Player = player; Generator = Generator.Get(generator); - IsAllowed = isAllowed; + IsAllowed = true; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/DeactivatingWorkstationEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/DeactivatingWorkstationEventArgs.cs index 48b7164d83..20ce6f84d0 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/DeactivatingWorkstationEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/DeactivatingWorkstationEventArgs.cs @@ -31,7 +31,7 @@ public class DeactivatingWorkstationEventArgs : IPlayerEvent, IDeniableEvent /// public DeactivatingWorkstationEventArgs(WorkstationController controller, bool isAllowed = true) { - Player = Player.Get(controller._knownUser); + Player = Player.Get(controller.KnownUser); WorkstationController = controller; IsAllowed = isAllowed; } diff --git a/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs index a10eea6922..4a4fa0dcba 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs @@ -25,7 +25,7 @@ public class EscapingEventArgs : IPlayerEvent, IDeniableEvent /// /// Initializes a new instance of the class. /// - /// + /// /// /// /// @@ -34,12 +34,12 @@ public class EscapingEventArgs : IPlayerEvent, IDeniableEvent /// /// /// - public EscapingEventArgs(Player player, RoleTypeId newRole, EscapeScenario escapeScenario) + public EscapingEventArgs(ReferenceHub referenceHub, RoleTypeId newRole, EscapeScenario escapeScenario) { - Player = player; + Player = Player.Get(referenceHub); NewRole = newRole; EscapeScenario = escapeScenario; - IsAllowed = escapeScenario is not EscapeScenario.CustomEscape; + IsAllowed = escapeScenario is not EscapeScenario.None and not EscapeScenario.CustomEscape; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/EscapingPocketDimensionEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/EscapingPocketDimensionEventArgs.cs index 375eed5302..841edfdcf6 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/EscapingPocketDimensionEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/EscapingPocketDimensionEventArgs.cs @@ -21,18 +21,27 @@ public class EscapingPocketDimensionEventArgs : IPlayerEvent, IDeniableEvent /// /// Initializes a new instance of the class. /// - /// + /// + /// + /// + /// /// /// /// /// /// - public EscapingPocketDimensionEventArgs(Player player, Vector3 position) + public EscapingPocketDimensionEventArgs(PocketDimensionTeleport pocketDimensionTeleport, ReferenceHub hub, Vector3 position) { - Player = player; + Teleporter = pocketDimensionTeleport; + Player = Player.Get(hub); TeleportPosition = position; } + /// + /// Gets the PocketDimensionTeleport the player walked into. + /// + public PocketDimensionTeleport Teleporter { get; } + /// /// Gets the player who's escaping the pocket dimension. /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/FailingEscapePocketDimensionEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/FailingEscapePocketDimensionEventArgs.cs index 247e62cbe7..620178368c 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/FailingEscapePocketDimensionEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/FailingEscapePocketDimensionEventArgs.cs @@ -7,6 +7,8 @@ namespace Exiled.Events.EventArgs.Player { + using System; + using API.Features; using Interfaces; @@ -19,19 +21,19 @@ public class FailingEscapePocketDimensionEventArgs : IPlayerEvent, IDeniableEven /// /// Initializes a new instance of the class. /// - /// - /// - /// - /// + /// /// /// + /// + /// + /// /// /// /// - public FailingEscapePocketDimensionEventArgs(Player player, PocketDimensionTeleport teleporter, bool isAllowed = true) + public FailingEscapePocketDimensionEventArgs(PocketDimensionTeleport pocketDimensionTeleport, ReferenceHub hub, bool isAllowed = true) { - Player = player; - Teleporter = teleporter; + Player = Player.Get(hub); + Teleporter = pocketDimensionTeleport; IsAllowed = isAllowed; } diff --git a/EXILED/Exiled.Events/EventArgs/Player/FlippingCoinEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/FlippingCoinEventArgs.cs index 369a443868..954d2f39e8 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/FlippingCoinEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/FlippingCoinEventArgs.cs @@ -20,7 +20,7 @@ public class FlippingCoinEventArgs : IPlayerEvent, IDeniableEvent, IItemEvent /// /// Initializes a new instance of the class. /// - /// + /// /// /// /// @@ -29,9 +29,9 @@ public class FlippingCoinEventArgs : IPlayerEvent, IDeniableEvent, IItemEvent /// /// /// - public FlippingCoinEventArgs(Player player, Coin coin, bool isTails) + public FlippingCoinEventArgs(ReferenceHub referenceHub, Coin coin, bool isTails) { - Player = player; + Player = Player.Get(referenceHub); Item = Item.Get(coin); IsTails = isTails; } diff --git a/EXILED/Exiled.Events/EventArgs/Player/HurtEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/HurtEventArgs.cs index 1b97b4a946..8fd0eab99b 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/HurtEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/HurtEventArgs.cs @@ -23,7 +23,7 @@ public class HurtEventArgs : IAttackerEvent /// /// Initializes a new instance of the class. /// - /// + /// /// /// /// @@ -32,11 +32,11 @@ public class HurtEventArgs : IAttackerEvent /// /// /// - public HurtEventArgs(Player target, DamageHandlerBase damageHandler, DamageHandlerBase.HandlerOutput handlerOutput) + public HurtEventArgs(ReferenceHub referenceHub, DamageHandlerBase damageHandler, DamageHandlerBase.HandlerOutput handlerOutput) { - DamageHandler = new CustomDamageHandler(target, damageHandler); + Player = Player.Get(referenceHub); + DamageHandler = new CustomDamageHandler(Player, damageHandler); Attacker = DamageHandler.BaseIs(out CustomAttackerHandler attackerDamageHandler) ? attackerDamageHandler.Attacker : null; - Player = target; HandlerOutput = handlerOutput; } diff --git a/EXILED/Exiled.Events/EventArgs/Player/InteractingDoorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/InteractingDoorEventArgs.cs index 75eb562f39..c93656d6fc 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/InteractingDoorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/InteractingDoorEventArgs.cs @@ -33,17 +33,14 @@ public class InteractingDoorEventArgs : IPlayerEvent, IDoorEvent, IDeniableEvent /// /// /// - /// - /// - /// - public InteractingDoorEventArgs(Player player, DoorVariant door, byte colliderId, bool isAllowed = true, bool canInteract = true) + public InteractingDoorEventArgs(Player player, DoorVariant door, byte colliderId, bool isAllowed) { Player = player; Door = Door.Get(door); ColliderId = colliderId; Collider = InteractableCollider.TryGetCollider(door, colliderId, out InteractableCollider interactableCollider) ? interactableCollider : null; IsAllowed = isAllowed; - CanInteract = canInteract; + CanInteract = true; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/OpeningGeneratorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/OpeningGeneratorEventArgs.cs index f69507e355..13dc43febf 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/OpeningGeneratorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/OpeningGeneratorEventArgs.cs @@ -27,14 +27,11 @@ public class OpeningGeneratorEventArgs : IPlayerEvent, IDeniableEvent, IGenerato /// /// /// - /// - /// - /// - public OpeningGeneratorEventArgs(Player player, Scp079Generator generator, bool isAllowed = true) + public OpeningGeneratorEventArgs(Player player, Scp079Generator generator) { Player = player; Generator = Generator.Get(generator); - IsAllowed = isAllowed; + IsAllowed = true; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/PickingUpItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/PickingUpItemEventArgs.cs index 90493c03c5..f71781e3b7 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/PickingUpItemEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/PickingUpItemEventArgs.cs @@ -21,7 +21,7 @@ public class PickingUpItemEventArgs : IPlayerEvent, IPickupEvent, IDeniableEvent /// /// Initializes a new instance of the class. /// - /// + /// /// /// /// @@ -30,10 +30,10 @@ public class PickingUpItemEventArgs : IPlayerEvent, IPickupEvent, IDeniableEvent /// /// /// - public PickingUpItemEventArgs(Player player, ItemPickupBase pickup, bool isAllowed = true) + public PickingUpItemEventArgs(ReferenceHub referenceHub, ItemPickupBase pickup, bool isAllowed = true) { IsAllowed = isAllowed; - Player = player; + Player = Player.Get(referenceHub); Pickup = Pickup.Get(pickup); } diff --git a/EXILED/Exiled.Events/EventArgs/Player/PreAuthenticatingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/PreAuthenticatingEventArgs.cs index f2af6a8300..3c127ca02e 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/PreAuthenticatingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/PreAuthenticatingEventArgs.cs @@ -13,7 +13,6 @@ namespace Exiled.Events.EventArgs.Player using LiteNetLib; using LiteNetLib.Utils; - using PluginAPI.Events; #pragma warning disable SA1600 //TODO: #pragma warning disable SA1309 diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReservedSlotsCheckEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReservedSlotsCheckEventArgs.cs index 47861a038c..d571f1e451 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ReservedSlotsCheckEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ReservedSlotsCheckEventArgs.cs @@ -13,21 +13,24 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information when checking if a player has a reserved slot. /// - public class ReservedSlotsCheckEventArgs : IExiledEvent + public class ReservedSlotsCheckEventArgs : IExiledEvent, IDeniableEvent { + private ReservedSlotEventResult reservedSlotEventResult = ReservedSlotEventResult.UseBaseGameSystem; + /// /// Initializes a new instance of the class. /// - /// - /// - /// /// /// /// - public ReservedSlotsCheckEventArgs(string userId, bool hasReservedSlot) + /// + /// + /// + public ReservedSlotsCheckEventArgs(bool hasReservedSlot, string userId) { UserId = userId; HasReservedSlot = hasReservedSlot; + IsAllowed = hasReservedSlot; } /// @@ -40,9 +43,36 @@ public ReservedSlotsCheckEventArgs(string userId, bool hasReservedSlot) /// public bool HasReservedSlot { get; } + /// + /// Gets or sets a value indicating whether the player is allowed to connect. + /// + public bool IsAllowed { get; set; } + /// /// Gets or sets the event result. /// - public ReservedSlotEventResult Result { get; set; } = ReservedSlotEventResult.UseBaseGameSystem; + public ReservedSlotEventResult Result + { + get => reservedSlotEventResult; + set + { + switch (reservedSlotEventResult) + { + case ReservedSlotEventResult.CanUseReservedSlots or ReservedSlotEventResult.UseBaseGameSystem: + IsAllowed = HasReservedSlot; + break; + case ReservedSlotEventResult.AllowConnectionUnconditionally: + IsAllowed = true; + break; + case ReservedSlotEventResult.CannotUseReservedSlots: + IsAllowed = false; + break; + default: + return; + } + + reservedSlotEventResult = value; + } + } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/SearchingPickupEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/SearchingPickupEventArgs.cs index c714df950a..fe17eb979a 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/SearchingPickupEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/SearchingPickupEventArgs.cs @@ -37,7 +37,7 @@ public class SearchingPickupEventArgs : IPlayerEvent, IPickupEvent, IDeniableEve /// /// /// - public SearchingPickupEventArgs(Player player, ItemPickupBase pickup, SearchSession searchSession, SearchCompletor searchCompletor, float searchTime) + public SearchingPickupEventArgs(Player player, ItemPickupBase pickup, SearchSession searchSession, PickupSearchCompletor searchCompletor, float searchTime) { Player = player; Pickup = Pickup.Get(pickup); @@ -54,7 +54,7 @@ public SearchingPickupEventArgs(Player player, ItemPickupBase pickup, SearchSess /// /// Gets or sets the SearchCompletor. /// - public SearchCompletor SearchCompletor { get; set; } + public PickupSearchCompletor SearchCompletor { get; set; } /// /// Gets or sets the Pickup search duration. diff --git a/EXILED/Exiled.Events/EventArgs/Player/SendingValidCommandEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/SendingValidCommandEventArgs.cs index a3fa2d5310..1ea8a6df71 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/SendingValidCommandEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/SendingValidCommandEventArgs.cs @@ -11,7 +11,7 @@ namespace Exiled.Events.EventArgs.Player using Exiled.API.Features; using Exiled.API.Features.Pickups; using Exiled.Events.EventArgs.Interfaces; - using PluginAPI.Enums; + using LabApi.Features.Enums; using RemoteAdmin; /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/SentValidCommandEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/SentValidCommandEventArgs.cs index 0fb7778a16..1c96ff88f9 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/SentValidCommandEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/SentValidCommandEventArgs.cs @@ -11,7 +11,7 @@ namespace Exiled.Events.EventArgs.Player using Exiled.API.Features; using Exiled.API.Features.Pickups; using Exiled.Events.EventArgs.Interfaces; - using PluginAPI.Enums; + using LabApi.Features.Enums; using RemoteAdmin; /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ShotEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ShotEventArgs.cs index 0eb6a5c69d..18d2303353 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ShotEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ShotEventArgs.cs @@ -25,15 +25,16 @@ public class ShotEventArgs : IPlayerEvent, IFirearmEvent /// Raycast hit info. /// The firearm used. /// The IDestructible that was hit. Can be null. - public ShotEventArgs(HitscanHitregModuleBase hitregModule, RaycastHit hitInfo, InventorySystem.Items.Firearms.Firearm firearm, IDestructible destructible) + /// + public ShotEventArgs(HitscanHitregModuleBase hitregModule, RaycastHit hitInfo, InventorySystem.Items.Firearms.Firearm firearm, IDestructible destructible, float damage) { HitregModule = hitregModule; RaycastHit = hitInfo; Destructible = destructible; Firearm = Item.Get(firearm); + Damage = damage; Player = Firearm.Owner; - Damage = Destructible is not null ? HitregModule.DamageAtDistance(hitInfo.distance) : 0f; if (Destructible is HitboxIdentity hitboxIdentity) { diff --git a/EXILED/Exiled.Events/EventArgs/Player/SpawningRagdollEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/SpawningRagdollEventArgs.cs index e12dc914a1..9ec7423835 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/SpawningRagdollEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/SpawningRagdollEventArgs.cs @@ -8,7 +8,6 @@ namespace Exiled.Events.EventArgs.Player { using API.Features; - using Interfaces; using PlayerRoles; @@ -16,6 +15,7 @@ namespace Exiled.Events.EventArgs.Player using PlayerStatsSystem; using UnityEngine; + using YamlDotNet.Core.Tokens; /// /// Contains all information before spawning a player ragdoll. @@ -45,7 +45,7 @@ public SpawningRagdollEventArgs(RagdollData info, bool isAllowed = true) public Vector3 Position { get => Info.StartPosition; - set => Info = new RagdollData(Player.ReferenceHub, DamageHandlerBase, value, Rotation); + set => Info = new RagdollData(Player.ReferenceHub, DamageHandlerBase, Role, value, Rotation, Scale, Nickname, CreationTime); } /// @@ -54,13 +54,22 @@ public Vector3 Position public Quaternion Rotation { get => Info.StartRotation; - set => Info = new RagdollData(Player.ReferenceHub, DamageHandlerBase, Position, value); + set => Info = new RagdollData(Player.ReferenceHub, DamageHandlerBase, Role, Position, value, Scale, Nickname, CreationTime); + } + + /// + /// Gets or sets the ragdoll's scale with RagdollData. + /// + public Vector3 Scale + { + get => Info.Scale; + set => Info = new RagdollData(Player.ReferenceHub, DamageHandlerBase, Role, Position, Rotation, Vector3.Scale(value, RagdollManager.GetDefaultScale(Role)), Nickname, CreationTime); } /// - /// Gets or sets the ragdoll's scale. + /// Gets or sets the ragdoll's scale with GameObject. /// - public Vector3 Scale { get; set; } + public Vector3 RagdollScale { get; set; } = Vector3.one; /// /// Gets or sets the ragdoll's . @@ -68,7 +77,7 @@ public Quaternion Rotation public RoleTypeId Role { get => Info.RoleType; - set => Info = new RagdollData(Player.ReferenceHub, DamageHandlerBase, value, Position, Rotation, Nickname, CreationTime); + set => Info = new RagdollData(Player.ReferenceHub, DamageHandlerBase, value, Position, Rotation, Scale, Nickname, CreationTime); } /// @@ -82,7 +91,7 @@ public RoleTypeId Role public string Nickname { get => Info.Nickname; - set => Info = new RagdollData(Player.ReferenceHub, DamageHandlerBase, Role, Position, Rotation, value, CreationTime); + set => Info = new RagdollData(Player.ReferenceHub, DamageHandlerBase, Role, Position, Rotation, Scale, value, CreationTime); } /// @@ -96,7 +105,7 @@ public string Nickname public DamageHandlerBase DamageHandlerBase { get => Info.Handler; - set => Info = new RagdollData(Player.ReferenceHub, value, Role, Position, Rotation, Nickname, CreationTime); + set => Info = new RagdollData(Player.ReferenceHub, value, Role, Position, Rotation, Scale, Nickname, CreationTime); } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/StoppingGeneratorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/StoppingGeneratorEventArgs.cs index 53f0d9ecf5..6462c655d8 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/StoppingGeneratorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/StoppingGeneratorEventArgs.cs @@ -21,12 +21,11 @@ public class StoppingGeneratorEventArgs : IPlayerEvent, IGeneratorEvent, IDeniab /// /// The player who's flipping the switch. /// The instance. - /// Indicates whether the switch of the generator can be flipped. - public StoppingGeneratorEventArgs(Player player, Scp079Generator generator, bool isAllowed = true) + public StoppingGeneratorEventArgs(Player player, Scp079Generator generator) { Player = player; Generator = Generator.Get(generator); - IsAllowed = isAllowed; + IsAllowed = true; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/TogglingNoClipEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/TogglingNoClipEventArgs.cs index 78144567ec..65ea273731 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/TogglingNoClipEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/TogglingNoClipEventArgs.cs @@ -19,7 +19,7 @@ public class TogglingNoClipEventArgs : IPlayerEvent, IDeniableEvent /// /// Initializes a new instance of the class. /// - /// + /// /// /// /// @@ -28,9 +28,9 @@ public class TogglingNoClipEventArgs : IPlayerEvent, IDeniableEvent /// /// /// - public TogglingNoClipEventArgs(Player player, bool newValue, bool isAllowed = true) + public TogglingNoClipEventArgs(ReferenceHub referenceHub, bool newValue, bool isAllowed = true) { - Player = player; + Player = Player.Get(referenceHub); IsEnabled = newValue; IsAllowed = isAllowed; } @@ -41,9 +41,9 @@ public TogglingNoClipEventArgs(Player player, bool newValue, bool isAllowed = tr public Player Player { get; } /// - /// Gets or sets a value indicating whether the noclip mode will be enabled. + /// Gets a value indicating whether the noclip mode will be enabled. /// - public bool IsEnabled { get; set; } + public bool IsEnabled { get; } /// /// Gets or sets a value indicating whether the player can toggle noclip. diff --git a/EXILED/Exiled.Events/EventArgs/Player/UnlockingGeneratorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UnlockingGeneratorEventArgs.cs index 422def506f..77541732d0 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/UnlockingGeneratorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/UnlockingGeneratorEventArgs.cs @@ -30,7 +30,7 @@ public class UnlockingGeneratorEventArgs : IPlayerEvent, IGeneratorEvent, IDenia /// /// /// - public UnlockingGeneratorEventArgs(Player player, Scp079Generator generator, bool isAllowed = true) + public UnlockingGeneratorEventArgs(Player player, Scp079Generator generator, bool isAllowed) { Player = player; Generator = Generator.Get(generator); diff --git a/EXILED/Exiled.Events/EventArgs/Player/UsingItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UsingItemEventArgs.cs index 6165eb35c3..317d6ddbeb 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/UsingItemEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/UsingItemEventArgs.cs @@ -21,16 +21,18 @@ public class UsingItemEventArgs : IPlayerEvent, IDeniableEvent, IUsableEvent /// /// Initializes a new instance of the class. /// - /// The player who's going to use the item. + /// + /// + /// /// /// /// /// /// /// - public UsingItemEventArgs(Player player, UsableItem item, float cooldown) + public UsingItemEventArgs(ReferenceHub hub, UsableItem item, float cooldown) { - Player = player; + Player = Player.Get(hub); Usable = Item.Get(item) is Usable usable ? usable : null; Cooldown = cooldown; } diff --git a/EXILED/Exiled.Events/EventArgs/Player/UsingRadioBatteryEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UsingRadioBatteryEventArgs.cs index ae1995da47..3b3af1c73f 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/UsingRadioBatteryEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/UsingRadioBatteryEventArgs.cs @@ -25,19 +25,16 @@ public class UsingRadioBatteryEventArgs : IPlayerEvent, IDeniableEvent, IItemEve /// /// /// - /// - /// - /// /// /// /// /// /// /// - public UsingRadioBatteryEventArgs(RadioItem radio, Player player, float drain, bool isAllowed = true) + public UsingRadioBatteryEventArgs(RadioItem radio, float drain, bool isAllowed = true) { Radio = Item.Get(radio); - Player = player; + Player = Radio.Owner; Drain = drain; IsAllowed = isAllowed; } diff --git a/EXILED/Exiled.Events/EventArgs/Scp049/ActivatingSenseEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp049/ActivatingSenseEventArgs.cs index c8ae4fdae2..a6144bbb8c 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp049/ActivatingSenseEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp049/ActivatingSenseEventArgs.cs @@ -29,8 +29,8 @@ public ActivatingSenseEventArgs(Player player, Player target, bool isAllowed = t Scp049 = player.Role.As(); Target = target; IsAllowed = isAllowed; - FailedCooldown = (float)Scp049.SenseAbilityFailCooldown; - Duration = (float)Scp049.SenseAbilityDuration; + FailedCooldown = PlayerRoles.PlayableScps.Scp049.Scp049SenseAbility.AttemptFailCooldown; + Duration = PlayerRoles.PlayableScps.Scp049.Scp049SenseAbility.EffectDuration; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp049/SendingCallEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp049/SendingCallEventArgs.cs index 2d302846cf..e859023690 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp049/SendingCallEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp049/SendingCallEventArgs.cs @@ -25,7 +25,7 @@ public SendingCallEventArgs(Player player, bool isAllowed = true) { Player = player; Scp049 = Player.Role.As(); - Duration = (float)Scp049.CallAbilityBaseCooldown; + Duration = PlayerRoles.PlayableScps.Scp049.Scp049CallAbility.BaseCooldown; IsAllowed = isAllowed; } diff --git a/EXILED/Exiled.Events/EventArgs/Scp0492/ConsumingCorpseEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp0492/ConsumingCorpseEventArgs.cs index 008ef83591..06de15a086 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp0492/ConsumingCorpseEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp0492/ConsumingCorpseEventArgs.cs @@ -25,10 +25,8 @@ public class ConsumingCorpseEventArgs : IScp0492Event, IRagdollEvent, IDeniableE /// /// /// - /// /// See for all ragdolls consumed. - // TODO: remove isAllowed argument - public ConsumingCorpseEventArgs(ReferenceHub player, BasicRagdoll ragDoll, ZombieConsumeAbility.ConsumeError error, bool isAllowed = true) + public ConsumingCorpseEventArgs(ReferenceHub player, BasicRagdoll ragDoll, ZombieConsumeAbility.ConsumeError error) { Player = Player.Get(player); Scp0492 = Player.Role.As(); diff --git a/EXILED/Exiled.Events/EventArgs/Scp173/PlacingTantrumEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp173/PlacingTantrumEventArgs.cs index 459befc3b5..70ed06bdf4 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp173/PlacingTantrumEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp173/PlacingTantrumEventArgs.cs @@ -7,6 +7,8 @@ namespace Exiled.Events.EventArgs.Scp173 { + using System; + using Exiled.API.Features; using Exiled.Events.EventArgs.Interfaces; @@ -39,7 +41,9 @@ public PlacingTantrumEventArgs(Player player, TantrumEnvironmentalHazard tantrum { Player = player; Scp173 = Player.Role.As(); +#pragma warning disable CS0618 TantrumHazard = tantrumHazard; +#pragma warning restore CS0618 Cooldown = cooldown; IsAllowed = isAllowed; } @@ -52,6 +56,7 @@ public PlacingTantrumEventArgs(Player player, TantrumEnvironmentalHazard tantrum /// /// Gets the . /// + [Obsolete("This propperty is always null")] public TantrumEnvironmentalHazard TantrumHazard { get; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs index dc39d420c5..d706ea289d 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs @@ -21,31 +21,29 @@ public class InteractingScp330EventArgs : IPlayerEvent, IScp330Event, IDeniableE /// /// Initializes a new instance of the class. /// - /// + /// /// /// /// /// /// - public InteractingScp330EventArgs(Player player, int usage) + /// + /// + /// + /// + /// + /// + /// + /// + /// + public InteractingScp330EventArgs(ReferenceHub referenceHub, int usage, bool shouldPlaySound, bool shouldSever, CandyKindID candy) { - Player = player; + Player = Player.Get(referenceHub); UsageCount = usage; ShouldSever = usage >= 2; - ShouldPlaySound = true; + ShouldPlaySound = shouldPlaySound; IsAllowed = Player.IsHuman; Candy = Scp330Candies.GetRandom(); - - if (Scp330Bag.TryGetBag(player.ReferenceHub, out Scp330Bag scp330Bag)) - { - Scp330 = (Scp330)Item.Get(scp330Bag); - } - else - { - Scp330 = (Scp330)Item.Create(ItemType.SCP330, player); - Scp330.RemoveAllCandy(); - player.AddItem(Scp330); - } } /// diff --git a/EXILED/Exiled.Events/EventArgs/Server/EndingRoundEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/EndingRoundEventArgs.cs index 216676772b..2e5c11dc05 100644 --- a/EXILED/Exiled.Events/EventArgs/Server/EndingRoundEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Server/EndingRoundEventArgs.cs @@ -7,6 +7,8 @@ namespace Exiled.Events.EventArgs.Server { + using System; + using API.Enums; using Interfaces; @@ -24,17 +26,13 @@ public class EndingRoundEventArgs : IDeniableEvent /// /// /// - /// - /// - /// /// /// /// - public EndingRoundEventArgs(LeadingTeam leadingTeam, RoundSummary.SumInfo_ClassList classList, bool isForceEnded, bool isAllowed) + public EndingRoundEventArgs(LeadingTeam leadingTeam, RoundSummary.SumInfo_ClassList classList, bool isAllowed) { LeadingTeam = leadingTeam; ClassList = classList; - IsForceEnded = isForceEnded; IsAllowed = isAllowed; } @@ -51,7 +49,12 @@ public EndingRoundEventArgs(LeadingTeam leadingTeam, RoundSummary.SumInfo_ClassL /// /// Gets or sets a value indicating whether the round is ended by API call. /// - public bool IsForceEnded { get; set; } + [Obsolete("This event is now call only when it's haven't been force eneded")] + public bool IsForceEnded + { + get => false; // This event is now call only when ForceEnd method haven't been called + set => IsAllowed = value; + } /// /// Gets or sets a value indicating whether the round is going to finish or not. diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index ac37f5528a..103ba58829 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -20,7 +20,7 @@ namespace Exiled.Events using InventorySystem.Items.Usables; using PlayerRoles.Ragdolls; using PlayerRoles.RoleAssign; - using PluginAPI.Events; + using Respawning; using UnityEngine.SceneManagement; using UserSettings.ServerSpecific; @@ -81,11 +81,13 @@ public override void OnEnabled() RagdollManager.OnRagdollRemoved += Handlers.Internal.RagdollList.OnRemovedRagdoll; ItemPickupBase.OnPickupAdded += Handlers.Internal.PickupEvent.OnSpawnedPickup; ItemPickupBase.OnPickupDestroyed += Handlers.Internal.PickupEvent.OnRemovedPickup; - ServerConsole.ReloadServerName(); + + AdminToys.AdminToyBase.OnAdded += Handlers.Internal.AdminToyList.OnAddedAdminToys; + AdminToys.AdminToyBase.OnRemoved += Handlers.Internal.AdminToyList.OnRemovedAdminToys; ServerSpecificSettingsSync.ServerOnSettingValueReceived += SettingBase.OnSettingUpdated; - EventManager.RegisterEvents(this); + ServerConsole.ReloadServerName(); } /// @@ -118,8 +120,6 @@ public override void OnDisabled() ItemPickupBase.OnPickupDestroyed -= Handlers.Internal.PickupEvent.OnRemovedPickup; ServerSpecificSettingsSync.ServerOnSettingValueReceived -= SettingBase.OnSettingUpdated; - - EventManager.UnregisterEvents(this); } /// diff --git a/EXILED/Exiled.Events/Exiled.Events.csproj b/EXILED/Exiled.Events/Exiled.Events.csproj index aa7f9ff4bf..620625057d 100644 --- a/EXILED/Exiled.Events/Exiled.Events.csproj +++ b/EXILED/Exiled.Events/Exiled.Events.csproj @@ -26,10 +26,10 @@ + - diff --git a/EXILED/Exiled.Events/Handlers/Internal/AdminToyList.cs b/EXILED/Exiled.Events/Handlers/Internal/AdminToyList.cs new file mode 100644 index 0000000000..2d4ebf971e --- /dev/null +++ b/EXILED/Exiled.Events/Handlers/Internal/AdminToyList.cs @@ -0,0 +1,27 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Handlers.Internal +{ + /// + /// Handles adding and removing from . + /// + internal static class AdminToyList + { + /// + /// Called after a ragdoll is spawned. Hooked to . + /// + /// The spawned ragdoll. + public static void OnAddedAdminToys(AdminToys.AdminToyBase adminToy) => API.Features.Toys.AdminToy.Get(adminToy); + + /// + /// Called before a ragdoll is destroyed. Hooked to . + /// + /// The destroyed ragdoll. + public static void OnRemovedAdminToys(AdminToys.AdminToyBase adminToy) => API.Features.Toys.AdminToy.BaseToAdminToy.Remove(adminToy); + } +} diff --git a/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs b/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs index a260cf4957..8115dc4e65 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs @@ -33,21 +33,38 @@ public static void OnClientStarted() foreach (KeyValuePair prefab in NetworkClient.prefabs) { - if(!prefabs.ContainsKey(prefab.Key)) + if (!prefabs.ContainsKey(prefab.Key)) prefabs.Add(prefab.Key, prefab.Value); } foreach (NetworkIdentity ragdollPrefab in RagdollManager.AllRagdollPrefabs) { - if(!prefabs.ContainsKey(ragdollPrefab.assetId)) + if (!prefabs.ContainsKey(ragdollPrefab.assetId)) prefabs.Add(ragdollPrefab.assetId, ragdollPrefab.gameObject); } - foreach (PrefabType prefabType in EnumUtils.Values) + for (int i = 0; i < EnumUtils.Values.Length; i++) { + PrefabType prefabType = EnumUtils.Values[i]; PrefabAttribute attribute = prefabType.GetPrefabAttribute(); - PrefabHelper.Prefabs.Add(prefabType, prefabs.FirstOrDefault(prefab => prefab.Key == attribute.AssetId || prefab.Value.name.Contains(attribute.Name)).Value); + if (prefabs.TryGetValue(attribute.AssetId, out GameObject gameObject)) + { + PrefabHelper.Prefabs.Add(prefabType, gameObject); + prefabs.Remove(attribute.AssetId); + continue; + } + + KeyValuePair? value = prefabs.FirstOrDefault(x => x.Value.name == attribute.Name); + if (value.HasValue) + { + PrefabHelper.Prefabs.Add(prefabType, gameObject); + prefabs.Remove(value.Value.Key); + continue; + } } + + foreach (KeyValuePair missing in prefabs) + Log.Warn($"Missing prefab in {nameof(PrefabType)}: {missing.Value.name} ({missing.Key})"); } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Internal/SceneUnloaded.cs b/EXILED/Exiled.Events/Handlers/Internal/SceneUnloaded.cs index 63bb70267e..55b9d0738b 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/SceneUnloaded.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/SceneUnloaded.cs @@ -35,7 +35,6 @@ public static void OnSceneUnloaded(Scene _) { Player.UserIdsCache.Clear(); Player.Dictionary.Clear(); - AdminToy.BaseToAdminToy.Clear(); } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index e272c42f3c..e35df7b044 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -17,10 +17,6 @@ namespace Exiled.Events.Handlers using Exiled.Events.Features; - using PluginAPI.Core.Attributes; - using PluginAPI.Enums; - using PluginAPI.Events; - /// /// Player related events. /// diff --git a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs index 1bdacfd8f2..0cb378ac02 100644 --- a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs +++ b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs @@ -22,7 +22,7 @@ namespace Exiled.Events.Patches.Events.Cassie using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Cassie), nameof(Cassie.SendingCassieMessage))] @@ -35,35 +35,62 @@ private static IEnumerable Transpiler(IEnumerable and adds implementation. /// Adds the event. /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.KeycardInteracting))] [HarmonyPatch(typeof(BaseKeycardPickup), nameof(BaseKeycardPickup.ProcessCollision))] internal static class KeycardInteracting { @@ -43,113 +40,65 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); LocalBuilder isUnlocked = generator.DeclareLocal(typeof(bool)); - LocalBuilder notEmptyPermissions = generator.DeclareLocal(typeof(bool)); - LocalBuilder havePermissions = generator.DeclareLocal(typeof(bool)); + LocalBuilder hasPermission = generator.DeclareLocal(typeof(bool)); - Label skip = generator.DefineLabel(); Label ret = generator.DefineLabel(); int offset = 1; int index = newInstructions.FindIndex(i => i.LoadsField(Field(typeof(DoorVariant), nameof(DoorVariant.ActiveLocks)))) + offset; + Label continueLabel = (Label)newInstructions[index].operand; + newInstructions.RemoveAt(index); newInstructions.InsertRange( index, - new[] + new CodeInstruction[] { // check and write door lock state (isUnlocked) new(OpCodes.Ldc_I4_0), new(OpCodes.Ceq), - new CodeInstruction(OpCodes.Stloc_S, isUnlocked.LocalIndex), + new(OpCodes.Stloc_S, isUnlocked.LocalIndex), + new(OpCodes.Br, continueLabel), }); - index = newInstructions.FindIndex(i => i.LoadsField(Field(typeof(DoorPermissions), nameof(DoorPermissions.RequiredPermissions)))) + offset; + offset = 1; + index = newInstructions.FindIndex(i => i.Calls(Method( + typeof(DoorPermissionsPolicyExtensions), + nameof(DoorPermissionsPolicyExtensions.CheckPermissions), + new[] { typeof(IDoorPermissionRequester), typeof(IDoorPermissionProvider), typeof(PermissionUsed).MakeByRefType() }))) + offset; newInstructions.InsertRange( index, - new[] - { - // checking empty permissions - new(OpCodes.Ldc_I4_0), - new(OpCodes.Cgt), - - new(OpCodes.Stloc_S, notEmptyPermissions.LocalIndex), - new(OpCodes.Br_S, skip), - - // save original return - new CodeInstruction(OpCodes.Ret).MoveLabelsFrom(newInstructions[index + 1]), - new CodeInstruction(OpCodes.Nop).WithLabels(skip), - }); - - // 6 new instructions - offset = 6; - index += offset; + new CodeInstruction[] + { + // hasPermission + new(OpCodes.Stloc_S, hasPermission.LocalIndex), - newInstructions.RemoveRange(index, 14); + // pickup + new(OpCodes.Ldarg_0), - newInstructions.InsertRange( - index, - new[] - { - // override permissions check, to implement KeycardPickup::Permissions - new(OpCodes.Ldarg_0), - new(OpCodes.Ldloc_1), - new CodeInstruction(OpCodes.Call, Method(typeof(KeycardInteracting), nameof(KeycardInteracting.CheckPermissions))), - new CodeInstruction(OpCodes.Stloc_S, havePermissions.LocalIndex), - }); + // PreviousOwner.Hub + new(OpCodes.Ldarg_0), + new(OpCodes.Ldflda, Field(typeof(BaseKeycardPickup), nameof(BaseKeycardPickup.PreviousOwner))), + new(OpCodes.Ldfld, Field(typeof(Footprint), nameof(Footprint.Hub))), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), - // 4 new instructions - offset = 4; - index += offset; + // door + new(OpCodes.Ldloc_1), - newInstructions.RemoveRange(index, 2); + // isAllowed = isUnlocked && hasPermission + new(OpCodes.Ldloc_S, isUnlocked.LocalIndex), + new(OpCodes.Ldloc_S, hasPermission.LocalIndex), + new(OpCodes.And), - offset = -5; - index = newInstructions.FindIndex(i => i.Calls(PropertySetter(typeof(DoorVariant), nameof(DoorVariant.NetworkTargetState)))) + offset; + // ev = new KeycardInteractingEventArgs(pickup, player, door, isAllowed) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(KeycardInteractingEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnKeycardInteracting))), - newInstructions.InsertRange( - index, - new[] - { - // pickup - new(OpCodes.Ldarg_0), - - // PreviousOwner.Hub - new CodeInstruction(OpCodes.Ldarg_0), - new(OpCodes.Ldflda, Field(typeof(BaseKeycardPickup), nameof(BaseKeycardPickup.PreviousOwner))), - new(OpCodes.Ldfld, Field(typeof(Footprint), nameof(Footprint.Hub))), - new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), - - // door - new(OpCodes.Ldloc_1), - - // allowed calculate - new(OpCodes.Ldloc_S, isUnlocked), - - new(OpCodes.Ldloc_S, havePermissions), - - new(OpCodes.Ldloc_S, notEmptyPermissions), - new(OpCodes.Call, PropertyGetter(typeof(Events), nameof(Events.Instance))), - new(OpCodes.Callvirt, PropertyGetter(typeof(Events), nameof(Events.Config))), - new(OpCodes.Callvirt, PropertyGetter(typeof(Config), nameof(Config.CanKeycardThrowAffectDoors))), - new(OpCodes.Or), - - new(OpCodes.And), - new(OpCodes.And), - - // ThrowKeycardInteractingEventArgs ev = new(pickup, player, door, isAllowed); - // - // Item.OnThrowKeycardInteracting(ev); - // - // if (!ev.IsAllowed) - // return; - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(KeycardInteractingEventArgs))[0]), - new(OpCodes.Dup), - new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnKeycardInteracting))), - new(OpCodes.Callvirt, PropertyGetter(typeof(KeycardInteractingEventArgs), nameof(KeycardInteractingEventArgs.IsAllowed))), - new(OpCodes.Brfalse_S, ret), - }); + new(OpCodes.Callvirt, PropertyGetter(typeof(KeycardInteractingEventArgs), nameof(KeycardInteractingEventArgs.IsAllowed))), + }); newInstructions.InsertRange( newInstructions.Count - 1, @@ -167,26 +116,5 @@ private static IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions); } - - private static bool CheckPermissions(BaseKeycardPickup keycard, DoorVariant door) - { - DoorPermissions permissions = door.RequiredPermissions; - if (permissions.RequiredPermissions == KeycardPermissions.None) - { - return true; - } - - if (Pickup.Get(keycard) is KeycardPickup keycardPickup) - { - if (!permissions.RequireAll) - { - return ((KeycardPermissions)keycardPickup.Permissions & permissions.RequiredPermissions) != 0; - } - - return ((KeycardPermissions)keycardPickup.Permissions & permissions.RequiredPermissions) == permissions.RequiredPermissions; - } - - return InventorySystem.InventoryItemLoader.AvailableItems.TryGetValue(keycard.Info.ItemId, out ItemBase itemBase) && permissions.CheckPermissions(itemBase, null); - } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs index 1bf2c9c02d..0d53ebeefb 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs @@ -42,7 +42,7 @@ private static IEnumerable Transpiler(IEnumerable i.opcode == OpCodes.Ldloca_S); + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Pop) + 1; newInstructions.InsertRange(index, new[] { diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingNtfEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingNtfEntrance.cs index f9663ecc7e..4d169bf050 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingNtfEntrance.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingNtfEntrance.cs @@ -55,8 +55,8 @@ private static IEnumerable Transpiler(IEnumerable x.characterClassManager.CurRole.team == Team.SCP && x.characterClassManager.CurClass != RoleTypeId.Scp0492); - new(OpCodes.Ldloc_3), + // scpsLeft + new(OpCodes.Ldloc_2), // string[] unitInformation = unitNameClear.Split('-'); new(OpCodes.Ldloc_1), @@ -111,7 +111,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable i.opcode == OpCodes.Ldloc_0) + offset; + int offset = -3; + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Newobj && (ConstructorInfo)i.operand == GetDeclaredConstructors(typeof(LabApi.Events.Arguments.ServerEvents.CassieQueuingScpTerminationEventArgs))[0]) + offset; newInstructions.InsertRange( index, @@ -53,10 +54,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); int offset = 1; - int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Stloc_3) + offset; + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Stloc_S && i.operand is LocalBuilder { LocalIndex: 5 }) + offset; - Label returnLabel = generator.DefineLabel(); + Label continueLabel = generator.DefineLabel(); LocalBuilder ev = generator.DeclareLocal(typeof(ExplodingGrenadeEventArgs)); - newInstructions.InsertRange( - index, - new CodeInstruction[] - { - // attacker; - new(OpCodes.Ldarg_0), - - // position - new(OpCodes.Ldarg_1), - - // grenade - new(OpCodes.Ldarg_2), - - // Collider[] - new(OpCodes.Ldloc_3), - - // explosionType - new(OpCodes.Ldarg_3), - - // ExplodingGrenadeEventArgs ev = new(player, position, grenade, colliders, ExplosionType); - new(OpCodes.Newobj, DeclaredConstructor(typeof(ExplodingGrenadeEventArgs), new[] { typeof(Footprint), typeof(Vector3), typeof(ExplosionGrenade), typeof(Collider[]), typeof(ExplosionType) })), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Stloc, ev.LocalIndex), - - // Map.OnExplodingGrenade(ev); - new(OpCodes.Call, Method(typeof(Handlers.Map), nameof(Handlers.Map.OnExplodingGrenade))), - - // if (!ev.IsAllowed) - // return; - new(OpCodes.Callvirt, PropertyGetter(typeof(ExplodingGrenadeEventArgs), nameof(ExplodingGrenadeEventArgs.IsAllowed))), - new(OpCodes.Brfalse, returnLabel), - - // colliders = TrimColliders(ev, colliders) - new(OpCodes.Ldloc, ev.LocalIndex), - new(OpCodes.Ldloc_3), - new(OpCodes.Call, Method(typeof(ExplodingFragGrenade), nameof(TrimColliders))), - new(OpCodes.Stloc_3), - }); - - newInstructions[newInstructions.Count - 1].labels.Add(returnLabel); + newInstructions.InsertRange(index, new CodeInstruction[] + { + // attacker; + new(OpCodes.Ldarg_0), + + // position + new(OpCodes.Ldarg_1), + + // grenade + new(OpCodes.Ldarg_2), + + // Collider[] + new(OpCodes.Ldloc_S, 5), + + // explosionType + new(OpCodes.Ldarg_3), + + // ExplodingGrenadeEventArgs ev = new(Footprint, position, grenade, colliders, ExplosionType); + new(OpCodes.Newobj, DeclaredConstructor(typeof(ExplodingGrenadeEventArgs), new[] { typeof(Footprint), typeof(Vector3), typeof(ExplosionGrenade), typeof(Collider[]), typeof(ExplosionType) })), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Stloc, ev.LocalIndex), + + // Map.OnExplodingGrenade(ev); + new(OpCodes.Call, Method(typeof(Handlers.Map), nameof(Handlers.Map.OnExplodingGrenade))), + + // if (!ev.IsAllowed) + // return; + new(OpCodes.Callvirt, PropertyGetter(typeof(ExplodingGrenadeEventArgs), nameof(ExplodingGrenadeEventArgs.IsAllowed))), + new(OpCodes.Brtrue_S, continueLabel), + + // HashSetPool.Shared.Return(hashSet); + new(OpCodes.Ldsfld, Field(typeof(NorthwoodLib.Pools.HashSetPool), nameof(NorthwoodLib.Pools.HashSetPool.Shared))), + new(OpCodes.Ldloc_2), + new(OpCodes.Callvirt, Method(typeof(NorthwoodLib.Pools.HashSetPool), nameof(NorthwoodLib.Pools.HashSetPool.Return))), + + // HashSetPool.Shared.Return(hashSet2); + new(OpCodes.Ldsfld, Field(typeof(NorthwoodLib.Pools.HashSetPool), nameof(NorthwoodLib.Pools.HashSetPool.Shared))), + new(OpCodes.Ldloc_3), + new(OpCodes.Callvirt, Method(typeof(NorthwoodLib.Pools.HashSetPool), nameof(NorthwoodLib.Pools.HashSetPool.Return))), + + // return; + new(OpCodes.Ret), + + // colliders = TrimColliders(ev, colliders) + new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex).WithLabels(continueLabel), + new(OpCodes.Ldloc_S, 5), + new(OpCodes.Call, Method(typeof(ExplodingFragGrenade), nameof(TrimColliders))), + new(OpCodes.Stloc_S, 5), + }); for (int z = 0; z < newInstructions.Count; z++) yield return newInstructions[z]; diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs index 0293950826..df768a3048 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs @@ -24,11 +24,11 @@ namespace Exiled.Events.Patches.Events.Map using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.SpawningItem))] - [HarmonyPatch(typeof(ItemDistributor), nameof(ItemDistributor.CreatePickup))] + [HarmonyPatch(typeof(ItemDistributor), nameof(ItemDistributor.ServerRegisterPickup))] internal static class SpawningItem { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs index 7b11934f9d..b379bdec1a 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs @@ -88,14 +88,14 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); - int offset = 0; - int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(RoomConnectorSpawnpointBase), nameof(RoomConnectorSpawnpointBase.SetupAllRoomConnectors)))) + offset; + int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(RoomConnectorSpawnpointBase), nameof(RoomConnectorSpawnpointBase.SetupAllRoomConnectors)))); + List - [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.InteractingDoor))] + [EventPatch(typeof(Handlers.Player), nameof(Player.InteractingDoor))] [HarmonyPatch(typeof(DoorVariant), nameof(DoorVariant.ServerInteract), typeof(ReferenceHub), typeof(byte))] internal static class InteractingDoor { @@ -33,92 +33,166 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); - LocalBuilder ev = generator.DeclareLocal(typeof(InteractingDoorEventArgs)); + LocalBuilder labEvent = generator.DeclareLocal(typeof(PlayerInteractedDoorEventArgs)); + + Label exiledEvContinue = generator.DefineLabel(); + Label labEvContinue = generator.DefineLabel(); + + int offset = -3; + int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(DoorVariant), nameof(DoorVariant.AllowInteracting)))) + offset; - List [Description("The config files distribution type (Default, Separated)")] - public ConfigType ConfigType { get; set; } = ConfigType.Default; + public ConfigType ConfigType { get; set; } = ConfigType.Separated; /// /// Gets or sets the quotes wrapper type. diff --git a/EXILED/Exiled.Loader/ConfigManager.cs b/EXILED/Exiled.Loader/ConfigManager.cs index 3a59afedf0..e925517be9 100644 --- a/EXILED/Exiled.Loader/ConfigManager.cs +++ b/EXILED/Exiled.Loader/ConfigManager.cs @@ -273,7 +273,7 @@ public static void ReloadRemoteAdmin() ServerStatic.SharedGroupsConfig = GameCore.ConfigSharing.Paths[4] is null ? null : new YamlConfig(GameCore.ConfigSharing.Paths[4] + "shared_groups.txt"); ServerStatic.SharedGroupsMembersConfig = GameCore.ConfigSharing.Paths[5] is null ? null : new YamlConfig(GameCore.ConfigSharing.Paths[5] + "shared_groups_members.txt"); ServerStatic.PermissionsHandler = new PermissionsHandler(ref ServerStatic.RolesConfig, ref ServerStatic.SharedGroupsConfig, ref ServerStatic.SharedGroupsMembersConfig); - ServerStatic.GetPermissionsHandler().RefreshPermissions(); + ServerStatic.PermissionsHandler.RefreshPermissions(); foreach (Player player in Player.List) { diff --git a/EXILED/Exiled.Loader/Exiled.Loader.csproj b/EXILED/Exiled.Loader/Exiled.Loader.csproj index fc19e5aea6..55b587ef44 100644 --- a/EXILED/Exiled.Loader/Exiled.Loader.csproj +++ b/EXILED/Exiled.Loader/Exiled.Loader.csproj @@ -25,8 +25,8 @@ + - diff --git a/EXILED/Exiled.Loader/Loader.cs b/EXILED/Exiled.Loader/Loader.cs index 2c3ce68de9..7c2194d09f 100644 --- a/EXILED/Exiled.Loader/Loader.cs +++ b/EXILED/Exiled.Loader/Loader.cs @@ -46,7 +46,7 @@ public Loader() Log.Warn("You are running a public beta build. It is not compatible with another version of the game."); #endif - Log.SendRaw($"Exiled.API - Version {PluginAPI.Loader.AssemblyLoader.Dependencies.FirstOrDefault(x => x.GetName().Name == "Exiled.API").GetCustomAttribute().InformationalVersion}", ConsoleColor.DarkRed); + Log.SendRaw($"Exiled.API - Version {LabApi.Loader.PluginLoader.Dependencies.FirstOrDefault(x => x.GetName().Name == "Exiled.API").GetCustomAttribute().InformationalVersion}", ConsoleColor.DarkRed); Log.SendRaw($"{Assembly.GetExecutingAssembly().GetName().Name} - Version {Assembly.GetExecutingAssembly().GetCustomAttribute().InformationalVersion}", ConsoleColor.DarkRed); if (MultiAdminFeatures.MultiAdminUsed) diff --git a/EXILED/Exiled.Loader/LoaderPlugin.cs b/EXILED/Exiled.Loader/LoaderPlugin.cs index 349da02566..b2f5215ccd 100644 --- a/EXILED/Exiled.Loader/LoaderPlugin.cs +++ b/EXILED/Exiled.Loader/LoaderPlugin.cs @@ -11,33 +11,69 @@ namespace Exiled.Loader using System.IO; using System.Reflection; - using MEC; + using LabApi.Loader.Features.Plugins; + using LabApi.Loader.Features.Plugins.Enums; - using PluginAPI.Core.Attributes; + using MEC; using Log = API.Features.Log; using Paths = API.Features.Paths; /// - /// The Northwood PluginAPI Plugin class for the EXILED Loader. + /// The Northwood LabAPI Plugin class for the EXILED Loader. /// - public class LoaderPlugin + public class LoaderPlugin : Plugin { #pragma warning disable SA1401 /// /// The config for the EXILED Loader. /// - [PluginConfig] - public static Config Config; + public static new Config Config; + + /// + /// The config for the EXILED Loader. + /// + public static LoaderPlugin Instance; #pragma warning restore SA1401 /// - /// Called by PluginAPI when the plugin is enabled. + /// Gets the Name of the EXILED Loader. + /// + public override string Name => "Exiled Loader"; + + /// + /// Gets the Description of the EXILED Loader. + /// + public override string Description => "Loads the EXILED Plugin Framework."; + + /// + /// Gets the Author of the EXILED Loader. + /// + public override string Author => "ExMod-Team"; + + /// + /// Gets the RequiredApiVersion of the EXILED Loader. /// - [PluginEntryPoint("Exiled Loader", null, "Loads the EXILED Plugin Framework.", "ExMod-Team")] - [PluginPriority(byte.MinValue)] - public void Enable() + public override Version RequiredApiVersion { get; } = Assembly.GetAssembly(typeof(LabApi.Loader.PluginLoader)).GetReferencedAssemblies()[0].Version; // TODO Not finish + + /// + /// Gets the Exiled Version. + /// + public override Version Version => Loader.Version; + + /// + /// Gets the Exiled Priority load. + /// + public override LoadPriority Priority { get; } = (LoadPriority)byte.MaxValue; + + /// + /// Called by LabAPI when the plugin is enabled. + /// + public override void Enable() { + Instance = this; + Config = base.Config; + if (Config == null) { Log.Error("Detected null config, EXILED will not be loaded."); @@ -63,5 +99,13 @@ public void Enable() Timing.RunCoroutine(new Loader().Run()); } + + /// + /// Called by LabAPI when the plugin is Disable. + /// + public override void Disable() + { + // Plugin will not be disable + } } } \ No newline at end of file diff --git a/EXILED/Exiled.Loader/Updater.cs b/EXILED/Exiled.Loader/Updater.cs index 448adfd6c2..a90f0589b0 100644 --- a/EXILED/Exiled.Loader/Updater.cs +++ b/EXILED/Exiled.Loader/Updater.cs @@ -69,7 +69,7 @@ where name.StartsWith("Exiled.", StringComparison.OrdinalIgnoreCase) && name != Assembly.GetExecutingAssembly().GetName().Name select new ExiledLib(a); - private string Folder => File.Exists($"{PluginAPI.Helpers.Paths.GlobalPlugins.Plugins}/Exiled.Loader.dll") ? "global" : Server.Port.ToString(); + private string Folder => File.Exists(Path.Combine(LabApi.Loader.Features.Paths.PathManager.Plugins.FullName, "global", "Exiled.Loader.dll")) ? "global" : Server.Port.ToString(); private string InstallerName { @@ -116,7 +116,7 @@ internal void CheckUpdate() try { using HttpClient client = CreateHttpClient(); - if (Busy = FindUpdate(client, !PluginAPI.Loader.AssemblyLoader.Dependencies.Exists(x => x.GetName().Name == "Exiled.API"), out NewVersion newVersion)) + if (Busy = FindUpdate(client, !LabApi.Loader.PluginLoader.Dependencies.Any(x => x.GetName().Name == "Exiled.API"), out NewVersion newVersion)) Update(client, newVersion); } catch (Exception e) @@ -136,7 +136,7 @@ private HttpClient CreateHttpClient() Timeout = TimeSpan.FromSeconds(480), }; - client.DefaultRequestHeaders.Add("User-Agent", $"Exiled.Loader (https://github.com/ExMod-Team/EXILED, {Assembly.GetExecutingAssembly().GetName().Version.ToString(3)})"); + client.DefaultRequestHeaders.Add("User-Agent", $"Exiled.Loader (https://github.com/ExSLMod-Team/EXILED, {Assembly.GetExecutingAssembly().GetName().Version.ToString(3)})"); return client; } diff --git a/EXILED/Exiled.Permissions/Exiled.Permissions.csproj b/EXILED/Exiled.Permissions/Exiled.Permissions.csproj index 3c130764f8..7057fc5d5d 100644 --- a/EXILED/Exiled.Permissions/Exiled.Permissions.csproj +++ b/EXILED/Exiled.Permissions/Exiled.Permissions.csproj @@ -23,10 +23,10 @@ + - diff --git a/EXILED/Exiled.Permissions/Extensions/Permissions.cs b/EXILED/Exiled.Permissions/Extensions/Permissions.cs index b03271b4be..56823e3feb 100644 --- a/EXILED/Exiled.Permissions/Extensions/Permissions.cs +++ b/EXILED/Exiled.Permissions/Extensions/Permissions.cs @@ -105,7 +105,7 @@ public static void Reload() { try { - if (string.Equals(group.Key, "user", StringComparison.OrdinalIgnoreCase) || ServerStatic.PermissionsHandler._groups.ContainsKey(group.Key)) + if (string.Equals(group.Key, "user", StringComparison.OrdinalIgnoreCase) || ServerStatic.PermissionsHandler.Groups.ContainsKey(group.Key)) { deserializedPerms.Add(group.Key, Deserializer.Deserialize(Serializer.Serialize(group.Value))); } @@ -207,7 +207,7 @@ public static bool CheckPermission(this Player player, string permission) Log.Debug($"UserID: {player.UserId} | PlayerId: {player.Id}"); Log.Debug($"Permission string: {permission}"); - string plyGroupKey = player.Group is not null ? ServerStatic.GetPermissionsHandler()._groups.FirstOrDefault(g => g.Value.EqualsTo(player.Group)).Key : null; + string plyGroupKey = player.Group is not null ? ServerStatic.PermissionsHandler.Groups.FirstOrDefault(g => g.Value.EqualsTo(player.Group)).Key : null; Log.Debug($"GroupKey: {plyGroupKey ?? "(null)"}"); if (plyGroupKey is null || !Groups.TryGetValue(plyGroupKey, out Group group)) diff --git a/EXILED/Exiled/Exiled.nuspec b/EXILED/Exiled/Exiled.nuspec index 388d8ae0e9..cf95b0fbc8 100644 --- a/EXILED/Exiled/Exiled.nuspec +++ b/EXILED/Exiled/Exiled.nuspec @@ -9,9 +9,9 @@ ExMod-Team Copyright © ExMod Team 2024 - $year$ false - - https://github.com/ExMod-Team/EXILED/blob/master/LICENSE - https://github.com/ExMod-Team/EXILED + + https://github.com/ExSLMod-Team/EXILED/blob/master/LICENSE + https://github.com/ExSLMod-Team/EXILED images\Exiled_Icon.png Plugin framework for SCP: Secret Laboratory. @@ -26,7 +26,7 @@ - + diff --git a/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md b/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md index 66dd2d881e..31ee11803d 100644 --- a/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md +++ b/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md @@ -17,7 +17,7 @@ title: NW Documentation --- -Last Update (14.0.0.2) +Last Update (14.1.0.0) ### Index @@ -61,8 +61,7 @@ Last Update (14.0.0.2) - [ChallengeState](#challengestate) - [ChallengeType](#challengetype) - [ChamberState](#chamberstate) -- [CheckpointErrorType](#checkpointerrortype) -- [CheckpointSequenceStage](#checkpointsequencestage) +- [ChaosMsgType](#chaosmsgtype) - [ClientFlags](#clientflags) - [ClientInstanceMode](#clientinstancemode) - [ClientReceivedContentType](#clientreceivedcontenttype) @@ -72,6 +71,7 @@ Last Update (14.0.0.2) - [CmdTeleportData](#cmdteleportdata) - [CoffeeTranslation](#coffeetranslation) - [CollectionDeserializeToBehaviour](#collectiondeserializetobehaviour) +- [ColliderShape](#collidershape) - [CollisionsDisablingReasons](#collisionsdisablingreasons) - [ColorMode](#colormode) - [CommandOperationMode](#commandoperationmode) @@ -89,6 +89,7 @@ Last Update (14.0.0.2) - [DecalPoolType](#decalpooltype) - [DecontaminationStatus](#decontaminationstatus) - [DeliveryMethod](#deliverymethod) +- [DetectionStatus](#detectionstatus) - [DiodeType](#diodetype) - [DisconnectReason](#disconnectreason) - [DisconnectResult](#disconnectresult) @@ -101,6 +102,7 @@ Last Update (14.0.0.2) - [DoorDamageType](#doordamagetype) - [DoorLockMode](#doorlockmode) - [DoorLockReason](#doorlockreason) +- [DoorPermissionFlags](#doorpermissionflags) - [DropdownEntryType](#dropdownentrytype) - [DtoaMode](#dtoamode) - [EffectClassification](#effectclassification) @@ -133,6 +135,8 @@ Last Update (14.0.0.2) - [FoldoutMode](#foldoutmode) - [FootprintsTranslation](#footprintstranslation) - [FootstepLoudness](#footsteploudness) +- [ForceCondition](#forcecondition) +- [ForceResult](#forceresult) - [FpcViewMode](#fpcviewmode) - [FreezingMode](#freezingmode) - [FriendlyFireAction](#friendlyfireaction) @@ -171,7 +175,8 @@ Last Update (14.0.0.2) - [JailbirdMessageType](#jailbirdmessagetype) - [JailbirdWearState](#jailbirdwearstate) - [JsonToken](#jsontoken) -- [KeycardPermissions](#keycardpermissions) +- [KeycardLabelTranslation](#keycardlabeltranslation) +- [KeyCodeTranslations](#keycodetranslations) - [LcdElementType](#lcdelementtype) - [LeadingTeam](#leadingteam) - [LegacyInterfaces](#legacyinterfaces) @@ -196,6 +201,7 @@ Last Update (14.0.0.2) - [Mode](#mode) - [ModifierMode](#modifiermode) - [Modules](#modules) +- [MsgType](#msgtype) - [NatAddressType](#nataddresstype) - [NetLogLevel](#netloglevel) - [NetworkProtocolType](#networkprotocoltype) @@ -231,12 +237,14 @@ Last Update (14.0.0.2) - [RadioCommand](#radiocommand) - [RadioRangeLevel](#radiorangelevel) - [RejectionReason](#rejectionreason) +- [RejectionReason](#rejectionreason) - [ReloaderMessageHeader](#reloadermessageheader) - [RemoteAdminResponseFlags](#remoteadminresponseflags) - [RemovalMode](#removalmode) - [ReproProjectAssetType](#reproprojectassettype) - [RequestType](#requesttype) - [RespawnSetting](#respawnsetting) +- [RespawnTooltipTranslation](#respawntooltiptranslation) - [ResurrectError](#resurrecterror) - [RoleChangeReason](#rolechangereason) - [RoleSpawnFlags](#rolespawnflags) @@ -257,6 +265,7 @@ Last Update (14.0.0.2) - [RpcType](#rpctype) - [RpcType](#rpctype) - [RpcType](#rpctype) +- [RpcType](#rpctype) - [ScanSequenceStep](#scansequencestep) - [Scp0492SoundId](#scp0492soundid) - [Scp079HudTranslation](#scp079hudtranslation) @@ -264,6 +273,8 @@ Last Update (14.0.0.2) - [Scp096HitResult](#scp096hitresult) - [Scp096HudTranslation](#scp096hudtranslation) - [Scp096RageState](#scp096ragestate) +- [Scp127Tier](#scp127tier) +- [Scp127VoiceLinesTranslation](#scp127voicelinestranslation) - [Scp1344Status](#scp1344status) - [Scp173SoundId](#scp173soundid) - [Scp244State](#scp244state) @@ -275,8 +286,10 @@ Last Update (14.0.0.2) - [Scp939DamageType](#scp939damagetype) - [Scp939HudTranslation](#scp939hudtranslation) - [Scp939LungeState](#scp939lungestate) +- [ScpSetting](#scpsetting) - [SecurityLevel](#securitylevel) - [SensitivitySetting](#sensitivitysetting) +- [SequenceState](#sequencestate) - [ServerLogType](#serverlogtype) - [ServerOperativeSystem](#serveroperativesystem) - [ServerRateLimit](#serverratelimit) @@ -290,6 +303,7 @@ Last Update (14.0.0.2) - [SpectatorSpawnReason](#spectatorspawnreason) - [State](#state) - [States](#states) +- [StatMessageType](#statmessagetype) - [StatusType](#statustype) - [SteamLobbyPrivacy](#steamlobbyprivacy) - [StorageLocation](#storagelocation) @@ -318,6 +332,7 @@ Last Update (14.0.0.2) - [VersionType](#versiontype) - [VoiceChatChannel](#voicechatchannel) - [VoiceChatSupportMode](#voicechatsupportmode) +- [VoiceLinePriority](#voicelinepriority) - [VoiceLinesName](#voicelinesname) - [VolumeSliderSetting](#volumeslidersetting) - [WarheadScenarioType](#warheadscenariotype) @@ -382,6 +397,7 @@ Last Update (14.0.0.2) [48] = UndeadSpaceProgram [49] = ArizonaRanger [50] = Matador + [51] = ToothAndNail ``` @@ -986,27 +1002,15 @@ Last Update (14.0.0.2) -### CheckpointErrorType +### ChaosMsgType -
Interactables.Interobjects.CheckpointDoor+CheckpointErrorType +
InventorySystem.Items.Keycards.ChaosKeycardItem+ChaosMsgType ``` - [0] = Denied - [1] = LockedDown - [2] = Destroyed -``` - -
- -### CheckpointSequenceStage - -
Interactables.Interobjects.CheckpointDoor+CheckpointSequenceStage - -``` - [0] = Idle - [1] = Granted - [2] = Open - [3] = Closing + [0] = SnakeMsgSync + [1] = NewConnectionFullSync + [2] = MovementSwitch + [3] = UseDetails ```
@@ -1161,6 +1165,18 @@ Last Update (14.0.0.2)
+### ColliderShape + +
AdminToys.InvisibleInteractableToy+ColliderShape + +``` + [0] = Box + [1] = Sphere + [2] = Capsule +``` + +
+ ### CollisionsDisablingReasons
Interactables.Interobjects.DoorUtils.DoorVariant+CollisionsDisablingReasons @@ -1413,6 +1429,18 @@ Last Update (14.0.0.2)
+### DetectionStatus + +
InventorySystem.Items.Firearms.Modules.Scp127.Scp127CassieBasedVoiceTriggerBase+DetectionStatus + +``` + [0] = Idle + [1] = WaitingForTrigger + [2] = AnnouncementStartedPlaying +``` + +
+ ### DiodeType
AlphaWarheadNukesitePanel+DiodeType @@ -1585,6 +1613,28 @@ Last Update (14.0.0.2)
+### DoorPermissionFlags + +
Interactables.Interobjects.DoorUtils.DoorPermissionFlags + +``` + [0] = None + [1] = Checkpoints + [2] = ExitGates + [4] = Intercom + [8] = AlphaWarhead + [16] = ContainmentLevelOne + [32] = ContainmentLevelTwo + [64] = ContainmentLevelThree + [128] = ArmoryLevelOne + [256] = ArmoryLevelTwo + [512] = ArmoryLevelThree + [1024] = ScpOverride + [65535] = All +``` + +
+ ### DropdownEntryType
UserSettings.ServerSpecific.SSDropdownSetting+DropdownEntryType @@ -1649,6 +1699,7 @@ Last Update (14.0.0.2) [6] = Nuke01 [7] = Scp049 [8] = Nuke02 + [9] = ServerRoom ```
@@ -1658,11 +1709,12 @@ Last Update (14.0.0.2)
Interactables.Interobjects.ElevatorChamber+ElevatorSequence ``` - [0] = DoorClosing - [1] = MovingAway - [2] = Arriving - [3] = DoorOpening - [4] = Ready + [0] = StartingSequence + [1] = DoorClosing + [2] = MovingAway + [3] = Arriving + [4] = DoorOpening + [5] = Ready ```
@@ -1747,6 +1799,7 @@ Last Update (14.0.0.2) [2] = CuffedClassD [3] = Scientist [4] = CuffedScientist + [5] = Custom ``` @@ -2022,6 +2075,7 @@ Last Update (14.0.0.2) [9] = HalloweenOutside [10] = ChristmasInside [11] = ChristmasOutside + [12] = PocketDimension ``` @@ -2071,6 +2125,29 @@ Last Update (14.0.0.2) +### ForceCondition + +
PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.GlowInTheDarkSubcontroller+ForceCondition + +``` + [0] = NeverForce + [1] = ForceWhenFriendly + [2] = ForceWhenEnemy +``` + +
+ +### ForceResult + +
PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.GlowInTheDarkSubcontroller+ForceResult + +``` + [0] = ForceDarkened + [1] = ForceNormal +``` + +
+ ### FpcViewMode
PlayerRoles.FirstPersonControl.FpcMotor+FpcViewMode @@ -2268,6 +2345,7 @@ Last Update (14.0.0.2) [15] = PackedLong [16] = PackedULong [17] = Scp330Hint + [18] = SSKeybind ```
@@ -2498,6 +2576,8 @@ Last Update (14.0.0.2) [24] = JailbirdChargeHint [25] = MicroHidReadyToDischarge [26] = MicroHidDamaged + [27] = Scp127OnEquip + [28] = SnakeHint ``` @@ -2658,6 +2738,13 @@ Last Update (14.0.0.2) [57] = Coal [58] = SpecialCoal [59] = SCP1507Tape + [60] = DebugRagdollMover + [61] = SurfaceAccessPass + [62] = GunSCP127 + [63] = KeycardCustomTaskForce + [64] = KeycardCustomSite02 + [65] = KeycardCustomManagement + [66] = KeycardCustomMetalCase [-1] = None ``` @@ -2717,23 +2804,48 @@ Last Update (14.0.0.2) -### KeycardPermissions +### KeycardLabelTranslation -
Interactables.Interobjects.DoorUtils.KeycardPermissions +
InventorySystem.Items.Keycards.TranslatedLabelDetail+KeycardLabelTranslation ``` - [0] = None - [1] = Checkpoints - [2] = ExitGates - [4] = Intercom - [8] = AlphaWarhead - [16] = ContainmentLevelOne - [32] = ContainmentLevelTwo - [64] = ContainmentLevelThree - [128] = ArmoryLevelOne - [256] = ArmoryLevelTwo - [512] = ArmoryLevelThree - [1024] = ScpOverride + [0] = Scientist + [1] = Janitor + [2] = ResearchSupervisor + [3] = ContEngineer + [4] = SecurityGuard + [5] = ZoneManager + [6] = FacilityManager + [7] = SurfaceAccessPassNormal + [8] = SurfaceAccessPassUsed +``` + +
+ +### KeyCodeTranslations + +
Hints.KeyCodeTranslations + +``` + [0] = ServerSettingNotFound + [1] = KeyNotAssigned + [2] = ArrowUp + [3] = ArrowDown + [4] = ArrowLeft + [5] = ArrowRight + [6] = LeftShift + [7] = RightShift + [8] = LeftControl + [9] = RightControl + [10] = LeftAlt + [11] = RightAlt + [12] = Tab + [13] = Space + [14] = Enter + [15] = MousePrimary + [16] = MouseSecondary + [17] = MouseMiddle + [18] = MouseN ```
@@ -2851,12 +2963,14 @@ Last Update (14.0.0.2)
MapGeneration.MapGenerationPhase ``` - [0] = ParentRoomRegistration - [1] = RelativePositioningWaypoints - [2] = ComplexDecorationsAndClutter - [3] = SimpleDecorations - [4] = CullingCaching - [5] = SpawnableStructures + [0] = RoomCoordsRegistrations + [1] = ParentRoomRegistration + [2] = RelativePositioningWaypoints + [3] = ComplexDecorationsAndClutter + [4] = SimpleDecorations + [5] = CullingCaching + [6] = SpawnableStructures + [7] = StaticBatching ```
@@ -2885,6 +2999,7 @@ Last Update (14.0.0.2) [3] = RpcFire [4] = RpcDryFire [5] = RpcNewPlayerSync + [6] = RpcRejectionReason ```
@@ -2923,9 +3038,10 @@ Last Update (14.0.0.2) [1] = RpcRequireReloadFalse [2] = RpcRequireReloadFullResync [3] = RpcStartFiring - [4] = RpcOnShot - [5] = CmdRequestStartFiring - [6] = CmdConfirmDischarge + [4] = RpcStopFiring + [5] = RpcOnShot + [6] = CmdRequestStartFiring + [7] = CmdConfirmDischarge ``` @@ -2987,6 +3103,7 @@ Last Update (14.0.0.2) [5] = RightClickToDrop [6] = InventoryToggle [7] = Scp079KeybindZoneSwitching + [8] = AutomaticSpectatorSwitch ``` @@ -3017,6 +3134,7 @@ Last Update (14.0.0.2) [2] = HeadBobbing [3] = FlashbangDarkMode [4] = ShowNeedles + [5] = Scp939VisionBlur ``` @@ -3031,6 +3149,7 @@ Last Update (14.0.0.2) [2] = Weapons [3] = VoiceChat [4] = NoDucking + [5] = Scp127VoiceViewmodel ``` @@ -3091,6 +3210,19 @@ Last Update (14.0.0.2) +### MsgType + +
InventorySystem.Items.Keycards.KeycardItem+MsgType + +``` + [0] = Custom + [1] = OnKeycardUsed + [2] = Inspect + [3] = NewPlayerFullResync +``` + +
+ ### NatAddressType
LiteNetLib.NatAddressType @@ -3657,6 +3789,19 @@ Last Update (14.0.0.2)
+### RejectionReason + +
InventorySystem.Items.Firearms.Modules.AutomaticActionModule+RejectionReason + +``` + [1] = TimedOut + [2] = ModuleBusy + [3] = NotCocked + [4] = BoltLocked +``` + +
+ ### ReloaderMessageHeader
InventorySystem.Items.Firearms.Modules.AnimatorReloaderModuleBase+ReloaderMessageHeader @@ -3730,6 +3875,18 @@ Last Update (14.0.0.2)
+### RespawnTooltipTranslation + +
Respawning.Graphics.RespawnTooltipTranslation + +``` + [0] = TimerBarTranslation + [1] = InfluenceTranslation + [2] = RespawnsTokensTranslation +``` + +
+ ### ResurrectError
PlayerRoles.PlayableScps.Scp049.Scp049ResurrectAbility+ResurrectError @@ -3859,6 +4016,7 @@ Last Update (14.0.0.2) [35] = Outside [36] = Pocket [37] = HczTestroom + [38] = Hcz127 ```
@@ -4040,6 +4198,17 @@ Last Update (14.0.0.2) ### RpcType +
InventorySystem.Items.Firearms.Modules.Scp127.Scp127VoiceLineManagerModule+RpcType + +``` + [0] = OwnerRegistered + [1] = PlayLine +``` + +
+ +### RpcType +
InventorySystem.Items.Firearms.Attachments.FlashlightAttachment+RpcType ``` @@ -4234,6 +4403,181 @@ Last Update (14.0.0.2)
+### Scp127Tier + +
InventorySystem.Items.Firearms.Modules.Scp127.Scp127Tier + +``` + [0] = Tier1 + [1] = Tier2 + [2] = Tier3 +``` + +
+ +### Scp127VoiceLinesTranslation + +
InventorySystem.Items.Firearms.Modules.Scp127.Scp127VoiceLinesTranslation + +``` + [0] = ChamberingDammitThatHurts + [1] = ChamberingFeelThatTmrw + [2] = ChamberingGrunt1 + [3] = ChamberingGrunt2 + [4] = ChamberingGrunt3 + [5] = ChamberingGrunt4 + [6] = ChamberingHateThatPart + [7] = ChamberingNopeNeverGettinBetter + [8] = ChamberingThatStings + [9] = ChaosSpawnDrowningConstantly + [10] = ChaosSpawnIDontTrustEm + [11] = ChaosSpawnNotHereNotAgain + [12] = ChaosSpawnNotJustMe + [13] = ChaosSpawnThemAgain + [14] = ChaosSpawnThisIsntGonnaEndWell + [15] = DrawGoodToSeeYa + [16] = DrawHelloAgain + [17] = DrawHelloThere + [18] = DrawHello + [19] = DrawHeyHey + [20] = DrawHowsItGoin + [21] = DroppedDontForgetAboutMe + [22] = DroppedGuessIllWaitHere + [23] = DroppedIllCatchUp + [24] = DroppedSeeyaLaterBoss + [25] = DroppedTakeCareBoss + [26] = DroppedWatchThePaint + [27] = HolsterBeHereIfYouNeedMe + [28] = HolsterByeBye + [29] = HolsterFairEnough + [30] = HolsterGoodbye + [31] = HolsterIsTheSafetyOn2 + [32] = HolsterIsTheSafetyOn + [33] = HolsterOffIGo + [34] = HolsterYouKnowWhereToFindMeBoss + [35] = IdleChatterBarDownInQueens + [36] = IdleChatterDifferentFacility + [37] = IdleChatterGettingPaidForThisRight + [38] = IdleChatterSoundedLikeDeath + [39] = IdleChatterThoughtIHeardSomething + [40] = IdleChatterWhatWentWrong + [41] = IdleChatterYouGotAnyPlans + [42] = IdleChatterYouKnowWhereYoureGoin + [43] = MissedAlmostHitSomething + [44] = MissedILikeYourStyleBoss + [45] = MissedInvisHatFellaAround + [46] = MissedUhYouGoodBoss + [47] = MtfSpawnAhaReinforcements + [48] = MtfSpawnDontLetEmTakeMeAgain + [49] = MtfSpawnDontSayAnything + [50] = MtfSpawnFriendsOfYours + [51] = MtfSpawnGotAPlan + [52] = MtfSpawnThatsNotGood + [53] = MtfSpawnThingsAreGettingInterestingNow + [54] = MtfSpawnWereGettingBackup + [55] = OnKillBang + [56] = OnKillBeatItBopIt + [57] = OnKillGoodOneBoss + [58] = OnKillGoodStuff + [59] = OnKillGoodWorkBoss + [60] = OnKillNiceOneBoss + [61] = OnKillNiceShot + [62] = OnKillOooNice + [63] = OnKillRattleHim + [64] = OnKillScram + [65] = OnKillWhamo + [66] = PickupChamberNecksnapMcgee + [67] = PickupChamberPleasedToMeetYa + [68] = PickupChamberRoomForOneMore + [69] = PickupChamberSayWhatYearIsIt + [70] = PickupChamberSweetOxygen + [71] = PickupChamberWaterboarding + [72] = PickupChaosGasMask + [73] = PickupChaosSickGladRagsBoss + [74] = PickupChaosYouFellasFromOuttaTown + [75] = PickupDclassCouplaCorpses + [76] = PickupDclassNeedAHand + [77] = PickupDclassPartnersInCrime + [78] = PickupDclassTagEmBoss + [79] = PickupDclassUsedToOwnAJumpsuit + [80] = PickupDclassWooBreakout + [81] = PickupGenericEasyOnTheGrip + [82] = PickupGenericHeyBossHowsItGoin + [83] = PickupGenericSobbing + [84] = PickupGenericTakeMeWith + [85] = PickupMtfAnyChanceICanGo + [86] = PickupMtfAwJeezRick + [87] = PickupScientistDidntYouStickMeInThatTank + [88] = PickupScientistThoseGlassesBetterBe + [89] = PickupScientistYouDoKnowHowToShootRight + [90] = PickupTutorialHereToRescueMe + [91] = PickupTutorialOutOfPlaceHereBoss + [92] = RankupBetterThanExpected + [93] = RankupDoinPrettyGood + [94] = RankupFeelsGoodToBeBack + [95] = RankupIThinkWereWinning + [96] = RankupManicLaughter + [97] = RankupPartnersInCrimeOrJustice + [98] = ScpKilled049AppleADay + [99] = ScpKilled049BehindThatBeak + [100] = ScpKilled049IAmTheBlackDeath + [101] = ScpKilled049MsBirdface + [102] = ScpKilled049OverdosedOnShells + [103] = ScpKilled049ResurrectThis + [104] = ScpKilled049TakeGoodCareOfTheKids + [105] = ScpKilled0790101Moron + [106] = ScpKilled079AintDyinToAMinifridge + [107] = ScpKilled079KeepTheCamera + [108] = ScpKilled079NeverLikedThatToaster + [109] = ScpKilled079WarrantyRunOut + [110] = ScpKilled0967FeetTall + [111] = ScpKilled096AllTheRage + [112] = ScpKilled096IMayNotHaveEyes2 + [113] = ScpKilled096IMayNotHaveEyes + [114] = ScpKilled096LikedTheStatue + [115] = ScpKilled096ThoughtHedNeverShutUp + [116] = ScpKilled106HaveFunInTheCage + [117] = ScpKilled106OldDudesGone + [118] = ScpKilled106PocketThisDimension + [119] = ScpKilled106SinkingFeeling + [120] = ScpKilled106StayForABit + [121] = ScpKilled106SunkIntoTheFloor + [122] = ScpKilled173EyeOpener + [123] = ScpKilled173PeiceThatBackTogether + [124] = ScpKilled173ScrapingWasGettingOnMyNerves + [125] = ScpKilled173ShatteredLikeGlass + [126] = ScpKilled939NothingToSayNow + [127] = ScpKilled939StayDownFreakshow + [128] = ScpKilled939YouAintTheFirst2 + [129] = ScpKilled939YouAintTheFirst + [130] = ScpKilled3114NoMoreBones + [131] = ScpKilled3114OneLessSkeleton + [132] = ScpKilled3114WeGotTheSkinwalker + [133] = ScpKilledAllThoseFreakyPowers + [134] = ScpKilledCoupleOfRounds + [135] = ScpKilledGunBeatsWhateverYouAre2 + [136] = ScpKilledGunBeatsWhateverYouAre + [137] = ScpKilledNotSoTough + [138] = ScpKilledWhyBuildAContainer + [139] = ScpKilledZombieAintNoPill + [140] = ScpKilledZombieGetHisGoons + [141] = ScpKilledZombieMr12FeetUnder + [142] = ScpKilledZombieSayGoodbyeToUrGoons + [143] = ScpKilledZombieStayDown + [144] = ScpKilledZombieTwoLivesTooMany + [145] = ScpKilledZombieWhatGetsUp + [146] = UserKilledAttacthmentIssues + [147] = UserKilledBooooosss + [148] = UserKilledHeyHeyGetUp + [149] = UserKilledJustStartingToLikeYou + [150] = UserKilledNoNotNow2 + [151] = UserKilledNoNotNow + [152] = UserKilledNotAgain2 + [153] = UserKilledNotAgain +``` + +
+ ### Scp1344Status
InventorySystem.Items.Usables.Scp1344.Scp1344Status @@ -4436,6 +4780,16 @@ Last Update (14.0.0.2)
+### ScpSetting + +
UserSettings.OtherSettings.ScpSetting + +``` + [0] = ScpOptOut +``` + +
+ ### SecurityLevel
EncryptedChannelManager+SecurityLevel @@ -4459,6 +4813,19 @@ Last Update (14.0.0.2)
+### SequenceState + +
Interactables.Interobjects.CheckpointDoor+SequenceState + +``` + [0] = Idle + [1] = Granted + [2] = OpenLoop + [3] = ClosingWarning +``` + +
+ ### ServerLogType
ServerLogs+ServerLogType @@ -4636,6 +5003,17 @@ Last Update (14.0.0.2)
+### StatMessageType + +
PlayerStatsSystem.SyncedStatMessages+StatMessageType + +``` + [0] = CurrentValue + [1] = MaxValue +``` + +
+ ### StatusType
InventorySystem.Items.Usables.StatusMessage+StatusType @@ -4881,6 +5259,7 @@ Last Update (14.0.0.2) [4] = Trigger [8] = Tokens [11] = All + [16] = Spawn ```
@@ -5054,6 +5433,19 @@ Last Update (14.0.0.2) +### VoiceLinePriority + +
InventorySystem.Items.Firearms.Modules.Scp127.Scp127VoiceTriggerBase+VoiceLinePriority + +``` + [0] = Low + [1] = Normal + [2] = High + [3] = VeryHigh +``` + +
+ ### VoiceLinesName
PlayerRoles.PlayableScps.Scp3114.Scp3114VoiceLines+VoiceLinesName @@ -5080,6 +5472,8 @@ Last Update (14.0.0.2) [2] = SoundEffects [3] = MenuMusic [4] = MenuUI + [5] = Scp127Voice + [6] = Scp3114Voice ```
@@ -5111,12 +5505,13 @@ Last Update (14.0.0.2) ### WearableElements -
PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.WearableElements +
PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.Wearables.WearableElements ``` [0] = None [1] = Scp268Hat [2] = Scp1344Goggles + [4] = Armor ```
@@ -5200,7 +5595,7 @@ Last Update (14.0.0.2)
Damage Handlers -```md title="Latest Updated: 14.0.0.2" +```md title="Latest Updated: 14.1.0.0" All available DamageHandlers + Symbol ':' literally means "inherits from" @@ -5210,6 +5605,7 @@ All available DamageHandlers Scp956DamageHandler : StandardDamageHandler SnowballDamageHandler : AttackerDamageHandler PlayerStatsSystem.CustomReasonDamageHandler : StandardDamageHandler +PlayerStatsSystem.CustomReasonFirearmDamageHandler : FirearmDamageHandler PlayerStatsSystem.DisruptorDamageHandler : AttackerDamageHandler PlayerStatsSystem.ExplosionDamageHandler : AttackerDamageHandler PlayerStatsSystem.FirearmDamageHandler : AttackerDamageHandler diff --git a/EXILED/docs/articles/contributing/index.md b/EXILED/docs/articles/contributing/index.md index b721accdf3..fdcec6d5a0 100644 --- a/EXILED/docs/articles/contributing/index.md +++ b/EXILED/docs/articles/contributing/index.md @@ -6,7 +6,7 @@ title: Contributing to EXILED This is a simple tutorial guiding you to contribute to our framework. ### Forking EXILED -First, create a fork of our [GitHub repository](https://github.com/ExMod-Team/EXILED). +First, create a fork of our [GitHub repository](https://github.com/ExSLMod-Team/EXILED). Then, clone it to your computer like so: `git clone https://github.com/your-username/EXILED.git` @@ -14,7 +14,7 @@ Open a terminal in your forked EXILED folder and run ```git checkout dev```. Thi ### Setting `EXILED_REFERENCES` -If you haven't already, install the `SCP: Secret Laboratory Dedicated Server` through Steam or extract [this zip file](https://ExMod-Team.github.io/SL-References/Dev.zip) to an easily accessible folder. +If you haven't already, install the `SCP: Secret Laboratory Dedicated Server` through Steam or extract [this zip file](https://ExSLMod-Team.github.io/SL-References/Dev.zip) to an easily accessible folder. #### Windows users Open the Environment Variables menu by searching for `Environment Variables` in the Start Menu. diff --git a/EXILED/docs/articles/installation/automatic/linux.md b/EXILED/docs/articles/installation/automatic/linux.md index d2b4550e2e..d8268593d6 100644 --- a/EXILED/docs/articles/installation/automatic/linux.md +++ b/EXILED/docs/articles/installation/automatic/linux.md @@ -4,7 +4,7 @@ title: Automatic Linux Installation # Automatic Linux Installation -Download `Exiled.Installer-Linux` from [here](https://github.com/ExMod-Team/EXILED/releases). +Download `Exiled.Installer-Linux` from [here](https://github.com/ExSLMod-Team/EXILED/releases). Move it into your **server directory** and run it using `./Exiled.Installer-Linux` - Make sure the server directory is the one where LocalAdmin executable is found. diff --git a/EXILED/docs/articles/installation/automatic/windows.md b/EXILED/docs/articles/installation/automatic/windows.md index 61bc27e7b7..c9e890ea74 100644 --- a/EXILED/docs/articles/installation/automatic/windows.md +++ b/EXILED/docs/articles/installation/automatic/windows.md @@ -4,7 +4,7 @@ title: Automatic Windows Installation # Automatic Windows Installation -Download `Exiled.Installer-Win.exe` from [here](https://github.com/ExMod-Team/EXILED/releases). +Download `Exiled.Installer-Win.exe` from [here](https://github.com/ExSLMod-Team/EXILED/releases). Move it into your **server directory** and double click the .exe. - Make sure the server directory is the one where LocalAdmin.exe is found. diff --git a/EXILED/docs/articles/installation/manual.md b/EXILED/docs/articles/installation/manual.md index 4b38c89fcd..9b8cb7c3d9 100644 --- a/EXILED/docs/articles/installation/manual.md +++ b/EXILED/docs/articles/installation/manual.md @@ -8,7 +8,7 @@ You can download exiled manually following this steps: ### Pick a release -You can select a release inside [our official GitHub repo](https://github.com/ExMod-Team/EXILED/releases/). +You can select a release inside [our official GitHub repo](https://github.com/ExSLMod-Team/EXILED/releases/). ### Download the release diff --git a/EXILED/docs/docfx.json b/EXILED/docs/docfx.json index 4991f54874..8dc6b28e44 100644 --- a/EXILED/docs/docfx.json +++ b/EXILED/docs/docfx.json @@ -27,7 +27,7 @@ "_enableSearch": true, "_lang": "en", "_gitContribute": { - "repo": "https://github.com/ExMod-Team/EXILED", + "repo": "https://github.com/ExSLMod-Team/EXILED", "branch": "dev" } }, diff --git a/EXILED/docs/docs.csproj b/EXILED/docs/docs.csproj index d8e9026b98..f315b6977d 100644 --- a/EXILED/docs/docs.csproj +++ b/EXILED/docs/docs.csproj @@ -35,7 +35,7 @@ - + diff --git a/EXILED/docs/toc.yml b/EXILED/docs/toc.yml index 4e78e3efc1..f3e6ee456a 100644 --- a/EXILED/docs/toc.yml +++ b/EXILED/docs/toc.yml @@ -5,6 +5,4 @@ - name: NW Documentation href: articles/SCPSLRessources/NW_Documentation.html - name: Repository - href: https://github.com/ExMod-Team/EXILED -- name: Plugins - href: https://hub.exiled-team.net/ + href: https://github.com/ExSLMod-Team/EXILED From 26321c625b5ab1f46b81bb561519f7e980bd38f6 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Sun, 8 Jun 2025 16:20:16 +0200 Subject: [PATCH 04/56] fix: Fix staff message wrong target (#542) Update Map.cs --- EXILED/Exiled.API/Features/Map.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs index add2a5123b..f64bf32c95 100644 --- a/EXILED/Exiled.API/Features/Map.cs +++ b/EXILED/Exiled.API/Features/Map.cs @@ -117,13 +117,12 @@ public static bool IsDecontaminationEnabled public static void StaffMessage(string message, Player player = null) { player ??= Server.Host; - foreach (Player target in Player.List) { if (!CommandProcessor.CheckPermissions(target.Sender, PlayerPermissions.AdminChat)) continue; - player.ReferenceHub.encryptedChannelManager.TrySendMessageToClient(player.NetId + "!" + message, EncryptedChannelManager.EncryptedChannel.AdminChat); + target.ReferenceHub.encryptedChannelManager.TrySendMessageToClient(player.NetId + "!" + message, EncryptedChannelManager.EncryptedChannel.AdminChat); } } @@ -420,4 +419,4 @@ internal static void ClearCache() #pragma warning restore CS0618 } } -} +} \ No newline at end of file From c5c886e264879d76a2548578f5f093134f09a5b4 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Sun, 8 Jun 2025 16:20:32 +0200 Subject: [PATCH 05/56] fix: fix being observed calling in reverse (#541) Update BeingObserved.cs --- .../Patches/Events/Scp173/BeingObserved.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs b/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs index 8bb058bf7c..a2c276d9d8 100755 --- a/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs +++ b/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs @@ -7,15 +7,20 @@ namespace Exiled.Events.Patches.Events.Scp173 { + using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; + using API.Features; + using Exiled.API.Features.Pools; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Scp173; using HarmonyLib; + + using PlayerRoles.PlayableScps; using PlayerRoles.PlayableScps.Scp173; using PlayerRoles.Subroutines; @@ -35,13 +40,12 @@ private static IEnumerable Transpiler(IEnumerable x.opcode == OpCodes.Brtrue_S) + offset; - + int offset = 4; + int index = newInstructions.FindIndex(x => x.Calls(PropertyGetter(typeof(VisionInformation), nameof(VisionInformation.IsLooking)))) + offset; newInstructions.InsertRange(index, new CodeInstruction[] { // Player.Get(target) - new(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Ldarg_1).MoveLabelsFrom(newInstructions[index]), new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(ReferenceHub) })), // Player.Get(base.Owner) @@ -78,4 +82,4 @@ private static IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions); } } -} +} \ No newline at end of file From 6760ae1ff1b27008b7c3c368f3426d8c6cf53dc6 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Sun, 8 Jun 2025 16:20:45 +0200 Subject: [PATCH 06/56] fix: CustomKeycard being blank and particle disruptor crashing (#540) customkeycard fix particle disruptor fix --- .../API/Features/CustomKeycard.cs | 3 +-- .../Patches/Events/Scp914/UpgradingPlayer.cs | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomKeycard.cs b/EXILED/Exiled.CustomItems/API/Features/CustomKeycard.cs index d53846cbb0..c7a225a897 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomKeycard.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomKeycard.cs @@ -75,10 +75,9 @@ public override ItemType Type /// public override void Give(Player player, Item item, bool displayMessage = true) { - base.Give(player, item, displayMessage); - if (item.Is(out Keycard card)) SetupKeycard(card); + base.Give(player, item, displayMessage); } /// diff --git a/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradingPlayer.cs b/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradingPlayer.cs index 394fd8815b..cffd499ea9 100644 --- a/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradingPlayer.cs +++ b/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradingPlayer.cs @@ -8,6 +8,7 @@ namespace Exiled.Events.Patches.Events.Scp914 { using System.Collections.Generic; + using System.Reflection; using System.Reflection.Emit; using API.Features; @@ -22,6 +23,7 @@ namespace Exiled.Events.Patches.Events.Scp914 using static HarmonyLib.AccessTools; + using OpCode = System.Reflection.Emit.OpCode; using Scp914 = Handlers.Scp914; /// @@ -112,8 +114,20 @@ private static IEnumerable Transpiler(IEnumerable x.opcode == OpCodes.Stloc_S && x.operand is LocalBuilder { LocalIndex: 10 }) + offset; + // index = newInstructions.FindIndex(x => x.opcode == OpCodes.Stloc_S && x.operand is LocalBuilder { LocalIndex: 10 }) + offset; + ConstructorInfo plugin_api_constructor = typeof(LabApi.Events.Arguments.Scp914Events.Scp914ProcessingInventoryItemEventArgs) + .GetConstructor(new[] + { + typeof(InventorySystem.Items.ItemBase), + typeof(Scp914KnobSetting), + typeof(ReferenceHub), + }); + index = newInstructions.FindIndex(x => x.Is(OpCodes.Newobj, plugin_api_constructor)) + offset; + + // ridtp lcz914 + // noclip + // give tuxwonder7 47 newInstructions.InsertRange( index, new CodeInstruction[] @@ -127,7 +141,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions); } } -} +} \ No newline at end of file From 5f5600d203fc5add5653c3f1d8efa042e7b00303 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Sun, 8 Jun 2025 16:20:57 +0200 Subject: [PATCH 07/56] fix: Fixes spawningItem transpiler (#539) * Update SpawningItem.cs * spacing --- .../Patches/Events/Map/SpawningItem.cs | 55 +++++++++++-------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs index df768a3048..bac813d138 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs @@ -11,18 +11,22 @@ namespace Exiled.Events.Patches.Events.Map using System.Reflection.Emit; using API.Features.Doors; - using API.Features.Pickups; using API.Features.Pools; - using Exiled.Events.Attributes; - using Exiled.Events.EventArgs.Map; - using Handlers; + using Attributes; + + using EventArgs.Map; + using HarmonyLib; + using Interactables.Interobjects.DoorUtils; + using MapGeneration.Distributors; using static HarmonyLib.AccessTools; + using Map = Handlers.Map; + /// /// Patches . /// Adds the event. @@ -40,6 +44,9 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable i.opcode == OpCodes.Ldfld) + offset; + index = newInstructions.FindLastIndex(i => i.LoadsField(Field(typeof(DoorVariantExtension), nameof(DoorVariantExtension.TargetDoor)))) + offset; + + newInstructions[index].WithLabels(allowOriginalLogic); - newInstructions.RemoveRange(index, 2); + int temp_instr = newInstructions.FindLastIndex(i => i.Calls(PropertyGetter(typeof(UnityEngine.Component), nameof(UnityEngine.Component.gameObject)))) - 1; + newInstructions[temp_instr].WithLabels(loadGameObjectLocation); newInstructions.InsertRange(index, new[] { // ev.Door.Base - new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex), + new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex), + new(OpCodes.Brfalse, allowOriginalLogic), + new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(SpawningItemEventArgs), nameof(SpawningItemEventArgs.TriggerDoor))), + new(OpCodes.Brfalse, allowOriginalLogic), + new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex), new(OpCodes.Callvirt, PropertyGetter(typeof(SpawningItemEventArgs), nameof(SpawningItemEventArgs.TriggerDoor))), new(OpCodes.Callvirt, PropertyGetter(typeof(Door), nameof(Door.Base))), + new(OpCodes.Br, loadGameObjectLocation), }); - newInstructions[newInstructions.Count - 1].WithLabels(returnLabel); - for (int z = 0; z < newInstructions.Count; z++) yield return newInstructions[z]; From 8e10d6f8d6701a02eab581fb691d3898700c3f82 Mon Sep 17 00:00:00 2001 From: Yamato Date: Thu, 12 Jun 2025 19:47:35 +0200 Subject: [PATCH 08/56] 14.1.1 TT File Update --- EXILED/Exiled.Loader/AutoUpdateFiles.cs | 2 +- .../SCPSLRessources/NW_Documentation.md | 88 +++++++++++-------- 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/EXILED/Exiled.Loader/AutoUpdateFiles.cs b/EXILED/Exiled.Loader/AutoUpdateFiles.cs index 8490d01eea..4c9d833bc4 100644 --- a/EXILED/Exiled.Loader/AutoUpdateFiles.cs +++ b/EXILED/Exiled.Loader/AutoUpdateFiles.cs @@ -17,6 +17,6 @@ public static class AutoUpdateFiles /// /// Gets which SCP: SL version generated Exiled. /// - public static readonly Version RequiredSCPSLVersion = new(14, 1, 0, 0); + public static readonly Version RequiredSCPSLVersion = new(14, 1, 0, 1); } } \ No newline at end of file diff --git a/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md b/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md index 31ee11803d..bfc0f31671 100644 --- a/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md +++ b/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md @@ -28,7 +28,6 @@ Last Update (14.1.0.0) - [ActionName](#actionname) - [Activity](#activity) - [AdminFlags](#adminflags) -- [AlphaPanelOperations](#alphapaneloperations) - [AnimItemLayer3p](#animitemlayer3p) - [AnimState3p](#animstate3p) - [AttachmentDescriptiveAdvantages](#attachmentdescriptiveadvantages) @@ -119,6 +118,7 @@ Last Update (14.1.0.0) - [ExampleId](#exampleid) - [ExampleId](#exampleid) - [ExplosionType](#explosiontype) +- [ExportPreset](#exportpreset) - [FacilityZone](#facilityzone) - [Faction](#faction) - [FailReason](#failreason) @@ -141,7 +141,6 @@ Last Update (14.1.0.0) - [FreezingMode](#freezingmode) - [FriendlyFireAction](#friendlyfireaction) - [FriendlyFireInteraction](#friendlyfireinteraction) -- [Generator079Operations](#generator079operations) - [GeneratorColliderId](#generatorcolliderid) - [GeneratorFlags](#generatorflags) - [GeoblockingMode](#geoblockingmode) @@ -211,13 +210,16 @@ Last Update (14.1.0.0) - [NtpMode](#ntpmode) - [NullableBoolValue](#nullableboolvalue) - [OpenerEventType](#openereventtype) +- [OptOutExportBehavior](#optoutexportbehavior) - [OpusApplicationType](#opusapplicationtype) - [OpusCtlGetRequest](#opusctlgetrequest) - [OpusCtlSetRequest](#opusctlsetrequest) - [OpusStatusCode](#opusstatuscode) +- [OtherAudioSetting](#otheraudiosetting) - [OtherCondition](#othercondition) - [OutputCodes](#outputcodes) - [PacketProperty](#packetproperty) +- [PanelColliderId](#panelcolliderid) - [ParameterMixingMode](#parametermixingmode) - [ParseResult](#parseresult) - [PDTeleportType](#pdteleporttype) @@ -326,7 +328,6 @@ Last Update (14.1.0.0) - [ValidationError](#validationerror) - [ValidationError](#validationerror) - [VariantType](#varianttype) -- [VcAudioSetting](#vcaudiosetting) - [VcMuteFlags](#vcmuteflags) - [VcPrivacyFlags](#vcprivacyflags) - [VersionType](#versiontype) @@ -486,17 +487,6 @@ Last Update (14.1.0.0)
-### AlphaPanelOperations - -
PlayerInteract+AlphaPanelOperations - -``` - [0] = Cancel - [1] = Lever -``` - -
- ### AnimItemLayer3p
InventorySystem.Items.Thirdperson.AnimItemLayer3p @@ -1894,6 +1884,16 @@ Last Update (14.1.0.0)
+### ExportPreset + +
Metrics.DeathsCollector+ExportPreset + +``` + [0] = DeathReasons +``` + +
+ ### FacilityZone
MapGeneration.FacilityZone @@ -2197,18 +2197,6 @@ Last Update (14.1.0.0)
-### Generator079Operations - -
PlayerInteract+Generator079Operations - -``` - [0] = Door - [1] = Tablet - [2] = Cancel -``` - -
- ### GeneratorColliderId
MapGeneration.Distributors.Scp079Generator+GeneratorColliderId @@ -2346,6 +2334,7 @@ Last Update (14.1.0.0) [16] = PackedULong [17] = Scp330Hint [18] = SSKeybind + [19] = AnimationCurve ```
@@ -3331,6 +3320,18 @@ Last Update (14.1.0.0)
+### OptOutExportBehavior + +
Metrics.ScpPreferencesCollector+OptOutExportBehavior + +``` + [0] = Include + [1] = Exclude + [2] = TreatAsZero +``` + +
+ ### OpusApplicationType
VoiceChat.Codec.Enums.OpusApplicationType @@ -3410,6 +3411,18 @@ Last Update (14.1.0.0)
+### OtherAudioSetting + +
UserSettings.AudioSettings.OtherAudioSetting + +``` + [0] = NoiseReduction + [1] = ProxVcReverbIntensity + [2] = SpatialAnnouncements +``` + +
+ ### OtherCondition
InventorySystem.Items.Firearms.Extensions.ConditionalEvaluator+OtherCondition @@ -3467,6 +3480,17 @@ Last Update (14.1.0.0)
+### PanelColliderId + +
AlphaWarheadNukesitePanel+PanelColliderId + +``` + [1] = Cancel + [2] = Lever +``` + +
+ ### ParameterMixingMode
InventorySystem.Items.Firearms.Attachments.ParameterMixingMode @@ -3641,6 +3665,7 @@ Last Update (14.1.0.0) [134217728] = FriendlyFireDetectorImmunity [268435456] = FriendlyFireDetectorTempDisable [536870912] = ServerLogLiveFeed + [1073741824] = ExecuteAs ```
@@ -3860,6 +3885,7 @@ Last Update (14.1.0.0) [1] = ConfirmThrowWeak [2] = ConfirmThrowFullForce [3] = CancelThrow + [4] = ForceCancel ``` @@ -5346,16 +5372,6 @@ Last Update (14.1.0.0) -### VcAudioSetting - -
UserSettings.AudioSettings.VcAudioSetting - -``` - [0] = NoiseReduction -``` - -
- ### VcMuteFlags
VoiceChat.VcMuteFlags From 4c53c0b3ed4d300cfb31fff9248d40b6276dba93 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Thu, 12 Jun 2025 20:02:53 +0200 Subject: [PATCH 09/56] Some fixes --- EXILED/EXILED.props | 2 +- .../Features/Core/UserSettings/KeybindSetting.cs | 14 ++++++++++++-- EXILED/Exiled.API/Features/Player.cs | 11 ++++++++--- .../Patches/Events/Player/Interacted.cs | 9 ++++----- .../Patches/Events/Warhead/ChangingLeverStatus.cs | 7 ++++--- 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/EXILED/EXILED.props b/EXILED/EXILED.props index eefc8a1140..6ff3aa50c2 100644 --- a/EXILED/EXILED.props +++ b/EXILED/EXILED.props @@ -15,7 +15,7 @@ - 9.6.0 + 9.6.1 false diff --git a/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs b/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs index cfb6b3bbca..a86f3269f2 100644 --- a/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs +++ b/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs @@ -25,11 +25,12 @@ public class KeybindSetting : SettingBase, IWrapper /// /// /// + /// /// /// /// - public KeybindSetting(int id, string label, KeyCode suggested, bool preventInteractionOnGUI = false, string hintDescription = "", HeaderSetting header = null, Action onChanged = null) - : base(new SSKeybindSetting(id, label, suggested, preventInteractionOnGUI, hintDescription), header, onChanged) + public KeybindSetting(int id, string label, KeyCode suggested, bool preventInteractionOnGUI = false, bool allowSpectatorTrigger = false, string hintDescription = "", HeaderSetting header = null, Action onChanged = null) + : base(new SSKeybindSetting(id, label, suggested, preventInteractionOnGUI, allowSpectatorTrigger, hintDescription), header, onChanged) { Base = (SSKeybindSetting)base.Base; } @@ -61,6 +62,15 @@ public bool PreventInteractionOnGUI set => Base.PreventInteractionOnGUI = value; } + /// + /// Gets or sets a value indicating whether the interaction is prevented in spectator roles. + /// + public bool AllowSpectatorTrigger + { + get => Base.AllowSpectatorTrigger; + set => Base.AllowSpectatorTrigger = value; + } + /// /// Gets or sets the assigned key. /// diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 4dfcf09409..6bb4124324 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -1163,6 +1163,11 @@ public bool IsSpawnProtected ///
protected HealthStat CustomHealthStat { get; set; } + /// + /// Gets or sets a . + /// + protected FpcScaleController ScaleController { get; set; } + /// /// Converts LabApi player to EXILED player. /// @@ -2072,7 +2077,7 @@ public void SetScale(Vector3 scale, IEnumerable viewers) try { - ReferenceHub.transform.localScale = scale; + ScaleController.Scale = scale; foreach (Player target in viewers) Server.SendSpawnMessage?.Invoke(null, new object[] { NetworkIdentity, target.Connection }); @@ -2094,12 +2099,12 @@ public void SetFakeScale(Vector3 fakeScale, IEnumerable viewers) try { - ReferenceHub.transform.localScale = fakeScale; + ScaleController.Scale = fakeScale; foreach (Player target in viewers) Server.SendSpawnMessage.Invoke(null, new object[] { NetworkIdentity, target.Connection }); - ReferenceHub.transform.localScale = currentScale; + ScaleController.Scale = currentScale; } catch (Exception ex) { diff --git a/EXILED/Exiled.Events/Patches/Events/Player/Interacted.cs b/EXILED/Exiled.Events/Patches/Events/Player/Interacted.cs index 1b5a21c170..3c6c6e7f30 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/Interacted.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/Interacted.cs @@ -14,19 +14,18 @@ namespace Exiled.Events.Patches.Events.Player using API.Features.Pools; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Player; - using HarmonyLib; - + using Interactables; using UnityEngine; using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.Interacted))] - [HarmonyPatch(typeof(PlayerInteract), nameof(PlayerInteract.OnInteract))] + [HarmonyPatch(typeof(InteractionCoordinator), nameof(InteractionCoordinator.ClientInteract))] internal static class Interacted { private static IEnumerable Transpiler(IEnumerable instructions) @@ -39,7 +38,7 @@ private static IEnumerable Transpiler(IEnumerable event. ///
[EventPatch(typeof(Warhead), nameof(Warhead.ChangingLeverStatus))] - [HarmonyPatch(typeof(PlayerInteract), nameof(PlayerInteract.UserCode_CmdUsePanel__AlphaPanelOperations))] + + // [HarmonyPatch(typeof(PlayerInteract), nameof(PlayerInteract.UserCode_CmdUsePanel__AlphaPanelOperations))] internal static class ChangingLeverStatus { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + /*private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); @@ -72,6 +73,6 @@ private static IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions); - } + }*/ } } \ No newline at end of file From 2e34c4b6f393dc047a42549eddd0e1be51ef634f Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:04:04 +0900 Subject: [PATCH 10/56] fix: player.MessageTranslated kick players (#545) fix player.MessageTranslated kick players --- EXILED/Exiled.API/Extensions/MirrorExtensions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs index 3244663a3e..1ab332af2a 100644 --- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs +++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs @@ -367,10 +367,11 @@ public static void PlayCassieAnnouncement(this Player player, string words, bool /// Target to send. /// The message to be reproduced. /// The translation should be show in the subtitles. + /// The custom subtitles to show. /// Same on 's isHeld. /// Same on 's isNoisy. /// Same on 's isSubtitles. - public static void MessageTranslated(this Player player, string words, string translation, bool makeHold = false, bool makeNoise = true, bool isSubtitles = true) + public static void MessageTranslated(this Player player, string words, string translation, string customSubtitles, bool makeHold = false, bool makeNoise = true, bool isSubtitles = true) { StringBuilder announcement = StringBuilderPool.Pool.Get(); @@ -386,7 +387,7 @@ public static void MessageTranslated(this Player player, string words, string tr { if (controller != null) { - SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), message, makeHold, makeNoise, isSubtitles); + SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), message, makeHold, makeNoise, isSubtitles, customSubtitles); } } } From c86ff0448b1d15d8121e921b67f096562b592dd6 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Fri, 13 Jun 2025 00:13:13 +0200 Subject: [PATCH 11/56] Update workflows --- .github/workflows/dev.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index ab7b2d0556..7ee77d48a0 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -16,9 +16,9 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/Dev.zip + EXILED_REFERENCES_URL: https://exmod-team.github.io/SL-References/Dev.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References - EXILED_DLL_ARCHIVER_URL: https://github.com/ExSLMod-Team/EXILED-DLL-Archiver/releases/latest/download/EXILED-DLL-Archiver.exe + EXILED_DLL_ARCHIVER_URL: https://github.com/ExMod-Team/EXILED-DLL-Archiver/releases/latest/download/EXILED-DLL-Archiver.exe jobs: From d44bedf7661800c18b027d6426f24dfeb35ae5fd Mon Sep 17 00:00:00 2001 From: "@Someone" <45270312+Someone-193@users.noreply.github.com> Date: Thu, 12 Jun 2025 19:05:06 -0400 Subject: [PATCH 12/56] fix: KeybindSetting and RoundEnd transpiler (#546) * fix KeybindSetting and RoundEnd transpiler I think it all works, I ran server and no errors, I got on and ended round and no errors * Fix Scale (ScaleController is mid) Fix ChangingLeverStatus event I think these work --- .../Core/UserSettings/KeybindSetting.cs | 17 +++++++++++++++++ EXILED/Exiled.API/Features/Player.cs | 11 +++-------- .../Patches/Events/Server/RoundEnd.cs | 4 ++-- .../Events/Warhead/ChangingLeverStatus.cs | 15 +++++++-------- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs b/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs index a86f3269f2..9fc693b7ee 100644 --- a/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs +++ b/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs @@ -18,6 +18,23 @@ namespace Exiled.API.Features.Core.UserSettings ///
public class KeybindSetting : SettingBase, IWrapper { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + [Obsolete("This method will be removed next major version because of a new feature. Use the constructor with \"allowSpectator\" instead.")] + public KeybindSetting(int id, string label, KeyCode suggested, bool preventInteractionOnGUI, string hintDescription, HeaderSetting header, Action onChanged) + : base(new SSKeybindSetting(id, label, suggested, preventInteractionOnGUI, false, hintDescription), header, onChanged) + { + Base = (SSKeybindSetting)base.Base; + } + /// /// Initializes a new instance of the class. /// diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 6bb4124324..4dfcf09409 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -1163,11 +1163,6 @@ public bool IsSpawnProtected ///
protected HealthStat CustomHealthStat { get; set; } - /// - /// Gets or sets a . - /// - protected FpcScaleController ScaleController { get; set; } - /// /// Converts LabApi player to EXILED player. /// @@ -2077,7 +2072,7 @@ public void SetScale(Vector3 scale, IEnumerable viewers) try { - ScaleController.Scale = scale; + ReferenceHub.transform.localScale = scale; foreach (Player target in viewers) Server.SendSpawnMessage?.Invoke(null, new object[] { NetworkIdentity, target.Connection }); @@ -2099,12 +2094,12 @@ public void SetFakeScale(Vector3 fakeScale, IEnumerable viewers) try { - ScaleController.Scale = fakeScale; + ReferenceHub.transform.localScale = fakeScale; foreach (Player target in viewers) Server.SendSpawnMessage.Invoke(null, new object[] { NetworkIdentity, target.Connection }); - ScaleController.Scale = currentScale; + ReferenceHub.transform.localScale = currentScale; } catch (Exception ex) { diff --git a/EXILED/Exiled.Events/Patches/Events/Server/RoundEnd.cs b/EXILED/Exiled.Events/Patches/Events/Server/RoundEnd.cs index 65a9abf52a..fba037de79 100644 --- a/EXILED/Exiled.Events/Patches/Events/Server/RoundEnd.cs +++ b/EXILED/Exiled.Events/Patches/Events/Server/RoundEnd.cs @@ -66,8 +66,8 @@ private static IEnumerable Transpiler(IEnumerable), nameof(HashSet.Contains))), + new(OpCodes.Ldloc_S, 20), + new(OpCodes.Callvirt, Method(typeof(HashSet), nameof(HashSet.Contains))), new(OpCodes.Brtrue_S, jmp), }); diff --git a/EXILED/Exiled.Events/Patches/Events/Warhead/ChangingLeverStatus.cs b/EXILED/Exiled.Events/Patches/Events/Warhead/ChangingLeverStatus.cs index 02596adcbc..bbcdd724e7 100644 --- a/EXILED/Exiled.Events/Patches/Events/Warhead/ChangingLeverStatus.cs +++ b/EXILED/Exiled.Events/Patches/Events/Warhead/ChangingLeverStatus.cs @@ -22,33 +22,32 @@ namespace Exiled.Events.Patches.Events.Warhead using Warhead = Handlers.Warhead; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Warhead), nameof(Warhead.ChangingLeverStatus))] - // [HarmonyPatch(typeof(PlayerInteract), nameof(PlayerInteract.UserCode_CmdUsePanel__AlphaPanelOperations))] + [HarmonyPatch(typeof(AlphaWarheadNukesitePanel), nameof(AlphaWarheadNukesitePanel.ServerInteract))] internal static class ChangingLeverStatus { - /*private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); Label returnLabel = generator.DefineLabel(); - int offset = 2; - int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Brtrue_S) + offset; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Call); newInstructions.InsertRange( index, new[] { // Player.Get(component) - new CodeInstruction(OpCodes.Ldloc_0).MoveLabelsFrom(newInstructions[index]), + new CodeInstruction(OpCodes.Ldarg_1).MoveLabelsFrom(newInstructions[index]), new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), // nukeside.Networkenabled - new(OpCodes.Ldloc_1), + new(OpCodes.Ldarg_0), new(OpCodes.Call, PropertyGetter(typeof(AlphaWarheadNukesitePanel), nameof(AlphaWarheadNukesitePanel.Networkenabled))), // true @@ -73,6 +72,6 @@ internal static class ChangingLeverStatus yield return newInstructions[z]; ListPool.Pool.Return(newInstructions); - }*/ + } } } \ No newline at end of file From d9a0896d126fad7ddd7e9831e1603c9c160e31b5 Mon Sep 17 00:00:00 2001 From: x3rt Date: Thu, 12 Jun 2025 21:43:42 -0600 Subject: [PATCH 13/56] Fix DroppedItem Event (#548) Fix dropping/dropped item event --- EXILED/Exiled.Events/Patches/Events/Player/DroppingItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EXILED/Exiled.Events/Patches/Events/Player/DroppingItem.cs b/EXILED/Exiled.Events/Patches/Events/Player/DroppingItem.cs index d10d6cb2dd..f5802d2a84 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/DroppingItem.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/DroppingItem.cs @@ -107,7 +107,7 @@ private static IEnumerable Transpiler(IEnumerable i.opcode == OpCodes.Stloc_1) + offset; + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Stloc_2) + offset; newInstructions.InsertRange(index, new CodeInstruction[] { @@ -116,7 +116,7 @@ private static IEnumerable Transpiler(IEnumerable Date: Fri, 13 Jun 2025 02:40:52 -0600 Subject: [PATCH 14/56] Fix door interaction patch --- EXILED/Exiled.Events/Patches/Events/Player/InteractingDoor.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/EXILED/Exiled.Events/Patches/Events/Player/InteractingDoor.cs b/EXILED/Exiled.Events/Patches/Events/Player/InteractingDoor.cs index dcdb2911f3..ddd406ac1f 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/InteractingDoor.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/InteractingDoor.cs @@ -55,10 +55,6 @@ private static IEnumerable Transpiler(IEnumerable Date: Fri, 13 Jun 2025 11:30:39 +0200 Subject: [PATCH 15/56] fix: Update repository URLs to reflect team name change (#552) --- .github/workflows/docs.yml | 2 +- .github/workflows/labapi.yml | 74 ------------------- .github/workflows/main.yml | 2 +- .github/workflows/push_nuget.yml | 2 +- .github/workflows/release.yml | 4 +- EXILED/EXILED.props | 4 +- .../Features/DatabaseHandler.cs | 2 +- EXILED/Exiled.Installer/README.md | 4 +- EXILED/Exiled.Loader/Updater.cs | 2 +- EXILED/Exiled/Exiled.nuspec | 6 +- EXILED/docs/articles/contributing/index.md | 4 +- .../articles/installation/automatic/linux.md | 2 +- .../installation/automatic/windows.md | 2 +- EXILED/docs/articles/installation/manual.md | 2 +- EXILED/docs/docfx.json | 2 +- EXILED/docs/toc.yml | 2 +- 16 files changed, 21 insertions(+), 95 deletions(-) delete mode 100644 .github/workflows/labapi.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 728da76f7f..d23c64887c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,7 +12,7 @@ permissions: id-token: write env: - EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/Master.zip + EXILED_REFERENCES_URL: https://Exmod-team.github.io/SL-References/Master.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. diff --git a/.github/workflows/labapi.yml b/.github/workflows/labapi.yml deleted file mode 100644 index 69cb71f0aa..0000000000 --- a/.github/workflows/labapi.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Exiled Dev CI - -on: - push: - branches: - - LabAPI - pull_request: - branches: - - LabAPI - workflow_dispatch: - -defaults: - run: - working-directory: ./EXILED - -env: - EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/LabAPI.zip - EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References - EXILED_DLL_ARCHIVER_URL: https://github.com/ExSLMod-Team/EXILED-DLL-Archiver/releases/download/v1.8.2/EXILED-DLL-Archiver.exe - -jobs: - - build: - - runs-on: windows-latest - # Prevent double running for push & pull_request events from the main repo - if: github.event_name != 'push' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name - - steps: - - - name: Setup .NET Core SDK - uses: actions/setup-dotnet@v4.0.1 - - - name: Setup Nuget - uses: nuget/setup-nuget@v2 - - - uses: actions/checkout@v4.1.7 - - - name: Get references - shell: pwsh - run: | - Invoke-WebRequest -Uri ${{ env.EXILED_REFERENCES_URL }} -OutFile ${{ github.workspace }}/EXILED/References.zip - Expand-Archive -Path References.zip -DestinationPath ${{ env.EXILED_REFERENCES_PATH }} - - - name: Build - env: - EXILED_REFERENCES: ${{ env.EXILED_REFERENCES_PATH }} - shell: pwsh - run: | - ./build.ps1 -BuildNuGet - $File = (Get-ChildItem -Path . -Include 'ExMod.Exiled.*.nupkg' -Recurse).Name - Out-File -FilePath ${{ github.env }} -InputObject "PackageFile=$File" -Encoding utf-8 -Append - - - name: Upload nuget package - uses: actions/upload-artifact@v4 - with: - name: ${{ env.PackageFile }} - path: EXILED/${{ env.PackageFile }} - - - name: Get references - shell: pwsh - run: | - Invoke-WebRequest -Uri ${{ env.EXILED_DLL_ARCHIVER_URL }} -OutFile ${{ github.workspace }}/EXILED/EXILED-DLL-Archiver.exe - - - name: Packaging results as tar.gz - shell: pwsh - run: ./packaging.ps1 - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: Build Result - path: EXILED/bin/Release/Exiled.tar.gz - diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 576a58f46b..0789a2649d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/Master.zip + EXILED_REFERENCES_URL: https://Exmod-team.github.io/SL-References/Master.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References jobs: diff --git a/.github/workflows/push_nuget.yml b/.github/workflows/push_nuget.yml index 29175ffee8..ea82f96926 100644 --- a/.github/workflows/push_nuget.yml +++ b/.github/workflows/push_nuget.yml @@ -10,7 +10,7 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/LabAPI.zip + EXILED_REFERENCES_URL: https://exmod-team.github.io/SL-References/Dev.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References jobs: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b1b16ee05..b7c930b5e1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,9 +11,9 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://exslmod-team.github.io/SL-References/LabAPI.zip + EXILED_REFERENCES_URL: https://Exmod-team.github.io/SL-References/Dev.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References - EXILED_DLL_ARCHIVER_URL: https://github.com/ExSLMod-Team/EXILED-DLL-Archiver/releases/download/v1.8.1/EXILED-DLL-Archiver.exe + EXILED_DLL_ARCHIVER_URL: https://github.com/Exmod-Team/EXILED-DLL-Archiver/releases/download/v1.8.1/EXILED-DLL-Archiver.exe jobs: build: diff --git a/EXILED/EXILED.props b/EXILED/EXILED.props index 6ff3aa50c2..a4e5a63b69 100644 --- a/EXILED/EXILED.props +++ b/EXILED/EXILED.props @@ -25,8 +25,8 @@ Copyright © $(Authors) 2020 - $([System.DateTime]::Now.ToString("yyyy")) Git - https://github.com/ExSLMod-Team/EXILED - https://github.com/ExSLMod-Team/EXILED + https://github.com/Exmod-Team/EXILED + https://github.com/Exmod-Team/EXILED CC-BY-SA-3.0 $(DefineConstants);PUBLIC_BETA diff --git a/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs b/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs index c2ec515742..ac3cc91781 100644 --- a/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs +++ b/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs @@ -17,7 +17,7 @@ namespace Exiled.CreditTags.Features public static class DatabaseHandler { - private const string Url = "https://raw.githubusercontent.com/ExSLMod-Team/CreditTags/main/data.yml"; + private const string Url = "https://raw.githubusercontent.com/Exmod-Team/CreditTags/main/data.yml"; private const string ETagCacheFileName = "etag_cache.txt"; private const string DatabaseCacheFileName = "data.yml"; private const int CacheTimeInMinutes = 5; diff --git a/EXILED/Exiled.Installer/README.md b/EXILED/Exiled.Installer/README.md index c2033165c2..ad658da899 100644 --- a/EXILED/Exiled.Installer/README.md +++ b/EXILED/Exiled.Installer/README.md @@ -43,7 +43,7 @@ Trying to find release.. Release found! PRE: True | ID: 87710626 | TAG: 6.0.0-beta.18 Asset found! -ID: 90263995 | NAME: Exiled.tar.gz | SIZE: 1027928 | URL: https://api.github.com/repos/ExSLMod-Team/Exiled-EA/releases/assets/90263995 | DownloadURL: https://github.com/ExSLMod-Team/Exiled-EA/releases/download/6.0.0-beta.18/Exiled.tar.gz +ID: 90263995 | NAME: Exiled.tar.gz | SIZE: 1027928 | URL: https://api.github.com/repos/Exmod-Team/Exiled-EA/releases/assets/90263995 | DownloadURL: https://github.com/Exmod-Team/Exiled-EA/releases/download/6.0.0-beta.18/Exiled.tar.gz Processing 'EXILED/Plugins/dependencies/0Harmony.dll' Extracting '0Harmony.dll' into 'YourAppDataPath/EXILED/Plugins/dependencies/0Harmony.dll'... Processing 'EXILED/Plugins/dependencies/Exiled.API.dll' @@ -88,7 +88,7 @@ Trying to find release.. Release found! PRE: False | ID: 87710626 | TAG: 6.0.0-beta.18 Asset found! -ID: 90263995 | NAME: Exiled.tar.gz | SIZE: 1027928 | URL: https://api.github.com/repos/ExSLMod-Team/Exiled-EA/releases/assets/90263995 | DownloadURL: https://github.com/ExSLMod-Team/Exiled-EA/releases/download/6.0.0-beta.18/Exiled.tar.gz +ID: 90263995 | NAME: Exiled.tar.gz | SIZE: 1027928 | URL: https://api.github.com/repos/Exmod-Team/Exiled-EA/releases/assets/90263995 | DownloadURL: https://github.com/Exmod-Team/Exiled-EA/releases/download/6.0.0-beta.18/Exiled.tar.gz Processing 'EXILED/Plugins/dependencies/0Harmony.dll' Extracting '0Harmony.dll' into '/user/SCP/EXILED/Plugins/dependencies/0Harmony.dll'... Processing 'EXILED/Plugins/dependencies/Exiled.API.dll' diff --git a/EXILED/Exiled.Loader/Updater.cs b/EXILED/Exiled.Loader/Updater.cs index a90f0589b0..0c70548bb4 100644 --- a/EXILED/Exiled.Loader/Updater.cs +++ b/EXILED/Exiled.Loader/Updater.cs @@ -136,7 +136,7 @@ private HttpClient CreateHttpClient() Timeout = TimeSpan.FromSeconds(480), }; - client.DefaultRequestHeaders.Add("User-Agent", $"Exiled.Loader (https://github.com/ExSLMod-Team/EXILED, {Assembly.GetExecutingAssembly().GetName().Version.ToString(3)})"); + client.DefaultRequestHeaders.Add("User-Agent", $"Exiled.Loader (https://github.com/Exmod-Team/EXILED, {Assembly.GetExecutingAssembly().GetName().Version.ToString(3)})"); return client; } diff --git a/EXILED/Exiled/Exiled.nuspec b/EXILED/Exiled/Exiled.nuspec index cf95b0fbc8..431aa120ee 100644 --- a/EXILED/Exiled/Exiled.nuspec +++ b/EXILED/Exiled/Exiled.nuspec @@ -9,9 +9,9 @@ ExMod-Team Copyright © ExMod Team 2024 - $year$ false - - https://github.com/ExSLMod-Team/EXILED/blob/master/LICENSE - https://github.com/ExSLMod-Team/EXILED + + https://github.com/Exmod-Team/EXILED/blob/master/LICENSE + https://github.com/Exmod-Team/EXILED images\Exiled_Icon.png Plugin framework for SCP: Secret Laboratory. diff --git a/EXILED/docs/articles/contributing/index.md b/EXILED/docs/articles/contributing/index.md index fdcec6d5a0..b97036c9c0 100644 --- a/EXILED/docs/articles/contributing/index.md +++ b/EXILED/docs/articles/contributing/index.md @@ -6,7 +6,7 @@ title: Contributing to EXILED This is a simple tutorial guiding you to contribute to our framework. ### Forking EXILED -First, create a fork of our [GitHub repository](https://github.com/ExSLMod-Team/EXILED). +First, create a fork of our [GitHub repository](https://github.com/Exmod-Team/EXILED). Then, clone it to your computer like so: `git clone https://github.com/your-username/EXILED.git` @@ -14,7 +14,7 @@ Open a terminal in your forked EXILED folder and run ```git checkout dev```. Thi ### Setting `EXILED_REFERENCES` -If you haven't already, install the `SCP: Secret Laboratory Dedicated Server` through Steam or extract [this zip file](https://ExSLMod-Team.github.io/SL-References/Dev.zip) to an easily accessible folder. +If you haven't already, install the `SCP: Secret Laboratory Dedicated Server` through Steam or extract [this zip file](https://Exmod-Team.github.io/SL-References/Dev.zip) to an easily accessible folder. #### Windows users Open the Environment Variables menu by searching for `Environment Variables` in the Start Menu. diff --git a/EXILED/docs/articles/installation/automatic/linux.md b/EXILED/docs/articles/installation/automatic/linux.md index d8268593d6..e88fec515b 100644 --- a/EXILED/docs/articles/installation/automatic/linux.md +++ b/EXILED/docs/articles/installation/automatic/linux.md @@ -4,7 +4,7 @@ title: Automatic Linux Installation # Automatic Linux Installation -Download `Exiled.Installer-Linux` from [here](https://github.com/ExSLMod-Team/EXILED/releases). +Download `Exiled.Installer-Linux` from [here](https://github.com/Exmod-Team/EXILED/releases). Move it into your **server directory** and run it using `./Exiled.Installer-Linux` - Make sure the server directory is the one where LocalAdmin executable is found. diff --git a/EXILED/docs/articles/installation/automatic/windows.md b/EXILED/docs/articles/installation/automatic/windows.md index c9e890ea74..90126907c3 100644 --- a/EXILED/docs/articles/installation/automatic/windows.md +++ b/EXILED/docs/articles/installation/automatic/windows.md @@ -4,7 +4,7 @@ title: Automatic Windows Installation # Automatic Windows Installation -Download `Exiled.Installer-Win.exe` from [here](https://github.com/ExSLMod-Team/EXILED/releases). +Download `Exiled.Installer-Win.exe` from [here](https://github.com/Exmod-Team/EXILED/releases). Move it into your **server directory** and double click the .exe. - Make sure the server directory is the one where LocalAdmin.exe is found. diff --git a/EXILED/docs/articles/installation/manual.md b/EXILED/docs/articles/installation/manual.md index 9b8cb7c3d9..994aee045e 100644 --- a/EXILED/docs/articles/installation/manual.md +++ b/EXILED/docs/articles/installation/manual.md @@ -8,7 +8,7 @@ You can download exiled manually following this steps: ### Pick a release -You can select a release inside [our official GitHub repo](https://github.com/ExSLMod-Team/EXILED/releases/). +You can select a release inside [our official GitHub repo](https://github.com/Exmod-Team/EXILED/releases/). ### Download the release diff --git a/EXILED/docs/docfx.json b/EXILED/docs/docfx.json index 8dc6b28e44..872a0ab23d 100644 --- a/EXILED/docs/docfx.json +++ b/EXILED/docs/docfx.json @@ -27,7 +27,7 @@ "_enableSearch": true, "_lang": "en", "_gitContribute": { - "repo": "https://github.com/ExSLMod-Team/EXILED", + "repo": "https://github.com/Exmod-Team/EXILED", "branch": "dev" } }, diff --git a/EXILED/docs/toc.yml b/EXILED/docs/toc.yml index f3e6ee456a..eb1be93595 100644 --- a/EXILED/docs/toc.yml +++ b/EXILED/docs/toc.yml @@ -5,4 +5,4 @@ - name: NW Documentation href: articles/SCPSLRessources/NW_Documentation.html - name: Repository - href: https://github.com/ExSLMod-Team/EXILED + href: https://github.com/Exmod-Team/EXILED From 06b97afe3c863471c9c62887522b0720ad1defa0 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Fri, 13 Jun 2025 12:02:56 +0200 Subject: [PATCH 16/56] fix: Update RepoID to reflect new repository identifier --- EXILED/Exiled.Installer/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXILED/Exiled.Installer/Program.cs b/EXILED/Exiled.Installer/Program.cs index 8b9c39c7e8..c7a43a2dcd 100644 --- a/EXILED/Exiled.Installer/Program.cs +++ b/EXILED/Exiled.Installer/Program.cs @@ -42,7 +42,7 @@ internal enum PathResolution internal static class Program { - private const long RepoID = 984817990; + private const long RepoID = 833723500; private const string ExiledAssetName = "exiled.tar.gz"; // This is the lowest version the installer will check to install From f9f3656365bb6a19567597272a77664389cf98a8 Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Thu, 19 Jun 2025 00:12:30 +0300 Subject: [PATCH 17/56] fix: Critical CustomRole api Error & Invalid ragdoll error (#560) * Added Safety Checks * Added SpawningRagdoll event for Safety Checks * Added Safety Checks * Simplfy * Simplfy --- EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs | 2 +- EXILED/Exiled.Events/Events.cs | 4 +++- EXILED/Exiled.Events/Handlers/Internal/Round.cs | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index ba6ecc95f8..ffb364760e 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -936,7 +936,7 @@ private void OnInternalChangingRole(ChangingRoleEventArgs ev) private void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { - if (Check(ev.Player)) + if (Check(ev.Player) && !Role.IsDead() && Role != RoleTypeId.Scp079) ev.Role = Role; } diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index 103ba58829..80173fa27a 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -68,6 +68,7 @@ public override void OnEnabled() 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; Handlers.Map.ChangedIntoGrenade += Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; @@ -105,6 +106,7 @@ public override void OnDisabled() 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; Handlers.Map.ChangedIntoGrenade -= Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; @@ -161,4 +163,4 @@ public void Unpatch() Log.Debug("All events have been unpatched complete. Goodbye!"); } } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 99212af062..7df3f63007 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -82,6 +82,13 @@ public static void OnChangingRole(ChangingRoleEventArgs ev) ev.Player.Inventory.ServerDropEverything(); } + /// + public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) + { + if (ev.Role.IsDead() || ev.Role == RoleTypeId.Scp079) + ev.IsAllowed = false; + } + /// public static void OnActivatingSense(ActivatingSenseEventArgs ev) { From 5a55e62083024b04fd5f40f8a095d7a41fcd23b2 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Thu, 19 Jun 2025 09:59:11 +0200 Subject: [PATCH 18/56] fix: Update spawning logic to use IsFpcRole for role validation (#573) fix: Update spawning logic to use IsFpcRole for role vdation --- EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs | 2 +- EXILED/Exiled.Events/Handlers/Internal/Round.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index ffb364760e..97790a3e24 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -936,7 +936,7 @@ private void OnInternalChangingRole(ChangingRoleEventArgs ev) private void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { - if (Check(ev.Player) && !Role.IsDead() && Role != RoleTypeId.Scp079) + if (Check(ev.Player) && Role.IsFpcRole()) ev.Role = Role; } diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 7df3f63007..ae8dbb5b4e 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -85,7 +85,7 @@ public static void OnChangingRole(ChangingRoleEventArgs ev) /// public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { - if (ev.Role.IsDead() || ev.Role == RoleTypeId.Scp079) + if (ev.Role.IsDead() || ev.Role.IsFpcRole()) ev.IsAllowed = false; } From 23ae2fdbd1d857fbc48519d27cfdddf3ee0d6b58 Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Thu, 19 Jun 2025 17:01:51 +0900 Subject: [PATCH 19/56] fix: DoorType.Scp173NewGate is DoorType.Scp049Gate (#569) Update Door.cs --- EXILED/Exiled.API/Features/Doors/Door.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXILED/Exiled.API/Features/Doors/Door.cs b/EXILED/Exiled.API/Features/Doors/Door.cs index c2cea9a761..22b0915132 100644 --- a/EXILED/Exiled.API/Features/Doors/Door.cs +++ b/EXILED/Exiled.API/Features/Doors/Door.cs @@ -600,7 +600,7 @@ private DoorType GetDoorType() { RoomType.EzCheckpointHallwayA => DoorType.CheckpointGateA, RoomType.EzCheckpointHallwayB => DoorType.CheckpointGateB, - RoomType.Hcz049 => Position.y < -805 ? DoorType.Scp049Gate : DoorType.Scp173NewGate, + RoomType.Hcz049 => Position.y < -10 ? DoorType.Scp049Gate : DoorType.Scp173NewGate, _ => DoorType.UnknownGate, }, "Elevator Door" or "Nuke Elevator Door" or "Elevator Door 02" => (Base as Interactables.Interobjects.ElevatorDoor)?.Group switch From e38d4b628a14e17acb197a0ab9c04ad8188fd6fd Mon Sep 17 00:00:00 2001 From: Naxefir <143349993+NaxefirYT@users.noreply.github.com> Date: Thu, 19 Jun 2025 11:02:20 +0300 Subject: [PATCH 20/56] fix: RemainingDecontaminationTime is wrong (#572) Update Map.cs --- EXILED/Exiled.API/Features/Map.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs index f64bf32c95..7bd9a19193 100644 --- a/EXILED/Exiled.API/Features/Map.cs +++ b/EXILED/Exiled.API/Features/Map.cs @@ -67,7 +67,7 @@ DecontaminationController.Singleton.NetworkDecontaminationOverride is Decontamin /// /// The remaining time in seconds for the decontamination process. /// - public static float RemainingDecontaminationTime => Mathf.Min(0, (float)(DecontaminationController.Singleton.DecontaminationPhases[DecontaminationController.Singleton.DecontaminationPhases.Length - 1].TimeTrigger - DecontaminationController.GetServerTime)); + public static float RemainingDecontaminationTime => Mathf.Max(0, (float)(DecontaminationController.Singleton.DecontaminationPhases[DecontaminationController.Singleton.DecontaminationPhases.Length - 1].TimeTrigger - DecontaminationController.GetServerTime)); /// /// Gets all objects. @@ -419,4 +419,4 @@ internal static void ClearCache() #pragma warning restore CS0618 } } -} \ No newline at end of file +} From 4ee1686d9ddd0448d49ac821929117e151a3e5e0 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Thu, 19 Jun 2025 10:13:12 +0200 Subject: [PATCH 21/56] fix: Correct role validation logic in spawning events --- EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs | 2 +- EXILED/Exiled.Events/Handlers/Internal/Round.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 97790a3e24..8e1620730f 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -936,7 +936,7 @@ private void OnInternalChangingRole(ChangingRoleEventArgs ev) private void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { - if (Check(ev.Player) && Role.IsFpcRole()) + if (Check(ev.Player) && !Role.IsFpcRole()) ev.Role = Role; } diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index ae8dbb5b4e..f81b0886b9 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -85,7 +85,7 @@ public static void OnChangingRole(ChangingRoleEventArgs ev) /// public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { - if (ev.Role.IsDead() || ev.Role.IsFpcRole()) + if (ev.Role.IsDead() || !ev.Role.IsFpcRole()) ev.IsAllowed = false; } From 6650b959fb1c230da3bf9b6e99292261464be3ab Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Thu, 19 Jun 2025 17:17:43 +0900 Subject: [PATCH 22/56] feat: Player hint update 14.1.1 (#549) * for 14.1.1 hint update * Resolve recursive call (sry my mistake) --- EXILED/Exiled.API/Features/Player.cs | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 4dfcf09409..67353fb2ba 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -3020,9 +3020,36 @@ public void ThrowItem(Throwable throwable, bool fullForce = true) /// The message to be shown. /// The duration the text will be on screen. public void ShowHint(string message, float duration = 3f) + { + ShowHint(message, new HintParameter[] { new StringHintParameter(message) }, null, duration); + } + + /// + /// Shows a hint to the player with the specified message, hint effects, and duration. + /// + /// The message to be shown as a hint. + /// The array of hint effects to apply. + /// The duration the hint will be displayed, in seconds. + public void ShowHint(string message, HintEffect[] hintEffects, float duration = 3f) + { + ShowHint(message, new HintParameter[] { new StringHintParameter(message) }, hintEffects, duration); + } + + /// + /// Shows a hint to the player with the specified message, hint parameters, hint effects, and duration. + /// + /// The message to be shown as a hint. + /// The array of hint parameters to use. + /// The array of hint effects to apply. + /// The duration the hint will be displayed, in seconds. + public void ShowHint(string message, HintParameter[] hintParameters, HintEffect[] hintEffects, float duration = 3f) { message ??= string.Empty; - HintDisplay.Show(new TextHint(message, new HintParameter[] { new StringHintParameter(message) }, null, duration)); + HintDisplay.Show(new TextHint( + message, + (!hintParameters.IsEmpty()) ? hintParameters : new HintParameter[] { new StringHintParameter(message) }, + hintEffects, + duration)); } /// From da8b88453281a7edf635b41b07d8ed876c1a47d0 Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Fri, 20 Jun 2025 01:19:14 +0300 Subject: [PATCH 23/56] Fix custom role ragdoll chechk --- EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 8e1620730f..97790a3e24 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -936,7 +936,7 @@ private void OnInternalChangingRole(ChangingRoleEventArgs ev) private void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { - if (Check(ev.Player) && !Role.IsFpcRole()) + if (Check(ev.Player) && Role.IsFpcRole()) ev.Role = Role; } From 463fd1fcf2ae5fece28d0e74b2c992419413e02c Mon Sep 17 00:00:00 2001 From: Yamato Date: Sat, 5 Jul 2025 16:03:47 +0200 Subject: [PATCH 24/56] Missing ServerRoom Elevator recognised as Unknown --- EXILED/Exiled.API/Features/Lift.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/EXILED/Exiled.API/Features/Lift.cs b/EXILED/Exiled.API/Features/Lift.cs index 43d83f09ad..01f0219a97 100644 --- a/EXILED/Exiled.API/Features/Lift.cs +++ b/EXILED/Exiled.API/Features/Lift.cs @@ -137,6 +137,7 @@ public ElevatorSequence Status ElevatorGroup.Scp049 => ElevatorType.Scp049, ElevatorGroup.GateA => ElevatorType.GateA, ElevatorGroup.GateB => ElevatorType.GateB, + ElevatorGroup.ServerRoom => ElevatorType.ServerRoom, ElevatorGroup.LczA01 or ElevatorGroup.LczA02 => ElevatorType.LczA, ElevatorGroup.LczB01 or ElevatorGroup.LczB02 => ElevatorType.LczB, ElevatorGroup.Nuke01 or ElevatorGroup.Nuke02 => ElevatorType.Nuke, From 79d5f41da2ebb706e246016fddaacd3815e26d76 Mon Sep 17 00:00:00 2001 From: officialvirtualrain <112497305+officialvirtualrain@users.noreply.github.com> Date: Sat, 5 Jul 2025 18:07:20 +0400 Subject: [PATCH 25/56] fix: CustomRoles GotRoleHint.Show config (#583) added GotRoleHint.Show config check --- EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 97790a3e24..2a4796bd10 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -578,7 +578,9 @@ public virtual void AddRole(Player player) ability.AddAbility(player); } - ShowMessage(player); + if (CustomRoles.Instance!.Config.GotRoleHint.Show) + ShowMessage(player); + ShowBroadcast(player); RoleAdded(player); player.TryAddCustomRoleFriendlyFire(Name, CustomRoleFFMultiplier); From a3a650df2269bafd2c55ec702e26bc7abb8d56d3 Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Sat, 5 Jul 2025 23:09:21 +0900 Subject: [PATCH 26/56] feat: Add UpgradedInventoryItem and UpgradedPickup on Scp914 (#579) * Add UpgradedInventoryItem and UpgradedPickup * please * Improved code (thanks to @MS-crew) --- .../Scp914/UpgradedInventoryItemEventArgs.cs | 65 ++++++++++++++ .../Scp914/UpgradedPickupEventArgs.cs | 64 ++++++++++++++ EXILED/Exiled.Events/Handlers/Scp914.cs | 22 +++++ .../Patches/Events/Scp914/UpgradedPickup.cs | 73 ++++++++++++++++ .../Patches/Events/Scp914/UpgradedPlayer.cs | 84 +++++++++++++++++++ .../{UpgradingItem.cs => UpgradingPickup.cs} | 4 +- .../Patches/Events/Scp914/UpgradingPlayer.cs | 4 +- 7 files changed, 312 insertions(+), 4 deletions(-) create mode 100644 EXILED/Exiled.Events/EventArgs/Scp914/UpgradedInventoryItemEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Scp914/UpgradedPickupEventArgs.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Scp914/UpgradedPickup.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Scp914/UpgradedPlayer.cs rename EXILED/Exiled.Events/Patches/Events/Scp914/{UpgradingItem.cs => UpgradingPickup.cs} (97%) diff --git a/EXILED/Exiled.Events/EventArgs/Scp914/UpgradedInventoryItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradedInventoryItemEventArgs.cs new file mode 100644 index 0000000000..4bd590dc55 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradedInventoryItemEventArgs.cs @@ -0,0 +1,65 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp914 +{ + using API.Features; + using API.Features.Items; + using global::Scp914; + using Interfaces; + using InventorySystem.Items; + using InventorySystem.Items.Pickups; + + /// + /// Contains all information before SCP-914 upgrades an item. + /// + public class UpgradedInventoryItemEventArgs : IItemEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public UpgradedInventoryItemEventArgs(Player player, ItemBase item, Scp914KnobSetting knobSetting, ItemBase[] result) + { + Player = player; + Item = Item.Get(item); + KnobSetting = knobSetting; + Result = result; + } + + /// + /// Gets SCP-914 working knob setting. + /// + public Scp914KnobSetting KnobSetting { get; } + + /// + /// Gets a list of items to be upgraded inside SCP-914. + /// + public Item Item { get; } + + /// + /// Gets the who owns the item to be upgraded. + /// + public Player Player { get; } + + /// + /// Gets the array of items created as a result of SCP-914 upgraded. + /// + public ItemBase[] Result { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp914/UpgradedPickupEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradedPickupEventArgs.cs new file mode 100644 index 0000000000..5bd2c9d952 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradedPickupEventArgs.cs @@ -0,0 +1,64 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp914 +{ + using Exiled.API.Features.Pickups; + using Exiled.Events.EventArgs.Interfaces; + using global::Scp914; + using InventorySystem.Items.Pickups; + using UnityEngine; + + /// + /// Contains all information before SCP-914 upgrades an item. + /// + public class UpgradedPickupEventArgs : IPickupEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public UpgradedPickupEventArgs(ItemPickupBase item, Vector3 newPos, Scp914KnobSetting knobSetting, ItemPickupBase[] result) + { + Pickup = Pickup.Get(item); + OutputPosition = newPos; + KnobSetting = knobSetting; + Result = result; + } + + /// + /// Gets a list of items to be upgraded inside SCP-914. + /// + public Pickup Pickup { get; } + + /// + /// Gets the position the item will be output to. + /// + public Vector3 OutputPosition { get; } + + /// + /// Gets SCP-914 working knob setting. + /// + public Scp914KnobSetting KnobSetting { get; } + + /// + /// Gets the array of items created as a result of SCP-914 upgraded. + /// + public ItemPickupBase[] Result { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Scp914.cs b/EXILED/Exiled.Events/Handlers/Scp914.cs index a9efe220a1..8d271661df 100644 --- a/EXILED/Exiled.Events/Handlers/Scp914.cs +++ b/EXILED/Exiled.Events/Handlers/Scp914.cs @@ -22,11 +22,21 @@ public static class Scp914 /// public static Event UpgradingPickup { get; set; } = new(); + /// + /// Invoked after SCP-914 upgrades a Pickup. + /// + public static Event UpgradedPickup { get; set; } = new(); + /// /// Invoked before SCP-914 upgrades an item in a player's inventory. /// public static Event UpgradingInventoryItem { get; set; } = new(); + /// + /// Invoked after SCP-914 upgrades an item in a player's inventory. + /// + public static Event UpgradedInventoryItem { get; set; } = new(); + /// /// Invoked before SCP-914 upgrades a player. /// @@ -48,12 +58,24 @@ public static class Scp914 /// The instance. public static void OnUpgradingPickup(UpgradingPickupEventArgs ev) => UpgradingPickup.InvokeSafely(ev); + /// + /// Called after SCP-914 upgrades a item. + /// + /// The instance. + public static void OnUpgradedPickup(UpgradedPickupEventArgs ev) => UpgradedPickup.InvokeSafely(ev); + /// /// Called before SCP-914 upgrades an item in a player's inventory. /// /// The instance. public static void OnUpgradingInventoryItem(UpgradingInventoryItemEventArgs ev) => UpgradingInventoryItem.InvokeSafely(ev); + /// + /// Called after SCP-914 upgrades an item in a player's inventory. + /// + /// The instance. + public static void OnUpgradedInventoryItem(UpgradedInventoryItemEventArgs ev) => UpgradedInventoryItem.InvokeSafely(ev); + /// /// Called before SCP-914 upgrades a player. /// diff --git a/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradedPickup.cs b/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradedPickup.cs new file mode 100644 index 0000000000..64842911da --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradedPickup.cs @@ -0,0 +1,73 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Scp914 +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Scp914; + + using global::Scp914; + + using Handlers; + + using HarmonyLib; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// Adds the event. + /// + [EventPatch(typeof(Scp914), nameof(Scp914.UpgradedPickup))] + [HarmonyPatch(typeof(Scp914Upgrader), nameof(Scp914Upgrader.ProcessPickup))] + internal static class UpgradedPickup + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ldloc_2); + + List [EventPatch(typeof(Scp914), nameof(Scp914.UpgradingPickup))] [HarmonyPatch(typeof(Scp914Upgrader), nameof(Scp914Upgrader.ProcessPickup))] - internal static class UpgradingItem + internal static class UpgradingPickup { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { diff --git a/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradingPlayer.cs b/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradingPlayer.cs index cffd499ea9..3927ed9a55 100644 --- a/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradingPlayer.cs +++ b/EXILED/Exiled.Events/Patches/Events/Scp914/UpgradingPlayer.cs @@ -116,14 +116,14 @@ private static IEnumerable Transpiler(IEnumerable x.opcode == OpCodes.Stloc_S && x.operand is LocalBuilder { LocalIndex: 10 }) + offset; - ConstructorInfo plugin_api_constructor = typeof(LabApi.Events.Arguments.Scp914Events.Scp914ProcessingInventoryItemEventArgs) + ConstructorInfo lab_api_constructor = typeof(LabApi.Events.Arguments.Scp914Events.Scp914ProcessingInventoryItemEventArgs) .GetConstructor(new[] { typeof(InventorySystem.Items.ItemBase), typeof(Scp914KnobSetting), typeof(ReferenceHub), }); - index = newInstructions.FindIndex(x => x.Is(OpCodes.Newobj, plugin_api_constructor)) + offset; + index = newInstructions.FindIndex(x => x.Is(OpCodes.Newobj, lab_api_constructor)) + offset; // ridtp lcz914 // noclip From 24795f4a2ced66ebfdda3de4f577bd91576ab0c6 Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Sun, 6 Jul 2025 00:43:22 +0900 Subject: [PATCH 27/56] fix: ChangingLeverStatusEventArgs (#582) * Resolve #581 * Update ChangingLeverStatus.cs * better implementation of the FindIndex --------- Co-authored-by: Yamato --- .../Patches/Events/Warhead/ChangingLeverStatus.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EXILED/Exiled.Events/Patches/Events/Warhead/ChangingLeverStatus.cs b/EXILED/Exiled.Events/Patches/Events/Warhead/ChangingLeverStatus.cs index bbcdd724e7..498c487f0c 100644 --- a/EXILED/Exiled.Events/Patches/Events/Warhead/ChangingLeverStatus.cs +++ b/EXILED/Exiled.Events/Patches/Events/Warhead/ChangingLeverStatus.cs @@ -8,6 +8,7 @@ namespace Exiled.Events.Patches.Events.Warhead { using System.Collections.Generic; + using System.Reflection; using System.Reflection.Emit; using API.Features; @@ -36,7 +37,7 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Call); + int index = newInstructions.FindIndex(x => x.operand == (object)PropertySetter(typeof(AlphaWarheadNukesitePanel), nameof(AlphaWarheadNukesitePanel.Networkenabled))) - 5; newInstructions.InsertRange( index, From d80e4de7b45c83ee0cf9a225069418616c4078a9 Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Sat, 5 Jul 2025 19:28:18 +0300 Subject: [PATCH 28/56] feat: New Changed Aspect Ratio Event & Player::AspectRatio Property (#556) * Create AspectRatioType.cs * Create FloatExtensions.cs * Add Player Aspect Ratio Property * Create ChangedRatioEventArgs.cs * Added ChangedRatio handlers * Create ChangedAspectRatio.cs * Added 1_1 Square type * Added Unknow and 1_1 ratio --- EXILED/Exiled.API/Enums/AspectRatioType.cs | 60 +++++++++++++ .../Exiled.API/Extensions/FloatExtensions.cs | 56 ++++++++++++ EXILED/Exiled.API/Features/Player.cs | 5 ++ .../EventArgs/Player/ChangedRatioEventArgs.cs | 54 ++++++++++++ EXILED/Exiled.Events/Handlers/Player.cs | 11 +++ .../Events/Player/ChangedAspectRatio.cs | 85 +++++++++++++++++++ 6 files changed, 271 insertions(+) create mode 100644 EXILED/Exiled.API/Enums/AspectRatioType.cs create mode 100644 EXILED/Exiled.API/Extensions/FloatExtensions.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Player/ChangedRatioEventArgs.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Player/ChangedAspectRatio.cs diff --git a/EXILED/Exiled.API/Enums/AspectRatioType.cs b/EXILED/Exiled.API/Enums/AspectRatioType.cs new file mode 100644 index 0000000000..79e4f4c96e --- /dev/null +++ b/EXILED/Exiled.API/Enums/AspectRatioType.cs @@ -0,0 +1,60 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Enums +{ + /// + /// All available screen aspect ratio types. + /// + public enum AspectRatioType : byte + { + /// + /// Unknown aspect ratio. + /// + Unknown, + + /// + /// 1:1 aspect ratio (square screen). + /// + Ratio1_1, + + /// + /// 3:2 aspect ratio. + /// + Ratio3_2, + + /// + /// 4:3 aspect ratio (standard definition TVs, older monitors). + /// + Ratio4_3, + + /// + /// 5:4 aspect ratio (some older computer monitors). + /// + Ratio5_4, + + /// + /// 16:9 aspect ratio (modern widescreen displays, HDTV). + /// + Ratio16_9, + + /// + /// 16:10 aspect ratio (common in productivity monitors and laptops). + /// + Ratio16_10, + + /// + /// 21:9 aspect ratio (ultrawide displays). + /// + Ratio21_9, + + /// + /// 32:9 aspect ratio (super ultrawide displays). + /// + Ratio32_9, + } +} diff --git a/EXILED/Exiled.API/Extensions/FloatExtensions.cs b/EXILED/Exiled.API/Extensions/FloatExtensions.cs new file mode 100644 index 0000000000..b7a32af87f --- /dev/null +++ b/EXILED/Exiled.API/Extensions/FloatExtensions.cs @@ -0,0 +1,56 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Extensions +{ + using System; + using System.Collections.Generic; + + using Exiled.API.Enums; + + /// + /// A set of extensions for . + /// + public static class FloatExtensions + { + private static readonly Dictionary AspectRatioReferences = new() + { + { AspectRatioType.Unknown, 0f }, + { AspectRatioType.Ratio1_1, 1f }, + { AspectRatioType.Ratio3_2, 3f / 2f }, + { AspectRatioType.Ratio4_3, 4f / 3f }, + { AspectRatioType.Ratio5_4, 5f / 4f }, + { AspectRatioType.Ratio16_9, 16f / 9f }, + { AspectRatioType.Ratio16_10, 16f / 10f }, + { AspectRatioType.Ratio21_9, 21f / 9f }, + { AspectRatioType.Ratio32_9, 32f / 9f }, + }; + + /// + /// Gets the closest for a given aspect ratio value. + /// + /// The aspect ratio value to compare. + /// The closest matching . + public static AspectRatioType GetAspectRatioLabel(this float ratio) + { + float closestDiff = float.MaxValue; + AspectRatioType closestRatio = AspectRatioType.Unknown; + + foreach (KeyValuePair kvp in AspectRatioReferences) + { + float diff = Math.Abs(ratio - kvp.Value); + if (diff < closestDiff) + { + closestDiff = diff; + closestRatio = kvp.Key; + } + } + + return closestRatio; + } + } +} diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 67353fb2ba..323b4ec463 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -343,6 +343,11 @@ public PlayerInfoArea InfoArea set => ReferenceHub.nicknameSync.Network_playerInfoToShow = value; } + /// + /// Gets the player's current aspect ratio type. + /// + public AspectRatioType AspectRatio => ReferenceHub.aspectRatioSync.AspectRatio.GetAspectRatioLabel(); + /// /// Gets or sets the player's custom player info string. This string is displayed along with the player's . /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangedRatioEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangedRatioEventArgs.cs new file mode 100644 index 0000000000..5df04b729e --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/ChangedRatioEventArgs.cs @@ -0,0 +1,54 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Player +{ + using Exiled.API.Enums; + using Exiled.API.Extensions; + using Exiled.API.Features; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information after a player's Aspect Ratio changes. + /// + public class ChangedRatioEventArgs : IPlayerEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The player who is changed ratio. + /// + /// + /// Old aspect ratio of the player. + /// + /// + /// New aspect ratio of the player. + /// + /// + public ChangedRatioEventArgs(ReferenceHub player, float oldratio, float newratio) + { + Player = Player.Get(player); + OldRatio = oldratio.GetAspectRatioLabel(); + NewRatio = newratio.GetAspectRatioLabel(); + } + + /// + /// Gets the player who is changed ratio. + /// + public Player Player { get; } + + /// + /// Gets the players old ratio. + /// + public AspectRatioType OldRatio { get; } + + /// + /// Gets the players new ratio. + /// + public AspectRatioType NewRatio { get; } + } +} diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index e35df7b044..b444aa4b4f 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -103,6 +103,11 @@ public class Player ///
public static Event CancelledItemUse { get; set; } = new(); + /// + /// Invoked after a 's aspect ratio has changed. + /// + public static Event ChangedRatio { get; set; } = new(); + /// /// Invoked after a interacted with something. /// @@ -684,6 +689,12 @@ public class Player /// The instance. public static void OnCancelledItemUse(CancelledItemUseEventArgs ev) => CancelledItemUse.InvokeSafely(ev); + /// + /// Called after a 's aspect ratio changes. + /// + /// The instance. + public static void OnChangedRatio(ChangedRatioEventArgs ev) => ChangedRatio.InvokeSafely(ev); + /// /// Called after a interacted with something. /// diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ChangedAspectRatio.cs b/EXILED/Exiled.Events/Patches/Events/Player/ChangedAspectRatio.cs new file mode 100644 index 0000000000..8a12f60f94 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Player/ChangedAspectRatio.cs @@ -0,0 +1,85 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Player +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using API.Features.Pools; + using CentralAuth; + using Exiled.Events.EventArgs.Player; + using HarmonyLib; + using UnityEngine; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// Adds the event. + /// + [HarmonyPatch(typeof(AspectRatioSync), nameof(AspectRatioSync.UserCode_CmdSetAspectRatio__Single))] + internal class ChangedAspectRatio + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + LocalBuilder oldratio = generator.DeclareLocal(typeof(float)); + LocalBuilder hub = generator.DeclareLocal(typeof(ReferenceHub)); + + Label retLabel = generator.DefineLabel(); + + newInstructions.InsertRange(0, new CodeInstruction[] + { + // float OldRatio = this.AspectRatio; + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(AspectRatioSync), nameof(AspectRatioSync.AspectRatio))), + new(OpCodes.Stloc_S, oldratio.LocalIndex), + }); + + int index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ret); + newInstructions[index].WithLabels(retLabel); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // ReferenceHub hub = this.GetComponent(); + new(OpCodes.Ldarg_0), + new(OpCodes.Call, Method(typeof(Component), nameof(Component.GetComponent)).MakeGenericMethod(typeof(ReferenceHub))), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, hub.LocalIndex), + + // if (hub.authManager._targetInstanceMode != ClientInstanceMode.ReadyClient) return; + new(OpCodes.Ldfld, Field(typeof(ReferenceHub), nameof(ReferenceHub.authManager))), + new(OpCodes.Ldfld, Field(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager._targetInstanceMode))), + new(OpCodes.Ldc_I4, 1), + new(OpCodes.Bne_Un_S, retLabel), + + // hub + new(OpCodes.Ldloc, hub.LocalIndex), + + // OldRatio + new(OpCodes.Ldloc, oldratio.LocalIndex), + + // this.AspectRatio + new(OpCodes.Ldarg_0), + new(OpCodes.Call, PropertyGetter(typeof(AspectRatioSync), nameof(AspectRatioSync.AspectRatio))), + + // ChangedRatioEventArgs ev = new ChangedRatioEventArgs(ReferenceHub, float, float) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ChangedRatioEventArgs))[0]), + + // Handlers.Player.OnChangedRatio(ev); + new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnChangedRatio))), + }); + + for (int i = 0; i < newInstructions.Count; i++) + yield return newInstructions[i]; + + ListPool.Pool.Return(newInstructions); + } + } +} From b7df2924210150c7234ef3f2da195a536d88dbbe Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Sun, 6 Jul 2025 01:52:22 +0900 Subject: [PATCH 29/56] feat: Server with more interaction (#535) --- EXILED/Exiled.API/Features/Server.cs | 36 +++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs index 5de5dd5655..8cd65dc079 100644 --- a/EXILED/Exiled.API/Features/Server.cs +++ b/EXILED/Exiled.API/Features/Server.cs @@ -238,6 +238,15 @@ public static bool IsIdleModeEnabled /// public static void Restart() => Round.Restart(false, true, ServerStatic.NextRoundAction.Restart); + /// + /// Restarts the server with specified options. + /// + /// Indicates whether the restart should be fast. + /// Indicates whether to override the default restart action. + /// Specifies the action to perform after the restart. + public static void Restart(bool fastRestart, bool overrideRestartAction = false, ServerStatic.NextRoundAction restartAction = ServerStatic.NextRoundAction.DoNothing) => + Round.Restart(fastRestart, overrideRestartAction, restartAction); + /// /// Shutdowns the server, disconnects all players. /// @@ -266,6 +275,19 @@ public static bool RestartRedirect(ushort redirectPort) return true; } + /// + /// Redirects players to a server on another port, restarts the current server. + /// + /// The port to redirect players to. + /// Indicates whether the restart should be fast. + /// Indicates whether to override the default restart action. + /// Specifies the action to perform after the restart. + public static void RestartRedirect(ushort redirectPort, bool fastRestart, bool overrideRestartAction = false, ServerStatic.NextRoundAction restartAction = ServerStatic.NextRoundAction.DoNothing) + { + NetworkServer.SendToAll(new RoundRestartMessage(RoundRestartType.RedirectRestart, 0.0f, redirectPort, true, false)); + Timing.CallDelayed(0.5f, () => { Restart(fastRestart, overrideRestartAction, restartAction); }); + } + /// /// Redirects players to a server on another port, shutdowns the current server. /// @@ -280,6 +302,18 @@ public static bool ShutdownRedirect(ushort redirectPort) return true; } + /// + /// Redirects players to a server on another port, shutdowns the current server. + /// + /// The port to redirect players to. + /// Indicates whether to terminate the application after shutting down the server. + /// Indicates whether to suppress the broadcast notification about the shutdown. + public static void ShutdownRedirect(ushort redirectPort, bool quit, bool suppressShutdownBroadcast = false) + { + NetworkServer.SendToAll(new RoundRestartMessage(RoundRestartType.RedirectRestart, 0.0f, redirectPort, true, false)); + Timing.CallDelayed(0.5f, () => { Shutdown(quit, suppressShutdownBroadcast); }); + } + /// /// Executes a server command. /// @@ -307,4 +341,4 @@ public static bool TryGetSessionVariable(string key, out T result) return false; } } -} +} \ No newline at end of file From 573cc6a3c98ad53aeafc917691cbf40fa6d700ff Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Sun, 6 Jul 2025 01:54:31 +0900 Subject: [PATCH 30/56] fix: Fix IsWeapon() did not check for jailbird (#584) * Jailbird * Update CustomWeapon.cs * Revert "Update CustomWeapon.cs" This reverts commit 4c5e275a8dd05a3e55ce800f68de27c7fcc54004. * Revert "Jailbird" This reverts commit 56e3d62afbd1b87504c1f47d5058138be9b09c29. * Approve Change Request * Better way --------- Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com> --- EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs | 6 +++--- EXILED/Exiled.API/Extensions/ItemExtensions.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs index 6abeea8a2f..eaba7fe2bd 100644 --- a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs +++ b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs @@ -124,12 +124,12 @@ public static class DamageTypeExtensions /// Check if a damage type is caused by a weapon. ///
/// The damage type to be checked. - /// Indicates whether the MicroHid damage type should be taken into account. + /// Indicates whether the MicroHid and Jailbird damage type should be taken into account. /// Returns whether the is caused by weapon. - public static bool IsWeapon(this DamageType type, bool checkMicro = true) => type switch + public static bool IsWeapon(this DamageType type, bool checkNonFirearm = true) => type switch { DamageType.Crossvec or DamageType.Logicer or DamageType.Revolver or DamageType.Shotgun or DamageType.AK or DamageType.Com15 or DamageType.Com18 or DamageType.E11Sr or DamageType.Fsp9 or DamageType.ParticleDisruptor or DamageType.Com45 or DamageType.Frmg0 or DamageType.A7 => true, - DamageType.MicroHid when checkMicro => true, + DamageType.MicroHid or DamageType.Jailbird when checkNonFirearm => true, _ => false, }; diff --git a/EXILED/Exiled.API/Extensions/ItemExtensions.cs b/EXILED/Exiled.API/Extensions/ItemExtensions.cs index 458fd10bc4..1c03c97d9c 100644 --- a/EXILED/Exiled.API/Extensions/ItemExtensions.cs +++ b/EXILED/Exiled.API/Extensions/ItemExtensions.cs @@ -38,9 +38,9 @@ public static class ItemExtensions /// Check if an item is a weapon. ///
/// The item to be checked. - /// Indicates whether the MicroHID item should be taken into account. + /// Indicates whether the MicroHID and Jailbird item should be taken into account. /// Returns whether the is a weapon. - public static bool IsWeapon(this ItemType type, bool checkMicro = true) => type.GetFirearmType() is not FirearmType.None || (checkMicro && type is ItemType.MicroHID); + public static bool IsWeapon(this ItemType type, bool checkNonFirearm = true) => type.GetFirearmType() is not FirearmType.None || (checkNonFirearm && type is ItemType.MicroHID or ItemType.Jailbird); /// /// Check if an item is an SCP. From 254c27a69f2cdf20cf759c7067edc8fe53cc8594 Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Sun, 6 Jul 2025 02:03:02 +0900 Subject: [PATCH 31/56] feat: Add Exiled.API.Features.Workstation (#568) * Add Exiled.API.Features.Workstation * fix * Approve the feedback * omg * fix: Workstation ctor could be called twice * use Transform --------- Co-authored-by: Yamato Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com> --- EXILED/Exiled.API/Features/Workstation.cs | 167 ++++++++++++++++++ .../Patches/Generic/WorkstationListAdd.cs | 39 ++++ 2 files changed, 206 insertions(+) create mode 100644 EXILED/Exiled.API/Features/Workstation.cs create mode 100644 EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs diff --git a/EXILED/Exiled.API/Features/Workstation.cs b/EXILED/Exiled.API/Features/Workstation.cs new file mode 100644 index 0000000000..7e7978a7ff --- /dev/null +++ b/EXILED/Exiled.API/Features/Workstation.cs @@ -0,0 +1,167 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + + using Exiled.API.Enums; + using Exiled.API.Interfaces; + using InventorySystem.Items.Firearms.Attachments; + using Mirror; + using UnityEngine; + + /// + /// A wrapper class for . + /// + public class Workstation : IWrapper, IWorldSpace + { + /// + /// A dictionary mapping to . + /// + internal static readonly Dictionary WorkstationControllerToWorkstation = new(new ComponentsEqualityComparer()); + + /// + /// Initializes a new instance of the class. + /// + /// The to wrap. + internal Workstation(WorkstationController workstationController) + { + WorkstationControllerToWorkstation.Add(workstationController, this); + Base = workstationController; + } + + /// + /// Gets a read-only collection of all instances. + /// + public static IReadOnlyCollection List => WorkstationControllerToWorkstation.Values; + + /// + /// Gets the underlying instance. + /// + public WorkstationController Base { get; } + + /// + /// Gets the of the workstation. + /// + public GameObject GameObject => Base.gameObject; + + /// + /// Gets the of the workstation. + /// + public Transform Transform => Base.transform; + + /// + /// Gets the the workstation is located in. + /// + public Room Room => Room.Get(Position); + + /// + /// Gets the of the workstation's room. + /// + public ZoneType Zone => Room.Zone; + + /// + /// Gets or sets the position of the workstation. + /// + public Vector3 Position + { + get => Transform.position; + set + { + NetworkServer.UnSpawn(GameObject); + Transform.position = value; + NetworkServer.Spawn(GameObject); + } + } + + /// + /// Gets or sets the rotation of the workstation. + /// + public Quaternion Rotation + { + get => Transform.rotation; + set + { + NetworkServer.UnSpawn(GameObject); + Transform.rotation = value; + NetworkServer.Spawn(GameObject); + } + } + + /// + /// Gets or sets the status of the workstation. + /// + public WorkstationController.WorkstationStatus Status + { + get => (WorkstationController.WorkstationStatus)Base.Status; + set => Base.NetworkStatus = (byte)value; + } + + /// + /// Gets the used by the workstation. + /// + public Stopwatch Stopwatch => Base.ServerStopwatch; + + /// + /// Gets or sets the player known to be using the workstation. + /// + public Player KnownUser + { + get => Player.Get(Base.KnownUser); + set => Base.KnownUser = value.ReferenceHub; + } + + /// + /// Gets a given a instance. + /// + /// The instance. + /// The instance. + public static Workstation Get(WorkstationController workstationController) => WorkstationControllerToWorkstation.TryGetValue(workstationController, out Workstation workstation) ? workstation : new(workstationController); + + /// + /// Gets all instances that match the specified predicate. + /// + /// The predicate to filter workstations. + /// An of matching workstations. + public static IEnumerable Get(Func predicate) => List.Where(predicate); + + /// + /// Tries to get all instances that match the specified predicate. + /// + /// The predicate to filter workstations. + /// The matching workstations, if any. + /// true if any workstations were found; otherwise, false. + public static bool TryGet(Func predicate, out IEnumerable workstations) + { + workstations = Get(predicate); + return workstations.Any(); + } + + /// + /// Determines whether the specified player is in range of the workstation. + /// + /// The player to check. + /// true if the player is in range; otherwise, false. + public bool IsInRange(Player player) => Base.IsInRange(player.ReferenceHub); + + /// + /// Interacts with the workstation as the specified player. + /// + /// The player to interact as. + public void Interact(Player player) => Base.ServerInteract(player.ReferenceHub, Base.ActivateCollider.ColliderId); + + /// + /// Returns the Room in a human-readable format. + /// + /// A string containing Workstation-related data. + public override string ToString() => $"{GameObject.name} ({Zone}) [{Room}]"; + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs b/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs new file mode 100644 index 0000000000..544ef5086e --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs @@ -0,0 +1,39 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Generic +{ +#pragma warning disable SA1313 +#pragma warning disable SA1402 + + using HarmonyLib; + using InventorySystem.Items.Firearms.Attachments; + + /// + /// Patch for adding to list. + /// + [HarmonyPatch(typeof(WorkstationController), nameof(WorkstationController.Start))] + internal class WorkstationListAdd + { + private static void Postfix(WorkstationController __instance) + { + API.Features.Workstation.Get(__instance); + } + } + + /// + /// Patch for removing to list. + /// + [HarmonyPatch(typeof(WorkstationController), nameof(WorkstationController.OnDestroy))] + internal class WorkstationListRemove + { + private static void Postfix(WorkstationController __instance) + { + API.Features.Workstation.WorkstationControllerToWorkstation.Remove(__instance); + } + } +} \ No newline at end of file From f1d20072b1a1a02bcf3d2c5198e5f39cdf63b5a4 Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Sat, 5 Jul 2025 20:03:32 +0300 Subject: [PATCH 32/56] fix: OnEscaping Exiled and LabAPI bug (#580) Fix --- EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs index 4a4fa0dcba..532c40f2f0 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs @@ -39,7 +39,7 @@ public EscapingEventArgs(ReferenceHub referenceHub, RoleTypeId newRole, EscapeSc Player = Player.Get(referenceHub); NewRole = newRole; EscapeScenario = escapeScenario; - IsAllowed = escapeScenario is not EscapeScenario.None and not EscapeScenario.CustomEscape; + IsAllowed = true; } /// From 1aeeb082008566d9d82ea2c375d09b12fee13e1e Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Sat, 5 Jul 2025 20:06:01 +0300 Subject: [PATCH 33/56] feat: Rework and Fix Custom Role Spawn Logic & Limits (#578) * Update CustomRole.cs * Update CustomRoles.cs * Update PlayerHandlers.cs * Delete white space * Update PlayerHandlers.cs * Update CustomRole.cs * F' * Fix * Update PlayerHandlers.cs * Add Spawn reason Spawn reasons have been set to prevent custom role assignment in incorrect situation. * Update PlayerHandlers.cs * Update PlayerHandlers.cs * Update Extensions.cs * Update PlayerHandlers.cs * Update PlayerHandlers.cs * Update PlayerHandlers.cs * Update CustomRole.cs * Update PlayerHandlers.cs * Update CustomRole.cs * white space * Changed to thread safe * non blocking, thread safe implementation Refactored the player spawning logic to be lock free by using Interlocked for atomic counters and a ConcurrentDictionary for safe concurrent processing. * Update PlayerHandlers.cs * Update CustomRole.cs * Update CustomRole.cs * Delete log info * Update PlayerHandlers.cs * Update CustomRole.cs * rework real random and fair spawn position system * Update CustomRole.cs * Update CustomRole.cs * Update CustomRole.cs --- EXILED/Exiled.CustomRoles/API/Extensions.cs | 21 ++++- .../API/Features/CustomRole.cs | 78 ++++++++++------ EXILED/Exiled.CustomRoles/CustomRoles.cs | 10 ++- .../Events/PlayerHandlers.cs | 89 ++++++++++++++++++- 4 files changed, 167 insertions(+), 31 deletions(-) diff --git a/EXILED/Exiled.CustomRoles/API/Extensions.cs b/EXILED/Exiled.CustomRoles/API/Extensions.cs index a2d6bb25fd..8a0821216d 100644 --- a/EXILED/Exiled.CustomRoles/API/Extensions.cs +++ b/EXILED/Exiled.CustomRoles/API/Extensions.cs @@ -41,6 +41,25 @@ public static ReadOnlyCollection GetCustomRoles(this Player player) return roles.AsReadOnly(); } + /// + /// Checks whether the player has any custom role assigned. + /// + /// The to check. + /// true if the player has at least one custom role; otherwise, false. + public static bool HasAnyCustomRole(this Player player) + { + if (player == null) + return false; + + foreach (CustomRole role in CustomRole.Registered) + { + if (role.Check(player)) + return true; + } + + return false; + } + /// /// Registers an of s. /// @@ -105,4 +124,4 @@ public static void Unregister(this IEnumerable customRoles) /// The the has selected, or . public static ActiveAbility? GetSelectedAbility(this Player player) => !ActiveAbility.AllActiveAbilities.TryGetValue(player, out HashSet abilities) ? null : abilities.FirstOrDefault(a => a.Check(player, CheckType.Selected)); } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 2a4796bd10..5329d0f954 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -37,6 +37,14 @@ namespace Exiled.CustomRoles.API.Features /// public abstract class CustomRole { + /// + /// Gets or sets the number of players that naturally spawned with this custom role. + /// + [YamlIgnore] + #pragma warning disable SA1401 // Fields should be private + public int SpawnedPlayers = 0; + #pragma warning restore SA1401 // Fields should be private + private const float AddRoleDelay = 0.25f; private static Dictionary typeLookupTable = new(); @@ -816,46 +824,68 @@ protected bool TryAddItem(Player player, string itemName) protected Vector3 GetSpawnPosition() { if (SpawnProperties is null || SpawnProperties.Count() == 0) + { return Vector3.zero; + } + + float totalchance = 0f; + List<(float chance, Vector3 pos)> spawnPointPool = new(4); + + void Add(Vector3 pos, float chance) + { + if (chance <= 0f) + return; + + spawnPointPool.Add((chance, pos)); + totalchance += chance; + } + + if (!SpawnProperties.StaticSpawnPoints.IsEmpty()) + { + foreach (StaticSpawnPoint sp in SpawnProperties.StaticSpawnPoints) + { + Add(sp.Position, sp.Chance); + } + } - if (SpawnProperties.StaticSpawnPoints.Count > 0) + if (!SpawnProperties.DynamicSpawnPoints.IsEmpty()) { - foreach ((float chance, Vector3 pos) in SpawnProperties.StaticSpawnPoints) + foreach (DynamicSpawnPoint sp in SpawnProperties.DynamicSpawnPoints) { - double r = Loader.Random.NextDouble() * 100; - if (r <= chance) - return pos; + Add(sp.Position, sp.Chance); } } - if (SpawnProperties.DynamicSpawnPoints.Count > 0) + if (!SpawnProperties.RoleSpawnPoints.IsEmpty()) { - foreach ((float chance, Vector3 pos) in SpawnProperties.DynamicSpawnPoints) + foreach (RoleSpawnPoint sp in SpawnProperties.RoleSpawnPoints) { - double r = Loader.Random.NextDouble() * 100; - if (r <= chance) - return pos; + Add(sp.Position, sp.Chance); } } - if (SpawnProperties.RoleSpawnPoints.Count > 0) + if (!SpawnProperties.RoomSpawnPoints.IsEmpty()) { - foreach ((float chance, Vector3 pos) in SpawnProperties.RoleSpawnPoints) + foreach (RoomSpawnPoint sp in SpawnProperties.RoomSpawnPoints) { - double r = Loader.Random.NextDouble() * 100; - if (r <= chance) - return pos; + Add(sp.Position, sp.Chance); } } - if (SpawnProperties.RoomSpawnPoints.Count > 0) + if (spawnPointPool.Count == 0 || totalchance <= 0f) + { + return Vector3.zero; + } + + float randomRoll = (float)(Loader.Random.NextDouble() * totalchance); + foreach ((float chance, Vector3 pos) in spawnPointPool) { - foreach ((float chance, Vector3 pos) in SpawnProperties.RoomSpawnPoints) + if (randomRoll < chance) { - double r = Loader.Random.NextDouble() * 100; - if (r <= chance) - return pos; + return pos; } + + randomRoll -= chance; } return Vector3.zero; @@ -869,7 +899,6 @@ protected virtual void SubscribeEvents() Log.Debug($"{Name}: Loading events."); Exiled.Events.Handlers.Player.ChangingNickname += OnInternalChangingNickname; Exiled.Events.Handlers.Player.ChangingRole += OnInternalChangingRole; - Exiled.Events.Handlers.Player.Spawned += OnInternalSpawned; Exiled.Events.Handlers.Player.SpawningRagdoll += OnSpawningRagdoll; Exiled.Events.Handlers.Player.Destroying += OnDestroying; } @@ -885,7 +914,6 @@ protected virtual void UnsubscribeEvents() Log.Debug($"{Name}: Unloading events."); Exiled.Events.Handlers.Player.ChangingNickname -= OnInternalChangingNickname; Exiled.Events.Handlers.Player.ChangingRole -= OnInternalChangingRole; - Exiled.Events.Handlers.Player.Spawned -= OnInternalSpawned; Exiled.Events.Handlers.Player.SpawningRagdoll -= OnSpawningRagdoll; Exiled.Events.Handlers.Player.Destroying -= OnDestroying; } @@ -924,12 +952,6 @@ private void OnInternalChangingNickname(ChangingNicknameEventArgs ev) ev.Player.CustomInfo = $"{ev.NewName}\n{CustomInfo}"; } - private void OnInternalSpawned(SpawnedEventArgs ev) - { - if (!IgnoreSpawnSystem && SpawnChance > 0 && !Check(ev.Player) && ev.Player.Role.Type == Role && Loader.Random.NextDouble() * 100 <= SpawnChance) - AddRole(ev.Player); - } - private void OnInternalChangingRole(ChangingRoleEventArgs ev) { if (ev.IsAllowed && ev.Reason != SpawnReason.Destroyed && Check(ev.Player) && ((ev.NewRole == RoleTypeId.Spectator && !KeepRoleOnDeath) || (ev.NewRole != RoleTypeId.Spectator && !KeepRoleOnChangingRole))) diff --git a/EXILED/Exiled.CustomRoles/CustomRoles.cs b/EXILED/Exiled.CustomRoles/CustomRoles.cs index 4ea4c77f1d..a66457b3bd 100644 --- a/EXILED/Exiled.CustomRoles/CustomRoles.cs +++ b/EXILED/Exiled.CustomRoles/CustomRoles.cs @@ -62,16 +62,24 @@ public override void OnEnabled() if (Config.UseKeypressActivation) keypressActivator = new(); + + Exiled.Events.Handlers.Player.Spawned += playerHandlers.OnSpawned; Exiled.Events.Handlers.Player.SpawningRagdoll += playerHandlers.OnSpawningRagdoll; + + Exiled.Events.Handlers.Server.WaitingForPlayers += playerHandlers.OnWaitingForPlayers; base.OnEnabled(); } /// public override void OnDisabled() { + Exiled.Events.Handlers.Player.Spawned -= playerHandlers!.OnSpawned; Exiled.Events.Handlers.Player.SpawningRagdoll -= playerHandlers!.OnSpawningRagdoll; + + Exiled.Events.Handlers.Server.WaitingForPlayers -= playerHandlers!.OnWaitingForPlayers; + keypressActivator = null; base.OnDisabled(); } } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs b/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs index b53556f007..5c0aa7356e 100644 --- a/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs +++ b/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs @@ -7,6 +7,14 @@ namespace Exiled.CustomRoles.Events { + using System; + using System.Collections.Generic; + using System.Threading; + + using Exiled.API.Enums; + using Exiled.API.Features; + using Exiled.CustomRoles.API; + using Exiled.CustomRoles.API.Features; using Exiled.Events.EventArgs.Player; /// @@ -15,6 +23,15 @@ namespace Exiled.CustomRoles.Events public class PlayerHandlers { private readonly CustomRoles plugin; + private readonly HashSet validSpawnReasons = new() + { + SpawnReason.RoundStart, + SpawnReason.Respawn, + SpawnReason.LateJoin, + SpawnReason.Revived, + SpawnReason.Escaped, + SpawnReason.ItemUsage, + }; /// /// Initializes a new instance of the class. @@ -25,6 +42,15 @@ public PlayerHandlers(CustomRoles plugin) this.plugin = plugin; } + /// + internal void OnWaitingForPlayers() + { + foreach (CustomRole role in CustomRole.Registered) + { + role.SpawnedPlayers = 0; + } + } + /// internal void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { @@ -34,5 +60,66 @@ internal void OnSpawningRagdoll(SpawningRagdollEventArgs ev) plugin.StopRagdollPlayers.Remove(ev.Player); } } + + /// + internal void OnSpawned(SpawnedEventArgs ev) + { + if (!validSpawnReasons.Contains(ev.Reason) || ev.Player.HasAnyCustomRole()) + { + return; + } + + float totalChance = 0f; + List eligibleRoles = new(8); + + foreach (CustomRole role in CustomRole.Registered) + { + if (role.Role == ev.Player.Role.Type && !role.IgnoreSpawnSystem && role.SpawnChance > 0 && !role.Check(ev.Player) && (role.SpawnProperties is null || role.SpawnedPlayers < role.SpawnProperties.Limit)) + { + eligibleRoles.Add(role); + totalChance += role.SpawnChance; + } + } + + if (eligibleRoles.Count == 0) + { + return; + } + + float lotterySize = Math.Max(100f, totalChance); + float randomRoll = (float)Loader.Loader.Random.NextDouble() * lotterySize; + + if (randomRoll >= totalChance) + { + return; + } + + foreach (CustomRole candidateRole in eligibleRoles) + { + if (randomRoll >= candidateRole.SpawnChance) + { + randomRoll -= candidateRole.SpawnChance; + continue; + } + + if (candidateRole.SpawnProperties is null) + { + candidateRole.AddRole(ev.Player); + break; + } + + int newSpawnCount = Interlocked.Increment(ref candidateRole.SpawnedPlayers); + if (newSpawnCount <= candidateRole.SpawnProperties.Limit) + { + candidateRole.AddRole(ev.Player); + break; + } + else + { + Interlocked.Decrement(ref candidateRole.SpawnedPlayers); + randomRoll -= candidateRole.SpawnChance; + } + } + } } -} \ No newline at end of file +} From 44afe852f85b85d2853ffc49a0157f8003155c9b Mon Sep 17 00:00:00 2001 From: Yamato Date: Sat, 5 Jul 2025 20:00:29 +0200 Subject: [PATCH 34/56] Bump Version --- EXILED/EXILED.props | 2 +- EXILED/docs/articles/SCPSLRessources/NW_Documentation.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/EXILED/EXILED.props b/EXILED/EXILED.props index a4e5a63b69..9dfffe99fd 100644 --- a/EXILED/EXILED.props +++ b/EXILED/EXILED.props @@ -15,7 +15,7 @@ - 9.6.1 + 9.6.2 false diff --git a/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md b/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md index bfc0f31671..f4d027231f 100644 --- a/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md +++ b/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md @@ -17,7 +17,7 @@ title: NW Documentation --- -Last Update (14.1.0.0) +Last Update (14.1.0.1) ### Index @@ -5611,7 +5611,7 @@ Last Update (14.1.0.0)
Damage Handlers -```md title="Latest Updated: 14.1.0.0" +```md title="Latest Updated: 14.1.0.1" All available DamageHandlers + Symbol ':' literally means "inherits from" From 28597de03674add9cb84b4d29d5f4d77ba9f043e Mon Sep 17 00:00:00 2001 From: Yamato Date: Sat, 5 Jul 2025 23:33:00 +0200 Subject: [PATCH 35/56] Fix CustomRole Issue not working when using OnSpawned --- EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 5329d0f954..fc4e897edb 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -514,6 +514,7 @@ public virtual void AddRole(Player player) { Log.Debug($"{Name}: Adding role to {player.Nickname}."); player.UniqueRole = Name; + TrackedPlayers.Add(player); if (Role != RoleTypeId.None) { @@ -534,7 +535,6 @@ public virtual void AddRole(Player player) } player.UniqueRole = Name; - TrackedPlayers.Add(player); Timing.CallDelayed( AddRoleDelay, From 3c7ce4d9405307fc79a6d4d8363b33b6f38442f9 Mon Sep 17 00:00:00 2001 From: Yamato Date: Sun, 6 Jul 2025 00:20:04 +0200 Subject: [PATCH 36/56] SpawnReason.CustomRole --- EXILED/Exiled.API/Enums/SpawnReason.cs | 5 +++++ EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/EXILED/Exiled.API/Enums/SpawnReason.cs b/EXILED/Exiled.API/Enums/SpawnReason.cs index 8274b99336..4ef67f1742 100644 --- a/EXILED/Exiled.API/Enums/SpawnReason.cs +++ b/EXILED/Exiled.API/Enums/SpawnReason.cs @@ -61,5 +61,10 @@ public enum SpawnReason : byte // TOTO: Remove this file and use Basegame /// The user has been spawn by the usage of an Item. ///
ItemUsage, + + /// + /// The user has been spawn by Exiled CustomRole. + /// + CustomRole, } } \ No newline at end of file diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index fc4e897edb..0e0d8042b0 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -521,16 +521,16 @@ public virtual void AddRole(Player player) if (KeepPositionOnSpawn) { if (KeepInventoryOnSpawn) - player.Role.Set(Role, SpawnReason.ForceClass, RoleSpawnFlags.None); + player.Role.Set(Role, SpawnReason.CustomRole, RoleSpawnFlags.None); else - player.Role.Set(Role, SpawnReason.ForceClass, RoleSpawnFlags.AssignInventory); + player.Role.Set(Role, SpawnReason.CustomRole, RoleSpawnFlags.AssignInventory); } else { if (KeepInventoryOnSpawn && player.IsAlive) - player.Role.Set(Role, SpawnReason.ForceClass, RoleSpawnFlags.UseSpawnpoint); + player.Role.Set(Role, SpawnReason.CustomRole, RoleSpawnFlags.UseSpawnpoint); else - player.Role.Set(Role, SpawnReason.ForceClass, RoleSpawnFlags.All); + player.Role.Set(Role, SpawnReason.CustomRole, RoleSpawnFlags.All); } } @@ -954,7 +954,7 @@ private void OnInternalChangingNickname(ChangingNicknameEventArgs ev) private void OnInternalChangingRole(ChangingRoleEventArgs ev) { - if (ev.IsAllowed && ev.Reason != SpawnReason.Destroyed && Check(ev.Player) && ((ev.NewRole == RoleTypeId.Spectator && !KeepRoleOnDeath) || (ev.NewRole != RoleTypeId.Spectator && !KeepRoleOnChangingRole))) + if (ev.IsAllowed && ev.Reason is not(SpawnReason.Destroyed or SpawnReason.CustomRole) && Check(ev.Player) && ((ev.NewRole == RoleTypeId.Spectator && !KeepRoleOnDeath) || (ev.NewRole != RoleTypeId.Spectator && !KeepRoleOnChangingRole))) RemoveRole(ev.Player); } From eeca9e9fa5a7157dceec26361ba83bb07f80e934 Mon Sep 17 00:00:00 2001 From: Yamato Date: Sun, 6 Jul 2025 18:30:38 +0200 Subject: [PATCH 37/56] fix up link --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b7c930b5e1..e0c018e25a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ defaults: env: EXILED_REFERENCES_URL: https://Exmod-team.github.io/SL-References/Dev.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References - EXILED_DLL_ARCHIVER_URL: https://github.com/Exmod-Team/EXILED-DLL-Archiver/releases/download/v1.8.1/EXILED-DLL-Archiver.exe + EXILED_DLL_ARCHIVER_URL: https://github.com/ExMod-Team/EXILED-DLL-Archiver/releases/latest/EXILED-DLL-Archiver.exe jobs: build: From e6f1edf2c4e3ed0637f97aad074029652babebfd Mon Sep 17 00:00:00 2001 From: "@Someone" <45270312+Someone-193@users.noreply.github.com> Date: Sun, 6 Jul 2025 12:33:28 -0400 Subject: [PATCH 38/56] fix: fix bad implementation of a CustomRole Field (#586) * fix KeybindSetting and RoundEnd transpiler I think it all works, I ran server and no errors, I got on and ended round and no errors * Fix Scale (ScaleController is mid) Fix ChangingLeverStatus event I think these work * Fix goofy goober stuff --- .../Exiled.CustomRoles/API/Features/CustomRole.cs | 14 ++++++-------- EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs | 11 ++++++----- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 0e0d8042b0..db5e599cd3 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -37,14 +37,6 @@ namespace Exiled.CustomRoles.API.Features ///
public abstract class CustomRole { - /// - /// Gets or sets the number of players that naturally spawned with this custom role. - /// - [YamlIgnore] - #pragma warning disable SA1401 // Fields should be private - public int SpawnedPlayers = 0; - #pragma warning restore SA1401 // Fields should be private - private const float AddRoleDelay = 0.25f; private static Dictionary typeLookupTable = new(); @@ -184,6 +176,12 @@ public abstract class CustomRole ///
public virtual string AbilityUsage { get; set; } = "Enter \".special\" in the console to use your ability. If you have multiple abilities, you can use this command to cycle through them, or specify the one to use with \".special ROLENAME AbilityNum\""; + /// + /// Gets or sets the number of players that naturally spawned with this custom role. + /// + [YamlIgnore] + public int SpawnedPlayers { get; set; } + /// /// Gets a by ID. /// diff --git a/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs b/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs index 5c0aa7356e..1a10e38dcf 100644 --- a/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs +++ b/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs @@ -22,8 +22,7 @@ namespace Exiled.CustomRoles.Events ///
public class PlayerHandlers { - private readonly CustomRoles plugin; - private readonly HashSet validSpawnReasons = new() + private static readonly HashSet ValidSpawnReasons = new() { SpawnReason.RoundStart, SpawnReason.Respawn, @@ -33,6 +32,8 @@ public class PlayerHandlers SpawnReason.ItemUsage, }; + private readonly CustomRoles plugin; + /// /// Initializes a new instance of the class. /// @@ -64,7 +65,7 @@ internal void OnSpawningRagdoll(SpawningRagdollEventArgs ev) /// internal void OnSpawned(SpawnedEventArgs ev) { - if (!validSpawnReasons.Contains(ev.Reason) || ev.Player.HasAnyCustomRole()) + if (!ValidSpawnReasons.Contains(ev.Reason) || ev.Player.HasAnyCustomRole()) { return; } @@ -108,7 +109,7 @@ internal void OnSpawned(SpawnedEventArgs ev) break; } - int newSpawnCount = Interlocked.Increment(ref candidateRole.SpawnedPlayers); + int newSpawnCount = candidateRole.SpawnedPlayers++; if (newSpawnCount <= candidateRole.SpawnProperties.Limit) { candidateRole.AddRole(ev.Player); @@ -116,7 +117,7 @@ internal void OnSpawned(SpawnedEventArgs ev) } else { - Interlocked.Decrement(ref candidateRole.SpawnedPlayers); + candidateRole.SpawnedPlayers--; randomRoll -= candidateRole.SpawnChance; } } From b896a73a32decb117268090f23ef29bebcf0322c Mon Sep 17 00:00:00 2001 From: Bonjemus <59416055+Bonjemus@users.noreply.github.com> Date: Mon, 7 Jul 2025 22:54:04 +0200 Subject: [PATCH 39/56] fix: Scale fix (#571) * scale fix first attempt * 2 attempt * 3 attempt * 4 attempt * Add fix for when player reconnect Scale not working * Remove TryCatch & error --------- Co-authored-by: Yamato --- EXILED/Exiled.API/Features/Player.cs | 46 +++++++------------ EXILED/Exiled.API/Features/Roles/FpcRole.cs | 9 ++++ .../API/Features/CustomRole.cs | 3 +- .../Exiled.Events/Handlers/Internal/Round.cs | 9 ++-- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 323b4ec463..779982d2fb 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -699,7 +699,7 @@ public ScpSpawnPreferences.SpawnPreferences ScpPreferences public Vector3 Scale { get => ReferenceHub.transform.localScale; - set => SetScale(value, List); + set => SetScale(value); } /// @@ -2065,6 +2065,16 @@ public void Disconnect(string reason = null) => /// public void ResetStamina() => Stamina = StaminaStat.MaxValue; + /// + /// Sets the scale of a player on the server side. + /// + /// The scale to set. + public void SetScale(Vector3 scale) + { + ReferenceHub.transform.localScale = scale; + new SyncedScaleMessages.ScaleMessage(scale, ReferenceHub).SendToAuthenticated(); + } + /// /// Sets the scale of a player on the server side. /// @@ -2072,20 +2082,8 @@ public void Disconnect(string reason = null) => /// Who should see the updated scale. public void SetScale(Vector3 scale, IEnumerable viewers) { - if (scale == Scale) - return; - - try - { - ReferenceHub.transform.localScale = scale; - - foreach (Player target in viewers) - Server.SendSpawnMessage?.Invoke(null, new object[] { NetworkIdentity, target.Connection }); - } - catch (Exception exception) - { - Log.Error($"{nameof(SetScale)} error: {exception}"); - } + ReferenceHub.transform.localScale = scale; + new SyncedScaleMessages.ScaleMessage(scale, ReferenceHub).SendToHubsConditionally(x => x != null && viewers.Contains(Get(x))); } /// @@ -2095,21 +2093,9 @@ public void SetScale(Vector3 scale, IEnumerable viewers) /// Who should see the fake scale. public void SetFakeScale(Vector3 fakeScale, IEnumerable viewers) { - Vector3 currentScale = Scale; - - try - { - ReferenceHub.transform.localScale = fakeScale; - - foreach (Player target in viewers) - Server.SendSpawnMessage.Invoke(null, new object[] { NetworkIdentity, target.Connection }); - - ReferenceHub.transform.localScale = currentScale; - } - catch (Exception ex) - { - Log.Error($"{nameof(SetFakeScale)}: {ex}"); - } + SyncedScaleMessages.ScaleMessage scaleMessage = new(fakeScale, ReferenceHub); + foreach (Player player in viewers) + player.Connection.Send(scaleMessage, 0); } /// diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs index d1c0a12591..d54201ff0e 100644 --- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs +++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs @@ -76,6 +76,15 @@ public Vector3 Gravity set => FirstPersonController.FpcModule.Motor.GravityController.Gravity = value; } + /// + /// Gets or sets the player's scale. + /// + public Vector3 Scale + { + get => FirstPersonController.FpcModule.Motor.ScaleController.Scale; + set => FirstPersonController.FpcModule.Motor.ScaleController.Scale = value; + } + /// /// Gets or sets a value indicating whether if the player should get damage. /// diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index db5e599cd3..895b483b2e 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -564,7 +564,7 @@ public virtual void AddRole(Player player) Log.Debug($"{Name}: Setting health values."); player.Health = MaxHealth; player.MaxHealth = MaxHealth; - player.Scale = Scale; + Timing.CallDelayed(0.1f, () => player.Scale = Scale); // To fix : remove the delay in 14.1.2 once the crash issue is resolved if (Gravity.HasValue && player.Role is FpcRole fpcRole) fpcRole.Gravity = Gravity.Value; Vector3 position = GetSpawnPosition(); @@ -627,7 +627,6 @@ public virtual void RemoveRole(Player player) TrackedPlayers.Remove(player); player.CustomInfo = string.Empty; player.InfoArea |= PlayerInfoArea.Role | PlayerInfoArea.Nickname; - player.Scale = Vector3.one; if (CustomAbilities is not null) { foreach (CustomAbility ability in CustomAbilities) diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index f81b0886b9..3ce8660bbe 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -29,7 +29,10 @@ namespace Exiled.Events.Handlers.Internal using InventorySystem.Items.Usables; using InventorySystem.Items.Usables.Scp244.Hypothermia; using PlayerRoles; + using PlayerRoles.FirstPersonControl; using PlayerRoles.RoleAssign; + using UnityEngine; + using Utils.Networking; using Utils.NonAllocLINQ; /// @@ -114,10 +117,10 @@ public static void OnVerified(VerifiedEventArgs ev) ev.Player.SendFakeSyncVar(room.RoomLightControllerNetIdentity, typeof(RoomLightController), nameof(RoomLightController.NetworkLightsEnabled), false); } - // TODO: Remove if this has been fixed for https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/947 - if (ev.Player.TryGetEffect(out Hypothermia hypothermia)) + // Fix bug that player that Join do not receive information about other players Scale + foreach (Player player in ReferenceHub.AllHubs.Select(Player.Get)) { - hypothermia.SubEffects = hypothermia.SubEffects.Where(x => x.GetType() != typeof(PostProcessSubEffect)).ToArray(); + player.SetFakeScale(player.Scale, new List() { ev.Player }); } } From 6085b42cc10f2ceef477b9896399ea949b69e49b Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:47:44 +0900 Subject: [PATCH 40/56] feat: Add Ragdoll features & readability (#567) * Update Ragdoll.cs * fix 2 * Remove Check in case of people using Mirror --------- Co-authored-by: Yamato --- EXILED/Exiled.API/Features/Ragdoll.cs | 64 +++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/EXILED/Exiled.API/Features/Ragdoll.cs b/EXILED/Exiled.API/Features/Ragdoll.cs index 011c092248..51878021cf 100644 --- a/EXILED/Exiled.API/Features/Ragdoll.cs +++ b/EXILED/Exiled.API/Features/Ragdoll.cs @@ -214,6 +214,11 @@ public bool IsConsumed } } + /// + /// Gets a value indicating whether this ragdoll is spawned. + /// + public bool IsSpawned => NetworkServer.spawned.ContainsValue(Base.netIdentity); + /// /// Gets the the ragdoll is located in. /// @@ -232,11 +237,17 @@ public Vector3 Position get => Base.transform.position; set { - NetworkServer.UnSpawn(GameObject); + if (!IsSpawned) + { + Base.transform.position = value; + return; + } + + UnSpawn(); Base.transform.position = value; - NetworkServer.Spawn(GameObject); + Spawn(); } } @@ -248,11 +259,17 @@ public Quaternion Rotation get => Base.transform.rotation; set { - NetworkServer.UnSpawn(GameObject); + if (!IsSpawned) + { + Base.transform.rotation = value; + return; + } + + UnSpawn(); Base.transform.rotation = value; - NetworkServer.Spawn(GameObject); + Spawn(); } } @@ -264,11 +281,17 @@ public Vector3 RagdollScale get => Base.transform.localScale; set { - NetworkServer.UnSpawn(GameObject); + if (!IsSpawned) + { + Base.transform.localScale = value; + return; + } + + UnSpawn(); Base.transform.localScale = value; - NetworkServer.Spawn(GameObject); + Spawn(); } } @@ -406,15 +429,40 @@ public static Ragdoll Get(BasicRagdoll ragdoll) => ragdoll == null ? null : public static IEnumerable Get(IEnumerable players) => players.SelectMany(pl => Ragdoll.List.Where(rd => rd.Owner == pl)); /// - /// Destroys the ragdoll. + /// Destroys the ragdoll immediately. /// public void Destroy() => Object.Destroy(GameObject); /// - /// Spawns the ragdoll. + /// Destroys the ragdoll after a specified delay. + /// + /// The delay in seconds before the ragdoll is destroyed. + public void Destroy(float delay) => Object.Destroy(GameObject, delay); + + /// + /// Spawns the ragdoll on the network. /// public void Spawn() => NetworkServer.Spawn(GameObject); + /// + /// Spawns the ragdoll on the network with a specified owner. + /// + /// The owner of the ragdoll. + public void Spawn(GameObject ownerPlayer) => NetworkServer.Spawn(GameObject, ownerPlayer); + + /// + /// Spawns the ragdoll on the network with a specified network connection or asset ID. + /// + /// The network connection of the owner. + /// The optional asset ID of the ragdoll. + public void Spawn(NetworkConnection ownerConnection, uint? assetId = null) + { + if (assetId.HasValue) + NetworkServer.Spawn(GameObject, assetId.Value, ownerConnection); + else + NetworkServer.Spawn(GameObject, ownerConnection); + } + /// /// Un-spawns the ragdoll. /// From ba204e5967f8dc32764420b5cd603eb27fb2cec3 Mon Sep 17 00:00:00 2001 From: Yamato Date: Tue, 8 Jul 2025 06:57:54 +0200 Subject: [PATCH 41/56] MissChanged from ExSLMod --- EXILED/Exiled.API/Features/Items/Throwable.cs | 5 ++ EXILED/Exiled.API/Features/Respawn.cs | 73 +++++++++++++++++++ EXILED/Exiled.API/Features/Toys/Capybara.cs | 6 +- EXILED/Exiled.API/Features/Warhead.cs | 6 +- .../Item/ChargingJailbirdEventArgs.cs | 14 ++-- .../Item/JailbirdChargeCompleteEventArgs.cs | 52 +++++++++++++ EXILED/Exiled.Events/Handlers/Item.cs | 15 +++- .../Patches/Events/Item/JailbirdPatch.cs | 16 +++- 8 files changed, 173 insertions(+), 14 deletions(-) create mode 100644 EXILED/Exiled.Events/EventArgs/Item/JailbirdChargeCompleteEventArgs.cs diff --git a/EXILED/Exiled.API/Features/Items/Throwable.cs b/EXILED/Exiled.API/Features/Items/Throwable.cs index 548b1037e7..721167a3b5 100644 --- a/EXILED/Exiled.API/Features/Items/Throwable.cs +++ b/EXILED/Exiled.API/Features/Items/Throwable.cs @@ -92,6 +92,11 @@ public void Throw(bool fullForce = true) Base.ServerThrow(settings.StartVelocity, settings.UpwardsFactor, settings.StartTorque, ThrowableNetworkHandler.GetLimitedVelocity(Owner?.Velocity ?? Vector3.one)); } + /// + /// Cancel the the throws of the item. + /// + public void CancelThrow() => Base.ServerProcessCancellation(); + /// /// Clones current object. /// diff --git a/EXILED/Exiled.API/Features/Respawn.cs b/EXILED/Exiled.API/Features/Respawn.cs index 2430d5bd9b..0f34495520 100644 --- a/EXILED/Exiled.API/Features/Respawn.cs +++ b/EXILED/Exiled.API/Features/Respawn.cs @@ -388,6 +388,26 @@ public static void ForceWave(SpawnableWaveBase spawnableWaveBase) WaveManager.Spawn(spawnableWaveBase); } + /// + /// Pauses a specific respawn wave by removing it from the active wave list and adding it to the paused wave list. + /// + /// The representing the wave to pause. + public static void PauseWave(SpawnableFaction spawnableFaction) + { + if (TryGetWaveBase(spawnableFaction, out SpawnableWaveBase spawnableWaveBase)) + { + if (!PausedWaves.Contains(spawnableWaveBase)) + { + PausedWaves.Add(spawnableWaveBase); + } + + if (WaveManager.Waves.Contains(spawnableWaveBase)) + { + WaveManager.Waves.Remove(spawnableWaveBase); + } + } + } + /// /// Pauses respawn waves by removing them from WaveManager.Waves and storing them in . /// @@ -399,6 +419,21 @@ public static void PauseWaves() WaveManager.Waves.Clear(); } + /// + /// Pauses the specified list of respawn waves by iterating through each wave + /// and pausing it using the method. + /// + /// + /// A list of instances representing the waves to pause. + /// + public static void PauseWaves(List spawnableFactions) + { + foreach (SpawnableFaction spawnableFaction in spawnableFactions) + { + PauseWave(spawnableFaction); + } + } + /// /// Resumes respawn waves by filling WaveManager.Waves with values stored in . /// @@ -411,6 +446,29 @@ public static void ResumeWaves() PausedWaves.Clear(); } + /// + /// Restarts a specific respawn wave by adding it back to the active wave list + /// and removing it from the paused wave list if necessary. + /// + /// + /// The representing the wave to restart. + /// + public static void RestartWave(SpawnableFaction spawnableFaction) + { + if (TryGetWaveBase(spawnableFaction, out SpawnableWaveBase spawnableWaveBase)) + { + if (!WaveManager.Waves.Contains(spawnableWaveBase)) + { + WaveManager.Waves.Add(spawnableWaveBase); + } + + if (PausedWaves.Contains(spawnableWaveBase)) + { + PausedWaves.Remove(spawnableWaveBase); + } + } + } + /// /// Restarts respawn waves by clearing WaveManager.Waves and filling it with new values.. /// @@ -423,6 +481,21 @@ public static void RestartWaves() PausedWaves.Clear(); } + /// + /// Restarts the specified respawn waves by iterating through each wave + /// and restarting it using the method. + /// + /// + /// A list of instances representing the waves to restart. + /// + public static void RestartWaves(List spawnableFactions) + { + foreach (SpawnableFaction spawnableFaction in spawnableFactions) + { + RestartWave(spawnableFaction); + } + } + /// /// Tries to get the influence value of a given . /// diff --git a/EXILED/Exiled.API/Features/Toys/Capybara.cs b/EXILED/Exiled.API/Features/Toys/Capybara.cs index b88dbfd9c8..23e3e07f23 100644 --- a/EXILED/Exiled.API/Features/Toys/Capybara.cs +++ b/EXILED/Exiled.API/Features/Toys/Capybara.cs @@ -19,9 +19,9 @@ public class Capybara : AdminToy, IWrapper /// /// Initializes a new instance of the class. /// - /// The of the toy. - internal Capybara(CapybaraToy speakerToy) - : base(speakerToy, AdminToyType.Speaker) => Base = speakerToy; + /// The of the toy. + internal Capybara(CapybaraToy capybaraToy) + : base(capybaraToy, AdminToyType.Capybara) => Base = capybaraToy; /// /// Gets the prefab. diff --git a/EXILED/Exiled.API/Features/Warhead.cs b/EXILED/Exiled.API/Features/Warhead.cs index 97ce5a9cfe..f261577770 100644 --- a/EXILED/Exiled.API/Features/Warhead.cs +++ b/EXILED/Exiled.API/Features/Warhead.cs @@ -45,7 +45,11 @@ public static class Warhead /// /// Gets or sets a value indicating whether DeadmanSwitch detonation is enabled. /// - public static bool DeadmanSwitchEnabled { get; set; } = true; + public static bool DeadmanSwitchEnabled + { + get => DeadmanSwitch.IsDeadmanSwitchEnabled; + set => DeadmanSwitch.IsDeadmanSwitchEnabled = value; + } /// /// Gets or sets a value indicating whether automatic detonation is enabled. diff --git a/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs index 6bb6c9ad6c..98f2588187 100644 --- a/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs @@ -12,20 +12,20 @@ namespace Exiled.Events.EventArgs.Item using Exiled.Events.EventArgs.Interfaces; /// - /// Contains all information before a player charges a . + /// Contains all information before a player starts charging an . /// - public class ChargingJailbirdEventArgs : IItemEvent + public class ChargingJailbirdEventArgs : IItemEvent, IDeniableEvent { /// /// Initializes a new instance of the class. /// - /// - /// The item being charged. - /// Whether the item can be charged. - public ChargingJailbirdEventArgs(ReferenceHub player, InventorySystem.Items.ItemBase swingItem, bool isAllowed = true) + /// The player who is attempting to charge the Jailbird. + /// The jailbird being charged. + /// Whether the item is allowed to be charged. + public ChargingJailbirdEventArgs(ReferenceHub player, InventorySystem.Items.ItemBase jailbird, bool isAllowed = true) { Player = Player.Get(player); - Jailbird = (Jailbird)Item.Get(swingItem); + Jailbird = Item.Get(jailbird); IsAllowed = isAllowed; } diff --git a/EXILED/Exiled.Events/EventArgs/Item/JailbirdChargeCompleteEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/JailbirdChargeCompleteEventArgs.cs new file mode 100644 index 0000000000..d583f22b3f --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Item/JailbirdChargeCompleteEventArgs.cs @@ -0,0 +1,52 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Item +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information when a player completes charging a . + /// + public class JailbirdChargeCompleteEventArgs : IItemEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The player who completed the charge. + /// The Jailbird item whose charge is complete. + /// Whether the Jailbird is allowed to attack after charging. + public JailbirdChargeCompleteEventArgs(ReferenceHub player, InventorySystem.Items.ItemBase jailbird, bool isAllowed = true) + { + Player = Player.Get(player); + Jailbird = Item.Get(jailbird); + IsAllowed = isAllowed; + } + + /// + /// Gets the who completed the charge. + /// + public Player Player { get; } + + /// + /// Gets the that was fully charged. + /// + public Jailbird Jailbird { get; } + + /// + /// Gets the associated with the charged Jailbird. + /// + public Item Item => Jailbird; + + /// + /// Gets or sets a value indicating whether the Jailbird is allowed to attack after charging. + /// + public bool IsAllowed { get; set; } + } +} diff --git a/EXILED/Exiled.Events/Handlers/Item.cs b/EXILED/Exiled.Events/Handlers/Item.cs index d8153a586e..af9dea76b5 100644 --- a/EXILED/Exiled.Events/Handlers/Item.cs +++ b/EXILED/Exiled.Events/Handlers/Item.cs @@ -44,10 +44,15 @@ public static class Item public static Event Swinging { get; set; } = new(); /// - /// Invoked before a is charged. + /// Invoked when a starts charging. /// public static Event ChargingJailbird { get; set; } = new(); + /// + /// Invoked after a finishes charging. + /// + public static Event JailbirdChargeComplete { get; set; } = new(); + /// /// Invoked before a radio pickup is draining battery. /// @@ -102,11 +107,17 @@ public static class Item public static void OnSwinging(SwingingEventArgs ev) => Swinging.InvokeSafely(ev); /// - /// Called before a is charged. + /// Called before a that is being charged. /// /// The instance. public static void OnChargingJailbird(ChargingJailbirdEventArgs ev) => ChargingJailbird.InvokeSafely(ev); + /// + /// Called after a finish charging. + /// + /// The instance. + public static void OnJailbirdChargeComplete(JailbirdChargeCompleteEventArgs ev) => JailbirdChargeComplete.InvokeSafely(ev); + /// /// Called before radio pickup is draining battery. /// diff --git a/EXILED/Exiled.Events/Patches/Events/Item/JailbirdPatch.cs b/EXILED/Exiled.Events/Patches/Events/Item/JailbirdPatch.cs index 8ffa6e06e4..653afada85 100644 --- a/EXILED/Exiled.Events/Patches/Events/Item/JailbirdPatch.cs +++ b/EXILED/Exiled.Events/Patches/Events/Item/JailbirdPatch.cs @@ -27,6 +27,7 @@ namespace Exiled.Events.Patches.Events.Item /// [EventPatch(typeof(Item), nameof(Item.Swinging))] [EventPatch(typeof(Item), nameof(Item.ChargingJailbird))] + [EventPatch(typeof(Item), nameof(Item.JailbirdChargeComplete))] [HarmonyPatch(typeof(JailbirdItem), nameof(JailbirdItem.ServerProcessCmd))] internal static class JailbirdPatch { @@ -83,7 +84,7 @@ private static bool HandleJailbird(JailbirdItem instance, JailbirdMessageType me return ev.IsAllowed; } - case JailbirdMessageType.ChargeStarted: + case JailbirdMessageType.ChargeLoadTriggered: { ChargingJailbirdEventArgs ev = new(instance.Owner, instance); @@ -91,6 +92,19 @@ private static bool HandleJailbird(JailbirdItem instance, JailbirdMessageType me if (ev.IsAllowed) return true; + ev.Player.RemoveHeldItem(destroy: false); + ev.Player.CurrentItem = ev.Item; + return false; + } + + case JailbirdMessageType.ChargeStarted: + { + JailbirdChargeCompleteEventArgs ev = new(instance.Owner, instance); + + Item.OnJailbirdChargeComplete(ev); + if (ev.IsAllowed) + return true; + ev.Player.RemoveHeldItem(destroy: false); ev.Player.AddItem(ev.Item); return false; From dfd76ea29f6080e556440e9cf1bf92980562ae6c Mon Sep 17 00:00:00 2001 From: Yamato Date: Tue, 8 Jul 2025 07:07:07 +0200 Subject: [PATCH 42/56] 9.6.3 --- EXILED/EXILED.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXILED/EXILED.props b/EXILED/EXILED.props index 9dfffe99fd..02d86cf5cc 100644 --- a/EXILED/EXILED.props +++ b/EXILED/EXILED.props @@ -15,7 +15,7 @@ - 9.6.2 + 9.6.3 false From 154ba8ded2e132483034baa58a0c9f818d3ed38b Mon Sep 17 00:00:00 2001 From: Bolton <48883340+BoltonDev@users.noreply.github.com> Date: Sun, 13 Jul 2025 15:01:32 +0200 Subject: [PATCH 43/56] fix: release workflow --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e0c018e25a..c4edbf2994 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ defaults: env: EXILED_REFERENCES_URL: https://Exmod-team.github.io/SL-References/Dev.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References - EXILED_DLL_ARCHIVER_URL: https://github.com/ExMod-Team/EXILED-DLL-Archiver/releases/latest/EXILED-DLL-Archiver.exe + EXILED_DLL_ARCHIVER_URL: https://github.com/ExMod-Team/EXILED-DLL-Archiver/releases/latest/download/EXILED-DLL-Archiver.exe jobs: build: From cbc5a25abeb04b1bfdb5bd630587ecf32eedcffc Mon Sep 17 00:00:00 2001 From: Yamato Date: Thu, 17 Jul 2025 20:59:54 +0200 Subject: [PATCH 44/56] why bruh nw add enum value in the middle --- EXILED/Exiled.API/Enums/SpawnReason.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/EXILED/Exiled.API/Enums/SpawnReason.cs b/EXILED/Exiled.API/Enums/SpawnReason.cs index 4ef67f1742..3bde3457df 100644 --- a/EXILED/Exiled.API/Enums/SpawnReason.cs +++ b/EXILED/Exiled.API/Enums/SpawnReason.cs @@ -57,6 +57,11 @@ public enum SpawnReason : byte // TOTO: Remove this file and use Basegame /// Destroyed, + /// + /// The player was dead and is respawning in a mini-wave. + /// + RespawnMiniwave, + /// /// The user has been spawn by the usage of an Item. /// From 3faecbbe9ffdd3b717400894042001e44c09fdb9 Mon Sep 17 00:00:00 2001 From: Yamato Date: Thu, 31 Jul 2025 18:13:21 +0200 Subject: [PATCH 45/56] Return LateJoin --- EXILED/Exiled.CustomItems/API/Features/CustomItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs index cf6d937b8b..fa39569e0a 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs @@ -937,7 +937,7 @@ protected virtual void ShowSelectedMessage(Player player) private void OnInternalOwnerChangingRole(ChangingRoleEventArgs ev) { - if (ev.Reason is SpawnReason.Escaped or SpawnReason.Destroyed) + if (ev.Reason is SpawnReason.Escaped or SpawnReason.Destroyed or SpawnReason.LateJoin) return; foreach (Item item in ev.Player.Items.ToList()) From 151bed1ce903a66454a063875437c2e0b81eec9f Mon Sep 17 00:00:00 2001 From: Yamato Date: Thu, 31 Jul 2025 18:15:32 +0200 Subject: [PATCH 46/56] Partially Revert "fix: Scale fix (#571)" This reverts commit b896a73a32decb117268090f23ef29bebcf0322c. Because of NW making crash on Player --- EXILED/Exiled.API/Features/Player.cs | 46 ++++++++++++------- .../API/Features/CustomRole.cs | 3 +- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 779982d2fb..323b4ec463 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -699,7 +699,7 @@ public ScpSpawnPreferences.SpawnPreferences ScpPreferences public Vector3 Scale { get => ReferenceHub.transform.localScale; - set => SetScale(value); + set => SetScale(value, List); } /// @@ -2065,16 +2065,6 @@ public void Disconnect(string reason = null) => /// public void ResetStamina() => Stamina = StaminaStat.MaxValue; - /// - /// Sets the scale of a player on the server side. - /// - /// The scale to set. - public void SetScale(Vector3 scale) - { - ReferenceHub.transform.localScale = scale; - new SyncedScaleMessages.ScaleMessage(scale, ReferenceHub).SendToAuthenticated(); - } - /// /// Sets the scale of a player on the server side. /// @@ -2082,8 +2072,20 @@ public void SetScale(Vector3 scale) /// Who should see the updated scale. public void SetScale(Vector3 scale, IEnumerable viewers) { - ReferenceHub.transform.localScale = scale; - new SyncedScaleMessages.ScaleMessage(scale, ReferenceHub).SendToHubsConditionally(x => x != null && viewers.Contains(Get(x))); + if (scale == Scale) + return; + + try + { + ReferenceHub.transform.localScale = scale; + + foreach (Player target in viewers) + Server.SendSpawnMessage?.Invoke(null, new object[] { NetworkIdentity, target.Connection }); + } + catch (Exception exception) + { + Log.Error($"{nameof(SetScale)} error: {exception}"); + } } /// @@ -2093,9 +2095,21 @@ public void SetScale(Vector3 scale, IEnumerable viewers) /// Who should see the fake scale. public void SetFakeScale(Vector3 fakeScale, IEnumerable viewers) { - SyncedScaleMessages.ScaleMessage scaleMessage = new(fakeScale, ReferenceHub); - foreach (Player player in viewers) - player.Connection.Send(scaleMessage, 0); + Vector3 currentScale = Scale; + + try + { + ReferenceHub.transform.localScale = fakeScale; + + foreach (Player target in viewers) + Server.SendSpawnMessage.Invoke(null, new object[] { NetworkIdentity, target.Connection }); + + ReferenceHub.transform.localScale = currentScale; + } + catch (Exception ex) + { + Log.Error($"{nameof(SetFakeScale)}: {ex}"); + } } /// diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 895b483b2e..db5e599cd3 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -564,7 +564,7 @@ public virtual void AddRole(Player player) Log.Debug($"{Name}: Setting health values."); player.Health = MaxHealth; player.MaxHealth = MaxHealth; - Timing.CallDelayed(0.1f, () => player.Scale = Scale); // To fix : remove the delay in 14.1.2 once the crash issue is resolved + player.Scale = Scale; if (Gravity.HasValue && player.Role is FpcRole fpcRole) fpcRole.Gravity = Gravity.Value; Vector3 position = GetSpawnPosition(); @@ -627,6 +627,7 @@ public virtual void RemoveRole(Player player) TrackedPlayers.Remove(player); player.CustomInfo = string.Empty; player.InfoArea |= PlayerInfoArea.Role | PlayerInfoArea.Nickname; + player.Scale = Vector3.one; if (CustomAbilities is not null) { foreach (CustomAbility ability in CustomAbilities) From 5a74a1bb4dc09fc7ef00a643cf8d417fc80c96fc Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Thu, 31 Jul 2025 19:16:49 +0300 Subject: [PATCH 47/56] feat: Add Model (#595) Update FpcRole.cs --- EXILED/Exiled.API/Features/Roles/FpcRole.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs index d54201ff0e..2abfc50377 100644 --- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs +++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs @@ -67,6 +67,15 @@ public RelativePosition ClientRelativePosition set => FirstPersonController.FpcModule.Motor.ReceivedPosition = value; } + /// + /// Gets or sets the associated with the player. + /// + public CharacterModel Model + { + get => FirstPersonController.FpcModule.CharacterModelInstance; + set => FirstPersonController.FpcModule.CharacterModelInstance = value; + } + /// /// Gets or sets the player's gravity. /// @@ -305,4 +314,4 @@ public void ResetStamina(bool multipliers = false) StaminaRegenMultiplier = 1f; } } -} \ No newline at end of file +} From 4296fa96dbee7ef55deb738b015ed5f4b9c9931c Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Thu, 31 Jul 2025 19:17:58 +0300 Subject: [PATCH 48/56] feat: New Scp049 Finishing Sense Event (#559) * Create FinishingSenseEventArgs.cs * Add Finishing Sense Handler * Create FinishingSense.cs --------- Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com> --- .../Scp049/FinishingSenseEventArgs.cs | 66 +++++ EXILED/Exiled.Events/Handlers/Scp049.cs | 13 +- .../Patches/Events/Scp049/FinishingSense.cs | 258 ++++++++++++++++++ 3 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 EXILED/Exiled.Events/EventArgs/Scp049/FinishingSenseEventArgs.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Scp049/FinishingSense.cs diff --git a/EXILED/Exiled.Events/EventArgs/Scp049/FinishingSenseEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp049/FinishingSenseEventArgs.cs new file mode 100644 index 0000000000..43baf5987b --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp049/FinishingSenseEventArgs.cs @@ -0,0 +1,66 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp049 +{ + using Exiled.API.Features; + using Exiled.API.Features.Roles; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information before SCP-049 finishes his sense ability. + /// + public class FinishingSenseEventArgs : IScp049Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The SCP-049 instance triggering the event. + /// + /// + /// The player targeted by SCP-049's Sense ability. + /// + /// + /// The time in seconds before the Sense ability can be used again. + /// + /// + /// Specifies whether the Sense effect is allowed to finish. + /// + /// + public FinishingSenseEventArgs(ReferenceHub scp049, ReferenceHub target, double cooldowntime, bool isAllowed = true) + { + Player = Player.Get(scp049); + Scp049 = Player.Role.As(); + Target = Player.Get(target); + IsAllowed = isAllowed; + CooldownTime = cooldowntime; + } + + /// + public Scp049Role Scp049 { get; } + + /// + /// Gets the player who is controlling SCP-049. + /// + public Player Player { get; } + + /// + /// Gets the player who is SCP-049's active target. Can be null. + /// + public Player Target { get; } + + /// + /// Gets or sets the cooldown duration of the Sense ability. + /// + public double CooldownTime { get; set; } + + /// + /// Gets or sets a value indicating whether the server will finishing or not finishing 049 Sense Ability. + /// + public bool IsAllowed { get; set; } + } +} diff --git a/EXILED/Exiled.Events/Handlers/Scp049.cs b/EXILED/Exiled.Events/Handlers/Scp049.cs index 94bb965746..f4a2010794 100644 --- a/EXILED/Exiled.Events/Handlers/Scp049.cs +++ b/EXILED/Exiled.Events/Handlers/Scp049.cs @@ -32,6 +32,11 @@ public static class Scp049 /// public static Event ActivatingSense { get; set; } = new(); + /// + /// Invoked before SCP-049 finish the good sense of the doctor ability. + /// + public static Event FinishingSense { get; set; } = new(); + /// /// Invoked before SCP-049 uses the call ability. /// @@ -60,6 +65,12 @@ public static class Scp049 /// The instance. public static void OnActivatingSense(ActivatingSenseEventArgs ev) => ActivatingSense.InvokeSafely(ev); + /// + /// Called before SCP-049 finish the good sense of the doctor ability. + /// + /// The instance. + public static void OnFinishingSense(FinishingSenseEventArgs ev) => FinishingSense.InvokeSafely(ev); + /// /// Called before SCP-049 starts the call ability. /// @@ -72,4 +83,4 @@ public static class Scp049 /// The instance. public static void OnAttacking(AttackingEventArgs ev) => Attacking.InvokeSafely(ev); } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.Events/Patches/Events/Scp049/FinishingSense.cs b/EXILED/Exiled.Events/Patches/Events/Scp049/FinishingSense.cs new file mode 100644 index 0000000000..9a63f16e7e --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Scp049/FinishingSense.cs @@ -0,0 +1,258 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Scp049 +{ +#pragma warning disable SA1402 // File may only contain a single type + using System.Collections.Generic; + using System.Reflection.Emit; + + using API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Scp049; + using HarmonyLib; + + using PlayerRoles.PlayableScps.Scp049; + using PlayerRoles.Subroutines; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Scp049), nameof(Handlers.Scp049.FinishingSense))] + [HarmonyPatch(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.ServerLoseTarget))] + internal class FinishingSense + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + LocalBuilder ev = generator.DeclareLocal(typeof(FinishingSenseEventArgs)); + Label retLabel = generator.DefineLabel(); + + newInstructions.InsertRange(0, new CodeInstruction[] + { + // this.Owner + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.Owner))), + + // this.Target + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.Target))), + + // Scp049SenseAbility.TargetLostCooldown + new(OpCodes.Ldc_R8, (double)Scp049SenseAbility.TargetLostCooldown), + + // true (IsAllowed) + new(OpCodes.Ldc_I4_1), + + // FinishingSenseEventArgs ev = new FinishingSenseEventArgs(ReferenceHub, ReferenceHub, double, bool) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(FinishingSenseEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev.LocalIndex), + + // Handlers.Scp049.OnFinishingSense(ev); + new(OpCodes.Call, Method(typeof(Handlers.Scp049), nameof(Handlers.Scp049.OnFinishingSense))), + + // if (!ev.IsAllowed) return; + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(FinishingSenseEventArgs), nameof(FinishingSenseEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, retLabel), + }); + + // this.Cooldown.Trigger((double)Scp049SenseAbility.TargetLostCooldown) index + int index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldc_R8 && (double)i.operand == Scp049SenseAbility.TargetLostCooldown); + + // Replace "this.Cooldown.Trigger((double)Scp049SenseAbility.ReducedCooldown)" with "this.Cooldown.Trigger((double)ev.cooldowntime)" + newInstructions.RemoveAt(index); + newInstructions.InsertRange(index, new CodeInstruction[] + { + new(OpCodes.Ldloc, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(FinishingSenseEventArgs), nameof(FinishingSenseEventArgs.CooldownTime))), + }); + + newInstructions[newInstructions.Count - 1].labels.Add(retLabel); + + for (int i = 0; i < newInstructions.Count; i++) + yield return newInstructions[i]; + + ListPool.Pool.Return(newInstructions); + } + } + + /// + /// Patches . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Scp049), nameof(Handlers.Scp049.FinishingSense))] + [HarmonyPatch(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.ServerProcessKilledPlayer))] + internal class FinishingSense2 + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + LocalBuilder ev = generator.DeclareLocal(typeof(FinishingSenseEventArgs)); + + // Continue label for isAllowed check + Label retLabel = generator.DefineLabel(); + + // this.Cooldown.Trigger(Scp049SenseAbility.BaseCooldown) index + int offset = -2; + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Ldc_R8 && (double)i.operand == Scp049SenseAbility.BaseCooldown) + offset; + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // this.Owner + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.Owner))), + + // this.Target + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.Target))), + + // double CooldownTime = Scp049SenseAbility.BaseCooldown; + new(OpCodes.Ldc_R8, (double)Scp049SenseAbility.BaseCooldown), + + // true (IsAllowed) + new(OpCodes.Ldc_I4_1), + + // FinishingSenseEventArgs ev = new FinishingSenseEventArgs(ReferenceHub, ReferenceHub, double, bool) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(FinishingSenseEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev.LocalIndex), + + // Handlers.Scp049.OnFinishingSense(ev); + new(OpCodes.Call, Method(typeof(Handlers.Scp049), nameof(Handlers.Scp049.OnFinishingSense))), + + // if (!ev.IsAllowed) return; + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(FinishingSenseEventArgs), nameof(FinishingSenseEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, retLabel), + }); + + // this.Cooldown.Trigger(Scp049SenseAbility.BaseCooldown) index + index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldc_R8 && (double)i.operand == Scp049SenseAbility.BaseCooldown); + + newInstructions.RemoveAt(index); + newInstructions.InsertRange(index, new CodeInstruction[] + { + new(OpCodes.Ldloc, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(FinishingSenseEventArgs), nameof(FinishingSenseEventArgs.CooldownTime))), + }); + + newInstructions[newInstructions.Count - 1].labels.Add(retLabel); + + for (int i = 0; i < newInstructions.Count; i++) + yield return newInstructions[i]; + + ListPool.Pool.Return(newInstructions); + } + } + + /// + /// Patches . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Scp049), nameof(Handlers.Scp049.FinishingSense))] + [HarmonyPatch(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.ServerProcessCmd), new[] { typeof(Mirror.NetworkReader) })] + internal class FinishingSense3 + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + LocalBuilder ev = generator.DeclareLocal(typeof(FinishingSenseEventArgs)); + LocalBuilder isAbilityActive = generator.DeclareLocal(typeof(bool)); + + Label skipactivatingsense = generator.DefineLabel(); + Label continueLabel = generator.DefineLabel(); + Label allowed = generator.DefineLabel(); + + newInstructions.InsertRange(0, new CodeInstruction[] + { + // isAbilityActive = this.HasTarget; + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.HasTarget))), + new(OpCodes.Stloc, isAbilityActive.LocalIndex), + }); + + // this.Cooldown.Trigger(2.5) index + int offset = -1; + int index = newInstructions.FindIndex(i => + i.opcode == OpCodes.Ldfld && + i.operand == (object)Field(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.Cooldown))) + offset; + + newInstructions[index].labels.Add(continueLabel); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // Skip if the ability is not active and this is an unsuccessful attempt + new(OpCodes.Ldloc, isAbilityActive.LocalIndex), + new(OpCodes.Brfalse_S, continueLabel), + + // this.Owner; + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.Owner))), + + // this.Target; + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.Target))), + + // Scp049SenseAbility.AttemptFailCooldown; + new(OpCodes.Ldc_R8, (double)Scp049SenseAbility.AttemptFailCooldown), + + // true (IsAllowed) + new(OpCodes.Ldc_I4_1), + + // FinishingSenseEventArgs ev = new FinishingSenseEventArgs(ReferenceHub, ReferenceHub, double, bool) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(FinishingSenseEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev.LocalIndex), + + // Handlers.Scp049.OnFinishingSense(ev); + new(OpCodes.Call, Method(typeof(Handlers.Scp049), nameof(Handlers.Scp049.OnFinishingSense))), + + // if (!ev.IsAllowed) return; + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(FinishingSenseEventArgs), nameof(FinishingSenseEventArgs.IsAllowed))), + new(OpCodes.Brtrue_S, allowed), + + // If not allowed, set has target to true so as not to break the sense ability + // this.HasTarget = true; + new(OpCodes.Ldarg_0), + new(OpCodes.Ldc_I4_1), + new(OpCodes.Callvirt, PropertySetter(typeof(Scp049SenseAbility), nameof(Scp049SenseAbility.HasTarget))), + + // return; + new(OpCodes.Ret), + + // this.Cooldown.Trigger(ev.cooldown.time) + new CodeInstruction(OpCodes.Ldarg_0).WithLabels(allowed), + new(OpCodes.Ldloc, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(FinishingSenseEventArgs), nameof(FinishingSenseEventArgs.CooldownTime))), + new(OpCodes.Callvirt, Method(typeof(AbilityCooldown), nameof(AbilityCooldown.Trigger), new[] { typeof(double) })), + + new(OpCodes.Br_S, skipactivatingsense), + }); + + offset = -2; + index = newInstructions.FindIndex(i => + i.opcode == OpCodes.Call && + i.operand == (object)Method(typeof(SubroutineBase), nameof(SubroutineBase.ServerSendRpc), new[] { typeof(bool) })) + offset; + + newInstructions[index].labels.Add(skipactivatingsense); + + for (int i = 0; i < newInstructions.Count; i++) + yield return newInstructions[i]; + + ListPool.Pool.Return(newInstructions); + } + } +} From c782ee288d25bbc0c4db42aa433ba83d0b4215a4 Mon Sep 17 00:00:00 2001 From: "@Someone" <45270312+Someone-193@users.noreply.github.com> Date: Thu, 31 Jul 2025 12:18:09 -0400 Subject: [PATCH 49/56] feat: RemovingTarget event for 096 (#576) * fix KeybindSetting and RoundEnd transpiler I think it all works, I ran server and no errors, I got on and ended round and no errors * Fix Scale (ScaleController is mid) Fix ChangingLeverStatus event I think these work * Add event (was painful cuz of previous shenanigans) --- .../Scp096/RemovingTargetEventArgs.cs | 59 +++++++ EXILED/Exiled.Events/Handlers/Scp096.cs | 11 ++ .../Patches/Events/Scp096/RemovingTarget.cs | 149 ++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 EXILED/Exiled.Events/EventArgs/Scp096/RemovingTargetEventArgs.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Scp096/RemovingTarget.cs diff --git a/EXILED/Exiled.Events/EventArgs/Scp096/RemovingTargetEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp096/RemovingTargetEventArgs.cs new file mode 100644 index 0000000000..1dc1934942 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp096/RemovingTargetEventArgs.cs @@ -0,0 +1,59 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp096 +{ + using API.Features; + + using Interfaces; + + using Scp096Role = API.Features.Roles.Scp096Role; + + /// + /// Contains all information after removing a target from SCP-096. + /// + public class RemovingTargetEventArgs : IScp096Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public RemovingTargetEventArgs(Player scp096, Player target, bool isAllowed = true) + { + Player = scp096; + Scp096 = scp096.Role.As(); + Target = target; + IsAllowed = isAllowed; + } + + /// + /// Gets the that is controlling SCP-096. + /// + public Player Player { get; } + + /// + public Scp096Role Scp096 { get; } + + /// + /// Gets the being removed as a target. + /// + public Player Target { get; } + + /// + /// Gets or sets a value indicating whether the target is allowed to be removed. + /// + public bool IsAllowed { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Scp096.cs b/EXILED/Exiled.Events/Handlers/Scp096.cs index 76a6052fb8..7ddf935fb5 100644 --- a/EXILED/Exiled.Events/Handlers/Scp096.cs +++ b/EXILED/Exiled.Events/Handlers/Scp096.cs @@ -32,6 +32,11 @@ public static class Scp096 /// public static Event AddingTarget { get; set; } = new(); + /// + /// Invoked before removing a target from SCP-096. + /// + public static Event RemovingTarget { get; set; } = new(); + /// /// Invoked before SCP-096 begins prying open a gate. /// @@ -65,6 +70,12 @@ public static class Scp096 /// The instance. public static void OnAddingTarget(AddingTargetEventArgs ev) => AddingTarget.InvokeSafely(ev); + /// + /// Called before removing a target from SCP-096. + /// + /// The instance. + public static void OnRemovingTarget(RemovingTargetEventArgs ev) => RemovingTarget.InvokeSafely(ev); + /// /// Called before SCP-096 begins prying open a gate. /// diff --git a/EXILED/Exiled.Events/Patches/Events/Scp096/RemovingTarget.cs b/EXILED/Exiled.Events/Patches/Events/Scp096/RemovingTarget.cs new file mode 100644 index 0000000000..869988bda6 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Scp096/RemovingTarget.cs @@ -0,0 +1,149 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Scp096 +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection.Emit; + + using API.Features; + using API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Scp096; + using HarmonyLib; + using PlayerRoles.PlayableScps.Scp096; + using PlayerRoles.Subroutines; + + using static HarmonyLib.AccessTools; + + /// + /// Patches and . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Scp096), nameof(Handlers.Scp096.RemovingTarget))] + [HarmonyPatch(typeof(Scp096TargetsTracker))] + internal static class RemovingTarget + { + [HarmonyPatch(nameof(Scp096TargetsTracker.RemoveTarget))] + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label retFalseLabel = generator.DefineLabel(); + Label runLabel = generator.DefineLabel(); + + // make game check contains instead of removing then forcibly running our event (so no spam event calls and is still deniable) + newInstructions.Find(instruction => instruction.Calls(Method(typeof(HashSet), nameof(HashSet.Remove)))).operand = Method(typeof(HashSet), nameof(HashSet.Contains)); + + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) - 1; + + newInstructions[index].WithLabels(retFalseLabel); + + index -= 1; + + // integrate our condition into first if statement + newInstructions.RemoveAt(index); + + newInstructions.InsertRange( + index, + new CodeInstruction[] + { + // integrate our condition into first if statement + new(OpCodes.Brfalse, retFalseLabel), + + // Player.Get(base.Owner) + new(OpCodes.Ldarg_0), + new(OpCodes.Call, PropertyGetter(typeof(StandardSubroutine), nameof(StandardSubroutine.Owner))), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), + + // Player.Get(target) + new(OpCodes.Ldarg_1), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), + + // true + new(OpCodes.Ldc_I4_1), + + // RemovingTargetEventArgs ev = new(scp096, target, isAllowed) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RemovingTargetEventArgs))[0]), + new(OpCodes.Dup), + + // Handlers.Scp096.OnRemovingTarget(ev) + new(OpCodes.Call, Method(typeof(Handlers.Scp096), nameof(Handlers.Scp096.OnRemovingTarget))), + + // if (!ev.IsAllowed) + // return; + new(OpCodes.Callvirt, PropertyGetter(typeof(RemovingTargetEventArgs), nameof(RemovingTargetEventArgs.IsAllowed))), + new(OpCodes.Brtrue, runLabel), + }); + + index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + 1; + + // if allowed, remove target + newInstructions.InsertRange(index, new[] + { + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]).WithLabels(runLabel), + new(OpCodes.Ldfld, Field(typeof(Scp096TargetsTracker), nameof(Scp096TargetsTracker.Targets))), + new(OpCodes.Ldarg_1), + new(OpCodes.Callvirt, Method(typeof(HashSet), nameof(HashSet.Remove))), + new(OpCodes.Pop), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + + [HarmonyPatch(nameof(Scp096TargetsTracker.ClearAllTargets))] + [HarmonyTranspiler] + private static IEnumerable Transpiler2(IEnumerable instructions) + { + List newInstructions = ListPool.Pool.Get(instructions); + + object continueLabel = newInstructions.Find(instruction => instruction.opcode == OpCodes.Br_S).operand; + + const int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Stloc_1) + offset; + + newInstructions.InsertRange( + index, + new[] + { + // Player.Get(base.Owner) + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + new(OpCodes.Call, PropertyGetter(typeof(StandardSubroutine), nameof(StandardSubroutine.Owner))), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), + + // Player.Get(target) + new(OpCodes.Ldloc_1), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), + + // true + new(OpCodes.Ldc_I4_1), + + // RemovingTargetEventArgs ev = new(scp096, target, isAllowed) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RemovingTargetEventArgs))[0]), + new(OpCodes.Dup), + + // Handlers.Scp096.OnRemovingTarget(ev) + new(OpCodes.Call, Method(typeof(Handlers.Scp096), nameof(Handlers.Scp096.OnRemovingTarget))), + + // if (!ev.IsAllowed) + // continue; + new(OpCodes.Callvirt, PropertyGetter(typeof(RemovingTargetEventArgs), nameof(RemovingTargetEventArgs.IsAllowed))), + new(OpCodes.Brfalse, continueLabel), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file From b3564e126a15fa6c3d90e2ac0f47275a471751af Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Thu, 31 Jul 2025 19:18:26 +0300 Subject: [PATCH 50/56] fix: Escaping Exiled and LabAPI bug different way (#589) * . * . --- EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs | 2 +- .../Patches/Events/Player/EscapingAndEscaped.cs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs index 532c40f2f0..9e80978aa2 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs @@ -39,7 +39,7 @@ public EscapingEventArgs(ReferenceHub referenceHub, RoleTypeId newRole, EscapeSc Player = Player.Get(referenceHub); NewRole = newRole; EscapeScenario = escapeScenario; - IsAllowed = true; + IsAllowed = escapeScenario is not EscapeScenario.None; } /// diff --git a/EXILED/Exiled.Events/Patches/Events/Player/EscapingAndEscaped.cs b/EXILED/Exiled.Events/Patches/Events/Player/EscapingAndEscaped.cs index 72bade7906..5b778fb0c9 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/EscapingAndEscaped.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/EscapingAndEscaped.cs @@ -13,14 +13,13 @@ namespace Exiled.Events.Patches.Events.Player using System.Collections.Generic; using System.Reflection.Emit; - using API.Enums; using API.Features; using API.Features.Pools; using EventArgs.Player; using Exiled.API.Features.Roles; using Exiled.Events.Attributes; using HarmonyLib; - using PlayerRoles.FirstPersonControl; + using LabApi.Events.Arguments.PlayerEvents; using static HarmonyLib.AccessTools; @@ -41,8 +40,8 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Newobj) + offset; + int offset = 2; + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Callvirt && i.operand == (object)PropertyGetter(typeof(PlayerEscapingEventArgs), nameof(PlayerEscapingEventArgs.EscapeScenario))) + offset; newInstructions.InsertRange( index, From 1c2792a7badc4e54730b644ebf74b4a75e31238a Mon Sep 17 00:00:00 2001 From: R2kip <56793105+R2kip@users.noreply.github.com> Date: Thu, 31 Jul 2025 19:18:57 +0300 Subject: [PATCH 51/56] feat: Add ragdoll to died event (#507) * Add ragdoll to died event * oops * oops 2x :) --- .../EventArgs/Player/DiedEventArgs.cs | 14 ++++++++++++-- .../Patches/Events/Player/DyingAndDied.cs | 11 ++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/EXILED/Exiled.Events/EventArgs/Player/DiedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/DiedEventArgs.cs index 26b6a26312..24e91e6870 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/DiedEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/DiedEventArgs.cs @@ -13,6 +13,7 @@ namespace Exiled.Events.EventArgs.Player using Interfaces; using PlayerRoles; + using PlayerRoles.Ragdolls; using CustomAttackerHandler = API.Features.DamageHandlers.AttackerDamageHandler; using DamageHandlerBase = PlayerStatsSystem.DamageHandlerBase; @@ -20,7 +21,7 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information after a player dies. /// - public class DiedEventArgs : IPlayerEvent, IAttackerEvent + public class DiedEventArgs : IPlayerEvent, IAttackerEvent, IRagdollEvent { /// /// Initializes a new instance of the class. @@ -32,12 +33,16 @@ public class DiedEventArgs : IPlayerEvent, IAttackerEvent /// /// /// - public DiedEventArgs(Player target, RoleTypeId targetOldRole, DamageHandlerBase damageHandler) + /// + /// + /// + public DiedEventArgs(Player target, RoleTypeId targetOldRole, DamageHandlerBase damageHandler, BasicRagdoll ragdoll) { DamageHandler = new CustomDamageHandler(target, damageHandler); Attacker = DamageHandler.BaseIs(out CustomAttackerHandler attackerDamageHandler) ? attackerDamageHandler.Attacker : null; Player = target; TargetOldRole = targetOldRole; + Ragdoll = Ragdoll.Get(ragdoll); } /// @@ -59,5 +64,10 @@ public DiedEventArgs(Player target, RoleTypeId targetOldRole, DamageHandlerBase /// Gets the attacker. /// public Player Attacker { get; } + + /// + /// Gets ragdoll of the dead player. + /// + public Ragdoll Ragdoll { get; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Player/DyingAndDied.cs b/EXILED/Exiled.Events/Patches/Events/Player/DyingAndDied.cs index 9b4c29b3b1..489732cf08 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/DyingAndDied.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/DyingAndDied.cs @@ -19,6 +19,7 @@ namespace Exiled.Events.Patches.Events.Player using HarmonyLib; using PlayerRoles; + using PlayerRoles.Ragdolls; using PlayerStatsSystem; @@ -41,6 +42,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable x.opcode == OpCodes.Pop); + + newInstructions[index] = new CodeInstruction(OpCodes.Stloc, ragdoll.LocalIndex); + newInstructions.InsertRange( newInstructions.Count - 1, new CodeInstruction[] @@ -90,6 +96,9 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions); } } -} \ No newline at end of file +} From 0778174e0d54c31eb7f97e957245d4d2a95306c4 Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Thu, 31 Jul 2025 19:20:41 +0300 Subject: [PATCH 52/56] feat: Generic damage handler add new value (#561) * Clean * Update GenericDamageHandler.cs * Cleanup * Remove BreakingChange * Fix Ambiguous when compiling --------- Co-authored-by: Yamato Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com> --- EXILED/Exiled.API/Enums/DamageType.cs | 5 ++--- .../DamageHandlers/GenericDamageHandler.cs | 8 ++++++-- EXILED/Exiled.API/Features/Player.cs | 14 +++++++++++++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/EXILED/Exiled.API/Enums/DamageType.cs b/EXILED/Exiled.API/Enums/DamageType.cs index ae93c5c020..e1054e1f33 100644 --- a/EXILED/Exiled.API/Enums/DamageType.cs +++ b/EXILED/Exiled.API/Enums/DamageType.cs @@ -15,8 +15,7 @@ namespace Exiled.API.Enums /// Identifiers for types of damage. /// /// - /// - /// + /// /// public enum DamageType { @@ -275,4 +274,4 @@ public enum DamageType /// Scp127, } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs index bd858b3447..4d74256cca 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs @@ -12,6 +12,7 @@ namespace Exiled.API.Features.DamageHandlers using Footprinting; using Items; + using PlayerRoles; using PlayerRoles.PlayableScps.Scp096; using PlayerRoles.PlayableScps.Scp939; @@ -29,6 +30,7 @@ public class GenericDamageHandler : CustomReasonDamageHandler private Player player; private DamageType damageType; private DamageHandlerBase.CassieAnnouncement customCassieAnnouncement; + private bool overrideCassieForAllRole; /// /// Initializes a new instance of the class. @@ -40,11 +42,13 @@ public class GenericDamageHandler : CustomReasonDamageHandler /// Damage type. /// Custom cassie announcment. /// Text to provide to player death screen. - public GenericDamageHandler(Player player, Player attacker, float damage, DamageType damageType, DamageHandlerBase.CassieAnnouncement cassieAnnouncement, string damageText = null) + /// Whether to play Cassie for non-SCPs as well. + public GenericDamageHandler(Player player, Player attacker, float damage, DamageType damageType, DamageHandlerBase.CassieAnnouncement cassieAnnouncement, string damageText = null, bool overrideCassieForAllRole = false) : base(DamageTextDefault) { this.player = player; this.damageType = damageType; + this.overrideCassieForAllRole = overrideCassieForAllRole; cassieAnnouncement ??= DamageHandlerBase.CassieAnnouncement.Default; customCassieAnnouncement = cassieAnnouncement; @@ -237,7 +241,7 @@ public override HandlerOutput ApplyDamage(ReferenceHub ply) HandlerOutput output = base.ApplyDamage(ply); if (output is HandlerOutput.Death) { - if (customCassieAnnouncement?.Announcement != null) + if (customCassieAnnouncement?.Announcement != null && (overrideCassieForAllRole || ply.IsSCP())) { Cassie.Message(customCassieAnnouncement.Announcement); } diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 323b4ec463..1689744773 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -2149,9 +2149,21 @@ public void Hurt(Player attacker, float amount, DamageType damageType = DamageTy /// The of the damage dealt. /// The cassie announcement to make if the damage kills the player. /// The death text to appear on screen. - public void Hurt(Player attacker, float amount, DamageType damageType = DamageType.Unknown, CassieAnnouncement cassieAnnouncement = null, string deathText = null) => + public void Hurt(Player attacker, float amount, DamageType damageType, CassieAnnouncement cassieAnnouncement, string deathText) => Hurt(new GenericDamageHandler(this, attacker, amount, damageType, cassieAnnouncement, deathText)); + /// + /// Hurts the player. + /// + /// The attacking player. + /// The amount of damage to deal. + /// The of the damage dealt. + /// The cassie announcement to make if the damage kills the player. + /// The death text to appear on screen. + /// Whether to play Cassie for non-SCPs as well. + public void Hurt(Player attacker, float amount, DamageType damageType, CassieAnnouncement cassieAnnouncement, string deathText, bool overrideCassieForAllRole) => + Hurt(new GenericDamageHandler(this, attacker, amount, damageType, cassieAnnouncement, deathText, overrideCassieForAllRole)); + /// /// Hurts the player. /// From 5e50a6e6f047dfd714a6bc60d86cf722b8c84e78 Mon Sep 17 00:00:00 2001 From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com> Date: Fri, 1 Aug 2025 01:21:37 +0900 Subject: [PATCH 53/56] feat: Add Wave related functions to Respawn (#536) Update Respawn.cs From 7c68ea72ea0d8f12994081ff84ad6347d9066c2d Mon Sep 17 00:00:00 2001 From: Yamato Date: Thu, 31 Jul 2025 18:40:37 +0200 Subject: [PATCH 54/56] Fix using --- EXILED/Exiled.API/Features/Roles/FpcRole.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs index 2abfc50377..57ba6bcf85 100644 --- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs +++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs @@ -8,12 +8,11 @@ namespace Exiled.API.Features.Roles { using System.Collections.Generic; - using System.Reflection; using Exiled.API.Features.Pools; - using HarmonyLib; using PlayerRoles; using PlayerRoles.FirstPersonControl; + using PlayerRoles.FirstPersonControl.Thirdperson; using PlayerRoles.Ragdolls; using PlayerRoles.Spectating; using PlayerRoles.Visibility; From baff9c5cad0650a4446d7cab1d6f3dd0f9e51b6b Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Thu, 31 Jul 2025 19:44:45 +0300 Subject: [PATCH 55/56] feat: All players spawned2 (#597) * Update Events.cs * Update Server.cs --- EXILED/Exiled.Events/Events.cs | 3 ++- EXILED/Exiled.Events/Handlers/Server.cs | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index 80173fa27a..b2c8e47e19 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -73,6 +73,7 @@ public override void OnEnabled() Handlers.Player.Verified += Handlers.Internal.Round.OnVerified; Handlers.Map.ChangedIntoGrenade += Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; + RoleAssigner.OnPlayersSpawned += Handlers.Server.OnAllPlayersSpawned; CharacterClassManager.OnRoundStarted += Handlers.Server.OnRoundStarted; WaveManager.OnWaveSpawned += Handlers.Server.OnRespawnedTeam; InventorySystem.InventoryExtensions.OnItemAdded += Handlers.Player.OnItemAdded; @@ -112,7 +113,7 @@ public override void OnDisabled() Handlers.Map.ChangedIntoGrenade -= Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; CharacterClassManager.OnRoundStarted -= Handlers.Server.OnRoundStarted; - + RoleAssigner.OnPlayersSpawned -= Handlers.Server.OnAllPlayersSpawned; InventorySystem.InventoryExtensions.OnItemAdded -= Handlers.Player.OnItemAdded; InventorySystem.InventoryExtensions.OnItemRemoved -= Handlers.Player.OnItemRemoved; WaveManager.OnWaveSpawned -= Handlers.Server.OnRespawnedTeam; diff --git a/EXILED/Exiled.Events/Handlers/Server.cs b/EXILED/Exiled.Events/Handlers/Server.cs index 7ddffb003a..80453625bb 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 all players have spawned at the start of a new round. + /// + public static Event AllPlayersSpawned { get; set; } = new(); + /// /// Invoked before ending a round. /// @@ -137,6 +142,11 @@ public static class Server /// public static void OnRoundStarted() => RoundStarted.InvokeSafely(); + /// + /// Called after all players have spawned at the start of a new round. + /// + public static void OnAllPlayersSpawned() => AllPlayersSpawned.InvokeSafely(); + /// /// Called before ending a round. /// @@ -245,4 +255,4 @@ public static class Server /// The instance. public static void OnCompletingObjective(CompletingObjectiveEventArgs ev) => CompletingObjective.InvokeSafely(ev); } -} \ No newline at end of file +} From 61e70a07e67ba4a35a494925635c0ae456de14c6 Mon Sep 17 00:00:00 2001 From: Yamato Date: Thu, 31 Jul 2025 19:42:16 +0200 Subject: [PATCH 56/56] Fix new Log Warning --- EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs b/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs index 3d5f5921d7..46e1f5881d 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs @@ -47,14 +47,15 @@ public static void OnClientStarted() { PrefabType prefabType = EnumUtils.Values[i]; PrefabAttribute attribute = prefabType.GetPrefabAttribute(); - if (prefabs.TryGetValue(attribute.AssetId, out GameObject gameObject)) + if (prefabs.TryGetValue(attribute.AssetId, out (GameObject, Component) tuple)) { + GameObject gameObject = tuple.Item1; PrefabHelper.Prefabs.Add(prefabType, prefabs.FirstOrDefault(prefab => prefab.Key == attribute.AssetId || prefab.Value.Item1.name.Contains(attribute.Name)).Value); prefabs.Remove(attribute.AssetId); continue; } - KeyValuePair? value = prefabs.FirstOrDefault(x => x.Value.name == attribute.Name); + KeyValuePair? value = prefabs.FirstOrDefault(x => x.Value.Item1.name == attribute.Name); if (value.HasValue) { PrefabHelper.Prefabs.Add(prefabType, prefabs.FirstOrDefault(prefab => prefab.Key == attribute.AssetId || prefab.Value.Item1.name.Contains(attribute.Name)).Value); @@ -63,8 +64,8 @@ public static void OnClientStarted() } } - foreach (KeyValuePair missing in prefabs) - Log.Warn($"Missing prefab in {nameof(PrefabType)}: {missing.Value.name} ({missing.Key})"); + foreach (KeyValuePair missing in prefabs) + Log.Warn($"Missing prefab in {nameof(PrefabType)}: {missing.Value.Item1.name} ({missing.Key})"); } } } \ No newline at end of file