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