Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SprayMod v1.1.0
plugins/SprayMod.dll
Decompiled a year agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("GraffitiMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("GraffitiMod")] [assembly: AssemblyTitle("GraffitiMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SprayMod { [BepInPlugin("IvitoDev.SprayMod", "Spray Mod", "1.1.0")] public class SprayMod : BaseUnityPlugin, IOnEventCallback, IInRoomCallbacks { [CompilerGenerated] private sealed class <LoadSelectedSprayCoroutine>d__35 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public SprayMod <>4__this; private string <path>5__1; private byte[] <data>5__2; private Exception <ex>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadSelectedSprayCoroutine>d__35(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <path>5__1 = null; <data>5__2 = null; <ex>5__3 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; try { <path>5__1 = Path.Combine(<>4__this.imagesFolderPath, <>4__this.selectedImageName); if (!File.Exists(<path>5__1)) { Logger.LogWarning((object)("Spray image not found: " + <>4__this.selectedImageName)); return false; } <data>5__2 = File.ReadAllBytes(<path>5__1); <>4__this.sprayTexture = <>4__this.LoadAndResizeImage(<data>5__2); if ((Object)(object)<>4__this.sprayTexture != (Object)null) { Logger.LogInfo((object)("Spray image loaded: " + <>4__this.selectedImageName)); } else { Logger.LogError((object)"Spray image is invalid and could not be loaded."); } <path>5__1 = null; <data>5__2 = null; } catch (Exception ex) { <ex>5__3 = ex; Logger.LogError((object)("Failed to load spray texture: " + <ex>5__3.Message)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private Texture2D sprayTexture = null; private string selectedImageName = string.Empty; private ConfigEntry<string> sprayImageEntry = null; private ConfigEntry<bool> openFolderFlag = null; private ConfigEntry<bool> refreshFlag = null; private string imagesFolderPath = null; private string[] availableImages = Array.Empty<string>(); private float cooldownTime = 10f; private float lastSprayTime = -999f; private bool registeredCallbacks = false; internal static SprayMod Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; private void Awake() { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); imagesFolderPath = Path.Combine(directoryName, "Images"); Logger.LogInfo((object)("Spray Mod initialized at: " + directoryName)); if (!Directory.Exists(imagesFolderPath)) { Logger.LogWarning((object)("Spray folder not found: " + imagesFolderPath)); } UpdateImageList(); InitConfigEntries(); Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); val.PatchAll(); } private void Update() { if (!registeredCallbacks && PhotonNetwork.InRoom) { PhotonNetwork.AddCallbackTarget((object)this); registeredCallbacks = true; Logger.LogInfo((object)"[SprayMod] Registered Photon callbacks."); } if (Input.GetKeyDown((KeyCode)121) && (Object)(object)sprayTexture != (Object)null) { TryPlaceSpray(); } if (openFolderFlag.Value) { OpenImagesFolder(); openFolderFlag.Value = false; } if (refreshFlag.Value) { RefreshImagesManually(); refreshFlag.Value = false; } } private void OnDestroy() { if (registeredCallbacks) { PhotonNetwork.RemoveCallbackTarget((object)this); } } public void OnJoinedRoom() { Logger.LogInfo((object)"[SprayMod] Joined Photon room. Ready to receive events."); } public void OnLeftRoom() { Logger.LogInfo((object)"[SprayMod] Left Photon room. Stopping event reception."); } public void OnPlayerEnteredRoom(Player newPlayer) { } public void OnPlayerLeftRoom(Player otherPlayer) { } public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { } public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { } public void OnMasterClientSwitched(Player newMasterClient) { } public void OnEvent(EventData photonEvent) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (photonEvent.Code != 42) { return; } object[] array = (object[])photonEvent.CustomData; byte[] buffer = (byte[])array[0]; Vector3 position = (Vector3)array[1]; Quaternion rotation = (Quaternion)array[2]; try { using MemoryStream stream = new MemoryStream(buffer); using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress); using MemoryStream memoryStream = new MemoryStream(); gZipStream.CopyTo(memoryStream); byte[] data = memoryStream.ToArray(); Texture2D val = LoadAndResizeImage(data); if ((Object)(object)val == (Object)null) { Logger.LogError((object)"[SprayMod] Received image is invalid."); return; } PlaceSpray(position, rotation, val); Logger.LogInfo((object)"Spray received and placed."); } catch (Exception ex) { Logger.LogError((object)("Error decompressing or processing spray: " + ex.Message)); } } private void Start() { selectedImageName = sprayImageEntry.Value; ((MonoBehaviour)this).StartCoroutine(LoadSelectedSprayCoroutine()); } private void InitConfigEntries() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown string text = availableImages.FirstOrDefault() ?? ""; sprayImageEntry = ((BaseUnityPlugin)this).Config.Bind<string>("Spray", "Image", text, new ConfigDescription("Select the spray image (PNG or JPG).", (AcceptableValueBase)(object)new AcceptableValueList<string>(availableImages), Array.Empty<object>())); sprayImageEntry.SettingChanged += delegate { selectedImageName = sprayImageEntry.Value; ((MonoBehaviour)this).StartCoroutine(LoadSelectedSprayCoroutine()); }; openFolderFlag = ((BaseUnityPlugin)this).Config.Bind<bool>("Spray", "Open Spray Folder", false, "Turn ON to open the spray folder. It will turn OFF automatically."); refreshFlag = ((BaseUnityPlugin)this).Config.Bind<bool>("Spray", "Refresh Spray List", false, "Turn ON to refresh image list. Then close and reopen this menu to update the dropdown."); } private void OpenImagesFolder() { Logger.LogInfo((object)"Opening spray image folder..."); try { Application.OpenURL(imagesFolderPath); } catch (Exception ex) { Logger.LogError((object)("Could not open folder: " + ex.Message)); } } private void RefreshImagesManually() { Logger.LogInfo((object)"Refreshing spray image list..."); UpdateImageList(); UpdateSprayConfigEntry(); } private void UpdateImageList() { try { availableImages = (from f in Directory.GetFiles(imagesFolderPath) where f.EndsWith(".png") || f.EndsWith(".jpg") select f).Select(Path.GetFileName).ToArray(); Logger.LogInfo((object)$"Found {availableImages.Length} spray image(s)."); } catch (Exception ex) { Logger.LogError((object)("Error reading spray folder: " + ex.Message)); } } private void UpdateSprayConfigEntry() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown string text = sprayImageEntry.Value; string text2 = availableImages.FirstOrDefault() ?? ""; if (!availableImages.Contains(text)) { text = text2; } ConfigDefinition definition = ((ConfigEntryBase)sprayImageEntry).Definition; ((BaseUnityPlugin)this).Config.Remove(definition); sprayImageEntry = ((BaseUnityPlugin)this).Config.Bind<string>(definition.Section, definition.Key, text, new ConfigDescription("Select the spray image (PNG or JPG).", (AcceptableValueBase)(object)new AcceptableValueList<string>(availableImages), Array.Empty<object>())); sprayImageEntry.SettingChanged += delegate { selectedImageName = sprayImageEntry.Value; ((MonoBehaviour)this).StartCoroutine(LoadSelectedSprayCoroutine()); }; } [IteratorStateMachine(typeof(<LoadSelectedSprayCoroutine>d__35))] private IEnumerator LoadSelectedSprayCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadSelectedSprayCoroutine>d__35(0) { <>4__this = this }; } private Texture2D LoadAndResizeImage(byte[] data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown try { Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, data, false)) { return null; } if (((Texture)val).width == 0 || ((Texture)val).height == 0 || val.GetPixels().All((Color c) => c.a == 0f)) { return null; } return ResizeIfTooLarge(val); } catch (Exception ex) { Logger.LogError((object)("Image decoding failed: " + ex.Message)); return null; } } private Texture2D ResizeIfTooLarge(Texture2D original) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) if (((Texture)original).width <= 1024 && ((Texture)original).height <= 1024) { return original; } float num = Math.Min(1024f / (float)((Texture)original).width, 1024f / (float)((Texture)original).height); int num2 = Mathf.RoundToInt((float)((Texture)original).width * num); int num3 = Mathf.RoundToInt((float)((Texture)original).height * num); try { RenderTexture temporary = RenderTexture.GetTemporary(num2, num3); Graphics.Blit((Texture)(object)original, temporary); RenderTexture.active = temporary; Texture2D val = new Texture2D(num2, num3, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)num2, (float)num3), 0, 0); val.Apply(); RenderTexture.active = null; RenderTexture.ReleaseTemporary(temporary); return val; } catch (Exception ex) { Logger.LogError((object)("Image resizing failed: " + ex.Message)); return null; } } private void TryPlaceSpray() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Expected O, but got Unknown if (Time.time - lastSprayTime < cooldownTime) { Logger.LogWarning((object)"Spray is on cooldown."); return; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return; } Ray val = main.ViewportPointToRay(new Vector3(0.5f, 0.5f)); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, ref val2, 3f)) { if ((Object)(object)sprayTexture == (Object)null || ((Texture)sprayTexture).width == 0 || ((Texture)sprayTexture).height == 0) { Logger.LogWarning((object)"Spray texture is invalid or null, skipping placement."); return; } PlaceSpray(((RaycastHit)(ref val2)).point, Quaternion.LookRotation(-((RaycastHit)(ref val2)).normal, Vector3.up), sprayTexture); if (PhotonNetwork.InRoom) { try { Texture2D val3 = new Texture2D(((Texture)sprayTexture).width, ((Texture)sprayTexture).height, (TextureFormat)4, false); val3.SetPixels(sprayTexture.GetPixels()); val3.Apply(); byte[] array = ImageConversion.EncodeToPNG(val3); if (array == null || array.Length == 0 || !ValidatePngData(array)) { Logger.LogWarning((object)"Failed to encode or validate spray image."); return; } byte[] array2 = CompressImage(array); if (array2.Length > 250000) { Logger.LogWarning((object)"Spray image too large to send after compression."); return; } object[] array3 = new object[3] { array2, ((RaycastHit)(ref val2)).point, Quaternion.LookRotation(-((RaycastHit)(ref val2)).normal, Vector3.up) }; PhotonNetwork.RaiseEvent((byte)42, (object)array3, new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable); } catch (Exception ex) { Logger.LogError((object)("Error sending spray image: " + ex.Message)); } } lastSprayTime = Time.time; } else { Logger.LogWarning((object)"No valid surface found to place spray."); } } private bool ValidatePngData(byte[] data) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown try { Texture2D val = new Texture2D(2, 2); return ImageConversion.LoadImage(val, data, true); } catch (Exception ex) { Logger.LogError((object)("Image validation failed: " + ex.Message)); return false; } } private void PlaceSpray(Vector3 position, Quaternion rotation, Texture2D texture) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown GameObject val = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)val).name = "SprayMod_Instance"; val.transform.position = position + rotation * Vector3.forward * 0.01f; val.transform.rotation = rotation; val.transform.localScale = new Vector3(1.2f, 1.2f, 1f); val.transform.parent = null; ((Object)val).hideFlags = (HideFlags)61; Object.Destroy((Object)(object)val.GetComponent<Collider>()); Material material = new Material(Shader.Find("Sprites/Default")) { mainTexture = (Texture)(object)texture }; val.GetComponent<Renderer>().material = material; Object.Destroy((Object)(object)val, 30f); } private byte[] CompressImage(byte[] data) { using MemoryStream memoryStream = new MemoryStream(); using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Compress)) { gZipStream.Write(data, 0, data.Length); } return memoryStream.ToArray(); } } }