diff --git a/.github/labeler.yml b/.github/labeler.yml index 5098459b0..97048dd23 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -35,6 +35,6 @@ Localization: # Add the 'Localization' label - changed-files: - any-glob-to-any-file: EXILED/Localization/** # Any modifications to Localization -GitHub_Actions: # Add the 'GitHub' label +GitHub: # Add the 'GitHub' label - changed-files: - any-glob-to-any-file: .github/** # Any modifications to github related files diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..032dc22c6 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,35 @@ +## Description +**Describe the changes** + + +**What is the current behavior?** (You can also link to an open issue here) + + +**What is the new behavior?** (if this is a feature change) + + +**Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?) + + +**Other information**: + +
+ +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) +- [ ] Documentations +
+ +## Submission checklist + +- [ ] I have checked the project can be compiled +- [ ] I have tested my changes and it worked as expected + +### Patches (if there are any changes related to Harmony patches) +- [ ] I have checked no IL patching errors in the console + +### Other +- [ ] Still requires more testing diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 6a9486427..a608aa15a 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -14,9 +14,9 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://Exiled-Official.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/Exiled-Official/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: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 351cdd3be..df73ad9a5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,7 +12,7 @@ permissions: id-token: write env: - EXILED_REFERENCES_URL: https://Exiled-Official.github.io/SL-References/Dev.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/labeler.yml b/.github/workflows/pull_request_opened.yml similarity index 72% rename from .github/workflows/labeler.yml rename to .github/workflows/pull_request_opened.yml index 0486bfaec..a54bed971 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/pull_request_opened.yml @@ -20,3 +20,10 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} configuration-path: .github/labeler.yml sync-labels: true + assign-author: + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - uses: toshimaru/auto-author-assign@v2.1.1 diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs index 8b30327d4..2dd66766c 100644 --- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs +++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs @@ -25,6 +25,7 @@ namespace Exiled.API.Extensions using PlayerRoles; using PlayerRoles.FirstPersonControl; using PlayerRoles.PlayableScps.Scp049.Zombies; + using PlayerRoles.Voice; using RelativePositioning; using Respawning; @@ -181,6 +182,18 @@ public static void PlayGunSound(this Player player, Vector3 position, ItemType i player.Connection.Send(message); } + /// + /// Sets that only the player can see. + /// + /// Only this player can see Display Text. + /// Text displayed to the player. + public static void SetIntercomDisplayTextForTargetOnly(this Player target, string text) => target.SendFakeSyncVar(IntercomDisplay._singleton.netIdentity, typeof(IntercomDisplay), nameof(IntercomDisplay.Network_overrideText), text); + + /// + /// Resync . + /// + public static void ResetIntercomDisplayText() => ResyncSyncVar(IntercomDisplay._singleton.netIdentity, typeof(IntercomDisplay), nameof(IntercomDisplay.Network_overrideText)); + /// /// Sets of a that only the player can see. /// diff --git a/EXILED/Exiled.API/Features/Items/Jailbird.cs b/EXILED/Exiled.API/Features/Items/Jailbird.cs index 9e508da11..2f8bfb524 100644 --- a/EXILED/Exiled.API/Features/Items/Jailbird.cs +++ b/EXILED/Exiled.API/Features/Items/Jailbird.cs @@ -7,11 +7,14 @@ namespace Exiled.API.Features.Items { + using System; + using Exiled.API.Features.Pickups; using Exiled.API.Interfaces; using InventorySystem.Items.Autosync; using InventorySystem.Items.Jailbird; using Mirror; + using UnityEngine; using JailbirdPickup = Pickups.JailbirdPickup; @@ -114,12 +117,35 @@ public JailbirdWearState WearState get => Base._deterioration.WearState; set { - if (JailbirdDeteriorationTracker.ReceivedStates.ContainsKey(Serial)) - JailbirdDeteriorationTracker.ReceivedStates[Serial] = value; + TotalDamageDealt = GetDamage(value); + TotalCharges = GetCharge(value); Base._deterioration.RecheckUsage(); } } + /// + /// Calculates the damage corresponding to a given . + /// + /// The wear state to calculate damage for. + /// The amount of damage associated with the specified wear state. + public float GetDamage(JailbirdWearState wearState) + { + foreach (Keyframe keyframe in Base._deterioration._damageToWearState.keys) + { + if (Base._deterioration.FloatToState(keyframe.value) == wearState) + return keyframe.time; + } + + throw new Exception("Wear state not found in damage to wear state mapping."); + } + + /// + /// Gets the charge needed to reach a specific . + /// + /// The desired wear state to calculate the charge for. + /// The charge value required to achieve the specified wear state. + public int GetCharge(JailbirdWearState wearState) => (int)wearState; + /// /// Breaks the Jailbird. /// diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs index c27f78840..4e8f2b094 100644 --- a/EXILED/Exiled.API/Features/Map.cs +++ b/EXILED/Exiled.API/Features/Map.cs @@ -57,11 +57,6 @@ public static class Map /// internal static readonly List TeleportsValue = new(8); - /// - /// A list of s on the map. - /// - internal static readonly List ToysValue = new(); - private static TantrumEnvironmentalHazard tantrumPrefab; private static Scp939AmnesticCloudInstance amnesticCloudPrefab; @@ -130,7 +125,7 @@ DecontaminationController.Singleton.NetworkDecontaminationOverride is Decontamin /// /// Gets all objects. /// - public static ReadOnlyCollection Toys { get; } = ToysValue.AsReadOnly(); + public static ReadOnlyCollection Toys => AdminToy.BaseToAdminToy.Values.ToList().AsReadOnly(); // TODO: Obsolete it and make people use AdminToy.List /// /// Gets or sets the current seed of the map. diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index d44a570e2..a3693d4f6 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -1266,8 +1266,13 @@ public static Player Get(GameObject gameObject) if (Dictionary.TryGetValue(gameObject, out Player player)) return player; - UnverifiedPlayers.TryGetValue(gameObject, out player); - return player; + if (UnverifiedPlayers.TryGetValue(gameObject, out player)) + return player; + + if (ReferenceHub.TryGetHub(gameObject, out ReferenceHub hub)) + return new(hub); + + return null; } /// @@ -2319,6 +2324,16 @@ public void Broadcast(ushort duration, string message, global::Broadcast.Broadca public void AddAmmo(AmmoType ammoType, ushort amount) => Inventory.ServerAddAmmo(ammoType.GetItemType(), amount); + /// + /// Adds the amount of a specified ammo type to player's inventory. + /// + /// A dictionary of ammo types that will be added. + public void AddAmmo(Dictionary ammoBag) + { + foreach (KeyValuePair kvp in ammoBag) + AddAmmo(kvp.Key, kvp.Value); + } + /// /// Adds the amount of a weapon's ammo type to the player's inventory. /// @@ -2338,6 +2353,16 @@ public void SetAmmo(AmmoType ammoType, ushort amount) Inventory.ServerSetAmmo(itemType, amount); } + /// + /// Sets the amount of a specified ammo type to player's inventory. + /// + /// A dictionary of ammo types that will be added. + public void SetAmmo(Dictionary ammoBag) + { + foreach (KeyValuePair kvp in ammoBag) + SetAmmo(kvp.Key, kvp.Value); + } + /// /// Gets the ammo count of a specified ammo type in a player's inventory. /// @@ -2728,8 +2753,8 @@ public void ResetInventory(IEnumerable newItems) /// public void ClearInventory(bool destroy = true) { - ClearItems(destroy); ClearAmmo(); + ClearItems(destroy); } /// diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs index 26cf64c98..908096434 100644 --- a/EXILED/Exiled.API/Features/Server.cs +++ b/EXILED/Exiled.API/Features/Server.cs @@ -178,6 +178,11 @@ public static bool IsWhitelisted set => ServerConsole.WhiteListEnabled = value; } + /// + /// Gets the list of user IDs of players currently whitelisted. + /// + public static HashSet WhitelistedPlayers => WhiteList.Users; + /// /// Gets a value indicating whether or not this server is verified. /// diff --git a/EXILED/Exiled.API/Features/Toys/AdminToy.cs b/EXILED/Exiled.API/Features/Toys/AdminToy.cs index bbffd7196..5287096a1 100644 --- a/EXILED/Exiled.API/Features/Toys/AdminToy.cs +++ b/EXILED/Exiled.API/Features/Toys/AdminToy.cs @@ -7,6 +7,7 @@ namespace Exiled.API.Features.Toys { + using System.Collections.Generic; using System.Linq; using AdminToys; @@ -14,6 +15,7 @@ namespace Exiled.API.Features.Toys using Enums; using Exiled.API.Interfaces; using Footprinting; + using InventorySystem.Items; using Mirror; using UnityEngine; @@ -23,6 +25,11 @@ namespace Exiled.API.Features.Toys /// public abstract class AdminToy : IWorldSpace { + /// + /// A dictionary of all 's that have been converted into . + /// + internal static readonly Dictionary BaseToAdminToy = new(new ComponentsEqualityComparer()); + /// /// Initializes a new instance of the class. /// @@ -33,9 +40,14 @@ internal AdminToy(AdminToyBase toyAdminToyBase, AdminToyType type) AdminToyBase = toyAdminToyBase; ToyType = type; - Map.ToysValue.Add(this); + BaseToAdminToy.Add(toyAdminToyBase, this); } + /// + /// Gets a list of all 's on the server. + /// + public static IReadOnlyCollection List => BaseToAdminToy.Values; + /// /// Gets the original . /// @@ -130,7 +142,22 @@ public bool IsStatic /// /// The instance. /// The corresponding instance. - public static AdminToy Get(AdminToyBase adminToyBase) => Map.Toys.FirstOrDefault(x => x.AdminToyBase == adminToyBase); + public static AdminToy Get(AdminToyBase adminToyBase) + { + if (adminToyBase == null) + return null; + + if (BaseToAdminToy.TryGetValue(adminToyBase, out AdminToy adminToy)) + return adminToy; + + return adminToyBase switch + { + LightSourceToy lightSourceToy => new Light(lightSourceToy), + PrimitiveObjectToy primitiveObjectToy => new Primitive(primitiveObjectToy), + ShootingTarget shootingTarget => new ShootingTargetToy(shootingTarget), + _ => throw new System.NotImplementedException() + }; + } /// /// Gets the by . @@ -156,7 +183,7 @@ public static T Get(AdminToyBase adminToyBase) /// public void Destroy() { - Map.ToysValue.Remove(this); + BaseToAdminToy.Remove(AdminToyBase); NetworkServer.Destroy(AdminToyBase.gameObject); } } diff --git a/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs index 1b17a1bb0..6ac613800 100644 --- a/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs @@ -7,6 +7,8 @@ namespace Exiled.Events.EventArgs.Item { + using System; + using Exiled.API.Features; using Exiled.API.Features.Items; using Exiled.Events.EventArgs.Interfaces; @@ -25,8 +27,10 @@ public class ChargingJailbirdEventArgs : IPlayerEvent, IItemEvent, IDeniableEven public ChargingJailbirdEventArgs(ReferenceHub player, InventorySystem.Items.ItemBase swingItem, bool isAllowed = true) { Player = Player.Get(player); - Item = Item.Get(swingItem); + Jailbird = (Jailbird)Item.Get(swingItem); +#pragma warning disable CS0618 IsAllowed = isAllowed; +#pragma warning restore CS0618 } /// @@ -35,13 +39,23 @@ public ChargingJailbirdEventArgs(ReferenceHub player, InventorySystem.Items.Item public Player Player { get; } /// - /// Gets the that is being charged. This will always be a . + /// Gets the that is being charged. + /// + public Jailbird Jailbird { get; } + + /// + /// Gets the that is being charged. /// - public Item Item { get; } + public Item Item => Jailbird; /// /// Gets or sets a value indicating whether or not the Jailbird can be charged. /// - public bool IsAllowed { get; set; } + public bool IsAllowed + { + get; + [Obsolete("This event cannot be denied as it will cause desync.")] + set; + } } } diff --git a/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs index 17c0319b0..6c8f0fce8 100644 --- a/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs @@ -25,7 +25,7 @@ public class SwingingEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent public SwingingEventArgs(ReferenceHub player, InventorySystem.Items.ItemBase swingItem, bool isAllowed = true) { Player = Player.Get(player); - Item = Item.Get(swingItem); + Jailbird = (Jailbird)Item.Get(swingItem); IsAllowed = isAllowed; } @@ -34,10 +34,15 @@ public SwingingEventArgs(ReferenceHub player, InventorySystem.Items.ItemBase swi /// public Player Player { get; } + /// + /// Gets the that is being swung. + /// + public Jailbird Jailbird { get; } + /// /// Gets the that is being swung. /// - public Item Item { get; } + public Item Item => Jailbird; /// /// Gets or sets a value indicating whether or not the item can be swung. diff --git a/EXILED/Exiled.Events/EventArgs/Server/RespawnedTeamEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/RespawnedTeamEventArgs.cs new file mode 100644 index 000000000..4aaa2b363 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Server/RespawnedTeamEventArgs.cs @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Server +{ + using System.Collections.Generic; + using System.Linq; + + using Exiled.API.Features; + using Exiled.Events.EventArgs.Interfaces; + using Respawning; + + /// + /// Contains all information after team spawns. + /// + public class RespawnedTeamEventArgs : IExiledEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public RespawnedTeamEventArgs(SpawnableTeamType team, IEnumerable hubs) + { + Players = hubs.Select(Player.Get); + Team = team; + } + + /// + /// Gets the list of spawned players. + /// + public IEnumerable Players { get; } + + /// + /// Gets the spawned team. + /// + public SpawnableTeamType Team { get; } + } +} diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index 178071bb7..4c5fcabc5 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -21,6 +21,7 @@ namespace Exiled.Events using PlayerRoles.Ragdolls; using PlayerRoles.RoleAssign; using PluginAPI.Events; + using Respawning; using UnityEngine.SceneManagement; /// @@ -70,7 +71,7 @@ public override void OnEnabled() Handlers.Map.ChangedIntoGrenade += Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; CharacterClassManager.OnRoundStarted += Handlers.Server.OnRoundStarted; - + RespawnManager.ServerOnRespawned += Handlers.Server.OnRespawnedTeam; InventorySystem.InventoryExtensions.OnItemAdded += Handlers.Player.OnItemAdded; InventorySystem.InventoryExtensions.OnItemRemoved += Handlers.Player.OnItemRemoved; @@ -105,7 +106,7 @@ public override void OnDisabled() InventorySystem.InventoryExtensions.OnItemAdded -= Handlers.Player.OnItemAdded; InventorySystem.InventoryExtensions.OnItemRemoved -= Handlers.Player.OnItemRemoved; - + RespawnManager.ServerOnRespawned -= Handlers.Server.OnRespawnedTeam; RagdollManager.OnRagdollSpawned -= Handlers.Internal.RagdollList.OnSpawnedRagdoll; RagdollManager.OnRagdollRemoved -= Handlers.Internal.RagdollList.OnRemovedRagdoll; ItemPickupBase.OnPickupAdded -= Handlers.Internal.PickupEvent.OnSpawnedPickup; diff --git a/EXILED/Exiled.Events/Handlers/Internal/SceneUnloaded.cs b/EXILED/Exiled.Events/Handlers/Internal/SceneUnloaded.cs index 9bcb75cc8..4ecdc5f93 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/SceneUnloaded.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/SceneUnloaded.cs @@ -8,7 +8,7 @@ namespace Exiled.Events.Handlers.Internal { using API.Features; - + using Exiled.API.Features.Toys; using UnityEngine.SceneManagement; #pragma warning disable SA1611 // Element parameters should be documented @@ -35,7 +35,7 @@ public static void OnSceneUnloaded(Scene _) { Player.UserIdsCache.Clear(); Player.Dictionary.Clear(); - Map.ToysValue.Clear(); + AdminToy.BaseToAdminToy.Clear(); } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Server.cs b/EXILED/Exiled.Events/Handlers/Server.cs index 1b3d0481a..75be4d81c 100644 --- a/EXILED/Exiled.Events/Handlers/Server.cs +++ b/EXILED/Exiled.Events/Handlers/Server.cs @@ -7,6 +7,9 @@ namespace Exiled.Events.Handlers { + using System.Collections.Generic; + + using Respawning; #pragma warning disable SA1623 // Property summary documentation should match accessors using Exiled.Events.EventArgs.Player; @@ -53,6 +56,11 @@ public static class Server /// public static Event RespawningTeam { get; set; } = new(); + /// + /// Invoked after team spawns. + /// + public static Event RespawnedTeam { get; set; } = new(); + /// /// Invoked before adding an unit name. /// @@ -142,6 +150,13 @@ public static class Server /// The instance. public static void OnRespawningTeam(RespawningTeamEventArgs ev) => RespawningTeam.InvokeSafely(ev); + /// + /// Called after team spawns. + /// + /// + /// + public static void OnRespawnedTeam(SpawnableTeamType teamType, List hubs) => RespawnedTeam.InvokeSafely(new RespawnedTeamEventArgs(teamType, hubs)); + /// /// Called before adding an unit name. /// diff --git a/EXILED/Exiled.Events/Patches/Events/Item/JailbirdPatch.cs b/EXILED/Exiled.Events/Patches/Events/Item/JailbirdPatch.cs index ec33236e0..1f8489fd3 100644 --- a/EXILED/Exiled.Events/Patches/Events/Item/JailbirdPatch.cs +++ b/EXILED/Exiled.Events/Patches/Events/Item/JailbirdPatch.cs @@ -88,10 +88,7 @@ private static bool HandleJailbird(JailbirdItem instance, JailbirdMessageType me ChargingJailbirdEventArgs ev = new(instance.Owner, instance); Item.OnChargingJailbird(ev); - if (ev.IsAllowed) - return true; - instance.SendRpc(JailbirdMessageType.ChargeFailed, null); - return false; + return true; } default: diff --git a/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs b/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs new file mode 100644 index 000000000..680e40608 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs @@ -0,0 +1,61 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Player +{ +#pragma warning disable IDE0060 + + using System.Collections.Generic; + using System.Reflection.Emit; + + using API.Features; + using API.Features.Pools; + + using HarmonyLib; + using InventorySystem.Items.Jailbird; + using Mirror; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// Bug reported to NW (https://trello.com/c/kyr3hV9B). + /// + [HarmonyPatch(typeof(JailbirdDeteriorationTracker), nameof(JailbirdDeteriorationTracker.Setup))] + internal static class Jailbird914CoarseFix + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int offset = -1; + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Blt_S) + offset; + + List