Decompiled source of JohnPorkMod v1.2.0

plugins/JohnPorkMod.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[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("Bengi")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("JohnPorkMod")]
[assembly: AssemblyTitle("JohnPorkMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 JohnPorkMod
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "JohnPorkMod";

		public const string PLUGIN_NAME = "JohnPorkMod";

		public const string PLUGIN_VERSION = "1.2.0";
	}
}
namespace smert_v_nishite
{
	public class AudioSourceData
	{
		public AudioClip OriginalClip { get; set; }

		public AudioClip RealClip
		{
			get
			{
				using (new SpoofBypass())
				{
					return Source.clip;
				}
			}
			set
			{
				using (new SpoofBypass())
				{
					Source.clip = value;
				}
			}
		}

		public AudioSource Source { get; }

		private AudioSourceData(AudioSource source)
		{
			Source = source;
		}

		public static AudioSourceData GetOrCreate(AudioSource source)
		{
			if (Plugin.audioSourceData.TryGetValue(source, out var value))
			{
				return value;
			}
			value = new AudioSourceData(source)
			{
				OriginalClip = source.clip
			};
			Plugin.audioSourceData[source] = value;
			return value;
		}
	}
	[HarmonyPatch(typeof(AudioSource))]
	public class AudioSourcePatch
	{
		[ThreadStatic]
		internal static bool bypassSpoofing;

		[HarmonyPrefix]
		[HarmonyPatch("Play", new Type[] { })]
		[HarmonyPatch("Play", new Type[] { typeof(ulong) })]
		[HarmonyPatch("Play", new Type[] { typeof(double) })]
		private static bool Play(AudioSource __instance)
		{
			AudioSourceData orCreate = AudioSourceData.GetOrCreate(__instance);
			AudioClip originalClip = orCreate.OriginalClip;
			AudioClip replacedSound = Plugin.GetReplacedSound(((originalClip != null) ? ((Object)originalClip).name : null) ?? "");
			if ((Object)(object)replacedSound == (Object)null)
			{
				return true;
			}
			orCreate.RealClip = replacedSound;
			using (new SpoofBypass())
			{
				__instance.clip = replacedSound;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("PlayOneShot", new Type[]
		{
			typeof(AudioClip),
			typeof(float)
		})]
		private static bool PlayOneShot(ref AudioClip clip)
		{
			AudioClip obj = clip;
			AudioClip replacedSound = Plugin.GetReplacedSound(((obj != null) ? ((Object)obj).name : null) ?? "");
			if ((Object)(object)replacedSound != (Object)null)
			{
				clip = replacedSound;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		private static bool ClipSetter(AudioSource __instance, AudioClip value)
		{
			if (bypassSpoofing)
			{
				return true;
			}
			if (Plugin.audioSourceData.TryGetValue(__instance, out var value2) && (Object)(object)value2.OriginalClip == (Object)(object)value)
			{
				return false;
			}
			AudioSourceData.GetOrCreate(__instance).OriginalClip = value;
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		private static void ClipGetter(AudioSource __instance, ref AudioClip __result)
		{
			if (!bypassSpoofing && Plugin.audioSourceData.TryGetValue(__instance, out var value) && (Object)(object)value.OriginalClip != (Object)null)
			{
				__result = value.OriginalClip;
			}
		}
	}
	public class SpoofBypass : IDisposable
	{
		public SpoofBypass()
		{
			AudioSourcePatch.bypassSpoofing = true;
		}

		public void Dispose()
		{
			AudioSourcePatch.bypassSpoofing = false;
		}
	}
	[BepInPlugin("JohnPorkMod", "JohnPorkMod", "1.1.3")]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(PhoneValuable), "Start")]
		internal static class PhoneValuableStartPatch
		{
			[HarmonyPostfix]
			private static void Postfix(PhoneValuable __instance)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					__instance.ringIntervalTimer = 0f;
					Logger.LogInfo((object)"[JohnPorkMod] First Time Phone Ringing");
				}
			}
		}

		[HarmonyPatch(typeof(PhoneValuable), "Update")]
		internal static class PhoneValuableUpdatePatch
		{
			private static float accumulatedTime = 0f;

			private static float targetInterval = -1f;

			[HarmonyPostfix]
			private static void Postfix(PhoneValuable __instance)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				if (targetInterval < 0f)
				{
					targetInterval = configMinInterval.Value;
				}
				if (!__instance.phoneRinging)
				{
					accumulatedTime += Time.deltaTime;
					if (__instance.ringIntervalTimer > 0f)
					{
						__instance.ringIntervalTimer = targetInterval;
					}
					if (accumulatedTime >= targetInterval)
					{
						__instance.ringIntervalTimer = 0f;
						accumulatedTime = 0f;
						int num = configMinInterval.Value;
						int value = configMaxInterval.Value;
						if (num > value)
						{
							num = value;
						}
						targetInterval = Random.Range(num, value + 1);
						Logger.LogInfo((object)$"[JohnPorkMod] Next interval from Config: {targetInterval}s");
					}
				}
				else
				{
					accumulatedTime = 0f;
				}
			}
		}

		internal static ManualLogSource Logger;

		internal static AudioClip replacementAudio;

		internal static Texture2D replacementTexture;

		internal static Dictionary<AudioSource, AudioSourceData> audioSourceData = new Dictionary<AudioSource, AudioSourceData>();

		internal static ConfigEntry<int> configMinInterval;

		internal static ConfigEntry<int> configMaxInterval;

		private static bool textureReplacerInitialized;

		private void Awake()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BaseUnityPlugin)this).Logger;
			configMinInterval = ((BaseUnityPlugin)this).Config.Bind<int>("Timer Settings", "MinInterval", 15, new ConfigDescription("Minimum wait time in seconds before the phone rings.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 200), Array.Empty<object>()));
			configMaxInterval = ((BaseUnityPlugin)this).Config.Bind<int>("Timer Settings", "MaxInterval", 100, new ConfigDescription("Maximum wait time in seconds before the phone rings.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(20, 300), Array.Empty<object>()));
			if (LoadAssetBundle())
			{
				new Harmony("JohnPorkMod").PatchAll();
				SceneManager.sceneLoaded += OnSceneLoaded;
				Logger.LogInfo((object)"Plugin loaded!");
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!textureReplacerInitialized)
			{
				textureReplacerInitialized = true;
				GameObject val = new GameObject("TextureReplacer");
				Object.DontDestroyOnLoad((Object)(object)val);
				val.AddComponent<TextureReplacer>();
			}
		}

		private bool LoadAssetBundle()
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			using Stream stream = executingAssembly.GetManifestResourceStream("smert_v_nishite.smert_v_nishite");
			if (stream == null)
			{
				Logger.LogError((object)"Embedded asset bundle not found.");
				return false;
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			AssetBundle val = AssetBundle.LoadFromMemory(array);
			if ((Object)(object)val == (Object)null)
			{
				Logger.LogError((object)"Failed to load asset bundle.");
				return false;
			}
			string[] allAssetNames = val.GetAllAssetNames();
			foreach (string text in allAssetNames)
			{
				if (text.EndsWith(".ogg"))
				{
					replacementAudio = val.LoadAsset<AudioClip>(text);
					Logger.LogDebug((object)("Ringtone loaded: " + text));
				}
				else if (text.EndsWith(".png"))
				{
					replacementTexture = val.LoadAsset<Texture2D>(text);
					Logger.LogDebug((object)("Screen loadded: " + text));
				}
			}
			return true;
		}

		public static AudioClip GetReplacedSound(string originalName)
		{
			return (originalName.ToLowerInvariant() == "phone ringtone") ? replacementAudio : null;
		}
	}
	public class TextureReplacer : MonoBehaviour
	{
		private const string ATLAS_NAME = "arctic small valuables_defaultmaterial_emissive";

		private const int OVERLAY_X = 241;

		private const int OVERLAY_Y_FROM_TOP = 107;

		private static readonly HashSet<int> processedMaterials = new HashSet<int>();

		private static readonly Dictionary<int, Texture2D> modifiedAtlasCache = new Dictionary<int, Texture2D>();

		private static readonly int EmissionMapId = Shader.PropertyToID("_EmissionMap");

		private float lastScanTime;

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(InitialScan());
		}

		private IEnumerator InitialScan()
		{
			yield return (object)new WaitForSeconds(0.5f);
			ScanRenderers();
		}

		private void Update()
		{
			if (!(Time.time - lastScanTime < 2f))
			{
				lastScanTime = Time.time;
				ScanRenderers();
			}
		}

		private void ScanRenderers()
		{
			Renderer[] array = Object.FindObjectsOfType<Renderer>();
			foreach (Renderer val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					TryReplacePropertyBlock(val);
					TryReplaceMaterials(val);
				}
			}
		}

		private void TryReplacePropertyBlock(Renderer renderer)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			MaterialPropertyBlock val = new MaterialPropertyBlock();
			renderer.GetPropertyBlock(val);
			Texture texture = val.GetTexture(EmissionMapId);
			Texture2D val2 = (Texture2D)(object)((texture is Texture2D) ? texture : null);
			if (val2 != null && !(((Object)val2).name?.ToLowerInvariant() != "arctic small valuables_defaultmaterial_emissive"))
			{
				Texture2D orCreateModifiedAtlas = GetOrCreateModifiedAtlas(val2);
				if (!((Object)(object)orCreateModifiedAtlas == (Object)null))
				{
					val.SetTexture(EmissionMapId, (Texture)(object)orCreateModifiedAtlas);
					renderer.SetPropertyBlock(val);
				}
			}
		}

		private void TryReplaceMaterials(Renderer renderer)
		{
			Material[] sharedMaterials = renderer.sharedMaterials;
			if (sharedMaterials == null)
			{
				return;
			}
			Material[] array = sharedMaterials;
			foreach (Material val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				int instanceID = ((Object)val).GetInstanceID();
				if (!processedMaterials.Contains(instanceID))
				{
					processedMaterials.Add(instanceID);
					if (!TryReplaceMaterialTexture(val, "_EmissionMap") && !TryReplaceMaterialTexture(val, "_MainTex"))
					{
						TryReplaceMaterialTexture(val, "_BaseMap");
					}
				}
			}
		}

		private bool TryReplaceMaterialTexture(Material mat, string prop)
		{
			if (!mat.HasProperty(prop))
			{
				return false;
			}
			Texture texture = mat.GetTexture(prop);
			Texture2D val = (Texture2D)(object)((texture is Texture2D) ? texture : null);
			if (val == null)
			{
				return false;
			}
			if (((Object)val).name?.ToLowerInvariant() != "arctic small valuables_defaultmaterial_emissive")
			{
				return false;
			}
			Texture2D orCreateModifiedAtlas = GetOrCreateModifiedAtlas(val);
			if ((Object)(object)orCreateModifiedAtlas == (Object)null)
			{
				return false;
			}
			mat.SetTexture(prop, (Texture)(object)orCreateModifiedAtlas);
			if (prop == "_EmissionMap")
			{
				try
				{
					mat.EnableKeyword("_EMISSION");
				}
				catch
				{
				}
			}
			return true;
		}

		private Texture2D GetOrCreateModifiedAtlas(Texture2D original)
		{
			int instanceID = ((Object)original).GetInstanceID();
			if (modifiedAtlasCache.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Texture2D val = CreateModifiedAtlas(original);
			if ((Object)(object)val != (Object)null)
			{
				modifiedAtlasCache[instanceID] = val;
			}
			return val;
		}

		private Texture2D CreateModifiedAtlas(Texture2D original)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)original == (Object)null || (Object)(object)Plugin.replacementTexture == (Object)null)
			{
				return null;
			}
			Texture2D replacementTexture = Plugin.replacementTexture;
			int num = ((Texture)original).height - 107 - ((Texture)replacementTexture).height;
			RenderTexture temporary = RenderTexture.GetTemporary(((Texture)original).width, ((Texture)original).height, 0, (RenderTextureFormat)0);
			Graphics.Blit((Texture)(object)original, temporary);
			Texture2D val = new Texture2D(((Texture)original).width, ((Texture)original).height, (TextureFormat)4, false, true);
			RenderTexture active = RenderTexture.active;
			RenderTexture.active = temporary;
			val.ReadPixels(new Rect(0f, 0f, (float)((Texture)original).width, (float)((Texture)original).height), 0, 0);
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			Color[] array = ReadPixels(replacementTexture);
			if (array == null)
			{
				return null;
			}
			val.SetPixels(241, num, ((Texture)replacementTexture).width, ((Texture)replacementTexture).height, array);
			val.Apply(false);
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)2;
			return val;
		}

		private Color[] ReadPixels(Texture2D tex)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			RenderTexture temporary = RenderTexture.GetTemporary(((Texture)tex).width, ((Texture)tex).height, 0, (RenderTextureFormat)0);
			Graphics.Blit((Texture)(object)tex, temporary);
			Texture2D val = new Texture2D(((Texture)tex).width, ((Texture)tex).height, (TextureFormat)4, false);
			RenderTexture active = RenderTexture.active;
			RenderTexture.active = temporary;
			val.ReadPixels(new Rect(0f, 0f, (float)((Texture)tex).width, (float)((Texture)tex).height), 0, 0);
			val.Apply();
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			Color[] pixels = val.GetPixels();
			Object.Destroy((Object)(object)val);
			return pixels;
		}

		private void OnDestroy()
		{
			processedMaterials.Clear();
			foreach (Texture2D value in modifiedAtlasCache.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			modifiedAtlasCache.Clear();
		}
	}
}