From c9654eee7c41eacf1b4301c45f58ea7c39b14765 Mon Sep 17 00:00:00 2001
From: VALERA771 <72030575+VALERA771@users.noreply.github.com>
Date: Fri, 2 Aug 2024 00:26:08 +0300
Subject: [PATCH 01/63] uwu (#5)
---
EXILED/Exiled.API/Features/Player.cs | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index def165726..ed937ead5 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -2319,6 +2319,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 +2348,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.
///
From 565373318d5aba8d2af3a438a03f2988a8a87e38 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Fri, 2 Aug 2024 21:12:57 +0200
Subject: [PATCH 02/63] AdminToy.List (#18)
* AdminToy.List
* Better AdminToy::Get()
* Update EXILED/Exiled.API/Features/Toys/AdminToy.cs
Co-authored-by: IRacle <79921583+IRacle1@users.noreply.github.com>
* TODO
* Fix Error
* Fix2
---------
Co-authored-by: IRacle <79921583+IRacle1@users.noreply.github.com>
---
EXILED/Exiled.API/Features/Map.cs | 7 +---
EXILED/Exiled.API/Features/Toys/AdminToy.cs | 33 +++++++++++++++++--
.../Handlers/Internal/SceneUnloaded.cs | 4 +--
3 files changed, 33 insertions(+), 11 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs
index 14f6d8214..24edcc90c 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/Toys/AdminToy.cs b/EXILED/Exiled.API/Features/Toys/AdminToy.cs
index fdbe03da1..2139059e9 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()
+ };
+ }
///
/// Spawns the toy into the game. Use to remove it.
@@ -147,7 +174,7 @@ public bool IsStatic
///
public void Destroy()
{
- Map.ToysValue.Remove(this);
+ BaseToAdminToy.Remove(AdminToyBase);
NetworkServer.Destroy(AdminToyBase.gameObject);
}
}
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
From 5a519a43b5be251f741dd5a8272267a08cb8892d Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Fri, 2 Aug 2024 21:18:36 +0200
Subject: [PATCH 03/63] Fix `Jailbird::WearState` (#12)
* Jailbird
* Fix
* Exception
* Fix NW moment
---
EXILED/Exiled.API/Features/Items/Jailbird.cs | 30 ++++++++-
.../Item/ChargingJailbirdEventArgs.cs | 11 +++-
.../EventArgs/Item/SwingingEventArgs.cs | 9 ++-
.../Patches/Fixes/Jailbird914CoarseFix.cs | 61 +++++++++++++++++++
4 files changed, 104 insertions(+), 7 deletions(-)
create mode 100644 EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs
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.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs
index 38f6ea7f8..6ac613800 100644
--- a/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs
@@ -27,7 +27,7 @@ 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
@@ -39,9 +39,14 @@ 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 Item Item { get; }
+ public Jailbird Jailbird { get; }
+
+ ///
+ /// Gets the that is being charged.
+ ///
+ public Item Item => Jailbird;
///
/// Gets or sets a value indicating whether or not the Jailbird can be charged.
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/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 labels = newInstructions[index].ExtractLabels();
+
+ int offsetToRemove = 2;
+ int indexToRemove = newInstructions.FindIndex(i => i.opcode == OpCodes.Blt_S) + offsetToRemove;
+ int countToRemove = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Blt_S) - indexToRemove + offsetToRemove;
+
+ newInstructions.RemoveRange(indexToRemove, countToRemove);
+
+ newInstructions.InsertRange(
+ index,
+ new CodeInstruction[]
+ {
+ // JailbirdDeteriorationTracker.Scp914CoarseCharges = JailbirdWearState.AlmostBroken
+ new CodeInstruction(OpCodes.Ldc_I4_4).WithLabels(labels),
+ new(OpCodes.Call, PropertySetter(typeof(JailbirdDeteriorationTracker), nameof(JailbirdDeteriorationTracker.Scp914CoarseCharges))),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file
From 81c365286384f9d8b9b8bb34ed96afe5a7954ebc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B0=B8=E5=AE=89404?=
<101850798+YongAn404@users.noreply.github.com>
Date: Sat, 3 Aug 2024 04:23:24 +0800
Subject: [PATCH 04/63] Porting EXILED9 RespawnedTeam event. by.VALERA771 (#27)
https://github.com/Exiled-Team/EXILED/pull/2386
---
.../Server/RespawnedTeamEventArgs.cs | 43 +++++++++++++++++++
EXILED/Exiled.Events/Events.cs | 5 ++-
EXILED/Exiled.Events/Handlers/Server.cs | 15 +++++++
3 files changed, 61 insertions(+), 2 deletions(-)
create mode 100644 EXILED/Exiled.Events/EventArgs/Server/RespawnedTeamEventArgs.cs
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/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.
///
From 1f2d209cbf5fff48513bacc100d55dcf64e037f7 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sun, 4 Aug 2024 15:12:21 +0200
Subject: [PATCH 05/63] Fix not returning null (#22)
* Fix not returning null
* Apply suggestions from code review
Co-authored-by: Jesus QC <69375249+Jesus-QC@users.noreply.github.com>
* Little modification
---------
Co-authored-by: Jesus QC <69375249+Jesus-QC@users.noreply.github.com>
---
EXILED/Exiled.API/Features/Player.cs | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index ed937ead5..b62524745 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;
}
///
From 4e508261a3b3879bef6512b7b7f9afd1a039eb51 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Tue, 6 Aug 2024 19:33:05 +0200
Subject: [PATCH 06/63] RecontainedEventArgs more feature (#20)
* RecontainedEventArgs more feature
* Fix Naming
* grammar
* Update RecontainedEventArgs.cs
---------
Co-authored-by: Misaka-ZeroTwo <45165615+Misaka-ZeroTwo@users.noreply.github.com>
---
.../EventArgs/Scp079/RecontainedEventArgs.cs | 25 +++++++++++++++++--
.../Patches/Events/Scp079/Recontain.cs | 3 ++-
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/EXILED/Exiled.Events/EventArgs/Scp079/RecontainedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp079/RecontainedEventArgs.cs
index 84a2e93ad..49b5dbebd 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp079/RecontainedEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp079/RecontainedEventArgs.cs
@@ -22,10 +22,16 @@ public class RecontainedEventArgs : IScp079Event
///
///
///
- public RecontainedEventArgs(Player player)
+ ///
+ ///
+ ///
+ public RecontainedEventArgs(Player player, PlayerRoles.PlayableScps.Scp079.Scp079Recontainer scp079Recontainer)
{
Player = player;
Scp079 = player.Role.As();
+ Recontainer = scp079Recontainer;
+ Attacker = Player.Get(scp079Recontainer._activatorGlass.LastAttacker);
+ IsAutomatic = scp079Recontainer._activatorGlass.LastAttacker.IsSet;
}
///
@@ -35,5 +41,20 @@ public RecontainedEventArgs(Player player)
///
public Scp079Role Scp079 { get; }
+
+ ///
+ /// Gets the instance that handle SCP-079 recontained proccess.
+ ///
+ public PlayerRoles.PlayableScps.Scp079.Scp079Recontainer Recontainer { get; }
+
+ ///
+ /// Gets the player who recontained SCP-079.
+ ///
+ public Player Attacker { get; }
+
+ ///
+ /// Gets a value indicating whether the recontainment has been made automatically or by triggering the process.
+ ///
+ public bool IsAutomatic { get; }
}
-}
\ No newline at end of file
+}
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp079/Recontain.cs b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontain.cs
index 991ffc47e..3338c84ab 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp079/Recontain.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontain.cs
@@ -37,9 +37,10 @@ private static IEnumerable Transpiler(IEnumerable
Date: Tue, 6 Aug 2024 15:59:41 -0400
Subject: [PATCH 07/63] InteractingScp330.cs: Reduction of bloat code from
original design. (#30)
* Should reduce bloat code that was required years ago.
* Should reduce bloat code that was required years ago.
* Added back per Yamato's request
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
.../Events/Scp330/InteractingScp330.cs | 87 ++-----------------
1 file changed, 7 insertions(+), 80 deletions(-)
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs b/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
index 0c43bbadd..aea840168 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
@@ -10,18 +10,12 @@ namespace Exiled.Events.Patches.Events.Scp330
using System.Collections.Generic;
using System.Reflection.Emit;
- using API.Features.Pools;
-
- using CustomPlayerEffects;
+ using Exiled.API.Features.Pools;
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Scp330;
using Exiled.Events.Handlers;
-
using HarmonyLib;
-
using Interactables.Interobjects;
-
- using InventorySystem;
using InventorySystem.Items.Usables.Scp330;
using static HarmonyLib.AccessTools;
@@ -79,69 +73,25 @@ private static IEnumerable Transpiler(IEnumerable instruction.Calls(Method(typeof(Scp330Bag), nameof(Scp330Bag.ServerProcessPickup)))) + removeServerProcessOffset;
-
- newInstructions.RemoveRange(removeServerProcessIndex, 3);
-
- // Replace NW server process logic.
- newInstructions.InsertRange(
- removeServerProcessIndex,
- new[]
- {
- // ldarg.1 is already in the stack
-
- // ev.Candy
- new CodeInstruction(OpCodes.Ldloc, ev),
- new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(InteractingScp330EventArgs), nameof(InteractingScp330EventArgs.Candy))),
-
- // bag
- new CodeInstruction(OpCodes.Ldloca_S, 3),
-
- // ServerProcessPickup(ReferenceHub, CandyKindID, Scp330Bag)
- new CodeInstruction(OpCodes.Call, Method(typeof(InteractingScp330), nameof(ServerProcessPickup), new[] { typeof(ReferenceHub), typeof(CandyKindID), typeof(Scp330Bag).MakeByRefType() })),
- });
-
// This is to find the location of RpcMakeSound to remove the original code and add a new sever logic structure (Start point)
int addShouldSeverOffset = 1;
int addShouldSeverIndex = newInstructions.FindLastIndex(
instruction => instruction.Calls(Method(typeof(Scp330Interobject), nameof(Scp330Interobject.RpcMakeSound)))) + addShouldSeverOffset;
- // This is to find the location of the next return (End point)
- int includeSameLine = 1;
- int nextReturn = newInstructions.FindIndex(addShouldSeverIndex, instruction => instruction.opcode == OpCodes.Ret) + includeSameLine;
- Label originalLabel = newInstructions[addShouldSeverIndex].ExtractLabels()[0];
-
- // Remove original code from after RpcMakeSound to next return and then fully replace it.
- newInstructions.RemoveRange(addShouldSeverIndex, nextReturn - addShouldSeverIndex);
-
- addShouldSeverIndex = newInstructions.FindLastIndex(
- instruction => instruction.Calls(Method(typeof(Scp330Interobject), nameof(Scp330Interobject.RpcMakeSound)))) + addShouldSeverOffset;
+ int serverEffectLocationStart = -1;
+ int enableEffect = newInstructions.FindLastIndex(
+ instruction => instruction.LoadsField(Field(typeof(PlayerEffectsController), nameof(ReferenceHub.playerEffectsController)))) + serverEffectLocationStart;
newInstructions.InsertRange(
addShouldSeverIndex,
- new CodeInstruction[]
+ new[]
{
// if (!ev.ShouldSever)
// goto shouldNotSever;
- new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex).WithLabels(originalLabel),
+ new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(InteractingScp330EventArgs), nameof(InteractingScp330EventArgs.ShouldSever))),
new(OpCodes.Brfalse, shouldNotSever),
-
- // ev.Player.EnableEffect("SevereHands", 1, 0f, false)
- new(OpCodes.Ldloc, ev.LocalIndex),
- new(OpCodes.Callvirt, PropertyGetter(typeof(InteractingScp330EventArgs), nameof(InteractingScp330EventArgs.Player))),
- new(OpCodes.Ldstr, nameof(SeveredHands)),
- new(OpCodes.Ldc_I4_1),
- new(OpCodes.Ldc_R4, 0f),
- new(OpCodes.Ldc_I4_0),
- new(OpCodes.Callvirt, Method(typeof(Player), nameof(Player.EnableEffect), new[] { typeof(string), typeof(byte), typeof(float), typeof(bool) })),
- new(OpCodes.Pop),
-
- // return;
- new(OpCodes.Ret),
+ new(OpCodes.Br, enableEffect),
});
// This will let us jump to the taken candies code and lock until ldarg_0, meaning we allow base game logic handle candy adding.
@@ -157,28 +107,5 @@ private static IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions);
}
-
- private static bool ServerProcessPickup(ReferenceHub player, CandyKindID candy, out Scp330Bag bag)
- {
- if (!Scp330Bag.TryGetBag(player, out bag))
- {
- player.inventory.ServerAddItem(ItemType.SCP330);
-
- if (!Scp330Bag.TryGetBag(player, out bag))
- return false;
-
- bag.Candies = new List { candy };
- bag.ServerRefreshBag();
-
- return true;
- }
-
- bool result = bag.TryAddSpecific(candy);
-
- if (bag.AcquisitionAlreadyReceived)
- bag.ServerRefreshBag();
-
- return result;
- }
}
}
\ No newline at end of file
From e39238e62841784b73c5fa917b3473b3e4b037ab Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Tue, 6 Aug 2024 22:53:39 +0200
Subject: [PATCH 08/63] IScp330Event (#11)
Co-authored-by: Misaka-ZeroTwo <45165615+Misaka-ZeroTwo@users.noreply.github.com>
---
.../EventArgs/Interfaces/IHazardEvent.cs | 2 +-
.../EventArgs/Interfaces/IScp330Event.cs | 22 +++++++++++++++++++
.../EventArgs/Interfaces/IUsableEvent.cs | 4 ++--
.../Scp330/DroppingScp330EventArgs.cs | 9 +++++---
.../EventArgs/Scp330/EatenScp330EventArgs.cs | 14 +++++++++---
.../EventArgs/Scp330/EatingScp330EventArgs.cs | 16 ++++++++++----
.../Scp330/InteractingScp330EventArgs.cs | 14 ++++++++++--
.../Patches/Events/Scp330/EatingScp330.cs | 10 +++++++--
8 files changed, 74 insertions(+), 17 deletions(-)
create mode 100644 EXILED/Exiled.Events/EventArgs/Interfaces/IScp330Event.cs
diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IHazardEvent.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IHazardEvent.cs
index 54f6a3f74..d10d34631 100644
--- a/EXILED/Exiled.Events/EventArgs/Interfaces/IHazardEvent.cs
+++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IHazardEvent.cs
@@ -10,7 +10,7 @@ namespace Exiled.Events.EventArgs.Interfaces
using Exiled.API.Features.Hazards;
///
- /// Event args for all related events.
+ /// Event args for all related events.
///
public interface IHazardEvent : IExiledEvent
{
diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp330Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp330Event.cs
new file mode 100644
index 000000000..45a3072e7
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp330Event.cs
@@ -0,0 +1,22 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Interfaces
+{
+ using Exiled.API.Features.Items;
+
+ ///
+ /// Event args used for all related events.
+ ///
+ public interface IScp330Event : IItemEvent
+ {
+ ///
+ /// Gets the triggering the event.
+ ///
+ public Scp330 Scp330 { get; }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IUsableEvent.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IUsableEvent.cs
index 6c34c16e8..67b28f5b6 100644
--- a/EXILED/Exiled.Events/EventArgs/Interfaces/IUsableEvent.cs
+++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IUsableEvent.cs
@@ -10,12 +10,12 @@ namespace Exiled.Events.EventArgs.Interfaces
using Exiled.API.Features.Items;
///
- /// Event args used for all related events.
+ /// Event args used for all related events.
///
public interface IUsableEvent : IItemEvent
{
///
- /// Gets the triggering the event.
+ /// Gets the triggering the event.
///
public Usable Usable { get; }
}
diff --git a/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs
index 5aabbd226..0105cc1a1 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs
@@ -17,7 +17,7 @@ namespace Exiled.Events.EventArgs.Scp330
///
/// Contains all information before a player drops a SCP-330 candy.
///
- public class DroppingScp330EventArgs : IPlayerEvent, IDeniableEvent
+ public class DroppingScp330EventArgs : IPlayerEvent, IScp330Event, IDeniableEvent
{
///
/// Initializes a new instance of the class.
@@ -39,9 +39,12 @@ public DroppingScp330EventArgs(Player player, Scp330Bag scp330, CandyKindID cand
}
///
- /// Gets or sets a value representing the being picked up.
+ /// Gets or sets a value representing the being picked up.
///
- public Scp330 Scp330 { get; set; }
+ public Scp330 Scp330 { get; set; } // Todo Remove set
+
+ ///
+ public Item Item => Scp330;
///
/// Gets or sets a value indicating whether or not the type of candy drop.
diff --git a/EXILED/Exiled.Events/EventArgs/Scp330/EatenScp330EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp330/EatenScp330EventArgs.cs
index 3fa09415b..29beac357 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp330/EatenScp330EventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp330/EatenScp330EventArgs.cs
@@ -8,7 +8,7 @@
namespace Exiled.Events.EventArgs.Scp330
{
using API.Features;
-
+ using Exiled.API.Features.Items;
using Interfaces;
using InventorySystem.Items.Usables.Scp330;
@@ -16,16 +16,18 @@ namespace Exiled.Events.EventArgs.Scp330
///
/// Contains all information after a player has eaten SCP-330.
///
- public class EatenScp330EventArgs : IPlayerEvent
+ public class EatenScp330EventArgs : IPlayerEvent, IScp330Event
{
///
/// Initializes a new instance of the class.
///
/// .
+ /// .
/// .
- public EatenScp330EventArgs(Player player, ICandy candy)
+ public EatenScp330EventArgs(Player player, Scp330Bag scp330, ICandy candy)
{
Player = player;
+ Scp330 = (Scp330)Item.Get(scp330);
Candy = candy;
}
@@ -38,5 +40,11 @@ public EatenScp330EventArgs(Player player, ICandy candy)
/// Gets the player who has eaten SCP-330.
///
public Player Player { get; }
+
+ ///
+ public Scp330 Scp330 { get; }
+
+ ///
+ public Item Item => Scp330;
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/EventArgs/Scp330/EatingScp330EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp330/EatingScp330EventArgs.cs
index d24a57ad4..825f8424b 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp330/EatingScp330EventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp330/EatingScp330EventArgs.cs
@@ -8,7 +8,7 @@
namespace Exiled.Events.EventArgs.Scp330
{
using API.Features;
-
+ using Exiled.API.Features.Items;
using Interfaces;
using InventorySystem.Items.Usables.Scp330;
@@ -16,17 +16,19 @@ namespace Exiled.Events.EventArgs.Scp330
///
/// Contains all information before a player eats SCP-330.
///
- public class EatingScp330EventArgs : IPlayerEvent, IDeniableEvent
+ public class EatingScp330EventArgs : IPlayerEvent, IScp330Event, IDeniableEvent
{
///
/// Initializes a new instance of the class.
///
/// .
- /// .
+ /// .
+ /// .
/// .
- public EatingScp330EventArgs(Player player, ICandy candy, bool isAllowed = true)
+ public EatingScp330EventArgs(Player player, Scp330Bag scp330, ICandy candy, bool isAllowed = true)
{
Player = player;
+ Scp330 = (Scp330)Item.Get(scp330);
Candy = candy;
IsAllowed = isAllowed;
}
@@ -45,5 +47,11 @@ public EatingScp330EventArgs(Player player, ICandy candy, bool isAllowed = true)
/// Gets the player who's eating SCP-330.
///
public Player Player { get; }
+
+ ///
+ public Scp330 Scp330 { get; }
+
+ ///
+ public Item Item => Scp330;
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs
index 30cd0a1ac..b87238842 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs
@@ -8,15 +8,16 @@
namespace Exiled.Events.EventArgs.Scp330
{
using API.Features;
-
+ using Exiled.API.Features.Items;
using Interfaces;
using InventorySystem.Items.Usables.Scp330;
+ using YamlDotNet.Core.Tokens;
///
/// Contains all information before a player interacts with SCP-330.
///
- public class InteractingScp330EventArgs : IPlayerEvent, IDeniableEvent
+ public class InteractingScp330EventArgs : IPlayerEvent, IScp330Event, IDeniableEvent
{
///
/// Initializes a new instance of the class.
@@ -30,6 +31,7 @@ public class InteractingScp330EventArgs : IPlayerEvent, IDeniableEvent
public InteractingScp330EventArgs(Player player, int usage)
{
Player = player;
+ Scp330 = Scp330Bag.TryGetBag(player.ReferenceHub, out Scp330Bag scp330Bag) ? (Scp330)Item.Get(scp330Bag) : null;
Candy = Scp330Candies.GetRandom();
UsageCount = usage;
ShouldSever = usage >= 2;
@@ -60,5 +62,13 @@ public InteractingScp330EventArgs(Player player, int usage)
/// Gets the triggering the event.
///
public Player Player { get; }
+
+ ///
+ /// This value can be null.
+ public Scp330 Scp330 { get; }
+
+ ///
+ /// This value can be null.
+ public Item Item => Scp330;
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp330/EatingScp330.cs b/EXILED/Exiled.Events/Patches/Events/Scp330/EatingScp330.cs
index 1ad59414d..f52435bdd 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp330/EatingScp330.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp330/EatingScp330.cs
@@ -51,13 +51,16 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable
Date: Tue, 6 Aug 2024 22:55:00 +0200
Subject: [PATCH 09/63] PR than i made (#9)
* PR made by me
Thanks Ika for the Help on CustomAmmo/CategoryLimit
Co-Authored-By: Ika <36999341+IkaOverride@users.noreply.github.com>
* Build error
* Added support to SCPs for escaping-related events.
* spacing
* LocalReporting Exiled should be call before NWAPI
* Optimising / More documentation on SpawningItem
* ISpawnableScp
* Use of ComponentsEqualityComparer for Dictionary
---------
Co-authored-by: Ika <36999341+IkaOverride@users.noreply.github.com>
---
.../Exiled.API/Extensions/MirrorExtensions.cs | 9 +-
EXILED/Exiled.API/Features/Camera.cs | 2 +-
.../Features/Doors/AirlockController.cs | 2 +-
EXILED/Exiled.API/Features/Doors/Door.cs | 2 +-
EXILED/Exiled.API/Features/Generator.cs | 2 +-
EXILED/Exiled.API/Features/Hazards/Hazard.cs | 2 +-
EXILED/Exiled.API/Features/Items/Ammo.cs | 2 +-
EXILED/Exiled.API/Features/Items/Item.cs | 2 +-
EXILED/Exiled.API/Features/Lift.cs | 2 +-
EXILED/Exiled.API/Features/Player.cs | 173 +++++++++++++++++-
EXILED/Exiled.API/Features/Ragdoll.cs | 2 +-
EXILED/Exiled.API/Features/Recontainer.cs | 5 +
EXILED/Exiled.API/Features/Roles/FpcRole.cs | 16 ++
.../Exiled.API/Features/Roles/Scp049Role.cs | 2 +-
.../Exiled.API/Features/Roles/Scp079Role.cs | 3 +-
.../Exiled.API/Features/Roles/Scp096Role.cs | 3 +-
.../Exiled.API/Features/Roles/Scp106Role.cs | 3 +-
.../Exiled.API/Features/Roles/Scp173Role.cs | 3 +-
.../Exiled.API/Features/Roles/Scp3114Role.cs | 2 +-
.../Exiled.API/Features/Roles/Scp939Role.cs | 3 +-
EXILED/Exiled.API/Features/Room.cs | 2 +-
EXILED/Exiled.API/Features/TeslaGate.cs | 2 +-
EXILED/Exiled.API/Features/Window.cs | 2 +-
.../Patches/Events/Map/SpawningItem.cs | 16 +-
.../Patches/Events/Player/Escaping.cs | 27 +--
.../Patches/Events/Server/Reporting.cs | 4 +-
.../Patches/Generic/GetCustomAmmoLimit.cs | 35 ++++
.../Patches/Generic/GetCustomCategoryLimit.cs | 34 ++++
28 files changed, 308 insertions(+), 54 deletions(-)
create mode 100644 EXILED/Exiled.Events/Patches/Generic/GetCustomAmmoLimit.cs
create mode 100644 EXILED/Exiled.Events/Patches/Generic/GetCustomCategoryLimit.cs
diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
index 2dd66766c..e85b54ed6 100644
--- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
+++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
@@ -435,12 +435,11 @@ public static void SendFakeTargetRpc(Player target, NetworkIdentity behaviorOwne
///
/// EffectOnlySCP207.
///
- /// MirrorExtensions.SendCustomSync(player, player.ReferenceHub.networkIdentity, typeof(PlayerEffectsController), (writer) => {
- /// writer.WriteUInt64(1ul); // DirtyObjectsBit
- /// writer.WriteUInt32(1); // DirtyIndexCount
+ /// MirrorExtensions.SendFakeSyncObject(player, player.NetworkIdentity, typeof(PlayerEffectsController), (writer) => {
+ /// writer.WriteULong(1ul); // DirtyObjectsBit
+ /// writer.WriteUInt(1); // DirtyIndexCount
/// writer.WriteByte((byte)SyncList<byte>.Operation.OP_SET); // Operations
- /// writer.WriteUInt32(17); // EditIndex
- /// writer.WriteByte(1); // Value
+ /// writer.WriteUInt(17); // EditIndex
/// });
///
///
diff --git a/EXILED/Exiled.API/Features/Camera.cs b/EXILED/Exiled.API/Features/Camera.cs
index 67f5d7418..56e7e7f24 100644
--- a/EXILED/Exiled.API/Features/Camera.cs
+++ b/EXILED/Exiled.API/Features/Camera.cs
@@ -28,7 +28,7 @@ public class Camera : IWrapper, IWorldSpace
///
/// A containing all known s and their corresponding .
///
- internal static readonly Dictionary Camera079ToCamera = new(250);
+ internal static readonly Dictionary Camera079ToCamera = new(250, new ComponentsEqualityComparer());
private static readonly Dictionary NameToCameraType = new()
{
diff --git a/EXILED/Exiled.API/Features/Doors/AirlockController.cs b/EXILED/Exiled.API/Features/Doors/AirlockController.cs
index 62645a392..eceda5f31 100644
--- a/EXILED/Exiled.API/Features/Doors/AirlockController.cs
+++ b/EXILED/Exiled.API/Features/Doors/AirlockController.cs
@@ -20,7 +20,7 @@ public class AirlockController
///
/// A containing all known 's and their corresponding .
///
- internal static readonly Dictionary BaseToExiledControllers = new();
+ internal static readonly Dictionary BaseToExiledControllers = new(new ComponentsEqualityComparer());
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Doors/Door.cs b/EXILED/Exiled.API/Features/Doors/Door.cs
index 584dc3fb0..230e05b0b 100644
--- a/EXILED/Exiled.API/Features/Doors/Door.cs
+++ b/EXILED/Exiled.API/Features/Doors/Door.cs
@@ -38,7 +38,7 @@ public class Door : TypeCastObject, IWrapper, IWorldSpace
///
/// A containing all known 's and their corresponding .
///
- internal static readonly Dictionary DoorVariantToDoor = new();
+ internal static readonly Dictionary DoorVariantToDoor = new(new ComponentsEqualityComparer());
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Generator.cs b/EXILED/Exiled.API/Features/Generator.cs
index b3f5bfb69..315f9af0f 100644
--- a/EXILED/Exiled.API/Features/Generator.cs
+++ b/EXILED/Exiled.API/Features/Generator.cs
@@ -26,7 +26,7 @@ public class Generator : IWrapper, IWorldSpace
///
/// A of on the map.
///
- internal static readonly Dictionary Scp079GeneratorToGenerator = new();
+ internal static readonly Dictionary Scp079GeneratorToGenerator = new(new ComponentsEqualityComparer());
private Room room;
///
diff --git a/EXILED/Exiled.API/Features/Hazards/Hazard.cs b/EXILED/Exiled.API/Features/Hazards/Hazard.cs
index 6861d1a68..36695f6de 100644
--- a/EXILED/Exiled.API/Features/Hazards/Hazard.cs
+++ b/EXILED/Exiled.API/Features/Hazards/Hazard.cs
@@ -25,7 +25,7 @@ public class Hazard : TypeCastObject, IWrapper
///
/// with to it's .
///
- internal static readonly Dictionary EnvironmentalHazardToHazard = new();
+ internal static readonly Dictionary EnvironmentalHazardToHazard = new(new ComponentsEqualityComparer());
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Items/Ammo.cs b/EXILED/Exiled.API/Features/Items/Ammo.cs
index 4c88a7f84..64c598ad7 100644
--- a/EXILED/Exiled.API/Features/Items/Ammo.cs
+++ b/EXILED/Exiled.API/Features/Items/Ammo.cs
@@ -20,7 +20,7 @@ public class Ammo : Item, IWrapper
///
/// Gets the absolute maximum amount of ammo that may be held at one time, if ammo is forcefully given to the player (regardless of worn armor or server configuration).
///
- /// For accessing the maximum amount of ammo that may be held based on worn armor and server settings, see .
+ /// For accessing the maximum amount of ammo that may be held based on worn armor and server settings, see .
///
///
public const ushort AmmoLimit = ushort.MaxValue;
diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs
index fd0bba35a..b38f4aa18 100644
--- a/EXILED/Exiled.API/Features/Items/Item.cs
+++ b/EXILED/Exiled.API/Features/Items/Item.cs
@@ -43,7 +43,7 @@ public class Item : TypeCastObject- , IWrapper
///
/// A dictionary of all 's that have been converted into .
///
- internal static readonly Dictionary BaseToItem = new();
+ internal static readonly Dictionary BaseToItem = new(new ComponentsEqualityComparer());
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Lift.cs b/EXILED/Exiled.API/Features/Lift.cs
index 944e5bd77..5222ca985 100644
--- a/EXILED/Exiled.API/Features/Lift.cs
+++ b/EXILED/Exiled.API/Features/Lift.cs
@@ -33,7 +33,7 @@ public class Lift : IWrapper, IWorldSpace
///
/// A containing all known s and their corresponding .
///
- internal static readonly Dictionary ElevatorChamberToLift = new(8);
+ internal static readonly Dictionary ElevatorChamberToLift = new(8, new ComponentsEqualityComparer());
///
/// Internal list that contains all ElevatorDoor for current group.
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index b62524745..9172aab3e 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -80,6 +80,16 @@ public class Player : TypeCastObject, IEntity, IWorldSpace
/// A list of the player's items.
///
internal readonly List- ItemsValue = new(8);
+
+ ///
+ /// A dictionary of custom item category limits.
+ ///
+ internal Dictionary CustomCategoryLimits = new();
+
+ ///
+ /// A dictionary of custom ammo limits.
+ ///
+ internal Dictionary CustomAmmoLimits = new();
#pragma warning restore SA1401
private readonly HashSet componentsInChildren = new();
@@ -2382,21 +2392,170 @@ public bool DropAmmo(AmmoType ammoType, ushort amount, bool checkMinimals = fals
///
/// Gets the maximum amount of ammo the player can hold, given the ammo .
- /// This method factors in the armor the player is wearing, as well as server configuration.
- /// For the maximum amount of ammo that can be given regardless of worn armor and server configuration, see .
///
/// The of the ammo to check.
- /// The maximum amount of ammo this player can carry. Guaranteed to be between 0 and .
- public int GetAmmoLimit(AmmoType type) =>
- InventorySystem.Configs.InventoryLimits.GetAmmoLimit(type.GetItemType(), referenceHub);
+ /// If the method should ignore the armor the player is wearing.
+ /// The maximum amount of ammo this player can carry.
+ public ushort GetAmmoLimit(AmmoType type, bool ignoreArmor = false)
+ {
+ if (ignoreArmor)
+ {
+ if (CustomAmmoLimits.TryGetValue(type, out ushort limit))
+ return limit;
+
+ ItemType itemType = type.GetItemType();
+ return ServerConfigSynchronizer.Singleton.AmmoLimitsSync.FirstOrDefault(x => x.AmmoType == itemType).Limit;
+ }
+
+ return InventorySystem.Configs.InventoryLimits.GetAmmoLimit(type.GetItemType(), referenceHub);
+ }
+
+ ///
+ /// Gets the maximum amount of ammo the player can hold, given the ammo .
+ /// This limit will scale with the armor the player is wearing.
+ /// For armor ammo limits, see .
+ ///
+ /// The of the ammo to check.
+ /// The number that will define the new limit.
+ public void SetAmmoLimit(AmmoType ammoType, ushort limit)
+ {
+ CustomAmmoLimits[ammoType] = limit;
+
+ ItemType itemType = ammoType.GetItemType();
+ int index = ServerConfigSynchronizer.Singleton.AmmoLimitsSync.FindIndex(x => x.AmmoType == itemType);
+ MirrorExtensions.SendFakeSyncObject(this, ServerConfigSynchronizer.Singleton.netIdentity, typeof(ServerConfigSynchronizer), writer =>
+ {
+ writer.WriteULong(2ul);
+ writer.WriteUInt(1);
+ writer.WriteByte((byte)SyncList.Operation.OP_SET);
+ writer.WriteInt(index);
+ writer.WriteAmmoLimit(new() { Limit = limit, AmmoType = itemType, });
+ });
+ }
+
+ ///
+ /// Reset a custom limit.
+ ///
+ /// The of the ammo to reset.
+ public void ResetAmmoLimit(AmmoType ammoType)
+ {
+ if (!HasCustomAmmoLimit(ammoType))
+ {
+ Log.Error($"{nameof(Player)}.{nameof(ResetAmmoLimit)}(AmmoType): AmmoType.{ammoType} does not have a custom limit.");
+ return;
+ }
+
+ CustomAmmoLimits.Remove(ammoType);
+
+ ItemType itemType = ammoType.GetItemType();
+ int index = ServerConfigSynchronizer.Singleton.AmmoLimitsSync.FindIndex(x => x.AmmoType == itemType);
+ MirrorExtensions.SendFakeSyncObject(this, ServerConfigSynchronizer.Singleton.netIdentity, typeof(ServerConfigSynchronizer), writer =>
+ {
+ writer.WriteULong(2ul);
+ writer.WriteUInt(1);
+ writer.WriteByte((byte)SyncList.Operation.OP_SET);
+ writer.WriteInt(index);
+ writer.WriteAmmoLimit(ServerConfigSynchronizer.Singleton.AmmoLimitsSync[index]);
+ });
+ }
+
+ ///
+ /// Check if the player has a custom limit for a specific .
+ ///
+ /// The to check.
+ /// If the player has a custom limit for the specific .
+ public bool HasCustomAmmoLimit(AmmoType ammoType) => CustomAmmoLimits.ContainsKey(ammoType);
///
/// Gets the maximum amount of an the player can hold, based on the armor the player is wearing, as well as server configuration.
///
/// The to check.
+ /// If the method should ignore the armor the player is wearing.
/// The maximum amount of items in the category that the player can hold.
- public int GetCategoryLimit(ItemCategory category) =>
- InventorySystem.Configs.InventoryLimits.GetCategoryLimit(category, referenceHub);
+ public sbyte GetCategoryLimit(ItemCategory category, bool ignoreArmor = false)
+ {
+ int index = InventorySystem.Configs.InventoryLimits.StandardCategoryLimits.Where(x => x.Value >= 0).OrderBy(x => x.Key).ToList().FindIndex(x => x.Key == category);
+
+ if (ignoreArmor && index != -1)
+ {
+ if (CustomCategoryLimits.TryGetValue(category, out sbyte customLimit))
+ return customLimit;
+
+ return ServerConfigSynchronizer.Singleton.CategoryLimits[index];
+ }
+
+ sbyte limit = InventorySystem.Configs.InventoryLimits.GetCategoryLimit(category, referenceHub);
+
+ return limit == -1 ? (sbyte)1 : limit;
+ }
+
+ ///
+ /// Set the maximum amount of an the player can hold. Only works with , , , and .
+ /// This limit will scale with the armor the player is wearing.
+ /// For armor category limits, see .
+ ///
+ /// The to check.
+ /// The number that will define the new limit.
+ public void SetCategoryLimit(ItemCategory category, sbyte limit)
+ {
+ int index = InventorySystem.Configs.InventoryLimits.StandardCategoryLimits.Where(x => x.Value >= 0).OrderBy(x => x.Key).ToList().FindIndex(x => x.Key == category);
+
+ if (index == -1)
+ {
+ Log.Error($"{nameof(Player)}.{nameof(SetCategoryLimit)}(ItemCategory, sbyte): Cannot set category limit for ItemCategory.{category}.");
+ return;
+ }
+
+ CustomCategoryLimits[category] = limit;
+
+ MirrorExtensions.SendFakeSyncObject(this, ServerConfigSynchronizer.Singleton.netIdentity, typeof(ServerConfigSynchronizer), writer =>
+ {
+ writer.WriteULong(1ul);
+ writer.WriteUInt(1);
+ writer.WriteByte((byte)SyncList.Operation.OP_SET);
+ writer.WriteInt(index);
+ writer.WriteSByte(limit);
+ });
+ }
+
+ ///
+ /// Reset a custom limit. Only works with , , , and .
+ ///
+ /// The of the category to reset.
+ public void ResetCategoryLimit(ItemCategory category)
+ {
+ int index = InventorySystem.Configs.InventoryLimits.StandardCategoryLimits.Where(x => x.Value >= 0).OrderBy(x => x.Key).ToList().FindIndex(x => x.Key == category);
+
+ if (index == -1)
+ {
+ Log.Error($"{nameof(Player)}.{nameof(ResetCategoryLimit)}(ItemCategory, sbyte): Cannot reset category limit for ItemCategory.{category}.");
+ return;
+ }
+
+ if (!HasCustomCategoryLimit(category))
+ {
+ Log.Error($"{nameof(Player)}.{nameof(ResetCategoryLimit)}(ItemCategory): ItemCategory.{category} does not have a custom limit.");
+ return;
+ }
+
+ CustomCategoryLimits.Remove(category);
+
+ MirrorExtensions.SendFakeSyncObject(this, ServerConfigSynchronizer.Singleton.netIdentity, typeof(ServerConfigSynchronizer), writer =>
+ {
+ writer.WriteULong(1ul);
+ writer.WriteUInt(1);
+ writer.WriteByte((byte)SyncList.Operation.OP_SET);
+ writer.WriteInt(index);
+ writer.WriteSByte(ServerConfigSynchronizer.Singleton.CategoryLimits[index]);
+ });
+ }
+
+ ///
+ /// Check if the player has a custom limit for a specific .
+ ///
+ /// The to check.
+ /// If the player has a custom limit for the specific .
+ public bool HasCustomCategoryLimit(ItemCategory category) => CustomCategoryLimits.ContainsKey(category);
///
/// Adds an item of the specified type with default durability(ammo/charge) and no mods to the player's inventory.
diff --git a/EXILED/Exiled.API/Features/Ragdoll.cs b/EXILED/Exiled.API/Features/Ragdoll.cs
index 9d73104fe..e1aefa56a 100644
--- a/EXILED/Exiled.API/Features/Ragdoll.cs
+++ b/EXILED/Exiled.API/Features/Ragdoll.cs
@@ -40,7 +40,7 @@ public class Ragdoll : IWrapper, IWorldSpace
///
/// A containing all known s and their corresponding .
///
- internal static readonly Dictionary BasicRagdollToRagdoll = new(250);
+ internal static readonly Dictionary BasicRagdollToRagdoll = new(250, new ComponentsEqualityComparer());
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Recontainer.cs b/EXILED/Exiled.API/Features/Recontainer.cs
index bdbbfcdf7..a63f8ada5 100644
--- a/EXILED/Exiled.API/Features/Recontainer.cs
+++ b/EXILED/Exiled.API/Features/Recontainer.cs
@@ -35,6 +35,11 @@ public static class Recontainer
///
public static bool IsCassieBusy => Base.CassieBusy;
+ ///
+ /// Gets a value about how many generator have been activated.
+ ///
+ public static int EngagedGeneratorCount => Base._prevEngaged;
+
///
/// Gets or sets a value indicating whether the containment zone is open.
///
diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs
index 27abeded8..dcf4e27cb 100644
--- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs
+++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs
@@ -8,9 +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;
@@ -24,6 +26,7 @@ namespace Exiled.API.Features.Roles
///
public abstract class FpcRole : Role
{
+ private static FieldInfo enableFallDamageField;
private bool isUsingStamina = true;
///
@@ -55,6 +58,19 @@ public RelativePosition RelativePosition
set => FirstPersonController.FpcModule.Motor.ReceivedPosition = 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);
+ }
+ }
+
///
/// Gets or sets a value indicating whether if a rotation is detected on the player.
///
diff --git a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs
index aecc872d4..eff90bc44 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs
@@ -25,7 +25,7 @@ namespace Exiled.API.Features.Roles
///
/// Defines a role that represents SCP-049.
///
- public class Scp049Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole
+ public class Scp049Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp
{
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Roles/Scp079Role.cs b/EXILED/Exiled.API/Features/Roles/Scp079Role.cs
index 8782137a7..a3de5059c 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp079Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp079Role.cs
@@ -16,6 +16,7 @@ namespace Exiled.API.Features.Roles
using MapGeneration;
using Mirror;
using PlayerRoles;
+ using PlayerRoles.PlayableScps;
using PlayerRoles.PlayableScps.Scp079;
using PlayerRoles.PlayableScps.Scp079.Cameras;
using PlayerRoles.PlayableScps.Scp079.Pinging;
@@ -31,7 +32,7 @@ namespace Exiled.API.Features.Roles
///
/// Defines a role that represents SCP-079.
///
- public class Scp079Role : Role, ISubroutinedScpRole
+ public class Scp079Role : Role, ISubroutinedScpRole, ISpawnableScp
{
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs
index 6d2662ad3..f30342b17 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs
@@ -11,6 +11,7 @@ namespace Exiled.API.Features.Roles
using System.Linq;
using PlayerRoles;
+ using PlayerRoles.PlayableScps;
using PlayerRoles.PlayableScps.HumeShield;
using PlayerRoles.PlayableScps.Scp096;
using PlayerRoles.Subroutines;
@@ -20,7 +21,7 @@ namespace Exiled.API.Features.Roles
///
/// Defines a role that represents SCP-096.
///
- public class Scp096Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole
+ public class Scp096Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp
{
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Roles/Scp106Role.cs b/EXILED/Exiled.API/Features/Roles/Scp106Role.cs
index 826e756a5..9480a37bc 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp106Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp106Role.cs
@@ -11,6 +11,7 @@ namespace Exiled.API.Features.Roles
using Exiled.API.Enums;
using PlayerRoles;
+ using PlayerRoles.PlayableScps;
using PlayerRoles.PlayableScps.HumeShield;
using PlayerRoles.PlayableScps.Scp049;
using PlayerRoles.PlayableScps.Scp106;
@@ -24,7 +25,7 @@ namespace Exiled.API.Features.Roles
///
/// Defines a role that represents SCP-106.
///
- public class Scp106Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole
+ public class Scp106Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp
{
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Roles/Scp173Role.cs b/EXILED/Exiled.API/Features/Roles/Scp173Role.cs
index 23536f696..3a5f625ca 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp173Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp173Role.cs
@@ -13,6 +13,7 @@ namespace Exiled.API.Features.Roles
using Exiled.API.Features.Hazards;
using Mirror;
using PlayerRoles;
+ using PlayerRoles.PlayableScps;
using PlayerRoles.PlayableScps.HumeShield;
using PlayerRoles.PlayableScps.Scp173;
using PlayerRoles.Subroutines;
@@ -23,7 +24,7 @@ namespace Exiled.API.Features.Roles
///
/// Defines a role that represents SCP-173.
///
- public class Scp173Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole
+ public class Scp173Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp
{
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs
index 3f7f6fae1..0d23e48ba 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs
@@ -23,7 +23,7 @@ namespace Exiled.API.Features.Roles
///
/// Defines a role that represents SCP-3114.
///
- public class Scp3114Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole
+ public class Scp3114Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp
{
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Roles/Scp939Role.cs b/EXILED/Exiled.API/Features/Roles/Scp939Role.cs
index b6dca72b8..ec404f349 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp939Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp939Role.cs
@@ -13,6 +13,7 @@ namespace Exiled.API.Features.Roles
using Exiled.API.Features.Pools;
using PlayerRoles;
+ using PlayerRoles.PlayableScps;
using PlayerRoles.PlayableScps.HumeShield;
using PlayerRoles.PlayableScps.Scp939;
using PlayerRoles.PlayableScps.Scp939.Mimicry;
@@ -28,7 +29,7 @@ namespace Exiled.API.Features.Roles
///
/// Defines a role that represents SCP-939.
///
- public class Scp939Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole
+ public class Scp939Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp
{
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Room.cs b/EXILED/Exiled.API/Features/Room.cs
index 8d0b70fe3..4ca8bc4d3 100644
--- a/EXILED/Exiled.API/Features/Room.cs
+++ b/EXILED/Exiled.API/Features/Room.cs
@@ -32,7 +32,7 @@ public class Room : MonoBehaviour, IWorldSpace
///
/// A containing all known s and their corresponding .
///
- internal static readonly Dictionary RoomIdentifierToRoom = new(250);
+ internal static readonly Dictionary RoomIdentifierToRoom = new(250, new ComponentsEqualityComparer());
///
/// Gets a of which contains all the instances.
diff --git a/EXILED/Exiled.API/Features/TeslaGate.cs b/EXILED/Exiled.API/Features/TeslaGate.cs
index 7ebdf6480..d161e6b08 100644
--- a/EXILED/Exiled.API/Features/TeslaGate.cs
+++ b/EXILED/Exiled.API/Features/TeslaGate.cs
@@ -27,7 +27,7 @@ public class TeslaGate : IWrapper, IWorldSpace
///
/// A containing all known s and their corresponding .
///
- internal static readonly Dictionary BaseTeslaGateToTeslaGate = new(10);
+ internal static readonly Dictionary BaseTeslaGateToTeslaGate = new(10, new ComponentsEqualityComparer());
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.API/Features/Window.cs b/EXILED/Exiled.API/Features/Window.cs
index 961fbab88..63ca362fd 100644
--- a/EXILED/Exiled.API/Features/Window.cs
+++ b/EXILED/Exiled.API/Features/Window.cs
@@ -25,7 +25,7 @@ public class Window : IWrapper, IWorldSpace
///
/// A containing all known s and their corresponding .
///
- internal static readonly Dictionary BreakableWindowToWindow = new();
+ internal static readonly Dictionary BreakableWindowToWindow = new(new ComponentsEqualityComparer());
///
/// Initializes a new instance of the class.
diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs
index ff3cd5762..28fd021f0 100644
--- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs
@@ -67,7 +67,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable instruction.IsLdarg(0));
newInstructions[lastIndex].labels.Add(doorSpawn);
+ // Replace
+ // "base.RegisterUnspawnedObject(doorNametagExtension.TargetDoor, itemPickupBase.gameObject);"
+ // with "base.RegisterUnspawnedObject(ev.Door.Base, itemPickupBase.gameObject);"
offset = -1;
index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldfld) + offset;
@@ -122,7 +120,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions);
- int e = 0;
+ LocalBuilder fpcRole = generator.DeclareLocal(typeof(FpcStandardRoleBase));
+
+ // replace HumanRole to FpcStandardRoleBase
+ newInstructions.Find(x => x.opcode == OpCodes.Isinst).operand = typeof(FpcStandardRoleBase);
+
+ // after this index all invalid exit are considered Custom
+ int customExit = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldarg_0);
for (int i = 0; i < newInstructions.Count; i++)
{
- CodeInstruction codeInstruction = newInstructions[i];
- if (codeInstruction.opcode == OpCodes.Ldc_I4_0)
- {
- e++;
- if (e > 3)
- {
- newInstructions[i].opcode = OpCodes.Ldc_I4_5;
- }
- }
+ OpCode opcode = newInstructions[i].opcode;
+ if (opcode == OpCodes.Stloc_0)
+ newInstructions[i] = new(OpCodes.Stloc_S, fpcRole.LocalIndex);
+ else if (opcode == OpCodes.Ldloc_0)
+ newInstructions[i] = new(OpCodes.Ldloc_S, fpcRole.LocalIndex);
+ else if (opcode == OpCodes.Ldc_I4_0 && i > customExit)
+ newInstructions[i].opcode = OpCodes.Ldc_I4_5;
}
for (int z = 0; z < newInstructions.Count; z++)
diff --git a/EXILED/Exiled.Events/Patches/Events/Server/Reporting.cs b/EXILED/Exiled.Events/Patches/Events/Server/Reporting.cs
index bba54c92e..5d22e96c5 100644
--- a/EXILED/Exiled.Events/Patches/Events/Server/Reporting.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Server/Reporting.cs
@@ -40,8 +40,8 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Newarr) + offset;
+ int offset = 2;
+ int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ldarg_S && instruction.operand == (object)4) + offset;
Label ret = generator.DefineLabel();
diff --git a/EXILED/Exiled.Events/Patches/Generic/GetCustomAmmoLimit.cs b/EXILED/Exiled.Events/Patches/Generic/GetCustomAmmoLimit.cs
new file mode 100644
index 000000000..eb533862e
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Generic/GetCustomAmmoLimit.cs
@@ -0,0 +1,35 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Generic
+{
+ using System;
+
+ using Exiled.API.Extensions;
+ using Exiled.API.Features;
+ using HarmonyLib;
+ using InventorySystem.Configs;
+ using UnityEngine;
+
+ ///
+ /// Patches the delegate.
+ /// Sync .
+ /// Changes to .
+ ///
+ [HarmonyPatch(typeof(InventoryLimits), nameof(InventoryLimits.GetAmmoLimit), new Type[] { typeof(ItemType), typeof(ReferenceHub) })]
+ internal static class GetCustomAmmoLimit
+ {
+#pragma warning disable SA1313
+ private static void Postfix(ItemType ammoType, ReferenceHub player, ref ushort __result)
+ {
+ if (!Player.TryGet(player, out Player ply) || !ply.CustomAmmoLimits.TryGetValue(ammoType.GetAmmoType(), out ushort limit))
+ return;
+
+ __result = (ushort)Mathf.Clamp(limit + __result - InventoryLimits.GetAmmoLimit(null, ammoType), ushort.MinValue, ushort.MaxValue);
+ }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Patches/Generic/GetCustomCategoryLimit.cs b/EXILED/Exiled.Events/Patches/Generic/GetCustomCategoryLimit.cs
new file mode 100644
index 000000000..8ceff7538
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Generic/GetCustomCategoryLimit.cs
@@ -0,0 +1,34 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Generic
+{
+ using System;
+
+ using Exiled.API.Features;
+ using HarmonyLib;
+ using InventorySystem.Configs;
+ using UnityEngine;
+
+ ///
+ /// Patches the delegate.
+ /// Sync , .
+ /// Changes to .
+ ///
+ [HarmonyPatch(typeof(InventoryLimits), nameof(InventoryLimits.GetCategoryLimit), new Type[] { typeof(ItemCategory), typeof(ReferenceHub), })]
+ internal static class GetCustomCategoryLimit
+ {
+#pragma warning disable SA1313
+ private static void Postfix(ItemCategory category, ReferenceHub player, ref sbyte __result)
+ {
+ if (!Player.TryGet(player, out Player ply) || !ply.CustomCategoryLimits.TryGetValue(category, out sbyte limit))
+ return;
+
+ __result = (sbyte)Mathf.Clamp(limit + __result - InventoryLimits.GetCategoryLimit(null, category), sbyte.MinValue, sbyte.MaxValue);
+ }
+ }
+}
From eb046ac0693bd9359583ebfa678e6b59d903da90 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Tue, 6 Aug 2024 22:55:12 +0200
Subject: [PATCH 10/63] [Events] Fix null reference (#15)
* fix situation when `ply == null`
* lol why
---------
Co-authored-by: IRacle
---
.../EventArgs/Player/ChangingItemEventArgs.cs | 2 +-
.../Patches/Events/Player/Healing.cs | 17 ++++++++++++++++-
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingItemEventArgs.cs
index 403f5f705..2265309e4 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/ChangingItemEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingItemEventArgs.cs
@@ -46,7 +46,7 @@ public Item Item
get => newItem;
set
{
- if (!Player.Inventory.UserInventory.Items.TryGetValue(value.Serial, out _))
+ if (value != null && !Player.Inventory.UserInventory.Items.TryGetValue(value.Serial, out _))
throw new InvalidOperationException("ev.NewItem cannot be set to an item they do not have.");
newItem = value;
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/Healing.cs b/EXILED/Exiled.Events/Patches/Events/Player/Healing.cs
index 6f17fad14..5acbce087 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/Healing.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/Healing.cs
@@ -1,4 +1,4 @@
-// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
//
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
@@ -34,6 +34,8 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions);
Label continueLabel = generator.DefineLabel();
+ Label skipHealing = generator.DefineLabel();
+ Label skipHealed = generator.DefineLabel();
LocalBuilder ev = generator.DeclareLocal(typeof(HealingEventArgs));
LocalBuilder player = generator.DeclareLocal(typeof(Player));
@@ -48,10 +50,14 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable
Date: Tue, 6 Aug 2024 14:59:04 -0600
Subject: [PATCH 11/63] Offline mode support (#19)
* Fix Offline-mode breaking everything
* Add `offline` authentication type and append `@offline` to UserIds during offline mode
* Add offline id support to Player.Get
* Comment transpilers
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
EXILED/Exiled.API/Enums/AuthenticationType.cs | 5 +
.../Exiled.API/Extensions/StringExtensions.cs | 6 +-
EXILED/Exiled.API/Features/Player.cs | 3 +-
.../Patches/Events/Player/Verified.cs | 56 +++++-
.../Patches/Generic/OfflineModeIds.cs | 164 ++++++++++++++++++
5 files changed, 226 insertions(+), 8 deletions(-)
create mode 100644 EXILED/Exiled.Events/Patches/Generic/OfflineModeIds.cs
diff --git a/EXILED/Exiled.API/Enums/AuthenticationType.cs b/EXILED/Exiled.API/Enums/AuthenticationType.cs
index 9de49f902..0590ea097 100644
--- a/EXILED/Exiled.API/Enums/AuthenticationType.cs
+++ b/EXILED/Exiled.API/Enums/AuthenticationType.cs
@@ -42,5 +42,10 @@ public enum AuthenticationType
/// Indicates that the player has been authenticated as DedicatedServer.
///
DedicatedServer,
+
+ ///
+ /// Indicates that the player has been authenticated during Offline mode.
+ ///
+ Offline,
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Extensions/StringExtensions.cs b/EXILED/Exiled.API/Extensions/StringExtensions.cs
index 69b184bc6..37d1a6777 100644
--- a/EXILED/Exiled.API/Extensions/StringExtensions.cs
+++ b/EXILED/Exiled.API/Extensions/StringExtensions.cs
@@ -161,7 +161,11 @@ public static string GetBefore(this string input, char symbol)
///
/// The user id.
/// Returns the raw user id.
- public static string GetRawUserId(this string userId) => userId.Substring(0, userId.LastIndexOf('@'));
+ public static string GetRawUserId(this string userId)
+ {
+ int index = userId.IndexOf('@');
+ return index == -1 ? userId : userId.Substring(0, index);
+ }
///
/// Gets a SHA256 hash of a player's user id without the authentication.
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 9172aab3e..f7403cdb6 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -292,6 +292,7 @@ public AuthenticationType AuthenticationType
"northwood" => AuthenticationType.Northwood,
"localhost" => AuthenticationType.LocalHost,
"ID_Dedicated" => AuthenticationType.DedicatedServer,
+ "offline" => AuthenticationType.Offline,
_ => AuthenticationType.Unknown,
};
}
@@ -1310,7 +1311,7 @@ public static Player Get(string args)
if (int.TryParse(args, out int id))
return Get(id);
- if (args.EndsWith("@steam") || args.EndsWith("@discord") || args.EndsWith("@northwood"))
+ if (args.EndsWith("@steam") || args.EndsWith("@discord") || args.EndsWith("@northwood") || args.EndsWith("@offline"))
{
foreach (Player player in Dictionary.Values)
{
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/Verified.cs b/EXILED/Exiled.Events/Patches/Events/Player/Verified.cs
index 585457a43..ce6697b5d 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/Verified.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/Verified.cs
@@ -7,16 +7,20 @@
namespace Exiled.Events.Patches.Events.Player
{
+#pragma warning disable SA1402 // File may only contain a single type
+#pragma warning disable SA1313 // Parameter names should begin with lower-case letter
using System;
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
using API.Features;
+ using API.Features.Pools;
using CentralAuth;
using Exiled.API.Extensions;
using Exiled.Events.EventArgs.Player;
-
using HarmonyLib;
-#pragma warning disable SA1313 // Parameter names should begin with lower-case letter
+ using static HarmonyLib.AccessTools;
///
/// Patches .
@@ -25,12 +29,16 @@ namespace Exiled.Events.Patches.Events.Player
[HarmonyPatch(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager.FinalizeAuthentication))]
internal static class Verified
{
- private static void Postfix(PlayerAuthenticationManager __instance)
+ ///
+ /// Called after the player has been verified.
+ ///
+ /// The player's hub.
+ internal static void PlayerVerified(ReferenceHub hub)
{
- if (!Player.UnverifiedPlayers.TryGetValue(__instance._hub.gameObject, out Player player))
- Joined.CallEvent(__instance._hub, out player);
+ if (!Player.UnverifiedPlayers.TryGetValue(hub.gameObject, out Player player))
+ Joined.CallEvent(hub, out player);
- Player.Dictionary.Add(__instance._hub.gameObject, player);
+ Player.Dictionary.Add(hub.gameObject, player);
player.IsVerified = true;
player.RawUserId = player.UserId.GetRawUserId();
@@ -39,5 +47,41 @@ private static void Postfix(PlayerAuthenticationManager __instance)
Handlers.Player.OnVerified(new VerifiedEventArgs(player));
}
+
+ private static void Postfix(PlayerAuthenticationManager __instance)
+ {
+ PlayerVerified(__instance._hub);
+ }
+ }
+
+ ///
+ /// Patches .
+ /// Adds the event during offline mode.
+ ///
+ [HarmonyPatch(typeof(NicknameSync), nameof(NicknameSync.UserCode_CmdSetNick__String))]
+ internal static class VerifiedOfflineMode
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ const int offset = 1;
+ int index = newInstructions.FindIndex(x => x.opcode == OpCodes.Callvirt && x.OperandIs(Method(typeof(CharacterClassManager), nameof(CharacterClassManager.SyncServerCmdBinding)))) + offset;
+
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ // Verified.PlayerVerified(this._hub);
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new CodeInstruction(OpCodes.Ldfld, Field(typeof(NicknameSync), nameof(NicknameSync._hub))),
+ new CodeInstruction(OpCodes.Call, Method(typeof(Verified), nameof(Verified.PlayerVerified))),
+ });
+
+ for (int i = 0; i < newInstructions.Count; i++)
+ yield return newInstructions[i];
+
+ ListPool.Pool.Return(newInstructions);
+ }
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Patches/Generic/OfflineModeIds.cs b/EXILED/Exiled.Events/Patches/Generic/OfflineModeIds.cs
new file mode 100644
index 000000000..46c412dc3
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Generic/OfflineModeIds.cs
@@ -0,0 +1,164 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Generic
+{
+#pragma warning disable SA1402 // File may only contain a single type
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using API.Features.Pools;
+ using CentralAuth;
+ using HarmonyLib;
+ using PluginAPI.Core.Interfaces;
+ using PluginAPI.Events;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches to add an @offline suffix to UserIds in Offline Mode.
+ ///
+ [HarmonyPatch(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager.Start))]
+ internal static class OfflineModeIds
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ const int offset = -1;
+ int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Call && instruction.OperandIs(PropertySetter(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager.UserId)))) + offset;
+
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ new CodeInstruction(OpCodes.Call, Method(typeof(OfflineModeIds), nameof(BuildUserId))),
+ });
+
+ for (int i = 0; i < newInstructions.Count; i++)
+ yield return newInstructions[i];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+
+ private static string BuildUserId(string userId) => $"{userId}@offline";
+ }
+
+ ///
+ /// Patches to add the player's UserId to the dictionary.
+ ///
+ [HarmonyPatch(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager.Start))]
+ internal static class OfflineModePlayerIds
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label skipLabel = generator.DefineLabel();
+
+ const int offset = 1;
+ int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Call && instruction.OperandIs(PropertySetter(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager.UserId)))) + offset;
+
+ // if (!Player.PlayersUserIds.ContainsKey(this.UserId))
+ // Player.PlayersUserIds.Add(this.UserId, this._hub);
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ // if (Player.PlayersUserIds.ContainsKey(this.UserId)) goto skip;
+ new(OpCodes.Ldsfld, Field(typeof(PluginAPI.Core.Player), nameof(PluginAPI.Core.Player.PlayersUserIds))),
+ new(OpCodes.Ldarg_0),
+ new(OpCodes.Call, PropertyGetter(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager.UserId))),
+ new(OpCodes.Callvirt, Method(typeof(Dictionary), nameof(Dictionary.ContainsKey))),
+ new(OpCodes.Brtrue_S, skipLabel),
+
+ // Player.PlayersUserIds.Add(this.UserId, this._hub);
+ new(OpCodes.Ldsfld, Field(typeof(PluginAPI.Core.Player), nameof(PluginAPI.Core.Player.PlayersUserIds))),
+ new(OpCodes.Ldarg_0),
+ new(OpCodes.Call, PropertyGetter(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager.UserId))),
+ new(OpCodes.Ldarg_0),
+ new(OpCodes.Ldfld, Field(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager._hub))),
+ new(OpCodes.Callvirt, Method(typeof(Dictionary), nameof(Dictionary.Add))),
+
+ // skip:
+ new CodeInstruction(OpCodes.Nop).WithLabels(skipLabel),
+ });
+
+ for (int i = 0; i < newInstructions.Count; i++)
+ yield return newInstructions[i];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+
+ ///
+ /// Patches to prevent it from executing the event when the server is in offline mode.
+ ///
+ [HarmonyPatch(typeof(ReferenceHub), nameof(ReferenceHub.Start))]
+ internal static class OfflineModeReferenceHub
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ const int offset = 1;
+ int index = newInstructions.FindIndex(x => x.opcode == OpCodes.Callvirt) + offset;
+
+ Label returnLabel = generator.DefineLabel();
+
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ new CodeInstruction(OpCodes.Br_S, returnLabel),
+ });
+
+ newInstructions[newInstructions.Count - 1].WithLabels(returnLabel);
+
+ for (int i = 0; i < newInstructions.Count; i++)
+ yield return newInstructions[i];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+
+ ///
+ /// Patches to execute the event when the server is in offline mode.
+ ///
+ [HarmonyPatch(typeof(NicknameSync), nameof(NicknameSync.UserCode_CmdSetNick__String))]
+ internal static class OfflineModeJoin
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ const int offset = 1;
+ int index = newInstructions.FindIndex(x => x.opcode == OpCodes.Callvirt && x.OperandIs(Method(typeof(CharacterClassManager), nameof(CharacterClassManager.SyncServerCmdBinding)))) + offset;
+
+ // EventManager.ExecuteEvent(new PlayerJoinedEvent(this._hub));
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ // EventManager.ExecuteEvent(new PlayerJoinedEvent(this._hub));
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new CodeInstruction(OpCodes.Ldfld, Field(typeof(NicknameSync), nameof(NicknameSync._hub))),
+ new CodeInstruction(OpCodes.Call, Method(typeof(OfflineModeJoin), nameof(ExecuteNwEvent))),
+ });
+
+ for (int i = 0; i < newInstructions.Count; i++)
+ yield return newInstructions[i];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+
+ private static void ExecuteNwEvent(ReferenceHub hub)
+ {
+ EventManager.ExecuteEvent(new PlayerJoinedEvent(hub));
+ }
+ }
+}
\ No newline at end of file
From 259cabb149861216517fde655fed91095e99f951 Mon Sep 17 00:00:00 2001
From: sky <99112969+skyyt15@users.noreply.github.com>
Date: Tue, 6 Aug 2024 23:00:44 +0200
Subject: [PATCH 12/63] Fix NW bugs (#32)
* Fix Armor Drop
from https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/230
* add comments
* fix scp173 and adding bug report link to summary class
fix https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/143
* Moved patches and fixed Scp173FirstKillPatch
* Add Slowness Fix
Avoid values more than 100 for effect slowness to fix https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/378
* skill issue
* skill issue (again=
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
.../Patches/Fixes/ArmorDropPatch.cs | 55 +++++++++++++++++++
.../Patches/Fixes/Scp173FirstKillPatch.cs | 55 +++++++++++++++++++
.../Patches/Fixes/Scp173SecondKillPatch.cs | 54 ++++++++++++++++++
.../Patches/Fixes/SlownessFix.cs | 2 +-
4 files changed, 165 insertions(+), 1 deletion(-)
create mode 100644 EXILED/Exiled.Events/Patches/Fixes/ArmorDropPatch.cs
create mode 100644 EXILED/Exiled.Events/Patches/Fixes/Scp173FirstKillPatch.cs
create mode 100644 EXILED/Exiled.Events/Patches/Fixes/Scp173SecondKillPatch.cs
diff --git a/EXILED/Exiled.Events/Patches/Fixes/ArmorDropPatch.cs b/EXILED/Exiled.Events/Patches/Fixes/ArmorDropPatch.cs
new file mode 100644
index 000000000..a924f6808
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Fixes/ArmorDropPatch.cs
@@ -0,0 +1,55 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Fixes
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using Exiled.API.Features.Pools;
+ using HarmonyLib;
+ using InventorySystem;
+ using InventorySystem.Items;
+ using InventorySystem.Items.Armor;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches to fix https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/230 bug.
+ ///
+ [HarmonyPatch(typeof(BodyArmorUtils), nameof(BodyArmorUtils.RemoveEverythingExceedingLimits))]
+ internal static class ArmorDropPatch
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label continueLabel = generator.DefineLabel();
+ int continueIndex = newInstructions.FindIndex(x => x.Is(OpCodes.Call, Method(typeof(Dictionary.Enumerator), nameof(Dictionary.Enumerator.MoveNext)))) - 1;
+ newInstructions[continueIndex].WithLabels(continueLabel);
+
+ // before: if (keyValuePair.Value.Category != ItemCategory.Armor)
+ // after: if (keyValuePair.Value.Category != ItemCategory.Armor && keyValuePair.Value.Category != ItemCategory.None)
+ int index = newInstructions.FindIndex(x => x.Is(OpCodes.Ldc_I4_S, 9));
+
+ newInstructions.InsertRange(index, new CodeInstruction[]
+ {
+ // && keyValuePair.Value.Category != ItemCategory.None)
+ new(OpCodes.Ldloca_S, 4),
+ new(OpCodes.Call, PropertyGetter(typeof(KeyValuePair), nameof(KeyValuePair.Value))),
+ new(OpCodes.Ldfld, Field(typeof(ItemBase), nameof(ItemBase.Category))),
+ new(OpCodes.Ldc_I4_0),
+ new(OpCodes.Beq_S, continueLabel),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Patches/Fixes/Scp173FirstKillPatch.cs b/EXILED/Exiled.Events/Patches/Fixes/Scp173FirstKillPatch.cs
new file mode 100644
index 000000000..f66d35058
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Fixes/Scp173FirstKillPatch.cs
@@ -0,0 +1,55 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Fixes
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using API.Features.Pools;
+ using CustomPlayerEffects;
+ using HarmonyLib;
+ using PlayerRoles.PlayableScps.Scp173;
+ using UnityEngine;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches to fix https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/143 bug.
+ ///
+ [HarmonyPatch(typeof(Scp173SnapAbility), nameof(Scp173SnapAbility.TryHitTarget))]
+ internal static class Scp173FirstKillPatch
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label continueLabel = generator.DefineLabel();
+
+ int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldc_I4_0);
+ newInstructions[index].WithLabels(continueLabel);
+
+ newInstructions.InsertRange(index, new CodeInstruction[]
+ {
+ // if (hitboxIdentity.TargetHub.playerEffectController.GetEffect().IsEnabled) return false;
+ new(OpCodes.Ldloc_2),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(HitboxIdentity), nameof(HitboxIdentity.TargetHub))),
+ new(OpCodes.Ldfld, Field(typeof(ReferenceHub), nameof(ReferenceHub.playerEffectsController))),
+ new(OpCodes.Callvirt, Method(typeof(PlayerEffectsController), nameof(PlayerEffectsController.GetEffect), generics: new[] { typeof(SpawnProtected) })),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(StatusEffectBase), nameof(StatusEffectBase.IsEnabled))),
+ new(OpCodes.Brfalse_S, continueLabel),
+ new(OpCodes.Ldc_I4_0),
+ new(OpCodes.Ret),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
diff --git a/EXILED/Exiled.Events/Patches/Fixes/Scp173SecondKillPatch.cs b/EXILED/Exiled.Events/Patches/Fixes/Scp173SecondKillPatch.cs
new file mode 100644
index 000000000..2b6dcb028
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Fixes/Scp173SecondKillPatch.cs
@@ -0,0 +1,54 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Fixes
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using API.Features.Pools;
+ using CustomPlayerEffects;
+ using HarmonyLib;
+ using Mirror;
+ using PlayerRoles.PlayableScps.Scp173;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches to fix https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/143 bug.
+ ///
+ [HarmonyPatch(typeof(Scp173TeleportAbility), nameof(Scp173TeleportAbility.ServerProcessCmd))]
+ internal static class Scp173SecondKillPatch
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label returnLabel = generator.DefineLabel();
+
+ newInstructions[newInstructions.Count - 1].WithLabels(returnLabel);
+
+ int offset = -5;
+ int index = newInstructions.FindIndex(x => x.Is(OpCodes.Callvirt, Method(typeof(MovementTracer), nameof(MovementTracer.GenerateBounds)))) + offset;
+
+ newInstructions.InsertRange(index, new[]
+ {
+ // if (hub.playerEffectController.GetEffect().IsEnabled) return;
+ new CodeInstruction(OpCodes.Ldloc_S, 5).MoveLabelsFrom(newInstructions[index]),
+ new(OpCodes.Ldfld, Field(typeof(ReferenceHub), nameof(ReferenceHub.playerEffectsController))),
+ new(OpCodes.Callvirt, Method(typeof(PlayerEffectsController), nameof(PlayerEffectsController.GetEffect), generics: new[] { typeof(SpawnProtected) })),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(StatusEffectBase), nameof(StatusEffectBase.IsEnabled))),
+ new(OpCodes.Brtrue_S, returnLabel),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
diff --git a/EXILED/Exiled.Events/Patches/Fixes/SlownessFix.cs b/EXILED/Exiled.Events/Patches/Fixes/SlownessFix.cs
index e2e69b756..5a05c31a0 100644
--- a/EXILED/Exiled.Events/Patches/Fixes/SlownessFix.cs
+++ b/EXILED/Exiled.Events/Patches/Fixes/SlownessFix.cs
@@ -62,4 +62,4 @@ private static IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions);
}
}
-}
+}
\ No newline at end of file
From 26d1fcc0d791fd036d4e28fdeb1f63235aeb26ec Mon Sep 17 00:00:00 2001
From: x3rt
Date: Wed, 7 Aug 2024 01:54:44 -0600
Subject: [PATCH 13/63] Useless Event (939 Placed Amnestic Cloud) (#40)
---
.../Scp939/PlacedAmnesticCloudEventArgs.cs | 51 +++++++++++++
EXILED/Exiled.Events/Handlers/Scp939.cs | 11 +++
.../Events/Scp939/PlacedAmnesticCloud.cs | 73 +++++++++++++++++++
3 files changed, 135 insertions(+)
create mode 100644 EXILED/Exiled.Events/EventArgs/Scp939/PlacedAmnesticCloudEventArgs.cs
create mode 100644 EXILED/Exiled.Events/Patches/Events/Scp939/PlacedAmnesticCloud.cs
diff --git a/EXILED/Exiled.Events/EventArgs/Scp939/PlacedAmnesticCloudEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp939/PlacedAmnesticCloudEventArgs.cs
new file mode 100644
index 000000000..107a7c869
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Scp939/PlacedAmnesticCloudEventArgs.cs
@@ -0,0 +1,51 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Scp939
+{
+ using API.Features;
+ using API.Features.Hazards;
+ using Interfaces;
+ using PlayerRoles.PlayableScps.Scp939;
+
+ using Scp939Role = API.Features.Roles.Scp939Role;
+
+ ///
+ /// Contains all information after SCP-939 used its amnestic cloud ability.
+ ///
+ public class PlacedAmnesticCloudEventArgs : IScp939Event
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public PlacedAmnesticCloudEventArgs(ReferenceHub hub, Scp939AmnesticCloudInstance cloud)
+ {
+ Player = Player.Get(hub);
+ AmnesticCloud = new AmnesticCloudHazard(cloud);
+ Scp939 = Player.Role.As();
+ }
+
+ ///
+ /// Gets the player who's controlling SCP-939.
+ ///
+ public Player Player { get; }
+
+ ///
+ /// Gets the instance.
+ ///
+ public AmnesticCloudHazard AmnesticCloud { get; }
+
+ ///
+ public Scp939Role Scp939 { get; }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Handlers/Scp939.cs b/EXILED/Exiled.Events/Handlers/Scp939.cs
index 14d1245c6..e82e94a80 100644
--- a/EXILED/Exiled.Events/Handlers/Scp939.cs
+++ b/EXILED/Exiled.Events/Handlers/Scp939.cs
@@ -32,6 +32,11 @@ public static class Scp939
///
public static Event PlacingAmnesticCloud { get; set; } = new();
+ ///
+ /// Invoked after SCP-939 used its amnestic cloud ability.
+ ///
+ public static Event PlacedAmnesticCloud { get; set; } = new();
+
///
/// Invoked before SCP-939 plays a stolen voice.
///
@@ -81,6 +86,12 @@ public static class Scp939
/// The instance.
public static void OnPlacingAmnesticCloud(PlacingAmnesticCloudEventArgs ev) => PlacingAmnesticCloud.InvokeSafely(ev);
+ ///
+ /// Called after SCP-939 used its amnestic cloud ability.
+ ///
+ /// The instance.
+ public static void OnPlacedAmnesticCloud(PlacedAmnesticCloudEventArgs ev) => PlacedAmnesticCloud.InvokeSafely(ev);
+
///
/// Called before SCP-939 plays a stolen voice.
///
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp939/PlacedAmnesticCloud.cs b/EXILED/Exiled.Events/Patches/Events/Scp939/PlacedAmnesticCloud.cs
new file mode 100644
index 000000000..ac224990f
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Events/Scp939/PlacedAmnesticCloud.cs
@@ -0,0 +1,73 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Events.Scp939
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using Exiled.API.Features.Pools;
+ using Exiled.Events.Attributes;
+ using Exiled.Events.EventArgs.Scp939;
+ using Exiled.Events.Handlers;
+ using HarmonyLib;
+ using PlayerRoles.PlayableScps.Scp939;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches
+ /// to add the event.
+ ///
+ [EventPatch(typeof(Scp939), nameof(Scp939.PlacedAmnesticCloud))]
+ [HarmonyPatch(typeof(Scp939AmnesticCloudAbility), nameof(Scp939AmnesticCloudAbility.OnStateEnabled))]
+ internal static class PlacedAmnesticCloud
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ LocalBuilder cloud = generator.DeclareLocal(typeof(Scp939AmnesticCloudInstance));
+
+ const int offset = -2;
+ int index = newInstructions.FindIndex(x => x.opcode == OpCodes.Callvirt && x.OperandIs(Method(typeof(Scp939AmnesticCloudInstance), nameof(Scp939AmnesticCloudInstance.ServerSetup)))) + offset;
+
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ // Scp939AmnesticCloudInstance cloud = Object.Instantiate(this._instancePrefab)
+ new CodeInstruction(OpCodes.Dup),
+ new CodeInstruction(OpCodes.Stloc_S, cloud),
+ });
+
+ index = newInstructions.Count - 1;
+
+ // Scp939.OnPlacedAmnesticCloud(new PlacedAmnesticCloudEventArgs(this.Owner, cloud));
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ // this.Owner
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(Scp939AmnesticCloudAbility), nameof(Scp939AmnesticCloudAbility.Owner))),
+
+ // cloud
+ new CodeInstruction(OpCodes.Ldloc_S, cloud),
+
+ // Scp939.OnPlacedAmnesticCloud(new PlacedAmnesticCloudEventArgs(this.Owner, cloud));
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(PlacedAmnesticCloudEventArgs))[0]),
+ new(OpCodes.Call, Method(typeof(Scp939), nameof(Scp939.OnPlacedAmnesticCloud))),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file
From 03d6bd7c06b55d132a6b58e8a3c3e6c0f4509dc4 Mon Sep 17 00:00:00 2001
From: TtroubleTT <121741230+TtroubleTT@users.noreply.github.com>
Date: Wed, 7 Aug 2024 13:23:59 -0700
Subject: [PATCH 14/63] Fix custom role classes giving custom ammo when they
are not suppose to (#24)
* Fix custom role classes giving custom ammmo when they are not suppose to
* change to using EnumUtils
* Moved Ammo additions into Inventory call delayed
---
.../API/Features/CustomRole.cs | 29 +++++++------------
1 file changed, 10 insertions(+), 19 deletions(-)
diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs
index 51e4ac008..61f88ec2c 100644
--- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs
+++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs
@@ -537,6 +537,16 @@ public virtual void AddRole(Player player)
Log.Debug($"{Name}: Adding {itemName} to inventory.");
TryAddItem(player, itemName);
}
+
+ if (Ammo.Count > 0)
+ {
+ Log.Debug($"{Name}: Adding Ammo to {player.Nickname} inventory.");
+ foreach (AmmoType type in EnumUtils.Values)
+ {
+ if (type != AmmoType.None)
+ player.SetAmmo(type, Ammo.ContainsKey(type) ? Ammo[type] == ushort.MaxValue ? InventoryLimits.GetAmmoLimit(type.GetItemType(), player.ReferenceHub) : Ammo[type] : (ushort)0);
+ }
+ }
});
Log.Debug($"{Name}: Setting health values.");
@@ -910,25 +920,6 @@ private void OnInternalChangingRole(ChangingRoleEventArgs ev)
{
RemoveRole(ev.Player);
}
- else if (Check(ev.Player))
- {
- Log.Debug($"{Name}: Checking ammo stuff {Ammo.Count}");
- if (Ammo.Count > 0)
- {
- Log.Debug($"{Name}: Clearing ammo");
- ev.Ammo.Clear();
- Timing.CallDelayed(
- 0.5f,
- () =>
- {
- foreach (AmmoType type in Enum.GetValues(typeof(AmmoType)))
- {
- if (type != AmmoType.None)
- ev.Player.SetAmmo(type, Ammo.ContainsKey(type) ? Ammo[type] == ushort.MaxValue ? InventoryLimits.GetAmmoLimit(type.GetItemType(), ev.Player.ReferenceHub) : Ammo[type] : (ushort)0);
- }
- });
- }
- }
}
private void OnSpawningRagdoll(SpawningRagdollEventArgs ev)
From 06cf2d7f8f4d61d1cc081cbcd2749ae310051f49 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Fri, 9 Aug 2024 10:05:15 +0200
Subject: [PATCH 15/63] `Item::Get()` and `Pickup::Get()` (#17)
* `Item::::Get()` and `Pickup::Get()`
* Revert doc change
* Add `Hazard::Get()`
* doc fix
* `Door::Get()`
* AdminToy.Get()
* More implementation
* WeirdFix
* simplify Scp244Spawning patch and AddedComment & NO IL error
* Remove Log.info
* DroppingItem light modifiication
* Moving Item.Get inside the eventargs instead of transpiller
---
EXILED/Exiled.API/Features/Doors/Door.cs | 57 ++++++++++++++-----
EXILED/Exiled.API/Features/Hazards/Hazard.cs | 9 +++
.../Features/Items/ExplosiveGrenade.cs | 2 +-
.../Exiled.API/Features/Items/FlashGrenade.cs | 2 +-
EXILED/Exiled.API/Features/Items/Item.cs | 45 ++++++++++++++-
EXILED/Exiled.API/Features/Items/Scp018.cs | 2 +-
EXILED/Exiled.API/Features/Items/Scp2176.cs | 2 +-
EXILED/Exiled.API/Features/Items/Scp330.cs | 4 +-
EXILED/Exiled.API/Features/Items/Throwable.cs | 2 +-
EXILED/Exiled.API/Features/Lift.cs | 4 +-
EXILED/Exiled.API/Features/Map.cs | 2 +-
EXILED/Exiled.API/Features/Pickups/Pickup.cs | 52 +++++++++++++++++
.../Pickups/Projectiles/Projectile.cs | 43 ++++++++++++--
EXILED/Exiled.API/Features/Player.cs | 4 +-
EXILED/Exiled.API/Features/TeslaGate.cs | 2 +-
EXILED/Exiled.API/Features/Toys/AdminToy.cs | 9 +++
.../Patches/PlayerInventorySee.cs | 3 +-
.../Item/ChangingAttachmentsEventArgs.cs | 14 ++---
.../Map/ExplodingGrenadeEventArgs.cs | 4 +-
.../EventArgs/Map/Scp244SpawningEventArgs.cs | 13 +++--
.../Player/CancellingItemUseEventArgs.cs | 2 +-
.../Player/ChangingMicroHIDStateEventArgs.cs | 2 +-
.../Player/ChangingRadioPresetEventArgs.cs | 2 +-
.../EventArgs/Player/DroppedItemEventArgs.cs | 5 +-
.../Player/ThrowingRequestEventArgs.cs | 2 +-
.../Player/ThrownProjectileEventArgs.cs | 4 +-
.../Player/TogglingFlashlightEventArgs.cs | 2 +-
.../Player/TogglingRadioEventArgs.cs | 2 +-
.../Player/UsingMicroHIDEnergyEventArgs.cs | 2 +-
.../Player/UsingRadioBatteryEventArgs.cs | 2 +-
.../Scp096/StartPryingGateEventArgs.cs | 2 +-
.../EventArgs/Scp244/UsingScp244EventArgs.cs | 2 +-
.../Scp330/DroppingScp330EventArgs.cs | 2 +-
.../Events/Item/ChangingAttachments.cs | 7 +--
.../Patches/Events/Map/Scp244Spawning.cs | 39 ++++++-------
.../Patches/Events/Player/DroppingItem.cs | 7 +--
.../Events/Player/FirearmRequestReceived.cs | 3 +-
.../Patches/Fixes/GrenadePropertiesFix.cs | 3 +-
.../Exiled.Events/Patches/Generic/DoorList.cs | 2 +-
.../Patches/Generic/PickupControlPatch.cs | 7 ++-
40 files changed, 271 insertions(+), 103 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Doors/Door.cs b/EXILED/Exiled.API/Features/Doors/Door.cs
index 230e05b0b..c06a13b9b 100644
--- a/EXILED/Exiled.API/Features/Doors/Door.cs
+++ b/EXILED/Exiled.API/Features/Doors/Door.cs
@@ -14,7 +14,9 @@ namespace Exiled.API.Features.Doors
using Exiled.API.Enums;
using Exiled.API.Extensions;
using Exiled.API.Features.Core;
+ using Exiled.API.Features.Hazards;
using Exiled.API.Interfaces;
+ using global::Hazards;
using Interactables.Interobjects;
using Interactables.Interobjects.DoorUtils;
using MEC;
@@ -309,6 +311,31 @@ public static Door Get(DoorVariant doorVariant)
return DoorVariantToDoor[doorVariant];
}
+ ///
+ /// Gets the by .
+ ///
+ /// The to convert into an door.
+ /// The specified type.
+ /// The door wrapper for the given .
+ public static T Get(DoorVariant doorVariant)
+ where T : Door => Get(doorVariant) as T;
+
+ ///
+ /// Gets a given the specified .
+ ///
+ /// The to search for.
+ /// The with the given or if not found.
+ public static Door Get(DoorType doorType) => List.FirstOrDefault(x => x.Type == doorType);
+
+ ///
+ /// Gets the by .
+ ///
+ /// The to convert into an door.
+ /// The specified type.
+ /// The door wrapper for the given .
+ public static T Get(DoorType doorType)
+ where T : Door => Get(doorType) as T;
+
///
/// Gets a given the specified name.
///
@@ -320,6 +347,15 @@ public static Door Get(string name)
return nameExtension is null ? null : Get(nameExtension.TargetDoor);
}
+ ///
+ /// Gets the by .
+ ///
+ /// The name to search for.
+ /// The specified type.
+ /// The door wrapper for the given .
+ public static T Get(string name)
+ where T : Door => Get(name) as T;
+
///
/// Gets the door object associated with a specific , or creates a new one if there isn't one.
///
@@ -327,20 +363,6 @@ public static Door Get(string name)
/// The with the given name or if not found.
public static Door Get(GameObject gameObject) => gameObject is null ? null : Get(gameObject.GetComponentInChildren());
- ///
- /// Gets a of filtered based on a predicate.
- ///
- /// The condition to satify.
- /// A of which contains elements that satify the condition.
- public static IEnumerable Get(Func predicate) => List.Where(predicate);
-
- ///
- /// Gets a given the specified .
- ///
- /// The to search for.
- /// The with the given or if not found.
- public static Door Get(DoorType doorType) => List.FirstOrDefault(x => x.Type == doorType);
-
///
/// Returns the closest to the given .
///
@@ -367,6 +389,13 @@ public static Door Random(ZoneType type = ZoneType.Unspecified, bool onlyUnbroke
return doors[UnityEngine.Random.Range(0, doors.Count)];
}
+ ///
+ /// Gets a of filtered based on a predicate.
+ ///
+ /// The condition to satify.
+ /// A of which contains elements that satify the condition.
+ public static IEnumerable Get(Func predicate) => List.Where(predicate);
+
///
/// Locks all doors given the specified .
///
diff --git a/EXILED/Exiled.API/Features/Hazards/Hazard.cs b/EXILED/Exiled.API/Features/Hazards/Hazard.cs
index 36695f6de..253825530 100644
--- a/EXILED/Exiled.API/Features/Hazards/Hazard.cs
+++ b/EXILED/Exiled.API/Features/Hazards/Hazard.cs
@@ -123,6 +123,15 @@ public static Hazard Get(EnvironmentalHazard environmentalHazard) =>
_ => new Hazard(environmentalHazard)
};
+ ///
+ /// Gets the by .
+ ///
+ /// The to convert into an hazard.
+ /// The specified type.
+ /// The hazard wrapper for the given .
+ public static T Get(EnvironmentalHazard environmentalHazard)
+ where T : Hazard => Get(environmentalHazard) as T;
+
///
/// Gets the hazard by the room where it's located.
///
diff --git a/EXILED/Exiled.API/Features/Items/ExplosiveGrenade.cs b/EXILED/Exiled.API/Features/Items/ExplosiveGrenade.cs
index 8f9aa165c..0002d5d76 100644
--- a/EXILED/Exiled.API/Features/Items/ExplosiveGrenade.cs
+++ b/EXILED/Exiled.API/Features/Items/ExplosiveGrenade.cs
@@ -119,7 +119,7 @@ public ExplosionGrenadeProjectile SpawnActive(Vector3 position, Player owner = n
ipb.Info = new PickupSyncInfo(Type, Weight, ItemSerialGenerator.GenerateNext());
- ExplosionGrenadeProjectile grenade = (ExplosionGrenadeProjectile)Pickup.Get(ipb);
+ ExplosionGrenadeProjectile grenade = Pickup.Get(ipb);
grenade.Base.gameObject.SetActive(true);
diff --git a/EXILED/Exiled.API/Features/Items/FlashGrenade.cs b/EXILED/Exiled.API/Features/Items/FlashGrenade.cs
index e2d009ac7..979784f2c 100644
--- a/EXILED/Exiled.API/Features/Items/FlashGrenade.cs
+++ b/EXILED/Exiled.API/Features/Items/FlashGrenade.cs
@@ -100,7 +100,7 @@ public FlashbangProjectile SpawnActive(Vector3 position, Player owner = null)
ipb.Info = new PickupSyncInfo(Type, Weight, ItemSerialGenerator.GenerateNext());
- FlashbangProjectile grenade = (FlashbangProjectile)Pickup.Get(ipb);
+ FlashbangProjectile grenade = Pickup.Get(ipb);
grenade.Base.gameObject.SetActive(true);
diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs
index b38f4aa18..96d02257f 100644
--- a/EXILED/Exiled.API/Features/Items/Item.cs
+++ b/EXILED/Exiled.API/Features/Items/Item.cs
@@ -25,7 +25,6 @@ namespace Exiled.API.Features.Items
using InventorySystem.Items.Radio;
using InventorySystem.Items.ThrowableProjectiles;
using InventorySystem.Items.ToggleableLights;
- using InventorySystem.Items.ToggleableLights.Flashlight;
using InventorySystem.Items.Usables;
using InventorySystem.Items.Usables.Scp1576;
using InventorySystem.Items.Usables.Scp244;
@@ -33,7 +32,6 @@ namespace Exiled.API.Features.Items
using UnityEngine;
using BaseConsumable = InventorySystem.Items.Usables.Consumable;
- using Object = UnityEngine.Object;
///
/// A wrapper class for .
@@ -219,6 +217,15 @@ public static Item Get(ItemBase itemBase)
};
}
+ ///
+ /// Gets an existing or creates a new instance of one.
+ ///
+ /// The to convert into an item.
+ /// The specified type.
+ /// The item wrapper for the given .
+ public static T Get(ItemBase itemBase)
+ where T : Item => Get(itemBase) as T;
+
///
/// Gets the Item belonging to the specified serial.
///
@@ -279,6 +286,40 @@ ItemType.KeycardGuard or ItemType.KeycardJanitor or ItemType.KeycardO5 or ItemTy
_ => new Item(type),
};
+ ///
+ /// Creates a new with the proper inherited subclass.
+ ///
+ /// Based on the , the returned can be casted into a subclass to gain more control over the object.
+ /// - Usable items (Adrenaline, Medkit, Painkillers, SCP-207, SCP-268, and SCP-500) should be casted to the class.
+ /// - All valid ammo should be casted to the class.
+ /// - All valid firearms (not including the Micro HID) should be casted to the class.
+ /// - All valid keycards should be casted to the class.
+ /// - All valid armor should be casted to the class.
+ /// - Explosive grenades and SCP-018 should be casted to the class.
+ /// - Flash grenades should be casted to the class.
+ ///
+ ///
+ /// The following have their own respective classes:
+ /// - Flashlights can be casted to .
+ /// - Radios can be casted to .
+ /// - The Micro HID can be casted to .
+ /// - SCP-244 A and B variants can be casted to .
+ /// - SCP-330 can be casted to .
+ /// - SCP-2176 can be casted to the class.
+ /// - SCP-1576 can be casted to the class.
+ /// - Jailbird can be casted to the class.
+ ///
+ ///
+ /// Items that are not listed above do not have a subclass, and can only use the base class.
+ ///
+ ///
+ /// The of the item to create.
+ /// The who owns the item by default.
+ /// The specified type.
+ /// The created. This can be cast as a subclass.
+ public static Item Create(ItemType type, Player owner = null)
+ where T : Item => Create(type, owner) as T;
+
///
/// Gives this item to a .
///
diff --git a/EXILED/Exiled.API/Features/Items/Scp018.cs b/EXILED/Exiled.API/Features/Items/Scp018.cs
index 57f8122c1..7c08c7c6d 100644
--- a/EXILED/Exiled.API/Features/Items/Scp018.cs
+++ b/EXILED/Exiled.API/Features/Items/Scp018.cs
@@ -86,7 +86,7 @@ public Scp018Projectile SpawnActive(Vector3 position, Player owner = null)
ipb.Info = new PickupSyncInfo(Type, Weight, ItemSerialGenerator.GenerateNext());
- Scp018Projectile grenade = (Scp018Projectile)Pickup.Get(ipb);
+ Scp018Projectile grenade = Pickup.Get(ipb);
grenade.Base.gameObject.SetActive(true);
diff --git a/EXILED/Exiled.API/Features/Items/Scp2176.cs b/EXILED/Exiled.API/Features/Items/Scp2176.cs
index 412c371d6..0ca9fc54d 100644
--- a/EXILED/Exiled.API/Features/Items/Scp2176.cs
+++ b/EXILED/Exiled.API/Features/Items/Scp2176.cs
@@ -71,7 +71,7 @@ public Scp2176Projectile SpawnActive(Vector3 position, Player owner = null)
ipb.Info = new PickupSyncInfo(Type, Weight, ItemSerialGenerator.GenerateNext());
- Scp2176Projectile grenade = (Scp2176Projectile)Pickup.Get(ipb);
+ Scp2176Projectile grenade = Pickup.Get(ipb);
grenade.Base.gameObject.SetActive(true);
diff --git a/EXILED/Exiled.API/Features/Items/Scp330.cs b/EXILED/Exiled.API/Features/Items/Scp330.cs
index d0a7e3b9c..689929f12 100644
--- a/EXILED/Exiled.API/Features/Items/Scp330.cs
+++ b/EXILED/Exiled.API/Features/Items/Scp330.cs
@@ -197,7 +197,7 @@ public IEnumerable DropCandy(CandyKindID type, bool dropAll = fals
ipb.Info = new(Type, Weight, ItemSerialGenerator.GenerateNext());
- Scp330Pickup pickup = (Scp330Pickup)Pickup.Get(ipb);
+ Scp330Pickup pickup = Pickup.Get(ipb);
if (exposedType is not CandyKindID.None)
pickup.ExposedCandy = exposedType;
@@ -218,7 +218,7 @@ public IEnumerable DropCandy(CandyKindID type, bool dropAll = fals
ipb.Info = new(Type, Weight, ItemSerialGenerator.GenerateNext());
- Scp330Pickup pickup = (Scp330Pickup)Pickup.Get(ipb);
+ Scp330Pickup pickup = Pickup.Get(ipb);
if (exposedType is not CandyKindID.None)
pickup.ExposedCandy = exposedType;
diff --git a/EXILED/Exiled.API/Features/Items/Throwable.cs b/EXILED/Exiled.API/Features/Items/Throwable.cs
index 4946d1722..4de522295 100644
--- a/EXILED/Exiled.API/Features/Items/Throwable.cs
+++ b/EXILED/Exiled.API/Features/Items/Throwable.cs
@@ -29,7 +29,7 @@ public Throwable(ThrowableItem itemBase)
{
Base = itemBase;
Base.Projectile.gameObject.SetActive(false);
- Projectile = (Projectile)Pickup.Get(Object.Instantiate(Base.Projectile));
+ Projectile = Pickup.Get(Object.Instantiate(Base.Projectile));
Base.Projectile.gameObject.SetActive(true);
Projectile.Serial = Serial;
}
diff --git a/EXILED/Exiled.API/Features/Lift.cs b/EXILED/Exiled.API/Features/Lift.cs
index 5222ca985..9a3b183c2 100644
--- a/EXILED/Exiled.API/Features/Lift.cs
+++ b/EXILED/Exiled.API/Features/Lift.cs
@@ -76,7 +76,7 @@ internal Lift(ElevatorChamber elevator)
///
/// Gets a value of the internal doors list.
///
- public IReadOnlyCollection Doors => internalDoorsList.Select(x => Door.Get(x).As()).ToList();
+ public IReadOnlyCollection Doors => internalDoorsList.Select(x => Door.Get(x)).ToList();
///
/// Gets a of in the .
@@ -201,7 +201,7 @@ public float AnimationTime
///
/// Gets the .
///
- public Doors.ElevatorDoor CurrentDestination => Door.Get(Base.CurrentDestination).As();
+ public Doors.ElevatorDoor CurrentDestination => Door.Get(Base.CurrentDestination);
///
/// Gets a of which contains all the instances from the specified .
diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs
index 24edcc90c..4e8f2b094 100644
--- a/EXILED/Exiled.API/Features/Map.cs
+++ b/EXILED/Exiled.API/Features/Map.cs
@@ -294,7 +294,7 @@ public static TantrumHazard PlaceTantrum(Vector3 position, bool isActive = true)
NetworkServer.Spawn(tantrum.gameObject);
- return Hazard.Get(tantrum).Cast();
+ return Hazard.Get(tantrum);
}
///
diff --git a/EXILED/Exiled.API/Features/Pickups/Pickup.cs b/EXILED/Exiled.API/Features/Pickups/Pickup.cs
index 70db62a8a..3f7373dee 100644
--- a/EXILED/Exiled.API/Features/Pickups/Pickup.cs
+++ b/EXILED/Exiled.API/Features/Pickups/Pickup.cs
@@ -338,6 +338,15 @@ public static Pickup Get(ItemPickupBase pickupBase)
};
}
+ ///
+ /// Gets an existing or creates a new instance of one.
+ ///
+ /// The to convert into an pickup.
+ /// The specified type.
+ /// The pickup wrapper for the given .
+ public static T Get(ItemPickupBase pickupBase)
+ where T : Pickup => Get(pickupBase) as T;
+
///
/// Gets the given a .
///
@@ -487,6 +496,36 @@ public static IEnumerable Get(IEnumerable gameObjects)
_ => new Pickup(type),
};
+ ///
+ /// Creates and returns a new with the proper inherited subclass.
+ ///
+ /// Based on the , the returned can be cast into a subclass to gain more control over the object.
+ /// - All valid ammo should be cast to the class.
+ /// - All valid firearms (not including the Micro HID) should be cast to the class.
+ /// - All valid keycards should be cast to the class.
+ /// - All valid armor should be cast to the class.
+ /// - All grenades and throwables (not including SCP-018 and SCP-2176) should be cast to the class.
+ ///
+ ///
+ /// The following have their own respective classes:
+ /// - Radios can be cast to .
+ /// - The Micro HID can be cast to .
+ /// - SCP-244 A and B variants can be cast to .
+ /// - SCP-330 can be cast to .
+ /// - SCP-018 can be cast to .
+ /// - SCP-2176 can be cast to .
+ ///
+ ///
+ /// Items that are not listed above do not have a subclass, and can only use the base class.
+ ///
+ ///
+ /// The of the pickup.
+ /// The specified type.
+ /// The created .
+ ///
+ public static Pickup Create(ItemType type)
+ where T : Pickup => Create(type) as T;
+
///
/// Creates and spawns a .
///
@@ -498,6 +537,19 @@ public static IEnumerable Get(IEnumerable gameObjects)
///
public static Pickup CreateAndSpawn(ItemType type, Vector3 position, Quaternion rotation, Player previousOwner = null) => Create(type).Spawn(position, rotation, previousOwner);
+ ///
+ /// Creates and spawns a .
+ ///
+ /// The of the pickup.
+ /// The position to spawn the at.
+ /// The rotation to spawn the .
+ /// An optional previous owner of the item.
+ /// The specified type.
+ /// The . See documentation of for more information on casting.
+ ///
+ public static Pickup CreateAndSpawn(ItemType type, Vector3 position, Quaternion rotation, Player previousOwner = null)
+ where T : Pickup => CreateAndSpawn(type, position, rotation, previousOwner) as T;
+
///
/// Spawns a .
///
diff --git a/EXILED/Exiled.API/Features/Pickups/Projectiles/Projectile.cs b/EXILED/Exiled.API/Features/Pickups/Projectiles/Projectile.cs
index cd18059bc..5406d6414 100644
--- a/EXILED/Exiled.API/Features/Pickups/Projectiles/Projectile.cs
+++ b/EXILED/Exiled.API/Features/Pickups/Projectiles/Projectile.cs
@@ -83,17 +83,37 @@ internal Projectile(ItemType type)
/// Projectile that are not listed will cause an Exception.
///
///
- /// The of the pickup.
- /// The created .
+ /// The of the projectile.
+ /// The created .
public static Projectile Create(ProjectileType projectiletype) => projectiletype switch
{
ProjectileType.Scp018 => new Scp018Projectile(),
ProjectileType.Flashbang => new FlashbangProjectile(),
ProjectileType.Scp2176 => new Scp2176Projectile(),
ProjectileType.FragGrenade => new ExplosionGrenadeProjectile(ItemType.GrenadeHE),
- _ => throw new System.Exception($"ProjectileType does not contain a valid value : {projectiletype}"),
+ _ => throw new Exception($"ProjectileType does not contain a valid value : {projectiletype}"),
};
+ ///
+ /// Creates and returns a new with the proper inherited subclass.
+ ///
+ /// Based on the , the returned can be casted into a subclass to gain more control over the object.
+ /// The following have their own respective classes:
+ /// - FragGrenade can be casted to .
+ /// - Flashbang can be casted to .
+ /// - Scp018 A and B variants can be casted to .
+ /// - Scp2176 can be casted to .
+ ///
+ ///
+ /// Projectile that are not listed will cause an Exception.
+ ///
+ ///
+ /// The of the projectile.
+ /// The specified type.
+ /// The created .
+ public static Projectile Create(ProjectileType projectiletype)
+ where T : Projectile => Create(projectiletype) as T;
+
///
/// Spawns a .
///
@@ -110,14 +130,27 @@ public static Projectile Spawn(Projectile pickup, Vector3 position, Quaternion r
///
/// Creates and spawns a .
///
- /// The of the pickup.
+ /// The of the projectile.
/// The position to spawn the at.
/// The rotation to spawn the .
/// Whether the should be in active state after spawn.
/// An optional previous owner of the item.
- /// The . See documentation of for more information on casting.
+ /// The . See documentation of for more information on casting.
public static Projectile CreateAndSpawn(ProjectileType type, Vector3 position, Quaternion rotation, bool shouldBeActive = true, Player previousOwner = null) => Create(type).Spawn(position, rotation, shouldBeActive, previousOwner);
+ ///
+ /// Creates and spawns a .
+ ///
+ /// The of the projectile.
+ /// The position to spawn the at.
+ /// The rotation to spawn the .
+ /// Whether the should be in active state after spawn.
+ /// An optional previous owner of the item.
+ /// The specified type.
+ /// The . See documentation of for more information on casting.
+ public static Projectile CreateAndSpawn(ProjectileType type, Vector3 position, Quaternion rotation, bool shouldBeActive = true, Player previousOwner = null)
+ where T : Projectile => CreateAndSpawn(type, position, rotation, shouldBeActive, previousOwner) as T;
+
///
/// Activates the current .
///
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index f7403cdb6..cb9e84fa3 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -969,7 +969,7 @@ public Item CurrentItem
///
/// Gets the armor that the player is currently wearing. Value will be if the player is not wearing any armor.
///
- public Armor CurrentArmor => Inventory.TryGetBodyArmor(out BodyArmor armor) ? (Armor)Item.Get(armor) : null;
+ public Armor CurrentArmor => Inventory.TryGetBodyArmor(out BodyArmor armor) ? Item.Get(armor) : null;
///
/// Gets the class.
@@ -2767,7 +2767,7 @@ public void AddItem(Firearm item, IEnumerable identifiers)
/// The that was added.
public Item AddItem(FirearmPickup pickup, IEnumerable identifiers)
{
- Firearm firearm = (Firearm)Item.Get(Inventory.ServerAddItem(pickup.Type, pickup.Serial, pickup.Base));
+ Firearm firearm = Item.Get(Inventory.ServerAddItem(pickup.Type, pickup.Serial, pickup.Base));
if (identifiers is not null)
firearm.AddAttachment(identifiers);
diff --git a/EXILED/Exiled.API/Features/TeslaGate.cs b/EXILED/Exiled.API/Features/TeslaGate.cs
index d161e6b08..4d7909592 100644
--- a/EXILED/Exiled.API/Features/TeslaGate.cs
+++ b/EXILED/Exiled.API/Features/TeslaGate.cs
@@ -178,7 +178,7 @@ public bool UseInstantBurst
///
/// Gets a of which contains all the tantrums to destroy.
///
- public IEnumerable TantrumsToDestroy => Base.TantrumsToBeDestroyed.Select(x => Hazard.Get(x) as TantrumHazard);
+ public IEnumerable TantrumsToDestroy => Base.TantrumsToBeDestroyed.Select(x => Hazard.Get(x));
///
/// Gets a of which contains all the players inside the hurt range.
diff --git a/EXILED/Exiled.API/Features/Toys/AdminToy.cs b/EXILED/Exiled.API/Features/Toys/AdminToy.cs
index 2139059e9..5287096a1 100644
--- a/EXILED/Exiled.API/Features/Toys/AdminToy.cs
+++ b/EXILED/Exiled.API/Features/Toys/AdminToy.cs
@@ -159,6 +159,15 @@ public static AdminToy Get(AdminToyBase adminToyBase)
};
}
+ ///
+ /// Gets the by .
+ ///
+ /// The to convert into an admintoy.
+ /// The specified type.
+ /// The admintoy wrapper for the given .
+ public static T Get(AdminToyBase adminToyBase)
+ where T : AdminToy => Get(adminToyBase) as T;
+
///
/// Spawns the toy into the game. Use to remove it.
///
diff --git a/EXILED/Exiled.CustomItems/Patches/PlayerInventorySee.cs b/EXILED/Exiled.CustomItems/Patches/PlayerInventorySee.cs
index 8f35712fb..1620477ba 100644
--- a/EXILED/Exiled.CustomItems/Patches/PlayerInventorySee.cs
+++ b/EXILED/Exiled.CustomItems/Patches/PlayerInventorySee.cs
@@ -8,6 +8,7 @@
namespace Exiled.CustomItems.Patches
{
using System.Collections.Generic;
+ using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
@@ -52,7 +53,7 @@ private static IEnumerable Transpiler(IEnumerable !x.IsGenericMethod && x.Name is nameof(Item.Get) && x.GetParameters().Length is 1 && x.GetParameters()[0].ParameterType == typeof(ItemBase))),
new(OpCodes.Dup),
new(OpCodes.Stloc_S, item.LocalIndex),
new(OpCodes.Brfalse_S, continueLabel),
diff --git a/EXILED/Exiled.Events/EventArgs/Item/ChangingAttachmentsEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/ChangingAttachmentsEventArgs.cs
index 0e1c8fbed..fad3ec0b5 100644
--- a/EXILED/Exiled.Events/EventArgs/Item/ChangingAttachmentsEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Item/ChangingAttachmentsEventArgs.cs
@@ -38,17 +38,13 @@ public class ChangingAttachmentsEventArgs : IPlayerEvent, IDeniableEvent, IFirea
///
///
///
- public ChangingAttachmentsEventArgs(
- Player player,
- Firearm firearm,
- uint code,
- bool isAllowed = true)
+ public ChangingAttachmentsEventArgs(Player player, InventorySystem.Items.Firearms.Firearm firearm, uint code, bool isAllowed = true)
{
Player = player;
- Firearm = firearm;
- CurrentAttachmentIdentifiers = firearm.AttachmentIdentifiers;
- NewAttachmentIdentifiers = firearm.FirearmType.GetAttachmentIdentifiers(code).ToList();
- CurrentCode = firearm.Base.GetCurrentAttachmentsCode();
+ Firearm = Item.Get(firearm);
+ CurrentAttachmentIdentifiers = Firearm.AttachmentIdentifiers;
+ NewAttachmentIdentifiers = Firearm.FirearmType.GetAttachmentIdentifiers(code).ToList();
+ CurrentCode = firearm.GetCurrentAttachmentsCode();
NewCode = code;
IsAllowed = isAllowed;
}
diff --git a/EXILED/Exiled.Events/EventArgs/Map/ExplodingGrenadeEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/ExplodingGrenadeEventArgs.cs
index 28b7b30f0..a0dbd7920 100644
--- a/EXILED/Exiled.Events/EventArgs/Map/ExplodingGrenadeEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Map/ExplodingGrenadeEventArgs.cs
@@ -37,7 +37,7 @@ public class ExplodingGrenadeEventArgs : IPlayerEvent, IDeniableEvent
public ExplodingGrenadeEventArgs(Footprint thrower, Vector3 position, ExplosionGrenade grenade, Collider[] targets)
{
Player = Player.Get(thrower.Hub);
- Projectile = (EffectGrenadeProjectile)Pickup.Get(grenade);
+ Projectile = Pickup.Get(grenade);
Position = position;
TargetsToAffect = ListPool.Pool.Get();
@@ -97,7 +97,7 @@ public ExplodingGrenadeEventArgs(Footprint thrower, Vector3 position, ExplosionG
public ExplodingGrenadeEventArgs(Player thrower, EffectGrenade grenade, List targetsToAffect, bool isAllowed = true)
{
Player = thrower ?? Server.Host;
- Projectile = (EffectGrenadeProjectile)Pickup.Get(grenade);
+ Projectile = Pickup.Get(grenade);
Position = Projectile.Position;
TargetsToAffect = ListPool.Pool.Get(targetsToAffect ?? new());
IsAllowed = isAllowed;
diff --git a/EXILED/Exiled.Events/EventArgs/Map/Scp244SpawningEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/Scp244SpawningEventArgs.cs
index 1ed101269..fd6a6fa76 100644
--- a/EXILED/Exiled.Events/EventArgs/Map/Scp244SpawningEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Map/Scp244SpawningEventArgs.cs
@@ -1,4 +1,4 @@
-// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
//
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
@@ -10,6 +10,8 @@ namespace Exiled.Events.EventArgs.Map
using API.Features;
using Exiled.API.Features.Pickups;
using Interfaces;
+ using InventorySystem.Items.Usables.Scp244;
+ using MapGeneration;
///
/// Contains all information up to spawning Scp244.
@@ -25,11 +27,10 @@ public class Scp244SpawningEventArgs : IRoomEvent, IPickupEvent, IDeniableEvent
///
///
///
- public Scp244SpawningEventArgs(Room room, Pickup scp244Pickup)
+ public Scp244SpawningEventArgs(RoomIdentifier room, Scp244DeployablePickup scp244Pickup)
{
- Room = room;
- Pickup = scp244Pickup;
- Scp244Pickup = scp244Pickup.As();
+ Room = Room.Get(room);
+ Scp244Pickup = Pickup.Get(scp244Pickup);
}
///
@@ -38,7 +39,7 @@ public Scp244SpawningEventArgs(Room room, Pickup scp244Pickup)
public Room Room { get; }
///
- public Pickup Pickup { get; }
+ public Pickup Pickup => Scp244Pickup;
///
/// Gets a value indicating the pickup being spawning.
diff --git a/EXILED/Exiled.Events/EventArgs/Player/CancellingItemUseEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/CancellingItemUseEventArgs.cs
index ac07393e7..f3f623f40 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/CancellingItemUseEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/CancellingItemUseEventArgs.cs
@@ -27,7 +27,7 @@ public class CancellingItemUseEventArgs : IPlayerEvent, IDeniableEvent, IUsableE
public CancellingItemUseEventArgs(Player player, UsableItem item)
{
Player = player;
- Usable = Item.Get(item) is Usable usable ? usable : null;
+ Usable = Item.Get(item);
}
///
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingMicroHIDStateEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingMicroHIDStateEventArgs.cs
index 4cb941b0a..2b9bacdbf 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/ChangingMicroHIDStateEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingMicroHIDStateEventArgs.cs
@@ -40,7 +40,7 @@ public class ChangingMicroHIDStateEventArgs : IPlayerEvent, IDeniableEvent
public ChangingMicroHIDStateEventArgs(Player player, MicroHIDItem microHID, HidState oldState, HidState newState, bool isAllowed = true)
{
Player = player;
- MicroHID = (MicroHid)Item.Get(microHID);
+ MicroHID = Item.Get(microHID);
OldState = oldState;
NewState = newState;
IsAllowed = isAllowed;
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingRadioPresetEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingRadioPresetEventArgs.cs
index 7b59f2fb9..70af9b581 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/ChangingRadioPresetEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingRadioPresetEventArgs.cs
@@ -44,7 +44,7 @@ public class ChangingRadioPresetEventArgs : IPlayerEvent, IItemEvent, IDeniableE
public ChangingRadioPresetEventArgs(Player player, RadioItem item, RadioRangeLevel oldValue, RadioRangeLevel newValue, bool isAllowed = true)
{
Player = player;
- Radio = (Radio)Item.Get(item);
+ Radio = Item.Get(item);
OldValue = (RadioRange)oldValue;
NewValue = (RadioRange)newValue;
IsAllowed = isAllowed;
diff --git a/EXILED/Exiled.Events/EventArgs/Player/DroppedItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/DroppedItemEventArgs.cs
index 14d298c84..0109a4bba 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/DroppedItemEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/DroppedItemEventArgs.cs
@@ -10,6 +10,7 @@ namespace Exiled.Events.EventArgs.Player
using API.Features;
using Exiled.API.Features.Pickups;
using Interfaces;
+ using InventorySystem.Items.Pickups;
///
/// Contains all information after a player drops an item.
@@ -28,10 +29,10 @@ public class DroppedItemEventArgs : IPlayerEvent, IPickupEvent
///
///
///
- public DroppedItemEventArgs(Player player, Pickup pickup, bool wasThrown)
+ public DroppedItemEventArgs(Player player, ItemPickupBase pickup, bool wasThrown)
{
Player = player;
- Pickup = pickup;
+ Pickup = Pickup.Get(pickup);
WasThrown = wasThrown;
}
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ThrowingRequestEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ThrowingRequestEventArgs.cs
index 273763fda..089695333 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/ThrowingRequestEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/ThrowingRequestEventArgs.cs
@@ -28,7 +28,7 @@ public class ThrowingRequestEventArgs : IPlayerEvent, IItemEvent
public ThrowingRequestEventArgs(Player player, ThrowableItem item, ThrowableNetworkHandler.RequestType request)
{
Player = player;
- Throwable = (Throwable)Item.Get(item);
+ Throwable = Item.Get(item);
RequestType = (ThrowRequest)request;
}
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ThrownProjectileEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ThrownProjectileEventArgs.cs
index aaf654d42..26984b839 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/ThrownProjectileEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/ThrownProjectileEventArgs.cs
@@ -29,8 +29,8 @@ public class ThrownProjectileEventArgs : IPlayerEvent, IItemEvent, IPickupEvent
public ThrownProjectileEventArgs(ThrownProjectile projectile, Player player, ThrowableItem item)
{
Player = player;
- Throwable = (Throwable)Item.Get(item);
- Projectile = (Projectile)Pickup.Get(projectile);
+ Throwable = Item.Get(item);
+ Projectile = Pickup.Get(projectile);
}
///
diff --git a/EXILED/Exiled.Events/EventArgs/Player/TogglingFlashlightEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/TogglingFlashlightEventArgs.cs
index b8990f85d..3a87a66a1 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/TogglingFlashlightEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/TogglingFlashlightEventArgs.cs
@@ -35,7 +35,7 @@ public class TogglingFlashlightEventArgs : IPlayerEvent, IDeniableEvent, IItemEv
public TogglingFlashlightEventArgs(ReferenceHub hub, ToggleableLightItemBase flashlight, bool newState)
{
Player = Player.Get(hub);
- Flashlight = (Flashlight)Item.Get(flashlight);
+ Flashlight = Item.Get(flashlight);
initialState = newState;
NewState = newState;
}
diff --git a/EXILED/Exiled.Events/EventArgs/Player/TogglingRadioEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/TogglingRadioEventArgs.cs
index 67db54505..38d0fe09b 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/TogglingRadioEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/TogglingRadioEventArgs.cs
@@ -36,7 +36,7 @@ public class TogglingRadioEventArgs : IPlayerEvent, IDeniableEvent, IItemEvent
public TogglingRadioEventArgs(Player player, RadioItem radio, bool newState, bool isAllowed = true)
{
Player = player;
- Radio = (Radio)Item.Get(radio);
+ Radio = Item.Get(radio);
NewState = newState;
IsAllowed = isAllowed;
}
diff --git a/EXILED/Exiled.Events/EventArgs/Player/UsingMicroHIDEnergyEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UsingMicroHIDEnergyEventArgs.cs
index d98f014ed..402d20e1b 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/UsingMicroHIDEnergyEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/UsingMicroHIDEnergyEventArgs.cs
@@ -40,7 +40,7 @@ public class UsingMicroHIDEnergyEventArgs : IPlayerEvent, IDeniableEvent, IItemE
public UsingMicroHIDEnergyEventArgs(Player player, MicroHIDItem microHIDitem, HidState currentState, float drain, bool isAllowed = true)
{
Player = player;
- MicroHID = (MicroHid)Item.Get(microHIDitem);
+ MicroHID = Item.Get(microHIDitem);
CurrentState = currentState;
Drain = drain;
IsAllowed = isAllowed;
diff --git a/EXILED/Exiled.Events/EventArgs/Player/UsingRadioBatteryEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UsingRadioBatteryEventArgs.cs
index 90369883f..1f07dadde 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/UsingRadioBatteryEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/UsingRadioBatteryEventArgs.cs
@@ -36,7 +36,7 @@ public class UsingRadioBatteryEventArgs : IPlayerEvent, IDeniableEvent, IItemEve
///
public UsingRadioBatteryEventArgs(RadioItem radio, Player player, float drain, bool isAllowed = true)
{
- Radio = (Radio)Item.Get(radio);
+ Radio = Item.Get(radio);
Player = player;
Drain = drain;
IsAllowed = isAllowed;
diff --git a/EXILED/Exiled.Events/EventArgs/Scp096/StartPryingGateEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp096/StartPryingGateEventArgs.cs
index f40e1e874..be8cef0ce 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp096/StartPryingGateEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp096/StartPryingGateEventArgs.cs
@@ -36,7 +36,7 @@ public StartPryingGateEventArgs(Player player, PryableDoor gate, bool isAllowed
{
Player = player;
Scp096 = player.Role.As();
- Gate = Door.Get(gate).As();
+ Gate = Door.Get(gate);
IsAllowed = isAllowed;
}
diff --git a/EXILED/Exiled.Events/EventArgs/Scp244/UsingScp244EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp244/UsingScp244EventArgs.cs
index c3077777c..5dca87a99 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp244/UsingScp244EventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp244/UsingScp244EventArgs.cs
@@ -33,7 +33,7 @@ public class UsingScp244EventArgs : IPlayerEvent, IDeniableEvent
///
public UsingScp244EventArgs(Scp244Item scp244, Player player, bool isAllowed = true)
{
- Scp244 = (Scp244)Item.Get(scp244);
+ Scp244 = Item.Get(scp244);
Player = player;
IsAllowed = isAllowed;
}
diff --git a/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs
index 0105cc1a1..985e90337 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs
@@ -34,7 +34,7 @@ public class DroppingScp330EventArgs : IPlayerEvent, IScp330Event, IDeniableEven
public DroppingScp330EventArgs(Player player, Scp330Bag scp330, CandyKindID candy)
{
Player = player;
- Scp330 = (Scp330)Item.Get(scp330);
+ Scp330 = Item.Get(scp330);
Candy = candy;
}
diff --git a/EXILED/Exiled.Events/Patches/Events/Item/ChangingAttachments.cs b/EXILED/Exiled.Events/Patches/Events/Item/ChangingAttachments.cs
index 3e49274a0..17394e444 100644
--- a/EXILED/Exiled.Events/Patches/Events/Item/ChangingAttachments.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Item/ChangingAttachments.cs
@@ -8,6 +8,7 @@
namespace Exiled.Events.Patches.Events.Item
{
using System.Collections.Generic;
+ using System.Linq;
using System.Reflection.Emit;
using API.Features;
@@ -67,10 +68,8 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions);
- Label continueLabel = generator.DefineLabel();
-
LocalBuilder pickup = generator.DeclareLocal(typeof(ItemPickupBase));
- int index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Dup);
-
- newInstructions.RemoveRange(index, 1);
-
- int offset = 1;
- index = newInstructions.FindIndex(i => i.opcode == OpCodes.Dup) + offset;
- newInstructions.InsertRange(index, new CodeInstruction[]
- {
- new(OpCodes.Dup),
- new(OpCodes.Stloc_S, pickup.LocalIndex),
- });
+ Label continueLabel = generator.DefineLabel();
- offset = -2;
- index = newInstructions.FindIndex(i => i.Calls(Method(typeof(NetworkServer), nameof(NetworkServer.Spawn), new[] { typeof(GameObject), typeof(NetworkConnection) }))) + offset;
+ int offset = -2;
+ int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(NetworkServer), nameof(NetworkServer.Spawn), new[] { typeof(GameObject), typeof(NetworkConnection) }))) + offset;
newInstructions.InsertRange(index, new[]
{
- new CodeInstruction(OpCodes.Ldsfld, Field(typeof(Scp244Spawner), nameof(Scp244Spawner.CompatibleRooms))).MoveLabelsFrom(newInstructions[index]),
+ // save Pickup from the stack
+ new CodeInstruction(OpCodes.Stloc_S, pickup.LocalIndex).MoveLabelsFrom(newInstructions[index]),
+
+ // Scp244Spawner.CompatibleRooms[num]
+ new(OpCodes.Ldsfld, Field(typeof(Scp244Spawner), nameof(Scp244Spawner.CompatibleRooms))),
new(OpCodes.Ldloc_0),
new(OpCodes.Callvirt, PropertyGetter(typeof(List), "Item")),
- new(OpCodes.Ldloc_S, pickup.LocalIndex),
- new(OpCodes.Call, Method(typeof(Pickup), nameof(Pickup.Get), new[] { typeof(ItemPickupBase) })),
+ // scp244DeployablePickup
+ new(OpCodes.Ldloc_2),
+ // Scp244SpawningEventArgs ev = new(Room, Scp244DeployablePickup)
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(Scp244SpawningEventArgs))[0]),
new(OpCodes.Dup),
new(OpCodes.Call, Method(typeof(Handlers.Map), nameof(Handlers.Map.OnScp244Spawning))),
+ // if (ev.IsAllowed) goto continueLabel;
new(OpCodes.Call, PropertyGetter(typeof(Scp244SpawningEventArgs), nameof(Scp244SpawningEventArgs.IsAllowed))),
new(OpCodes.Brtrue_S, continueLabel),
- new(OpCodes.Ldloc_S, pickup.LocalIndex),
+ // scp244DeployablePickup.gameObject.Destroy()
+ // return;
+ new(OpCodes.Ldloc_2),
new(OpCodes.Callvirt, PropertyGetter(typeof(ItemPickupBase), nameof(ItemPickupBase.gameObject))),
new(OpCodes.Call, Method(typeof(NetworkServer), nameof(NetworkServer.Destroy))),
new(OpCodes.Ret),
- new CodeInstruction(OpCodes.Nop).WithLabels(continueLabel),
- new(OpCodes.Ldloc_S, pickup.LocalIndex),
+ // load pickup back into the stack
+ new CodeInstruction(OpCodes.Ldloc_S, pickup.LocalIndex).WithLabels(continueLabel),
});
for (int z = 0; z < newInstructions.Count; z++)
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/DroppingItem.cs b/EXILED/Exiled.Events/Patches/Events/Player/DroppingItem.cs
index 0e0311532..26d8cb2cc 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/DroppingItem.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/DroppingItem.cs
@@ -11,14 +11,12 @@ namespace Exiled.Events.Patches.Events.Player
using System.Reflection.Emit;
using API.Features.Pools;
- using Exiled.API.Features.Pickups;
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Player;
using HarmonyLib;
using InventorySystem;
- using InventorySystem.Items.Pickups;
using static HarmonyLib.AccessTools;
@@ -117,15 +115,14 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable !x.IsGenericMethod && x.Name is nameof(API.Features.Items.Item.Get) && x.GetParameters().Length is 1 && x.GetParameters()[0].ParameterType == typeof(ItemBase))),
new(OpCodes.Isinst, typeof(Firearm)),
new(OpCodes.Dup),
new(OpCodes.Stloc_S, firearm.LocalIndex),
diff --git a/EXILED/Exiled.Events/Patches/Fixes/GrenadePropertiesFix.cs b/EXILED/Exiled.Events/Patches/Fixes/GrenadePropertiesFix.cs
index 8c37c4f9a..e37fb8993 100644
--- a/EXILED/Exiled.Events/Patches/Fixes/GrenadePropertiesFix.cs
+++ b/EXILED/Exiled.Events/Patches/Fixes/GrenadePropertiesFix.cs
@@ -8,6 +8,7 @@
namespace Exiled.Events.Patches.Fixes
{
using System.Collections.Generic;
+ using System.Linq;
using System.Reflection.Emit;
using API.Features.Items;
@@ -58,7 +59,7 @@ private static IEnumerable Transpiler(IEnumerable !x.IsGenericMethod && x.Name is nameof(Item.Get) && x.GetParameters().Length is 1 && x.GetParameters()[0].ParameterType == typeof(ItemBase))),
new(OpCodes.Isinst, typeof(Throwable)),
new(OpCodes.Dup),
new(OpCodes.Stloc_S, throwable.LocalIndex),
diff --git a/EXILED/Exiled.Events/Patches/Generic/DoorList.cs b/EXILED/Exiled.Events/Patches/Generic/DoorList.cs
index 1b63ec329..4f1ce6e33 100644
--- a/EXILED/Exiled.Events/Patches/Generic/DoorList.cs
+++ b/EXILED/Exiled.Events/Patches/Generic/DoorList.cs
@@ -50,7 +50,7 @@ private static void Postfix(DoorVariant __instance)
foreach (DoorVariant subDoor in checkpoint.Base.SubDoors)
{
subDoor.RegisterRooms();
- BreakableDoor targetDoor = Door.Get(subDoor).Cast();
+ BreakableDoor targetDoor = Door.Get(subDoor);
targetDoor.ParentCheckpointDoor = checkpoint;
checkpoint.SubDoorsValue.Add(targetDoor);
diff --git a/EXILED/Exiled.Events/Patches/Generic/PickupControlPatch.cs b/EXILED/Exiled.Events/Patches/Generic/PickupControlPatch.cs
index c76a8f247..fc319c474 100644
--- a/EXILED/Exiled.Events/Patches/Generic/PickupControlPatch.cs
+++ b/EXILED/Exiled.Events/Patches/Generic/PickupControlPatch.cs
@@ -9,6 +9,7 @@ namespace Exiled.Events.Patches.Generic
{
using System;
using System.Collections.Generic;
+ using System.Linq;
using System.Reflection.Emit;
using API.Features.Pickups;
@@ -48,11 +49,11 @@ private static IEnumerable Transpiler(
{
// pickup = Pickup.Get(pickupBase);
new(OpCodes.Ldloc_0),
- new(OpCodes.Call, Method(typeof(Pickup), nameof(Pickup.Get), new[] { typeof(ItemPickupBase) })),
+ new(OpCodes.Call, GetDeclaredMethods(typeof(Pickup)).First(x => !x.IsGenericMethod && x.Name is nameof(Pickup.Get) && x.GetParameters().Length is 1 && x.GetParameters()[0].ParameterType == typeof(ItemPickupBase))),
// Item.Get(itemBase);
new(OpCodes.Ldarg_0),
- new(OpCodes.Call, Method(typeof(Item), nameof(Item.Get), new[] { typeof(ItemBase) })),
+ new(OpCodes.Call, GetDeclaredMethods(typeof(Item)).First(x => !x.IsGenericMethod && x.Name is nameof(Item.Get) && x.GetParameters().Length is 1 && x.GetParameters()[0].ParameterType == typeof(ItemBase))),
// pickup.ReadItemInfo(item);
new(OpCodes.Callvirt, Method(typeof(Pickup), nameof(Pickup.ReadItemInfo))),
@@ -79,7 +80,7 @@ private static IEnumerable Transpiler(IEnumerable !x.IsGenericMethod && x.Name is nameof(Pickup.Get) && x.GetParameters().Length is 1 && x.GetParameters()[0].ParameterType == typeof(ItemPickupBase))),
new(OpCodes.Pop),
});
From 09de18badea5b048caab8e24198eab8341739f09 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Fri, 9 Aug 2024 19:03:12 +0200
Subject: [PATCH 16/63] FixNpcNoclip (#34)
* FixNpcNoclip
* oups
* .
* virtual / override
---
EXILED/Exiled.API/Features/Npc.cs | 15 ++++++++++++++-
EXILED/Exiled.API/Features/Player.cs | 2 +-
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Npc.cs b/EXILED/Exiled.API/Features/Npc.cs
index 473bb4c14..6824cbab9 100644
--- a/EXILED/Exiled.API/Features/Npc.cs
+++ b/EXILED/Exiled.API/Features/Npc.cs
@@ -17,7 +17,6 @@ namespace Exiled.API.Features
using Exiled.API.Enums;
using Exiled.API.Extensions;
using Exiled.API.Features.Components;
-
using Footprinting;
using MEC;
@@ -52,6 +51,20 @@ public Npc(GameObject gameObject)
///
public static new List List => Player.List.OfType().ToList();
+ ///
+ /// Gets or sets the player's position.
+ ///
+ public override Vector3 Position
+ {
+ get => base.Position;
+ set
+ {
+ base.Position = value;
+ if (Role is Roles.FpcRole fpcRole)
+ fpcRole.RelativePosition = new(value);
+ }
+ }
+
///
/// Retrieves the NPC associated with the specified ReferenceHub.
///
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index cb9e84fa3..0a0b6c83e 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -514,7 +514,7 @@ public Player Cuffer
///
///
///
- public Vector3 Position
+ public virtual Vector3 Position
{
get => Transform.position;
set => ReferenceHub.TryOverridePosition(value, Vector3.zero);
From a1ae55455dfca4bd39fa2c5a8dfd0b1c4f51cd99 Mon Sep 17 00:00:00 2001
From: Misaka-ZeroTwo <45165615+Misaka-ZeroTwo@users.noreply.github.com>
Date: Sat, 10 Aug 2024 02:40:30 +0800
Subject: [PATCH 17/63] Implements more patches for RemovingHandcuffs event and
adding RemovedHandcuffs event (#3)
* Update labeler.yml
* RemovingHandcuffs event
* Update UncuffReason.cs
* New event
* docs
---
EXILED/Exiled.API/Enums/UncuffReason.cs | 30 +++
.../Player/RemovedHandcuffsEventArgs.cs | 47 ++++
.../Player/RemovingHandcuffsEventArgs.cs | 13 +-
EXILED/Exiled.Events/Handlers/Player.cs | 11 +
.../Events/Player/ProcessDisarmMessage.cs | 224 +++++++++++++++++-
5 files changed, 321 insertions(+), 4 deletions(-)
create mode 100644 EXILED/Exiled.API/Enums/UncuffReason.cs
create mode 100644 EXILED/Exiled.Events/EventArgs/Player/RemovedHandcuffsEventArgs.cs
diff --git a/EXILED/Exiled.API/Enums/UncuffReason.cs b/EXILED/Exiled.API/Enums/UncuffReason.cs
new file mode 100644
index 000000000..6b3018fda
--- /dev/null
+++ b/EXILED/Exiled.API/Enums/UncuffReason.cs
@@ -0,0 +1,30 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.API.Enums
+{
+ ///
+ /// Reasons that player gets uncuffed.
+ ///
+ public enum UncuffReason
+ {
+ ///
+ /// Uncuffed by a player.
+ ///
+ Player,
+
+ ///
+ /// Uncuffed due to the distance between cuffer and target.
+ ///
+ OutOfRange,
+
+ ///
+ /// Uncuffed due to the cuffer no longer alive.
+ ///
+ CufferDied,
+ }
+}
diff --git a/EXILED/Exiled.Events/EventArgs/Player/RemovedHandcuffsEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/RemovedHandcuffsEventArgs.cs
new file mode 100644
index 000000000..ee152fb34
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Player/RemovedHandcuffsEventArgs.cs
@@ -0,0 +1,47 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Player
+{
+ using API.Enums;
+ using API.Features;
+ using Exiled.Events.EventArgs.Interfaces;
+
+ ///
+ /// Contains all information after freeing a handcuffed player.
+ ///
+ public class RemovedHandcuffsEventArgs : IPlayerEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The cuffer player.
+ /// The target player was uncuffed.
+ /// The reason for removing the handcuffs.
+ public RemovedHandcuffsEventArgs(Player cuffer, Player target, UncuffReason uncuffReason)
+ {
+ Player = cuffer;
+ Target = target;
+ UncuffReason = uncuffReason;
+ }
+
+ ///
+ /// Gets the target player to be cuffed.
+ ///
+ public Player Target { get; }
+
+ ///
+ /// Gets the cuffer player.
+ ///
+ public Player Player { get; }
+
+ ///
+ /// Gets the reason for removing handcuffs.
+ ///
+ public UncuffReason UncuffReason { get; }
+ }
+}
diff --git a/EXILED/Exiled.Events/EventArgs/Player/RemovingHandcuffsEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/RemovingHandcuffsEventArgs.cs
index c6a90a835..c375bb4b7 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/RemovingHandcuffsEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/RemovingHandcuffsEventArgs.cs
@@ -7,6 +7,7 @@
namespace Exiled.Events.EventArgs.Player
{
+ using API.Enums;
using API.Features;
using Exiled.Events.EventArgs.Interfaces;
@@ -20,11 +21,13 @@ public class RemovingHandcuffsEventArgs : IPlayerEvent, IDeniableEvent
///
/// The cuffer player.
/// The target player to be uncuffed.
+ /// The reason of removing handcuffs.
/// Indicates whether the event can be executed or not.
- public RemovingHandcuffsEventArgs(Player cuffer, Player target, bool isAllowed = true)
+ public RemovingHandcuffsEventArgs(Player cuffer, Player target, UncuffReason uncuffReason, bool isAllowed = true)
{
Player = cuffer;
Target = target;
+ UncuffReason = uncuffReason;
IsAllowed = isAllowed;
}
@@ -34,13 +37,19 @@ public RemovingHandcuffsEventArgs(Player cuffer, Player target, bool isAllowed =
public Player Target { get; }
///
- /// Gets or sets a value indicating whether or not the player can be handcuffed.
+ /// Gets or sets a value indicating whether or not the player can be handcuffed. Denying the event will only have an effect when is until next major update.
///
+ /// TODO: Update docs and patches
public bool IsAllowed { get; set; }
///
/// Gets the cuffer player.
///
public Player Player { get; }
+
+ ///
+ /// Gets the reason of removing handcuffs.
+ ///
+ public UncuffReason UncuffReason { get; }
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs
index aca07ce6e..016bdf644 100644
--- a/EXILED/Exiled.Events/Handlers/Player.cs
+++ b/EXILED/Exiled.Events/Handlers/Player.cs
@@ -223,6 +223,11 @@ public class Player
///
public static Event RemovingHandcuffs { get; set; } = new();
+ ///
+ /// Invoked after freeing a handcuffed .
+ ///
+ public static Event RemovedHandcuffs { get; set; } = new();
+
///
/// Invoked before a escapes.
///
@@ -704,6 +709,12 @@ public class Player
/// The instance.
public static void OnRemovingHandcuffs(RemovingHandcuffsEventArgs ev) => RemovingHandcuffs.InvokeSafely(ev);
+ ///
+ /// Called after freeing a handcuffed .
+ ///
+ /// The instance.
+ public static void OnRemovedHandcuffs(RemovedHandcuffsEventArgs ev) => RemovedHandcuffs.InvokeSafely(ev);
+
///
/// Called before a escapes.
///
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ProcessDisarmMessage.cs b/EXILED/Exiled.Events/Patches/Events/Player/ProcessDisarmMessage.cs
index bd83c19e9..a3805d33d 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/ProcessDisarmMessage.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/ProcessDisarmMessage.cs
@@ -7,6 +7,7 @@
namespace Exiled.Events.Patches.Events.Player
{
+ #pragma warning disable SA1402 // File may only contain a single type
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
@@ -26,10 +27,11 @@ namespace Exiled.Events.Patches.Events.Player
///
/// Patches .
- /// Adds the and events.
+ /// Adds the , , and events.
///
[EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.Handcuffing))]
[EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.RemovingHandcuffs))]
+ [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.RemovedHandcuffs))]
[HarmonyPatch(typeof(DisarmingHandlers), nameof(DisarmingHandlers.ServerProcessDisarmMessage))]
internal static class ProcessDisarmMessage
{
@@ -46,6 +48,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions);
}
}
+
+ ///
+ /// Patches .
+ /// Invokes and event.
+ ///
+ [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.RemovingHandcuffs))]
+ [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.RemovedHandcuffs))]
+ [HarmonyPatch(typeof(DisarmedPlayers), nameof(DisarmedPlayers.ValidateEntry))]
+ internal static class Uncuff
+ {
+ 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.Calls(Method(typeof(ReferenceHub), nameof(ReferenceHub.TryGetHubNetID)))) + offset;
+
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ // Invoking RemovingHandcuffs event
+ // Player.Get(Cuffer)
+ new CodeInstruction(OpCodes.Ldloc_1),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // Player.Get(Target)
+ new(OpCodes.Ldloc_0),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // UncuffReason.CufferDied
+ new(OpCodes.Ldc_I4_2),
+
+ // true
+ new(OpCodes.Ldc_I4_1),
+
+ // RemovingHandcuffsEventArgs ev = new(Cuffer, Target, UncuffReason.CufferDied, true)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RemovingHandcuffsEventArgs))[0]),
+
+ // TODO: Uncomment this part in next major update to prevent breaking changes
+ // new(OpCodes.Dup),
+
+ // Handlers.Player.OnRemovingHandcuffs(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnRemovingHandcuffs))),
+
+ // TODO: Uncomment this part in next major update to prevent breaking changes
+ // if (!ev.IsAllowed)
+ // return true;
+ // new(OpCodes.Callvirt, PropertyGetter(typeof(RemovingHandcuffsEventArgs), nameof(RemovingHandcuffsEventArgs.IsAllowed))),
+ // new(OpCodes.Brfalse_S, returnLabel),
+
+ // Invoking RemovedHandcuffs event
+ // Player.Get(Cuffer)
+ new CodeInstruction(OpCodes.Ldloc_1),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // Player.Get(Target)
+ new(OpCodes.Ldloc_0),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // UncuffReason.CufferDied
+ new(OpCodes.Ldc_I4_2),
+
+ // RemovedHandcuffsEventArgs ev = new(Cuffer, Target, UncuffReason.CufferDied)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RemovedHandcuffsEventArgs))[0]),
+
+ // Handlers.Player.OnRemovedHandcuffs(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnRemovedHandcuffs))),
+ });
+
+ offset = 5;
+ index = newInstructions.FindLastIndex(
+ instruction => instruction.Calls(PropertyGetter(typeof(PlayerRoles.PlayerRoleManager), nameof(PlayerRoles.PlayerRoleManager.CurrentRole)))) + offset;
+
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ // Invoking RemovingHandcuffs event
+ // Player.Get(Cuffer)
+ new CodeInstruction(OpCodes.Ldloc_1),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // Player.Get(Target)
+ new(OpCodes.Ldloc_0),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // UncuffReason.CufferDied
+ new(OpCodes.Ldc_I4_2),
+
+ // true
+ new(OpCodes.Ldc_I4_1),
+
+ // RemovingHandcuffsEventArgs ev = new(Cuffer, Target, UncuffReason.CufferDied, true)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RemovingHandcuffsEventArgs))[0]),
+
+ // TODO: Uncomment this part in next major update to prevent breaking changes
+ // new(OpCodes.Dup),
+
+ // Handlers.Player.OnRemovingHandcuffs(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnRemovingHandcuffs))),
+
+ // TODO: Uncomment this part in next major update to prevent breaking changes
+ // if (!ev.IsAllowed)
+ // return true;
+ // new(OpCodes.Callvirt, PropertyGetter(typeof(RemovingHandcuffsEventArgs), nameof(RemovingHandcuffsEventArgs.IsAllowed))),
+ // new(OpCodes.Brfalse_S, returnLabel),
+
+ // Invoking RemovedHandcuffs event
+ // Player.Get(Cuffer)
+ new CodeInstruction(OpCodes.Ldloc_1),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // Player.Get(Target)
+ new(OpCodes.Ldloc_0),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // UncuffReason.CufferDied
+ new(OpCodes.Ldc_I4_2),
+
+ // RemovedHandcuffsEventArgs ev = new(Cuffer, Target, UncuffReason.CufferDied)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RemovedHandcuffsEventArgs))[0]),
+
+ // Handlers.Player.OnRemovedHandcuffs(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnRemovedHandcuffs))),
+ });
+
+ offset = 3;
+ index = newInstructions.FindLastIndex(
+ instruction => instruction.Calls(PropertyGetter(typeof(UnityEngine.Vector3), nameof(UnityEngine.Vector3.sqrMagnitude)))) + offset;
+
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ // Invoking RemovingHandcuffs event
+ // Player.Get(Cuffer)
+ new CodeInstruction(OpCodes.Ldloc_1),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // Player.Get(Target)
+ new(OpCodes.Ldloc_0),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // UncuffReason.OutOfRange
+ new(OpCodes.Ldc_I4_1),
+
+ // true
+ new(OpCodes.Ldc_I4_1),
+
+ // RemovingHandcuffsEventArgs ev = new(Cuffer, Target, UncuffReason.OutOfRange, true)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RemovingHandcuffsEventArgs))[0]),
+
+ // TODO: Uncomment this part in next major update to prevent breaking changes
+ // new(OpCodes.Dup),
+
+ // Handlers.Player.OnRemovingHandcuffs(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnRemovingHandcuffs))),
+
+ // TODO: Uncomment this part in next major update to prevent breaking changes
+ // if (!ev.IsAllowed)
+ // return true;
+ // new(OpCodes.Callvirt, PropertyGetter(typeof(RemovingHandcuffsEventArgs), nameof(RemovingHandcuffsEventArgs.IsAllowed))),
+ // new(OpCodes.Brfalse_S, returnLabel),
+
+ // Invoking RemovedHandcuffs event
+ // Player.Get(Cuffer)
+ new CodeInstruction(OpCodes.Ldloc_1),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // Player.Get(Target)
+ new(OpCodes.Ldloc_0),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // UncuffReason.CufferDied
+ new(OpCodes.Ldc_I4_2),
+
+ // RemovedHandcuffsEventArgs ev = new(Cuffer, Target, UncuffReason.OutOfRange)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RemovedHandcuffsEventArgs))[0]),
+
+ // Handlers.Player.OnRemovedHandcuffs(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnRemovedHandcuffs))),
+ });
+
+ newInstructions[newInstructions.Count - 2].labels.Add(returnLabel);
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
}
\ No newline at end of file
From 2c41d7d817c73864b63033120a35949a5c2e859f Mon Sep 17 00:00:00 2001
From: X <24619207+Undid-Iridium@users.noreply.github.com>
Date: Sat, 10 Aug 2024 02:47:30 -0400
Subject: [PATCH 18/63] Interacting scp330 compile fix (#43)
* My scp built with no issues.. no idea why.
* Fixes issue
* Harmony suppresses NON harmony errors.
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
.../Patches/Events/Scp330/InteractingScp330.cs | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs b/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
index aea840168..640b224d7 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
@@ -36,6 +36,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable instruction.Calls(Method(typeof(Scp330Interobject), nameof(Scp330Interobject.RpcMakeSound)))) + addShouldSeverOffset;
int serverEffectLocationStart = -1;
int enableEffect = newInstructions.FindLastIndex(
- instruction => instruction.LoadsField(Field(typeof(PlayerEffectsController), nameof(ReferenceHub.playerEffectsController)))) + serverEffectLocationStart;
-
+ instruction => instruction.LoadsField(Field(typeof(ReferenceHub), nameof(ReferenceHub.playerEffectsController)))) + serverEffectLocationStart;
+ newInstructions[enableEffect].WithLabels(enableEffectLabel);
newInstructions.InsertRange(
addShouldSeverIndex,
new[]
@@ -91,7 +92,7 @@ private static IEnumerable Transpiler(IEnumerable
Date: Sat, 10 Aug 2024 22:15:40 +0200
Subject: [PATCH 19/63] Trello is no more & more NW Fix & Fix IL Code on dev
(#28)
* Trello Is Replaced by gitlab
* also this one
* Fix106RegenerationWithScp244
* Report To NW
* .
* Scp3114FriendlyFireFix
* Fix
* yamatotototo
* Fix
* Fix for building dev + TODO than i just seen
* Fix Undid patch
* fIX
* Fix Client Crash Issue
---------
Co-authored-by: IRacle
---
.../Player/LocalReportingEventArgs.cs | 2 +-
.../Scp049/FinishingRecallEventArgs.cs | 2 +-
.../Handlers/Internal/MapGenerated.cs | 2 +-
.../Exiled.Events/Handlers/Internal/Round.cs | 2 +-
.../Patches/Events/Map/SpawningItem.cs | 7 +-
.../Patches/Events/Player/Escaping.cs | 4 +-
.../Patches/Events/Scp049/FinishingRecall.cs | 5 +-
.../Events/Scp330/InteractingScp330.cs | 1 +
.../Patches/Events/Server/Reporting.cs | 2 +-
.../Fixes/Fix106RegenerationWithScp244.cs | 72 ++++++++++
.../Patches/Fixes/NWFixScp096BreakingDoor.cs | 2 +-
.../Patches/Fixes/Scp3114AttackAhpFix.cs | 2 +-
.../Patches/Fixes/Scp3114FriendlyFireFix.cs | 124 ++++++++++++++++++
.../Patches/Fixes/SlownessFix.cs | 2 +
.../Patches/Fixes/WarheadConfigLockGateFix.cs | 45 +++++++
15 files changed, 259 insertions(+), 15 deletions(-)
create mode 100644 EXILED/Exiled.Events/Patches/Fixes/Fix106RegenerationWithScp244.cs
create mode 100644 EXILED/Exiled.Events/Patches/Fixes/Scp3114FriendlyFireFix.cs
create mode 100644 EXILED/Exiled.Events/Patches/Fixes/WarheadConfigLockGateFix.cs
diff --git a/EXILED/Exiled.Events/EventArgs/Player/LocalReportingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/LocalReportingEventArgs.cs
index 316be5039..97a443ea7 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/LocalReportingEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/LocalReportingEventArgs.cs
@@ -5,7 +5,7 @@
//
// -----------------------------------------------------------------------
-namespace Exiled.Events.EventArgs.Player
+namespace Exiled.Events.EventArgs.Player // TODO: Wrong namespace should be Server
{
using API.Features;
diff --git a/EXILED/Exiled.Events/EventArgs/Scp049/FinishingRecallEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp049/FinishingRecallEventArgs.cs
index e2c2c0728..e897dbb04 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp049/FinishingRecallEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp049/FinishingRecallEventArgs.cs
@@ -38,7 +38,7 @@ public FinishingRecallEventArgs(Player target, Player scp049, BasicRagdoll ragdo
Scp049 = Player.Role.As();
Target = target;
Ragdoll = Ragdoll.Get(ragdoll);
- IsAllowed = isAllowed && Target.Role is SpectatorRole spectatorRole && spectatorRole.IsReadyToRespawn;
+ IsAllowed = isAllowed;
}
///
diff --git a/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs b/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
index 1b1dadf46..f75f2e91f 100644
--- a/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
+++ b/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
@@ -48,7 +48,7 @@ public static void OnMapGenerated()
Map.ClearCache();
PrefabHelper.LoadPrefabs();
- // TODO: Fix For (https://trello.com/c/cUwpZDLs/5003-config-teamrespawnqueue-in-configgameplay-is-not-working-as-expected)
+ // TODO: Fix For (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/377)
PlayerRoles.RoleAssign.HumanSpawner.Handlers[PlayerRoles.Team.ChaosInsurgency] = new PlayerRoles.RoleAssign.OneRoleHumanSpawner(PlayerRoles.RoleTypeId.ChaosConscript);
PlayerRoles.RoleAssign.HumanSpawner.Handlers[PlayerRoles.Team.OtherAlive] = new PlayerRoles.RoleAssign.OneRoleHumanSpawner(PlayerRoles.RoleTypeId.Tutorial);
PlayerRoles.RoleAssign.HumanSpawner.Handlers[PlayerRoles.Team.Dead] = new PlayerRoles.RoleAssign.OneRoleHumanSpawner(PlayerRoles.RoleTypeId.Spectator);
diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs
index 400eb044c..8f9bd58b2 100644
--- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs
+++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs
@@ -86,7 +86,7 @@ public static void OnVerified(VerifiedEventArgs ev)
{
RoleAssigner.CheckLateJoin(ev.Player.ReferenceHub, ClientInstanceMode.ReadyClient);
- // TODO: Remove if this has been fixed for https://trello.com/c/CzPD304L/5983-networking-blackout-is-not-synchronized-for-the-new-players
+ // TODO: Remove if this has been fixed for https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/52
foreach (Room room in Room.List.Where(current => current.AreLightsOff))
{
ev.Player.SendFakeSyncVar(room.RoomLightControllerNetIdentity, typeof(RoomLightController), nameof(RoomLightController.NetworkLightsEnabled), true);
diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs
index 28fd021f0..e65ced6fb 100644
--- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningItem.cs
@@ -40,6 +40,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable instruction.IsLdarg(0));
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/Escaping.cs b/EXILED/Exiled.Events/Patches/Events/Player/Escaping.cs
index b19ffdaee..048de1136 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/Escaping.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/Escaping.cs
@@ -138,9 +138,9 @@ private static IEnumerable Transpiler(IEnumerable customExit)
newInstructions[i].opcode = OpCodes.Ldc_I4_5;
}
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp049/FinishingRecall.cs b/EXILED/Exiled.Events/Patches/Events/Scp049/FinishingRecall.cs
index d1458e0fd..2eab40acc 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp049/FinishingRecall.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp049/FinishingRecall.cs
@@ -25,11 +25,8 @@ namespace Exiled.Events.Patches.Events.Scp049
///
/// Patches .
/// Adds the event.
- /// Fix bug than Overwatch can get force respawn by Scp049
- /// Bug reported to NW https://trello.com/c/V0uHP2eV/5745-overwatch-overwatch-can-get-respawned-by-scp-049.
- /// The fix is directly inside the .
///
- // [EventPatch(typeof(Handlers.Scp049), nameof(Handlers.Scp049.FinishingRecall))]
+ [EventPatch(typeof(Handlers.Scp049), nameof(Handlers.Scp049.FinishingRecall))]
[HarmonyPatch(typeof(Scp049ResurrectAbility), nameof(Scp049ResurrectAbility.ServerComplete))]
internal static class FinishingRecall
{
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs b/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
index 640b224d7..c8ff97d32 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
@@ -82,6 +82,7 @@ private static IEnumerable Transpiler(IEnumerable instruction.LoadsField(Field(typeof(ReferenceHub), nameof(ReferenceHub.playerEffectsController)))) + serverEffectLocationStart;
+
newInstructions[enableEffect].WithLabels(enableEffectLabel);
newInstructions.InsertRange(
addShouldSeverIndex,
diff --git a/EXILED/Exiled.Events/Patches/Events/Server/Reporting.cs b/EXILED/Exiled.Events/Patches/Events/Server/Reporting.cs
index 5d22e96c5..d672d1831 100644
--- a/EXILED/Exiled.Events/Patches/Events/Server/Reporting.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Server/Reporting.cs
@@ -41,7 +41,7 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Ldarg_S && instruction.operand == (object)4) + offset;
+ int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ldarg_S && instruction.operand is byte and 4) + offset;
Label ret = generator.DefineLabel();
diff --git a/EXILED/Exiled.Events/Patches/Fixes/Fix106RegenerationWithScp244.cs b/EXILED/Exiled.Events/Patches/Fixes/Fix106RegenerationWithScp244.cs
new file mode 100644
index 000000000..33c54d5ad
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Fixes/Fix106RegenerationWithScp244.cs
@@ -0,0 +1,72 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Fixes
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using API.Features.Pools;
+ using CustomPlayerEffects;
+ using HarmonyLib;
+ using InventorySystem.Items.Usables.Scp244.Hypothermia;
+ using PlayerRoles;
+ using PlayerRoles.PlayableScps.Scp106;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches the delegate.
+ /// Fix than SCP-106 regenerates slower in SCP-244 even if they are in stalk.
+ /// Bug reported to NW (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/367).
+ ///
+ [HarmonyPatch(typeof(Hypothermia), nameof(Hypothermia.Update))]
+ internal class Fix106RegenerationWithScp244
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ LocalBuilder scp106Role = generator.DeclareLocal(typeof(Scp106Role));
+ Label continueLabel = generator.DefineLabel();
+
+ int offset = 1;
+ int index = newInstructions.FindLastIndex(x => x.operand == (object)Method(typeof(SpawnProtected), nameof(SpawnProtected.CheckPlayer))) + offset;
+
+ Label skip = (Label)newInstructions[index].operand;
+
+ index += offset;
+
+ newInstructions[index].labels.Add(continueLabel);
+
+ newInstructions.InsertRange(index, new[]
+ {
+ // Scp106Role scp106Role = base.Hub.roleManager.CurrentRole as Scp106Role;
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(StatusEffectBase), nameof(StatusEffectBase.Hub))),
+ new CodeInstruction(OpCodes.Ldfld, Field(typeof(ReferenceHub), nameof(ReferenceHub.roleManager))),
+ new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(PlayerRoleManager), nameof(PlayerRoleManager.CurrentRole))),
+ new CodeInstruction(OpCodes.Isinst, typeof(Scp106Role)),
+ new CodeInstruction(OpCodes.Stloc_S, scp106Role.LocalIndex),
+
+ // if (scp106Role is null) goto continueLabel
+ new CodeInstruction(OpCodes.Ldloc_S, scp106Role.LocalIndex),
+ new CodeInstruction(OpCodes.Brfalse_S, continueLabel),
+
+ // if (!scp106Role.IsSubmerged) goto skip
+ new CodeInstruction(OpCodes.Ldloc_S, scp106Role.LocalIndex),
+ new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(Scp106Role), nameof(Scp106Role.IsSubmerged))),
+ new CodeInstruction(OpCodes.Brtrue_S, skip),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
diff --git a/EXILED/Exiled.Events/Patches/Fixes/NWFixScp096BreakingDoor.cs b/EXILED/Exiled.Events/Patches/Fixes/NWFixScp096BreakingDoor.cs
index 4b294f953..5401f24b8 100644
--- a/EXILED/Exiled.Events/Patches/Fixes/NWFixScp096BreakingDoor.cs
+++ b/EXILED/Exiled.Events/Patches/Fixes/NWFixScp096BreakingDoor.cs
@@ -22,7 +22,7 @@ namespace Exiled.Events.Patches.Fixes
///
/// Patches the delegate.
/// Fixes open doors getting easily broke.
- /// Bug reported to NW (https://trello.com/c/6Nz7Isjm/4637-scp096-easily-breaking-opened-doors).
+ /// Bug reported to NW (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/198).
///
[HarmonyPatch(typeof(Scp096HitHandler), nameof(Scp096HitHandler.CheckDoorHit))]
internal class NWFixScp096BreakingDoor
diff --git a/EXILED/Exiled.Events/Patches/Fixes/Scp3114AttackAhpFix.cs b/EXILED/Exiled.Events/Patches/Fixes/Scp3114AttackAhpFix.cs
index 2722c59e1..45f3774c4 100644
--- a/EXILED/Exiled.Events/Patches/Fixes/Scp3114AttackAhpFix.cs
+++ b/EXILED/Exiled.Events/Patches/Fixes/Scp3114AttackAhpFix.cs
@@ -20,7 +20,7 @@ namespace Exiled.Events.Patches.Fixes
///
/// Patches the delegate.
/// Fix than Scp3114Slap was giving humeshield even if player was not hit by Scp3114.
- /// Bug reported to NW (https://trello.com/c/1AwpM8XE/5814-scp3114-is-able-to-get-humeshield-with-godmod-player).
+ /// Bug reported to NW (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/119).
///
[HarmonyPatch(typeof(Scp3114Slap), nameof(Scp3114Slap.DamagePlayers))]
internal class Scp3114AttackAhpFix
diff --git a/EXILED/Exiled.Events/Patches/Fixes/Scp3114FriendlyFireFix.cs b/EXILED/Exiled.Events/Patches/Fixes/Scp3114FriendlyFireFix.cs
new file mode 100644
index 000000000..70eca7fba
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Fixes/Scp3114FriendlyFireFix.cs
@@ -0,0 +1,124 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Fixes
+{
+#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.API.Features;
+
+ using Footprinting;
+ using HarmonyLib;
+ using InventorySystem.Items.Pickups;
+ using InventorySystem.Items.ThrowableProjectiles;
+ using PlayerRoles;
+ using PlayerStatsSystem;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches the delegate.
+ /// Fix Throwing a ghostlight with Scp in the room stun 079.
+ /// Bug reported to NW (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/55).
+ ///
+ [HarmonyPatch(typeof(Scp2176Projectile), nameof(Scp2176Projectile.ServerShatter))]
+ internal class Scp3114FriendlyFireFix
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label cnt = generator.DefineLabel();
+
+ int offset = 0;
+ int index = newInstructions.FindIndex(x => x.LoadsField(Field(typeof(RoomLightController), nameof(RoomLightController.Instances)))) + offset;
+
+ Label skip = newInstructions[index].labels[0];
+
+ offset = -3;
+ index += offset;
+
+ newInstructions.InsertRange(index, new[]
+ {
+ // if (this.PreviousOwner.Role.GetTeam() is Team.SCPs)
+ new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]),
+ new(OpCodes.Ldfld, Field(typeof(Scp2176Projectile), nameof(Scp2176Projectile.PreviousOwner))),
+ new(OpCodes.Ldfld, Field(typeof(Footprint), nameof(Footprint.Role))),
+ new(OpCodes.Call, Method(typeof(PlayerRolesUtils), nameof(PlayerRolesUtils.GetTeam), new[] { typeof(RoleTypeId) })),
+ new(OpCodes.Ldc_I4_0),
+ new(OpCodes.Ceq),
+
+ new(OpCodes.Brfalse_S, cnt),
+
+ new(OpCodes.Pop),
+ new(OpCodes.Br_S, skip),
+
+ new CodeInstruction(OpCodes.Nop).WithLabels(cnt),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+
+ ///
+ /// Patches the delegate.
+ /// Fix Throwing a ghostlight with Scp in the room stun 079.
+ /// Bug reported to NW (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/55).
+ ///
+ [HarmonyPatch(typeof(CollisionDetectionPickup), nameof(CollisionDetectionPickup.ProcessCollision))]
+ internal class Scp3114FriendlyFireFix2 : AttackerDamageHandler
+ {
+#pragma warning disable SA1600 // Elements should be documented
+ public Scp3114FriendlyFireFix2(Footprint attacker, float damage)
+ {
+ Attacker = attacker;
+ Damage = damage;
+ AllowSelfDamage = false;
+ ServerLogsText = "Scp3114 Fix";
+ }
+
+ public override Footprint Attacker { get; set; }
+
+ public override bool AllowSelfDamage { get; }
+
+ public override float Damage { get; set; }
+
+ public override string ServerLogsText { get; }
+#pragma warning restore SA1600 // Elements should be documented
+
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ int offset = 0;
+ int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldnull) + offset;
+
+ // replace null with new Scp3114FriendlyFireFix2(this.PreviousOwner, num2)
+ newInstructions.RemoveAt(index);
+ newInstructions.InsertRange(index, new CodeInstruction[]
+ {
+ // new Scp3114FriendlyFireFix2(this.PreviousOwner, num2)
+ new(OpCodes.Ldarg_0),
+ new(OpCodes.Ldfld, Field(typeof(CollisionDetectionPickup), nameof(CollisionDetectionPickup.PreviousOwner))),
+ new(OpCodes.Ldloc_3),
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(Scp3114FriendlyFireFix2))[0]),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
diff --git a/EXILED/Exiled.Events/Patches/Fixes/SlownessFix.cs b/EXILED/Exiled.Events/Patches/Fixes/SlownessFix.cs
index 5a05c31a0..1d8774a46 100644
--- a/EXILED/Exiled.Events/Patches/Fixes/SlownessFix.cs
+++ b/EXILED/Exiled.Events/Patches/Fixes/SlownessFix.cs
@@ -19,6 +19,7 @@ namespace Exiled.Events.Patches.Fixes
///
/// Patches getter to fix Slowness effect.
+ /// reported to NW (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/378).
///
[HarmonyPatch(typeof(FpcMotor), nameof(FpcMotor.DesiredMove), MethodType.Getter)]
internal class SlownessFix
@@ -41,6 +42,7 @@ private static IEnumerable Transpiler(IEnumerable
/// Patches method to fix Slowness effect.
+ /// reported to NW (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/378).
///
[HarmonyPatch(typeof(FpcMotor), nameof(FpcMotor.UpdatePosition))]
#pragma warning disable SA1402 // File may only contain a single type
diff --git a/EXILED/Exiled.Events/Patches/Fixes/WarheadConfigLockGateFix.cs b/EXILED/Exiled.Events/Patches/Fixes/WarheadConfigLockGateFix.cs
new file mode 100644
index 000000000..2c65c58a8
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Fixes/WarheadConfigLockGateFix.cs
@@ -0,0 +1,45 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Fixes
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using API.Features.Pools;
+ using Footprinting;
+ using HarmonyLib;
+ using Interactables.Interobjects.DoorUtils;
+ using InventorySystem;
+ using InventorySystem.Items.Firearms.Ammo;
+ using InventorySystem.Items.Pickups;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches delegate.
+ /// Fix than NW config "lock_gates_on_countdown"
+ /// reported https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/316.
+ ///
+ [HarmonyPatch(typeof(DoorEventOpenerExtension), nameof(DoorEventOpenerExtension.Trigger))]
+ internal class WarheadConfigLockGateFix
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ // replace Contains with StartWith
+ int index = newInstructions.FindIndex(x => x.operand == (object)Method(typeof(string), nameof(string.Contains), new[] { typeof(string) }));
+ newInstructions[index].operand = Method(typeof(string), nameof(string.StartsWith), new System.Type[] { typeof(string) });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
From a3595e10250fe3233bf22670f0582a438667d540 Mon Sep 17 00:00:00 2001
From: Nameless <85962933+Misfiy@users.noreply.github.com>
Date: Sun, 11 Aug 2024 10:59:58 +0200
Subject: [PATCH 20/63] Additions (#29)
* Add a bunch
* Fix
* Security
* Make changes
* remove unused usings
* Getting inventory
* oops
* Dev commit
* use exiled
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
EXILED/Exiled.API/Enums/HazardType.cs | 37 +++++++++++
.../Extensions/BitwiseExtensions.cs | 63 +++++++++++++++++++
.../Exiled.API/Extensions/RoleExtensions.cs | 23 ++++---
.../Features/Hazards/AmnesticCloudHazard.cs | 22 ++++++-
EXILED/Exiled.API/Features/Hazards/Hazard.cs | 13 ++++
.../Features/Hazards/SinkholeHazard.cs | 4 ++
.../Features/Hazards/TantrumHazard.cs | 44 +++++++++++++
EXILED/Exiled.API/Features/Map.cs | 56 +----------------
EXILED/Exiled.API/Features/Player.cs | 2 +-
EXILED/Exiled.API/Features/PrefabHelper.cs | 19 +++++-
EXILED/Exiled.API/Features/Roles/FpcRole.cs | 11 +++-
EXILED/Exiled.API/Features/Server.cs | 9 +++
EXILED/Exiled.Events/Commands/TpsCommand.cs | 46 ++++++++++++++
.../EventArgs/Player/ChangingRoleEventArgs.cs | 22 +++----
14 files changed, 290 insertions(+), 81 deletions(-)
create mode 100644 EXILED/Exiled.API/Enums/HazardType.cs
create mode 100644 EXILED/Exiled.API/Extensions/BitwiseExtensions.cs
create mode 100644 EXILED/Exiled.Events/Commands/TpsCommand.cs
diff --git a/EXILED/Exiled.API/Enums/HazardType.cs b/EXILED/Exiled.API/Enums/HazardType.cs
new file mode 100644
index 000000000..f05f8852f
--- /dev/null
+++ b/EXILED/Exiled.API/Enums/HazardType.cs
@@ -0,0 +1,37 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.API.Enums
+{
+ using Exiled.API.Features.Hazards;
+
+ ///
+ /// Unique identifier for a .
+ ///
+ public enum HazardType
+ {
+ ///
+ /// SCP-939 amnestic cloud.
+ ///
+ AmnesticCloud,
+
+ ///
+ /// Sinkhole spawned at start of round.
+ ///
+ Sinkhole,
+
+ ///
+ /// SCP-173 tantrum.
+ ///
+ Tantrum,
+
+ ///
+ /// Should never happen
+ ///
+ Unknown,
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Extensions/BitwiseExtensions.cs b/EXILED/Exiled.API/Extensions/BitwiseExtensions.cs
new file mode 100644
index 000000000..2f8473784
--- /dev/null
+++ b/EXILED/Exiled.API/Extensions/BitwiseExtensions.cs
@@ -0,0 +1,63 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.API.Extensions
+{
+ using System;
+
+ ///
+ /// Extensions for bitwise operations.
+ ///
+ public static class BitwiseExtensions
+ {
+ ///
+ /// Adds the specified flags to the given enum value.
+ ///
+ /// The type of the enum.
+ /// The enum value to add flags to.
+ /// The flags to add.
+ /// The enum value with the specified flags added.
+ public static T AddFlags(this T flags, params T[] newFlags)
+ where T : Enum => flags.ModifyFlags(true, newFlags);
+
+ ///
+ /// Removes the specified flags from the given enum value.
+ ///
+ /// The type of the enum.
+ /// The enum value to remove flags from.
+ /// The flags to remove.
+ /// The enum value with the specified flags removed.
+ public static T RemoveFlags(this T flags, params T[] oldFlags)
+ where T : Enum => flags.ModifyFlags(false, oldFlags);
+
+ ///
+ /// Sets the specified flag to the given value, default is true.
+ ///
+ /// The flags enum to modify.
+ /// The value to set the flag to.
+ /// The flags to modify.
+ /// The type of the enum.
+ /// The flags enum with the flag set to the given value.
+ public static T ModifyFlags(this T flags, bool value, params T[] changeFlags)
+ where T : Enum
+ {
+ long currentValue = Convert.ToInt64(flags);
+
+ foreach (T flag in changeFlags)
+ {
+ long flagValue = Convert.ToInt64(flag);
+
+ if (value)
+ currentValue |= flagValue;
+ else
+ currentValue &= ~flagValue;
+ }
+
+ return (T)Enum.ToObject(typeof(T), currentValue);
+ }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Extensions/RoleExtensions.cs b/EXILED/Exiled.API/Extensions/RoleExtensions.cs
index e9186ba71..c674af1bf 100644
--- a/EXILED/Exiled.API/Extensions/RoleExtensions.cs
+++ b/EXILED/Exiled.API/Extensions/RoleExtensions.cs
@@ -140,18 +140,22 @@ public static SpawnLocation GetRandomSpawnLocation(this RoleTypeId roleType)
return null;
}
+ ///
+ /// Gets the starting of a .
+ ///
+ /// The .
+ /// The that the role receives on spawn.
+ public static InventoryRoleInfo GetInventory(this RoleTypeId role)
+ => StartingInventories.DefinedInventories.TryGetValue(role, out InventoryRoleInfo info)
+ ? info
+ : new(Array.Empty(), new());
+
///
/// Gets the starting items of a .
///
/// The .
/// An of that the role receives on spawn. Will be empty for classes that do not spawn with items.
- public static ItemType[] GetStartingInventory(this RoleTypeId roleType)
- {
- if (StartingInventories.DefinedInventories.TryGetValue(roleType, out InventoryRoleInfo info))
- return info.Items;
-
- return Array.Empty();
- }
+ public static ItemType[] GetStartingInventory(this RoleTypeId roleType) => GetInventory(roleType).Items;
///
/// Gets the starting ammo of a .
@@ -160,10 +164,9 @@ public static ItemType[] GetStartingInventory(this RoleTypeId roleType)
/// An of that the role receives on spawn. Will be empty for classes that do not spawn with ammo.
public static Dictionary GetStartingAmmo(this RoleTypeId roleType)
{
- if (StartingInventories.DefinedInventories.TryGetValue(roleType, out InventoryRoleInfo info))
- return info.Ammo.ToDictionary(kvp => kvp.Key.GetAmmoType(), kvp => kvp.Value);
+ InventoryRoleInfo info = roleType.GetInventory();
- return new();
+ return info.Ammo.ToDictionary(kvp => kvp.Key.GetAmmoType(), kvp => kvp.Value);
}
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Features/Hazards/AmnesticCloudHazard.cs b/EXILED/Exiled.API/Features/Hazards/AmnesticCloudHazard.cs
index c385c143f..31c9ad244 100644
--- a/EXILED/Exiled.API/Features/Hazards/AmnesticCloudHazard.cs
+++ b/EXILED/Exiled.API/Features/Hazards/AmnesticCloudHazard.cs
@@ -3,10 +3,11 @@
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
//
-// -----------------------------------------------------------------------
+// ------------------------------------------------------------------------
namespace Exiled.API.Features.Hazards
{
+ using Exiled.API.Enums;
using PlayerRoles.PlayableScps.Scp939;
///
@@ -14,6 +15,8 @@ namespace Exiled.API.Features.Hazards
///
public class AmnesticCloudHazard : TemporaryHazard
{
+ private static Scp939AmnesticCloudInstance amnesticCloudPrefab;
+
///
/// Initializes a new instance of the class.
///
@@ -26,9 +29,26 @@ public AmnesticCloudHazard(Scp939AmnesticCloudInstance hazard)
Owner = Player.Get(Ability.Owner);
}
+ ///
+ /// Gets the amnestic cloud prefab.
+ ///
+ public static Scp939AmnesticCloudInstance AmnesticCloudPrefab
+ {
+ get
+ {
+ if (amnesticCloudPrefab == null)
+ amnesticCloudPrefab = PrefabHelper.GetPrefab(PrefabType.AmnesticCloudHazard);
+
+ return amnesticCloudPrefab;
+ }
+ }
+
///
public new Scp939AmnesticCloudInstance Base { get; }
+ ///
+ public override HazardType Type => HazardType.AmnesticCloud;
+
///
/// Gets the for this instance.
///
diff --git a/EXILED/Exiled.API/Features/Hazards/Hazard.cs b/EXILED/Exiled.API/Features/Hazards/Hazard.cs
index 253825530..09bd880d3 100644
--- a/EXILED/Exiled.API/Features/Hazards/Hazard.cs
+++ b/EXILED/Exiled.API/Features/Hazards/Hazard.cs
@@ -11,6 +11,7 @@ namespace Exiled.API.Features.Hazards
using System.Collections.Generic;
using System.Linq;
+ using Exiled.API.Enums;
using Exiled.API.Features.Core;
using Exiled.API.Interfaces;
using global::Hazards;
@@ -48,6 +49,11 @@ public Hazard(EnvironmentalHazard hazard)
///
public EnvironmentalHazard Base { get; }
+ ///
+ /// Gets the associated with the current Hazard.
+ ///
+ public virtual HazardType Type { get; } = HazardType.Unknown;
+
///
/// Gets or sets the list with all affected by this hazard players.
///
@@ -153,6 +159,13 @@ public static T Get(EnvironmentalHazard environmentalHazard)
/// of based on predicate.
public static IEnumerable Get(Func predicate) => List.Where(predicate);
+ ///
+ /// Gets an of .
+ ///
+ /// The to get.
+ /// of based on type.
+ public static IEnumerable Get(HazardType type) => Get(h => h.Type == type);
+
///
/// Checks if player is in hazard zone.
///
diff --git a/EXILED/Exiled.API/Features/Hazards/SinkholeHazard.cs b/EXILED/Exiled.API/Features/Hazards/SinkholeHazard.cs
index e8e0c4f3a..34cbaacd5 100644
--- a/EXILED/Exiled.API/Features/Hazards/SinkholeHazard.cs
+++ b/EXILED/Exiled.API/Features/Hazards/SinkholeHazard.cs
@@ -7,6 +7,7 @@
namespace Exiled.API.Features.Hazards
{
+ using Exiled.API.Enums;
using global::Hazards;
///
@@ -28,5 +29,8 @@ public SinkholeHazard(SinkholeEnvironmentalHazard hazard)
/// Gets the .
///
public new SinkholeEnvironmentalHazard Base { get; }
+
+ ///
+ public override HazardType Type => HazardType.Sinkhole;
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Features/Hazards/TantrumHazard.cs b/EXILED/Exiled.API/Features/Hazards/TantrumHazard.cs
index 15f54b5ac..906bd4faf 100644
--- a/EXILED/Exiled.API/Features/Hazards/TantrumHazard.cs
+++ b/EXILED/Exiled.API/Features/Hazards/TantrumHazard.cs
@@ -7,7 +7,9 @@
namespace Exiled.API.Features.Hazards
{
+ using Exiled.API.Enums;
using global::Hazards;
+ using Mirror;
using RelativePositioning;
using UnityEngine;
@@ -16,6 +18,8 @@ namespace Exiled.API.Features.Hazards
///
public class TantrumHazard : TemporaryHazard
{
+ private static TantrumEnvironmentalHazard tantrumPrefab;
+
///
/// Initializes a new instance of the class.
///
@@ -26,11 +30,28 @@ public TantrumHazard(TantrumEnvironmentalHazard hazard)
Base = hazard;
}
+ ///
+ /// Gets the tantrum prefab.
+ ///
+ public static TantrumEnvironmentalHazard TantrumPrefab
+ {
+ get
+ {
+ if (tantrumPrefab == null)
+ tantrumPrefab = PrefabHelper.GetPrefab(PrefabType.TantrumObj);
+
+ return tantrumPrefab;
+ }
+ }
+
///
/// Gets the .
///
public new TantrumEnvironmentalHazard Base { get; }
+ ///
+ public override HazardType Type => HazardType.Tantrum;
+
///
/// Gets or sets a value indicating whether or not sizzle should be played.
///
@@ -57,5 +78,28 @@ public Transform CorrectPosition
get => Base._correctPosition;
set => Base._correctPosition = value;
}
+
+ ///
+ /// Places a Tantrum (SCP-173's ability) in the indicated position.
+ ///
+ /// The position where you want to spawn the Tantrum.
+ /// Whether or not the tantrum will apply the effect.
+ /// If is , the tantrum is moved slightly up from its original position. Otherwise, the collision will not be detected and the slowness will not work.
+ /// The instance.
+ public static TantrumHazard PlaceTantrum(Vector3 position, bool isActive = true)
+ {
+ TantrumEnvironmentalHazard tantrum = Object.Instantiate(TantrumPrefab);
+
+ if (!isActive)
+ tantrum.SynchronizedPosition = new(position);
+ else
+ tantrum.SynchronizedPosition = new(position + (Vector3.up * 0.25f));
+
+ tantrum._destroyed = !isActive;
+
+ NetworkServer.Spawn(tantrum.gameObject);
+
+ return Get(tantrum);
+ }
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs
index 4e8f2b094..3f1f6fc1a 100644
--- a/EXILED/Exiled.API/Features/Map.cs
+++ b/EXILED/Exiled.API/Features/Map.cs
@@ -28,9 +28,6 @@ namespace Exiled.API.Features
using LightContainmentZoneDecontamination;
using MapGeneration;
using MapGeneration.Distributors;
- using Mirror;
- using PlayerRoles;
- using PlayerRoles.PlayableScps.Scp173;
using PlayerRoles.PlayableScps.Scp939;
using PlayerRoles.Ragdolls;
using RelativePositioning;
@@ -39,8 +36,6 @@ namespace Exiled.API.Features
using Utils.Networking;
using Object = UnityEngine.Object;
- using Scp173GameRole = PlayerRoles.PlayableScps.Scp173.Scp173Role;
- using Scp939GameRole = PlayerRoles.PlayableScps.Scp939.Scp939Role;
///
/// A set of tools to easily handle the in-game map.
@@ -57,48 +52,17 @@ public static class Map
///
internal static readonly List TeleportsValue = new(8);
- private static TantrumEnvironmentalHazard tantrumPrefab;
- private static Scp939AmnesticCloudInstance amnesticCloudPrefab;
-
private static AmbientSoundPlayer ambientSoundPlayer;
///
/// Gets the tantrum prefab.
///
- public static TantrumEnvironmentalHazard TantrumPrefab
- {
- get
- {
- if (tantrumPrefab == null)
- {
- Scp173GameRole scp173Role = (Scp173GameRole)RoleTypeId.Scp173.GetRoleBase();
-
- if (scp173Role.SubroutineModule.TryGetSubroutine(out Scp173TantrumAbility scp173TantrumAbility))
- tantrumPrefab = scp173TantrumAbility._tantrumPrefab;
- }
-
- return tantrumPrefab;
- }
- }
+ public static TantrumEnvironmentalHazard TantrumPrefab => TantrumHazard.TantrumPrefab; // TODO: Remove this.
///
/// Gets the amnestic cloud prefab.
///
- public static Scp939AmnesticCloudInstance AmnesticCloudPrefab
- {
- get
- {
- if (amnesticCloudPrefab == null)
- {
- Scp939GameRole scp939Role = (Scp939GameRole)RoleTypeId.Scp939.GetRoleBase();
-
- if (scp939Role.SubroutineModule.TryGetSubroutine(out Scp939AmnesticCloudAbility ability))
- amnesticCloudPrefab = ability._instancePrefab;
- }
-
- return amnesticCloudPrefab;
- }
- }
+ public static Scp939AmnesticCloudInstance AmnesticCloudPrefab => AmnesticCloudHazard.AmnesticCloudPrefab; // TODO: Remove this.
///
/// Gets a value indicating whether decontamination has begun in the light containment zone.
@@ -281,21 +245,7 @@ public static void PlayAmbientSound(int id)
/// Whether or not the tantrum will apply the effect.
/// If is , the tantrum is moved slightly up from its original position. Otherwise, the collision will not be detected and the slowness will not work.
/// The instance.
- public static TantrumHazard PlaceTantrum(Vector3 position, bool isActive = true)
- {
- TantrumEnvironmentalHazard tantrum = Object.Instantiate(TantrumPrefab);
-
- if (!isActive)
- tantrum.SynchronizedPosition = new RelativePosition(position);
- else
- tantrum.SynchronizedPosition = new RelativePosition(position + (Vector3.up * 0.25f));
-
- tantrum._destroyed = !isActive;
-
- NetworkServer.Spawn(tantrum.gameObject);
-
- return Hazard.Get(tantrum);
- }
+ public static TantrumHazard PlaceTantrum(Vector3 position, bool isActive = true) => TantrumHazard.PlaceTantrum(position, isActive); // TODO: Remove this.
///
/// Destroy all objects.
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 0a0b6c83e..0885000f7 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -3406,7 +3406,7 @@ public void ChangeEffectIntensity(string effectName, byte intensity, float durat
/// Whether or not the tantrum will apply the effect.
/// If is , the tantrum is moved slightly up from its original position. Otherwise, the collision will not be detected and the slowness will not work.
/// The instance..
- public TantrumHazard PlaceTantrum(bool isActive = true) => Map.PlaceTantrum(Position, isActive);
+ public TantrumHazard PlaceTantrum(bool isActive = true) => TantrumHazard.PlaceTantrum(Position, isActive);
///
/// Gives a new to the player .
diff --git a/EXILED/Exiled.API/Features/PrefabHelper.cs b/EXILED/Exiled.API/Features/PrefabHelper.cs
index de97e15d5..fd18e9fe9 100644
--- a/EXILED/Exiled.API/Features/PrefabHelper.cs
+++ b/EXILED/Exiled.API/Features/PrefabHelper.cs
@@ -41,6 +41,21 @@ public static PrefabAttribute GetPrefabAttribute(this PrefabType prefabType)
return type.GetField(Enum.GetName(type, prefabType)).GetCustomAttribute();
}
+ ///
+ /// Gets the prefab of the specified .
+ ///
+ /// The to get prefab of.
+ /// The to get.
+ /// Returns the prefab component as {T}.
+ public static T GetPrefab(PrefabType type)
+ where T : Component
+ {
+ if (!Stored.TryGetValue(type, out GameObject gameObject) || !gameObject.TryGetComponent(out T component))
+ return null;
+
+ return component;
+ }
+
///
/// Spawns a prefab on server.
///
@@ -68,9 +83,7 @@ public static GameObject Spawn(PrefabType prefabType, Vector3 position = default
public static T Spawn(PrefabType prefabType, Vector3 position = default, Quaternion rotation = default)
where T : Component
{
- if (!Stored.TryGetValue(prefabType, out GameObject gameObject) || !gameObject.TryGetComponent(out T component))
- return null;
- T obj = UnityEngine.Object.Instantiate(component, position, rotation);
+ T obj = UnityEngine.Object.Instantiate(GetPrefab(prefabType), position, rotation);
NetworkServer.Spawn(obj.gameObject);
return obj;
}
diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs
index dcf4e27cb..4ca71d8c8 100644
--- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs
+++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs
@@ -50,9 +50,18 @@ protected FpcRole(FpcStandardRoleBase baseRole)
public FpcStandardRoleBase FirstPersonController { get; }
///
- /// Gets or sets the player's relative position.
+ /// Gets or sets the player's relative position as perceived by the server.
///
public RelativePosition RelativePosition
+ {
+ get => new(Owner.Position);
+ set => Owner.Position = value.Position;
+ }
+
+ ///
+ /// Gets or sets the player's relative position as perceived by the client.
+ ///
+ public RelativePosition ClientRelativePosition
{
get => FirstPersonController.FpcModule.Motor.ReceivedPosition;
set => FirstPersonController.FpcModule.Motor.ReceivedPosition = value;
diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs
index 908096434..b1b05e8c1 100644
--- a/EXILED/Exiled.API/Features/Server.cs
+++ b/EXILED/Exiled.API/Features/Server.cs
@@ -111,6 +111,15 @@ public static string Name
///
public static double Tps => Math.Round(1f / Time.smoothDeltaTime);
+ ///
+ /// Gets or sets the max ticks per second of the server.
+ ///
+ public static short MaxTps
+ {
+ get => ServerStatic.ServerTickrate;
+ set => ServerStatic.ServerTickrate = value;
+ }
+
///
/// Gets the actual frametime of the server.
///
diff --git a/EXILED/Exiled.Events/Commands/TpsCommand.cs b/EXILED/Exiled.Events/Commands/TpsCommand.cs
new file mode 100644
index 000000000..2d7412919
--- /dev/null
+++ b/EXILED/Exiled.Events/Commands/TpsCommand.cs
@@ -0,0 +1,46 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Commands
+{
+ using System;
+
+ using CommandSystem;
+ using Exiled.API.Features;
+
+ ///
+ /// Command for showing current server TPS.
+ ///
+ [CommandHandler(typeof(RemoteAdminCommandHandler))]
+ [CommandHandler(typeof(GameConsoleCommandHandler))]
+ public class TpsCommand : ICommand
+ {
+ ///
+ public string Command { get; } = "tps";
+
+ ///
+ public string[] Aliases { get; } = Array.Empty();
+
+ ///
+ public string Description { get; } = "Shows the current TPS of the server";
+
+ ///
+ public bool Execute(ArraySegment arguments, ICommandSender sender, out string response)
+ {
+ double diff = Server.Tps / Server.MaxTps;
+ string color = diff switch
+ {
+ > 0.9 => "green",
+ > 0.5 => "yellow",
+ _ => "red"
+ };
+
+ response = $"{Server.Tps}/{Server.MaxTps} ";
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingRoleEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingRoleEventArgs.cs
index 552d70a73..c8ab4d9ba 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/ChangingRoleEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingRoleEventArgs.cs
@@ -11,11 +11,10 @@ namespace Exiled.Events.EventArgs.Player
using API.Enums;
using API.Features;
+ using Exiled.API.Extensions;
using Exiled.API.Features.Pools;
using Interfaces;
-
- using InventorySystem.Configs;
-
+ using InventorySystem;
using PlayerRoles;
///
@@ -70,17 +69,16 @@ public RoleTypeId NewRole
get => newRole;
set
{
- if (StartingInventories.DefinedInventories.ContainsKey(value))
- {
- Items.Clear();
- Ammo.Clear();
+ InventoryRoleInfo inventory = value.GetInventory();
+
+ Items.Clear();
+ Ammo.Clear();
- foreach (ItemType itemType in StartingInventories.DefinedInventories[value].Items)
- Items.Add(itemType);
+ foreach (ItemType itemType in inventory.Items)
+ Items.Add(itemType);
- foreach (KeyValuePair ammoPair in StartingInventories.DefinedInventories[value].Ammo)
- Ammo.Add(ammoPair.Key, ammoPair.Value);
- }
+ foreach (KeyValuePair ammoPair in inventory.Ammo)
+ Ammo.Add(ammoPair.Key, ammoPair.Value);
newRole = value;
}
From fada3676d72f58936cbf37680d0bc50bcb110ab6 Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Sun, 11 Aug 2024 13:31:52 +0200
Subject: [PATCH 21/63] `[EXILED::API]` Pickup::Category (#46)
* Item Category on Pickup
* Fixed Build Error
---
EXILED/Exiled.API/Features/Pickups/Pickup.cs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/EXILED/Exiled.API/Features/Pickups/Pickup.cs b/EXILED/Exiled.API/Features/Pickups/Pickup.cs
index 3f7373dee..6c600dd4c 100644
--- a/EXILED/Exiled.API/Features/Pickups/Pickup.cs
+++ b/EXILED/Exiled.API/Features/Pickups/Pickup.cs
@@ -11,6 +11,7 @@ namespace Exiled.API.Features.Pickups
using System.Collections.Generic;
using System.Linq;
+ using Exiled.API.Extensions;
using Exiled.API.Features.Core;
using Exiled.API.Features.Pickups.Projectiles;
using Exiled.API.Interfaces;
@@ -208,6 +209,11 @@ public float PickupTime
///
public ItemType Type => Base.NetworkInfo.ItemId;
+ ///
+ /// Gets the of the item.
+ ///
+ public ItemCategory Category => Type.GetCategory();
+
///
/// Gets or sets a value indicating whether the pickup is locked (can't be picked up).
///
From 2ee9f467af6b4eceaa83372cd273249a77760bff Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Sun, 11 Aug 2024 19:29:08 +0200
Subject: [PATCH 22/63] Fix (#50)
---
EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs b/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs
index d052b914c..e31fe2615 100644
--- a/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs
+++ b/EXILED/Exiled.CreditTags/Features/DatabaseHandler.cs
@@ -1,4 +1,4 @@
-// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
//
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
@@ -17,7 +17,7 @@ namespace Exiled.CreditTags.Features
public static class DatabaseHandler
{
- private const string Url = "https://raw.githubusercontent.com/Exiled-Official/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;
From ee317e7cc868e990c9e599ec08e2326b8de53dd5 Mon Sep 17 00:00:00 2001
From: VALERA771 <72030575+VALERA771@users.noreply.github.com>
Date: Mon, 12 Aug 2024 19:25:26 +0300
Subject: [PATCH 23/63] `[Exiled::API]` Removing breaking changes (#54)
Co-authored-by: Nameless <85962933+Misfiy@users.noreply.github.com>
---
EXILED/Exiled.API/Features/Player.cs | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 0885000f7..314817264 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -2411,6 +2411,17 @@ public ushort GetAmmoLimit(AmmoType type, bool ignoreArmor = false)
return InventorySystem.Configs.InventoryLimits.GetAmmoLimit(type.GetItemType(), referenceHub);
}
+ ///
+ /// Gets the maximum amount of ammo the player can hold, given the ammo .
+ ///
+ /// The of the ammo to check.
+ /// The maximum amount of ammo this player can carry.
+ [Obsolete("Use Player::GetAmmoLimit(AmmoType, bool) instead.")]
+ public int GetAmmoLimit(AmmoType type)
+ {
+ return (int)InventorySystem.Configs.InventoryLimits.GetAmmoLimit(type.GetItemType(), referenceHub);
+ }
+
///
/// Gets the maximum amount of ammo the player can hold, given the ammo .
/// This limit will scale with the armor the player is wearing.
From b66b2fd95e3811a0dea662b584ba925042a6c75e Mon Sep 17 00:00:00 2001
From: IRacle <79921583+IRacle1@users.noreply.github.com>
Date: Mon, 12 Aug 2024 20:15:02 +0300
Subject: [PATCH 24/63] `Scp330` sound fix (#55)
Co-authored-by: Misaka-ZeroTwo <45165615+Misaka-ZeroTwo@users.noreply.github.com>
---
.../Scp330/InteractingScp330EventArgs.cs | 9 ++-
.../Events/Scp330/InteractingScp330.cs | 67 +++++++++++++------
2 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs
index b87238842..45a587755 100644
--- a/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs
@@ -35,6 +35,7 @@ public InteractingScp330EventArgs(Player player, int usage)
Candy = Scp330Candies.GetRandom();
UsageCount = usage;
ShouldSever = usage >= 2;
+ ShouldPlaySound = true;
IsAllowed = Player.IsHuman;
}
@@ -53,10 +54,16 @@ public InteractingScp330EventArgs(Player player, int usage)
///
public bool ShouldSever { get; set; }
+ ///
+ /// Gets or sets a value indicating whether the sound should be played.
+ ///
+ /// It won't work if = .
+ public bool ShouldPlaySound { get; set; }
+
///
/// Gets or sets a value indicating whether the player is allowed to interact with SCP-330.
///
- public bool IsAllowed { get; set; } = true;
+ public bool IsAllowed { get; set; }
///
/// Gets the triggering the event.
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs b/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
index c8ff97d32..bcb4f5308 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
@@ -10,6 +10,7 @@ namespace Exiled.Events.Patches.Events.Scp330
using System.Collections.Generic;
using System.Reflection.Emit;
+ using Exiled.API.Features;
using Exiled.API.Features.Pools;
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Scp330;
@@ -17,6 +18,7 @@ namespace Exiled.Events.Patches.Events.Scp330
using HarmonyLib;
using Interactables.Interobjects;
using InventorySystem.Items.Usables.Scp330;
+ using PluginAPI.Events;
using static HarmonyLib.AccessTools;
@@ -34,9 +36,7 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions);
- Label shouldNotSever = generator.DefineLabel();
Label returnLabel = generator.DefineLabel();
- Label enableEffectLabel = generator.DefineLabel();
LocalBuilder ev = generator.DeclareLocal(typeof(InteractingScp330EventArgs));
@@ -74,35 +74,60 @@ private static IEnumerable Transpiler(IEnumerable instruction.Calls(Method(typeof(Scp330Interobject), nameof(Scp330Interobject.RpcMakeSound)))) + addShouldSeverOffset;
+ /* next code will used to override sound rpc check by EXILED
+ * old:
+ * if (args.PlaySound)
+ * new:
+ * if (args.PlaySound && ev.PlaySound)
+ */
- int serverEffectLocationStart = -1;
- int enableEffect = newInstructions.FindLastIndex(
- instruction => instruction.LoadsField(Field(typeof(ReferenceHub), nameof(ReferenceHub.playerEffectsController)))) + serverEffectLocationStart;
+ offset = 1;
+ index = newInstructions.FindLastIndex(
+ instruction => instruction.Calls(PropertyGetter(typeof(PlayerInteractScp330Event), nameof(PlayerInteractScp330Event.PlaySound)))) + offset;
- newInstructions[enableEffect].WithLabels(enableEffectLabel);
newInstructions.InsertRange(
- addShouldSeverIndex,
+ index,
+ new[]
+ {
+ // load ev.ShouldPlaySound and or operation with nw property.
+ new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(InteractingScp330EventArgs), nameof(InteractingScp330EventArgs.ShouldPlaySound))),
+ new(OpCodes.And),
+ });
+
+ /* next code will used to override Sever check by EXILED
+ * old:
+ * if (args.AllowPunishment && uses >= 2)
+ * new:
+ * if (args.AllowPunishment && ev.ShouldSever)
+ */
+
+ // set `notSeverLabel`
+ offset = -1;
+ index = newInstructions.FindLastIndex(
+ instruction => instruction.LoadsField(Field(typeof(Scp330Interobject), nameof(Scp330Interobject._takenCandies)))) + offset;
+
+ Label notSeverLabel = newInstructions[index].labels[0];
+
+ offset = 2;
+ index = newInstructions.FindLastIndex(
+ instruction => instruction.Calls(PropertyGetter(typeof(PlayerInteractScp330Event), nameof(PlayerInteractScp330Event.AllowPunishment)))) + offset;
+
+ // remove `uses >= 2` check, to override that by ev.ShouldSever
+ newInstructions.RemoveRange(index, 3);
+
+ newInstructions.InsertRange(
+ index,
new[]
{
// if (!ev.ShouldSever)
// goto shouldNotSever;
- new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex),
+ new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(InteractingScp330EventArgs), nameof(InteractingScp330EventArgs.ShouldSever))),
- new(OpCodes.Brfalse, shouldNotSever),
- new(OpCodes.Br, enableEffectLabel),
+ new(OpCodes.Brfalse_S, notSeverLabel),
});
- // This will let us jump to the taken candies code and lock until ldarg_0, meaning we allow base game logic handle candy adding.
- int addTakenCandiesOffset = -1;
- int addTakenCandiesIndex = newInstructions.FindLastIndex(
- instruction => instruction.LoadsField(Field(typeof(Scp330Interobject), nameof(Scp330Interobject._takenCandies)))) + addTakenCandiesOffset;
-
- newInstructions[addTakenCandiesIndex].WithLabels(shouldNotSever);
- newInstructions[newInstructions.Count - 1].WithLabels(returnLabel);
+ newInstructions[newInstructions.Count - 1].labels.Add(returnLabel);
for (int z = 0; z < newInstructions.Count; z++)
yield return newInstructions[z];
From 0ab903797dfa7cc5fbdf5199a97df9eb18de323c Mon Sep 17 00:00:00 2001
From: Nameless <85962933+Misfiy@users.noreply.github.com>
Date: Mon, 12 Aug 2024 20:21:52 +0200
Subject: [PATCH 25/63] Fix Npc (#58)
---
EXILED/Exiled.API/Features/Npc.cs | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Npc.cs b/EXILED/Exiled.API/Features/Npc.cs
index 6824cbab9..52f339dea 100644
--- a/EXILED/Exiled.API/Features/Npc.cs
+++ b/EXILED/Exiled.API/Features/Npc.cs
@@ -5,26 +5,22 @@
//
// -----------------------------------------------------------------------
-#nullable enable
namespace Exiled.API.Features
{
+#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using CommandSystem;
-
using Exiled.API.Enums;
using Exiled.API.Extensions;
using Exiled.API.Features.Components;
+ using Exiled.API.Features.Roles;
using Footprinting;
-
using MEC;
-
using Mirror;
-
using PlayerRoles;
-
using UnityEngine;
using Object = UnityEngine.Object;
@@ -60,8 +56,8 @@ public override Vector3 Position
set
{
base.Position = value;
- if (Role is Roles.FpcRole fpcRole)
- fpcRole.RelativePosition = new(value);
+ if (Role is FpcRole fpcRole)
+ fpcRole.ClientRelativePosition = new(value);
}
}
From 119f930f5a910e3c645fe01c0915681984b6eab8 Mon Sep 17 00:00:00 2001
From: Misaka-ZeroTwo <45165615+Misaka-ZeroTwo@users.noreply.github.com>
Date: Wed, 14 Aug 2024 00:08:25 +0800
Subject: [PATCH 26/63] Fix breaking change (#61)
Fix a breaking change in #9
---
EXILED/Exiled.API/Features/Player.cs | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 314817264..0a2b20b4f 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -2478,6 +2478,15 @@ public void ResetAmmoLimit(AmmoType ammoType)
/// If the player has a custom limit for the specific .
public bool HasCustomAmmoLimit(AmmoType ammoType) => CustomAmmoLimits.ContainsKey(ammoType);
+ ///
+ /// Gets the maximum amount of an the player can hold, based on the armor the player is wearing, as well as server configuration.
+ ///
+ /// The to check.
+ /// The maximum amount of items in the category that the player can hold.
+ [Obsolete("Use Player::GetCategoryLimit(ItemCategory, bool) instead.")]
+ public int GetCategoryLimit(ItemCategory category) =>
+ InventorySystem.Configs.InventoryLimits.GetCategoryLimit(category, referenceHub);
+
///
/// Gets the maximum amount of an the player can hold, based on the armor the player is wearing, as well as server configuration.
///
From afdb0b216f43d6910453aaa34f483035e81614fd Mon Sep 17 00:00:00 2001
From: Misaka-ZeroTwo <45165615+Misaka-ZeroTwo@users.noreply.github.com>
Date: Wed, 14 Aug 2024 00:11:19 +0800
Subject: [PATCH 27/63] Version bump
---
EXILED/EXILED.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/EXILED/EXILED.props b/EXILED/EXILED.props
index 52056665f..e1ff99890 100644
--- a/EXILED/EXILED.props
+++ b/EXILED/EXILED.props
@@ -15,7 +15,7 @@
- 8.12.0-rc.2
+ 8.12.0-rc.3
false
From 904865e04f86424b77b27023aa7d138ed5dfe220 Mon Sep 17 00:00:00 2001
From: IRacle
Date: Wed, 14 Aug 2024 15:36:50 +0300
Subject: [PATCH 28/63] =?UTF-8?q?=F0=9F=92=80=F0=9F=92=80=F0=9F=92=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
EXILED/Exiled.API/Features/Player.cs | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 0a2b20b4f..b5890c2a7 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -1277,13 +1277,8 @@ public static Player Get(GameObject gameObject)
if (Dictionary.TryGetValue(gameObject, out Player player))
return player;
- if (UnverifiedPlayers.TryGetValue(gameObject, out player))
- return player;
-
- if (ReferenceHub.TryGetHub(gameObject, out ReferenceHub hub))
- return new(hub);
-
- return null;
+ UnverifiedPlayers.TryGetValue(gameObject, out player);
+ return player;
}
///
From bcb78e70ede8b6bf7a022fe55bcd06b06f442430 Mon Sep 17 00:00:00 2001
From: IRacle
Date: Thu, 15 Aug 2024 14:38:35 +0300
Subject: [PATCH 29/63] `SendStaffMessage` fix
---
EXILED/Exiled.API/Features/Player.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index b5890c2a7..175d7731a 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -2288,7 +2288,7 @@ public void RemoteAdminMessage(string message, bool success = true, string plugi
/// if message was send; otherwise, .
public bool SendStaffMessage(string message, EncryptedChannelManager.EncryptedChannel channel = EncryptedChannelManager.EncryptedChannel.AdminChat)
{
- return ReferenceHub.encryptedChannelManager.TrySendMessageToClient("!" + NetId + message, channel);
+ return ReferenceHub.encryptedChannelManager.TrySendMessageToClient(NetId + "!" + message, channel);
}
///
@@ -2299,7 +2299,7 @@ public bool SendStaffMessage(string message, EncryptedChannelManager.EncryptedCh
/// if message was send; otherwise, .
public bool SendStaffPing(string message, EncryptedChannelManager.EncryptedChannel channel = EncryptedChannelManager.EncryptedChannel.AdminChat)
{
- return ReferenceHub.encryptedChannelManager.TrySendMessageToClient("!0" + message, channel);
+ return ReferenceHub.encryptedChannelManager.TrySendMessageToClient("0!" + message, channel);
}
///
From 53ce718f2522a0c967ebb72f010b699fe6cbff11 Mon Sep 17 00:00:00 2001
From: FoxWorn3365 <61429263+FoxWorn3365@users.noreply.github.com>
Date: Fri, 16 Aug 2024 01:25:00 +0200
Subject: [PATCH 30/63] Added the SCP-079 Recontaining event (#21)
* added the RecontainingEvent with the patch
* Fixed constructors
* consistency
* fixed logic skill issue
* Removed "useless" constructor
* corrected the typo
* fixed some typo
* final edit for the final request
* Apply suggestions from code review
* Apply suggestions from code review
Co-authored-by: VALERA771 <72030575+VALERA771@users.noreply.github.com>
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
Co-authored-by: VALERA771 <72030575+VALERA771@users.noreply.github.com>
---
.../EventArgs/Scp079/RecontainingEventArgs.cs | 42 ++++++++++++
EXILED/Exiled.Events/Handlers/Scp079.cs | 11 +++
.../Patches/Events/Scp079/Recontaining.cs | 67 +++++++++++++++++++
3 files changed, 120 insertions(+)
create mode 100644 EXILED/Exiled.Events/EventArgs/Scp079/RecontainingEventArgs.cs
create mode 100644 EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs
diff --git a/EXILED/Exiled.Events/EventArgs/Scp079/RecontainingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp079/RecontainingEventArgs.cs
new file mode 100644
index 000000000..11d88c3f1
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Scp079/RecontainingEventArgs.cs
@@ -0,0 +1,42 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Scp079
+{
+ using Exiled.API.Features;
+ using Exiled.Events.EventArgs.Interfaces;
+
+ ///
+ /// Contains information before SCP-079 gets recontained.
+ ///
+ public class RecontainingEventArgs : IDeniableEvent, IPlayerEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The instance.
+ public RecontainingEventArgs(BreakableWindow recontainer)
+ {
+ Player = Player.Get(recontainer.LastAttacker.Hub);
+ IsAutomatic = recontainer.LastAttacker.IsSet;
+ }
+
+ ///
+ /// Gets the Player that started the recontainment process.
+ /// Can be null if is true.
+ ///
+ public Player Player { get; }
+
+ ///
+ public bool IsAllowed { get; set; } = true;
+
+ ///
+ /// Gets a value indicating whether or not the recontained has been made automatically or by triggering the proccess.
+ ///
+ public bool IsAutomatic { get; }
+ }
+}
diff --git a/EXILED/Exiled.Events/Handlers/Scp079.cs b/EXILED/Exiled.Events/Handlers/Scp079.cs
index 85da2da7e..b272defea 100644
--- a/EXILED/Exiled.Events/Handlers/Scp079.cs
+++ b/EXILED/Exiled.Events/Handlers/Scp079.cs
@@ -57,6 +57,11 @@ public static class Scp079
///
public static Event ChangingSpeakerStatus { get; set; } = new();
+ ///
+ /// Invoked before SCP-079 recontainment.
+ ///
+ public static Event Recontaining { get; set; } = new();
+
///
/// Invoked after SCP-079 recontainment.
///
@@ -125,6 +130,12 @@ public static class Scp079
/// The instance.
public static void OnChangingSpeakerStatus(ChangingSpeakerStatusEventArgs ev) => ChangingSpeakerStatus.InvokeSafely(ev);
+ ///
+ /// Called before SCP-079 is recontained.
+ ///
+ /// The instance.
+ public static void OnRecontaining(RecontainingEventArgs ev) => Recontaining.InvokeSafely(ev);
+
///
/// Called after SCP-079 is recontained.
///
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs
new file mode 100644
index 000000000..82e924fbc
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs
@@ -0,0 +1,67 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Events.Scp079
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using Exiled.API.Features.Pools;
+ using Exiled.Events.Attributes;
+ using Exiled.Events.EventArgs.Scp079;
+ using Exiled.Events.Handlers;
+
+ using HarmonyLib;
+
+ using PlayerRoles.PlayableScps.Scp079;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches .
+ /// Adds the event.
+ ///
+ [EventPatch(typeof(Scp079), nameof(Scp079.Recontaining))]
+ [HarmonyPatch(typeof(Scp079Recontainer), nameof(Scp079Recontainer.Recontain))]
+ internal class Recontaining
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ int index = 0;
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ LocalBuilder ev = generator.DeclareLocal(typeof(RecontainingEventArgs));
+
+ Label returnLabel = generator.DefineLabel();
+
+ newInstructions.InsertRange(index, new CodeInstruction[]
+ {
+ // RecontainingEventArgs ev = new(this._activatorGlass)
+ new(OpCodes.Ldarg_0),
+ new(OpCodes.Ldfld, PropertyGetter(typeof(Scp079Recontainer), nameof(Scp079Recontainer._activatorGlass))),
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RecontainingEventArgs))[0]),
+ new(OpCodes.Stloc_S, ev.LocalIndex),
+
+ // Scp079.OnRecontaining(ev)
+ new(OpCodes.Ldloc_S, ev.LocalIndex),
+ new(OpCodes.Call, Method(typeof(Scp079), nameof(Scp079.OnRecontaining))),
+
+ // if (!ev.IsAllowed) return;
+ new(OpCodes.Ldloc_S, ev.LocalIndex),
+ new(OpCodes.Callvirt, Method(typeof(RecontainingEventArgs), nameof(RecontainingEventArgs.IsAllowed))),
+ new(OpCodes.Brfalse_S, returnLabel),
+ });
+
+ newInstructions[newInstructions.Count - 1].WithLabels(returnLabel);
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
From bc0b1798cd4a764e625b6c77f8c1b90009a32852 Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Fri, 16 Aug 2024 01:28:35 +0200
Subject: [PATCH 31/63] `[EXILED::API]` Adding SpawnMice (#47)
* Mouse Spawner
* Changes to make it public
* Optimization
* Finally can i spawn rats?
* Fix adding throw and changing the error that throws
---------
Co-authored-by: VALERA771 <72030575+VALERA771@users.noreply.github.com>
---
EXILED/Exiled.API/Features/Map.cs | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs
index 3f1f6fc1a..2b3c4cdb0 100644
--- a/EXILED/Exiled.API/Features/Map.cs
+++ b/EXILED/Exiled.API/Features/Map.cs
@@ -54,6 +54,8 @@ public static class Map
private static AmbientSoundPlayer ambientSoundPlayer;
+ private static SqueakSpawner squeakSpawner;
+
///
/// Gets the tantrum prefab.
///
@@ -109,6 +111,11 @@ public static int Seed
///
public static AmbientSoundPlayer AmbientSoundPlayer => ambientSoundPlayer ??= ReferenceHub.HostHub.GetComponent();
+ ///
+ /// Gets the .
+ ///
+ public static SqueakSpawner SqueakSpawner => squeakSpawner ??= Object.FindObjectOfType();
+
///
/// Broadcasts a message to all players .
///
@@ -362,6 +369,19 @@ public static void PlayGunSound(Vector3 position, ItemType firearmType, byte max
msg.SendToAuthenticated();
}
+ ///
+ /// Spawns mice inside the .
+ ///
+ /// The type of mice you want to spawn..
+ public static void SpawnMice(byte mice = 1)
+ {
+ if (mice > SqueakSpawner.mice.Length)
+ throw new ArgumentOutOfRangeException($"Mouse type must be between 1 and {SqueakSpawner.mice.Length}.");
+
+ SqueakSpawner.NetworksyncSpawn = mice;
+ SqueakSpawner.SyncMouseSpawn(0, SqueakSpawner.NetworksyncSpawn);
+ }
+
///
/// Clears the lazy loading game object cache.
///
From 7a6df1691c72691efc2e7b4139a0708215c657d0 Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Fri, 16 Aug 2024 01:29:05 +0200
Subject: [PATCH 32/63] `[EXILED::API]` Adding ScaleNetworkIdentityObject (#49)
---
.../Exiled.API/Extensions/MirrorExtensions.cs | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
index e85b54ed6..21f2d111e 100644
--- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
+++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
@@ -355,6 +355,44 @@ public static void MessageTranslated(this Player player, string words, string tr
}
}
+ ///
+ /// Scales an object for the specified player.
+ ///
+ /// Target to send.
+ /// The to scale.
+ /// The scale the object needs to be set to.
+ public static void ScaleNetworkIdentityObject(this Player player, NetworkIdentity identity, Vector3 scale)
+ {
+ identity.gameObject.transform.localScale = scale;
+ ObjectDestroyMessage objectDestroyMessage = new()
+ {
+ netId = identity.netId,
+ };
+
+ player.Connection.Send(objectDestroyMessage, 0);
+ SendSpawnMessageMethodInfo?.Invoke(null, new object[] { identity, player.Connection });
+ }
+
+ ///
+ /// Scales an object for all players.
+ ///
+ /// The to scale.
+ /// The scale the object needs to be set to.
+ public static void ScaleNetworkIdentityObject(this NetworkIdentity identity, Vector3 scale)
+ {
+ identity.gameObject.transform.localScale = scale;
+ ObjectDestroyMessage objectDestroyMessage = new()
+ {
+ netId = identity.netId,
+ };
+
+ foreach (Player ply in Player.List)
+ {
+ ply.Connection.Send(objectDestroyMessage, 0);
+ SendSpawnMessageMethodInfo?.Invoke(null, new object[] { identity, ply.Connection });
+ }
+ }
+
///
/// Send fake values to client's .
///
From 7befb7a4c2a82c6336c1b564f1c346486932c440 Mon Sep 17 00:00:00 2001
From: IRacle
Date: Fri, 16 Aug 2024 16:42:17 +0300
Subject: [PATCH 33/63] =?UTF-8?q?Revert=20"=F0=9F=92=80=F0=9F=92=80?=
=?UTF-8?q?=F0=9F=92=80"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit 904865e04f86424b77b27023aa7d138ed5dfe220.
---
EXILED/Exiled.API/Features/Player.cs | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 175d7731a..b7a4afee5 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -1277,8 +1277,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;
}
///
From 0c9cfff3bb7fc9fa45d850f87403429e76b4a6b8 Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Tue, 20 Aug 2024 21:02:26 +0200
Subject: [PATCH 34/63] `[EXILED::API]` Adding SendFakeSceneLoading (#45)
* Added ScenesType and Corrisponding Methods for the Server and Player
* Fixing Building Error
* Applied the Change request
* Changes requested by Yamato made
* Fixed Building Errors
* Fix build
---------
Co-authored-by: VALERA771 <72030575+VALERA771@users.noreply.github.com>
---
EXILED/Exiled.API/Enums/ScenesType.cs | 47 +++++++++++++++++++
.../Exiled.API/Extensions/MirrorExtensions.cs | 30 ++++++++++++
EXILED/Exiled.API/Features/Server.cs | 2 +
3 files changed, 79 insertions(+)
create mode 100644 EXILED/Exiled.API/Enums/ScenesType.cs
diff --git a/EXILED/Exiled.API/Enums/ScenesType.cs b/EXILED/Exiled.API/Enums/ScenesType.cs
new file mode 100644
index 000000000..2a7898ca6
--- /dev/null
+++ b/EXILED/Exiled.API/Enums/ScenesType.cs
@@ -0,0 +1,47 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.API.Enums
+{
+ ///
+ /// Unique identifier for the different types of Scenes the client and server can load.
+ ///
+ public enum ScenesType
+ {
+ ///
+ /// The facility itself.
+ ///
+ Facility,
+
+ ///
+ /// The current main menu.
+ /// ! Will cause crash when trying joining servers !
+ ///
+ NewMainMenu,
+
+ ///
+ /// The old main menu.
+ ///
+ MainMenuRemastered,
+
+ ///
+ /// The old server list.
+ ///
+ FastMenu,
+
+ ///
+ /// The loading Screen.
+ /// ! Will cause crash when trying joining servers !
+ ///
+ PreLoader,
+
+ ///
+ /// A black menu before loading the .
+ ///
+ Loader,
+ }
+}
diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
index 21f2d111e..8b4350b5b 100644
--- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
+++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
@@ -15,6 +15,7 @@ namespace Exiled.API.Extensions
using System.Reflection.Emit;
using System.Text;
+ using Exiled.API.Enums;
using Features;
using Features.Pools;
@@ -355,6 +356,35 @@ public static void MessageTranslated(this Player player, string words, string tr
}
}
+ ///
+ /// Sends to the player a Fake Change Scene.
+ ///
+ /// The player to send the Scene.
+ /// The new Scene the client will load.
+ public static void SendFakeSceneLoading(this Player player, ScenesType newSceneName)
+ {
+ SceneMessage message = new()
+ {
+ sceneName = newSceneName.ToString(),
+ };
+
+ player.Connection.Send(message);
+ }
+
+ ///
+ /// Emulation of the method SCP:SL uses to change scene.
+ ///
+ /// The new Scene the client will load.
+ public static void ChangeSceneToAllClients(ScenesType scene)
+ {
+ SceneMessage message = new()
+ {
+ sceneName = scene.ToString(),
+ };
+
+ NetworkServer.SendToAll(message);
+ }
+
///
/// Scales an object for the specified player.
///
diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs
index b1b05e8c1..5dea5ee84 100644
--- a/EXILED/Exiled.API/Features/Server.cs
+++ b/EXILED/Exiled.API/Features/Server.cs
@@ -11,6 +11,8 @@ namespace Exiled.API.Features
using System.Collections.Generic;
using System.Reflection;
+ using Exiled.API.Enums;
+
using GameCore;
using Interfaces;
From 5fc1b143806940d08b6dccf02187cac57464a926 Mon Sep 17 00:00:00 2001
From: IRacle <79921583+IRacle1@users.noreply.github.com>
Date: Sat, 24 Aug 2024 13:16:45 +0300
Subject: [PATCH 35/63] scp018projectile (#73)
---
EXILED/Exiled.API/Features/Pickups/Pickup.cs | 1 +
.../Pickups/Projectiles/Scp018Projectile.cs | 20 +++++++++++++++++--
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Pickups/Pickup.cs b/EXILED/Exiled.API/Features/Pickups/Pickup.cs
index 6c600dd4c..010b1e52c 100644
--- a/EXILED/Exiled.API/Features/Pickups/Pickup.cs
+++ b/EXILED/Exiled.API/Features/Pickups/Pickup.cs
@@ -133,6 +133,7 @@ internal Pickup(ItemType type)
public PickupStandardPhysics PhysicsModule
{
get => Base.PhysicsModule as PickupStandardPhysics;
+ [Obsolete("Unsafe.")]
set
{
Base.PhysicsModule.DestroyModule();
diff --git a/EXILED/Exiled.API/Features/Pickups/Projectiles/Scp018Projectile.cs b/EXILED/Exiled.API/Features/Pickups/Projectiles/Scp018Projectile.cs
index c5549c87f..798cd04fc 100644
--- a/EXILED/Exiled.API/Features/Pickups/Projectiles/Scp018Projectile.cs
+++ b/EXILED/Exiled.API/Features/Pickups/Projectiles/Scp018Projectile.cs
@@ -7,7 +7,11 @@
namespace Exiled.API.Features.Pickups.Projectiles
{
+ using System;
+ using System.Reflection;
+
using Exiled.API.Interfaces;
+ using HarmonyLib;
using InventorySystem.Items.ThrowableProjectiles;
@@ -18,6 +22,9 @@ namespace Exiled.API.Features.Pickups.Projectiles
///
public class Scp018Projectile : TimeGrenadeProjectile, IWrapper
{
+ private static FieldInfo maxVelocityField;
+ private static FieldInfo velocityPerBounceField;
+
///
/// Initializes a new instance of the class.
///
@@ -48,6 +55,7 @@ internal Scp018Projectile()
public new Scp018Physics PhysicsModule
{
get => Base.PhysicsModule as Scp018Physics;
+ [Obsolete("Unsafe.", true)]
set
{
Base.PhysicsModule.DestroyModule();
@@ -61,7 +69,11 @@ internal Scp018Projectile()
public float MaxVelocity
{
get => PhysicsModule._maxVel;
- set => PhysicsModule = new Scp018Physics(Base, PhysicsModule._trail, PhysicsModule._radius, value, PhysicsModule._velPerBounce);
+ set
+ {
+ maxVelocityField ??= AccessTools.Field(typeof(Scp018Physics), nameof(Scp018Physics._maxVel));
+ maxVelocityField.SetValue(PhysicsModule, value);
+ }
}
///
@@ -70,7 +82,11 @@ public float MaxVelocity
public float VelocityPerBounce
{
get => PhysicsModule._maxVel;
- set => PhysicsModule = new Scp018Physics(Base, PhysicsModule._trail, PhysicsModule._radius, MaxVelocity, value);
+ set
+ {
+ velocityPerBounceField ??= AccessTools.Field(typeof(Scp018Physics), nameof(Scp018Physics._velPerBounce));
+ velocityPerBounceField.SetValue(PhysicsModule, value);
+ }
}
///
From 327801e77e8ab5c8a59122db71e56853eda0995e Mon Sep 17 00:00:00 2001
From: IRacle <79921583+IRacle1@users.noreply.github.com>
Date: Tue, 27 Aug 2024 17:21:36 +0300
Subject: [PATCH 36/63] =?UTF-8?q?=F0=9F=98=B1=F0=9F=98=8E=F0=9F=99=82?=
=?UTF-8?q?=F0=9F=92=80=F0=9F=98=88=20(#51)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Разрабы дауны😱😎🙂💀😈
* new better `SendFakeSyncVar` method
* ililililililil
* c
---
.../Exiled.API/Extensions/MirrorExtensions.cs | 33 +++++++++++++++
.../Exiled.Events/Patches/Generic/DoorList.cs | 42 +++++++++++++++++--
2 files changed, 71 insertions(+), 4 deletions(-)
diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
index 8b4350b5b..22d799677 100644
--- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
+++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
@@ -431,6 +431,7 @@ public static void ScaleNetworkIdentityObject(this NetworkIdentity identity, Vec
/// 's type.
/// Property name starting with Network.
/// Value of send to target.
+ [Obsolete("Use overload with type-template instead.")]
public static void SendFakeSyncVar(this Player target, NetworkIdentity behaviorOwner, Type targetType, string propertyName, object value)
{
if (!target.IsConnected)
@@ -454,6 +455,38 @@ void CustomSyncVarGenerator(NetworkWriter targetWriter)
}
}
+ ///
+ /// Send fake values to client's .
+ ///
+ /// Target SyncVar property type.
+ /// Target to send.
+ /// of object that owns .
+ /// 's type.
+ /// Property name starting with Network.
+ /// Value of send to target.
+ public static void SendFakeSyncVar(this Player target, NetworkIdentity behaviorOwner, Type targetType, string propertyName, T value)
+ {
+ if (!target.IsConnected)
+ return;
+
+ NetworkWriterPooled writer = NetworkWriterPool.Get();
+ NetworkWriterPooled writer2 = NetworkWriterPool.Get();
+ MakeCustomSyncWriter(behaviorOwner, targetType, null, CustomSyncVarGenerator, writer, writer2);
+ target.Connection.Send(new EntityStateMessage
+ {
+ netId = behaviorOwner.netId,
+ payload = writer.ToArraySegment(),
+ });
+
+ NetworkWriterPool.Return(writer);
+ NetworkWriterPool.Return(writer2);
+ void CustomSyncVarGenerator(NetworkWriter targetWriter)
+ {
+ targetWriter.WriteULong(SyncVarDirtyBits[$"{targetType.Name}.{propertyName}"]);
+ WriterExtensions[typeof(T)]?.Invoke(null, new object[2] { targetWriter, value });
+ }
+ }
+
///
/// Force resync to client's .
///
diff --git a/EXILED/Exiled.Events/Patches/Generic/DoorList.cs b/EXILED/Exiled.Events/Patches/Generic/DoorList.cs
index 4f1ce6e33..b8b653455 100644
--- a/EXILED/Exiled.Events/Patches/Generic/DoorList.cs
+++ b/EXILED/Exiled.Events/Patches/Generic/DoorList.cs
@@ -30,14 +30,48 @@ namespace Exiled.Events.Patches.Generic
[HarmonyPatch(typeof(DoorVariant), nameof(DoorVariant.RegisterRooms))]
internal class DoorList
{
- private static void Postfix(DoorVariant __instance)
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
{
- if (Door.DoorVariantToDoor.ContainsKey(__instance))
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label ret = generator.DefineLabel();
+
+ // if (Rooms == null)
+ // return;
+ newInstructions.InsertRange(
+ 0,
+ new CodeInstruction[]
+ {
+ new(OpCodes.Ldarg_0),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(DoorVariant), nameof(DoorVariant.Rooms))),
+ new(OpCodes.Brfalse_S, ret),
+ });
+
+ // DoorList.InitDoor(this);
+ newInstructions.InsertRange(
+ newInstructions.Count - 1,
+ new CodeInstruction[]
+ {
+ new(OpCodes.Ldarg_0),
+ new(OpCodes.Call, Method(typeof(DoorList), nameof(DoorList.InitDoor))),
+ });
+
+ newInstructions[newInstructions.Count - 1].labels.Add(ret);
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+
+ private static void InitDoor(DoorVariant doorVariant)
+ {
+ if (Door.DoorVariantToDoor.ContainsKey(doorVariant))
return;
- List rooms = __instance.Rooms.Select(identifier => Room.RoomIdentifierToRoom[identifier]).ToList();
+ List rooms = doorVariant.Rooms.Select(identifier => Room.RoomIdentifierToRoom[identifier]).ToList();
- Door door = Door.Create(__instance, rooms);
+ Door door = Door.Create(doorVariant, rooms);
foreach (Room room in rooms)
{
From 880fde01370a4c77fdd19cf94560d8341ddf5ea2 Mon Sep 17 00:00:00 2001
From: IRacle <79921583+IRacle1@users.noreply.github.com>
Date: Tue, 27 Aug 2024 17:25:40 +0300
Subject: [PATCH 37/63] `KeycardPickup.Permissions` now is not joke (#70)
---
.../Item/KeycardInteractingEventArgs.cs | 7 ++-
.../Patches/Events/Item/KeycardInteracting.cs | 62 +++++++++++++------
2 files changed, 48 insertions(+), 21 deletions(-)
diff --git a/EXILED/Exiled.Events/EventArgs/Item/KeycardInteractingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/KeycardInteractingEventArgs.cs
index 65f7a95c7..181f7c7eb 100644
--- a/EXILED/Exiled.Events/EventArgs/Item/KeycardInteractingEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Item/KeycardInteractingEventArgs.cs
@@ -29,7 +29,7 @@ public class KeycardInteractingEventArgs : IPlayerEvent, IDeniableEvent, IDoorEv
///
public KeycardInteractingEventArgs(BaseKeycardPickup pickup, Player player, DoorVariant door, bool isAllowed = true)
{
- Pickup = Pickup.Get(pickup);
+ KeycardPickup = Pickup.Get(pickup);
Player = player;
Door = Door.Get(door);
IsAllowed = isAllowed;
@@ -38,7 +38,10 @@ public KeycardInteractingEventArgs(BaseKeycardPickup pickup, Player player, Door
///
/// Gets the item that's interacting with the door.
///
- public Pickup Pickup { get; }
+ public Pickup Pickup => KeycardPickup;
+
+ ///
+ public KeycardPickup KeycardPickup { get; }
///
/// Gets the player who's threw the keycard.
diff --git a/EXILED/Exiled.Events/Patches/Events/Item/KeycardInteracting.cs b/EXILED/Exiled.Events/Patches/Events/Item/KeycardInteracting.cs
index 288e5d212..e26ef525d 100644
--- a/EXILED/Exiled.Events/Patches/Events/Item/KeycardInteracting.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Item/KeycardInteracting.cs
@@ -11,10 +11,10 @@ namespace Exiled.Events.Patches.Events.Item
using System.Reflection.Emit;
using API.Features;
+ using API.Features.Pickups;
using API.Features.Pools;
using Exiled.Events;
- using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Item;
using Footprinting;
@@ -23,18 +23,19 @@ namespace Exiled.Events.Patches.Events.Item
using Interactables.Interobjects.DoorUtils;
- using InventorySystem.Items.Keycards;
+ using InventorySystem.Items;
using UnityEngine;
using static HarmonyLib.AccessTools;
+ using BaseKeycardPickup = InventorySystem.Items.Keycards.KeycardPickup;
+
///
- /// Patches .
+ /// Patches and adds implementation.
/// Adds the event.
///
- [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.KeycardInteracting))]
- [HarmonyPatch(typeof(KeycardPickup), nameof(KeycardPickup.ProcessCollision))]
+ [HarmonyPatch(typeof(BaseKeycardPickup), nameof(BaseKeycardPickup.ProcessCollision))]
internal static class KeycardInteracting
{
private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
@@ -46,7 +47,6 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable i.Calls(Method(typeof(DoorPermissions), nameof(DoorPermissions.CheckPermissions)))) + offset;
+ newInstructions.RemoveRange(index, 14);
newInstructions.InsertRange(
index,
new[]
{
- new(OpCodes.Stloc_S, havePermissions.LocalIndex),
- new(OpCodes.Br_S, skip2),
-
- // save original return
- new CodeInstruction(OpCodes.Ret).MoveLabelsFrom(newInstructions[index + 1]),
- new CodeInstruction(OpCodes.Nop).WithLabels(skip2),
+ // 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),
});
- newInstructions.RemoveRange(index + 4, 2);
+ // 4 new instructions
+ offset = 4;
+ index += offset;
+
+ newInstructions.RemoveRange(index, 2);
offset = -5;
index = newInstructions.FindIndex(i => i.Calls(PropertySetter(typeof(DoorVariant), nameof(DoorVariant.NetworkTargetState)))) + offset;
@@ -111,7 +117,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions);
}
+
+ private static bool CheckPermissions(BaseKeycardPickup keycard, DoorPermissions permissions)
+ {
+ 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
From acd1b2984db65090576c11e2a196da7432bcc223 Mon Sep 17 00:00:00 2001
From: VALERA771 <72030575+VALERA771@users.noreply.github.com>
Date: Tue, 27 Aug 2024 17:26:34 +0300
Subject: [PATCH 38/63] `[Exiled::Events]` `Unbanning` and `Unbanned` events
(#68)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* 🐱👤🐱👤🐱👤
* some fixes
* fix
* ☠️💀💀💀☠️💀
Co-authored-by: IRacle <79921583+IRacle1@users.noreply.github.com>
---------
Co-authored-by: IRacle <79921583+IRacle1@users.noreply.github.com>
---
.../EventArgs/Server/UnbannedEventArgs.cs | 36 ++++++++
.../EventArgs/Server/UnbanningEventArgs.cs | 43 +++++++++
EXILED/Exiled.Events/Handlers/Server.cs | 22 +++++
.../Patches/Events/Server/Unban.cs | 92 +++++++++++++++++++
4 files changed, 193 insertions(+)
create mode 100644 EXILED/Exiled.Events/EventArgs/Server/UnbannedEventArgs.cs
create mode 100644 EXILED/Exiled.Events/EventArgs/Server/UnbanningEventArgs.cs
create mode 100644 EXILED/Exiled.Events/Patches/Events/Server/Unban.cs
diff --git a/EXILED/Exiled.Events/EventArgs/Server/UnbannedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/UnbannedEventArgs.cs
new file mode 100644
index 000000000..f1181a3b9
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Server/UnbannedEventArgs.cs
@@ -0,0 +1,36 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Server
+{
+ ///
+ /// Contains all information after a player gets unbanned.
+ ///
+ public class UnbannedEventArgs
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ ///
+ public UnbannedEventArgs(string details, BanHandler.BanType banType)
+ {
+ BanDetails = BanHandler.ProcessBanItem(details, banType);
+ BanType = banType;
+ }
+
+ ///
+ /// Gets the ban details.
+ ///
+ public BanDetails BanDetails { get; }
+
+ ///
+ /// Gets the ban type.
+ ///
+ public BanHandler.BanType BanType { get; }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/EventArgs/Server/UnbanningEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/UnbanningEventArgs.cs
new file mode 100644
index 000000000..aa23690e6
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Server/UnbanningEventArgs.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 Exiled.Events.EventArgs.Interfaces;
+
+ ///
+ /// Contains all information before player is unbanned.
+ ///
+ public class UnbanningEventArgs : IDeniableEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ ///
+ ///
+ public UnbanningEventArgs(string banDetails, BanHandler.BanType banType, bool isAllowed = true)
+ {
+ BanDetails = BanHandler.ProcessBanItem(banDetails, banType);
+ BanType = banType;
+ IsAllowed = isAllowed;
+ }
+
+ ///
+ /// Gets or sets the ban details.
+ ///
+ public BanDetails BanDetails { get; set; }
+
+ ///
+ /// Gets the ban type.
+ ///
+ public BanHandler.BanType BanType { get; }
+
+ ///
+ public bool IsAllowed { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Handlers/Server.cs b/EXILED/Exiled.Events/Handlers/Server.cs
index 75be4d81c..3f5b71e63 100644
--- a/EXILED/Exiled.Events/Handlers/Server.cs
+++ b/EXILED/Exiled.Events/Handlers/Server.cs
@@ -111,6 +111,16 @@ public static class Server
///
public static Event ReloadedPermissions { get; set; } = new();
+ ///
+ /// Invoked before player is being unbanned.
+ ///
+ public static Event Unbanning { get; set; } = new();
+
+ ///
+ /// Invoked after player is being unbanned.
+ ///
+ public static Event Unbanned { get; set; } = new();
+
///
/// Called before waiting for players.
///
@@ -210,5 +220,17 @@ public static class Server
///
/// The instance.
public static void OnSelectingRespawnTeam(SelectingRespawnTeamEventArgs ev) => SelectingRespawnTeam.InvokeSafely(ev);
+
+ ///
+ /// Called before player is being unbanned.
+ ///
+ /// The instance.
+ public static void OnUnbanning(UnbanningEventArgs ev) => Unbanning.InvokeSafely(ev);
+
+ ///
+ /// Called after player is being unbanned.
+ ///
+ /// The instance.
+ public static void OnUnbanned(UnbannedEventArgs ev) => Unbanned.InvokeSafely(ev);
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Patches/Events/Server/Unban.cs b/EXILED/Exiled.Events/Patches/Events/Server/Unban.cs
new file mode 100644
index 000000000..5eb89d224
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Events/Server/Unban.cs
@@ -0,0 +1,92 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Events.Server
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using Exiled.API.Features.Pools;
+ using Exiled.Events.Attributes;
+ using Exiled.Events.EventArgs.Server;
+ using HarmonyLib;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches
+ /// to add and events.
+ ///
+ [HarmonyPatch(typeof(BanHandler), nameof(BanHandler.RemoveBan))]
+ [EventPatch(typeof(Handlers.Server), nameof(Handlers.Server.Unbanning))]
+ [EventPatch(typeof(Handlers.Server), nameof(Handlers.Server.Unbanned))]
+ internal class Unban
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ LocalBuilder ev = generator.DeclareLocal(typeof(UnbanningEventArgs));
+
+ Label continueLabel = generator.DefineLabel();
+
+ newInstructions.InsertRange(0, new CodeInstruction[]
+ {
+ // id
+ new(OpCodes.Ldarg_0),
+
+ // type
+ new(OpCodes.Ldarg_1),
+
+ // true
+ new(OpCodes.Ldc_I4_1),
+
+ // UnbanningEventArgs ev = new(string, BanHandler.BanType, true);
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(UnbanningEventArgs))[0]),
+ new(OpCodes.Dup),
+ new(OpCodes.Dup),
+ new(OpCodes.Stloc_S, ev.LocalIndex),
+
+ // Handlers.Server.OnUnbanning(ev);
+ new(OpCodes.Call, Method(typeof(Handlers.Server), nameof(Handlers.Server.OnUnbanning))),
+
+ // if (!ev.IsAllowed)
+ // return;
+ new(OpCodes.Callvirt, PropertyGetter(typeof(UnbanningEventArgs), nameof(UnbanningEventArgs.IsAllowed))),
+ new(OpCodes.Brtrue_S, continueLabel),
+
+ new(OpCodes.Ret),
+
+ // id = ev.BanDetails.ToString();
+ new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex).WithLabels(continueLabel),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(UnbanningEventArgs), nameof(UnbanningEventArgs.BanDetails))),
+ new(OpCodes.Call, Method(typeof(BanDetails), nameof(BanDetails.ToString))),
+ new(OpCodes.Starg_S, 1),
+ });
+
+ newInstructions.InsertRange(newInstructions.Count - 1, new CodeInstruction[]
+ {
+ // id
+ new(OpCodes.Ldarg_0),
+
+ // type
+ new(OpCodes.Ldarg_1),
+
+ // UnbannedEventArgs ev2 = new(string, BanHandler.BanType);
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(UnbannedEventArgs))[0]),
+
+ // Handlers.Server.OnUnbanned(ev2);
+ new(OpCodes.Call, Method(typeof(Handlers.Server), nameof(Handlers.Server.OnUnbanned))),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file
From 5aa87548bb89c3b7a34f0a047947d64fba579154 Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Tue, 27 Aug 2024 16:39:24 +0200
Subject: [PATCH 39/63] `[EXILED::API]` Adding StaminaRegenMultiplier
(BodyArmor) (#71)
* First push
* using removed
* Added to the pickup
* Forgot to add to Armor (not pickup)
* Fix Build error
* Simplification
---
EXILED/Exiled.API/Features/Items/Armor.cs | 8 ++++-
.../Features/Pickups/BodyArmorPickup.cs | 7 +++++
.../Patches/Generic/StaminaRegenArmor.cs | 30 +++++++++++++++++++
3 files changed, 44 insertions(+), 1 deletion(-)
create mode 100644 EXILED/Exiled.Events/Patches/Generic/StaminaRegenArmor.cs
diff --git a/EXILED/Exiled.API/Features/Items/Armor.cs b/EXILED/Exiled.API/Features/Items/Armor.cs
index 8f176e676..1a46bc360 100644
--- a/EXILED/Exiled.API/Features/Items/Armor.cs
+++ b/EXILED/Exiled.API/Features/Items/Armor.cs
@@ -15,7 +15,6 @@ namespace Exiled.API.Features.Items
using Exiled.API.Interfaces;
using InventorySystem.Items.Armor;
-
using PlayerRoles;
using Structs;
@@ -110,6 +109,11 @@ public float StaminaUseMultiplier
set => Base._staminaUseMultiplier = value;
}
+ ///
+ /// Gets or sets the stamina regen multiplier.
+ ///
+ public float StaminaRegenMultiplier { get; set; } = 1f;
+
///
/// Gets or sets how much the users movement speed should be affected when wearing this armor. (higher values = slower movement).
///
@@ -153,6 +157,7 @@ public IEnumerable CategoryLimits
StaminaUseMultiplier = StaminaUseMultiplier,
RemoveExcessOnDrop = RemoveExcessOnDrop,
CategoryLimits = CategoryLimits,
+ StaminaRegenMultiplier = StaminaRegenMultiplier,
AmmoLimits = AmmoLimits,
VestEfficacy = VestEfficacy,
HelmetEfficacy = HelmetEfficacy,
@@ -168,6 +173,7 @@ internal override void ReadPickupInfo(Pickup pickup)
VestEfficacy = armorPickup.VestEfficacy;
RemoveExcessOnDrop = armorPickup.RemoveExcessOnDrop;
StaminaUseMultiplier = armorPickup.StaminaUseMultiplier;
+ StaminaRegenMultiplier = armorPickup.StaminaRegenMultiplier;
AmmoLimits = armorPickup.AmmoLimits;
CategoryLimits = armorPickup.CategoryLimits;
}
diff --git a/EXILED/Exiled.API/Features/Pickups/BodyArmorPickup.cs b/EXILED/Exiled.API/Features/Pickups/BodyArmorPickup.cs
index 1d98dd7ec..e387cf182 100644
--- a/EXILED/Exiled.API/Features/Pickups/BodyArmorPickup.cs
+++ b/EXILED/Exiled.API/Features/Pickups/BodyArmorPickup.cs
@@ -98,6 +98,11 @@ public int VestEfficacy
///
public float StaminaUseMultiplier { get; set; }
+ ///
+ /// Gets or sets the stamina regen multiplier.
+ ///
+ public float StaminaRegenMultiplier { get; set; }
+
///
/// Gets how much the users movement speed should be affected when wearing this armor. (higher values = slower movement).
///
@@ -129,6 +134,7 @@ internal override void ReadItemInfo(Item item)
vestEfficacy = armoritem.VestEfficacy;
RemoveExcessOnDrop = armoritem.RemoveExcessOnDrop;
StaminaUseMultiplier = armoritem.StaminaUseMultiplier;
+ StaminaRegenMultiplier = armoritem.StaminaRegenMultiplier;
AmmoLimits = armoritem.AmmoLimits;
CategoryLimits = armoritem.CategoryLimits;
}
@@ -144,6 +150,7 @@ protected override void InitializeProperties(ItemBase itemBase)
vestEfficacy = armoritem.VestEfficacy;
RemoveExcessOnDrop = !armoritem.DontRemoveExcessOnDrop;
StaminaUseMultiplier = armoritem._staminaUseMultiplier;
+ StaminaRegenMultiplier = armoritem.StaminaRegenMultiplier;
AmmoLimits = armoritem.AmmoLimits.Select(limit => (ArmorAmmoLimit)limit);
CategoryLimits = armoritem.CategoryLimits;
}
diff --git a/EXILED/Exiled.Events/Patches/Generic/StaminaRegenArmor.cs b/EXILED/Exiled.Events/Patches/Generic/StaminaRegenArmor.cs
new file mode 100644
index 000000000..e4b83f10e
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Generic/StaminaRegenArmor.cs
@@ -0,0 +1,30 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Generic
+{
+ using Exiled.API.Features;
+ using Exiled.API.Features.Items;
+#pragma warning disable SA1313
+
+ using HarmonyLib;
+ using InventorySystem.Items.Armor;
+
+ ///
+ /// Patches .
+ /// Implements .
+ ///
+ [HarmonyPatch(typeof(BodyArmor), nameof(BodyArmor.StaminaRegenMultiplier), MethodType.Getter)]
+ internal class StaminaRegenArmor
+ {
+ private static void Postfix(BodyArmor __instance, ref float __result)
+ {
+ if(Item.Get(__instance) is Armor armor)
+ __result *= armor.StaminaRegenMultiplier;
+ }
+ }
+}
\ No newline at end of file
From af3da2d92e71d38321f5c29b0df49e63c130431f Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Tue, 27 Aug 2024 20:59:04 +0200
Subject: [PATCH 40/63] `[EXILED::API]` Adding MoveNetworkIdentityObject (#48)
* MoveNetworkObject Added
* fix builds
* Fix Builds
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
.../Exiled.API/Extensions/MirrorExtensions.cs | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
index 22d799677..114435a40 100644
--- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
+++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
@@ -356,6 +356,24 @@ public static void MessageTranslated(this Player player, string words, string tr
}
}
+ ///
+ /// Moves object for the player.
+ ///
+ /// Target to send.
+ /// The to move.
+ /// The position to change.
+ public static void MoveNetworkIdentityObject(this Player player, NetworkIdentity identity, Vector3 pos)
+ {
+ identity.gameObject.transform.position = pos;
+ ObjectDestroyMessage objectDestroyMessage = new()
+ {
+ netId = identity.netId,
+ };
+
+ player.Connection.Send(objectDestroyMessage, 0);
+ SendSpawnMessageMethodInfo?.Invoke(null, new object[] { identity, player.Connection });
+ }
+
///
/// Sends to the player a Fake Change Scene.
///
@@ -403,6 +421,26 @@ public static void ScaleNetworkIdentityObject(this Player player, NetworkIdentit
SendSpawnMessageMethodInfo?.Invoke(null, new object[] { identity, player.Connection });
}
+ ///
+ /// Moves object for all the players.
+ ///
+ /// The to move.
+ /// The position to change.
+ public static void MoveNetworkIdentityObject(this NetworkIdentity identity, Vector3 pos)
+ {
+ identity.gameObject.transform.position = pos;
+ ObjectDestroyMessage objectDestroyMessage = new()
+ {
+ netId = identity.netId,
+ };
+
+ foreach (Player ply in Player.List)
+ {
+ ply.Connection.Send(objectDestroyMessage, 0);
+ SendSpawnMessageMethodInfo?.Invoke(null, new object[] { identity, ply.Connection });
+ }
+ }
+
///
/// Scales an object for all players.
///
From 532fdfb1eb8046fb1c0c7ea48a9f56b8c488f509 Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Tue, 27 Aug 2024 20:59:57 +0200
Subject: [PATCH 41/63] `[EXILED::EVENTS]` Adding PlayingAudioLog 69 PR (#69)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Audio log event
* Mistakes
* Fix build errors
* Update EXILED/Exiled.Events/Patches/Events/Player/PlayingAudioLog.cs
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
* Update EXILED/Exiled.Events/EventArgs/Player/PlayingAudioLogEventArgs.cs
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
* Update EXILED/Exiled.Events/EventArgs/Player/PlayingAudioLogEventArgs.cs
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
* Update EXILED/Exiled.Events/EventArgs/Player/PlayingAudioLogEventArgs.cs
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
* Update EXILED/Exiled.Events/EventArgs/Player/PlayingAudioLogEventArgs.cs
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
* 🧠💭😔😞📉😭🤔➡️🧑⚕️💬💊📈😌
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
.../Player/PlayingAudioLogEventArgs.cs | 44 ++++++++++++
EXILED/Exiled.Events/Handlers/Player.cs | 11 +++
.../Patches/Events/Player/PlayingAudioLog.cs | 68 +++++++++++++++++++
3 files changed, 123 insertions(+)
create mode 100644 EXILED/Exiled.Events/EventArgs/Player/PlayingAudioLogEventArgs.cs
create mode 100644 EXILED/Exiled.Events/Patches/Events/Player/PlayingAudioLog.cs
diff --git a/EXILED/Exiled.Events/EventArgs/Player/PlayingAudioLogEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/PlayingAudioLogEventArgs.cs
new file mode 100644
index 000000000..cad328ea2
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Player/PlayingAudioLogEventArgs.cs
@@ -0,0 +1,44 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Player
+{
+ using API.Features;
+
+ using Interfaces;
+
+ ///
+ /// Contains all information before a player plays the AudioLog.
+ ///
+ public class PlayingAudioLogEventArgs : IPlayerEvent, IDeniableEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public PlayingAudioLogEventArgs(Player player, bool isAllowed = true)
+ {
+ Player = player;
+ IsAllowed = isAllowed;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether or not the audio will start.
+ ///
+ public bool IsAllowed { get; set; }
+
+ ///
+ /// Gets the player who started the AudioLog.
+ ///
+ public Player Player { get; }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs
index 016bdf644..5cf86d879 100644
--- a/EXILED/Exiled.Events/Handlers/Player.cs
+++ b/EXILED/Exiled.Events/Handlers/Player.cs
@@ -208,6 +208,11 @@ public class Player
///
public static Event DroppingNothing { get; set; } = new();
+ ///
+ /// Invoked before playing an AudioLog.
+ ///
+ public static Event PlayingAudioLog { get; set; } = new();
+
///
/// Invoked before picking up an .
///
@@ -691,6 +696,12 @@ public class Player
/// The instance.
public static void OnDroppingNothing(DroppingNothingEventArgs ev) => DroppingNothing.InvokeSafely(ev);
+ ///
+ /// Called before a plays an AudioLog.
+ ///
+ /// The instance.
+ public static void OnPlayingAudioLog(PlayingAudioLogEventArgs ev) => PlayingAudioLog.InvokeSafely(ev);
+
///
/// Called before a picks up an item.
///
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/PlayingAudioLog.cs b/EXILED/Exiled.Events/Patches/Events/Player/PlayingAudioLog.cs
new file mode 100644
index 000000000..c2b0125e1
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Events/Player/PlayingAudioLog.cs
@@ -0,0 +1,68 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled 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;
+ using API.Features.Pools;
+ using Exiled.Events.Attributes;
+ using Exiled.Events.EventArgs.Player;
+ using HarmonyLib;
+ using MapGeneration.Spawnables;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patch the .
+ /// Adds the event.
+ ///
+ [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.PlayingAudioLog))]
+ [HarmonyPatch(typeof(AudioLog), nameof(AudioLog.ServerInteract))]
+ internal static class PlayingAudioLog
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label retLabel = generator.DefineLabel();
+
+ newInstructions.InsertRange(
+ 0,
+ new CodeInstruction[]
+ {
+ // Player player = Player.Get(ReferenceHub);
+ new(OpCodes.Ldarg_1),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // true
+ new(OpCodes.Ldc_I4_1),
+
+ // PlayingAudioLogEventArgs ev = new(Player, bool)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(PlayingAudioLogEventArgs))[0]),
+ new(OpCodes.Dup),
+
+ // Handlers.Player.OnPlayingAudioLog(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnPlayingAudioLog))),
+
+ // if (!ev.IsAllowed)
+ // return;
+ new(OpCodes.Callvirt, PropertyGetter(typeof(PlayingAudioLogEventArgs), nameof(PlayingAudioLogEventArgs.IsAllowed))),
+ new(OpCodes.Brfalse, retLabel),
+ });
+
+ newInstructions[newInstructions.Count - 1].labels.Add(retLabel);
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file
From 96ecc2498d6cb23689b3ff8ee7e8d5a9c6f84d25 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Wed, 28 Aug 2024 08:23:42 +0200
Subject: [PATCH 42/63] `RecontainedWhenNoScps` feature (#16)
---
EXILED/Exiled.Events/Config.cs | 8 ++-
.../Events/Player/ActivatingWorkstation.cs | 2 +-
.../Events/Player/ChangingDangerState.cs | 2 +-
.../Patches/Events/Scp096/AddingTarget.cs | 2 +-
.../Patches/Events/Scp096/CalmingDown.cs | 2 +-
.../Patches/Events/Scp173/BlinkingRequest.cs | 2 +-
.../Patches/Events/Server/AddingUnitName.cs | 2 +-
.../Patches/Generic/ParseVisionInformation.cs | 2 +-
.../Patches/Generic/Scp079Recontain.cs | 54 +++++++++++++++++++
9 files changed, 68 insertions(+), 8 deletions(-)
create mode 100644 EXILED/Exiled.Events/Patches/Generic/Scp079Recontain.cs
diff --git a/EXILED/Exiled.Events/Config.cs b/EXILED/Exiled.Events/Config.cs
index 006be02b2..b141cd17e 100644
--- a/EXILED/Exiled.Events/Config.cs
+++ b/EXILED/Exiled.Events/Config.cs
@@ -80,6 +80,12 @@ public sealed class Config : IConfig
[Description("Indicates whether thrown keycards can affect doors that don't require any permissions")]
public bool CanKeycardThrowAffectDoors { get; set; } = false;
+ ///
+ /// Gets or sets a value indicating whether the SCP079 will recontained if there are no SCPs left.
+ ///
+ [Description("Indicates whether the SCP079 will recontained if there are no SCPs left.")]
+ public bool RecontainScp079IfNoScpsLeft { get; set; } = true;
+
///
/// Gets or sets a value indicating whether configs has to be reloaded every time a round restarts.
///
@@ -90,7 +96,7 @@ public sealed class Config : IConfig
/// Gets or sets a value indicating whether translations has to be reloaded every time a round restarts.
///
[Description("Indicates whether translations has to be reloaded every round restart")]
- public bool ShouldReloadTranslationsAtRoundRestart { get; set; }
+ public bool ShouldReloadTranslationsAtRoundRestart { get; set; } = false;
///
/// Gets a value indicating whether bans should be logged or not.
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ActivatingWorkstation.cs b/EXILED/Exiled.Events/Patches/Events/Player/ActivatingWorkstation.cs
index 4ee58f8ec..28edd3803 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/ActivatingWorkstation.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/ActivatingWorkstation.cs
@@ -78,7 +78,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Generic.Scp079API
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using API.Features.Pools;
+
+ using HarmonyLib;
+
+ using PlayerRoles.PlayableScps.Scp079;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches .
+ /// Adds the support.
+ ///
+ [HarmonyPatch(typeof(Scp079Recontainer), nameof(Scp079Recontainer.OnServerRoleChanged))]
+ internal class Scp079Recontain
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label ret = generator.DefineLabel();
+
+ newInstructions.InsertRange(
+ 0,
+ new[]
+ {
+ // if (!Events.Instance.Config.ShouldScp079RecontainedWhenNoScps)
+ // return;
+ new CodeInstruction(OpCodes.Call, PropertyGetter(typeof(Exiled.Events.Events), nameof(Exiled.Events.Events.Instance))),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(Exiled.Events.Events), nameof(Exiled.Events.Events.Config))),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(Exiled.Events.Config), nameof(Exiled.Events.Config.RecontainScp079IfNoScpsLeft))),
+ new(OpCodes.Brfalse_S, ret),
+ });
+
+ newInstructions[newInstructions.Count - 1].labels.Add(ret);
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file
From 83ff82e7825480de14c93a4dc8e27d0af673c3d6 Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Fri, 30 Aug 2024 18:14:25 +0200
Subject: [PATCH 43/63] `[EXILED::EVENTS]` Fixing bug report n.396 (#59)
* Fix
* Added the Bug report
---
.../Patches/Fixes/NWFixDetonationTimer.cs | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 EXILED/Exiled.Events/Patches/Fixes/NWFixDetonationTimer.cs
diff --git a/EXILED/Exiled.Events/Patches/Fixes/NWFixDetonationTimer.cs b/EXILED/Exiled.Events/Patches/Fixes/NWFixDetonationTimer.cs
new file mode 100644
index 000000000..fec4aa869
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Fixes/NWFixDetonationTimer.cs
@@ -0,0 +1,32 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Fixes
+{
+ using System;
+ using System.Linq;
+
+ using GameCore;
+ using HarmonyLib;
+
+ ///
+ /// Fixes the issue where the game was not selecting the scenario with the nearest value.
+ /// Bug Report
+ ///
+ [HarmonyPatch(typeof(AlphaWarheadController), nameof(AlphaWarheadController.Start))]
+ internal class NWFixDetonationTimer
+ {
+ private static void Postfix()
+ {
+ AlphaWarheadSyncInfo networkInfo = default;
+ networkInfo.ScenarioId = Array.IndexOf(AlphaWarheadController.Singleton._startScenarios, AlphaWarheadController.Singleton._startScenarios.OrderBy(d => Math.Abs(d.TimeToDetonate - ConfigFile.ServerConfig.GetInt("warhead_tminus_start_duration", 90))).First());
+
+ AlphaWarheadController.Singleton.NetworkInfo = networkInfo;
+ return;
+ }
+ }
+}
From daecbb9bb63a882a5f6cd84d2cc7d247f2c636de Mon Sep 17 00:00:00 2001
From: DrBright <125764730+alexomur@users.noreply.github.com>
Date: Fri, 30 Aug 2024 20:13:47 +0300
Subject: [PATCH 44/63] feat: Added IsDecontaminationEnabled property (#82)
---
EXILED/Exiled.API/Features/Map.cs | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs
index 2b3c4cdb0..fa8db85b0 100644
--- a/EXILED/Exiled.API/Features/Map.cs
+++ b/EXILED/Exiled.API/Features/Map.cs
@@ -106,6 +106,18 @@ public static int Seed
}
}
+ ///
+ /// Gets or sets a value indicating whether decontamination is enabled.
+ ///
+ public static bool IsDecontaminationEnabled
+ {
+ get => DecontaminationController.Singleton.NetworkDecontaminationOverride == DecontaminationController.DecontaminationStatus.None;
+ set =>
+ DecontaminationController.Singleton.NetworkDecontaminationOverride = value
+ ? DecontaminationController.DecontaminationStatus.None
+ : DecontaminationController.DecontaminationStatus.Disabled;
+ }
+
///
/// Gets the .
///
@@ -159,7 +171,7 @@ public static void ShowHint(string message, float duration = 3f)
public static void ClearBroadcasts() => Server.Broadcast.RpcClearElements();
///
- /// Starts the light containment zone decontamination process.
+ /// Forces the light containment zone decontamination process.
///
public static void StartDecontamination() => DecontaminationController.Singleton.ForceDecontamination();
From cb8fbbea924802ecb865381fc085e0af87137546 Mon Sep 17 00:00:00 2001
From: Nameless <85962933+Misfiy@users.noreply.github.com>
Date: Fri, 30 Aug 2024 20:02:42 +0200
Subject: [PATCH 45/63] Multiple change (UwU) (#79)
Add `Player::AddAmmo(Dictionary ammo)`
Add `Player::GrantLoadout()`
Add `Player::GrantLoadout(RoleTypeId)`
Add `GetEffect()`
Add `Scp3114Role::UpdateIdentity()`
Fixed `Scp3114Role::DisguiseDuration` not being sync to client
---
EXILED/Exiled.API/Features/Player.cs | 35 +++++++++++++++++++
.../Exiled.API/Features/Roles/Scp3114Role.cs | 21 +++++++----
EXILED/Exiled.CustomItems/CustomItems.cs | 8 ++---
.../Events/{RoundHandler.cs => MapHandler.cs} | 10 +++---
.../Player/KillingPlayerEventArgs.cs | 4 ++-
EXILED/Exiled.Events/Handlers/Player.cs | 5 ++-
.../Exiled.Events/Patches/Fixes/KillPlayer.cs | 2 ++
7 files changed, 69 insertions(+), 16 deletions(-)
rename EXILED/Exiled.CustomItems/Events/{RoundHandler.cs => MapHandler.cs} (72%)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index b7a4afee5..24ec22c7c 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -2335,6 +2335,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 to player's inventory.
+ ///
+ /// A dictionary of ItemType and ushort of ammo and amount.
+ public void AddAmmo(Dictionary ammo)
+ {
+ foreach (KeyValuePair kvp in ammo)
+ AddAmmo(kvp.Key.GetAmmoType(), kvp.Value);
+ }
+
///
/// Adds the amount of a specified ammo type to player's inventory.
///
@@ -2578,6 +2588,23 @@ public void ResetCategoryLimit(ItemCategory category)
/// If the player has a custom limit for the specific .
public bool HasCustomCategoryLimit(ItemCategory category) => CustomCategoryLimits.ContainsKey(category);
+ ///
+ /// Grants the player their current role's loadout.
+ ///
+ public void GrantLoadout() => GrantLoadout(Role.Type);
+
+ ///
+ /// Grants a player a role's loadout.
+ ///
+ /// The role loadout to give.
+ public void GrantLoadout(RoleTypeId roleType)
+ {
+ InventoryRoleInfo info = roleType.GetInventory();
+
+ AddItem(info.Items);
+ AddAmmo(info.Ammo);
+ }
+
///
/// Adds an item of the specified type with default durability(ammo/charge) and no mods to the player's inventory.
///
@@ -3305,6 +3332,14 @@ public void SyncEffects(IEnumerable effects)
SyncEffect(effect);
}
+ ///
+ /// Gets an effect of a player.
+ ///
+ /// The to get.
+ /// The found.
+ public T GetEffect()
+ where T : StatusEffectBase => ReferenceHub.playerEffectsController.GetEffect();
+
///
/// Gets an instance of by .
///
diff --git a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs
index 0d23e48ba..b8867839a 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs
@@ -153,7 +153,7 @@ public RoleTypeId StolenRole
return;
Ragdoll.Role = value;
- Identity.ServerResendIdentity();
+ UpdateIdentity();
}
}
@@ -166,7 +166,7 @@ public Ragdoll Ragdoll
set
{
Identity.CurIdentity.Ragdoll = value?.Base;
- Identity.ServerResendIdentity();
+ UpdateIdentity();
}
}
@@ -179,7 +179,7 @@ public byte UnitId
set
{
Identity.CurIdentity.UnitNameId = value;
- Identity.ServerResendIdentity();
+ UpdateIdentity();
}
}
@@ -192,7 +192,7 @@ public DisguiseStatus DisguiseStatus
set
{
Identity.CurIdentity.Status = value;
- Identity.ServerResendIdentity();
+ UpdateIdentity();
}
}
@@ -202,7 +202,11 @@ public DisguiseStatus DisguiseStatus
public float DisguiseDuration
{
get => Identity._disguiseDurationSeconds;
- set => Identity._disguiseDurationSeconds = value;
+ set
+ {
+ Identity._disguiseDurationSeconds = value;
+ UpdateIdentity();
+ }
}
///
@@ -219,13 +223,18 @@ public float WarningTime
///
internal DanceType DanceType { get; set; }
+ ///
+ /// Updates the identity of SCP-3114.
+ ///
+ public void UpdateIdentity() => Identity.ServerResendIdentity();
+
///
/// Reset Scp3114 FakeIdentity.
///
public void ResetIdentity()
{
Identity.CurIdentity.Reset();
- Identity.ServerResendIdentity();
+ UpdateIdentity();
}
///
diff --git a/EXILED/Exiled.CustomItems/CustomItems.cs b/EXILED/Exiled.CustomItems/CustomItems.cs
index 8a8e15b36..e11a0df2c 100644
--- a/EXILED/Exiled.CustomItems/CustomItems.cs
+++ b/EXILED/Exiled.CustomItems/CustomItems.cs
@@ -19,7 +19,7 @@ namespace Exiled.CustomItems
///
public class CustomItems : Plugin
{
- private RoundHandler? roundHandler;
+ private MapHandler? mapHandler;
private PlayerHandler? playerHandler;
private Harmony? harmony;
@@ -32,10 +32,10 @@ public class CustomItems : Plugin
public override void OnEnabled()
{
Instance = this;
- roundHandler = new RoundHandler();
+ mapHandler = new MapHandler();
playerHandler = new PlayerHandler();
- Exiled.Events.Handlers.Server.RoundStarted += roundHandler.OnRoundStarted;
+ Exiled.Events.Handlers.Map.Generated += mapHandler.OnMapGenerated;
Exiled.Events.Handlers.Player.ChangingItem += playerHandler.OnChangingItem;
@@ -50,7 +50,7 @@ public override void OnEnabled()
///
public override void OnDisabled()
{
- Exiled.Events.Handlers.Server.RoundStarted -= roundHandler!.OnRoundStarted;
+ Exiled.Events.Handlers.Map.Generated -= mapHandler!.OnMapGenerated;
Exiled.Events.Handlers.Player.ChangingItem -= playerHandler!.OnChangingItem;
diff --git a/EXILED/Exiled.CustomItems/Events/RoundHandler.cs b/EXILED/Exiled.CustomItems/Events/MapHandler.cs
similarity index 72%
rename from EXILED/Exiled.CustomItems/Events/RoundHandler.cs
rename to EXILED/Exiled.CustomItems/Events/MapHandler.cs
index ebc8c4648..678d0c404 100644
--- a/EXILED/Exiled.CustomItems/Events/RoundHandler.cs
+++ b/EXILED/Exiled.CustomItems/Events/MapHandler.cs
@@ -1,5 +1,5 @@
// -----------------------------------------------------------------------
-//
+//
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
//
@@ -12,10 +12,12 @@ namespace Exiled.CustomItems.Events
///
/// Event Handlers for the CustomItem API.
///
- internal sealed class RoundHandler
+ internal sealed class MapHandler
{
- ///
- public void OnRoundStarted()
+ ///
+ /// Handle spawning Custom Items.
+ ///
+ public void OnMapGenerated()
{
foreach (CustomItem customItem in CustomItem.Registered)
customItem?.SpawnAll();
diff --git a/EXILED/Exiled.Events/EventArgs/Player/KillingPlayerEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/KillingPlayerEventArgs.cs
index 865542742..44aba0c4e 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/KillingPlayerEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/KillingPlayerEventArgs.cs
@@ -7,13 +7,15 @@
namespace Exiled.Events.EventArgs.Player
{
- using Interfaces;
+ using System;
+ using Interfaces;
using PlayerStatsSystem;
///
/// Contains all information before player data to kill player is sent.
///
+ [Obsolete]
public class KillingPlayerEventArgs : IPlayerEvent
{
///
diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs
index 5cf86d879..2e6209741 100644
--- a/EXILED/Exiled.Events/Handlers/Player.cs
+++ b/EXILED/Exiled.Events/Handlers/Player.cs
@@ -7,7 +7,8 @@
namespace Exiled.Events.Handlers
{
- using Exiled.API.Features.Pickups;
+ using System;
+
#pragma warning disable IDE0079
#pragma warning disable IDE0060
#pragma warning disable SA1623 // Property summary documentation should match accessors
@@ -516,6 +517,7 @@ public class Player
///
/// Invoked before KillPlayer is called.
///
+ [Obsolete("Use DyingEventArgs")]
public static Event KillingPlayer { get; set; } = new();
///
@@ -976,6 +978,7 @@ public class Player
/// Called before KillPlayer is called.
///
/// The event handler.
+ [Obsolete("Use DyingEventArgs")]
public static void OnKillPlayer(KillingPlayerEventArgs ev) => KillingPlayer.InvokeSafely(ev);
///
diff --git a/EXILED/Exiled.Events/Patches/Fixes/KillPlayer.cs b/EXILED/Exiled.Events/Patches/Fixes/KillPlayer.cs
index cded0dee0..db9f45551 100644
--- a/EXILED/Exiled.Events/Patches/Fixes/KillPlayer.cs
+++ b/EXILED/Exiled.Events/Patches/Fixes/KillPlayer.cs
@@ -8,6 +8,8 @@
namespace Exiled.Events.Patches.Fixes
{
#pragma warning disable SA1313 // Parameter names should begin with lower-case letter
+#pragma warning disable CS0612 // Type or member is obsolete
+#pragma warning disable CS0618 // Type or member is obsolete
using API.Features;
using API.Features.DamageHandlers;
From 6f5cd2fd34f3e58742d0460c22cacf303d033b7b Mon Sep 17 00:00:00 2001
From: SrLicht
Date: Sun, 1 Sep 2024 08:08:57 -0300
Subject: [PATCH 46/63] ``[Exiled::CustomRoles]`` ``[Exiled::CustomItems]`` QoL
in List commands. (#78)
* Ye
* I dont need to use ``ci list registered`` only ``ci list``
* You now that ``customroles list abilities`` exist ? no ? yeah its because never say it the command
* Its the same for me
* Pi pi po po
* Im silly @louis1706 uwu
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
EXILED/Exiled.CustomItems/Commands/List/List.cs | 9 ++++++++-
EXILED/Exiled.CustomRoles/Commands/List/List.cs | 9 ++++++++-
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.CustomItems/Commands/List/List.cs b/EXILED/Exiled.CustomItems/Commands/List/List.cs
index 9ee1bcf62..98f3e2d12 100644
--- a/EXILED/Exiled.CustomItems/Commands/List/List.cs
+++ b/EXILED/Exiled.CustomItems/Commands/List/List.cs
@@ -45,7 +45,14 @@ public override void LoadGeneratedCommands()
///
protected override bool ExecuteParent(ArraySegment arguments, ICommandSender sender, out string response)
{
- response = $"Invalid subcommand! Available: registered, insideinventories";
+ if (arguments.IsEmpty() && TryGetCommand(Registered.Instance.Command, out ICommand command))
+ {
+ command.Execute(arguments, sender, out response);
+ response += $"\nTo view custom items in players' inventories, use the command: {string.Join(" ", arguments.Array)} insideinventories";
+ return true;
+ }
+
+ response = "Invalid subcommand! Available: registered, insideinventories";
return false;
}
}
diff --git a/EXILED/Exiled.CustomRoles/Commands/List/List.cs b/EXILED/Exiled.CustomRoles/Commands/List/List.cs
index 919105a32..661cecb49 100644
--- a/EXILED/Exiled.CustomRoles/Commands/List/List.cs
+++ b/EXILED/Exiled.CustomRoles/Commands/List/List.cs
@@ -45,7 +45,14 @@ public override void LoadGeneratedCommands()
///
protected override bool ExecuteParent(ArraySegment arguments, ICommandSender sender, out string response)
{
- response = "Invalid subcommand! Available: registered.";
+ if (arguments.IsEmpty() && TryGetCommand(Registered.Instance.Command, out ICommand command))
+ {
+ command.Execute(arguments, sender, out response);
+ response += $"\nTo view all abilities registered use command: {string.Join(" ", arguments.Array)} abilities";
+ return true;
+ }
+
+ response = "Invalid subcommand! Available: registered, abilities";
return false;
}
}
From d08b002d09c00d40b0dcc8176a8b821a98324e8a Mon Sep 17 00:00:00 2001
From: X <24619207+Undid-Iridium@users.noreply.github.com>
Date: Mon, 2 Sep 2024 13:17:15 -0400
Subject: [PATCH 47/63] DroppingScp330 Event Fix. (#83)
* Probably fixes it.
* Sigh stylecop
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
.../Patches/Events/Scp330/DroppingCandy.cs | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp330/DroppingCandy.cs b/EXILED/Exiled.Events/Patches/Events/Scp330/DroppingCandy.cs
index a4bd131a9..d18bceb08 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp330/DroppingCandy.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp330/DroppingCandy.cs
@@ -57,11 +57,14 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable instruction.StoresField(Field(typeof(ItemPickupBase), nameof(ItemPickupBase.PreviousOwner)))) + jumpOverOffset;
- // Remove TryRemove candy logic since we did it earlier from current location
- newInstructions.RemoveRange(jumpOverIndex, 6);
-
int candyKindIdIndex = 4;
newInstructions.InsertRange(
jumpOverIndex,
new[]
{
- // candyKindID = ev.Candy
+ // candyKindID = ev.Candy, save locally.
new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(DroppingScp330EventArgs), nameof(DroppingScp330EventArgs.Candy))),
new(OpCodes.Stloc, candyKindIdIndex),
-
- // candyKindID
- new(OpCodes.Ldloc, candyKindIdIndex),
});
newInstructions[newInstructions.Count - 1].labels.Add(returnLabel);
From 96ccf323a77ef563b5693524a95d3026d9e313aa Mon Sep 17 00:00:00 2001
From: SrLicht
Date: Mon, 2 Sep 2024 15:06:37 -0300
Subject: [PATCH 48/63] ``[Exiled::CustomItems]`` ``[Exiled::API]``
``[Exiled::CustomRoles]`` Adding news Spawnpoints, Wrapper for Locker and
added LockerType (#77)
* QoL
* Added ``RoomSpawnPoint`` for spawning things in a room with a offset property.
* Now Items will be spawned in the MapGenerated event instead of RoundStart avoiding the micro-log for spawning to many pickups in one frame.
* YES YAMATO I USE NULLEABLE
* Shut
* Done
* Created a Wrapper for Locker
* Created LockerSpawnPoint
* I NEED HELP FOR IMPLEMENTING SUPPLYLOCKER I DONT FUCKING KNOW HOW MAKE A TRANSPILER
* I hate you Yamato :D
* Boop
* Why Exiled use MONO.POSIX
* And dont use the nuget for it :skull:
* Now it will compile in the page
* Removing Else if (spawnPoint is RoleSpawnPoint roleSpawnPoint) since its not necessary spawnpoint.Position does the same.
* Supressing CS0618 due the obsolet in SpawnLocationType.InsideLocker.
* Note: SpawnLocationType.InsideLocker its only used in CustomItem.SpawnAll() so it will be fine to deleted this in futures releases.
* Fixing compile action due the warnings
* Adding support for Offset
Almost forget about this :P
* Sorry
I cant resist adding more things
* Adding support for CustomRoles
* Implementing SupplyLocker
* I literally copy the generator transpiler
* Its works i test it.
* Give me my exiled contributor role.
* LockerType enum
* Code part of the code has been taken from MER (https://github.com/Michal78900/MapEditorReborn/blob/dev/MapEditorReborn/API/Extensions/LockerExtensions.cs) - Credits to Michal, i ask him i can use it, not answer yet but if the say no i will use another way.
* SupplyLocker now have a LockerType Property to know what type of Locker is
* LockerSpawnPoint can now chose what locker want to use
* Mimimi warnings
* Re-implementing Locker API
* Re-implementing locker api of https://github.com/Exiled-Team/EXILED/pull/2026
* Update EXILED/Exiled.API/Enums/LockerType.cs
Co-authored-by: Nameless <85962933+Misfiy@users.noreply.github.com>
* I dont like the name of ExiledLockers but
* Resolving https://github.com/ExMod-Team/EXILED/pull/77#discussion_r1734360930
* Resolving https://github.com/ExMod-Team/EXILED/pull/77#discussion_r1734360419
* Cleaning Chambers List.
* Fixing CustomWeapon
* Fixing a Bug with custom items with spawning in old SpawnLocationType.InsideLocker
* Update Map.cs
Removing blank line.
* MORE
* Added GetRandomSpawnPoint() in Chamber
* Added AddItemToSpawn((ItemType itemType, int quantity = 1, bool spawnIfIsOpen = false)) in Chamber
* Added IsOpen in chamber.
* Fixing obsolet use
* Sorry @VALERA771
* Resolve https://github.com/ExMod-Team/EXILED/pull/77#pullrequestreview-2267004377
* Update Exiled.Loader.csproj
* Resolving https://github.com/ExMod-Team/EXILED/pull/77#discussion_r1734047353
* Update MapHandler.cs
Reduce the delay on spawning items, its not necessary to be to long
* Ups
Ups
---------
Co-authored-by: Nameless <85962933+Misfiy@users.noreply.github.com>
---
EXILED/Exiled.API/Enums/LockerType.cs | 50 ++++
EXILED/Exiled.API/Enums/SpawnLocationType.cs | 4 +-
.../Exiled.API/Extensions/LockerExtensions.cs | 43 ++++
EXILED/Exiled.API/Features/Lockers/Chamber.cs | 224 +++++++++++++++++
EXILED/Exiled.API/Features/Lockers/Locker.cs | 230 ++++++++++++++++++
EXILED/Exiled.API/Features/Map.cs | 26 +-
EXILED/Exiled.API/Features/Player.cs | 4 +-
.../Features/Spawn/LockerSpawnPoint.cs | 72 ++++++
.../Features/Spawn/RoomSpawnPoint.cs | 56 +++++
.../Features/Spawn/SpawnProperties.cs | 12 +-
.../API/Features/CustomItem.cs | 26 +-
EXILED/Exiled.CustomItems/Commands/Info.cs | 11 +-
EXILED/Exiled.CustomItems/CustomItems.cs | 8 +-
.../Exiled.CustomItems/Events/MapHandler.cs | 12 +-
.../API/Features/CustomRole.cs | 10 +
.../Handlers/Internal/MapGenerated.cs | 3 +-
.../Patches/Generic/LockerList.cs | 12 +-
17 files changed, 761 insertions(+), 42 deletions(-)
create mode 100644 EXILED/Exiled.API/Enums/LockerType.cs
create mode 100644 EXILED/Exiled.API/Extensions/LockerExtensions.cs
create mode 100644 EXILED/Exiled.API/Features/Lockers/Chamber.cs
create mode 100644 EXILED/Exiled.API/Features/Lockers/Locker.cs
create mode 100644 EXILED/Exiled.API/Features/Spawn/LockerSpawnPoint.cs
create mode 100644 EXILED/Exiled.API/Features/Spawn/RoomSpawnPoint.cs
diff --git a/EXILED/Exiled.API/Enums/LockerType.cs b/EXILED/Exiled.API/Enums/LockerType.cs
new file mode 100644
index 000000000..c44037a3a
--- /dev/null
+++ b/EXILED/Exiled.API/Enums/LockerType.cs
@@ -0,0 +1,50 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.API.Enums
+{
+ ///
+ /// Unique identifier for different types of s.
+ ///
+ public enum LockerType
+ {
+ ///
+ /// The pedestal used by SCP items.
+ ///
+ Pedestal,
+
+ ///
+ /// Large weapon locker.
+ ///
+ LargeGun,
+
+ ///
+ /// Locker for rifles, known as a rifle rack.
+ ///
+ RifleRack,
+
+ ///
+ /// Miscellaneous locker for various items.
+ ///
+ Misc,
+
+ ///
+ /// Locker that contains medkits.
+ ///
+ Medkit,
+
+ ///
+ /// Locker that contains adrenaline.
+ ///
+ Adrenaline,
+
+ ///
+ /// Unknow type of locker.
+ ///
+ Unknow,
+ }
+}
diff --git a/EXILED/Exiled.API/Enums/SpawnLocationType.cs b/EXILED/Exiled.API/Enums/SpawnLocationType.cs
index 852e07f43..63568ba3b 100644
--- a/EXILED/Exiled.API/Enums/SpawnLocationType.cs
+++ b/EXILED/Exiled.API/Enums/SpawnLocationType.cs
@@ -4,9 +4,10 @@
// Licensed under the CC BY-SA 3.0 license.
//
// -----------------------------------------------------------------------
-
namespace Exiled.API.Enums
{
+ using System;
+
///
/// All of the valid spawn location types.
///
@@ -150,6 +151,7 @@ public enum SpawnLocationType
///
/// Inside a random locker on the map.
///
+ [Obsolete("Use LockerSpawnPoint instead")]
InsideLocker,
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Extensions/LockerExtensions.cs b/EXILED/Exiled.API/Extensions/LockerExtensions.cs
new file mode 100644
index 000000000..7304cbd4e
--- /dev/null
+++ b/EXILED/Exiled.API/Extensions/LockerExtensions.cs
@@ -0,0 +1,43 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.API.Extensions
+{
+ using System;
+
+ using Exiled.API.Enums;
+ using MapGeneration.Distributors;
+
+ ///
+ /// A set of extensions for .
+ ///
+ public static class LockerExtensions
+ {
+ ///
+ /// Gets the from the given object.
+ ///
+ /// The to check.
+ /// The corresponding .
+ public static LockerType GetLockerType(this Locker locker) => locker.name.GetLockerTypeByName();
+
+ ///
+ /// Gets the by name.
+ ///
+ /// The name to check.
+ /// The corresponding .
+ public static LockerType GetLockerTypeByName(this string name) => name.Replace("(Clone)", string.Empty) switch
+ {
+ "Scp500PedestalStructure Variant" => LockerType.Pedestal,
+ "LargeGunLockerStructure" => LockerType.LargeGun,
+ "RifleRackStructure" => LockerType.RifleRack,
+ "MiscLocker" => LockerType.Misc,
+ "RegularMedkitStructure" => LockerType.Medkit,
+ "AdrenalineMedkitStructure" => LockerType.Adrenaline,
+ _ => LockerType.Unknow,
+ };
+ }
+}
diff --git a/EXILED/Exiled.API/Features/Lockers/Chamber.cs b/EXILED/Exiled.API/Features/Lockers/Chamber.cs
new file mode 100644
index 000000000..25f9385b8
--- /dev/null
+++ b/EXILED/Exiled.API/Features/Lockers/Chamber.cs
@@ -0,0 +1,224 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+namespace Exiled.API.Features.Lockers
+{
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Linq;
+
+ using Exiled.API.Enums;
+ using Exiled.API.Extensions;
+ using Exiled.API.Features.Pickups;
+ using Exiled.API.Interfaces;
+ using MapGeneration.Distributors;
+ using UnityEngine;
+
+ ///
+ /// A wrapper for .
+ ///
+ public class Chamber : IWrapper, IWorldSpace
+ {
+ ///
+ /// with and .
+ ///
+ internal static readonly Dictionary Chambers = new();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// instance.
+ /// where this chamber is located.
+ public Chamber(LockerChamber chamber, Locker locker)
+ {
+ Base = chamber;
+ Locker = locker;
+
+ Chambers.Add(chamber, this);
+ }
+
+ ///
+ /// Gets a of which contains all the instances.
+ ///
+ public static IReadOnlyCollection List => Chambers.Values;
+
+ ///
+ public LockerChamber Base { get; }
+
+ ///
+ /// Gets the where this chamber is located at.
+ ///
+ public Locker Locker { get; }
+
+ ///
+ public Vector3 Position => Base.transform.position;
+
+ ///
+ public Quaternion Rotation => Base.transform.rotation;
+
+ ///
+ /// Gets or sets all pickups that should be spawned when the door is initially opened.
+ ///
+ public IEnumerable ToBeSpawned
+ {
+ get => Base._toBeSpawned.Select(Pickup.Get);
+ set
+ {
+ Base._toBeSpawned.Clear();
+
+ foreach (Pickup pickup in value)
+ Base._toBeSpawned.Add(pickup.Base);
+ }
+ }
+
+ ///
+ /// Gets or sets all spawn points.
+ ///
+ ///
+ /// Used if is set to .
+ ///
+ public IEnumerable Spawnpoints
+ {
+ get => Base._spawnpoints;
+ set => Base._spawnpoints = value.ToArray();
+ }
+
+ ///
+ /// Gets or sets all the acceptable items which can be spawned in this chamber.
+ ///
+ public IEnumerable AcceptableTypes
+ {
+ get => Base.AcceptableItems;
+ set => Base.AcceptableItems = value.ToArray();
+ }
+
+ ///
+ /// Gets or sets required permissions to open this chamber.
+ ///
+ public KeycardPermissions RequiredPermissions
+ {
+ get => (KeycardPermissions)Base.RequiredPermissions;
+ set => Base.RequiredPermissions = (Interactables.Interobjects.DoorUtils.KeycardPermissions)value;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether multiple spawn points should be used.
+ ///
+ ///
+ /// If , will be used over .
+ ///
+ public bool UseMultipleSpawnpoints
+ {
+ get => Base._useMultipleSpawnpoints;
+ set => Base._useMultipleSpawnpoints = value;
+ }
+
+ ///
+ /// Gets or sets a spawn point for the items in the chamber.
+ ///
+ ///
+ /// Used if is set to .
+ ///
+ public Transform Spawnpoint
+ {
+ get => Base._spawnpoint;
+ set => Base._spawnpoint = value;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether or not items should be spawned as soon as they one chamber is opened.
+ ///
+ public bool InitiallySpawn
+ {
+ get => Base._spawnOnFirstChamberOpening;
+ set => Base._spawnOnFirstChamberOpening = value;
+ }
+
+ ///
+ /// Gets or sets the amount of time before a player can interact with the chamber again.
+ ///
+ public float Cooldown
+ {
+ get => Base._targetCooldown;
+ set => Base._targetCooldown = value;
+ }
+
+ ///
+ /// Gets a value indicating whether the chamber is currently open.
+ ///
+ public bool IsOpen => Base.IsOpen;
+
+ ///
+ /// Gets the of current cooldown.
+ ///
+ /// Used in check.
+ public Stopwatch CurrentCooldown => Base._stopwatch;
+
+ ///
+ /// Gets a value indicating whether the chamber is interactable.
+ ///
+ public bool CanInteract => Base.CanInteract;
+
+ ///
+ /// Spawns a specified item from .
+ ///
+ /// from .
+ /// Amount of items that should be spawned.
+ public void SpawnItem(ItemType type, int amount) => Base.SpawnItem(type, amount);
+
+ ///
+ /// Adds an item of the specified type to the chamber's spawn list.
+ /// If the chamber is open and is set to ,
+ /// the item is spawned immediately at a random spawn point within the chamber.
+ ///
+ /// The type of item to add to the spawn list.
+ /// The number of items to add. Defaults to 1.
+ ///
+ /// If and the chamber is open, the item is immediately spawned at a random spawn point.
+ /// Otherwise, the item is added to the spawn list and will spawn when the chamber is opened.
+ ///
+ public void AddItemToSpawn(ItemType itemType, int quantity = 1, bool spawnIfIsOpen = false)
+ {
+ for (int i = 0; i < quantity; i++)
+ {
+ Pickup pickup = Pickup.Create(itemType);
+
+ if (spawnIfIsOpen && IsOpen)
+ {
+ pickup.Position = GetRandomSpawnPoint();
+ pickup.Spawn();
+ continue;
+ }
+
+ Base._toBeSpawned.Add(pickup.Base);
+ }
+ }
+
+ ///
+ /// Gets a random spawn point within the chamber.
+ /// If multiple spawn points are available and is ,
+ /// a random spawn point is selected from the available points.
+ /// Otherwise, the default spawn point is used.
+ ///
+ /// A representing the position of the selected spawn point.
+ public Vector3 GetRandomSpawnPoint()
+ {
+ if (UseMultipleSpawnpoints && Spawnpoints.Any())
+ {
+ return Spawnpoints.GetRandomValue().position;
+ }
+
+ return Spawnpoint.position;
+ }
+
+ ///
+ /// Gets the chamber by its .
+ ///
+ /// .
+ /// .
+ 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());
+ }
+}
diff --git a/EXILED/Exiled.API/Features/Lockers/Locker.cs b/EXILED/Exiled.API/Features/Lockers/Locker.cs
new file mode 100644
index 000000000..73108359b
--- /dev/null
+++ b/EXILED/Exiled.API/Features/Lockers/Locker.cs
@@ -0,0 +1,230 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+namespace Exiled.API.Features.Lockers
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ using Exiled.API.Enums;
+ using Exiled.API.Extensions;
+ using Exiled.API.Features;
+ using Exiled.API.Features.Pickups;
+ using Exiled.API.Interfaces;
+
+ using InventorySystem.Items.Pickups;
+ using MapGeneration.Distributors;
+
+ using Mirror;
+ using UnityEngine;
+
+ using BaseLocker = MapGeneration.Distributors.Locker;
+#nullable enable
+ ///
+ /// The in-game Locker.
+ ///
+ public class Locker : IWrapper, IWorldSpace
+ {
+ ///
+ /// A containing all known s and their corresponding .
+ ///
+ internal static readonly Dictionary BaseToExiledLockers = new();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The encapsulated .
+ public Locker(BaseLocker locker)
+ {
+ Base = locker;
+ BaseToExiledLockers.Add(locker, this);
+
+ Chambers = locker.Chambers.Select(x => new Chamber(x, this)).ToList();
+ Type = locker.GetLockerType();
+ }
+
+ ///
+ /// Gets a of which contains all the instances.
+ ///
+ public static IReadOnlyCollection List => BaseToExiledLockers.Values;
+
+ ///
+ public BaseLocker Base { get; }
+
+ ///
+ /// Gets the of the .
+ ///
+ public LockerType Type { get; }
+
+ ///
+ /// Gets the .
+ ///
+ public Transform Transform => Base.transform;
+
+ ///
+ public Vector3 Position => Base.transform.position;
+
+ ///
+ public Quaternion Rotation => Base.transform.rotation;
+
+ ///
+ /// Gets the in which the is located.
+ ///
+ public Room? Room => Room.Get(Position);
+
+ ///
+ /// Gets the in which the locker is located.
+ ///
+ public ZoneType Zone => Room?.Zone ?? ZoneType.Unspecified;
+
+ ///
+ /// Gets the all in this locker.
+ ///
+ public IReadOnlyCollection Chambers { get; }
+
+ ///
+ /// Gets or sets an id for manipulating opened chambers.
+ ///
+ public ushort OpenedChambers
+ {
+ get => Base.OpenedChambers;
+ set => Base.NetworkOpenedChambers = value;
+ }
+
+ ///
+ /// Gets a random position from one of the .
+ ///
+ public Vector3 RandomChamberPosition
+ {
+ get
+ {
+ Chamber randomChamber = Chambers.GetRandomValue();
+
+ // Determine if the chamber uses multiple spawn points and has at least one available spawn point.
+ if (randomChamber.UseMultipleSpawnpoints && randomChamber.Spawnpoints.Count() > 0)
+ {
+ // Return the position of a random spawn point within the chamber.
+ return randomChamber.Spawnpoints.GetRandomValue().position;
+ }
+
+ // Return the position of the main spawn point for the chamber.
+ return randomChamber.Spawnpoint.position;
+ }
+ }
+
+ ///
+ /// Gets the belonging to the , if any.
+ ///
+ /// The to get.
+ /// A or if not found.
+ public static Locker? Get(BaseLocker locker) => locker == null ? null :
+ BaseToExiledLockers.TryGetValue(locker, out Locker supply) ? supply : new Locker(locker);
+
+ ///
+ /// Gets a of given the specified .
+ ///
+ /// The to search for.
+ /// The with the given or if not found.
+ public static IEnumerable Get(ZoneType zoneType) => Get(room => room.Zone.HasFlag(zoneType));
+
+ ///
+ /// Gets a of filtered based on a predicate.
+ ///
+ /// The condition to satify.
+ /// A of which contains elements that satify the condition.
+ public static IEnumerable Get(Func predicate) => List.Where(predicate);
+
+ ///
+ /// Gets a random based on the specified filters.
+ ///
+ /// The to filter by. If unspecified, all zones are considered.
+ /// The to filter by. If unspecified, all locker types are considered.
+ /// A random object, or if no matching locker is found.
+ public static Locker? Random(ZoneType zone = ZoneType.Unspecified, LockerType lockerType = LockerType.Unknow)
+ {
+ IEnumerable filteredLockers = List;
+
+ if (lockerType != LockerType.Unknow)
+ filteredLockers = filteredLockers.Where(l => l.Type == lockerType);
+
+ if (zone != ZoneType.Unspecified)
+ filteredLockers = filteredLockers.Where(l => l.Zone == zone);
+
+ return filteredLockers.GetRandomValue();
+ }
+
+ ///
+ /// Adds an item to a randomly selected locker chamber.
+ ///
+ /// The to be added to the locker chamber.
+ public void AddItem(Pickup item)
+ {
+ // Select a random chamber from the available locker chambers.
+ Chamber chamber = Chambers.GetRandomValue();
+
+ // Determine the parent transform where the item will be placed.
+ Transform parentTransform = chamber.UseMultipleSpawnpoints && chamber.Spawnpoints.Count() > 0
+ ? chamber.Spawnpoints.GetRandomValue()
+ : chamber.Spawnpoint;
+
+ // If the chamber is open, immediately set the item's parent and spawn it.
+ if (chamber.Base.IsOpen)
+ {
+ item.Transform.SetParent(parentTransform);
+ item.Spawn();
+ }
+ else
+ {
+ // If the item is already spawned on the network, unspawn it before proceeding.
+ if (NetworkServer.spawned.ContainsKey(item.Base.netId))
+ NetworkServer.UnSpawn(item.GameObject);
+
+ // Set the item's parent transform.
+ item.Transform.SetParent(parentTransform);
+
+ // Lock the item in place.
+ item.IsLocked = true;
+
+ // Notify any pickup distributor triggers.
+ (item.Base as IPickupDistributorTrigger)?.OnDistributed();
+
+ // If the item has a Rigidbody component, make it kinematic and reset its position and rotation.
+ if (item.Rigidbody != null)
+ {
+ item.Rigidbody.isKinematic = true;
+ item.Rigidbody.transform.localPosition = Vector3.zero;
+ item.Rigidbody.transform.localRotation = Quaternion.identity;
+
+ // Add the Rigidbody to the list of bodies to be unfrozen later.
+ SpawnablesDistributorBase.BodiesToUnfreeze.Add(item.Rigidbody);
+ }
+
+ // If the chamber is configured to spawn items on the first opening, add the item to the list of items to be spawned.
+ // Otherwise, spawn the item immediately.
+ if (chamber.InitiallySpawn)
+ chamber.Base._toBeSpawned.Add(item.Base);
+ else
+ ItemDistributor.SpawnPickup(item.Base);
+ }
+ }
+
+ ///
+ /// Spawns an item of the specified to the locker by creating a new .
+ ///
+ /// The type of item to be added.
+ public void AddItem(ItemType type) => AddItem(Pickup.Create(type));
+
+ ///
+ /// Clears the cached lockers in the dictionary.
+ ///
+ internal static void ClearCache()
+ {
+ BaseToExiledLockers.Clear();
+ Chamber.Chambers.Clear();
+ }
+ }
+}
diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs
index fa8db85b0..9df9bbd37 100644
--- a/EXILED/Exiled.API/Features/Map.cs
+++ b/EXILED/Exiled.API/Features/Map.cs
@@ -16,6 +16,7 @@ namespace Exiled.API.Features
using Enums;
using Exiled.API.Extensions;
using Exiled.API.Features.Hazards;
+ using Exiled.API.Features.Lockers;
using Exiled.API.Features.Pickups;
using Exiled.API.Features.Toys;
using global::Hazards;
@@ -42,11 +43,6 @@ namespace Exiled.API.Features
///
public static class Map
{
- ///
- /// A list of s on the map.
- ///
- internal static readonly List LockersValue = new(35);
-
///
/// A list of s on the map.
///
@@ -84,9 +80,13 @@ DecontaminationController.Singleton.NetworkDecontaminationOverride is Decontamin
public static ReadOnlyCollection PocketDimensionTeleports { get; } = TeleportsValue.AsReadOnly();
///
- /// Gets all objects.
+ /// Gets all objects in the current map.
///
- public static ReadOnlyCollection Lockers { get; } = LockersValue.AsReadOnly();
+ ///
+ /// This property is obsolete. Use instead to retrieve a collection of all instances.
+ ///
+ [Obsolete("Use Locker.List instead.")]
+ public static ReadOnlyCollection Lockers { get; } = Features.Lockers.Locker.BaseToExiledLockers.Keys.ToList().AsReadOnly();
///
/// Gets all objects.
@@ -224,10 +224,14 @@ public static void ResetLightsColor()
}
///
- /// Gets a random .
+ /// Gets a random object from the current map.
///
- /// object.
- public static Locker GetRandomLocker() => Lockers.GetRandomValue();
+ ///
+ /// This method is obsolete. Use instead to get a random instance.
+ ///
+ /// A randomly selected object.
+ [Obsolete("Use Locker.Random() instead.")]
+ public static MapGeneration.Distributors.Locker GetRandomLocker() => Lockers.GetRandomValue();
///
/// Gets a random .
@@ -401,8 +405,6 @@ internal static void ClearCache()
{
Item.BaseToItem.Clear();
- LockersValue.RemoveAll(locker => locker == null);
-
Ragdoll.BasicRagdollToRagdoll.Clear();
Items.Firearm.ItemTypeToFirearmInstance.Clear();
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 24ec22c7c..bf67ae13d 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -3607,11 +3607,11 @@ public void RandomTeleport(Type type)
nameof(Player) => Dictionary.Values.GetRandomValue(),
nameof(Pickup) => Pickup.BaseToPickup.GetRandomValue().Value,
nameof(Ragdoll) => Ragdoll.List.GetRandomValue(),
- nameof(Locker) => Map.GetRandomLocker(),
+ nameof(Locker) => Lockers.Locker.Random().Base,
nameof(Generator) => Generator.List.GetRandomValue(),
nameof(Window) => Window.List.GetRandomValue(),
nameof(Scp914) => Scp914.Scp914Controller,
- nameof(LockerChamber) => Map.GetRandomLocker().Chambers.GetRandomValue(),
+ nameof(LockerChamber) => Lockers.Locker.Random().Chambers.GetRandomValue().Base,
_ => null,
};
diff --git a/EXILED/Exiled.API/Features/Spawn/LockerSpawnPoint.cs b/EXILED/Exiled.API/Features/Spawn/LockerSpawnPoint.cs
new file mode 100644
index 000000000..ecc434127
--- /dev/null
+++ b/EXILED/Exiled.API/Features/Spawn/LockerSpawnPoint.cs
@@ -0,0 +1,72 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+namespace Exiled.API.Features.Spawn
+{
+ using System;
+ using System.Linq;
+
+ using Exiled.API.Enums;
+ using Exiled.API.Features.Lockers;
+ using UnityEngine;
+ using YamlDotNet.Serialization;
+
+ ///
+ /// Handles the spawn point inside a locker.
+ ///
+ public class LockerSpawnPoint : SpawnPoint
+ {
+ ///
+ /// Gets or sets the zone where the locker is located.
+ ///
+ public ZoneType Zone { get; set; } = ZoneType.Unspecified;
+
+ ///
+ /// Gets or sets a value indicating whether to use a random locker chamber's position for spawning.
+ /// If , will be ignored.
+ ///
+ public bool UseChamber { get; set; }
+
+ ///
+ /// Gets or sets the offset position within the locker where the spawn point is located, relative to the locker's origin.
+ ///
+ public Vector3 Offset { get; set; } = Vector3.zero;
+
+ ///
+ /// Gets or sets the type of the .
+ ///
+ public LockerType Type { get; set; } = LockerType.Unknow;
+
+ ///
+ public override float Chance { get; set; }
+
+ ///
+ [YamlIgnore]
+ public override string Name
+ {
+ get => Zone.ToString();
+ set => throw new InvalidOperationException("The name of this type of SpawnPoint cannot be changed.");
+ }
+
+ ///
+ [YamlIgnore]
+ public override Vector3 Position
+ {
+ get
+ {
+ Locker foundLocker = Locker.Random(Zone, Type) ?? throw new NullReferenceException("No locker found in the specified zone.");
+
+ // If UseChamber is true, use a random chamber's position.
+ if (UseChamber)
+ return foundLocker.RandomChamberPosition;
+
+ // Otherwise, use the Offset if provided, or the locker's position.
+ return Offset != Vector3.zero ? foundLocker.Transform.TransformPoint(Offset) : foundLocker.Position;
+ }
+ set => throw new InvalidOperationException("The position of this type of SpawnPoint cannot be changed.");
+ }
+ }
+}
diff --git a/EXILED/Exiled.API/Features/Spawn/RoomSpawnPoint.cs b/EXILED/Exiled.API/Features/Spawn/RoomSpawnPoint.cs
new file mode 100644
index 000000000..92e24e712
--- /dev/null
+++ b/EXILED/Exiled.API/Features/Spawn/RoomSpawnPoint.cs
@@ -0,0 +1,56 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+namespace Exiled.API.Features.Spawn
+{
+ using System;
+
+ using Exiled.API.Enums;
+
+ using UnityEngine;
+
+ using YamlDotNet.Serialization;
+
+ ///
+ /// Represents a spawn point within a specific room in the game.
+ ///
+ public class RoomSpawnPoint : SpawnPoint
+ {
+ ///
+ /// Gets or sets the room type used for this spawn.
+ ///
+ public RoomType Room { get; set; }
+
+ ///
+ /// Gets or sets the offset position within the room where the spawn point is located, relative to the room's origin.
+ ///
+ public Vector3 Offset { get; set; } = Vector3.zero;
+
+ ///
+ public override float Chance { get; set; }
+
+ ///
+ [YamlIgnore]
+ public override string Name
+ {
+ get => Room.ToString();
+ set => throw new InvalidOperationException("The name of this type of SpawnPoint cannot be changed.");
+ }
+
+ ///
+ [YamlIgnore]
+ public override Vector3 Position
+ {
+ get
+ {
+ Room roomInstance = Features.Room.Get(Room) ?? throw new InvalidOperationException("The room instance could not be found.");
+
+ return Offset != Vector3.zero ? roomInstance.transform.TransformPoint(Offset) : roomInstance.Position;
+ }
+ set => throw new InvalidOperationException("The position of this type of SpawnPoint cannot be changed.");
+ }
+ }
+}
diff --git a/EXILED/Exiled.API/Features/Spawn/SpawnProperties.cs b/EXILED/Exiled.API/Features/Spawn/SpawnProperties.cs
index ee8ddef4b..4cdf3345b 100644
--- a/EXILED/Exiled.API/Features/Spawn/SpawnProperties.cs
+++ b/EXILED/Exiled.API/Features/Spawn/SpawnProperties.cs
@@ -34,10 +34,20 @@ public class SpawnProperties
///
public List RoleSpawnPoints { get; set; } = new();
+ ///
+ /// Gets or sets a of possible room-based spawn points.
+ ///
+ public List RoomSpawnPoints { get; set; } = new();
+
+ ///
+ /// Gets or sets a of possible locker-based spawn points.
+ ///
+ public List LockerSpawnPoints { get; set; } = new();
+
///
/// Counts how many spawn points are in this instance.
///
/// How many spawn points there are.
- public int Count() => DynamicSpawnPoints.Count + StaticSpawnPoints.Count + RoleSpawnPoints.Count;
+ public int Count() => DynamicSpawnPoints.Count + StaticSpawnPoints.Count + RoleSpawnPoints.Count + RoomSpawnPoints.Count + LockerSpawnPoints.Count;
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs
index 23359d6b0..c8598a98b 100644
--- a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs
+++ b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs
@@ -619,6 +619,7 @@ public virtual uint Spawn(IEnumerable spawnPoints, uint limit)
spawned++;
+#pragma warning disable CS0618 // Type or member is obsolete \\ TODO: REMOVE THIS
if (spawnPoint is DynamicSpawnPoint dynamicSpawnPoint && dynamicSpawnPoint.Location == SpawnLocationType.InsideLocker)
{
for (int i = 0; i < 50; i++)
@@ -660,16 +661,18 @@ public virtual uint Spawn(IEnumerable spawnPoints, uint limit)
}
Vector3 position = chamber._spawnpoint.transform.position;
- Spawn(position, null);
- Log.Debug($"Spawned {Name} at {position} ({spawnPoint.Name})");
+ Pickup? pickup = Spawn(position, null);
+ if (pickup?.Base is BaseFirearmPickup firearmPickup && this is CustomWeapon customWeapon)
+ {
+ firearmPickup.Status = new FirearmStatus(customWeapon.ClipSize, firearmPickup.Status.Flags, firearmPickup.Status.Attachments);
+ firearmPickup.NetworkStatus = firearmPickup.Status;
+ }
+
+ Log.Debug($"Spawned {Name} at {position} ({spawnPoint.Name})");
break;
}
}
- else if (spawnPoint is RoleSpawnPoint roleSpawnPoint)
- {
- Spawn(roleSpawnPoint.Role.GetRandomSpawnLocation().Position, null);
- }
else
{
Pickup? pickup = Spawn(spawnPoint.Position, null);
@@ -681,6 +684,7 @@ public virtual uint Spawn(IEnumerable spawnPoints, uint limit)
Log.Debug($"Spawned {Name} at {spawnPoint.Position} ({spawnPoint.Name})");
}
+#pragma warning restore CS0618 // Type or member is obsolete
}
return spawned;
@@ -694,8 +698,8 @@ public virtual void SpawnAll()
if (SpawnProperties is null)
return;
- // This will go over each spawn property type (static, dynamic and role) to try and spawn the item.
- // It will attempt to spawn in role-based locations, and then dynamic ones, and finally static.
+ // This will go over each spawn property type (static, dynamic, role-based, room-based, and locker-based) to try and spawn the item.
+ // It will attempt to spawn in role-based locations, then dynamic ones, followed by room-based, locker-based, and finally static.
// Math.Min is used here to ensure that our recursive Spawn() calls do not result in exceeding the spawn limit config.
// This is the same as:
// int spawned = 0;
@@ -703,8 +707,12 @@ public virtual void SpawnAll()
// if (spawned < SpawnProperties.Limit)
// spawned += Spawn(SpawnProperties.DynamicSpawnPoints, SpawnProperties.Limit - spawned);
// if (spawned < SpawnProperties.Limit)
+ // spawned += Spawn(SpawnProperties.RoomSpawnPoints, SpawnProperties.Limit - spawned);
+ // if (spawned < SpawnProperties.Limit)
+ // spawned += Spawn(SpawnProperties.LockerSpawnPoints, SpawnProperties.Limit - spawned);
+ // if (spawned < SpawnProperties.Limit)
// Spawn(SpawnProperties.StaticSpawnPoints, SpawnProperties.Limit - spawned);
- Spawn(SpawnProperties.StaticSpawnPoints, Math.Min(0, SpawnProperties.Limit - Math.Min(0, Spawn(SpawnProperties.DynamicSpawnPoints, SpawnProperties.Limit) - Spawn(SpawnProperties.RoleSpawnPoints, SpawnProperties.Limit))));
+ Spawn(SpawnProperties.StaticSpawnPoints, Math.Min(SpawnProperties.Limit, SpawnProperties.Limit - Math.Min(Spawn(SpawnProperties.DynamicSpawnPoints, SpawnProperties.Limit), SpawnProperties.Limit - Math.Min(Spawn(SpawnProperties.RoleSpawnPoints, SpawnProperties.Limit), SpawnProperties.Limit - Math.Min(Spawn(SpawnProperties.RoomSpawnPoints, SpawnProperties.Limit), SpawnProperties.Limit - Spawn(SpawnProperties.LockerSpawnPoints, SpawnProperties.Limit))))));
}
///
diff --git a/EXILED/Exiled.CustomItems/Commands/Info.cs b/EXILED/Exiled.CustomItems/Commands/Info.cs
index f0de9f1a9..0b6c6e549 100644
--- a/EXILED/Exiled.CustomItems/Commands/Info.cs
+++ b/EXILED/Exiled.CustomItems/Commands/Info.cs
@@ -68,7 +68,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s
.Append("- ").AppendLine(item?.Description)
.AppendLine(item?.Type.ToString())
.Append("- Spawn Limit: ").AppendLine(item?.SpawnProperties?.Limit.ToString()).AppendLine()
- .Append("[Spawn Locations (").Append(item?.SpawnProperties?.DynamicSpawnPoints.Count + item?.SpawnProperties?.StaticSpawnPoints.Count).AppendLine(")]");
+ .Append("[Spawn Locations (").Append(item?.SpawnProperties?.Count()).AppendLine(")]");
foreach (DynamicSpawnPoint spawnPoint in item?.SpawnProperties?.DynamicSpawnPoints!)
message.Append(spawnPoint.Name).Append(' ').Append(spawnPoint.Position).Append(" Chance: ").Append(spawnPoint.Chance).AppendLine("%");
@@ -76,6 +76,15 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s
foreach (StaticSpawnPoint spawnPoint in item.SpawnProperties.StaticSpawnPoints)
message.Append(spawnPoint.Name).Append(' ').Append(spawnPoint.Position).Append(" Chance: ").Append(spawnPoint.Chance).AppendLine("%");
+ foreach (RoleSpawnPoint spawnPoint in item.SpawnProperties.RoleSpawnPoints)
+ message.Append(spawnPoint.Name).Append(' ').Append(spawnPoint.Position).Append(" Chance: ").Append(spawnPoint.Chance).AppendLine("%");
+
+ foreach (LockerSpawnPoint spawnPoint in item.SpawnProperties.LockerSpawnPoints)
+ message.Append(spawnPoint.Name).Append(' ').Append(spawnPoint.Position).Append(" Chance: ").Append(spawnPoint.Chance).AppendLine("%");
+
+ foreach (RoomSpawnPoint spawnPoint in item.SpawnProperties.RoomSpawnPoints)
+ message.Append(spawnPoint.Name).Append(' ').Append(spawnPoint.Position).Append(" Chance: ").Append(spawnPoint.Chance).AppendLine("%");
+
response = StringBuilderPool.Pool.ToStringReturn(message);
return true;
}
diff --git a/EXILED/Exiled.CustomItems/CustomItems.cs b/EXILED/Exiled.CustomItems/CustomItems.cs
index e11a0df2c..855186c00 100644
--- a/EXILED/Exiled.CustomItems/CustomItems.cs
+++ b/EXILED/Exiled.CustomItems/CustomItems.cs
@@ -19,7 +19,7 @@ namespace Exiled.CustomItems
///
public class CustomItems : Plugin
{
- private MapHandler? mapHandler;
+ private MapHandler? roundHandler;
private PlayerHandler? playerHandler;
private Harmony? harmony;
@@ -32,10 +32,10 @@ public class CustomItems : Plugin
public override void OnEnabled()
{
Instance = this;
- mapHandler = new MapHandler();
+ roundHandler = new MapHandler();
playerHandler = new PlayerHandler();
- Exiled.Events.Handlers.Map.Generated += mapHandler.OnMapGenerated;
+ Exiled.Events.Handlers.Map.Generated += roundHandler.OnMapGenerated;
Exiled.Events.Handlers.Player.ChangingItem += playerHandler.OnChangingItem;
@@ -50,7 +50,7 @@ public override void OnEnabled()
///
public override void OnDisabled()
{
- Exiled.Events.Handlers.Map.Generated -= mapHandler!.OnMapGenerated;
+ Exiled.Events.Handlers.Map.Generated -= roundHandler!.OnMapGenerated;
Exiled.Events.Handlers.Player.ChangingItem -= playerHandler!.OnChangingItem;
diff --git a/EXILED/Exiled.CustomItems/Events/MapHandler.cs b/EXILED/Exiled.CustomItems/Events/MapHandler.cs
index 678d0c404..4e0c2442f 100644
--- a/EXILED/Exiled.CustomItems/Events/MapHandler.cs
+++ b/EXILED/Exiled.CustomItems/Events/MapHandler.cs
@@ -8,19 +8,21 @@
namespace Exiled.CustomItems.Events
{
using Exiled.CustomItems.API.Features;
+ using MEC;
///
/// Event Handlers for the CustomItem API.
///
internal sealed class MapHandler
{
- ///
- /// Handle spawning Custom Items.
- ///
+ ///
public void OnMapGenerated()
{
- foreach (CustomItem customItem in CustomItem.Registered)
- customItem?.SpawnAll();
+ Timing.CallDelayed(0.5f, () => // Delay its necessary for the spawnpoints of lockers and rooms to be generated.
+ {
+ foreach (CustomItem customItem in CustomItem.Registered)
+ customItem?.SpawnAll();
+ });
}
}
}
\ 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 61f88ec2c..29151b1f4 100644
--- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs
+++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs
@@ -840,6 +840,16 @@ protected Vector3 GetSpawnPosition()
}
}
+ if (SpawnProperties.RoomSpawnPoints.Count > 0)
+ {
+ foreach ((float chance, Vector3 pos) in SpawnProperties.RoomSpawnPoints)
+ {
+ double r = Loader.Random.NextDouble() * 100;
+ if (r <= chance)
+ return pos;
+ }
+ }
+
return Vector3.zero;
}
diff --git a/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs b/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
index f75f2e91f..30ad47c9f 100644
--- a/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
+++ b/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
@@ -18,7 +18,7 @@ namespace Exiled.Events.Handlers.Internal
using Exiled.API.Enums;
using Exiled.API.Extensions;
-
+ using Exiled.API.Features.Lockers;
using InventorySystem.Items.Firearms.Attachments;
using InventorySystem.Items.Firearms.Attachments.Components;
@@ -47,6 +47,7 @@ public static void OnMapGenerated()
{
Map.ClearCache();
PrefabHelper.LoadPrefabs();
+ Locker.ClearCache();
// TODO: Fix For (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/377)
PlayerRoles.RoleAssign.HumanSpawner.Handlers[PlayerRoles.Team.ChaosInsurgency] = new PlayerRoles.RoleAssign.OneRoleHumanSpawner(PlayerRoles.RoleTypeId.ChaosConscript);
diff --git a/EXILED/Exiled.Events/Patches/Generic/LockerList.cs b/EXILED/Exiled.Events/Patches/Generic/LockerList.cs
index 26b0732ab..7dadd8817 100644
--- a/EXILED/Exiled.Events/Patches/Generic/LockerList.cs
+++ b/EXILED/Exiled.Events/Patches/Generic/LockerList.cs
@@ -12,7 +12,7 @@ namespace Exiled.Events.Patches.Generic
using API.Features;
using API.Features.Pools;
-
+ using Exiled.API.Features.Lockers;
using HarmonyLib;
using MapGeneration.Distributors;
@@ -20,23 +20,23 @@ namespace Exiled.Events.Patches.Generic
using static HarmonyLib.AccessTools;
///
- /// Patches .
+ /// Patches .
///
- [HarmonyPatch(typeof(Locker), nameof(Locker.Start))]
+ [HarmonyPatch(typeof(MapGeneration.Distributors.Locker), nameof(MapGeneration.Distributors.Locker.Start))]
internal class LockerList
{
private static IEnumerable Transpiler(IEnumerable codeInstructions)
{
List newInstructions = ListPool.Pool.Get(codeInstructions);
- // Map.LockersValue.Add(this);
+ // new Locker(this)
newInstructions.InsertRange(
0,
new CodeInstruction[]
{
- new(OpCodes.Ldsfld, Field(typeof(Map), nameof(Map.LockersValue))),
new(OpCodes.Ldarg_0),
- new(OpCodes.Callvirt, Method(typeof(List), nameof(List.Add), new[] { typeof(Locker) })),
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(API.Features.Lockers.Locker))[0]),
+ new(OpCodes.Pop),
});
for (int z = 0; z < newInstructions.Count; z++)
From c9a1b9a988b5808602cb20ed5dd717f3edfd8db5 Mon Sep 17 00:00:00 2001
From: VALERA771 <72030575+VALERA771@users.noreply.github.com>
Date: Mon, 2 Sep 2024 21:24:45 +0300
Subject: [PATCH 49/63] `[Exiled::API]` Adding new properties for `FpcRole`
(#65)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* 👉👈
* suggestions
* no more bc
---------
Co-authored-by: Vladislav Popovič
---
EXILED/Exiled.API/Features/Player.cs | 13 ++++----
EXILED/Exiled.API/Features/Roles/FpcRole.cs | 33 ++++++++++++++++---
.../Exiled.API/Features/Roles/IVoiceRole.cs | 22 +++++++++++++
EXILED/Exiled.API/Features/Roles/NoneRole.cs | 6 +++-
.../Exiled.API/Features/Roles/Scp0492Role.cs | 2 +-
.../Exiled.API/Features/Roles/Scp049Role.cs | 4 +--
.../Exiled.API/Features/Roles/Scp079Role.cs | 6 +++-
.../Exiled.API/Features/Roles/Scp3114Role.cs | 17 ++++++++--
.../Features/Roles/SpectatorRole.cs | 7 ++--
.../Patches/Events/Player/VoiceChatting.cs | 5 ++-
10 files changed, 92 insertions(+), 23 deletions(-)
create mode 100644 EXILED/Exiled.API/Features/Roles/IVoiceRole.cs
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index bf67ae13d..6c6c88702 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -214,12 +214,13 @@ private set
///
/// Gets the 's , can be null.
///
- public VoiceModuleBase VoiceModule => RoleManager.CurrentRole is IVoiceRole voiceRole ? voiceRole.VoiceModule : null;
+ [Obsolete("Use IVoiceRole::VoiceModule instead.")]
+ public VoiceModuleBase VoiceModule => Role is Roles.IVoiceRole voiceRole ? voiceRole.VoiceModule : null;
///
/// Gets the 's , can be null.
///
- public PersonalRadioPlayback RadioPlayback => VoiceModule is IRadioVoiceModule radioVoiceModule ? radioVoiceModule.RadioPlayback : null;
+ public PersonalRadioPlayback RadioPlayback => Role is Roles.IVoiceRole voiceRole ? voiceRole.VoiceModule is IRadioVoiceModule radioVoiceModule ? radioVoiceModule.RadioPlayback : null : null;
///
/// Gets the of the player.
@@ -793,7 +794,7 @@ public bool IsIntercomMuted
///
/// Gets a value indicating whether or not the player is speaking.
///
- public bool IsSpeaking => VoiceModule != null && VoiceModule.IsSpeaking;
+ public bool IsSpeaking => Role is Roles.IVoiceRole voiceRole && voiceRole.VoiceModule.IsSpeaking;
///
/// Gets the player's voice color.
@@ -805,13 +806,13 @@ public bool IsIntercomMuted
///
public VoiceChatChannel VoiceChannel
{
- get => VoiceModule == null ? VoiceChatChannel.None : VoiceModule.CurrentChannel;
+ get => Role is Roles.IVoiceRole voiceRole ? voiceRole.VoiceModule.CurrentChannel : VoiceChatChannel.None;
set
{
- if (VoiceModule == null)
+ if (Role is not Roles.IVoiceRole voiceRole)
return;
- VoiceModule.CurrentChannel = value;
+ voiceRole.VoiceModule.CurrentChannel = value;
}
}
diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs
index 4ca71d8c8..4fe6151bd 100644
--- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs
+++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs
@@ -11,20 +11,21 @@ namespace Exiled.API.Features.Roles
using System.Reflection;
using Exiled.API.Features.Pools;
-
using HarmonyLib;
using PlayerRoles;
using PlayerRoles.FirstPersonControl;
-
+ using PlayerRoles.Ragdolls;
+ using PlayerRoles.Spectating;
+ using PlayerRoles.Visibility;
+ using PlayerRoles.Voice;
using PlayerStatsSystem;
using RelativePositioning;
-
using UnityEngine;
///
/// Defines a role that represents an fpc class.
///
- public abstract class FpcRole : Role
+ public abstract class FpcRole : Role, IVoiceRole
{
private static FieldInfo enableFallDamageField;
private bool isUsingStamina = true;
@@ -243,6 +244,30 @@ public bool IsNoclipEnabled
set => Owner.ReferenceHub.playerStats.GetModule().SetFlag(AdminFlags.Noclip, value);
}
+ ///
+ /// Gets or sets a prefab ragdoll for this role.
+ ///
+ public BasicRagdoll Ragdoll
+ {
+ get => FirstPersonController.Ragdoll;
+ set => FirstPersonController.Ragdoll = value;
+ }
+
+ ///
+ /// Gets a voice module for this role.
+ ///
+ public VoiceModuleBase VoiceModule => FirstPersonController.VoiceModule;
+
+ ///
+ /// Gets a for this role.
+ ///
+ public VisibilityController VisibilityController => FirstPersonController.VisibilityController;
+
+ ///
+ /// Gets a for this role.
+ ///
+ public SpectatableModuleBase SpectatableModuleBase => FirstPersonController.SpectatorModule;
+
///
/// Resets the 's stamina.
///
diff --git a/EXILED/Exiled.API/Features/Roles/IVoiceRole.cs b/EXILED/Exiled.API/Features/Roles/IVoiceRole.cs
new file mode 100644
index 000000000..74e431fcd
--- /dev/null
+++ b/EXILED/Exiled.API/Features/Roles/IVoiceRole.cs
@@ -0,0 +1,22 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.API.Features.Roles
+{
+ using PlayerRoles.Voice;
+
+ ///
+ /// Interface for all roles with .
+ ///
+ public interface IVoiceRole
+ {
+ ///
+ /// Gets the of the role.
+ ///
+ public VoiceModuleBase VoiceModule { get; }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Features/Roles/NoneRole.cs b/EXILED/Exiled.API/Features/Roles/NoneRole.cs
index d97cd448e..b890ddb23 100644
--- a/EXILED/Exiled.API/Features/Roles/NoneRole.cs
+++ b/EXILED/Exiled.API/Features/Roles/NoneRole.cs
@@ -8,13 +8,14 @@
namespace Exiled.API.Features.Roles
{
using PlayerRoles;
+ using PlayerRoles.Voice;
using NoneGameRole = PlayerRoles.NoneRole;
///
/// Defines a role that represents players with no role.
///
- public class NoneRole : Role
+ public class NoneRole : Role, IVoiceRole
{
///
/// Initializes a new instance of the class.
@@ -27,5 +28,8 @@ internal NoneRole(PlayerRoleBase baseRole)
///
public override RoleTypeId Type { get; } = RoleTypeId.None;
+
+ ///
+ public VoiceModuleBase VoiceModule => (Base as NoneGameRole) !.VoiceModule;
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Features/Roles/Scp0492Role.cs b/EXILED/Exiled.API/Features/Roles/Scp0492Role.cs
index 1596ad83c..f2196a0a7 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp0492Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp0492Role.cs
@@ -105,7 +105,7 @@ public float SimulatedStare
///
/// Gets the that SCP-049-2 is currently consuming. Will be if is .
///
- public Ragdoll RagdollConsuming => Ragdoll.Get(ConsumeAbility.CurRagdoll);
+ public Ragdoll RagdollConsuming => Features.Ragdoll.Get(ConsumeAbility.CurRagdoll);
///
/// Gets the amount of time in between SCP-049-2 attacks.
diff --git a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs
index eff90bc44..2e1384e6e 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs
@@ -111,7 +111,7 @@ internal Scp049Role(Scp049GameRole baseRole)
///
/// Gets the ragdoll that is currently being revived by SCP-049. Will be if is .
///
- public Ragdoll RecallingRagdoll => Ragdoll.Get(ResurrectAbility.CurRagdoll);
+ public Ragdoll RecallingRagdoll => Features.Ragdoll.Get(ResurrectAbility.CurRagdoll);
///
/// Gets all the dead zombies.
@@ -255,7 +255,7 @@ public bool Resurrect(Player player)
HumeShieldModuleBase humeShield = ResurrectAbility.CastRole.HumeShieldModule;
humeShield.HsCurrent = Mathf.Min(humeShield.HsCurrent + 100f, humeShield.HsMax);
- return Resurrect(Ragdoll.GetLast(player));
+ return Resurrect(Features.Ragdoll.GetLast(player));
}
///
diff --git a/EXILED/Exiled.API/Features/Roles/Scp079Role.cs b/EXILED/Exiled.API/Features/Roles/Scp079Role.cs
index a3de5059c..05334e308 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp079Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp079Role.cs
@@ -22,6 +22,7 @@ namespace Exiled.API.Features.Roles
using PlayerRoles.PlayableScps.Scp079.Pinging;
using PlayerRoles.PlayableScps.Scp079.Rewards;
using PlayerRoles.Subroutines;
+ using PlayerRoles.Voice;
using RelativePositioning;
using Utils.NonAllocLINQ;
@@ -32,7 +33,7 @@ namespace Exiled.API.Features.Roles
///
/// Defines a role that represents SCP-079.
///
- public class Scp079Role : Role, ISubroutinedScpRole, ISpawnableScp
+ public class Scp079Role : Role, ISubroutinedScpRole, ISpawnableScp, IVoiceRole
{
///
/// Initializes a new instance of the class.
@@ -374,6 +375,9 @@ public float Scp2176LostTime
///
public float EnergyRegenerationSpeed => AuxManager.RegenSpeed;
+ ///
+ public VoiceModuleBase VoiceModule => Base.VoiceModule;
+
///
/// Gets the game .
///
diff --git a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs
index b8867839a..89dcefa15 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs
@@ -7,6 +7,7 @@
namespace Exiled.API.Features.Roles
{
+ using System;
using System.Collections.Generic;
using Exiled.API.Enums;
@@ -149,10 +150,10 @@ public RoleTypeId StolenRole
get => Identity.CurIdentity.StolenRole;
set
{
- if (Ragdoll is null)
+ if (IdentityRagdoll is null)
return;
- Ragdoll.Role = value;
+ IdentityRagdoll.Role = value;
UpdateIdentity();
}
}
@@ -160,7 +161,17 @@ public RoleTypeId StolenRole
///
/// Gets or sets the SCP-3114's Ragdoll used for it's FakeIdentity.
///
- public Ragdoll Ragdoll
+ [Obsolete("Ragdoll in Role now has other meaning. Use IdentityRagdoll instead.")]
+ public new Ragdoll Ragdoll
+ {
+ get => IdentityRagdoll;
+ set => IdentityRagdoll = value;
+ }
+
+ ///
+ /// Gets or sets the SCP-3114's Ragdoll used for it's FakeIdentity.
+ ///
+ public Ragdoll IdentityRagdoll
{
get => Ragdoll.Get(Identity.CurIdentity.Ragdoll);
set
diff --git a/EXILED/Exiled.API/Features/Roles/SpectatorRole.cs b/EXILED/Exiled.API/Features/Roles/SpectatorRole.cs
index cdaf0fe86..3bb2f052f 100644
--- a/EXILED/Exiled.API/Features/Roles/SpectatorRole.cs
+++ b/EXILED/Exiled.API/Features/Roles/SpectatorRole.cs
@@ -10,7 +10,7 @@ namespace Exiled.API.Features.Roles
using System;
using PlayerRoles;
-
+ using PlayerRoles.Voice;
using UnityEngine;
using SpectatorGameRole = PlayerRoles.Spectating.SpectatorRole;
@@ -18,7 +18,7 @@ namespace Exiled.API.Features.Roles
///
/// Defines a role that represents a spectator.
///
- public class SpectatorRole : Role
+ public class SpectatorRole : Role, IVoiceRole
{
///
/// Initializes a new instance of the class.
@@ -70,5 +70,8 @@ public Player SpectatedPlayer
/// Gets the game .
///
public new SpectatorGameRole Base { get; }
+
+ ///
+ public VoiceModuleBase VoiceModule => Base.VoiceModule;
}
}
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/VoiceChatting.cs b/EXILED/Exiled.Events/Patches/Events/Player/VoiceChatting.cs
index 875e099b0..993993826 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/VoiceChatting.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/VoiceChatting.cs
@@ -80,9 +80,8 @@ private static IEnumerable Transpiler(IEnumerable
Date: Tue, 10 Sep 2024 16:35:42 -0400
Subject: [PATCH 50/63] Update programs.yml
---
.github/workflows/programs.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/programs.yml b/.github/workflows/programs.yml
index 68d87cf02..4852aee62 100644
--- a/.github/workflows/programs.yml
+++ b/.github/workflows/programs.yml
@@ -36,7 +36,7 @@ jobs:
run: dotnet publish ${{ matrix.proj_name }} -r ${{ matrix.target }} -c release -o builds/${{ matrix.target }} --self-contained true
- name: Upload ${{ matrix.proj_name }}@${{ matrix.target }} build
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: ${{ matrix.proj_name }}-${{ matrix.target }}
path: EXILED/builds/${{ matrix.target }}
From fb40d833fb02615731633809e4d2592e79d5fd28 Mon Sep 17 00:00:00 2001
From: X <24619207+Undid-Iridium@users.noreply.github.com>
Date: Thu, 12 Sep 2024 14:58:20 -0400
Subject: [PATCH 51/63] Scp0492 change apperance fix (#87)
* 0492 appearance change fix.
* Yamato is correct, ZombieRole also inherits StandardRoleBase
* Stylecop, sigh
---------
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
.../Exiled.API/Extensions/MirrorExtensions.cs | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
index 114435a40..568eabf51 100644
--- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
+++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
@@ -271,6 +271,15 @@ public static void ChangeAppearance(this Player player, RoleTypeId type, IEnumer
writer.WriteByte(unitId);
}
+ if (roleBase is ZombieRole)
+ {
+ if (player.Role.Base is not ZombieRole)
+ isRisky = true;
+
+ writer.WriteUShort((ushort)Mathf.Clamp(Mathf.CeilToInt(player.MaxHealth), ushort.MinValue, ushort.MaxValue));
+ writer.WriteBool(true);
+ }
+
if (roleBase is FpcStandardRoleBase fpc)
{
if (player.Role.Base is not FpcStandardRoleBase playerfpc)
@@ -284,14 +293,6 @@ public static void ChangeAppearance(this Player player, RoleTypeId type, IEnumer
writer.WriteUShort(value);
}
- if (roleBase is ZombieRole)
- {
- if (player.Role.Base is not ZombieRole)
- isRisky = true;
-
- writer.WriteUShort((ushort)Mathf.Clamp(Mathf.CeilToInt(player.MaxHealth), ushort.MinValue, ushort.MaxValue));
- }
-
foreach (Player target in playersToAffect)
{
if (target != player || !isRisky)
From 4d5d1427165581ae6eec6b1d800ab31f8ed1090d Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sat, 14 Sep 2024 17:26:08 +0200
Subject: [PATCH 52/63] Add plugin website
---
EXILED/docs/toc.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/EXILED/docs/toc.yml b/EXILED/docs/toc.yml
index bbebe92c1..612552b99 100644
--- a/EXILED/docs/toc.yml
+++ b/EXILED/docs/toc.yml
@@ -4,3 +4,5 @@
href: api/Exiled.html
- name: Repository
href: https://github.com/Exiled-Official/EXILED
+- name: Plugin
+ href: https://hub.exiled-team.net/
From e1d726f08057ead751efac00b8ceaed51fb369db Mon Sep 17 00:00:00 2001
From: VALERA771 <72030575+VALERA771@users.noreply.github.com>
Date: Sun, 15 Sep 2024 14:55:06 +0300
Subject: [PATCH 53/63] fix (#95)
---
EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs
index 82e924fbc..46a90559d 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs
@@ -42,7 +42,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable
Date: Mon, 23 Sep 2024 09:02:13 +0300
Subject: [PATCH 54/63] Replace with exiled wrapper class (#94)
---
EXILED/Exiled.API/Features/Lockers/Chamber.cs | 8 ++++
.../EventArgs/Map/FillingLockerEventArgs.cs | 20 ++++++++--
.../Player/InteractingLockerEventArgs.cs | 39 +++++++++++--------
.../Events/Player/InteractingLocker.cs | 6 ---
4 files changed, 46 insertions(+), 27 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Lockers/Chamber.cs b/EXILED/Exiled.API/Features/Lockers/Chamber.cs
index 25f9385b8..8209d39a5 100644
--- a/EXILED/Exiled.API/Features/Lockers/Chamber.cs
+++ b/EXILED/Exiled.API/Features/Lockers/Chamber.cs
@@ -4,8 +4,10 @@
// Licensed under the CC BY-SA 3.0 license.
//
// -----------------------------------------------------------------------
+
namespace Exiled.API.Features.Lockers
{
+ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -36,6 +38,7 @@ public Chamber(LockerChamber chamber, Locker locker)
{
Base = chamber;
Locker = locker;
+ Id = (byte)Array.IndexOf(locker.Base.Chambers, chamber);
Chambers.Add(chamber, this);
}
@@ -151,6 +154,11 @@ public float Cooldown
///
public bool IsOpen => Base.IsOpen;
+ ///
+ /// Gets the id of this chamber in .
+ ///
+ public byte Id { get; }
+
///
/// Gets the of current cooldown.
///
diff --git a/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs
index f50a87182..2d28744b2 100644
--- a/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs
@@ -7,11 +7,12 @@
namespace Exiled.Events.EventArgs.Map
{
+ using System;
+
+ using Exiled.API.Features.Lockers;
using Exiled.API.Features.Pickups;
using Exiled.Events.EventArgs.Interfaces;
-
using InventorySystem.Items.Pickups;
-
using MapGeneration.Distributors;
///
@@ -31,7 +32,7 @@ public class FillingLockerEventArgs : IDeniableEvent, IPickupEvent
public FillingLockerEventArgs(ItemPickupBase pickupBase, LockerChamber lockerChamber)
{
Pickup = Pickup.Get(pickupBase);
- LockerChamber = lockerChamber;
+ Chamber = Chamber.Get(lockerChamber);
}
///
@@ -42,7 +43,18 @@ public FillingLockerEventArgs(ItemPickupBase pickupBase, LockerChamber lockerCha
///
/// Gets a value indicating the target locker chamber.
///
- public LockerChamber LockerChamber { get; }
+ [Obsolete("Use Chamber instead.")]
+ public LockerChamber LockerChamber => Chamber.Base;
+
+ ///
+ /// Gets a locker which is containing .
+ ///
+ public API.Features.Lockers.Locker Locker => Chamber.Locker;
+
+ ///
+ /// Gets a chamber which is filling.
+ ///
+ public Chamber Chamber { get; }
///
/// Gets or sets a value indicating whether or not the item can be spawned.
diff --git a/EXILED/Exiled.Events/EventArgs/Player/InteractingLockerEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/InteractingLockerEventArgs.cs
index 2eec0c06b..46a7dfc63 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/InteractingLockerEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/InteractingLockerEventArgs.cs
@@ -7,12 +7,12 @@
namespace Exiled.Events.EventArgs.Player
{
- using API.Features;
+ using System;
+ using API.Features;
+ using Exiled.API.Features.Lockers;
using Interfaces;
- using MapGeneration.Distributors;
-
///
/// Contains all information before a player interacts with a locker.
///
@@ -24,41 +24,46 @@ public class InteractingLockerEventArgs : IPlayerEvent, IDeniableEvent
///
///
///
- ///
- ///
- ///
///
- ///
- ///
- ///
- ///
+ ///
///
///
///
///
- public InteractingLockerEventArgs(Player player, Locker locker, LockerChamber lockerChamber, byte chamberId, bool isAllowed)
+ public InteractingLockerEventArgs(Player player, MapGeneration.Distributors.LockerChamber lockerChamber, bool isAllowed)
{
Player = player;
- Locker = locker;
- Chamber = lockerChamber;
- ChamberId = chamberId;
+ InteractingChamber = API.Features.Lockers.Chamber.Get(lockerChamber);
IsAllowed = isAllowed;
}
///
/// Gets the instance.
///
- public Locker Locker { get; }
+ [Obsolete("Use InteractingLocker instead.")]
+ public MapGeneration.Distributors.Locker Locker => InteractingLocker.Base;
+
+ ///
+ /// Gets the interacting chamber.
+ ///
+ [Obsolete("Use InteractingChamber instead.")]
+ public MapGeneration.Distributors.LockerChamber Chamber => InteractingChamber.Base;
+
+ ///
+ /// Gets the locker which is containing .
+ ///
+ public Locker InteractingLocker => InteractingChamber.Locker;
///
/// Gets the interacting chamber.
///
- public LockerChamber Chamber { get; }
+ public Chamber InteractingChamber { get; }
///
/// Gets the chamber id.
///
- public byte ChamberId { get; }
+ [Obsolete("Use Chamber::Id instead.")]
+ public byte ChamberId => InteractingChamber.Id;
///
/// Gets or sets a value indicating whether or not the player can interact with the locker.
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/InteractingLocker.cs b/EXILED/Exiled.Events/Patches/Events/Player/InteractingLocker.cs
index b706f067f..e99120751 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/InteractingLocker.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/InteractingLocker.cs
@@ -43,18 +43,12 @@ private static IEnumerable Transpiler(IEnumerable
Date: Mon, 23 Sep 2024 19:33:11 +0200
Subject: [PATCH 55/63] Fix Role NRE (#66)
---
EXILED/Exiled.API/Features/Roles/Role.cs | 7 ++--
.../Events/Player/ChangingRoleAndSpawned.cs | 33 +------------------
2 files changed, 4 insertions(+), 36 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Roles/Role.cs b/EXILED/Exiled.API/Features/Roles/Role.cs
index 96f7a3b68..bc9f94d20 100644
--- a/EXILED/Exiled.API/Features/Roles/Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Role.cs
@@ -10,19 +10,17 @@ namespace Exiled.API.Features.Roles
using System;
using Enums;
-
using Exiled.API.Features.Core;
using Exiled.API.Features.Spawn;
using Exiled.API.Interfaces;
using Extensions;
-
using PlayerRoles;
using PlayerRoles.PlayableScps.Scp049.Zombies;
-
using UnityEngine;
using FilmmakerGameRole = PlayerRoles.Filmmaker.FilmmakerRole;
using HumanGameRole = PlayerRoles.HumanRole;
+ using NoneGameRole = PlayerRoles.NoneRole;
using OverwatchGameRole = PlayerRoles.Spectating.OverwatchRole;
using Scp049GameRole = PlayerRoles.PlayableScps.Scp049.Scp049Role;
using Scp079GameRole = PlayerRoles.PlayableScps.Scp079.Scp079Role;
@@ -229,7 +227,8 @@ public virtual void Set(RoleTypeId newRole, SpawnReason reason, RoleSpawnFlags s
SpectatorGameRole spectatorRole => new SpectatorRole(spectatorRole),
HumanGameRole humanRole => new HumanRole(humanRole),
FilmmakerGameRole filmmakerRole => new FilmMakerRole(filmmakerRole),
- _ => new NoneRole(role),
+ NoneGameRole noneRole => new NoneRole(noneRole),
+ _ => null,
};
}
}
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ChangingRoleAndSpawned.cs b/EXILED/Exiled.Events/Patches/Events/Player/ChangingRoleAndSpawned.cs
index 786842b5b..8de757847 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/ChangingRoleAndSpawned.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/ChangingRoleAndSpawned.cs
@@ -43,8 +43,6 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable instruction.Calls(Method(typeof(GameObjectPools.PoolObject), nameof(GameObjectPools.PoolObject.SetupPoolObject)))) + offset;
- newInstructions[index].WithLabels(continueLabel1);
-
newInstructions.InsertRange(
index,
new[]
{
- // if (player == null)
- // continue
- new CodeInstruction(OpCodes.Ldloc_S, player.LocalIndex),
- new(OpCodes.Brfalse_S, continueLabel1),
-
// player.Role = Role.Create(roleBase);
new CodeInstruction(OpCodes.Ldloc_S, player.LocalIndex),
new(OpCodes.Ldloc_2),
@@ -154,22 +140,10 @@ private static IEnumerable Transpiler(IEnumerable i.Calls(Method(typeof(PlayerRoleManager.RoleChanged), nameof(PlayerRoleManager.RoleChanged.Invoke)))) + offset;
- newInstructions[index].labels.Add(continueLabel2);
-
newInstructions.InsertRange(
index,
- new[]
+ new CodeInstruction[]
{
- // if (player == null)
- // continue
- new CodeInstruction(OpCodes.Ldloc_S, player.LocalIndex),
- new(OpCodes.Brfalse_S, continueLabel2),
-
- // if (changingRoleEventArgs == null)
- // continue
- new CodeInstruction(OpCodes.Ldloc_S, changingRoleEventArgs.LocalIndex),
- new(OpCodes.Brfalse_S, continueLabel2),
-
// changingRoleEventArgs
new(OpCodes.Ldloc_S, changingRoleEventArgs.LocalIndex),
@@ -181,11 +155,6 @@ private static IEnumerable Transpiler(IEnumerable
Date: Mon, 23 Sep 2024 20:33:25 +0300
Subject: [PATCH 56/63] `[Exiled::API]` New way to register parent commands
(#74)
* uwu
* optimising
---
EXILED/Exiled.API/Features/Plugin.cs | 71 ++++++++++++++++---
.../Exiled.Events/Commands/Config/EConfig.cs | 10 ---
EXILED/Exiled.Events/Commands/Config/Merge.cs | 1 +
EXILED/Exiled.Events/Commands/Config/Split.cs | 1 +
.../Commands/PluginManager/Disable.cs | 1 +
.../Commands/PluginManager/Enable.cs | 1 +
.../Commands/PluginManager/Patches.cs | 1 +
.../Commands/PluginManager/PluginManager.cs | 12 ----
.../Commands/PluginManager/Show.cs | 1 +
EXILED/Exiled.Events/Commands/Reload/All.cs | 1 +
.../Exiled.Events/Commands/Reload/Configs.cs | 1 +
.../Exiled.Events/Commands/Reload/GamePlay.cs | 1 +
.../Commands/Reload/Permissions.cs | 1 +
.../Exiled.Events/Commands/Reload/Plugins.cs | 1 +
.../Exiled.Events/Commands/Reload/Reload.cs | 15 ----
.../Commands/Reload/RemoteAdmin.cs | 1 +
.../Commands/Reload/Translations.cs | 1 +
17 files changed, 74 insertions(+), 47 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Plugin.cs b/EXILED/Exiled.API/Features/Plugin.cs
index 0c4b23fd2..6153cbeee 100644
--- a/EXILED/Exiled.API/Features/Plugin.cs
+++ b/EXILED/Exiled.API/Features/Plugin.cs
@@ -7,6 +7,8 @@
namespace Exiled.API.Features
{
+ using System.Linq;
+
#pragma warning disable SA1402
using System;
using System.Collections.Generic;
@@ -97,6 +99,8 @@ public virtual void OnEnabled()
///
public virtual void OnRegisteringCommands()
{
+ Dictionary> toRegister = new();
+
foreach (Type type in Assembly.GetTypes())
{
if (type.GetInterface("ICommand") != typeof(ICommand))
@@ -105,28 +109,42 @@ public virtual void OnRegisteringCommands()
if (!Attribute.IsDefined(type, typeof(CommandHandlerAttribute)))
continue;
- foreach (CustomAttributeData customAttributeData in type.CustomAttributes)
+ foreach (CustomAttributeData customAttributeData in type.GetCustomAttributesData())
{
try
{
if (customAttributeData.AttributeType != typeof(CommandHandlerAttribute))
continue;
- Type commandType = (Type)customAttributeData.ConstructorArguments?[0].Value;
+ Type commandHandlerType = (Type)customAttributeData.ConstructorArguments[0].Value;
- if (!Commands.TryGetValue(commandType, out Dictionary typeCommands))
- continue;
+ ICommand command = GetCommand(type) ?? (ICommand)Activator.CreateInstance(type);
- if (!typeCommands.TryGetValue(type, out ICommand command))
- command = (ICommand)Activator.CreateInstance(type);
+ if (typeof(ParentCommand).IsAssignableFrom(commandHandlerType))
+ {
+ ParentCommand parentCommand = GetCommand(commandHandlerType) as ParentCommand;
+
+ if (parentCommand == null)
+ {
+ if (!toRegister.TryGetValue(commandHandlerType, out List list))
+ toRegister.Add(commandHandlerType, new() { command });
+ else
+ list.Add(command);
+
+ continue;
+ }
+
+ parentCommand.RegisterCommand(command);
+ continue;
+ }
try
{
- if (commandType == typeof(RemoteAdminCommandHandler))
+ if (commandHandlerType == typeof(RemoteAdminCommandHandler))
CommandProcessor.RemoteAdminCommandHandler.RegisterCommand(command);
- else if (commandType == typeof(GameConsoleCommandHandler))
+ else if (commandHandlerType == typeof(GameConsoleCommandHandler))
GameCore.Console.singleton.ConsoleCommandHandler.RegisterCommand(command);
- else if (commandType == typeof(ClientCommandHandler))
+ else if (commandHandlerType == typeof(ClientCommandHandler))
QueryProcessor.DotCommandHandler.RegisterCommand(command);
}
catch (ArgumentException e)
@@ -141,7 +159,7 @@ public virtual void OnRegisteringCommands()
}
}
- Commands[commandType][type] = command;
+ Commands[commandHandlerType][type] = command;
}
catch (Exception exception)
{
@@ -149,6 +167,39 @@ public virtual void OnRegisteringCommands()
}
}
}
+
+ foreach (KeyValuePair> kvp in toRegister)
+ {
+ ParentCommand parentCommand = GetCommand(kvp.Key) as ParentCommand;
+
+ foreach (ICommand command in kvp.Value)
+ parentCommand.RegisterCommand(command);
+ }
+ }
+
+ ///
+ /// Gets a command by it's type.
+ ///
+ /// 's type.
+ /// 's type. Defines in which command handler command is registered.
+ /// A . May be if command is not registered.
+ public ICommand GetCommand(Type type, Type commandHandler = null)
+ {
+ if (type.GetInterface("ICommand") != typeof(ICommand))
+ return null;
+
+ if (commandHandler != null)
+ {
+ if (!Commands.TryGetValue(commandHandler, out Dictionary commands))
+ return null;
+
+ if (!commands.TryGetValue(type, out ICommand command))
+ return null;
+
+ return command;
+ }
+
+ return Commands.Keys.Select(commandHandlerType => GetCommand(type, commandHandlerType)).FirstOrDefault(command => command != null);
}
///
diff --git a/EXILED/Exiled.Events/Commands/Config/EConfig.cs b/EXILED/Exiled.Events/Commands/Config/EConfig.cs
index 120ed4661..6b6ead4b6 100644
--- a/EXILED/Exiled.Events/Commands/Config/EConfig.cs
+++ b/EXILED/Exiled.Events/Commands/Config/EConfig.cs
@@ -17,14 +17,6 @@ namespace Exiled.Events.Commands.Config
[CommandHandler(typeof(GameConsoleCommandHandler))]
public class EConfig : ParentCommand
{
- ///
- /// Initializes a new instance of the class.
- ///
- public EConfig()
- {
- LoadGeneratedCommands();
- }
-
///
public override string Command { get; } = "econfig";
@@ -37,8 +29,6 @@ public EConfig()
///
public override void LoadGeneratedCommands()
{
- RegisterCommand(Merge.Instance);
- RegisterCommand(Split.Instance);
}
///
diff --git a/EXILED/Exiled.Events/Commands/Config/Merge.cs b/EXILED/Exiled.Events/Commands/Config/Merge.cs
index dc90cad8e..7bad3a00e 100644
--- a/EXILED/Exiled.Events/Commands/Config/Merge.cs
+++ b/EXILED/Exiled.Events/Commands/Config/Merge.cs
@@ -20,6 +20,7 @@ namespace Exiled.Events.Commands.Config
///
/// The config merge command.
///
+ [CommandHandler(typeof(EConfig))]
public class Merge : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/Config/Split.cs b/EXILED/Exiled.Events/Commands/Config/Split.cs
index ab2f1a577..ad42f3024 100644
--- a/EXILED/Exiled.Events/Commands/Config/Split.cs
+++ b/EXILED/Exiled.Events/Commands/Config/Split.cs
@@ -20,6 +20,7 @@ namespace Exiled.Events.Commands.Config
///
/// The config split command.
///
+ [CommandHandler(typeof(EConfig))]
public class Split : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/PluginManager/Disable.cs b/EXILED/Exiled.Events/Commands/PluginManager/Disable.cs
index 998a81cdf..81d3bdffd 100644
--- a/EXILED/Exiled.Events/Commands/PluginManager/Disable.cs
+++ b/EXILED/Exiled.Events/Commands/PluginManager/Disable.cs
@@ -17,6 +17,7 @@ namespace Exiled.Events.Commands.PluginManager
///
/// The command to disable a plugin.
///
+ [CommandHandler(typeof(PluginManager))]
public sealed class Disable : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/PluginManager/Enable.cs b/EXILED/Exiled.Events/Commands/PluginManager/Enable.cs
index 5c0201b64..4e400fe81 100644
--- a/EXILED/Exiled.Events/Commands/PluginManager/Enable.cs
+++ b/EXILED/Exiled.Events/Commands/PluginManager/Enable.cs
@@ -21,6 +21,7 @@ namespace Exiled.Events.Commands.PluginManager
///
/// The command to enable a plugin.
///
+ [CommandHandler(typeof(PluginManager))]
public sealed class Enable : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/PluginManager/Patches.cs b/EXILED/Exiled.Events/Commands/PluginManager/Patches.cs
index 9543e73aa..61d729f82 100644
--- a/EXILED/Exiled.Events/Commands/PluginManager/Patches.cs
+++ b/EXILED/Exiled.Events/Commands/PluginManager/Patches.cs
@@ -23,6 +23,7 @@ namespace Exiled.Events.Commands.PluginManager
///
/// The command to show all the patches done by plugins.
///
+ [CommandHandler(typeof(PluginManager))]
public sealed class Patches : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/PluginManager/PluginManager.cs b/EXILED/Exiled.Events/Commands/PluginManager/PluginManager.cs
index ba778d5f4..2a4a550b4 100644
--- a/EXILED/Exiled.Events/Commands/PluginManager/PluginManager.cs
+++ b/EXILED/Exiled.Events/Commands/PluginManager/PluginManager.cs
@@ -18,14 +18,6 @@ namespace Exiled.Events.Commands.PluginManager
[CommandHandler(typeof(GameConsoleCommandHandler))]
public class PluginManager : ParentCommand
{
- ///
- /// Initializes a new instance of the class.
- ///
- public PluginManager()
- {
- LoadGeneratedCommands();
- }
-
///
public override string Command { get; } = "pluginmanager";
@@ -38,10 +30,6 @@ public PluginManager()
///
public override void LoadGeneratedCommands()
{
- RegisterCommand(Show.Instance);
- RegisterCommand(Enable.Instance);
- RegisterCommand(Disable.Instance);
- RegisterCommand(Patches.Instance);
}
///
diff --git a/EXILED/Exiled.Events/Commands/PluginManager/Show.cs b/EXILED/Exiled.Events/Commands/PluginManager/Show.cs
index b703d44fc..cd7379932 100644
--- a/EXILED/Exiled.Events/Commands/PluginManager/Show.cs
+++ b/EXILED/Exiled.Events/Commands/PluginManager/Show.cs
@@ -24,6 +24,7 @@ namespace Exiled.Events.Commands.PluginManager
///
/// The command to show all plugins.
///
+ [CommandHandler(typeof(PluginManager))]
public sealed class Show : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/Reload/All.cs b/EXILED/Exiled.Events/Commands/Reload/All.cs
index 124114e7e..a46af1f5e 100644
--- a/EXILED/Exiled.Events/Commands/Reload/All.cs
+++ b/EXILED/Exiled.Events/Commands/Reload/All.cs
@@ -14,6 +14,7 @@ namespace Exiled.Events.Commands.Reload
///
/// The reload all command.
///
+ [CommandHandler(typeof(Reload))]
public class All : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/Reload/Configs.cs b/EXILED/Exiled.Events/Commands/Reload/Configs.cs
index 81ab11e79..2c6ed0a27 100644
--- a/EXILED/Exiled.Events/Commands/Reload/Configs.cs
+++ b/EXILED/Exiled.Events/Commands/Reload/Configs.cs
@@ -20,6 +20,7 @@ namespace Exiled.Events.Commands.Reload
///
/// The reload configs command.
///
+ [CommandHandler(typeof(Reload))]
public class Configs : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/Reload/GamePlay.cs b/EXILED/Exiled.Events/Commands/Reload/GamePlay.cs
index babd4c5bd..02a02460a 100644
--- a/EXILED/Exiled.Events/Commands/Reload/GamePlay.cs
+++ b/EXILED/Exiled.Events/Commands/Reload/GamePlay.cs
@@ -18,6 +18,7 @@ namespace Exiled.Events.Commands.Reload
///
/// The reload gameplay command.
///
+ [CommandHandler(typeof(Reload))]
public class GamePlay : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/Reload/Permissions.cs b/EXILED/Exiled.Events/Commands/Reload/Permissions.cs
index 1f3943a82..a0e9b9ec4 100644
--- a/EXILED/Exiled.Events/Commands/Reload/Permissions.cs
+++ b/EXILED/Exiled.Events/Commands/Reload/Permissions.cs
@@ -17,6 +17,7 @@ namespace Exiled.Events.Commands.Reload
///
/// The reload permissions command.
///
+ [CommandHandler(typeof(Reload))]
public class Permissions : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/Reload/Plugins.cs b/EXILED/Exiled.Events/Commands/Reload/Plugins.cs
index 1a1c14472..f41d6027c 100644
--- a/EXILED/Exiled.Events/Commands/Reload/Plugins.cs
+++ b/EXILED/Exiled.Events/Commands/Reload/Plugins.cs
@@ -19,6 +19,7 @@ namespace Exiled.Events.Commands.Reload
///
/// The reload plugins command.
///
+ [CommandHandler(typeof(Reload))]
public class Plugins : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/Reload/Reload.cs b/EXILED/Exiled.Events/Commands/Reload/Reload.cs
index bf139a7fd..b68927f63 100644
--- a/EXILED/Exiled.Events/Commands/Reload/Reload.cs
+++ b/EXILED/Exiled.Events/Commands/Reload/Reload.cs
@@ -18,14 +18,6 @@ namespace Exiled.Events.Commands.Reload
[CommandHandler(typeof(GameConsoleCommandHandler))]
public class Reload : ParentCommand
{
- ///
- /// Initializes a new instance of the class.
- ///
- public Reload()
- {
- LoadGeneratedCommands();
- }
-
///
public override string Command { get; } = "reload";
@@ -38,13 +30,6 @@ public Reload()
///
public override void LoadGeneratedCommands()
{
- RegisterCommand(All.Instance);
- RegisterCommand(Configs.Instance);
- RegisterCommand(Translations.Instance);
- RegisterCommand(Plugins.Instance);
- RegisterCommand(GamePlay.Instance);
- RegisterCommand(RemoteAdmin.Instance);
- RegisterCommand(Permissions.Instance);
}
///
diff --git a/EXILED/Exiled.Events/Commands/Reload/RemoteAdmin.cs b/EXILED/Exiled.Events/Commands/Reload/RemoteAdmin.cs
index 4777a7e4b..7c21428b3 100644
--- a/EXILED/Exiled.Events/Commands/Reload/RemoteAdmin.cs
+++ b/EXILED/Exiled.Events/Commands/Reload/RemoteAdmin.cs
@@ -18,6 +18,7 @@ namespace Exiled.Events.Commands.Reload
///
/// The reload remoteadmin command.
///
+ [CommandHandler(typeof(Reload))]
public class RemoteAdmin : ICommand
{
///
diff --git a/EXILED/Exiled.Events/Commands/Reload/Translations.cs b/EXILED/Exiled.Events/Commands/Reload/Translations.cs
index 68d6f6698..621a7036b 100644
--- a/EXILED/Exiled.Events/Commands/Reload/Translations.cs
+++ b/EXILED/Exiled.Events/Commands/Reload/Translations.cs
@@ -20,6 +20,7 @@ namespace Exiled.Events.Commands.Reload
///
/// The reload translations command.
///
+ [CommandHandler(typeof(Reload))]
public class Translations : ICommand
{
///
From 56b409845e10a8b65b6fb390c2c8abe53d072f05 Mon Sep 17 00:00:00 2001
From: ZeroTwo <63092138+NotZer0Two@users.noreply.github.com>
Date: Mon, 23 Sep 2024 19:33:39 +0200
Subject: [PATCH 57/63] Allow `ID_Dedicated`/`null` for `Npc.UserId` Parameter
(#75)
* Npc
* Fix Build Error
* Update EXILED/Exiled.API/Features/Npc.cs
Co-authored-by: Alex Rouse <123724383+ALEXWARELLC@users.noreply.github.com>
* Fix for the PR
* Fix Pr
* Fixing a small issue if the player is choosing something not ID_DEDICATED
* Fix
* forgot
---------
Co-authored-by: Alex Rouse <123724383+ALEXWARELLC@users.noreply.github.com>
---
EXILED/Exiled.API/Features/Npc.cs | 66 +++++++++++++++++++------------
1 file changed, 41 insertions(+), 25 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Npc.cs b/EXILED/Exiled.API/Features/Npc.cs
index 52f339dea..82a6c7374 100644
--- a/EXILED/Exiled.API/Features/Npc.cs
+++ b/EXILED/Exiled.API/Features/Npc.cs
@@ -11,7 +11,9 @@ namespace Exiled.API.Features
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Reflection;
+ using CentralAuth;
using CommandSystem;
using Exiled.API.Enums;
using Exiled.API.Extensions;
@@ -140,55 +142,69 @@ public override Vector3 Position
/// The userID of the NPC.
/// The position to spawn the NPC.
/// The spawned.
- public static Npc Spawn(string name, RoleTypeId role, int id = 0, string userId = "", Vector3? position = null)
+ public static Npc Spawn(string name, RoleTypeId role, int id = 0, string userId = PlayerAuthenticationManager.DedicatedId, Vector3? position = null)
{
- GameObject newObject = Object.Instantiate(NetworkManager.singleton.playerPrefab);
+ GameObject newObject = UnityEngine.Object.Instantiate(Mirror.NetworkManager.singleton.playerPrefab);
+
Npc npc = new(newObject)
{
- IsVerified = true,
IsNPC = true,
};
- try
- {
- npc.ReferenceHub.roleManager.InitializeNewRole(RoleTypeId.None, RoleChangeReason.None);
- }
- catch (Exception e)
+
+ if (!RecyclablePlayerId.FreeIds.Contains(id) && RecyclablePlayerId._autoIncrement >= id)
{
- Log.Debug($"Ignore: {e}");
+ Log.Warn($"{Assembly.GetCallingAssembly().GetName().Name} tried to spawn an NPC with a duplicate PlayerID. Using auto-incremented ID instead to avoid an ID clash.");
+ id = new RecyclablePlayerId(true).Value;
}
- if (RecyclablePlayerId.FreeIds.Contains(id))
+ try
{
- RecyclablePlayerId.FreeIds.RemoveFromQueue(id);
+ if (userId == PlayerAuthenticationManager.DedicatedId)
+ {
+ npc.ReferenceHub.authManager.SyncedUserId = userId;
+ try
+ {
+ npc.ReferenceHub.authManager.InstanceMode = ClientInstanceMode.DedicatedServer;
+ }
+ catch (Exception e)
+ {
+ Log.Debug($"Ignore: {e.Message}");
+ }
+ }
+ else
+ {
+ npc.ReferenceHub.authManager.InstanceMode = ClientInstanceMode.Unverified;
+ npc.ReferenceHub.authManager._privUserId = userId == string.Empty ? $"Dummy@localhost" : userId;
+ }
}
- else if (RecyclablePlayerId._autoIncrement >= id)
+ catch (Exception e)
{
- RecyclablePlayerId._autoIncrement = id = RecyclablePlayerId._autoIncrement + 1;
+ Log.Debug($"Ignore: {e.Message}");
}
- FakeConnection fakeConnection = new(id);
- NetworkServer.AddPlayerForConnection(fakeConnection, newObject);
try
{
- npc.ReferenceHub.authManager.UserId = string.IsNullOrEmpty(userId) ? $"Dummy@localhost" : userId;
+ npc.ReferenceHub.roleManager.InitializeNewRole(RoleTypeId.None, RoleChangeReason.None);
}
catch (Exception e)
{
- Log.Debug($"Ignore: {e}");
+ Log.Debug($"Ignore: {e.Message}");
}
+ FakeConnection fakeConnection = new(id);
+ NetworkServer.AddPlayerForConnection(fakeConnection, newObject);
+
npc.ReferenceHub.nicknameSync.Network_myNickSync = name;
Dictionary.Add(newObject, npc);
- Timing.CallDelayed(
- 0.3f,
- () =>
- {
- npc.Role.Set(role, SpawnReason.RoundStart, position is null ? RoleSpawnFlags.All : RoleSpawnFlags.AssignInventory);
- });
+ Timing.CallDelayed(0.5f, () =>
+ {
+ npc.Role.Set(role, SpawnReason.RoundStart, position is null ? RoleSpawnFlags.All : RoleSpawnFlags.AssignInventory);
+
+ if (position is not null)
+ npc.Position = position.Value;
+ });
- if (position is not null)
- Timing.CallDelayed(0.5f, () => npc.Position = position.Value);
return npc;
}
From 25cedad3241d1f373d6fd59e75ee8cce5c935ef3 Mon Sep 17 00:00:00 2001
From: SrLicht
Date: Mon, 23 Sep 2024 14:33:53 -0300
Subject: [PATCH 58/63] Update Exiled.Loader.csproj (#80)
* It gives me anxiety to use something that can be a nuget.
Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com>
---
EXILED/Exiled.Loader/Exiled.Loader.csproj | 1 +
1 file changed, 1 insertion(+)
diff --git a/EXILED/Exiled.Loader/Exiled.Loader.csproj b/EXILED/Exiled.Loader/Exiled.Loader.csproj
index 4a48187e2..cb3a04e39 100644
--- a/EXILED/Exiled.Loader/Exiled.Loader.csproj
+++ b/EXILED/Exiled.Loader/Exiled.Loader.csproj
@@ -17,6 +17,7 @@
+
From e533dd69f5eefbe9f946de830449c7e4699dd622 Mon Sep 17 00:00:00 2001
From: IRacle <79921583+IRacle1@users.noreply.github.com>
Date: Mon, 23 Sep 2024 20:36:17 +0300
Subject: [PATCH 59/63] [Events] Fix crash (#96)
* fix
* oh, already made in #95
---
EXILED/Exiled.Events/Patches/Generic/DoorList.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.Events/Patches/Generic/DoorList.cs b/EXILED/Exiled.Events/Patches/Generic/DoorList.cs
index b8b653455..a00a33337 100644
--- a/EXILED/Exiled.Events/Patches/Generic/DoorList.cs
+++ b/EXILED/Exiled.Events/Patches/Generic/DoorList.cs
@@ -36,7 +36,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable
Date: Mon, 23 Sep 2024 20:40:37 +0300
Subject: [PATCH 60/63] Random fixes (#103)
* fixes
* also
---
EXILED/Exiled.API/Features/Items/Firearm.cs | 14 +++-----------
EXILED/Exiled.API/Features/Items/Usable.cs | 2 --
EXILED/Exiled.API/Features/Player.cs | 6 +++---
.../EventArgs/Server/UnbannedEventArgs.cs | 12 ++++++------
.../EventArgs/Server/UnbanningEventArgs.cs | 12 ++++++------
.../Exiled.Events/Patches/Events/Server/Unban.cs | 9 ++++-----
6 files changed, 22 insertions(+), 33 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Items/Firearm.cs b/EXILED/Exiled.API/Features/Items/Firearm.cs
index e05a9180f..f9b4b2cec 100644
--- a/EXILED/Exiled.API/Features/Items/Firearm.cs
+++ b/EXILED/Exiled.API/Features/Items/Firearm.cs
@@ -633,18 +633,10 @@ internal override void ChangeOwner(Player oldOwner, Player newOwner)
{
Base.Owner = newOwner.ReferenceHub;
- Base.HitregModule = Base switch
+ if (Base.HitregModule is StandardHitregBase hitReg)
{
- AutomaticFirearm automaticFirearm =>
- new SingleBulletHitreg(automaticFirearm, automaticFirearm.Owner, automaticFirearm._recoilPattern),
- Shotgun shotgun =>
- new BuckshotHitreg(shotgun, shotgun.Owner, shotgun.GetBuckshotPattern),
- ParticleDisruptor particleDisruptor =>
- new DisruptorHitreg(particleDisruptor, particleDisruptor.Owner, particleDisruptor._explosionSettings),
- Revolver revolver =>
- new SingleBulletHitreg(revolver, revolver.Owner),
- _ => throw new NotImplementedException("Should never happend"),
- };
+ hitReg.Hub = Base.Owner;
+ }
Base._sendStatusNextFrame = true;
Base._footprintValid = false;
diff --git a/EXILED/Exiled.API/Features/Items/Usable.cs b/EXILED/Exiled.API/Features/Items/Usable.cs
index c6c7f1b33..aba803d38 100644
--- a/EXILED/Exiled.API/Features/Items/Usable.cs
+++ b/EXILED/Exiled.API/Features/Items/Usable.cs
@@ -115,8 +115,6 @@ public override Pickup CreatePickup(Vector3 position, Quaternion rotation = defa
ItemPickupBase ipb = InventoryExtensions.ServerCreatePickup(Base, info, position, rotation);
- Base.OnRemoved(ipb);
-
Pickup pickup = Pickup.Get(ipb);
if (spawn)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 6c6c88702..9e55712ee 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -2001,8 +2001,8 @@ public bool RemoveItem(Item item, bool destroy = true)
if (item.Serial == Inventory.CurItem.SerialNumber)
Inventory.NetworkCurItem = ItemIdentifier.None;
+ ItemsValue.Remove(item);
Inventory.UserInventory.Items.Remove(item.Serial);
- typeof(InventoryExtensions).InvokeStaticEvent(nameof(InventoryExtensions.OnItemRemoved), new object[] { ReferenceHub, item.Base, null });
Inventory.SendItemsNextFrame = true;
}
@@ -2974,8 +2974,8 @@ public void ClearInventory(bool destroy = true)
///
public void ClearItems(bool destroy = true)
{
- if (CurrentArmor is not null)
- CurrentArmor.RemoveExcessOnDrop = true;
+ if (CurrentArmor is Armor armor)
+ armor.RemoveExcessOnDrop = false;
while (Items.Count > 0)
RemoveItem(Items.ElementAt(0), destroy);
diff --git a/EXILED/Exiled.Events/EventArgs/Server/UnbannedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/UnbannedEventArgs.cs
index f1181a3b9..a88a5f3a4 100644
--- a/EXILED/Exiled.Events/EventArgs/Server/UnbannedEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Server/UnbannedEventArgs.cs
@@ -1,4 +1,4 @@
-// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
//
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
@@ -15,18 +15,18 @@ public class UnbannedEventArgs
///
/// Initializes a new instance of the class.
///
- ///
+ ///
///
- public UnbannedEventArgs(string details, BanHandler.BanType banType)
+ public UnbannedEventArgs(string id, BanHandler.BanType banType)
{
- BanDetails = BanHandler.ProcessBanItem(details, banType);
+ TargetId = id;
BanType = banType;
}
///
- /// Gets the ban details.
+ /// Gets or sets the target player id.
///
- public BanDetails BanDetails { get; }
+ public string TargetId { get; set; }
///
/// Gets the ban type.
diff --git a/EXILED/Exiled.Events/EventArgs/Server/UnbanningEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/UnbanningEventArgs.cs
index aa23690e6..9822622cd 100644
--- a/EXILED/Exiled.Events/EventArgs/Server/UnbanningEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Server/UnbanningEventArgs.cs
@@ -1,4 +1,4 @@
-// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
//
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
@@ -17,20 +17,20 @@ public class UnbanningEventArgs : IDeniableEvent
///
/// Initializes a new instance of the class.
///
- ///
+ ///
///
///
- public UnbanningEventArgs(string banDetails, BanHandler.BanType banType, bool isAllowed = true)
+ public UnbanningEventArgs(string id, BanHandler.BanType banType, bool isAllowed = true)
{
- BanDetails = BanHandler.ProcessBanItem(banDetails, banType);
+ TargetId = id;
BanType = banType;
IsAllowed = isAllowed;
}
///
- /// Gets or sets the ban details.
+ /// Gets or sets the target player id.
///
- public BanDetails BanDetails { get; set; }
+ public string TargetId { get; set; }
///
/// Gets the ban type.
diff --git a/EXILED/Exiled.Events/Patches/Events/Server/Unban.cs b/EXILED/Exiled.Events/Patches/Events/Server/Unban.cs
index 5eb89d224..aa367c711 100644
--- a/EXILED/Exiled.Events/Patches/Events/Server/Unban.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Server/Unban.cs
@@ -1,4 +1,4 @@
-// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
//
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
@@ -61,11 +61,10 @@ private static IEnumerable Transpiler(IEnumerable
Date: Mon, 23 Sep 2024 13:58:47 -0400
Subject: [PATCH 61/63] Adding Turning On All Lights (#105)
---
EXILED/Exiled.API/Features/Map.cs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs
index 9df9bbd37..d0b31f391 100644
--- a/EXILED/Exiled.API/Features/Map.cs
+++ b/EXILED/Exiled.API/Features/Map.cs
@@ -175,6 +175,12 @@ public static void ShowHint(string message, float duration = 3f)
///
public static void StartDecontamination() => DecontaminationController.Singleton.ForceDecontamination();
+ ///
+ /// Turns on all lights in the facility.
+ ///
+ /// The s to affect.
+ public static void TurnOnAllLights(IEnumerable zoneTypes) => TurnOffAllLights(0, zoneTypes);
+
///
/// Turns off all lights in the facility.
///
From c91a606a3652e6e9e6cab6c479ac6231b8a292b4 Mon Sep 17 00:00:00 2001
From: Panikorovskii Vladislav <68610520+bladuk@users.noreply.github.com>
Date: Mon, 23 Sep 2024 21:43:45 +0300
Subject: [PATCH 62/63] `[EXILED::Events]` Introduce `hub install` command
(#101)
* feat: introduce plugin installation command
* fix: fix build errors
wtf was this actually
---
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 | 116 ++++++++++++++++++
EXILED/Exiled.Events/Exiled.Events.csproj | 1 +
EXILED/Exiled.Loader/LinuxPermission.cs | 4 +-
6 files changed, 269 insertions(+), 2 deletions(-)
create mode 100644 EXILED/Exiled.Events/Commands/Hub/Hub.cs
create mode 100644 EXILED/Exiled.Events/Commands/Hub/HubApi/ApiProvider.cs
create mode 100644 EXILED/Exiled.Events/Commands/Hub/HubApi/Models/HubPlugin.cs
create mode 100644 EXILED/Exiled.Events/Commands/Hub/Install.cs
diff --git a/EXILED/Exiled.Events/Commands/Hub/Hub.cs b/EXILED/Exiled.Events/Commands/Hub/Hub.cs
new file mode 100644
index 000000000..ba36480fa
--- /dev/null
+++ b/EXILED/Exiled.Events/Commands/Hub/Hub.cs
@@ -0,0 +1,51 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled 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
new file mode 100644
index 000000000..ad2f59223
--- /dev/null
+++ b/EXILED/Exiled.Events/Commands/Hub/HubApi/ApiProvider.cs
@@ -0,0 +1,64 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled 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
new file mode 100644
index 000000000..cac15a689
--- /dev/null
+++ b/EXILED/Exiled.Events/Commands/Hub/HubApi/Models/HubPlugin.cs
@@ -0,0 +1,35 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled 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
new file mode 100644
index 000000000..bdcd7e18f
--- /dev/null
+++ b/EXILED/Exiled.Events/Commands/Hub/Install.cs
@@ -0,0 +1,116 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled 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;
+ }
+
+ Log.Info($"Downloading release \"{releaseToDownload.TagName}\". Found {releaseToDownload.Assets.Length} asset(s) to download.");
+
+ foreach (ReleaseAsset asset in releaseToDownload.Assets)
+ {
+ 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/Exiled.Events.csproj b/EXILED/Exiled.Events/Exiled.Events.csproj
index 421dc0108..aa7f9ff4b 100644
--- a/EXILED/Exiled.Events/Exiled.Events.csproj
+++ b/EXILED/Exiled.Events/Exiled.Events.csproj
@@ -30,6 +30,7 @@
+
diff --git a/EXILED/Exiled.Loader/LinuxPermission.cs b/EXILED/Exiled.Loader/LinuxPermission.cs
index 1c47e340b..d5bf1da12 100644
--- a/EXILED/Exiled.Loader/LinuxPermission.cs
+++ b/EXILED/Exiled.Loader/LinuxPermission.cs
@@ -12,13 +12,13 @@ namespace Exiled.Loader
///
/// A set of extensions to easily interact with Linux/Unix environment.
///
- internal static class LinuxPermission
+ public static class LinuxPermission
{
///
/// Sets rw and execution permissions given a file, for the current user and group.
///
/// The path of the file.
- internal static void SetFileUserAndGroupReadWriteExecutePermissions(string path)
+ public static void SetFileUserAndGroupReadWriteExecutePermissions(string path)
{
UnixFileSystemInfo.GetFileSystemEntry(path).FileAccessPermissions |= FileAccessPermissions.UserReadWriteExecute | FileAccessPermissions.GroupReadWriteExecute;
}
From 6464c462cf97a63483e9c6a7d0cab76cffecc392 Mon Sep 17 00:00:00 2001
From: Jesus QC <69375249+Jesus-QC@users.noreply.github.com>
Date: Mon, 23 Sep 2024 20:46:11 +0200
Subject: [PATCH 63/63] version bump
---
EXILED/EXILED.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/EXILED/EXILED.props b/EXILED/EXILED.props
index e1ff99890..f68f5ffc8 100644
--- a/EXILED/EXILED.props
+++ b/EXILED/EXILED.props
@@ -15,7 +15,7 @@
- 8.12.0-rc.3
+ 8.12.0
false