diff --git a/EXILED/Exiled.API/Enums/CameraType.cs b/EXILED/Exiled.API/Enums/CameraType.cs index 535e7366ce..1a193d16db 100644 --- a/EXILED/Exiled.API/Enums/CameraType.cs +++ b/EXILED/Exiled.API/Enums/CameraType.cs @@ -159,6 +159,8 @@ public enum CameraType EzGateAElevators, EzGateBInterior, EzGateBSide, + EzGateAStairwell, + EzGateAUpper, #endregion } } diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs index 605e6466c0..3ba47fd9a8 100644 --- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs +++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs @@ -17,6 +17,7 @@ namespace Exiled.API.Extensions using AdminToys; using AudioPooling; + using Cassie; using CustomPlayerEffects; using Exiled.API.Enums; using Exiled.API.Features.Items; @@ -512,13 +513,12 @@ public static void ResyncKeycardPickup(CustomKeycardPickup customKeycard) /// Same on 's isSubtitles. public static void PlayCassieAnnouncement(this Player player, string words, bool makeHold = false, bool makeNoise = true, bool isSubtitles = false) { - foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) - { - if (controller != null) - { - SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), words, makeHold, makeNoise, isSubtitles); - } - } + CassieAnnouncement announcement = new(new CassieTtsPayload(words, isSubtitles, makeHold), 0, makeNoise ? 1 : 0); + + // processes makeNoise + announcement.OnStartedPlaying(); + + announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); } /// @@ -533,23 +533,12 @@ public static void PlayCassieAnnouncement(this Player player, string words, bool /// Same on 's isSubtitles. public static void MessageTranslated(this Player player, string words, string translation, string customSubtitles, bool makeHold = false, bool makeNoise = true, bool isSubtitles = true) { - StringBuilder announcement = StringBuilderPool.Pool.Get(); + CassieAnnouncement announcement = new(new CassieTtsPayload(words, customSubtitles, makeHold), 0, makeNoise ? 1 : 0); - string[] cassies = words.Split('\n'); - string[] translations = translation.Split('\n'); + // processes makeNoise + announcement.OnStartedPlaying(); - for (int i = 0; i < cassies.Length; i++) - announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); - - string message = StringBuilderPool.Pool.ToStringReturn(announcement); - - foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) - { - if (controller != null) - { - SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), message, makeHold, makeNoise, isSubtitles, customSubtitles); - } - } + announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); } /// diff --git a/EXILED/Exiled.API/Features/Camera.cs b/EXILED/Exiled.API/Features/Camera.cs index fca5cbbc73..4601a5ada1 100644 --- a/EXILED/Exiled.API/Features/Camera.cs +++ b/EXILED/Exiled.API/Features/Camera.cs @@ -143,6 +143,8 @@ public class Camera : IWrapper, IWorldSpace ["GATE A ELEVATORS"] = CameraType.EzGateAElevators, ["GATE B INTERIOR"] = CameraType.EzGateBInterior, ["GATE B SIDE"] = CameraType.EzGateBSide, + ["GATE A STAIRWELL"] = CameraType.EzGateAStairwell, + ["GATE A UPPER"] = CameraType.EzGateAUpper, // CustomCamera ["EZ ARM CAMERA TOY"] = CameraType.EzArmCameraToy, diff --git a/EXILED/Exiled.API/Features/Cassie.cs b/EXILED/Exiled.API/Features/Cassie.cs index 0730f9a5a9..42f0911ddd 100644 --- a/EXILED/Exiled.API/Features/Cassie.cs +++ b/EXILED/Exiled.API/Features/Cassie.cs @@ -7,19 +7,19 @@ namespace Exiled.API.Features { + using System; using System.Collections.Generic; using System.Linq; using System.Text; using Exiled.API.Features.Pools; - + using global::Cassie; + using global::Cassie.Interpreters; using MEC; - using PlayerRoles; - using PlayerStatsSystem; - using Respawning; + using Respawning.NamingRules; using CustomFirearmHandler = DamageHandlers.FirearmDamageHandler; using CustomHandlerBase = DamageHandlers.DamageHandlerBase; @@ -29,20 +29,15 @@ namespace Exiled.API.Features /// public static class Cassie { - /// - /// Gets the singleton. - /// - public static NineTailedFoxAnnouncer Announcer => NineTailedFoxAnnouncer.singleton; - /// /// Gets a value indicating whether C.A.S.S.I.E is currently announcing. Does not include decontamination or Alpha Warhead Messages. /// - public static bool IsSpeaking => Announcer.queue.Count != 0; + public static bool IsSpeaking => CassieAnnouncementDispatcher.AllAnnouncements.Count != 0; /// - /// Gets a of objects that C.A.S.S.I.E recognizes. + /// Gets a of objects that C.A.S.S.I.E recognizes. /// - public static IReadOnlyCollection VoiceLines => Announcer.voiceLines; + public static IReadOnlyCollection VoiceLines => CassieAnnouncementDispatcher.AllAnnouncements; /// /// Reproduce a non-glitched C.A.S.S.I.E message. @@ -52,7 +47,7 @@ public static class Cassie /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void Message(string message, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles); + new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); /// /// Reproduce a non-glitched C.A.S.S.I.E message with a possibility to custom the subtitles. @@ -70,7 +65,7 @@ public static void MessageTranslated(string message, string translation, bool is for (int i = 0; i < cassies.Length; i++) announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); - RespawnEffectsController.PlayCassieAnnouncement(announcement.ToString(), isHeld, isNoisy, isSubtitles); + new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); StringBuilderPool.Pool.Return(announcement); } @@ -81,7 +76,7 @@ public static void MessageTranslated(string message, string translation, bool is /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void GlitchyMessage(string message, float glitchChance, float jamChance) => - Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance); + new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue(); /// /// Reproduce a non-glitched C.A.S.S.I.E message after a certain amount of seconds. @@ -92,7 +87,7 @@ public static void GlitchyMessage(string message, float glitchChance, float jamC /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void DelayedMessage(string message, float delay, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - Timing.CallDelayed(delay, () => RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles)); + Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue()); /// /// Reproduce a glitchy C.A.S.S.I.E announcement after a certain period of seconds. @@ -102,17 +97,45 @@ public static void DelayedMessage(string message, float delay, bool isHeld = fal /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void DelayedGlitchyMessage(string message, float delay, float glitchChance, float jamChance) => - Timing.CallDelayed(delay, () => Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance)); + Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue()); /// /// Calculates the duration of a C.A.S.S.I.E message. /// /// The message, which duration will be calculated. - /// Determines if a number won't be converted to its full pronunciation. - /// The speed of the message. + /// An obsolete parameter. + /// Another obsolete parameter. /// Duration (in seconds) of specified message. - public static float CalculateDuration(string message, bool rawNumber = false, float speed = 1f) - => Announcer.CalculateDuration(message, rawNumber, speed); + public static float CalculateDuration(string message, bool obsolete1, float obsolete2) + { + if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) + { + return 0; + } + + float value = 0; + string[] lines = message.Split(' ', StringSplitOptions.RemoveEmptyEntries); + + CassiePlaybackModifiers modifiers = new(); + StringBuilder builder = StringBuilderPool.Pool.Get(); + + for (int i = 0; i < lines.Length; i++) + { + foreach (CassieInterpreter interpreter in CassieTtsAnnouncer.Interpreters) + { + bool halt; + foreach (CassieInterpreter.Result result in interpreter.GetResults(cassieLineDatabase, ref modifiers, lines[i], builder, out halt)) + { + value += (float)result.Modifiers.GetTimeUntilNextWord(result.Line); + } + + if (halt) + break; + } + } + + return value; + } /// /// Converts a into a Cassie-Readable CONTAINMENTUNIT. @@ -120,8 +143,16 @@ public static float CalculateDuration(string message, bool rawNumber = false, fl /// . /// Unit Name. /// Containment Unit text. - public static string ConvertTeam(Team team, string unitName) - => NineTailedFoxAnnouncer.ConvertTeam(team, unitName); + public static string ConvertTeam(Team team, string unitName) => team switch + { + Team.FoundationForces when NamingRulesManager.TryGetNamingRule(team, out UnitNamingRule unitNamingRule) => "CONTAINMENTUNIT " + unitNamingRule.TranslateToCassie(unitName), + Team.FoundationForces => "CONTAINMENTUNIT UNKNOWN", + Team.ChaosInsurgency => "BY CHAOSINSURGENCY", + Team.Scientists => "BY SCIENCE PERSONNEL", + Team.ClassD => "BY CLASSD PERSONNEL", + Team.Flamingos => "BY FLAMINGOS", + _ => "UNKNOWN", + }; /// /// Converts a number into a Cassie-Readable String. @@ -129,7 +160,23 @@ public static string ConvertTeam(Team team, string unitName) /// Number to convert. /// A CASSIE-readable representing the number. public static string ConvertNumber(int num) - => NineTailedFoxAnnouncer.ConvertNumber(num); + { + if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) + { + return string.Empty; + } + + NumberInterpreter numberInterpreter = (NumberInterpreter)CassieTtsAnnouncer.Interpreters.FirstOrDefault((CassieInterpreter x) => x is NumberInterpreter); + if (numberInterpreter == null) + { + return string.Empty; + } + + CassiePlaybackModifiers cassiePlaybackModifiers = default; + StringBuilder stringBuilder = new(); + numberInterpreter.GetResults(cassieLineDatabase, ref cassiePlaybackModifiers, num.ToString(), stringBuilder, out bool flag); + return stringBuilder.ToString(); + } /// /// Announce a SCP Termination. @@ -137,7 +184,7 @@ public static string ConvertNumber(int num) /// SCP to announce termination of. /// HitInformation. public static void ScpTermination(Player scp, DamageHandlerBase info) - => NineTailedFoxAnnouncer.AnnounceScpTermination(scp.ReferenceHub, info); + => CassieScpTerminationAnnouncement.AnnounceScpTermination(scp.ReferenceHub, info); /// /// Announces the termination of a custom SCP name. @@ -167,14 +214,14 @@ public static void CustomScpTermination(string scpName, CustomHandlerBase info) /// /// Clears the C.A.S.S.I.E queue. /// - public static void Clear() => RespawnEffectsController.ClearQueue(); + public static void Clear() => CassieAnnouncementDispatcher.ClearAll(); /// /// Gets a value indicating whether the given word is a valid C.A.S.S.I.E word. /// /// The word to check. /// if the word is valid; otherwise, . - public static bool IsValid(string word) => Announcer.voiceLines.Any(line => line.apiName.ToUpper() == word.ToUpper()); + public static bool IsValid(string word) => CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase) ? cassieLineDatabase.AllLines.Any(line => line.ApiName.ToUpper() == word.ToUpper()) : false; /// /// Gets a value indicating whether the given sentence is all valid C.A.S.S.I.E word. diff --git a/EXILED/Exiled.API/Features/Items/Jailbird.cs b/EXILED/Exiled.API/Features/Items/Jailbird.cs index b68a3473c2..7e67d0cc73 100644 --- a/EXILED/Exiled.API/Features/Items/Jailbird.cs +++ b/EXILED/Exiled.API/Features/Items/Jailbird.cs @@ -52,8 +52,8 @@ internal Jailbird() /// public float MeleeDamage { - get => Base._hitreg._damageMelee; - set => Base._hitreg._damageMelee = value; + get => Base.MeleeDamage; + set => Base.MeleeDamage = value; } /// @@ -61,8 +61,8 @@ public float MeleeDamage /// public float ChargeDamage { - get => Base._hitreg._damageCharge; - set => Base._hitreg._damageCharge = value; + get => Base._chargeDamage; + set => Base._chargeDamage = value; } /// @@ -70,8 +70,8 @@ public float ChargeDamage /// public float FlashDuration { - get => Base._hitreg._flashedDuration; - set => Base._hitreg._flashedDuration = value; + get => Base._flashedDuration; + set => Base._flashedDuration = value; } /// @@ -79,8 +79,8 @@ public float FlashDuration /// public float ConcussionDuration { - get => Base._hitreg._concussionDuration; - set => Base._hitreg._concussionDuration = value; + get => Base._concussionDuration; + set => Base._concussionDuration = value; } /// @@ -88,8 +88,8 @@ public float ConcussionDuration /// public float Radius { - get => Base._hitreg._hitregRadius; - set => Base._hitreg._hitregRadius = value; + get => Radius; + set => Radius = value; } /// @@ -97,10 +97,10 @@ public float Radius /// public float TotalDamageDealt { - get => Base._hitreg.TotalMeleeDamageDealt; + get => Base.TotalMeleeDamageDealt; set { - Base._hitreg.TotalMeleeDamageDealt = value; + Base.TotalMeleeDamageDealt = value; Base._deterioration.RecheckUsage(); } } diff --git a/EXILED/Exiled.API/Features/Lift.cs b/EXILED/Exiled.API/Features/Lift.cs index 469a33bd22..d191cd6764 100644 --- a/EXILED/Exiled.API/Features/Lift.cs +++ b/EXILED/Exiled.API/Features/Lift.cs @@ -47,6 +47,7 @@ public class Lift : IWrapper, IWorldSpace internal Lift(ElevatorChamber elevator) { Base = elevator; + ElevatorAutoReturn = elevator.GetComponent(); ElevatorChamberToLift.Add(elevator, this); internalDoorsList.AddRange(Elevator.AllElevatorDoors[Group]); @@ -73,6 +74,12 @@ internal Lift(ElevatorChamber elevator) /// public ElevatorChamber Base { get; } + /// + /// Gets the base . + /// + /// Would be null for any elevator that do not used . + public ElevatorAutoReturn ElevatorAutoReturn { get; } + /// /// Gets a value of the internal doors list. /// diff --git a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs index 0494d2e966..eaaf77cb7a 100644 --- a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs @@ -123,11 +123,11 @@ protected override void InitializeProperties(ItemBase itemBase) base.InitializeProperties(itemBase); if (itemBase is JailbirdItem jailbirdItem) { - MeleeDamage = jailbirdItem._hitreg._damageMelee; - ChargeDamage = jailbirdItem._hitreg._damageCharge; - FlashDuration = jailbirdItem._hitreg._flashedDuration; - ConcussionDuration = jailbirdItem._hitreg._concussionDuration; - Radius = jailbirdItem._hitreg._hitregRadius; + MeleeDamage = jailbirdItem.MeleeDamage; + ChargeDamage = jailbirdItem._chargeDamage; + FlashDuration = jailbirdItem._flashedDuration; + ConcussionDuration = jailbirdItem._concussionDuration; + Radius = Radius; } } } diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index ea317a5d5d..e635bfd650 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -1982,6 +1982,21 @@ public void Broadcast(Broadcast broadcast, bool shouldClearPrevious = false) Broadcast(broadcast.Duration, broadcast.Content, broadcast.Type, shouldClearPrevious); } + /// + /// Send an to the player. + /// + /// The to be broadcasted. + /// if Cassie failed to play it or it's play nothing, otherwise it's return the duration of the annoucement. + public float CassieAnnouncement(global::Cassie.CassieAnnouncement cassieAnnouncement) + { + global::Cassie.CassieAnnouncementDispatcher.CurrentAnnouncement.OnStartedPlaying(); + global::Cassie.CassieTtsPayload payload = cassieAnnouncement.Payload; + if (!global::Cassie.CassieTtsAnnouncer.TryPlay(payload, out float totalduration)) + return 0; + payload.SendToHubsConditionally(x => x == ReferenceHub); + return totalduration; + } + /// /// Drops an item from the player's inventory. /// diff --git a/EXILED/Exiled.API/Features/Recontainer.cs b/EXILED/Exiled.API/Features/Recontainer.cs index 17f59c97d5..dbc31a35bf 100644 --- a/EXILED/Exiled.API/Features/Recontainer.cs +++ b/EXILED/Exiled.API/Features/Recontainer.cs @@ -7,6 +7,7 @@ namespace Exiled.API.Features { + using System; using System.Collections.Generic; using System.Linq; @@ -33,7 +34,8 @@ public static class Recontainer /// /// Gets a value indicating whether the C.A.S.S.I.E is currently busy. /// - public static bool IsCassieBusy => Base.CassieBusy; + [Obsolete("Use Cassie.IsSpeaking instead")] + public static bool IsCassieBusy => Cassie.IsSpeaking; /// /// Gets a value about how many generator have been activated. @@ -61,11 +63,8 @@ public static bool IsContainmentZoneLocked /// /// Gets or sets the delay to wait before overcharging. /// - public static float OverchargeDelay - { - get => Base._activationDelay; - set => Base._activationDelay = value; - } + [Obsolete("Will be removed in Exiled 10, patch the Cassie079RecontainAnnouncement ctor if you need this functionality")] + public static float OverchargeDelay { get; set; } /// /// Gets or sets the lockdown duration. @@ -188,7 +187,7 @@ public static bool IsContainmentSequenceSuccessful /// /// The announcement to play. /// The glitchy multiplier. - public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, glitchyMultiplier); + public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, false, false, null); /// /// Begins the overcharge procedure. @@ -199,7 +198,6 @@ public static void BeginOvercharge(bool endOvercharge = true) Base.BeginOvercharge(); if (endOvercharge) { - Base._delayStopwatch.Stop(); Base._unlockStopwatch.Start(); } } @@ -228,7 +226,7 @@ public static void BeginOvercharge(bool endOvercharge = true) /// /// Begins the recontainment procedure. /// - public static void Recontain() => Base.Recontain(); + public static void Recontain() => Base.Recontain(false); /// /// Refreshes the activator. diff --git a/EXILED/Exiled.API/Features/Waves/TimedWave.cs b/EXILED/Exiled.API/Features/Waves/TimedWave.cs index 8856727c58..6e9a5c55bf 100644 --- a/EXILED/Exiled.API/Features/Waves/TimedWave.cs +++ b/EXILED/Exiled.API/Features/Waves/TimedWave.cs @@ -193,13 +193,13 @@ public static List GetTimedWaves() /// Plays the announcement for this wave. /// /// Wave must implement . - public void PlayAnnouncement() => Announcement?.PlayAnnouncement(new()); + public void PlayAnnouncement() => Announcement?.PlayAnnouncement([], Base as IAnnouncedWave); /// /// Plays the announcement for this wave. /// /// Wave must implement . /// The list of Player to spawn. - public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList()); + public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList(), Base as IAnnouncedWave); } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs index a8b986c171..abd2f4877f 100644 --- a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs @@ -7,39 +7,70 @@ namespace Exiled.Events.EventArgs.Cassie { + using System; + using System.Text; + + using Exiled.API.Features.Pools; + using global::Cassie; using Interfaces; + using Subtitles; /// /// Contains all the information after sending a C.A.S.S.I.E. message. /// public class SendingCassieMessageEventArgs : IDeniableEvent { + private readonly CassieAnnouncement announcement; + private readonly CassieTtsPayload payload; + + private string customSubtitles; + private float glitchScale; + /// /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - /// - /// - /// + /// The announcement to populate all properties from. + /// + /// /// - /// - /// - /// - /// - /// - /// - /// Indicates whether the event can be executed. - public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise, bool customAnnouncement, string customSubtitles, bool isAllowed = true) + public SendingCassieMessageEventArgs(CassieAnnouncement annc, bool isAllowed = true) { - Words = words; - CustomSubtitles = customSubtitles; - MakeHold = makeHold; - MakeNoise = makeNoise; - IsCustomAnnouncement = customAnnouncement; + announcement = annc; + payload = annc.Payload; + + Words = payload.Content; + switch (payload.SubtitleSource) + { + case CassieTtsPayload.SubtitleMode.None: + case CassieTtsPayload.SubtitleMode.Automatic: + CustomSubtitles = string.Empty; + break; + case CassieTtsPayload.SubtitleMode.Custom: + CustomSubtitles = payload._customSubtitle; + break; + case CassieTtsPayload.SubtitleMode.FromTranslation: + StringBuilder builder = StringBuilderPool.Pool.Get(); + SubtitleController controller = SubtitleController.Singleton; + + foreach (SubtitlePart part in payload._subtitleMessage.SubtitleParts) + { + Subtitle subtitle = controller.Subtitles[part.Subtitle]; + builder.Append(controller.GetTranslation(subtitle)); + } + + CustomSubtitles = StringBuilderPool.Pool.ToStringReturn(builder); + + break; + default: + CustomSubtitles = string.Empty; + break; + } + + MakeHold = payload.PlayBackground; + GlitchScale = annc.GlitchScale; + MakeNoise = annc.GlitchScale is not 0; + SubtitleSource = payload.SubtitleSource; + IsAllowed = isAllowed; } @@ -51,13 +82,38 @@ public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise /// /// Gets or sets the message subtitles. /// - public string CustomSubtitles { get; set; } + public string CustomSubtitles + { + get => customSubtitles; + set + { + if (customSubtitles != value) + SubtitleSource = CassieTtsPayload.SubtitleMode.Custom; + + customSubtitles = value; + } + } /// /// Gets or sets a value indicating whether the message should be held. /// public bool MakeHold { get; set; } + /// + /// Gets or sets a value controlling how glitchy this CASSIE message is. + /// + public float GlitchScale + { + get => glitchScale; + set + { + if (!MakeNoise && value is not 0) + MakeNoise = true; + + glitchScale = value; + } + } + /// /// Gets or sets a value indicating whether the message should make noise. /// @@ -69,8 +125,50 @@ public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise public bool IsAllowed { get; set; } /// - /// Gets or sets a value indicating whether the message can be sent. + /// Gets or sets a value indicating whether the event can be executed. /// + [Obsolete("Useless and will be removed in Exiled 10.")] public bool IsCustomAnnouncement { get; set; } + + /// + /// Gets or sets a value indicating where the subtitles for this message came from. + /// + public CassieTtsPayload.SubtitleMode SubtitleSource { get; set; } + + /// + /// Gets a consisting of all properties in this event. + /// + public CassieAnnouncement Announcement + { + get + { + CassieTtsPayload newPayload; + + // I love readonly fields :) + if (SubtitleSource is CassieTtsPayload.SubtitleMode.FromTranslation) + { + newPayload = new CassieTtsPayload(Words, MakeHold, payload._subtitleMessage.SubtitleParts); + } + else + { + if (SubtitleSource is CassieTtsPayload.SubtitleMode.Automatic) + newPayload = new CassieTtsPayload(Words, true, MakeHold); + else + newPayload = new CassieTtsPayload(Words, CustomSubtitles, MakeHold); + } + + return announcement switch + { + CassieScpTerminationAnnouncement => + + // this is disabled via patch b/c termination messages are not modifiable at the stage the SendCassieMessage patch is in. + throw new InvalidOperationException("SendCassieMessage was called for a SCP termination message!"), + + CassieWaveAnnouncement waveAnnc => new CassieWaveAnnouncement(waveAnnc.Wave, newPayload), + Cassie079RecontainAnnouncement recontainAnnc => new Cassie079RecontainAnnouncement(recontainAnnc._callback, false, newPayload), + _ => new CassieAnnouncement(newPayload, 0, GlitchScale / (API.Features.Warhead.IsDetonated ? 2F : 1F) * (MakeNoise ? 1F : 0F)), + }; + } + } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs index 4c43eb1df8..d8d38cc474 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs @@ -7,15 +7,13 @@ namespace Exiled.Events.EventArgs.Map { + using System; + using API.Features; using API.Features.DamageHandlers; using API.Features.Roles; - using Interfaces; - using CustomAttackerHandler = API.Features.DamageHandlers.AttackerDamageHandler; - using DamageHandlerBase = PlayerStatsSystem.DamageHandlerBase; - /// /// Contains all information before C.A.S.S.I.E announces an SCP termination. /// @@ -27,16 +25,14 @@ public class AnnouncingScpTerminationEventArgs : IAttackerEvent, IDeniableEvent /// /// /// - /// - /// + /// + /// /// - public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHandlerBase) + public AnnouncingScpTerminationEventArgs(Player scp, string terminationCause) { Player = scp; Role = scp.Role; - DamageHandler = new CustomDamageHandler(scp, damageHandlerBase); - Attacker = DamageHandler.BaseIs(out CustomAttackerHandler customAttackerHandler) ? customAttackerHandler.Attacker : null; - TerminationCause = damageHandlerBase.CassieDeathAnnouncement.Announcement; + TerminationCause = terminationCause; IsAllowed = true; } @@ -58,11 +54,13 @@ public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHan /// /// Gets the player who killed the SCP. /// + [Obsolete("Attacker can no longer be acquired for this event. This will be readded in a different event.")] public Player Attacker { get; } /// /// Gets or sets the . /// + [Obsolete("DamageHandler can no longer be acquired for this event. This will be readded in a different event.")] public CustomDamageHandler DamageHandler { get; set; } /// diff --git a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs index 0cb378ac02..1e7b55e3a8 100644 --- a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs +++ b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs @@ -8,87 +8,61 @@ namespace Exiled.Events.Patches.Events.Cassie { using System.Collections.Generic; + using System.Linq; using System.Reflection.Emit; using API.Features.Pools; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Cassie; - + using global::Cassie; using Handlers; - using HarmonyLib; using Respawning; using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Cassie), nameof(Cassie.SendingCassieMessage))] - [HarmonyPatch(typeof(RespawnEffectsController), nameof(RespawnEffectsController.PlayCassieAnnouncement))] + [HarmonyPatch(typeof(CassieAnnouncementDispatcher), nameof(CassieAnnouncementDispatcher.PlayNewAnnouncement))] internal static class SendingCassieMessage { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); + Label skipLabel = generator.DefineLabel(); Label returnLabel = generator.DefineLabel(); + newInstructions[0].WithLabels(skipLabel); + newInstructions.InsertRange( 0, new CodeInstruction[] { - // words new(OpCodes.Ldarg_0), + new(OpCodes.Isinst, typeof(CassieScpTerminationAnnouncement)), + new(OpCodes.Brtrue_S, skipLabel), - // makeHold - new(OpCodes.Ldarg_1), - - // makeNoise - new(OpCodes.Ldarg_2), - - // customAnnouncement - new(OpCodes.Ldarg_3), - - // customSubtitles - new(OpCodes.Ldarg_S, 4), + new(OpCodes.Ldarg_0), // isAllowed new(OpCodes.Ldc_I4_1), - // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(string, bool, bool, bool, string, bool); - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs))[0]), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Dup), + // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(CassieAnnouncement, bool); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs)).Single(ctor => ctor.GetParameters().Length == 2)), new(OpCodes.Dup), new(OpCodes.Dup), // Cassie.OnSendingCassieMessage(ev); new(OpCodes.Call, Method(typeof(Cassie), nameof(Cassie.OnSendingCassieMessage))), - // words = ev.Words - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Words))), + // annc = ev.Announcement + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Announcement))), new(OpCodes.Starg_S, 0), - // makeHold = ev.MakeHold - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeHold))), - new(OpCodes.Starg_S, 1), - - // makeNoise = ev.MakeNoise - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeNoise))), - new(OpCodes.Starg_S, 2), - - // customAnnouncement = ev.IsCustomAnnouncement - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsCustomAnnouncement))), - new(OpCodes.Starg_S, 3), - - // customSubtitles = ev.CustomSubtitles - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.CustomSubtitles))), - new(OpCodes.Starg_S, 4), - // if (!IsAllowed) // return; new(OpCodes.Callvirt, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsAllowed))), diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs index 0d53ebeefb..3033a0327d 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs @@ -7,6 +7,7 @@ namespace Exiled.Events.Patches.Events.Map { + using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; @@ -17,11 +18,12 @@ namespace Exiled.Events.Patches.Events.Map using Exiled.Events.EventArgs.Map; using HarmonyLib; using Respawning.Announcements; + using Subtitles; using static HarmonyLib.AccessTools; /// - /// Patches and + /// Patches and /// to add event. /// [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] @@ -30,8 +32,8 @@ internal static class AnnouncingChaosEntrance { private static IEnumerable TargetMethods() { - yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncementString)); - yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncementString)); + yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncement)); + yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncement)); } private static IEnumerable Transpiler(IEnumerable instruction, ILGenerator generator) @@ -70,6 +72,9 @@ private static IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncementString))] + [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncement))] internal static class AnnouncingNtfEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -39,8 +40,8 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Stloc_3) + offset; + int offset = 2; + int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(UnitNamingRule), nameof(UnitNamingRule.TranslateToCassie)))) + offset; newInstructions.InsertRange( index, @@ -50,10 +51,10 @@ private static IEnumerable Transpiler(IEnumerable]*?>"), new(OpCodes.Ldsfld, Field(typeof(string), nameof(string.Empty))), new(OpCodes.Call, Method(typeof(Regex), nameof(Regex.Replace), new System.Type[] { typeof(string), typeof(string), typeof(string) })), @@ -63,9 +64,9 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncementString))] + [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncement))] internal static class AnnouncingNtfMiniEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -35,15 +35,17 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Stloc_1) + 1; + newInstructions.InsertRange( - 0, + index, new CodeInstruction[] { // WaveAnnouncementBase new(OpCodes.Ldarg_0), // scpsLeft - new(OpCodes.Ldloc_0), + new(OpCodes.Ldloc_1), // null new(OpCodes.Ldnull), @@ -66,7 +68,7 @@ private static IEnumerable Transpiler(IEnumerable /// Patches - /// . + /// . /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingScpTermination))] - [HarmonyPatch(typeof(NineTailedFoxAnnouncer), nameof(NineTailedFoxAnnouncer.AnnounceScpTermination))] + [HarmonyPatch(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.OnStartedPlaying))] internal static class AnnouncingScpTermination { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); - LocalBuilder ev = generator.DeclareLocal(typeof(AnnouncingScpTerminationEventArgs)); + LocalBuilder cause = generator.DeclareLocal(typeof(string)); + LocalBuilder enumerator = generator.DeclareLocal(typeof(IEnumerator)); + + ExceptionBlock beginTry = new(ExceptionBlockType.BeginExceptionBlock); + ExceptionBlock beginFinally = new(ExceptionBlockType.BeginFinallyBlock); + ExceptionBlock endFinally = new(ExceptionBlockType.EndExceptionBlock); Label ret = generator.DefineLabel(); + Label entryLabel = generator.DefineLabel(); + Label loopLabel = generator.DefineLabel(); + Label leaveLabel = generator.DefineLabel(); + Label endFinallyLabel = generator.DefineLabel(); + + int offset = -1; + int index = newInstructions.FindIndex(i => i.LoadsField(Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts)))) + offset; + + newInstructions.RemoveRange(index, 2); + newInstructions.Insert(index, new CodeInstruction(OpCodes.Ldloc_S, cause)); - int offset = -4; - int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Newobj && (ConstructorInfo)i.operand == GetDeclaredConstructors(typeof(LabApi.Events.Arguments.ServerEvents.CassieQueuingScpTerminationEventArgs))[0]) + offset; + newInstructions[0].WithLabels(leaveLabel); newInstructions.InsertRange( - index, + 0, new[] - { - // Player.Get(scp) - new CodeInstruction(OpCodes.Ldarg_0), - new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), - - // hit - new(OpCodes.Ldarg_1), - - // AnnouncingScpTerminationEventArgs ev = new(Player, DamageHandlerBase) - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(AnnouncingScpTerminationEventArgs))[0]), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Stloc_S, ev.LocalIndex), - - // Map.OnAnnouncingScpTermination(ev) - new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), - - // if (!ev.IsAllowed) - // return; - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.IsAllowed))), - new(OpCodes.Brfalse_S, ret), - - // hit = ev.DamageHandler.Base - new(OpCodes.Ldloc_S, ev.LocalIndex), - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.DamageHandler))), - new(OpCodes.Callvirt, PropertyGetter(typeof(CustomDamageHandler), nameof(CustomDamageHandler.Base))), - new(OpCodes.Starg, 1), - - // announcement = ev.TerminationCause - new(OpCodes.Ldloc_S, ev.LocalIndex), - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), - new(OpCodes.Stloc_0), - }); + { + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts))), + new(OpCodes.Stloc_S, cause), + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.Victims))), + new(OpCodes.Callvirt, Method(typeof(IEnumerable), nameof(IEnumerable.GetEnumerator))), + new(OpCodes.Stloc_S, enumerator), + + // start of try + new CodeInstruction(OpCodes.Br_S, entryLabel).WithBlocks(beginTry), + + // start of loop + new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(loopLabel), + new(OpCodes.Callvirt, PropertyGetter(typeof(IEnumerator), nameof(IEnumerator.Current))), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(Footprint) })), + new(OpCodes.Ldloc_S, cause), + new(OpCodes.Newobj, Constructor(typeof(AnnouncingScpTerminationEventArgs), new[] { typeof(Player), typeof(string) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), + new(OpCodes.Stloc_S, cause), + + // entry point + new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(entryLabel), + new(OpCodes.Callvirt, Method(typeof(IEnumerator), nameof(IEnumerator.MoveNext))), + new(OpCodes.Brtrue_S, loopLabel), + + // end of loop + new(OpCodes.Leave, leaveLabel), + + // begin finally + new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithBlocks(beginFinally), + new(OpCodes.Brfalse, endFinallyLabel), + new(OpCodes.Ldloc_S, enumerator), + new(OpCodes.Callvirt, Method(typeof(IDisposable), nameof(IDisposable.Dispose))), + + // end of finally + new CodeInstruction(OpCodes.Endfinally).WithLabels(endFinallyLabel).WithBlocks(endFinally), + }); newInstructions[newInstructions.Count - 1].labels.Add(ret); diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs deleted file mode 100644 index 7193f8d17f..0000000000 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs +++ /dev/null @@ -1,68 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Patches.Events.Map -{ - using System.Collections.Generic; - using System.Reflection; - using System.Reflection.Emit; - using System.Text; - - using Exiled.API.Features.Pools; - using Exiled.Events.Attributes; - using Exiled.Events.EventArgs.Map; - using HarmonyLib; - using Respawning.Announcements; - - using static HarmonyLib.AccessTools; - - /// - /// Patches to prevent cassie from playing empty string. - /// - [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingNtfEntrance))] - [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] - [HarmonyPatch(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.PlayAnnouncement))] - internal static class AnnouncingTeamEntrance - { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - List newInstructions = ListPool.Pool.Get(instructions); - - Label returnLabel = generator.DefineLabel(); - - // the instruction that sends subtitles is called before stringReturn is created (and thus checked) so we need to move it so that empty (or disallowed) message's subtitles are not sent. - // this removes the Ldarg_0 and the CallVirt - int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.SendSubtitles)))); - CodeInstruction sendSubtitlesInstruction = newInstructions[index]; - newInstructions.RemoveRange(index - 2, 3); - - index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldsfld); - - newInstructions.InsertRange(index, new[] - { - // if (stringReturn == "") - // return; - new(OpCodes.Ldloc_S, 4), - new(OpCodes.Ldstr, string.Empty), - new(OpCodes.Ceq), - new(OpCodes.Brtrue_S, returnLabel), - - // send subtitles before cassie message, but after our check. - new(OpCodes.Ldarg_0), - new(OpCodes.Ldarg_1), - sendSubtitlesInstruction, - }); - - newInstructions[newInstructions.Count - 1].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 diff --git a/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs index d2efcd3fd3..680bbbf0dd 100644 --- a/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs +++ b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs @@ -31,17 +31,18 @@ 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[] + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + 1; + + newInstructions.InsertRange(index, new[] { // RecontainingEventArgs ev = new(this._activatorGlass) - new(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), new(OpCodes.Ldfld, Field(typeof(Scp079Recontainer), nameof(Scp079Recontainer._activatorGlass))), new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RecontainingEventArgs))[0]), new(OpCodes.Stloc_S, ev.LocalIndex), diff --git a/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs b/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs index 1f6a8ee431..17bdf5e142 100644 --- a/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs +++ b/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs @@ -22,7 +22,7 @@ namespace Exiled.Events.Patches.Fixes using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Bug reported to NW (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/88). /// [HarmonyPatch(typeof(JailbirdDeteriorationTracker), nameof(JailbirdDeteriorationTracker.Setup))] diff --git a/EXILED/Exiled.Events/Patches/Fixes/JailbirdHitRegFix.cs b/EXILED/Exiled.Events/Patches/Fixes/JailbirdHitRegFix.cs deleted file mode 100644 index 46151c7577..0000000000 --- a/EXILED/Exiled.Events/Patches/Fixes/JailbirdHitRegFix.cs +++ /dev/null @@ -1,61 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod 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 HarmonyLib; - using InventorySystem.Items.Jailbird; - using Mirror; - using Utils.Networking; - - using static HarmonyLib.AccessTools; - - /// - /// Patches . - /// - [HarmonyPatch(typeof(JailbirdHitreg), nameof(JailbirdHitreg.ServerAttack))] - internal static class JailbirdHitRegFix - { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - List newInstructions = ListPool.Pool.Get(instructions); - - int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(ReferenceHubReaderWriter), nameof(ReferenceHubReaderWriter.TryReadReferenceHub)))) - 2; - - int breakIndex = newInstructions.FindIndex(i => i.Calls(Method(typeof(JailbirdHitreg), nameof(JailbirdHitreg.DetectDestructibles)))) - 1; - Label breakLabel = generator.DefineLabel(); - newInstructions[breakIndex].WithLabels(breakLabel); - - List