Decompiled source of VikingLove v1.4.3

VikingLove.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("VikingLove")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.3.0")]
[assembly: AssemblyInformationalVersion("1.4.3")]
[assembly: AssemblyProduct("VikingLove")]
[assembly: AssemblyTitle("VikingLove")]
[assembly: AssemblyVersion("1.4.3.0")]
[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 VikingLove
{
	public sealed class Synced<T> : ConfigSync.ISyncedEntry
	{
		private readonly ConfigEntry<T> _entry;

		private T _serverValue;

		private bool _hasServerValue;

		public T Value
		{
			get
			{
				if (!_hasServerValue)
				{
					return _entry.Value;
				}
				return _serverValue;
			}
		}

		public T LocalValue => _entry.Value;

		public bool IsServerControlled => _hasServerValue;

		string ConfigSync.ISyncedEntry.Key => ((ConfigEntryBase)_entry).Definition.Section + "/" + ((ConfigEntryBase)_entry).Definition.Key;

		internal Synced(ConfigEntry<T> entry)
		{
			_entry = entry;
		}

		string ConfigSync.ISyncedEntry.SerializeLocal()
		{
			return TomlTypeConverter.ConvertToString((object)_entry.Value, typeof(T));
		}

		void ConfigSync.ISyncedEntry.ApplyServerValue(string raw)
		{
			try
			{
				_serverValue = (T)TomlTypeConverter.ConvertToValue(raw, typeof(T));
				_hasServerValue = true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read server value '" + raw + "' for " + ((ConfigSync.ISyncedEntry)this).Key + ": " + ex.Message));
			}
		}

		void ConfigSync.ISyncedEntry.ClearServerValue()
		{
			_hasServerValue = false;
			_serverValue = default(T);
		}
	}
	public static class ConfigSync
	{
		public interface ISyncedEntry
		{
			string Key { get; }

			string SerializeLocal();

			void ApplyServerValue(string raw);

			void ClearServerValue();
		}

		public const string RpcPush = "VikingLove_ConfigSync";

		public const string RpcRequest = "VikingLove_ConfigRequest";

		private static readonly List<ISyncedEntry> Entries = new List<ISyncedEntry>();

		private static readonly Dictionary<string, ISyncedEntry> ByKey = new Dictionary<string, ISyncedEntry>(StringComparer.Ordinal);

		private static readonly List<string> Overridden = new List<string>();

		public static bool ServerControlled { get; private set; }

		public static int Count => Entries.Count;

		public static Synced<T> Register<T>(ConfigEntry<T> entry)
		{
			Synced<T> synced = new Synced<T>(entry);
			Entries.Add(synced);
			ByKey[((ISyncedEntry)synced).Key] = synced;
			return synced;
		}

		public static ZPackage BuildPackage()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write("1.4.3");
			val.Write(Entries.Count);
			foreach (ISyncedEntry entry in Entries)
			{
				val.Write(entry.Key);
				string text;
				try
				{
					text = entry.SerializeLocal();
				}
				catch
				{
					text = "";
				}
				val.Write(text);
			}
			return val;
		}

		public static void ApplyPackage(ZPackage pkg)
		{
			if (pkg == null)
			{
				return;
			}
			try
			{
				pkg.SetPos(0);
				string text = pkg.ReadString();
				if (text != "1.4.3")
				{
					Plugin.Log.LogWarning((object)("The server runs VikingLove " + text + " and you run 1.4.3. Applying what it sent; update if anything looks wrong."));
				}
				int num = pkg.ReadInt();
				int num2 = 0;
				int num3 = 0;
				Overridden.Clear();
				for (int i = 0; i < num; i++)
				{
					string text2 = pkg.ReadString();
					string text3 = pkg.ReadString();
					if (!ByKey.TryGetValue(text2, out var value))
					{
						num3++;
						continue;
					}
					string text4 = null;
					try
					{
						text4 = value.SerializeLocal();
					}
					catch
					{
					}
					value.ApplyServerValue(text3);
					num2++;
					if (text4 != null && !string.Equals(text4, text3, StringComparison.Ordinal))
					{
						Overridden.Add(text2 + ": the server says " + text3 + ", yours says " + text4);
					}
				}
				ServerControlled = num2 > 0;
				Plugin.Log.LogInfo((object)("Applied " + num2 + " VikingLove settings from the server" + ((num3 > 0) ? (" (" + num3 + " unrecognised, ignored)") : "") + "."));
				if (Overridden.Count == 0)
				{
					return;
				}
				Plugin.Log.LogWarning((object)("This server sets " + Overridden.Count + " VikingLove setting(s) differently from yours. The server decides while you are on it, so editing these will look like it does nothing until you leave."));
				foreach (string item in Overridden)
				{
					Plugin.Log.LogWarning((object)("  " + item));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Malformed config package from the server, keeping local settings: " + ex.Message));
			}
		}

		public static void ClearServerValues()
		{
			bool serverControlled = ServerControlled;
			foreach (ISyncedEntry entry in Entries)
			{
				entry.ClearServerValue();
			}
			Overridden.Clear();
			ServerControlled = false;
			if (serverControlled)
			{
				Plugin.Log.LogInfo((object)"Your own VikingLove settings are back in force.");
			}
		}

		public static void PushToEveryone()
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && ZRoutedRpc.instance != null)
			{
				int count = ZNet.instance.GetPeers().Count;
				if (count != 0)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, "VikingLove_ConfigSync", new object[1] { BuildPackage() });
					Plugin.Log.LogInfo((object)("Sent VikingLove settings to " + count + " player(s)."));
				}
			}
		}

		public static void OnConfigRequested(long sender)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && ZRoutedRpc.instance != null && sender != 0L)
			{
				Plugin.Log.LogInfo((object)("Sending VikingLove settings to peer " + sender + "."));
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "VikingLove_ConfigSync", new object[1] { BuildPackage() });
			}
		}

		public static void OnConfigReceived(long sender, ZPackage pkg)
		{
			if (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer())
			{
				ApplyPackage(pkg);
			}
		}
	}
	public class CreatureAnchor
	{
		private static readonly FieldRef<Character, GameObject> VisualRef = AccessTools.FieldRefAccess<Character, GameObject>("m_visual");

		private static readonly FieldRef<Character, CapsuleCollider> ColliderRef = AccessTools.FieldRefAccess<Character, CapsuleCollider>("m_collider");

		private static readonly Dictionary<Character, CreatureAnchor> Cache = new Dictionary<Character, CreatureAnchor>();

		private readonly List<Transform> _bones = new List<Transform>();

		private string _mode = "bounds";

		public static void PruneCache()
		{
			List<Character> list = new List<Character>();
			foreach (KeyValuePair<Character, CreatureAnchor> item in Cache)
			{
				if ((Object)(object)item.Key == (Object)null)
				{
					list.Add(item.Key);
				}
			}
			foreach (Character item2 in list)
			{
				Cache.Remove(item2);
			}
		}

		public static CreatureAnchor Get(Character c)
		{
			if (Cache.TryGetValue(c, out var value))
			{
				return value;
			}
			value = Resolve(c);
			Cache[c] = value;
			return value;
		}

		private static bool Has(string n, params string[] words)
		{
			foreach (string value in words)
			{
				if (n.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsLeft(string n)
		{
			if (!n.Contains("left") && !n.Contains("_l_") && !n.EndsWith("_l") && !n.EndsWith(".l") && !n.StartsWith("l_"))
			{
				return n.Contains(".l.");
			}
			return true;
		}

		private static bool IsRight(string n)
		{
			if (!n.Contains("right") && !n.Contains("_r_") && !n.EndsWith("_r") && !n.EndsWith(".r") && !n.StartsWith("r_"))
			{
				return n.Contains(".r.");
			}
			return true;
		}

		private static CreatureAnchor Resolve(Character c)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			CreatureAnchor creatureAnchor = new CreatureAnchor();
			Transform[] componentsInChildren = ((Component)(((Object)(object)VisualRef.Invoke(c) != (Object)null) ? VisualRef.Invoke(c).transform : ((Component)c).transform)).GetComponentsInChildren<Transform>(true);
			Transform val = null;
			Transform val2 = null;
			Transform val3 = null;
			Transform val4 = null;
			Transform val5 = null;
			Vector3 forward = ((Component)c).transform.forward;
			Transform[] array = componentsInChildren;
			foreach (Transform val6 in array)
			{
				string n = ((Object)val6).name.ToLowerInvariant();
				if ((Object)(object)val5 == (Object)null && Has(n, "pelvis", "hips", "hip_", "_hip"))
				{
					val5 = val6;
				}
				if (!Has(n, "thigh", "upleg", "upperleg", "up_leg", "leg_upper", "leg1", "leg_1", "femur"))
				{
					continue;
				}
				if (Has(n, "hind", "back", "rear", "hindleg", "backleg"))
				{
					if ((Object)(object)val == (Object)null && IsLeft(n) && !IsRight(n))
					{
						val = val6;
					}
					if ((Object)(object)val2 == (Object)null && IsRight(n) && !IsLeft(n))
					{
						val2 = val6;
					}
				}
				else
				{
					if ((Object)(object)val3 == (Object)null && IsLeft(n) && !IsRight(n))
					{
						val3 = val6;
					}
					if ((Object)(object)val4 == (Object)null && IsRight(n) && !IsLeft(n))
					{
						val4 = val6;
					}
				}
			}
			if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null)
			{
				creatureAnchor._bones.Add(val);
				creatureAnchor._bones.Add(val2);
				creatureAnchor._mode = "rear legs";
			}
			else if ((Object)(object)val3 != (Object)null && (Object)(object)val4 != (Object)null)
			{
				Transform item = val3;
				Transform item2 = val4;
				float num = float.MaxValue;
				array = componentsInChildren;
				foreach (Transform val7 in array)
				{
					string n2 = ((Object)val7).name.ToLowerInvariant();
					if (Has(n2, "thigh", "upleg", "upperleg", "up_leg", "leg_upper", "leg1", "leg_1", "femur"))
					{
						float num2 = Vector3.Dot(val7.position - ((Component)c).transform.position, forward);
						if (IsLeft(n2) && !IsRight(n2) && num2 < num)
						{
							num = num2;
							item = val7;
						}
					}
				}
				array = componentsInChildren;
				foreach (Transform val8 in array)
				{
					string n3 = ((Object)val8).name.ToLowerInvariant();
					if (Has(n3, "thigh", "upleg", "upperleg", "up_leg", "leg_upper", "leg1", "leg_1", "femur") && IsRight(n3) && !IsLeft(n3) && Mathf.Abs(Vector3.Dot(val8.position - ((Component)c).transform.position, forward) - num) < 0.15f)
					{
						item2 = val8;
						break;
					}
				}
				creatureAnchor._bones.Add(item);
				creatureAnchor._bones.Add(item2);
				creatureAnchor._mode = "legs";
			}
			else if ((Object)(object)val5 != (Object)null)
			{
				creatureAnchor._bones.Add(val5);
				creatureAnchor._mode = "pelvis";
			}
			Plugin.Log.LogInfo((object)("VikingLove creature anchor for " + c.m_name + ": " + creatureAnchor._mode + ((creatureAnchor._bones.Count > 0) ? (" (" + ((Object)creatureAnchor._bones[0]).name + ((creatureAnchor._bones.Count > 1) ? (", " + ((Object)creatureAnchor._bones[1]).name) : "") + ")") : "")));
			return creatureAnchor;
		}

		public Vector3 Position(Character c)
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			if (_bones.Count == 2 && (Object)(object)_bones[0] != (Object)null && (Object)(object)_bones[1] != (Object)null)
			{
				return (_bones[0].position + _bones[1].position) * 0.5f;
			}
			if (_bones.Count == 1 && (Object)(object)_bones[0] != (Object)null)
			{
				return _bones[0].position;
			}
			CapsuleCollider val = ColliderRef.Invoke(c);
			Bounds val2 = (Bounds)(((Object)(object)val != (Object)null) ? ((Collider)val).bounds : new Bounds(c.GetCenterPoint(), Vector3.one * (c.GetRadius() * 2f)));
			Vector3 forward = ((Component)c).transform.forward;
			forward.y = 0f;
			((Vector3)(ref forward)).Normalize();
			float num = ((Bounds)(ref val2)).min.y + ((Bounds)(ref val2)).size.y * Mathf.Clamp01(Plugin.CreatureAnchorHeight.Value);
			Vector3 val3 = ((Bounds)(ref val2)).center - forward * (((Bounds)(ref val2)).extents.z * 0.6f);
			return new Vector3(val3.x, num, val3.z);
		}
	}
	public class GenitalAttachment : MonoBehaviour
	{
		private static readonly FieldRef<Character, Animator> AnimatorRef = AccessTools.FieldRefAccess<Character, Animator>("m_animator");

		private static readonly FieldRef<Character, GameObject> VisualRef = AccessTools.FieldRefAccess<Character, GameObject>("m_visual");

		private static readonly int SkinColorId = Shader.PropertyToID("_SkinColor");

		private static readonly int MainTexId = Shader.PropertyToID("_MainTex");

		private Player _player;

		private VisEquipment _vis;

		private Transform _hips;

		private Transform _spine;

		private Transform _legL;

		private Transform _legR;

		private GameObject _obj;

		private MeshRenderer _renderer;

		private Material[] _mats;

		private float _nextColorSync;

		private string _builtWithTone;

		private Material _bodyMat;

		private float _skinFactor = 1f;

		private bool _skinLogged;

		private bool _bonesResolved;

		private float _fwdSign;

		private Quaternion _hipsOffset;

		private bool _hiddenForOral;

		private static readonly Dictionary<Player, GenitalAttachment> Attachments = new Dictionary<Player, GenitalAttachment>();

		private Mesh _mesh;

		private static readonly FieldRef<Character, Rigidbody> BodyRef = AccessTools.FieldRefAccess<Character, Rigidbody>("m_body");

		private float _swPitch;

		private float _swPitchVel;

		private float _swYaw;

		private float _swYawVel;

		private Vector3 _lastVel;

		private float _lastYaw;

		private bool _yawInit;

		private bool _velInit;

		private float _runPhase;

		private ParticleSystem _spray;

		private float _sprayUntil;

		private static readonly FieldRef<Character, ZNetView> NviewRef = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview");

		private bool _stroking;

		private float _nextEmoteCheck;

		private bool _emoteCached;

		private float _strokeStart;

		private float _strokePhase;

		private Vector3[] _baseVerts;

		private float _stretch = 1f;

		private float _appliedStretch = 1f;

		private const float ShaftStartZ = 0.12f;

		private const float TipZ = 0.57f;

		public Transform MeshTransform
		{
			get
			{
				if (!((Object)(object)_obj != (Object)null))
				{
					return null;
				}
				return _obj.transform;
			}
		}

		public bool Visible
		{
			get
			{
				if ((Object)(object)_obj != (Object)null)
				{
					return _obj.activeSelf;
				}
				return false;
			}
			set
			{
				if ((Object)(object)_obj != (Object)null && _obj.activeSelf != value)
				{
					_obj.SetActive(value);
				}
			}
		}

		public void SetHiddenForOral(bool hidden)
		{
			if (_hiddenForOral != hidden)
			{
				_hiddenForOral = hidden;
				if ((Object)(object)_renderer != (Object)null)
				{
					((Renderer)_renderer).enabled = !hidden;
				}
			}
		}

		public static GenitalAttachment Ensure(Player player, VisEquipment vis)
		{
			if (Attachments.TryGetValue(player, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			value = ((Component)player).GetComponent<GenitalAttachment>();
			if ((Object)(object)value == (Object)null)
			{
				value = ((Component)player).gameObject.AddComponent<GenitalAttachment>();
				value._player = player;
				value._vis = vis;
			}
			Attachments[player] = value;
			return value;
		}

		public static void PruneCaches()
		{
			List<Player> list = new List<Player>();
			foreach (KeyValuePair<Player, GenitalAttachment> attachment in Attachments)
			{
				if ((Object)(object)attachment.Key == (Object)null || (Object)(object)attachment.Value == (Object)null)
				{
					list.Add(attachment.Key);
				}
			}
			foreach (Player item in list)
			{
				Attachments.Remove(item);
			}
		}

		private void Start()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if ((Object)(object)Plugin.GenitalMesh == (Object)null)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			_obj = new GameObject("VikingLove_Mesh");
			_obj.transform.SetParent(((Component)this).transform, false);
			_mesh = Object.Instantiate<Mesh>(Plugin.GenitalMesh);
			_baseVerts = _mesh.vertices;
			_obj.AddComponent<MeshFilter>().sharedMesh = _mesh;
			_renderer = _obj.AddComponent<MeshRenderer>();
			((Renderer)_renderer).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)_renderer).receiveShadows = true;
			BuildMaterials();
			_obj.SetActive(false);
		}

		private unsafe void BuildMaterials()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e6: Expected O, but got Unknown
			//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Expected O, but got Unknown
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Expected O, but got Unknown
			_builtWithTone = Plugin.SkinToneOverride.Value;
			Material val = null;
			Material val2 = null;
			SkinnedMeshRenderer val3 = (((Object)(object)_vis != (Object)null) ? _vis.m_bodyModel : null);
			Color value = default(Color);
			((Color)(ref value))..ctor(0.72f, 0.55f, 0.43f);
			Vector2 bestUv = default(Vector2);
			((Vector2)(ref bestUv))..ctor(-1f, -1f);
			Color? val4 = SkinTexture.ParseHex(Plugin.SkinToneOverride.Value);
			if (val4.HasValue)
			{
				value = val4.Value;
			}
			else if ((Object)(object)val3 != (Object)null && ((Renderer)val3).materials.Length != 0)
			{
				Vector2[] uvs = (((Object)(object)val3.sharedMesh != (Object)null) ? val3.sharedMesh.uv : null);
				Color? val5 = SkinTexture.SampleAtUvs(((Renderer)val3).materials[0].GetTexture(MainTexId), uvs, out bestUv);
				float num = (val5.HasValue ? (val5.Value.r * 0.3f + val5.Value.g * 0.59f + val5.Value.b * 0.11f) : 0f);
				if (val5.HasValue && num > 0.12f)
				{
					value = val5.Value;
				}
				ManualLogSource log = Plugin.Log;
				string[] obj = new string[8]
				{
					"VikingLove skin sample for ",
					_player.GetPlayerName(),
					": ",
					val5.HasValue ? ((object)val5.Value/*cast due to .constrained prefix*/).ToString() : "none",
					" lum=",
					num.ToString("0.00"),
					" -> using ",
					null
				};
				Color val6 = value;
				obj[7] = ((object)(*(Color*)(&val6))/*cast due to .constrained prefix*/).ToString();
				log.LogInfo((object)string.Concat(obj));
			}
			Color baseTone = new Color(value.r * 0.9f, value.g * 0.68f, value.b * 0.66f);
			Texture2D val7 = SkinTexture.Generate(value, 128, 11);
			Texture2D val8 = SkinTexture.Generate(baseTone, 128, 23);
			if (Plugin.UseBodyShader.Value && (Object)(object)val3 != (Object)null && ((Renderer)val3).materials.Length != 0)
			{
				try
				{
					val = new Material(((Renderer)val3).materials[0]);
					Texture2D val9 = SkinTexture.Solid(new Color(0f, 0f, 0f, 0f));
					Texture2D val10 = SkinTexture.Solid(new Color(0.5f, 0.5f, 1f, 1f));
					string[] array = new string[2] { "_ChestTex", "_LegsTex" };
					foreach (string text in array)
					{
						if (val.HasProperty(text))
						{
							val.SetTexture(text, (Texture)(object)val9);
						}
					}
					if (!val4.HasValue && bestUv.x >= 0f)
					{
						MoveShaftUvs(bestUv);
					}
					else
					{
						val.SetTexture(MainTexId, (Texture)(object)val7);
						array = new string[2] { "_SkinBumpMap", "_BumpMap" };
						foreach (string text2 in array)
						{
							if (val.HasProperty(text2))
							{
								val.SetTexture(text2, (Texture)(object)val10);
							}
						}
					}
					val2 = new Material(val);
					val2.SetTexture(MainTexId, (Texture)(object)val8);
					array = new string[2] { "_SkinBumpMap", "_BumpMap" };
					foreach (string text3 in array)
					{
						if (val2.HasProperty(text3))
						{
							val2.SetTexture(text3, (Texture)(object)val10);
						}
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Body shader clone failed, falling back to Standard: " + ex.Message));
					val = null;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Shader obj2 = Shader.Find("Standard") ?? Shader.Find("Diffuse");
				val = new Material(obj2);
				val.mainTexture = (Texture)(object)val7;
				val2 = new Material(obj2);
				val2.mainTexture = (Texture)(object)val8;
				if (val.HasProperty("_Glossiness"))
				{
					val.SetFloat("_Glossiness", 0.2f);
					val2.SetFloat("_Glossiness", 0.3f);
				}
			}
			_mats = (Material[])(object)new Material[2] { val, val2 };
			((Renderer)_renderer).sharedMaterials = _mats;
		}

		private void MoveShaftUvs(Vector2 uv)
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_mesh == (Object)null) && _mesh.subMeshCount != 0)
			{
				Vector2[] array = _mesh.uv;
				if (array == null || array.Length != _mesh.vertexCount)
				{
					array = (Vector2[])(object)new Vector2[_mesh.vertexCount];
				}
				int[] triangles = _mesh.GetTriangles(0);
				Vector3[] vertices = _mesh.vertices;
				int[] array2 = triangles;
				foreach (int num in array2)
				{
					float num2 = Mathf.PerlinNoise(vertices[num].x * 40f + 3.1f, vertices[num].z * 40f) - 0.5f;
					float num3 = Mathf.PerlinNoise(vertices[num].y * 40f + 7.7f, vertices[num].z * 40f + 1.3f) - 0.5f;
					array[num] = uv + new Vector2(num2, num3) * 0.004f;
				}
				_mesh.uv = array;
			}
		}

		private unsafe void SyncSkinColor()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_vis == (Object)null || (Object)(object)_vis.m_bodyModel == (Object)null || _mats == null)
			{
				return;
			}
			if ((Object)(object)_bodyMat == (Object)null)
			{
				Material[] materials = ((Renderer)_vis.m_bodyModel).materials;
				if (materials.Length == 0)
				{
					return;
				}
				_bodyMat = materials[0];
			}
			if (!_bodyMat.HasProperty(SkinColorId))
			{
				return;
			}
			Color color = _bodyMat.GetColor(SkinColorId);
			Material[] mats = _mats;
			foreach (Material val in mats)
			{
				if ((Object)(object)val != (Object)null && val.HasProperty(SkinColorId))
				{
					val.SetColor(SkinColorId, color);
				}
			}
			float num = color.r * 0.3f + color.g * 0.59f + color.b * 0.11f;
			float num2 = Mathf.InverseLerp(Plugin.LightestSkinLuminance.Value, Plugin.DarkestSkinLuminance.Value, num);
			_skinFactor = Mathf.Lerp(Plugin.SizeAtLightestSkin.Value, Plugin.SizeAtDarkestSkin.Value, Mathf.Clamp01(num2));
			if (!_skinLogged)
			{
				_skinLogged = true;
				ManualLogSource log = Plugin.Log;
				string[] obj = new string[8]
				{
					"VikingLove skin-size for ",
					_player.GetPlayerName(),
					": skinColor=",
					null,
					null,
					null,
					null,
					null
				};
				Color val2 = color;
				obj[3] = ((object)(*(Color*)(&val2))/*cast due to .constrained prefix*/).ToString();
				obj[4] = " lum=";
				obj[5] = num.ToString("0.00");
				obj[6] = " -> size x";
				obj[7] = _skinFactor.ToString("0.00");
				log.LogInfo((object)string.Concat(obj));
			}
		}

		private void ResolveBones()
		{
			//IL_039b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Expected O, but got Unknown
			_bonesResolved = true;
			Animator val = AnimatorRef.Invoke((Character)(object)_player);
			if ((Object)(object)val != (Object)null && val.isHuman)
			{
				_hips = val.GetBoneTransform((HumanBodyBones)0);
				_spine = val.GetBoneTransform((HumanBodyBones)7);
				_legL = val.GetBoneTransform((HumanBodyBones)1);
				_legR = val.GetBoneTransform((HumanBodyBones)2);
			}
			Transform val2 = (((Object)(object)VisualRef.Invoke((Character)(object)_player) != (Object)null) ? VisualRef.Invoke((Character)(object)_player).transform : ((Component)this).transform);
			if ((Object)(object)_hips == (Object)null || (Object)(object)_legL == (Object)null || (Object)(object)_legR == (Object)null || (Object)(object)_spine == (Object)null)
			{
				Transform[] componentsInChildren = ((Component)val2).GetComponentsInChildren<Transform>(true);
				foreach (Transform val3 in componentsInChildren)
				{
					string text = ((Object)val3).name.ToLowerInvariant();
					if ((Object)(object)_hips == (Object)null)
					{
						switch (text)
						{
						default:
							if (!text.EndsWith("_hips") && !text.EndsWith("pelvis"))
							{
								break;
							}
							goto case "hips";
						case "hips":
						case "hip":
						case "pelvis":
							_hips = val3;
							break;
						}
					}
					if ((Object)(object)_spine == (Object)null)
					{
						switch (text)
						{
						default:
							if (!text.EndsWith("_spine"))
							{
								break;
							}
							goto case "spine";
						case "spine":
						case "spine1":
						case "spine_01":
							_spine = val3;
							break;
						}
					}
					if (text.Contains("upleg") || text.Contains("upperleg") || text.Contains("thigh") || text.Contains("up_leg"))
					{
						bool flag = text.Contains("left") || text.StartsWith("l_") || text.EndsWith(".l") || text.EndsWith("_l") || text.Contains("l.");
						bool flag2 = text.Contains("right") || text.StartsWith("r_") || text.EndsWith(".r") || text.EndsWith("_r") || text.Contains("r.");
						if ((Object)(object)_legL == (Object)null && flag && !flag2)
						{
							_legL = val3;
						}
						if ((Object)(object)_legR == (Object)null && flag2 && !flag)
						{
							_legR = val3;
						}
					}
				}
			}
			if ((Object)(object)_spine == (Object)null && (Object)(object)_hips != (Object)null)
			{
				foreach (Transform hip in _hips)
				{
					Transform val4 = hip;
					if ((Object)(object)val4 != (Object)(object)_legL && (Object)(object)val4 != (Object)(object)_legR)
					{
						_spine = val4;
						break;
					}
				}
			}
			_fwdSign = 1f;
			if ((Object)(object)_legL != (Object)null && (Object)(object)_legR != (Object)null && Vector3.Dot(PelvisForward(out var _), ((Component)this).transform.forward) < 0f)
			{
				_fwdSign = -1f;
			}
			if ((Object)(object)_hips != (Object)null)
			{
				_hipsOffset = Quaternion.Inverse(_hips.rotation) * Quaternion.LookRotation(((Component)this).transform.forward, ((Component)this).transform.up);
			}
			if ((Object)(object)_hips == (Object)null)
			{
				Plugin.Log.LogWarning((object)("VikingLove: hips bone not found on " + _player.GetPlayerName() + "; using body centre."));
				return;
			}
			Plugin.Log.LogInfo((object)("VikingLove bones for " + _player.GetPlayerName() + ": hips=" + ((Object)_hips).name + " spine=" + (Object.op_Implicit((Object)(object)_spine) ? ((Object)_spine).name : "none") + " legs=" + (Object.op_Implicit((Object)(object)_legL) ? ((Object)_legL).name : "none") + "/" + (Object.op_Implicit((Object)(object)_legR) ? ((Object)_legR).name : "none")));
		}

		private Vector3 PelvisForward(out Vector3 up)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = _legR.position - _legL.position;
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			Vector3 val2;
			if (!((Object)(object)_spine != (Object)null) || !((Object)(object)_hips != (Object)null))
			{
				val2 = ((Component)this).transform.up;
			}
			else
			{
				val = _spine.position - _hips.position;
				val2 = ((Vector3)(ref val)).normalized;
			}
			up = val2;
			val = Vector3.Cross(normalized, up);
			Vector3 val3 = ((Vector3)(ref val)).normalized * _fwdSign;
			val = Vector3.Cross(val3, normalized);
			up = ((Vector3)(ref val)).normalized;
			return val3;
		}

		private void LateUpdate()
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: 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_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: 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_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: 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_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: 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_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: 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_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_obj == (Object)null)
			{
				return;
			}
			if (!_obj.activeSelf)
			{
				UpdateStroke(meshVisible: false);
				return;
			}
			if (!_bonesResolved)
			{
				ResolveBones();
			}
			Vector3 val;
			Vector3 val2;
			Vector3 up;
			if ((Object)(object)_legL != (Object)null && (Object)(object)_legR != (Object)null)
			{
				val = (_legL.position + _legR.position) * 0.5f;
				if (LoveManager.HipsOffset.TryGetValue((Character)(object)_player, out var value))
				{
					val += value;
				}
				val2 = PelvisForward(out up);
			}
			else if ((Object)(object)_hips != (Object)null)
			{
				val = _hips.position;
				Quaternion val3 = _hips.rotation * _hipsOffset;
				val2 = val3 * Vector3.forward;
				up = val3 * Vector3.up;
			}
			else
			{
				val = ((Component)this).transform.position + ((Component)this).transform.up * 0.9f;
				val2 = ((Component)this).transform.forward;
				up = ((Component)this).transform.up;
			}
			float num = Plugin.Scale.Value * _skinFactor;
			float num2 = num;
			bool flag = LoveManager.MeshShouldDangle((Character)(object)_player);
			if (flag)
			{
				num *= Mathf.Clamp(Plugin.ReceiverScale.Value, 0.05f, 1f);
			}
			Vector3 val4 = val + val2 * (Plugin.ForwardOffset.Value * num2 + (flag ? 0.05f : 0f)) + up * (Plugin.UpOffset.Value * num2 - (flag ? 0.02f : 0f));
			float target = 1f;
			Vector3 val5;
			Quaternion val6;
			if (flag)
			{
				val5 = val2 * 0.25f - up;
				val6 = Quaternion.LookRotation(((Vector3)(ref val5)).normalized, val2);
			}
			else
			{
				if (LoveManager.TryGetAim((Character)(object)_player, out var point))
				{
					val5 = point - val4;
					if (((Vector3)(ref val5)).sqrMagnitude > 0.0001f)
					{
						val5 = point - val4;
						Vector3 normalized = ((Vector3)(ref val5)).normalized;
						Vector3 val7 = Vector3.ProjectOnPlane(up, normalized);
						if (((Vector3)(ref val7)).sqrMagnitude < 0.0001f)
						{
							val7 = Vector3.up;
						}
						val6 = Quaternion.LookRotation(normalized, ((Vector3)(ref val7)).normalized) * Quaternion.Euler(Plugin.AimDownDegrees.Value, 0f, 0f);
						target = DesiredStretch(val4, point, num);
						goto IL_02bf;
					}
				}
				val6 = Quaternion.LookRotation(val2, up) * Quaternion.Euler(0f - Plugin.TiltDegrees.Value, 0f, 0f) * BounceOffset(val2, up);
			}
			goto IL_02bf;
			IL_02bf:
			_obj.transform.SetPositionAndRotation(val4, val6);
			if (!_hiddenForOral)
			{
				UpdateStretch(target);
			}
			_obj.transform.localScale = Vector3.one * num;
			if (Time.time >= _nextColorSync)
			{
				_nextColorSync = Time.time + 0.5f;
				if (_builtWithTone != Plugin.SkinToneOverride.Value)
				{
					BuildMaterials();
				}
				SyncSkinColor();
			}
			UpdateStroke(meshVisible: true);
			UpdateSpray();
		}

		private Quaternion BounceOffset(Vector3 fwd, Vector3 up)
		{
			//IL_000c: 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_0042: 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)
			//IL_0066: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.BounceEnabled.Value)
			{
				return Quaternion.identity;
			}
			float num = Mathf.Clamp(Time.deltaTime, 0.001f, 0.05f);
			Rigidbody val = BodyRef.Invoke((Character)(object)_player);
			Vector3 val2 = (((Object)(object)val != (Object)null) ? val.linearVelocity : Vector3.zero);
			if (!_velInit)
			{
				_lastVel = val2;
				_velInit = true;
			}
			Vector3 val3 = (val2 - _lastVel) / num;
			_lastVel = val2;
			Vector3 val4 = Vector3.Cross(up, fwd);
			Vector3 normalized = ((Vector3)(ref val4)).normalized;
			float num2 = Mathf.Clamp(val3.y, -60f, 60f) / 60f;
			float num3 = Mathf.Clamp(Vector3.Dot(val3, normalized), -40f, 40f) / 40f;
			float num4 = Mathf.Clamp(Vector3.Dot(val3, fwd), -40f, 40f) / 40f;
			val4 = Vector3.ProjectOnPlane(val2, up);
			float magnitude = ((Vector3)(ref val4)).magnitude;
			bool num5 = ((Character)_player).IsOnGround();
			float num6 = Mathf.Atan2(fwd.x, fwd.z) * 57.29578f;
			if (!_yawInit)
			{
				_lastYaw = num6;
				_yawInit = true;
			}
			float num7 = Mathf.DeltaAngle(_lastYaw, num6) / num;
			_lastYaw = num6;
			float num8 = (0f - Mathf.Clamp(num7, -270f, 270f)) / 270f * Plugin.BounceTurnGain.Value;
			_runPhase += num * (4f + magnitude * 0.9f);
			float num9 = (num5 ? (Mathf.Clamp01((magnitude - 0.4f) / 5f) * Plugin.BounceRunGain.Value) : 0f);
			float num10 = Mathf.Sin(_runPhase) * num9;
			float num11 = Mathf.Sin(_runPhase * 2f) * num9 * 0.5f;
			float value = Plugin.BounceLandingGain.Value;
			float num12 = num2 * value * 0.8f - num4 * value * 0.5f + num11;
			float num13 = num3 * value * 0.7f + num10 + num8;
			float value2 = Plugin.BounceStiffness.Value;
			float value3 = Plugin.BounceDamping.Value;
			_swPitchVel += ((0f - value2) * _swPitch - value3 * _swPitchVel + num12 * value2) * num;
			_swPitch += _swPitchVel * num;
			_swYawVel += ((0f - value2) * _swYaw - value3 * _swYawVel + num13 * value2) * num;
			_swYaw += _swYawVel * num;
			float value4 = Plugin.BounceMaxDegrees.Value;
			_swPitch = Mathf.Clamp(_swPitch, 0f - value4, value4);
			_swYaw = Mathf.Clamp(_swYaw, 0f - value4, value4);
			return Quaternion.Euler(_swPitch, _swYaw, 0f);
		}

		public void StartSpray(float seconds)
		{
			//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)
			if (!((Object)(object)_obj == (Object)null) && _obj.activeSelf)
			{
				if ((Object)(object)_spray == (Object)null)
				{
					_spray = BuildSpray();
				}
				if (!((Object)(object)_spray == (Object)null))
				{
					_sprayUntil = Time.time + seconds;
					EmissionModule emission = _spray.emission;
					((EmissionModule)(ref emission)).enabled = true;
					_spray.Play();
				}
			}
		}

		private void UpdateSpray()
		{
			if (!((Object)(object)_spray == (Object)null) && _spray.isPlaying && Time.time >= _sprayUntil)
			{
				_spray.Stop(true, (ParticleSystemStopBehavior)1);
			}
		}

		private ParticleSystem BuildSpray()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0037: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Expected O, but got Unknown
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: 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_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Expected O, but got Unknown
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("VikingLove_Spray");
			val.transform.SetParent(_obj.transform, false);
			val.transform.localPosition = new Vector3(0f, 0.17f, 0.57f);
			Transform transform = val.transform;
			Vector3 val2 = new Vector3(0f, 0.6f, 1f);
			transform.localRotation = Quaternion.LookRotation(((Vector3)(ref val2)).normalized, Vector3.up);
			ParticleSystem val3 = val.AddComponent<ParticleSystem>();
			val3.Stop(true, (ParticleSystemStopBehavior)0);
			MainModule main = val3.main;
			((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
			((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.6f, 1.1f);
			((MainModule)(ref main)).startSpeed = new MinMaxCurve(3.5f, 7f);
			((MainModule)(ref main)).startSize = new MinMaxCurve(0.04f, 0.09f);
			((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.97f, 0.96f, 0.9f, 0.95f));
			((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(1.1f);
			((MainModule)(ref main)).maxParticles = 600;
			((MainModule)(ref main)).loop = true;
			((MainModule)(ref main)).playOnAwake = false;
			EmissionModule emission = val3.emission;
			((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(45f);
			((EmissionModule)(ref emission)).SetBursts((Burst[])(object)new Burst[1]
			{
				new Burst(0f, (short)20, (short)30, 0, 0.38f)
			});
			ShapeModule shape = val3.shape;
			((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4;
			((ShapeModule)(ref shape)).angle = 7f;
			((ShapeModule)(ref shape)).radius = 0.008f;
			ColorOverLifetimeModule colorOverLifetime = val3.colorOverLifetime;
			((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true;
			Gradient val4 = new Gradient();
			val4.SetKeys((GradientColorKey[])(object)new GradientColorKey[2]
			{
				new GradientColorKey(Color.white, 0f),
				new GradientColorKey(Color.white, 1f)
			}, (GradientAlphaKey[])(object)new GradientAlphaKey[3]
			{
				new GradientAlphaKey(1f, 0f),
				new GradientAlphaKey(0.9f, 0.7f),
				new GradientAlphaKey(0f, 1f)
			});
			((ColorOverLifetimeModule)(ref colorOverLifetime)).color = MinMaxGradient.op_Implicit(val4);
			CollisionModule collision = val3.collision;
			((CollisionModule)(ref collision)).enabled = true;
			((CollisionModule)(ref collision)).type = (ParticleSystemCollisionType)1;
			((CollisionModule)(ref collision)).mode = (ParticleSystemCollisionMode)0;
			((CollisionModule)(ref collision)).dampen = MinMaxCurve.op_Implicit(0.6f);
			((CollisionModule)(ref collision)).bounce = MinMaxCurve.op_Implicit(0.05f);
			((CollisionModule)(ref collision)).lifetimeLoss = MinMaxCurve.op_Implicit(0.3f);
			ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>();
			component.renderMode = (ParticleSystemRenderMode)1;
			component.velocityScale = 0.06f;
			component.lengthScale = 1.6f;
			((Renderer)component).shadowCastingMode = (ShadowCastingMode)0;
			Shader val5 = null;
			string[] array = new string[5] { "Particles/Standard Unlit", "Legacy Shaders/Particles/Alpha Blended", "Sprites/Default", "Unlit/Color", "Standard" };
			for (int i = 0; i < array.Length; i++)
			{
				val5 = Shader.Find(array[i]);
				if ((Object)(object)val5 != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val5 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No particle shader found; spray disabled.");
				Object.Destroy((Object)(object)val);
				return null;
			}
			Material val6 = new Material(val5);
			val6.color = new Color(0.97f, 0.96f, 0.9f, 0.95f);
			if (val6.HasProperty("_Color"))
			{
				val6.SetColor("_Color", new Color(0.97f, 0.96f, 0.9f, 0.95f));
			}
			((Renderer)component).material = val6;
			return val3;
		}

		private bool InStrokeEmote()
		{
			if (Time.time < _nextEmoteCheck)
			{
				return _emoteCached;
			}
			_nextEmoteCheck = Time.time + 0.25f;
			_emoteCached = false;
			if (!Plugin.StrokeEnabled.Value || !((Character)_player).InEmote())
			{
				return false;
			}
			ZNetView val = NviewRef.Invoke((Character)(object)_player);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return false;
			}
			string text = val.GetZDO().GetString(ZDOVars.s_emote, "");
			_emoteCached = text.Length > 0 && string.Equals(text, Plugin.StrokeEmote.Value, StringComparison.OrdinalIgnoreCase);
			return _emoteCached;
		}

		private void UpdateStroke(bool meshVisible)
		{
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: 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_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: 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_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			bool flag = LoveManager.IsJerking(_player);
			bool num = meshVisible && !LoveManager.InAnySession((Character)(object)_player) && (flag || InStrokeEmote());
			RigBones rigBones = RigBones.Get(_player);
			if (!num || !rigBones.ArmValid)
			{
				if (_stroking)
				{
					LoveManager.RestoreBone(rigBones.ArmL);
					LoveManager.RestoreBone(rigBones.ForeArmL);
					LoveManager.RestoreBone(rigBones.HandL);
					_stroking = false;
				}
				return;
			}
			if (!_stroking)
			{
				_stroking = true;
				_strokeStart = Time.time;
				_strokePhase = 0f;
			}
			float num2 = Time.time - _strokeStart;
			float num3 = Mathf.SmoothStep(0f, 1f, Mathf.Clamp01(num2 / 0.5f));
			float num4 = (flag ? (1f + 1.2f * LoveManager.JerkProgress(_player)) : 1f);
			_strokePhase += Time.deltaTime * Plugin.StrokeRate.Value * num4 * MathF.PI * 2f;
			float num5 = 0.5f - 0.5f * Mathf.Cos(_strokePhase);
			Transform transform = _obj.transform;
			float num6 = 0.42f * transform.localScale.x;
			Vector3 val = transform.position + transform.forward * (num6 * (0.25f + 0.45f * num5)) + transform.up * (0.045f * transform.localScale.x) - transform.right * 0.01f;
			LoveManager.BeginBone(rigBones.ArmL);
			LoveManager.BeginBone(rigBones.ForeArmL);
			LoveManager.BeginBone(rigBones.HandL);
			Vector3 target = Vector3.Lerp(rigBones.HandL.position, val, num3);
			Vector3 poleDir = -((Component)this).transform.right * 0.7f - ((Component)this).transform.forward * 0.25f - ((Component)this).transform.up * 0.5f;
			SolveArm(rigBones.ArmL, rigBones.ForeArmL, rigBones.HandL, target, poleDir);
			Vector3 val2 = rigBones.HandL.position - rigBones.ForeArmL.position;
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			rigBones.HandL.rotation = Quaternion.FromToRotation(normalized, Vector3.Slerp(normalized, transform.forward, 0.6f)) * rigBones.HandL.rotation;
			LoveManager.EndBone(rigBones.ArmL);
			LoveManager.EndBone(rigBones.ForeArmL);
			LoveManager.EndBone(rigBones.HandL);
		}

		private static void SolveArm(Transform upper, Transform lower, Transform hand, Vector3 target, Vector3 poleDir)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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)
			//IL_000d: 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)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: 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_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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)
			Vector3 position = upper.position;
			Vector3 position2 = lower.position;
			Vector3 position3 = hand.position;
			float num = Vector3.Distance(position, position2);
			float num2 = Vector3.Distance(position2, position3);
			if (!(num < 0.001f) && !(num2 < 0.001f))
			{
				Vector3 val = target - position;
				float num3 = Mathf.Clamp(((Vector3)(ref val)).magnitude, 0.01f, num + num2 - 0.005f);
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				Vector3 val2 = poleDir - Vector3.Dot(poleDir, normalized) * normalized;
				if (((Vector3)(ref val2)).sqrMagnitude < 1E-06f)
				{
					val2 = Vector3.Cross(normalized, Vector3.up);
				}
				((Vector3)(ref val2)).Normalize();
				float num4 = Mathf.Acos(Mathf.Clamp((num * num + num3 * num3 - num2 * num2) / (2f * num * num3), -1f, 1f));
				Vector3 val3 = Mathf.Cos(num4) * normalized + Mathf.Sin(num4) * val2;
				Vector3 val4 = position + val3 * num;
				upper.rotation = Quaternion.FromToRotation(position2 - position, val4 - position) * upper.rotation;
				position2 = lower.position;
				position3 = hand.position;
				lower.rotation = Quaternion.FromToRotation(position3 - position2, target - position2) * lower.rotation;
			}
		}

		private float DesiredStretch(Vector3 pos, Vector3 aim, float scale)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.StretchEnabled.Value)
			{
				return 1f;
			}
			Vector3 val = aim - pos;
			return Mathf.Clamp(((((Vector3)(ref val)).magnitude + Plugin.StretchOverlap.Value) / Mathf.Max(0.01f, scale) - 0.12f) / 0.45f, 1f, Mathf.Max(1f, Plugin.StretchMax.Value));
		}

		private void UpdateStretch(float target)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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)
			_stretch = Mathf.MoveTowards(_stretch, target, Time.deltaTime * 3f);
			if (Mathf.Abs(_stretch - _appliedStretch) < 0.01f || _baseVerts == null)
			{
				return;
			}
			_appliedStretch = _stretch;
			Vector3[] array = (Vector3[])(object)new Vector3[_baseVerts.Length];
			for (int i = 0; i < array.Length; i++)
			{
				Vector3 val = _baseVerts[i];
				if (val.z > 0.12f)
				{
					float num = val.z - 0.12f;
					val.z = 0.12f + num * _stretch;
					val.y = val.y - 0.55f * (num + 0.12f) * (num + 0.12f) + 0.55f * (num + 0.12f) * (num + 0.12f) / _stretch;
				}
				array[i] = val;
			}
			_mesh.vertices = array;
			if ((Object)(object)_spray != (Object)null)
			{
				float num2 = 0.12f + 0.45f * _stretch;
				((Component)_spray).transform.localPosition = new Vector3(0f, -0.008695006f + 0.17869501f / _stretch, num2);
			}
			_mesh.RecalculateBounds();
			if (!Plugin.FlatShading.Value)
			{
				_mesh.RecalculateNormals();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_obj != (Object)null)
			{
				Object.Destroy((Object)(object)_obj);
			}
			if ((Object)(object)_mesh != (Object)null)
			{
				Object.Destroy((Object)(object)_mesh);
			}
		}
	}
	public static class SkinTexture
	{
		private struct SampleResult
		{
			public bool Ok;

			public Color Colour;

			public Vector2 Uv;
		}

		private static readonly Dictionary<long, Texture2D> GeneratedCache = new Dictionary<long, Texture2D>();

		private static readonly Dictionary<int, SampleResult> SampleCache = new Dictionary<int, SampleResult>();

		public static Texture2D Solid(Color c)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			val.SetPixels((Color[])(object)new Color[4] { c, c, c, c });
			val.Apply();
			return val;
		}

		public static Color? ParseHex(string hex)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(hex))
			{
				return null;
			}
			Color value = default(Color);
			if (!ColorUtility.TryParseHtmlString(hex.StartsWith("#") ? hex : ("#" + hex), ref value))
			{
				return null;
			}
			return value;
		}

		public static Color? SampleAtUvs(Texture tex, Vector2[] uvs, out Vector2 bestUv)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			bestUv = new Vector2(-1f, -1f);
			if ((Object)(object)tex == (Object)null)
			{
				return null;
			}
			int instanceID = ((Object)tex).GetInstanceID();
			if (SampleCache.TryGetValue(instanceID, out var value))
			{
				bestUv = value.Uv;
				if (!value.Ok)
				{
					return null;
				}
				return value.Colour;
			}
			Color? val = SampleUncached(tex, uvs, out bestUv);
			SampleCache[instanceID] = new SampleResult
			{
				Ok = val.HasValue,
				Colour = (Color)(((??)val) ?? Color.white),
				Uv = bestUv
			};
			return val;
		}

		private static Color? SampleUncached(Texture tex, Vector2[] uvs, out Vector2 bestUv)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			bestUv = new Vector2(-1f, -1f);
			RenderTexture val = null;
			RenderTexture active = RenderTexture.active;
			try
			{
				val = RenderTexture.GetTemporary(256, 256, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
				Graphics.Blit(tex, val);
				RenderTexture.active = val;
				Texture2D val2 = new Texture2D(256, 256, (TextureFormat)4, false);
				val2.ReadPixels(new Rect(0f, 0f, 256f, 256f), 0, 0);
				val2.Apply();
				Color[] pixels = val2.GetPixels();
				Object.Destroy((Object)val2);
				List<float> list = new List<float>();
				List<float> list2 = new List<float>();
				List<float> list3 = new List<float>();
				List<Vector2> list4 = new List<Vector2>();
				List<Color> list5 = new List<Color>();
				if (uvs != null && uvs.Length != 0)
				{
					int num = Mathf.Max(1, uvs.Length / 3000);
					for (int i = 0; i < uvs.Length; i += num)
					{
						float num2 = uvs[i].x - Mathf.Floor(uvs[i].x);
						float num3 = uvs[i].y - Mathf.Floor(uvs[i].y);
						Color val3 = pixels[Mathf.Clamp((int)(num3 * 256f), 0, 255) * 256 + Mathf.Clamp((int)(num2 * 256f), 0, 255)];
						if (!(val3.a < 0.5f) && !(val3.r + val3.g + val3.b < 0.25f))
						{
							list.Add(val3.r);
							list2.Add(val3.g);
							list3.Add(val3.b);
							list4.Add(new Vector2(num2, num3));
							list5.Add(val3);
						}
					}
				}
				if (list.Count < 20)
				{
					list.Clear();
					list2.Clear();
					list3.Clear();
					for (int j = 0; j < pixels.Length; j += 3)
					{
						Color val4 = pixels[j];
						if (!(val4.a < 0.5f) && !(val4.r + val4.g + val4.b < 0.6f))
						{
							list.Add(val4.r);
							list2.Add(val4.g);
							list3.Add(val4.b);
						}
					}
				}
				if (list.Count == 0)
				{
					return null;
				}
				list.Sort();
				list2.Sort();
				list3.Sort();
				int index = list.Count / 2;
				Color val5 = default(Color);
				((Color)(ref val5))..ctor(list[index], list2[index], list3[index]);
				float num4 = float.MaxValue;
				for (int k = 0; k < list5.Count; k++)
				{
					Color val6 = list5[k];
					float num5 = (val6.r - val5.r) * (val6.r - val5.r) + (val6.g - val5.g) * (val6.g - val5.g) + (val6.b - val5.b) * (val6.b - val5.b);
					if (num5 < num4)
					{
						num4 = num5;
						bestUv = list4[k];
					}
				}
				return val5;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Skin sample failed: " + ex.Message));
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					RenderTexture.ReleaseTemporary(val);
				}
			}
		}

		public static Texture2D Generate(Color baseTone, int size, int seed)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.RoundToInt(Mathf.Clamp01(baseTone.r) * 63f);
			int num2 = Mathf.RoundToInt(Mathf.Clamp01(baseTone.g) * 63f);
			int num3 = Mathf.RoundToInt(Mathf.Clamp01(baseTone.b) * 63f);
			long key = ((((long)num * 64L + num2) * 64 + num3) * 256 + (size & 0xFF)) * 64 + (seed & 0x3F);
			if (GeneratedCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Texture2D val = GenerateUncached(baseTone, size, seed);
			GeneratedCache[key] = val;
			return val;
		}

		private static Texture2D GenerateUncached(Color baseTone, int size, int seed)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(size, size, (TextureFormat)4, true);
			Color[] array = (Color[])(object)new Color[size * size];
			float num = (float)seed * 7.13f;
			float num2 = (float)seed * 3.71f;
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					float num3 = (float)j / (float)size;
					float num4 = (float)i / (float)size;
					float num5 = Mathf.PerlinNoise(num + num3 * 6f, num2 + num4 * 6f);
					float num6 = Mathf.PerlinNoise(num + num3 * 18f, num2 + num4 * 18f);
					float num7 = num5 * 0.65f + num6 * 0.35f;
					float num8 = 0.88f + (num7 - 0.5f) * 0.28f;
					float num9 = 1f - 0.1f * Mathf.Clamp01(Mathf.Cos(num3 * MathF.PI * 2f) * -1f);
					Color val2 = baseTone * num8 * num9;
					val2.r += (0.5f - num7) * 0.03f;
					val2.g -= (0.5f - num7) * 0.01f;
					val2.a = 1f;
					array[i * size + j] = val2;
				}
			}
			val.SetPixels(array);
			val.Apply(true);
			((Texture)val).wrapMode = (TextureWrapMode)0;
			((Texture)val).filterMode = (FilterMode)1;
			return val;
		}
	}
	[HarmonyPatch(typeof(VisEquipment), "UpdateEquipmentVisuals")]
	public static class VisEquipment_UpdateEquipmentVisuals_Patch
	{
		private static readonly FieldRef<VisEquipment, int> LegItemRef = AccessTools.FieldRefAccess<VisEquipment, int>("m_currentLegItemHash");

		private static readonly FieldRef<VisEquipment, int> ModelIndexRef = AccessTools.FieldRefAccess<VisEquipment, int>("m_modelIndex");

		public static bool IsFemale(VisEquipment vis)
		{
			return ModelIndexRef.Invoke(vis) == 1;
		}

		public static bool PantsDown(Player p)
		{
			if ((Object)(object)p == (Object)null)
			{
				return false;
			}
			VisEquipment component = ((Component)p).GetComponent<VisEquipment>();
			if ((Object)(object)component != (Object)null)
			{
				return LegItemRef.Invoke(component) == 0;
			}
			return false;
		}

		private static void Postfix(VisEquipment __instance)
		{
			if (__instance.m_isPlayer && !__instance.m_isArmorStand && !((Object)(object)Plugin.GenitalMesh == (Object)null))
			{
				Player val = (((Object)(object)__instance.m_playerComponent != (Object)null) ? __instance.m_playerComponent : ((Component)__instance).GetComponent<Player>());
				if (!((Object)(object)val == (Object)null))
				{
					GenitalAttachment genitalAttachment = GenitalAttachment.Ensure(val, __instance);
					bool visible = Plugin.ShowGenitals.Value && LegItemRef.Invoke(__instance) == 0 && (Plugin.ShowOnFemaleModels.Value || !IsFemale(__instance));
					genitalAttachment.Visible = visible;
					genitalAttachment.SetHiddenForOral(Plugin.HideMeshDuringOral.Value && LoveManager.InOralSession((Character)(object)val));
				}
			}
		}
	}
	public enum LoveKind
	{
		Back,
		Oral
	}
	public class LoveSession
	{
		public LoveKind Kind;

		public long InitiatorId;

		public long TargetPlayerId;

		public ZDOID TargetZdo;

		public float StartTime;

		public Player Initiator;

		public Character Target;

		public bool Pinned;

		public Vector3 TargetPos;

		public Quaternion TargetRot;

		public bool CollisionsIgnored;

		public bool InitiatorSnapped;

		public float NextDrain;

		public float RearOffset;

		public List<Collider> CollidersA = new List<Collider>();

		public List<Collider> CollidersB = new List<Collider>();

		public string InitiatorKey => "p" + InitiatorId;

		public unsafe string TargetKey
		{
			get
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				if (TargetPlayerId == 0L)
				{
					ZDOID targetZdo = TargetZdo;
					return "z" + ((object)(*(ZDOID*)(&targetZdo))/*cast due to .constrained prefix*/).ToString();
				}
				return "p" + TargetPlayerId;
			}
		}

		public bool TargetIsCreature => TargetPlayerId == 0;

		public bool Involves(Character c)
		{
			if ((Object)(object)c != (Object)null)
			{
				if (!((Object)(object)Initiator == (Object)(object)c))
				{
					return (Object)(object)Target == (Object)(object)c;
				}
				return true;
			}
			return false;
		}

		public bool InvolvesKey(string key)
		{
			if (!(InitiatorKey == key))
			{
				return TargetKey == key;
			}
			return true;
		}
	}
	public class LoveManager : MonoBehaviour
	{
		private class BoneState
		{
			public Vector3 CleanPos;

			public Vector3 DirtyPos;

			public Quaternion CleanRot;

			public Quaternion DirtyRot;

			public bool HasDirty;
		}

		public const string RpcStart = "VikingLove_Start3";

		public const string RpcStop = "VikingLove_Stop";

		public const string RpcFinish = "VikingLove_Finish";

		public const string RpcJerkStart = "VikingLove_JerkStart";

		public const string RpcJerkStop = "VikingLove_JerkStop";

		public static LoveManager Instance;

		public static readonly List<LoveSession> Sessions = new List<LoveSession>();

		private static float _cooldownUntil;

		private static bool _rpcRegistered;

		private static readonly FieldRef<Character, Rigidbody> BodyRef = AccessTools.FieldRefAccess<Character, Rigidbody>("m_body");

		private static readonly FieldRef<Character, ZNetView> NviewRef = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview");

		private static readonly FieldRef<StatusEffect, float> SeTimeRef = AccessTools.FieldRefAccess<StatusEffect, float>("m_time");

		private static readonly MethodInfo StopEmoteMethod = AccessTools.Method(typeof(Player), "StopEmote", (Type[])null, (Type[])null);

		public static readonly Dictionary<Character, Vector3> HipsOffset = new Dictionary<Character, Vector3>();

		private static readonly Dictionary<Character, AudioSource> Moans = new Dictionary<Character, AudioSource>();

		private static readonly Dictionary<Character, AudioSource> Sucks = new Dictionary<Character, AudioSource>();

		private static readonly HashSet<Character> WantMoan = new HashSet<Character>();

		private static readonly HashSet<Character> WantSuck = new HashSet<Character>();

		private static readonly List<Character> StaleTmp = new List<Character>();

		private static readonly List<Transform> ChainTmp = new List<Transform>();

		private static float _nextSkillTick;

		private static float _levelsGained;

		private static readonly Dictionary<long, float> Jerking = new Dictionary<long, float>();

		private static float _reloadAt;

		private static float _nextPrune;

		private static readonly Dictionary<Transform, BoneState> BoneStates = new Dictionary<Transform, BoneState>();

		private static readonly HashSet<Character> PosedThisFrame = new HashSet<Character>();

		private void Awake()
		{
			Instance = this;
		}

		public static string Key(Character c)
		{
			//IL_0016: 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)
			Player val = (Player)(object)((c is Player) ? c : null);
			if (!((Object)(object)val != (Object)null))
			{
				return "z" + ((object)c.GetZDOID()/*cast due to .constrained prefix*/).ToString();
			}
			return "p" + val.GetPlayerID();
		}

		public static bool IsCreature(Character c)
		{
			if ((Object)(object)c != (Object)null)
			{
				return !(c is Player);
			}
			return false;
		}

		public static bool IsBackInitiator(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			foreach (LoveSession session in Sessions)
			{
				if (session.Kind == LoveKind.Back && (Object)(object)session.Initiator == (Object)(object)c)
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsBackTarget(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			foreach (LoveSession session in Sessions)
			{
				if (session.Kind == LoveKind.Back && (Object)(object)session.Target == (Object)(object)c)
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsKneeler(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			foreach (LoveSession session in Sessions)
			{
				if (session.Kind == LoveKind.Oral && (Object)(object)session.Initiator == (Object)(object)c)
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsOralTarget(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			foreach (LoveSession session in Sessions)
			{
				if (session.Kind == LoveKind.Oral && (Object)(object)session.Target == (Object)(object)c)
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsTarget(Character c)
		{
			if (!IsBackTarget(c))
			{
				return IsOralTarget(c);
			}
			return true;
		}

		public static bool InOralSession(Character c)
		{
			if (!IsKneeler(c))
			{
				return IsOralTarget(c);
			}
			return true;
		}

		public static bool InAnySession(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			foreach (LoveSession session in Sessions)
			{
				if (session.Involves(c))
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsParticipant(Character c)
		{
			if (Sessions.Count > 0)
			{
				return InAnySession(c);
			}
			return false;
		}

		public static bool LocalIsFrozen()
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				return InAnySession((Character)(object)Player.m_localPlayer);
			}
			return false;
		}

		public static bool MeshShouldDangle(Character c)
		{
			if (!IsKneeler(c))
			{
				if (IsBackTarget(c) && !IsBackInitiator(c))
				{
					return !IsOralTarget(c);
				}
				return false;
			}
			return true;
		}

		public static bool CanReceiveBack(Character c)
		{
			if ((Object)(object)c != (Object)null && !IsKneeler(c))
			{
				return !IsBackTarget(c);
			}
			return false;
		}

		public static bool CanReceiveOral(Character c)
		{
			if (c is Player && !IsKneeler(c) && !IsOralTarget(c))
			{
				return !IsBackInitiator(c);
			}
			return false;
		}

		public static bool CreatureAllowed(Character c)
		{
			if (!IsCreature(c) || !Plugin.EnemiesEnabled.Value)
			{
				return false;
			}
			if (c.IsDead())
			{
				return false;
			}
			if (c.IsTamed() && !Plugin.EnemiesIncludeTamed.Value)
			{
				return false;
			}
			if (c.IsBoss() && !Plugin.EnemiesIncludeBosses.Value)
			{
				return false;
			}
			return true;
		}

		public static bool IsInFrontOf(Character a, Character b)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			Vector3 forward = ((Component)b).transform.forward;
			forward.y = 0f;
			Vector3 val = ((Component)a).transform.position - ((Component)b).transform.position;
			val.y = 0f;
			return Vector3.Dot(forward, val) > 0f;
		}

		public static bool ArePartners(Character a, Character b)
		{
			foreach (LoveSession session in Sessions)
			{
				if (((Object)(object)session.Initiator == (Object)(object)a && (Object)(object)session.Target == (Object)(object)b) || ((Object)(object)session.Initiator == (Object)(object)b && (Object)(object)session.Target == (Object)(object)a))
				{
					return true;
				}
			}
			return false;
		}

		private static LoveSession SessionAsInitiator(Character c, LoveKind kind)
		{
			foreach (LoveSession session in Sessions)
			{
				if (session.Kind == kind && (Object)(object)session.Initiator == (Object)(object)c)
				{
					return session;
				}
			}
			return null;
		}

		private static LoveSession SessionAsTarget(Character c, LoveKind kind)
		{
			foreach (LoveSession session in Sessions)
			{
				if (session.Kind == kind && (Object)(object)session.Target == (Object)(object)c)
				{
					return session;
				}
			}
			return null;
		}

		private static LoveSession FindByInitiatorId(long id)
		{
			foreach (LoveSession session in Sessions)
			{
				if (session.InitiatorId == id)
				{
					return session;
				}
			}
			return null;
		}

		private static bool KeyInAnySession(string key)
		{
			foreach (LoveSession session in Sessions)
			{
				if (session.InvolvesKey(key))
				{
					return true;
				}
			}
			return false;
		}

		private static Character ResolveTarget(LoveSession s)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (s.TargetPlayerId != 0L)
			{
				return (Character)(object)Player.GetPlayer(s.TargetPlayerId);
			}
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			GameObject val = ZNetScene.instance.FindInstance(s.TargetZdo);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<Character>();
		}

		public static void RegisterRpcs()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<long, long, ZDOID, int>("VikingLove_Start3", (Method<long, long, ZDOID, int>)OnRpcStart);
				ZRoutedRpc.instance.Register<long, long>("VikingLove_Stop", (Action<long, long, long>)OnRpcStop);
				ZRoutedRpc.instance.Register<long, long>("VikingLove_Finish", (Action<long, long, long>)OnRpcFinish);
				ZRoutedRpc.instance.Register<long>("VikingLove_JerkStart", (Action<long, long>)OnRpcJerkStart);
				ZRoutedRpc.instance.Register<long, bool>("VikingLove_JerkStop", (Action<long, long, bool>)OnRpcJerkStop);
				ZRoutedRpc.instance.Register<ZPackage>("VikingLove_ConfigSync", (Action<long, ZPackage>)ConfigSync.OnConfigReceived);
				ZRoutedRpc.instance.Register("VikingLove_ConfigRequest", (Action<long>)ConfigSync.OnConfigRequested);
				_rpcRegistered = true;
				Plugin.Log.LogInfo((object)"VikingLove RPCs registered");
			}
		}

		private static void OnRpcStart(long sender, long initiatorId, long targetPlayerId, ZDOID targetZdo, int kindInt)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (KeyInAnySession("p" + initiatorId))
			{
				return;
			}
			LoveSession loveSession = new LoveSession
			{
				Kind = (LoveKind)kindInt,
				InitiatorId = initiatorId,
				TargetPlayerId = targetPlayerId,
				TargetZdo = targetZdo,
				StartTime = Time.time
			};
			if (KeyInAnySession(loveSession.TargetKey) && kindInt == 0)
			{
				foreach (LoveSession session in Sessions)
				{
					if (session.Kind == LoveKind.Back && session.TargetKey == loveSession.TargetKey)
					{
						return;
					}
				}
			}
			if (KeyInAnySession(loveSession.TargetKey) && kindInt == 1)
			{
				foreach (LoveSession session2 in Sessions)
				{
					if ((session2.Kind == LoveKind.Oral && session2.TargetKey == loveSession.TargetKey) || (session2.Kind == LoveKind.Back && session2.InitiatorKey == loveSession.TargetKey))
					{
						return;
					}
				}
			}
			loveSe