Decompiled source of UsainsBelt v0.1.4

BepInEx/plugins/UsainsBelt/UsainsBelt.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace UsainsBelt;

internal static class Artwork
{
	internal static void Apply(GameObject prefab, ItemDrop drop, Color tint)
	{
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Invalid comparison between Unknown and I4
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Expected O, but got Unknown
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: 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_003c: Expected O, but got Unknown
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0225: Expected O, but got Unknown
		//IL_0271: Unknown result type (might be due to invalid IL or missing references)
		//IL_0277: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Unknown result type (might be due to invalid IL or missing references)
		//IL_0294: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val in componentsInChildren)
		{
			if (val is ParticleSystemRenderer)
			{
				continue;
			}
			Material[] sharedMaterials = val.sharedMaterials;
			for (int j = 0; j < sharedMaterials.Length; j++)
			{
				if (Object.op_Implicit((Object)(object)sharedMaterials[j]))
				{
					sharedMaterials[j] = new Material(sharedMaterials[j]);
					if (sharedMaterials[j].HasProperty("_Color"))
					{
						sharedMaterials[j].SetColor("_Color", tint);
					}
					if (sharedMaterials[j].HasProperty("_BaseColor"))
					{
						sharedMaterials[j].SetColor("_BaseColor", tint);
					}
				}
			}
			val.sharedMaterials = sharedMaterials;
		}
		if ((int)SystemInfo.graphicsDeviceType == 4)
		{
			return;
		}
		Sprite val2 = drop.m_itemData.m_shared.m_icons[0];
		Texture2D texture = val2.texture;
		RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0);
		RenderTexture active = RenderTexture.active;
		Texture2D val3 = null;
		try
		{
			Graphics.Blit((Texture)(object)texture, temporary);
			RenderTexture.active = temporary;
			val3 = new Texture2D(((Texture)texture).width, ((Texture)texture).height, (TextureFormat)4, false);
			val3.ReadPixels(new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), 0, 0);
			Rect rect = val2.rect;
			int num = Mathf.RoundToInt(((Rect)(ref rect)).width);
			Rect rect2 = val2.rect;
			int num2 = Mathf.RoundToInt(((Rect)(ref rect2)).height);
			Color[] array = IconRaster.Extract(val3.GetPixels(), ((Texture)texture).width, ((Texture)texture).height, num, num2, val2.vertices, val2.uv, val2.triangles, val2.pivot, val2.pixelsPerUnit);
			Object.Destroy((Object)(object)val3);
			val3 = null;
			for (int k = 0; k < array.Length; k++)
			{
				Color val4 = array[k];
				if (((Color)(ref val4)).maxColorComponent < 0.8f)
				{
					ref Color reference = ref array[k];
					reference = new Color(((Color)(ref val4)).grayscale * tint.r, ((Color)(ref val4)).grayscale * tint.g, ((Color)(ref val4)).grayscale * tint.b, val4.a);
				}
			}
			Texture2D val5 = new Texture2D(num, num2, (TextureFormat)4, false);
			((Object)val5).name = "UB_UsainsBelt_Icon";
			((Texture)val5).wrapMode = (TextureWrapMode)1;
			val5.SetPixels(array);
			val5.Apply();
			drop.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { Sprite.Create(val5, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(val2.pivot.x / (float)num, val2.pivot.y / (float)num2), val2.pixelsPerUnit) };
		}
		finally
		{
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			if (Object.op_Implicit((Object)(object)val3))
			{
				Object.Destroy((Object)(object)val3);
			}
		}
	}
}
internal static class IconRaster
{
	internal static Color[] Extract(Color[] atlas, int atlasWidth, int atlasHeight, int width, int height, Vector2[] vertices, Vector2[] uv, ushort[] triangles, Vector2 pivot, float pixelsPerUnit)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: 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_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_027b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_0287: Unknown result type (might be due to invalid IL or missing references)
		//IL_0295: Unknown result type (might be due to invalid IL or missing references)
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0304: Unknown result type (might be due to invalid IL or missing references)
		//IL_0309: Unknown result type (might be due to invalid IL or missing references)
		Color[] array = (Color[])(object)new Color[width * height];
		for (int i = 0; i < triangles.Length; i += 3)
		{
			int num = triangles[i];
			int num2 = triangles[i + 1];
			int num3 = triangles[i + 2];
			Vector2 val = vertices[num] * pixelsPerUnit + pivot;
			Vector2 val2 = vertices[num2] * pixelsPerUnit + pivot;
			Vector2 val3 = vertices[num3] * pixelsPerUnit + pivot;
			float num4 = (val2.y - val3.y) * (val.x - val3.x) + (val3.x - val2.x) * (val.y - val3.y);
			if (Math.Abs(num4) < 1E-06f)
			{
				continue;
			}
			int num5 = Math.Max(0, (int)Math.Floor(Math.Min(val.x, Math.Min(val2.x, val3.x))));
			int num6 = Math.Min(width - 1, (int)Math.Ceiling(Math.Max(val.x, Math.Max(val2.x, val3.x))));
			int num7 = Math.Max(0, (int)Math.Floor(Math.Min(val.y, Math.Min(val2.y, val3.y))));
			int num8 = Math.Min(height - 1, (int)Math.Ceiling(Math.Max(val.y, Math.Max(val2.y, val3.y))));
			for (int j = num7; j <= num8; j++)
			{
				for (int k = num5; k <= num6; k++)
				{
					float num9 = ((val2.y - val3.y) * ((float)k + 0.5f - val3.x) + (val3.x - val2.x) * ((float)j + 0.5f - val3.y)) / num4;
					float num10 = ((val3.y - val.y) * ((float)k + 0.5f - val3.x) + (val.x - val3.x) * ((float)j + 0.5f - val3.y)) / num4;
					float num11 = 1f - num9 - num10;
					if (!(num9 < -1E-05f) && !(num10 < -1E-05f) && !(num11 < -1E-05f))
					{
						Vector2 val4 = uv[num] * num9 + uv[num2] * num10 + uv[num3] * num11;
						int num12 = Math.Max(0, Math.Min(atlasWidth - 1, (int)Math.Floor(val4.x * (float)atlasWidth)));
						int num13 = Math.Max(0, Math.Min(atlasHeight - 1, (int)Math.Floor(val4.y * (float)atlasHeight)));
						ref Color reference = ref array[j * width + k];
						reference = atlas[num13 * atlasWidth + num12];
					}
				}
			}
		}
		return array;
	}
}
[BepInPlugin("au.tyvalheim.usainsbelt", "Usain's Belt", "0.1.4")]
public sealed class Plugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	private static class DB
	{
		private static void Prefix(ObjectDB __instance)
		{
			Instance.Register(__instance);
		}

		private static void Postfix()
		{
			Instance.Network(ZNetScene.instance);
		}
	}

	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	private static class Copy
	{
		private static void Postfix(ObjectDB __instance)
		{
			Instance.Register(__instance);
			AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null).Invoke(__instance, null);
			Instance.Network(ZNetScene.instance);
		}
	}

	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	private static class NetworkInit
	{
		private static void Prefix(ZNetScene __instance)
		{
			if (Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				Instance.Register(ObjectDB.instance);
			}
			if (Object.op_Implicit((Object)(object)Instance.prefab) && !Instance.failed && !__instance.m_prefabs.Contains(Instance.prefab))
			{
				__instance.m_prefabs.Add(Instance.prefab);
			}
		}

		private static void Postfix(ZNetScene __instance)
		{
			Instance.Network(__instance);
		}
	}

	public const string Id = "au.tyvalheim.usainsbelt";

	public const string Version = "0.1.4";

	public const string PrefabName = "UB_UsainsBelt";

	internal static Plugin Instance;

	internal ConfigEntry<float> Speed;

	internal ConfigEntry<float> RunReduction;

	internal ConfigEntry<float> JumpReduction;

	internal ConfigEntry<float> StaminaRecovery;

	private ConfigEntry<int> stationLevel;

	private ConfigEntry<bool> craftable;

	private ConfigEntry<string> ingredients;

	private ConfigEntry<string> station;

	private ConfigEntry<string> beltColour;

	private GameObject root;

	private GameObject prefab;

	private SE_UsainsBelt effect;

	private Recipe recipe;

	private bool failed;

	private void Awake()
	{
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Expected O, but got Unknown
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Expected O, but got Unknown
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		Speed = Percent("RunSpeedBonusPercent", 10f, 100f, "Bonus to running speed only.");
		RunReduction = Percent("RunStaminaReductionPercent", 50f, 100f, "Reduction in running stamina cost. Adds to other native stamina reductions.");
		JumpReduction = Percent("JumpStaminaReductionPercent", 50f, 100f, "Reduction in jumping stamina cost. Adds to other native stamina reductions.");
		StaminaRecovery = Percent("StaminaRecoveryBonusPercent", 10f, 100f, "Bonus to stamina regeneration rate while equipped. Uses native regeneration stacking; does not shorten the delay before recovery. Set 0 to disable.");
		craftable = ((BaseUnityPlugin)this).Config.Bind<bool>("Crafting", "Enabled", true, "Enable the conversion recipe. Restart required.");
		ingredients = ((BaseUnityPlugin)this).Config.Bind<string>("Crafting", "Materials", "BeltStrength:1,ScaleHide:10,Eitr:5", "Comma-separated prefab:amount pairs. Consumes the listed items, including Megingjord (BeltStrength). Restart required.");
		station = ((BaseUnityPlugin)this).Config.Bind<string>("Crafting", "Station", "piece_magetable", "Crafting station prefab name. Restart required.");
		stationLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Crafting", "StationLevel", 1, new ConfigDescription("Required crafting station level. Restart required.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[0]));
		beltColour = ((BaseUnityPlugin)this).Config.Bind<string>("Appearance", "BeltColour", "#39B85A", "HTML colour tint for the cloned belt and inventory icon. Restart required.");
		root = new GameObject("UsainsBelt_Prefabs");
		root.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)root);
		new Harmony("au.tyvalheim.usainsbelt").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Usain's Belt 0.1.4 playtest build loaded.");
	}

	private ConfigEntry<float> Percent(string key, float value, float max, string description)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		return ((BaseUnityPlugin)this).Config.Bind<float>("Balance", key, value, new ConfigDescription(description + " Restart required. Use matching settings on all clients/server.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, max), new object[0]));
	}

	internal void Register(ObjectDB db)
	{
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Expected O, but got Unknown
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_027a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0487: Unknown result type (might be due to invalid IL or missing references)
		//IL_048e: Expected O, but got Unknown
		if (failed)
		{
			return;
		}
		try
		{
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				GameObject val = ((IEnumerable<GameObject>)db.m_items).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => Object.op_Implicit((Object)(object)x) && ((Object)x).name == "BeltStrength"));
				if (!Object.op_Implicit((Object)(object)val))
				{
					return;
				}
				prefab = Object.Instantiate<GameObject>(val, root.transform, false);
				((Object)prefab).name = "UB_UsainsBelt";
				ItemDrop component = prefab.GetComponent<ItemDrop>();
				component.m_itemData = val.GetComponent<ItemDrop>().m_itemData.Clone();
				component.m_itemData.m_shared = (SharedData)AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null).Invoke(component.m_itemData.m_shared, null);
				SharedData shared = component.m_itemData.m_shared;
				shared.m_name = "Usain's Belt";
				shared.m_description = "For the Viking who is already halfway home. A fleet-footed belt that makes running and jumping less tiring and helps you catch your breath.";
				shared.m_itemType = (ItemType)18;
				shared.m_maxStackSize = 1;
				shared.m_maxQuality = 1;
				shared.m_value = 0;
				shared.m_setName = "";
				shared.m_setStatusEffect = null;
				shared.m_movementModifier = 0f;
				shared.m_armor = 0f;
				shared.m_armorPerLevel = 0f;
				effect = ScriptableObject.CreateInstance<SE_UsainsBelt>();
				((Object)effect).name = "UB_FleetFooted";
				((StatusEffect)effect).m_name = "Usain's Belt";
				effect.RunBonus = Speed.Value / 100f;
				((SE_Stats)effect).m_runStaminaDrainModifier = (0f - RunReduction.Value) / 100f;
				((SE_Stats)effect).m_jumpStaminaUseModifier = (0f - JumpReduction.Value) / 100f;
				((SE_Stats)effect).m_staminaRegenMultiplier = 1f + StaminaRecovery.Value / 100f;
				((StatusEffect)effect).m_tooltip = "Running speed: +" + Speed.Value.ToString("0.#") + "%";
				shared.m_equipStatusEffect = (StatusEffect)(object)effect;
				component.m_itemData.m_dropPrefab = prefab;
				component.m_itemData.m_stack = 1;
				Color tint = default(Color);
				if (!ColorUtility.TryParseHtmlString(beltColour.Value, ref tint))
				{
					tint = new Color(0.22f, 0.72f, 0.35f);
				}
				Artwork.Apply(prefab, component, tint);
				((StatusEffect)effect).m_icon = shared.m_icons[0];
				prefab.SetActive(true);
			}
			if (!db.m_items.Contains(prefab))
			{
				db.m_items.Add(prefab);
			}
			if (!db.m_StatusEffects.Contains((StatusEffect)(object)effect))
			{
				db.m_StatusEffects.Add((StatusEffect)(object)effect);
			}
			if (!Object.op_Implicit((Object)(object)recipe))
			{
				CraftingStation val2 = (from x in db.m_recipes
					where Object.op_Implicit((Object)(object)x) && Object.op_Implicit((Object)(object)x.m_craftingStation)
					select x.m_craftingStation).FirstOrDefault((Func<CraftingStation, bool>)((CraftingStation x) => ((Object)x).name == station.Value));
				if (!Object.op_Implicit((Object)(object)val2))
				{
					return;
				}
				List<Requirement> list = new List<Requirement>();
				string[] array = ingredients.Value.Split(new char[1] { ',' });
				foreach (string text in array)
				{
					string[] pair = text.Trim().Split(new char[1] { ':' });
					if (pair.Length != 2 || !int.TryParse(pair[1], out var result) || result < 1 || result > 10000)
					{
						throw new InvalidOperationException("Invalid crafting material: " + text);
					}
					GameObject item = ((IEnumerable<GameObject>)db.m_items).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => Object.op_Implicit((Object)(object)x) && ((Object)x).name == pair[0].Trim()));
					if (!Object.op_Implicit((Object)(object)item) || (Object)(object)item == (Object)(object)prefab)
					{
						throw new InvalidOperationException("Unknown or self-referencing crafting material: " + text);
					}
					if (list.Any((Requirement x) => (Object)(object)x.m_resItem == (Object)(object)item.GetComponent<ItemDrop>()))
					{
						throw new InvalidOperationException("Duplicate crafting material: " + text);
					}
					Requirement val3 = new Requirement();
					val3.m_resItem = item.GetComponent<ItemDrop>();
					val3.m_amount = result;
					val3.m_amountPerLevel = 0;
					val3.m_recover = false;
					list.Add(val3);
				}
				recipe = ScriptableObject.CreateInstance<Recipe>();
				((Object)recipe).name = "Recipe_UsainsBelt";
				recipe.m_item = prefab.GetComponent<ItemDrop>();
				recipe.m_amount = 1;
				recipe.m_enabled = craftable.Value;
				recipe.m_craftingStation = val2;
				recipe.m_minStationLevel = stationLevel.Value;
				recipe.m_resources = list.ToArray();
			}
			if (!db.m_recipes.Contains(recipe))
			{
				db.m_recipes.Add(recipe);
			}
		}
		catch (Exception ex)
		{
			failed = true;
			((BaseUnityPlugin)this).Logger.LogError((object)("Usain's Belt registration failed: " + ex));
		}
	}

	internal void Network(ZNetScene scene)
	{
		if (Object.op_Implicit((Object)(object)scene) && Object.op_Implicit((Object)(object)prefab) && !failed)
		{
			Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(scene);
			int stableHashCode = StringExtensionMethods.GetStableHashCode("UB_UsainsBelt");
			if (dictionary.TryGetValue(stableHashCode, out var value) && (Object)(object)value != (Object)(object)prefab)
			{
				throw new InvalidOperationException("Usain's Belt prefab hash collision.");
			}
			if (!scene.m_prefabs.Contains(prefab))
			{
				scene.m_prefabs.Add(prefab);
			}
			dictionary[stableHashCode] = prefab;
		}
	}
}
public sealed class SE_UsainsBelt : SE_Stats
{
	public float RunBonus;

	public override void ModifySpeed(float baseSpeed, ref float speed, Character character, Vector3 dir)
	{
		if (Object.op_Implicit((Object)(object)character) && character.IsRunning() && !character.IsSwimming())
		{
			speed += baseSpeed * RunBonus;
		}
	}
}