Decompiled source of SpeedSpell v1.0.0

BepInEX/plugins/SpeedSpell/SpeedSpell.dll

Decompiled 3 weeks 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 BepInEx;
using BlackMagicAPI.Managers;
using BlackMagicAPI.Modules.Spells;
using BlackMagicAPI.Network;
using FishNet;
using FishNet.Connection;
using FishNet.Object;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("SpeedSpell")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SpeedSpell")]
[assembly: AssemblyTitle("SpeedSpell")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SpeedSpell;

[BepInPlugin("com.thewargod_ares.speedspell", "SpeedSpell", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
	public const string GUID = "com.thewargod_ares.speedspell";

	public const string NAME = "SpeedSpell";

	public const string VERSION = "1.0.0";

	public static string modsync = "all";

	private void Awake()
	{
		BlackMagicManager.RegisterSpell((BaseUnityPlugin)(object)this, typeof(SpeedData), typeof(SpeedLogic));
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Speed spell loaded.");
	}
}
public class SpeedData : SpellData
{
	public override string Name => "Speed";

	public override float Cooldown => 30f;

	public override Color GlowColor => new Color(1f, 0.85f, 0f);

	public override string[] SubNames => new string[6] { "Speed Up", "Swiftness", "Haste", "Sprint", "Swift", "Go Fast" };

	public override bool CanSpawnInTeamChest => false;

	public override bool DebugForceSpawn => false;
}
public class SpeedLogic : SpellLogic
{
	private const float BOOST_MULTIPLIER = 2.5f;

	private const float DURATION = 15f;

	private static readonly string[] SPEED_FIELD_NAMES = new string[8] { "walkingSpeed", "runningSpeed", "movespeed", "moveSpeed", "MoveSpeed", "speed", "baseSpeed", "currentSpeed" };

	private static readonly string[] BONUS_FIELD_NAMES = new string[3] { "stewspeedboost", "pixiedustspeedmult", "currentSpeedMultiplier" };

	private const float BONUS_VALUE = 15f;

	public override bool CastSpell(PlayerMovement caster, PageController page, Vector3 spawnPos, Vector3 viewDirectionVector, int castingLevel)
	{
		Debug.Log((object)"[SpeedSpell] CastSpell fired — boost will apply via SyncData.");
		return true;
	}

	public override void WriteData(DataWriter writer, PageController page, PlayerMovement caster, Vector3 spawnPos, Vector3 viewDirectionVector, int level)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = (((Object)(object)caster != (Object)null) ? ((Component)caster).transform.position : spawnPos);
		writer.Write<float>(val.x);
		writer.Write<float>(val.y);
		writer.Write<float>(val.z);
	}

	public override void SyncData(object[] values)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		if (((SpellLogic)this).IsPrefab)
		{
			return;
		}
		Debug.Log((object)"[SpeedSpell] SyncData received on client.");
		try
		{
			Vector3 castPos = default(Vector3);
			((Vector3)(ref castPos))..ctor(Convert.ToSingle(values[0]), Convert.ToSingle(values[1]), Convert.ToSingle(values[2]));
			((MonoBehaviour)this).StartCoroutine(BoostLocalPlayer(castPos));
			((MonoBehaviour)this).StartCoroutine(PlayCastSound());
			((MonoBehaviour)this).StartCoroutine(SpawnSpeedParticles(castPos));
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[SpeedSpell] SyncData error: " + ex.Message));
		}
	}

	private IEnumerator SpawnSpeedParticles(Vector3 castPos)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		yield return null;
		Transform val = null;
		try
		{
			NetworkConnection val2 = InstanceFinder.ClientManager?.Connection;
			if (val2 != (NetworkConnection)null)
			{
				foreach (NetworkObject @object in val2.Objects)
				{
					PlayerMovement component = ((Component)@object).GetComponent<PlayerMovement>();
					if ((Object)(object)component != (Object)null)
					{
						val = ((Component)component).transform;
						break;
					}
				}
			}
		}
		catch
		{
		}
		if ((Object)(object)val == (Object)null)
		{
			PlayerMovement[] array = Object.FindObjectsOfType<PlayerMovement>();
			float num = float.MaxValue;
			PlayerMovement[] array2 = array;
			foreach (PlayerMovement val3 in array2)
			{
				float num2 = Vector3.Distance(((Component)val3).transform.position, castPos);
				if (num2 < num)
				{
					num = num2;
					val = ((Component)val3).transform;
				}
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			yield break;
		}
		GameObject psObj = new GameObject("SpeedAura");
		psObj.transform.SetParent(val);
		psObj.transform.localPosition = new Vector3(0f, 0.9f, 0f);
		ParticleSystem ps = psObj.AddComponent<ParticleSystem>();
		ParticleSystemRenderer component2 = psObj.GetComponent<ParticleSystemRenderer>();
		Material val4 = null;
		ParticleSystem[] array3 = Object.FindObjectsOfType<ParticleSystem>();
		for (int i = 0; i < array3.Length; i++)
		{
			ParticleSystemRenderer component3 = ((Component)array3[i]).GetComponent<ParticleSystemRenderer>();
			if ((Object)(object)component3 != (Object)null && (Object)(object)((Renderer)component3).sharedMaterial != (Object)null)
			{
				val4 = new Material(((Renderer)component3).sharedMaterial);
				val4.color = Color.white;
				break;
			}
		}
		if ((Object)(object)val4 == (Object)null)
		{
			string[] array4 = new string[5] { "Particles/Standard Unlit", "Particles/Alpha Blended", "Legacy Shaders/Particles/Alpha Blended", "Particles/Additive", "Legacy Shaders/Particles/Additive" };
			for (int i = 0; i < array4.Length; i++)
			{
				Shader val5 = Shader.Find(array4[i]);
				if ((Object)(object)val5 != (Object)null)
				{
					val4 = new Material(val5);
					val4.color = Color.white;
					break;
				}
			}
		}
		if ((Object)(object)val4 != (Object)null)
		{
			((Renderer)component2).material = val4;
		}
		MainModule main = ps.main;
		((MainModule)(ref main)).loop = true;
		((MainModule)(ref main)).duration = 15f;
		((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
		((MainModule)(ref main)).maxParticles = 300;
		((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.3f, 0.6f);
		((MainModule)(ref main)).startSpeed = new MinMaxCurve(2.5f, 5f);
		((MainModule)(ref main)).startSize = new MinMaxCurve(0.04f, 0.12f);
		((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(1f, 0.95f, 0.2f, 0.9f), new Color(1f, 0.55f, 0f, 0.7f));
		((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(-0.3f);
		EmissionModule emission = ps.emission;
		((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(40f);
		((EmissionModule)(ref emission)).SetBursts((Burst[])(object)new Burst[1]
		{
			new Burst(0f, (short)60)
		});
		ShapeModule shape = ps.shape;
		((ShapeModule)(ref shape)).enabled = true;
		((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0;
		((ShapeModule)(ref shape)).radius = 0.35f;
		ColorOverLifetimeModule colorOverLifetime = ps.colorOverLifetime;
		((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true;
		Gradient val6 = new Gradient();
		val6.SetKeys((GradientColorKey[])(object)new GradientColorKey[2]
		{
			new GradientColorKey(new Color(1f, 1f, 0.4f), 0f),
			new GradientColorKey(new Color(1f, 0.5f, 0f), 1f)
		}, (GradientAlphaKey[])(object)new GradientAlphaKey[3]
		{
			new GradientAlphaKey(1f, 0f),
			new GradientAlphaKey(0.6f, 0.4f),
			new GradientAlphaKey(0f, 1f)
		});
		((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val6);
		SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime;
		((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true;
		AnimationCurve val7 = new AnimationCurve((Keyframe[])(object)new Keyframe[2]
		{
			new Keyframe(0f, 1f),
			new Keyframe(1f, 0f)
		});
		((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, val7);
		ps.Play();
		yield return (object)new WaitForSeconds(15f);
		ps.Stop(true, (ParticleSystemStopBehavior)1);
		Object.Destroy((Object)(object)psObj, 1.5f);
	}

	private IEnumerator PlayCastSound()
	{
		string directoryName = Path.GetDirectoryName(((object)this).GetType().Assembly.Location);
		string wavPath = Path.Combine(directoryName, "Sounds", "SpeedSpell.wav");
		string text = "file:///" + wavPath.Replace('\\', '/');
		AudioClip clip = null;
		UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(text, (AudioType)20);
		yield return req.SendWebRequest();
		if ((int)req.result == 1)
		{
			clip = DownloadHandlerAudioClip.GetContent(req);
		}
		else
		{
			Debug.LogWarning((object)("[SpeedSpell] Audio load failed: " + req.error + " | path: " + wavPath));
		}
		req.Dispose();
		if (!((Object)(object)clip == (Object)null))
		{
			GameObject val = new GameObject("SpeedSpellAudio");
			AudioSource obj = val.AddComponent<AudioSource>();
			obj.spatialBlend = 0f;
			obj.volume = 1f;
			obj.clip = clip;
			obj.Play();
			Object.Destroy((Object)val, clip.length + 0.1f);
		}
	}

	private IEnumerator BoostLocalPlayer(Vector3 castPos)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		yield return null;
		PlayerMovement val = null;
		try
		{
			NetworkConnection val2 = InstanceFinder.ClientManager?.Connection;
			if (val2 != (NetworkConnection)null)
			{
				foreach (NetworkObject @object in val2.Objects)
				{
					PlayerMovement component = ((Component)@object).GetComponent<PlayerMovement>();
					if ((Object)(object)component != (Object)null)
					{
						val = component;
						Debug.Log((object)"[SpeedSpell] Found local player via InstanceFinder.");
						break;
					}
				}
			}
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[SpeedSpell] InstanceFinder path failed: " + ex.Message));
		}
		if ((Object)(object)val == (Object)null)
		{
			Debug.Log((object)"[SpeedSpell] Falling back to proximity search.");
			PlayerMovement[] array = Object.FindObjectsOfType<PlayerMovement>();
			float num = float.MaxValue;
			PlayerMovement[] array2 = array;
			foreach (PlayerMovement val3 in array2)
			{
				float num2 = Vector3.Distance(((Component)val3).transform.position, castPos);
				if (num2 < num)
				{
					num = num2;
					val = val3;
				}
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			Debug.LogWarning((object)"[SpeedSpell] Could not find local PlayerMovement.");
		}
		else
		{
			((MonoBehaviour)this).StartCoroutine(ApplyBoost(val, "CLIENT"));
		}
	}

	private IEnumerator ApplyBoost(PlayerMovement target, string context)
	{
		if ((Object)(object)target == (Object)null)
		{
			yield break;
		}
		Type type = ((object)target).GetType();
		Debug.Log((object)("[SpeedSpell][" + context + "] Float fields on " + type.Name + ":"));
		FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (fieldInfo.FieldType == typeof(float))
			{
				Debug.Log((object)$"  {fieldInfo.Name} = {fieldInfo.GetValue(target)}");
			}
		}
		List<(FieldInfo fi, float orig, bool isBonus)> boosted = new List<(FieldInfo, float, bool)>();
		string[] sPEED_FIELD_NAMES = SPEED_FIELD_NAMES;
		foreach (string text in sPEED_FIELD_NAMES)
		{
			FieldInfo field = type.GetField(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(field == null) && !(field.FieldType != typeof(float)))
			{
				float num = (float)field.GetValue(target);
				field.SetValue(target, num * 2.5f);
				boosted.Add((field, num, false));
				Debug.Log((object)$"[SpeedSpell][{context}] {text}: {num:F2} -> {num * 2.5f:F2}");
			}
		}
		sPEED_FIELD_NAMES = BONUS_FIELD_NAMES;
		foreach (string text2 in sPEED_FIELD_NAMES)
		{
			FieldInfo field2 = type.GetField(text2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(field2 == null) && !(field2.FieldType != typeof(float)))
			{
				float num2 = (float)field2.GetValue(target);
				field2.SetValue(target, num2 + 15f);
				boosted.Add((field2, num2, true));
				Debug.Log((object)$"[SpeedSpell][{context}] bonus {text2}: {num2:F2} -> {num2 + 15f:F2}");
			}
		}
		if (boosted.Count == 0)
		{
			Debug.LogWarning((object)("[SpeedSpell][" + context + "] No speed fields found — check the field dump above."));
			yield break;
		}
		Debug.Log((object)("[SpeedSpell][" + context + "] Boost active for " + 15f + "s."));
		yield return (object)new WaitForSeconds(15f);
		if ((Object)(object)target == (Object)null)
		{
			yield break;
		}
		foreach (var (fieldInfo2, num3, _) in boosted)
		{
			fieldInfo2.SetValue(target, num3);
		}
		Debug.Log((object)("[SpeedSpell][" + context + "] Boost expired, values restored."));
	}
}