Decompiled source of SprayMod v1.1.0

plugins/SprayMod.dll

Decompiled 3 weeks ago
using 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();
		}
	}
}