From c0da41120d63037f6430194317ae03edb0db3359 Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:00:20 +0200 Subject: [PATCH 1/3] add installer choice --- EXILED/Exiled.Installer/Program.cs | 24 +++ .../Properties/Resources.Designer.cs | 188 ++++++++++++------ .../Properties/Resources.resx | 15 ++ 3 files changed, 164 insertions(+), 63 deletions(-) diff --git a/EXILED/Exiled.Installer/Program.cs b/EXILED/Exiled.Installer/Program.cs index c7a43a2dcd..98d4a9d25a 100644 --- a/EXILED/Exiled.Installer/Program.cs +++ b/EXILED/Exiled.Installer/Program.cs @@ -89,6 +89,30 @@ internal static async Task MainSafe(CommandSettings args) GitHubClient.Credentials = new Credentials(args.GitHubToken, AuthenticationType.Bearer); } + if (string.IsNullOrEmpty(args.TargetVersion)) + { + Console.WriteLine(Resources.Program_MainSafe_Which_version_would_you_like_to_install_); + Console.WriteLine(Resources.Program_MainSafe__1___Latest_stable_release); + Console.WriteLine(Resources.Program_MainSafe__2___Latest_prerelease__beta_dev_); + + Console.Write(Resources.Program_MainSafe_Your_choice__1_2___); + ConsoleKeyInfo key = Console.ReadKey(intercept: true); + Console.WriteLine(key.KeyChar); + + if (key.KeyChar == '2') + { + args.PreReleases = true; + Console.WriteLine(Resources.Program_MainSafe_); + } + else + { + args.PreReleases = false; + Console.WriteLine(Resources.Program_MainSafe_); + } + } + + + Console.WriteLine(Resources.Program_MainSafe_Receiving_releases___); Console.WriteLine(Resources.Program_MainSafe_Prereleases_included____0_, args.PreReleases); Console.WriteLine(Resources.Program_MainSafe_Target_release_version____0_, string.IsNullOrEmpty(args.TargetVersion) ? "(null)" : args.TargetVersion); diff --git a/EXILED/Exiled.Installer/Properties/Resources.Designer.cs b/EXILED/Exiled.Installer/Properties/Resources.Designer.cs index e382401b53..b95cc93c54 100644 --- a/EXILED/Exiled.Installer/Properties/Resources.Designer.cs +++ b/EXILED/Exiled.Installer/Properties/Resources.Designer.cs @@ -1,39 +1,38 @@ //------------------------------------------------------------------------------ // -// Il codice è stato generato da uno strumento. -// Versione runtime:4.0.30319.42000 +// This code was generated by a tool. // -// Le modifiche apportate a questo file possono provocare un comportamento non corretto e andranno perse se -// il codice viene rigenerato. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ namespace Exiled.Installer.Properties { using System; - - + + /// - /// Classe di risorse fortemente tipizzata per la ricerca di stringhe localizzate e così via. + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // Questa classe è stata generata automaticamente dalla classe StronglyTypedResourceBuilder. - // tramite uno strumento quale ResGen o Visual Studio. - // Per aggiungere o rimuovere un membro, modificare il file con estensione ResX ed eseguire nuovamente ResGen - // con l'opzione /str oppure ricompilare il progetto VS. + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - + /// - /// Restituisce l'istanza di ResourceManager nella cache utilizzata da questa classe. + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -45,10 +44,10 @@ internal Resources() { return resourceMan; } } - + /// - /// Esegue l'override della proprietà CurrentUICulture del thread corrente per tutte le - /// ricerche di risorse eseguite utilizzando questa classe di risorse fortemente tipizzata. + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { @@ -59,9 +58,9 @@ internal Resources() { resourceCulture = value; } } - + /// - /// Cerca una stringa localizzata simile a EXILED\:EXILED + /// Looks up a localized string similar to EXILED\:EXILED ///SCP Secret Laboratory\:ABSOLUTE ///. /// @@ -70,108 +69,153 @@ internal static string Markup { return ResourceManager.GetString("Markup", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Does it exist? - {0}. + /// Looks up a localized string similar to Does it exist? - {0}. /// internal static string Program_EnsureDirExists_Does_it_exist_____0_ { get { return ResourceManager.GetString("Program_EnsureDirExists_Does_it_exist_____0_", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Ensuring directory path: {0}. + /// Looks up a localized string similar to Ensuring directory path: {0}. /// internal static string Program_EnsureDirExists_Ensuring_directory_path___0_ { get { return ResourceManager.GetString("Program_EnsureDirExists_Ensuring_directory_path___0_", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a An exception occurred while trying to extract a file. + /// Looks up a localized string similar to An exception occurred while trying to extract a file. /// internal static string Program_ExtractEntry_An_exception_occurred_while_trying_to_extract_a_file { get { return ResourceManager.GetString("Program_ExtractEntry_An_exception_occurred_while_trying_to_extract_a_file", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Extracting '{0}' into '{1}'.... + /// Looks up a localized string similar to Extracting '{0}' into '{1}'.... /// internal static string Program_ExtractEntry_Extracting___0___into___1_____ { get { return ResourceManager.GetString("Program_ExtractEntry_Extracting___0___into___1_____", resourceCulture); } } - + + /// + /// Looks up a localized string similar to → Prerelease selected.. + /// + internal static string Program_MainSafe_ { + get { + return ResourceManager.GetString("Program_MainSafe_", resourceCulture); + } + } + /// - /// Cerca una stringa localizzata simile a --- ASSETS ---. + /// Looks up a localized string similar to --- ASSETS ---. /// internal static string Program_MainSafe_____ASSETS____ { get { return ResourceManager.GetString("Program_MainSafe_____ASSETS____", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a --- AVAILABLE VERSIONS ---. + /// Looks up a localized string similar to --- AVAILABLE VERSIONS ---. /// internal static string Program_MainSafe_____AVAILABLE_VERSIONS____ { get { return ResourceManager.GetString("Program_MainSafe_____AVAILABLE_VERSIONS____", resourceCulture); } } - + + /// + /// Looks up a localized string similar to --- RELEASES ---. + /// + internal static string Program_MainSafe_____RELEASES____ { + get { + return ResourceManager.GetString("Program_MainSafe_____RELEASES____", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 1 - Latest stable release. + /// + internal static string Program_MainSafe__1___Latest_stable_release { + get { + return ResourceManager.GetString("Program_MainSafe__1___Latest_stable_release", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2 - Latest prerelease (beta/dev). + /// + internal static string Program_MainSafe__2___Latest_prerelease__beta_dev_ { + get { + return ResourceManager.GetString("Program_MainSafe__2___Latest_prerelease__beta_dev_", resourceCulture); + } + } + /// - /// Cerca una stringa localizzata simile a AppData folder: {0}. + /// Looks up a localized string similar to AppData folder: {0}. /// internal static string Program_MainSafe_AppData_folder___0_ { get { return ResourceManager.GetString("Program_MainSafe_AppData_folder___0_", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Asset found!. + /// Looks up a localized string similar to Asset found!. /// internal static string Program_MainSafe_Asset_found_ { get { return ResourceManager.GetString("Program_MainSafe_Asset_found_", resourceCulture); } } - + + /// + /// Looks up a localized string similar to Couldn't find '{0}' in '{1}'. + /// + internal static string Program_MainSafe_Couldn_t_find___0___in___1__ { + get { + return ResourceManager.GetString("Program_MainSafe_Couldn_t_find___0___in___1__", resourceCulture); + } + } + /// - /// Cerca una stringa localizzata simile a Exiled folder: {0}. + /// Looks up a localized string similar to Exiled folder: {0}. /// internal static string Program_MainSafe_Exiled_folder___0_ { get { return ResourceManager.GetString("Program_MainSafe_Exiled_folder___0_", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Installation complete. + /// Looks up a localized string similar to Installation complete. /// internal static string Program_MainSafe_Installation_complete { get { return ResourceManager.GetString("Program_MainSafe_Installation_complete", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Prereleases included - {0}. + /// Looks up a localized string similar to Prereleases included - {0}. /// internal static string Program_MainSafe_Prereleases_included____0_ { get { return ResourceManager.GetString("Program_MainSafe_Prereleases_included____0_", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Read the exception message, read the readme, and if you still don't understand what to do, then contact #support in our discord server with the attached screenshot of the full exception. + /// Looks up a localized string similar to Read the exception message, read the readme, and if you still don't understand what to do, then contact #support in our discord server with the attached screenshot of the full exception. /// internal static string Program_MainSafe_Read_the_exception_message__read_the_readme__and_if_you_still_don_t_understand_what_to_do__then_contact__support_in_our_discord_server_with_the_attached_screenshot_of_the_full_exception { get { @@ -180,81 +224,99 @@ internal static string Program_MainSafe_Read_the_exception_message__read_the_rea "attached_screenshot_of_the_full_exception", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Receiving releases.... + /// Looks up a localized string similar to Receiving releases.... /// internal static string Program_MainSafe_Receiving_releases___ { get { return ResourceManager.GetString("Program_MainSafe_Receiving_releases___", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Release found!. + /// Looks up a localized string similar to Release found!. /// internal static string Program_MainSafe_Release_found_ { get { return ResourceManager.GetString("Program_MainSafe_Release_found_", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Searching for the latest release that matches the parameters.... + /// Looks up a localized string similar to Searching for the latest release that matches the parameters.... /// internal static string Program_MainSafe_Searching_for_the_latest_release_that_matches_the_parameters___ { get { return ResourceManager.GetString("Program_MainSafe_Searching_for_the_latest_release_that_matches_the_parameters___", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Target release version - {0}. + /// Looks up a localized string similar to Target release version - {0}. /// internal static string Program_MainSafe_Target_release_version____0_ { get { return ResourceManager.GetString("Program_MainSafe_Target_release_version____0_", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Token detected! Using the token.... + /// Looks up a localized string similar to Token detected! Using the token.... /// internal static string Program_MainSafe_Token_detected__Using_the_token___ { get { return ResourceManager.GetString("Program_MainSafe_Token_detected__Using_the_token___", resourceCulture); } } - + + /// + /// Looks up a localized string similar to Which version would you like to install?. + /// + internal static string Program_MainSafe_Which_version_would_you_like_to_install_ { + get { + return ResourceManager.GetString("Program_MainSafe_Which_version_would_you_like_to_install_", resourceCulture); + } + } + /// - /// Cerca una stringa localizzata simile a Couldn't resolve path for '{0}', update installer. + /// Looks up a localized string similar to Your choice (1/2): . + /// + internal static string Program_MainSafe_Your_choice__1_2___ { + get { + return ResourceManager.GetString("Program_MainSafe_Your_choice__1_2___", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Couldn't resolve path for '{0}', update installer. /// internal static string Program_ProcessTarEntry_Couldn_t_resolve_path_for___0____update_installer { get { return ResourceManager.GetString("Program_ProcessTarEntry_Couldn_t_resolve_path_for___0____update_installer", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Extract for {0} is disabled. + /// Looks up a localized string similar to Extract for {0} is disabled. /// internal static string Program_ProcessTarEntry_Extract_for__0__is_disabled { get { return ResourceManager.GetString("Program_ProcessTarEntry_Extract_for__0__is_disabled", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Processing '{0}'. + /// Looks up a localized string similar to Processing '{0}'. /// internal static string Program_ProcessTarEntry_Processing___0__ { get { return ResourceManager.GetString("Program_ProcessTarEntry_Processing___0__", resourceCulture); } } - + /// - /// Cerca una stringa localizzata simile a Trying to find release... + /// Looks up a localized string similar to Trying to find release... /// internal static string Program_TryFindRelease_Trying_to_find_release__ { get { diff --git a/EXILED/Exiled.Installer/Properties/Resources.resx b/EXILED/Exiled.Installer/Properties/Resources.resx index 656ed6ad10..7c7ae02ee9 100644 --- a/EXILED/Exiled.Installer/Properties/Resources.resx +++ b/EXILED/Exiled.Installer/Properties/Resources.resx @@ -191,4 +191,19 @@ Exiled folder: {0} + + Which version would you like to install? + + + 1 - Latest stable release + + + 2 - Latest prerelease (beta/dev) + + + Your choice (1/2): + + + → Prerelease selected. + \ No newline at end of file From a933fc57a021a9d1622635b2e99f0295ef67bb4d Mon Sep 17 00:00:00 2001 From: Mike <146554836+MikeSus1@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:56:44 +0200 Subject: [PATCH 2/3] Link to exiled.Loader Testing is rly needed on this as i cant test it locally because it takes the installer from github release --- EXILED/Exiled.Installer/Program.cs | 2 +- EXILED/Exiled.Loader/Models/NewVersion.cs | 9 ++++++++- EXILED/Exiled.Loader/Updater.cs | 7 +++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/EXILED/Exiled.Installer/Program.cs b/EXILED/Exiled.Installer/Program.cs index 98d4a9d25a..6f18258c2f 100644 --- a/EXILED/Exiled.Installer/Program.cs +++ b/EXILED/Exiled.Installer/Program.cs @@ -89,7 +89,7 @@ internal static async Task MainSafe(CommandSettings args) GitHubClient.Credentials = new Credentials(args.GitHubToken, AuthenticationType.Bearer); } - if (string.IsNullOrEmpty(args.TargetVersion)) + if (string.IsNullOrEmpty(args.TargetVersion) && !args.PreReleases) { Console.WriteLine(Resources.Program_MainSafe_Which_version_would_you_like_to_install_); Console.WriteLine(Resources.Program_MainSafe__1___Latest_stable_release); diff --git a/EXILED/Exiled.Loader/Models/NewVersion.cs b/EXILED/Exiled.Loader/Models/NewVersion.cs index 81cb4f3e42..ea7e852373 100644 --- a/EXILED/Exiled.Loader/Models/NewVersion.cs +++ b/EXILED/Exiled.Loader/Models/NewVersion.cs @@ -24,15 +24,22 @@ public readonly struct NewVersion /// public readonly ReleaseAsset Asset; + /// + /// Indicates if the release is a prerelease. + /// + public readonly bool IsPrerelease; + /// /// Initializes a new instance of the struct. /// /// /// - public NewVersion(Release release, ReleaseAsset asset) + /// /// Indicates whether the release is a prerelease. + public NewVersion(Release release, ReleaseAsset asset, bool isPrerelease) { Release = release; Asset = asset; + IsPrerelease = isPrerelease; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Loader/Updater.cs b/EXILED/Exiled.Loader/Updater.cs index 2aef897a61..5c6af65500 100644 --- a/EXILED/Exiled.Loader/Updater.cs +++ b/EXILED/Exiled.Loader/Updater.cs @@ -167,8 +167,11 @@ private bool FindUpdate(HttpClient client, bool forced, out NewVersion newVersio } else { + bool isPrerelease = targetRelease.PreRelease; + Log.Info($"Release type: {(isPrerelease ? "Prerelease" : "Stable")}"); + Log.Info($"Found asset - Name: {asset.Name} | Size: {asset.Size} Download: {asset.BrowserDownloadUrl}"); - newVersion = new NewVersion(targetRelease, asset); + newVersion = new NewVersion(targetRelease, asset, isPrerelease); return true; } } @@ -226,7 +229,7 @@ private void Update(HttpClient client, NewVersion newVersion) FileName = installerPath, UseShellExecute = false, CreateNoWindow = true, - Arguments = $"--exit {(Folder == "global" ? string.Empty : $"--target-port {Folder}")} --target-version {newVersion.Release.TagName} --appdata \"{Paths.AppData}\" --exiled \"{Path.Combine(Paths.Exiled, "..")}\"", + Arguments = $"--exit {(Folder == "global" ? string.Empty : $"--target-port {Folder}")} --target-version {newVersion.Release.TagName} --appdata \"{Paths.AppData}\" --exiled \"{Path.Combine(Paths.Exiled, "..")}\" {(newVersion.IsPrerelease ? "--pre-releases" : string.Empty)}", RedirectStandardOutput = true, RedirectStandardError = true, StandardErrorEncoding = ProcessEncoding, From 7ebe899c7c6d984887ee2f5dfd3cb669aff10feb Mon Sep 17 00:00:00 2001 From: VALERA771 <72030575+VALERA771@users.noreply.github.com> Date: Thu, 31 Jul 2025 20:47:44 +0300 Subject: [PATCH 3/3] feat: Item::Inspected Item::Inspecting & Scp939::PlacingMimicPoint (#473) * feat: a bunch of new evs * revert Events.cs changes * docs: comments for transpilers * feat: support for all items * feat: mhid support * docs: fetch documentation * fix: fix InspectedItemEventArgs.cs and docs update --------- Co-authored-by: Yamato <66829532+louis1706@users.noreply.github.com> --- .../EventArgs/Item/InspectedItemEventArgs.cs | 35 ++ .../EventArgs/Item/InspectingItemEventArgs.cs | 41 +++ .../Scp939/PlacingMimicPointEventArgs.cs | 48 +++ EXILED/Exiled.Events/Handlers/Item.cs | 22 ++ EXILED/Exiled.Events/Handlers/Scp939.cs | 11 + .../Patches/Events/Item/Inspect.cs | 319 ++++++++++++++++++ .../Events/Scp939/PlacingMimicPoint.cs | 84 +++++ 7 files changed, 560 insertions(+) create mode 100644 EXILED/Exiled.Events/EventArgs/Item/InspectedItemEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Item/InspectingItemEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Scp939/PlacingMimicPointEventArgs.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Item/Inspect.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Scp939/PlacingMimicPoint.cs diff --git a/EXILED/Exiled.Events/EventArgs/Item/InspectedItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/InspectedItemEventArgs.cs new file mode 100644 index 0000000000..283fd4910f --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Item/InspectedItemEventArgs.cs @@ -0,0 +1,35 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Item +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items; + + /// + /// Contains all information before weapon is inspected. + /// + public class InspectedItemEventArgs : IItemEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + public InspectedItemEventArgs(ItemBase item) + { + Item = Item.Get(item); + } + + /// + public Player Player => Item.Owner; + + /// + public Item Item { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Item/InspectingItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/InspectingItemEventArgs.cs new file mode 100644 index 0000000000..5bb7cb4077 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Item/InspectingItemEventArgs.cs @@ -0,0 +1,41 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Item +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items; + + /// + /// Contains all information before weapon is inspected. + /// + public class InspectingItemEventArgs : IItemEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public InspectingItemEventArgs(ItemBase item, bool isAllowed = true) + { + Item = Item.Get(item); + IsAllowed = isAllowed; + } + + /// + public Player Player => Item.Owner; + + /// + public Item Item { get; } + + /// + /// Setter will not work if inspected is a or a . + public bool IsAllowed { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp939/PlacingMimicPointEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp939/PlacingMimicPointEventArgs.cs new file mode 100644 index 0000000000..a761942caf --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp939/PlacingMimicPointEventArgs.cs @@ -0,0 +1,48 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp939 +{ + using Exiled.API.Features; + using Exiled.API.Features.Roles; + using Exiled.Events.EventArgs.Interfaces; + using RelativePositioning; + + /// + /// Contains all information before mimicry point is placed. + /// + public class PlacingMimicPointEventArgs : IScp939Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + public PlacingMimicPointEventArgs(Player player, RelativePosition position, bool isAllowed = true) + { + Player = player; + Scp939 = player.Role.As(); + Position = position; + IsAllowed = isAllowed; + } + + /// + public Player Player { get; } + + /// + public Scp939Role Scp939 { get; } + + /// + public bool IsAllowed { get; set; } + + /// + /// Gets or sets a position of mimicry point. + /// + public RelativePosition Position { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Item.cs b/EXILED/Exiled.Events/Handlers/Item.cs index d8153a586e..4cca796fef 100644 --- a/EXILED/Exiled.Events/Handlers/Item.cs +++ b/EXILED/Exiled.Events/Handlers/Item.cs @@ -58,6 +58,16 @@ public static class Item /// public static Event ChangingMicroHIDPickupState { get; set; } = new(); + /// + /// Invoked before item inspection is started. + /// + public static Event InspectingItem { get; set; } = new(); + + /// + /// Invoked after item inspection is started. + /// + public static Event InspectedItem { get; set; } = new(); + /// /// Invoked before a firing while on the ground. /// The client will still see all effects, like sounds and shoot. @@ -118,5 +128,17 @@ public static class Item /// /// The instance. public static void OnChangingMicroHIDPickupState(ChangingMicroHIDPickupStateEventArgs ev) => ChangingMicroHIDPickupState.InvokeSafely(ev); + + /// + /// Called before item inspection is started. + /// + /// The instance. + public static void OnInspectingItem(InspectingItemEventArgs ev) => InspectingItem.InvokeSafely(ev); + + /// + /// Called before item inspection is started. + /// + /// The instance. + public static void OnInspectedItem(InspectedItemEventArgs ev) => InspectedItem.InvokeSafely(ev); } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Scp939.cs b/EXILED/Exiled.Events/Handlers/Scp939.cs index d2ca5e4533..d5d5da378e 100644 --- a/EXILED/Exiled.Events/Handlers/Scp939.cs +++ b/EXILED/Exiled.Events/Handlers/Scp939.cs @@ -74,6 +74,11 @@ public static class Scp939 /// public static Event ValidatingVisibility { get; set; } = new(); + /// + /// Invoked before mimicry point is placed. + /// + public static Event PlacingMimicPoint { get; set; } = new(); + /// /// Called before SCP-939 changes its target focus. /// @@ -139,5 +144,11 @@ public static class Scp939 /// /// The instance. public static void OnValidatingVisibility(ValidatingVisibilityEventArgs ev) => ValidatingVisibility.InvokeSafely(ev); + + /// + /// Called before mimicry point is placed. + /// + /// The instance. + public static void OnPlacingMimicPoint(PlacingMimicPointEventArgs ev) => PlacingMimicPoint.InvokeSafely(ev); } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Inspect.cs b/EXILED/Exiled.Events/Patches/Events/Item/Inspect.cs new file mode 100644 index 0000000000..860d064ea1 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Item/Inspect.cs @@ -0,0 +1,319 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Item +{ +#pragma warning disable SA1402 +#pragma warning disable SA1649 + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Item; + using HarmonyLib; + using InventorySystem.Items.Firearms.Modules; + using InventorySystem.Items.Jailbird; + using InventorySystem.Items.Keycards; + using InventorySystem.Items.MicroHID.Modules; + using InventorySystem.Items.Usables.Scp1344; + + using static HarmonyLib.AccessTools; + + /// + /// Patches + /// to add and event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectingItem))] + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectedItem))] + [HarmonyPatch(typeof(SimpleInspectorModule), nameof(SimpleInspectorModule.ServerProcessCmd))] + internal class InspectWeapon + { + private static IEnumerable Transpiler(IEnumerable instructions) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldarg_0); + + newInstructions.InsertRange(index, new[] + { + // this.Firearm + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + new(OpCodes.Callvirt, PropertyGetter(typeof(SimpleInspectorModule), nameof(SimpleInspectorModule.Firearm))), + + // true + new(OpCodes.Ldc_I4_1), + + // InspectingItemEventArgs ev = new(this.Firearm) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectingItemEventArgs))[0]), + + // Handlers.Item.OnInspectingItem(ev) + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectingItem))), + }); + + newInstructions.InsertRange(newInstructions.Count - 1, new CodeInstruction[] + { + // this.Firearm + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(SimpleInspectorModule), nameof(SimpleInspectorModule.Firearm))), + + // InspectedItemEventArgs ev = new(this.Firearm) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectedItemEventArgs))[0]), + + // Handlers.Item.OnInspectedItem(ev) + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectedItem))), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } + + /// + /// Patches + /// to add and event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectingItem))] + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectedItem))] + [HarmonyPatch(typeof(Scp1344NetworkHandler), nameof(Scp1344NetworkHandler.TryInspect))] + internal class InspectScp1344 + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int offset = 1; + int index = newInstructions.FindIndex(x => x.Is(OpCodes.Callvirt, PropertyGetter(typeof(Scp1344Item), nameof(Scp1344Item.AllowInspect)))) + offset; + + LocalBuilder allowed = generator.DeclareLocal(typeof(bool)); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // store isAllowed + new(OpCodes.Stloc_S, allowed.LocalIndex), + + // curInstance + new(OpCodes.Ldloc_0), + + // load isAllowed + new(OpCodes.Ldloc_S, allowed.LocalIndex), + + // InspectingItemEventArgs ev = new(curInstance, isAllowed); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectingItemEventArgs))[0]), + new(OpCodes.Dup), + + // Handlers.Item.OnInspectingItem(ev); + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectingItem))), + + // load isAllowed + new(OpCodes.Callvirt, PropertyGetter(typeof(InspectingItemEventArgs), nameof(InspectingItemEventArgs.IsAllowed))), + }); + + newInstructions.InsertRange(newInstructions.Count - 1, new CodeInstruction[] + { + // curInstance + new(OpCodes.Ldloc_0), + + // InspectedItemEventArgs = new(curInstance); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectedItemEventArgs))[0]), + + // Handlers.Item.OnInspectedItem(ev); + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectedItem))), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } + + /// + /// Patches + /// to add and event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectingItem))] + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectedItem))] + [HarmonyPatch(typeof(KeycardItem), nameof(KeycardItem.ServerProcessCmd))] + internal class InspectKeycard + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int offset = 1; + int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldloc_1) + offset; + + LocalBuilder allowed = generator.DeclareLocal(typeof(bool)); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // save flag value as isAllowed + new(OpCodes.Stloc_S, allowed.LocalIndex), + + // this + new(OpCodes.Ldarg_0), + + // load isAllowed + new(OpCodes.Ldloc_S, allowed.LocalIndex), + + // InspectingItemEventArgs ev = new(this, isAllowed) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectingItemEventArgs))[0]), + new(OpCodes.Dup), + + // Handlers.Item.OnInspectingItem(ev) + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectingItem))), + + // load isAllowed + new(OpCodes.Callvirt, PropertyGetter(typeof(InspectingItemEventArgs), nameof(InspectingItemEventArgs.IsAllowed))), + }); + + newInstructions.InsertRange(newInstructions.Count - 1, new CodeInstruction[] + { + // this + new(OpCodes.Ldarg_0), + + // InspectedItemEventArgs ev = new(this) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectedItemEventArgs))[0]), + + // Handlers.Item.OnInspectedItem(ev) + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectedItem))), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + + private static void Return(KeycardItem item) => item.ServerSendPrivateRpc(x => KeycardItem.WriteInspect(x, false)); + } + + /// + /// Patches + /// to add and event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectingItem))] + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectedItem))] + [HarmonyPatch(typeof(JailbirdItem), nameof(JailbirdItem.ServerProcessCmd))] + internal class InspectJailbird + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int offset = 1; + int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldloc_2) + offset; + + LocalBuilder allowed = generator.DeclareLocal(typeof(bool)); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // save flag value as isAllowed + new(OpCodes.Stloc_S, allowed.LocalIndex), + + // this + new(OpCodes.Ldarg_0), + + // load isAllowed + new(OpCodes.Ldloc_S, allowed.LocalIndex), + + // InspectingItemEventArgs ev = new(this, isAllowed) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectingItemEventArgs))[0]), + new(OpCodes.Dup), + + // Handlers.Item.OnInspectingItem(ev) + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectingItem))), + + // load isAllowed + new(OpCodes.Callvirt, PropertyGetter(typeof(InspectingItemEventArgs), nameof(InspectingItemEventArgs.IsAllowed))), + }); + + index = newInstructions.FindLastIndex(x => x.Calls(Method(typeof(JailbirdItem), nameof(JailbirdItem.SendRpc)))) + offset; + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // this + new(OpCodes.Ldarg_0), + + // InspectedItemEventArgs ev = new(this) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectedItemEventArgs))[0]), + + // Handlers.Item.OnInspectedItem(ev) + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectedItem))), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } + + /// + /// Patches + /// to add and event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectingItem))] + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.InspectedItem))] + [HarmonyPatch(typeof(DrawAndInspectorModule), nameof(DrawAndInspectorModule.ServerProcessCmd))] + internal class InspectMicroHid + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldarg_0); + + Label returnLabel = generator.DefineLabel(); + + newInstructions.InsertRange(index, new[] + { + // this.MicroHid + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + new(OpCodes.Callvirt, PropertyGetter(typeof(DrawAndInspectorModule), nameof(DrawAndInspectorModule.MicroHid))), + + // true + new(OpCodes.Ldc_I4_1), + + // InspectingItemEventArgs ev = new(this.MicroHid, true) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectingItemEventArgs))[0]), + new(OpCodes.Dup), + + // Handlers.Item.OnInspectingItem(ev) + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectingItem))), + + // if (!ev.IsAllowed) + // return + new(OpCodes.Callvirt, PropertyGetter(typeof(InspectingItemEventArgs), nameof(InspectingItemEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, returnLabel), + }); + + newInstructions.InsertRange(newInstructions.Count - 1, new CodeInstruction[] + { + // this.MicroHid + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(DrawAndInspectorModule), nameof(DrawAndInspectorModule.MicroHid))), + + // InspectedItemEventArgs = new(this.MicroHid) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(InspectedItemEventArgs))[0]), + + // Handlers.Item.OnInspectedItem(ev) + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnInspectedItem))), + }); + + 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/Scp939/PlacingMimicPoint.cs b/EXILED/Exiled.Events/Patches/Events/Scp939/PlacingMimicPoint.cs new file mode 100644 index 0000000000..753291df01 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Scp939/PlacingMimicPoint.cs @@ -0,0 +1,84 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod 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; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Scp939; + using HarmonyLib; + using PlayerRoles.PlayableScps.Scp939.Mimicry; + + using static HarmonyLib.AccessTools; + + /// + /// Patches + /// to add event. + /// + [EventPatch(typeof(Handlers.Scp939), nameof(Handlers.Scp939.PlacingMimicPoint))] + [HarmonyPatch(typeof(MimicPointController), nameof(MimicPointController.ServerProcessCmd))] + internal class PlacingMimicPoint + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int offset = 1; + int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Stfld) + offset; + + Label returnLabel = generator.DefineLabel(); + + LocalBuilder ev = generator.DeclareLocal(typeof(PlacingMimicPointEventArgs)); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // Player.Get(this.Owner) + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(MimicPointController), nameof(MimicPointController.Owner))), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), + + // this._syncPos + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, Field(typeof(MimicPointController), nameof(MimicPointController._syncPos))), + + // true + new(OpCodes.Ldc_I4_1), + + // PlacingMimicPointEventArgs = new(Player.Get(this.Owner), this._syncPos, true) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(PlacingMimicPointEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev.LocalIndex), + + // Handlers.Scp939.OnPlacingMimicPoint(ev) + new(OpCodes.Call, Method(typeof(Handlers.Scp939), nameof(Handlers.Scp939.OnPlacingMimicPoint))), + + // if (!ev.IsAllowed) + // return + new(OpCodes.Callvirt, PropertyGetter(typeof(PlacingMimicPointEventArgs), nameof(PlacingMimicPointEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, returnLabel), + + // this._syncPos = ev.Position + new(OpCodes.Ldarg_0), + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(PlacingMimicPointEventArgs), nameof(PlacingMimicPointEventArgs.Position))), + new(OpCodes.Stfld, Field(typeof(MimicPointController), nameof(MimicPointController._syncPos))), + }); + + 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