Decompiled source of SemiKick v1.0.1

SemiKick.dll

Decompiled 4 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using KeybindLib.Classes;
using Newtonsoft.Json;
using Photon.Pun;
using REPOLib.Modules;
using REPOLib.Objects.Sdk;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("SemiKick")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SemiKick")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f6f7da04-f36c-4ac4-a3dc-28fbe347a753")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
[Serializable]
public class AnimationData
{
	public float duration;

	public List<FrameData> frames;
}
[Serializable]
public class FrameData
{
	public float time;

	public Dictionary<string, BoneRotation> bones;
}
[Serializable]
public struct BoneRotation
{
	public float x;

	public float y;

	public float z;

	public float w;

	public Quaternion ToQuaternion()
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		return new Quaternion(x, y, z, w);
	}
}
public struct RuntimeFrame
{
	public float time;

	public Quaternion[] rotations;
}
public class KickAnimationPlayer : MonoBehaviour
{
	private static readonly Dictionary<string, string> BoneMap = new Dictionary<string, string>
	{
		{ "Bone", "ANIM BODY BOT" },
		{ "Bone.003", "ANIM HEAD BOT" },
		{ "Bone.004", "Player Spring Impulse - Leg Right" },
		{ "Bone.005", "Player Spring Impulse - Leg Left" },
		{ "Bone.006", "Player Spring Impulse - Arm Left" },
		{ "Bone.007", "Player Spring Impulse - Arm Right" }
	};

	private Transform[] boneTransforms;

	private string[] blenderBoneNames;

	private Quaternion[] initialLocalRotations;

	private int rightLegBoneIndex = -1;

	private Vector3? stretchTargetWorldPos;

	private float currentStretchFactor = 1f;

	private RuntimeFrame[] runtimeFrames;

	private float totalDuration;

	private bool isReady;

	private bool isPlaying;

	[SerializeField]
	private float returnToRestDuration = 0.15f;

	private Coroutine returnToRestCoroutine;

	private RuntimeFrame currentFrameA;

	private RuntimeFrame currentFrameB;

	private float currentT;

	private bool hasFrameToApply;

	private bool _loggedFirstApply;

	private bool _loggedNullBoneWarning;

	private static string LoadTextFromEmbeddedResource(string resourceFileName)
	{
		Assembly executingAssembly = Assembly.GetExecutingAssembly();
		string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string n) => n.EndsWith(resourceFileName, StringComparison.OrdinalIgnoreCase));
		if (text == null)
		{
			Debug.LogError((object)("[JSONAnimation] Embedded resource '" + resourceFileName + "' не найден. Доступные ресурсы: " + string.Join(", ", executingAssembly.GetManifestResourceNames())));
			return null;
		}
		using Stream stream = executingAssembly.GetManifestResourceStream(text);
		if (stream == null)
		{
			Debug.LogError((object)("[JSONAnimation] GetManifestResourceStream вернул null для '" + text + "'."));
			return null;
		}
		using StreamReader streamReader = new StreamReader(stream);
		return streamReader.ReadToEnd();
	}

	public void Initialize(string jsonPath, Transform rigRoot)
	{
		Debug.Log((object)("[JSONAnimation] Initialize вызван: jsonPath=" + jsonPath + ", rigRoot=" + (((Object)(object)rigRoot != (Object)null) ? ((Object)rigRoot).name : "NULL")));
		bool flag = File.Exists(jsonPath);
		Debug.Log((object)$"[JSONAnimation] Проверка файла анимации: fileExists={flag}, path={jsonPath}");
		string text = (flag ? File.ReadAllText(jsonPath) : null);
		InitializeInternal(text, rigRoot, flag, "Файл kick_animation.json не найден по указанному пути. ");
	}

	public void InitializeFromJsonText(string jsonText, Transform rigRoot)
	{
		Debug.Log((object)string.Format("[JSONAnimation] Initialize (embedded) вызван: jsonText.Length={0}, rigRoot={1}", jsonText?.Length ?? (-1), ((Object)(object)rigRoot != (Object)null) ? ((Object)rigRoot).name : "NULL"));
		InitializeInternal(jsonText, rigRoot, !string.IsNullOrEmpty(jsonText), "JSON-текст из embedded resource пуст или не был найден (см. лог LoadTextFromEmbeddedResource выше). ");
	}

	public void InitializeFromEmbeddedResource(string resourceFileName, Transform rigRoot)
	{
		string jsonText = LoadTextFromEmbeddedResource(resourceFileName);
		InitializeFromJsonText(jsonText, rigRoot);
	}

	private void InitializeInternal(string text, Transform rigRoot, bool hasSource, string missingSourceReason)
	{
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0330: 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_0307: Unknown result type (might be due to invalid IL or missing references)
		//IL_030c: Unknown result type (might be due to invalid IL or missing references)
		List<Transform> list = new List<Transform>();
		List<string> list2 = new List<string>();
		foreach (KeyValuePair<string, string> item in BoneMap)
		{
			Transform val = FindDeepChild(rigRoot, item.Value);
			if ((Object)(object)val != (Object)null)
			{
				list.Add(val);
				list2.Add(item.Key);
				Debug.Log((object)("[JSONAnimation] Привязана кость: blenderName=" + item.Key + " -> unityName='" + item.Value + "', path=" + GetHierarchyPath(val)));
			}
			else
			{
				Debug.LogWarning((object)("[JSONAnimation] НЕ найдена кость: blenderName=" + item.Key + ", ожидалось имя в Unity='" + item.Value + "' (FindDeepChild не нашёл такого объекта под " + (((Object)(object)rigRoot != (Object)null) ? ((Object)rigRoot).name : "NULL") + ")."));
			}
		}
		boneTransforms = list.ToArray();
		blenderBoneNames = list2.ToArray();
		int num = boneTransforms.Length;
		Debug.Log((object)$"[JSONAnimation] Итог поиска костей: найдено {num}/{BoneMap.Count}.");
		initialLocalRotations = (Quaternion[])(object)new Quaternion[num];
		for (int i = 0; i < num; i++)
		{
			initialLocalRotations[i] = boneTransforms[i].localRotation;
		}
		rightLegBoneIndex = Array.IndexOf(blenderBoneNames, "Bone.004");
		if (rightLegBoneIndex < 0)
		{
			Debug.LogWarning((object)"[JSONAnimation] Кость правой ноги (Bone.004 / 'Player Spring Impulse - Leg Right') не найдена в рантайм-иерархии — стретч ноги работать не будет для этого аватара.");
		}
		if (hasSource && num > 0)
		{
			Debug.Log((object)$"[JSONAnimation] JSON получен, длина текста={text.Length} символов. Десериализую...");
			AnimationData animationData = JsonConvert.DeserializeObject<AnimationData>(text);
			if (animationData == null)
			{
				Debug.LogError((object)"[JSONAnimation] JsonConvert.DeserializeObject вернул NULL — файл битый или не соответствует структуре AnimationData. Анимация не будет готова.");
				return;
			}
			if (animationData.frames == null || animationData.frames.Count == 0)
			{
				Debug.LogError((object)$"[JSONAnimation] rawData.frames пуст или NULL (duration={animationData.duration}). Анимация не будет готова.");
				return;
			}
			totalDuration = animationData.duration;
			runtimeFrames = new RuntimeFrame[animationData.frames.Count];
			Debug.Log((object)$"[JSONAnimation] Десериализация ок: duration={totalDuration}, framesCount={animationData.frames.Count}. Пересобираю в RuntimeFrame...");
			int num2 = 0;
			for (int j = 0; j < animationData.frames.Count; j++)
			{
				FrameData frameData = animationData.frames[j];
				runtimeFrames[j].time = frameData.time;
				runtimeFrames[j].rotations = (Quaternion[])(object)new Quaternion[num];
				for (int k = 0; k < num; k++)
				{
					string key = blenderBoneNames[k];
					if (frameData.bones != null && frameData.bones.TryGetValue(key, out var value))
					{
						runtimeFrames[j].rotations[k] = value.ToQuaternion();
						continue;
					}
					runtimeFrames[j].rotations[k] = boneTransforms[k].localRotation;
					num2++;
				}
			}
			if (num2 > 0)
			{
				Debug.LogWarning((object)$"[JSONAnimation] В {num2} случаях (кадр x кость) в JSON не было данных для найденной кости — использован текущий localRotation как фоллбэк. Если это не задумано, проверьте имена костей в Blender-экспорте.");
			}
			isReady = true;
			Debug.Log((object)$"[JSONAnimation] Initialize завершён успешно: isReady=true, totalDuration={totalDuration}, framesCount={runtimeFrames.Length}, boneCount={num}.");
		}
		else
		{
			Debug.LogWarning((object)($"[JSONAnimation] Initialize НЕ завершился (isReady останется false): hasSource={hasSource}, actualBoneCount={num}. " + ((!hasSource) ? missingSourceReason : "") + ((num == 0) ? "Ни одна кость из BoneMap не найдена в rigRoot — проверьте иерархию/имена." : "")));
		}
	}

	private static string GetHierarchyPath(Transform t)
	{
		if ((Object)(object)t == (Object)null)
		{
			return "NULL";
		}
		string text = ((Object)t).name;
		Transform parent = t.parent;
		while ((Object)(object)parent != (Object)null)
		{
			text = ((Object)parent).name + "/" + text;
			parent = parent.parent;
		}
		return text;
	}

	private IEnumerator RunKick()
	{
		if (returnToRestCoroutine != null)
		{
			((MonoBehaviour)this).StopCoroutine(returnToRestCoroutine);
			returnToRestCoroutine = null;
		}
		isPlaying = true;
		float startTime = Time.time;
		int currentFrameIndex = 0;
		int frameCount = runtimeFrames.Length;
		int loggedFrameIndex = -1;
		object[] obj = new object[4] { startTime, totalDuration, frameCount, null };
		Transform[] array = boneTransforms;
		obj[3] = ((array != null) ? array.Length : 0);
		Debug.Log((object)string.Format("[JSONAnimation] RunKick стартовал: startTime={0}, totalDuration={1}, frameCount={2}, boneCount={3}.", obj));
		while (Time.time - startTime < totalDuration)
		{
			float num;
			for (num = Time.time - startTime; currentFrameIndex < frameCount - 1 && runtimeFrames[currentFrameIndex + 1].time <= num; currentFrameIndex++)
			{
			}
			if (currentFrameIndex != loggedFrameIndex)
			{
				Debug.Log((object)$"[JSONAnimation] RunKick: переход на кадр {currentFrameIndex}/{frameCount - 1} (time={runtimeFrames[currentFrameIndex].time}, elapsed={num:F3}).");
				loggedFrameIndex = currentFrameIndex;
			}
			currentFrameA = runtimeFrames[currentFrameIndex];
			currentFrameB = runtimeFrames[Mathf.Min(currentFrameIndex + 1, frameCount - 1)];
			currentT = Mathf.InverseLerp(currentFrameA.time, currentFrameB.time, num);
			hasFrameToApply = true;
			yield return null;
		}
		isPlaying = false;
		hasFrameToApply = false;
		stretchTargetWorldPos = null;
		currentStretchFactor = 1f;
		if (rightLegBoneIndex >= 0 && rightLegBoneIndex < boneTransforms.Length && (Object)(object)boneTransforms[rightLegBoneIndex] != (Object)null)
		{
			boneTransforms[rightLegBoneIndex].localScale = Vector3.one;
		}
		if (returnToRestCoroutine != null)
		{
			((MonoBehaviour)this).StopCoroutine(returnToRestCoroutine);
		}
		returnToRestCoroutine = ((MonoBehaviour)this).StartCoroutine(ReturnToRestPose());
		Debug.Log((object)$"[JSONAnimation] RunKick завершён: реальная длительность={Time.time - startTime:F3} (ожидалось totalDuration={totalDuration}), запущен плавный возврат костей в стартовую позу за {returnToRestDuration:F3}с.");
	}

	private IEnumerator ReturnToRestPose()
	{
		if (initialLocalRotations == null || boneTransforms == null)
		{
			yield break;
		}
		int count = boneTransforms.Length;
		Quaternion[] fromRotations = (Quaternion[])(object)new Quaternion[count];
		for (int i = 0; i < count; i++)
		{
			if ((Object)(object)boneTransforms[i] != (Object)null)
			{
				fromRotations[i] = boneTransforms[i].localRotation;
			}
		}
		if (returnToRestDuration <= 0f)
		{
			for (int j = 0; j < count; j++)
			{
				if ((Object)(object)boneTransforms[j] != (Object)null && j < initialLocalRotations.Length)
				{
					boneTransforms[j].localRotation = initialLocalRotations[j];
				}
			}
			returnToRestCoroutine = null;
			yield break;
		}
		float elapsed = 0f;
		while (elapsed < returnToRestDuration)
		{
			elapsed += Time.deltaTime;
			float num = Mathf.Clamp01(elapsed / returnToRestDuration);
			for (int k = 0; k < count; k++)
			{
				if ((Object)(object)boneTransforms[k] != (Object)null && k < initialLocalRotations.Length)
				{
					boneTransforms[k].localRotation = Quaternion.Slerp(fromRotations[k], initialLocalRotations[k], num);
				}
			}
			yield return null;
		}
		for (int l = 0; l < count; l++)
		{
			if ((Object)(object)boneTransforms[l] != (Object)null && l < initialLocalRotations.Length)
			{
				boneTransforms[l].localRotation = initialLocalRotations[l];
			}
		}
		returnToRestCoroutine = null;
	}

	private void LateUpdate()
	{
		//IL_0089: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
		if (!hasFrameToApply)
		{
			_loggedFirstApply = false;
			return;
		}
		if (!_loggedFirstApply)
		{
			Debug.Log((object)$"[JSONAnimation] LateUpdate: начал применять ротации к {boneTransforms.Length} костям.");
			_loggedFirstApply = true;
		}
		for (int i = 0; i < boneTransforms.Length; i++)
		{
			if ((Object)(object)boneTransforms[i] == (Object)null)
			{
				if (!_loggedNullBoneWarning)
				{
					Debug.LogWarning((object)$"[JSONAnimation] LateUpdate: boneTransforms[{i}] == NULL (кость уничтожена/недоступна?), пропускаю. Дальнейшие такие предупреждения на этот проигрыш подавлены.");
					_loggedNullBoneWarning = true;
				}
			}
			else
			{
				boneTransforms[i].localRotation = Quaternion.Slerp(currentFrameA.rotations[i], currentFrameB.rotations[i], currentT);
			}
		}
		if (rightLegBoneIndex >= 0 && rightLegBoneIndex < boneTransforms.Length && (Object)(object)boneTransforms[rightLegBoneIndex] != (Object)null)
		{
			ApplyLegStretch(boneTransforms[rightLegBoneIndex]);
		}
	}

	private void ApplyLegStretch(Transform legBone)
	{
		//IL_006c: 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_0080: 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_001f: Unknown result type (might be due to invalid IL or missing references)
		float num = 1f;
		if (stretchTargetWorldPos.HasValue)
		{
			float num2 = Vector3.Distance(legBone.position, stretchTargetWorldPos.Value);
			float num3 = 0.5f;
			if (num3 > 0f && num2 > num3)
			{
				num = Mathf.Clamp(num2 / num3, 1f, 1.8f);
			}
		}
		currentStretchFactor = Mathf.Lerp(currentStretchFactor, num, Time.deltaTime * 8f);
		Vector3 one = Vector3.one;
		one.y = currentStretchFactor;
		legBone.localScale = one;
	}

	private Transform FindDeepChild(Transform parent, string targetName)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		if (((Object)parent).name == targetName)
		{
			return parent;
		}
		foreach (Transform item in parent)
		{
			Transform parent2 = item;
			Transform val = FindDeepChild(parent2, targetName);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
		}
		return null;
	}

	public void PlayKick(Vector3? targetWorldPoint = null)
	{
		//IL_0044: 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)
		Debug.Log((object)string.Format("[JSONAnimation] PlayKick вызван: isReady={0}, isPlaying={1}, gameObject={2}, targetWorldPoint={3}.", isReady, isPlaying, ((Object)this).name, targetWorldPoint.HasValue ? ((object)targetWorldPoint.Value/*cast due to .constrained prefix*/).ToString() : "NULL"));
		if (!isReady)
		{
			Debug.LogWarning((object)"[JSONAnimation] PlayKick: isReady=false, анимация не запущена (Initialize не завершился успешно — см. логи выше).");
			return;
		}
		if (isPlaying)
		{
			Debug.LogWarning((object)"[JSONAnimation] PlayKick: анимация уже проигрывается (isPlaying=true), повторный запуск пропущен.");
			return;
		}
		stretchTargetWorldPos = targetWorldPoint;
		currentStretchFactor = 1f;
		((MonoBehaviour)this).StartCoroutine(RunKick());
	}
}
namespace SemiKick;

internal class EnemyKickReceiver : MonoBehaviour
{
	private const float KickStunDuration = 1f;

	private Enemy _enemy;

	private EnemyRigidbody _enemyRigidbody;

	private EnemyStateStunned _stateStunned;

	private void Awake()
	{
		_enemy = ((Component)this).GetComponent<Enemy>();
		_stateStunned = InternalAccessors.GetEnemyStateStunned(_enemy);
		_enemyRigidbody = (((Object)(object)((Component)this).transform.parent != (Object)null) ? ((Component)((Component)this).transform.parent).GetComponentInChildren<EnemyRigidbody>() : ((Component)this).GetComponentInChildren<EnemyRigidbody>());
		if ((Object)(object)_enemyRigidbody == (Object)null)
		{
			SemiKick.LogWarning("[SemiKick] EnemyKickReceiver на " + ((Object)this).name + ": не нашёл EnemyRigidbody у сиблингов родителя.");
		}
		if ((Object)(object)_stateStunned == (Object)null)
		{
			SemiKick.LogWarning("[SemiKick] EnemyKickReceiver на " + ((Object)this).name + ": не нашёл StateStunned — нокбэк будет гаситься AI на следующем кадре.");
		}
		SemiKick.LogInfo($"[SemiKick] EnemyKickReceiver.Awake на {((Object)this).name}: enemyRigidbody={(Object)(object)_enemyRigidbody != (Object)null}, stateStunned={(Object)(object)_stateStunned != (Object)null}");
	}

	public float GetMass()
	{
		if ((Object)(object)_enemyRigidbody == (Object)null)
		{
			SemiKick.LogWarning("[SemiKick] EnemyKickReceiver.GetMass на " + ((Object)this).name + ": _enemyRigidbody == null, возвращаю 0.");
			return 0f;
		}
		Rigidbody enemyRigidbody = InternalAccessors.GetEnemyRigidbody(_enemyRigidbody);
		float num = (((Object)(object)enemyRigidbody != (Object)null) ? enemyRigidbody.mass : 0f);
		SemiKick.LogInfo($"[SemiKick] EnemyKickReceiver.GetMass на {((Object)this).name}: rb={(Object)(object)enemyRigidbody != (Object)null}, mass={num}");
		return num;
	}

	public void SendKick(Vector3 force)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: 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_0054: 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)
		SemiKick.LogInfo($"[SemiKick] EnemyKickReceiver.SendKick на {((Object)this).name}: force={force}, magnitude={((Vector3)(ref force)).magnitude}, Multiplayer={GameManager.Multiplayer()}");
		if (!GameManager.Multiplayer())
		{
			ReceiveKickRPC(force);
			return;
		}
		PhotonView enemyPhotonView = InternalAccessors.GetEnemyPhotonView(_enemy);
		if ((Object)(object)enemyPhotonView == (Object)null)
		{
			SemiKick.LogWarning("[SemiKick] EnemyKickReceiver.SendKick на " + ((Object)this).name + ": photonView == null, RPC не отправлен.");
			return;
		}
		enemyPhotonView.RPC("ReceiveKickRPC", (RpcTarget)0, new object[1] { force });
	}

	[PunRPC]
	public void ReceiveKickRPC(Vector3 force, PhotonMessageInfo _info = default(PhotonMessageInfo))
	{
		//IL_000b: 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_0061: Unknown result type (might be due to invalid IL or missing references)
		SemiKick.LogInfo($"[SemiKick] EnemyKickReceiver.ReceiveKickRPC на {((Object)this).name}: force={force}");
		if ((Object)(object)_enemyRigidbody == (Object)null)
		{
			SemiKick.LogWarning("[SemiKick] EnemyKickReceiver.ReceiveKickRPC на " + ((Object)this).name + ": _enemyRigidbody == null, импульс не применён.");
			return;
		}
		EnemyStateStunned stateStunned = _stateStunned;
		if (stateStunned != null)
		{
			stateStunned.Set(1f);
		}
		_enemyRigidbody.FreezeForces(force, Vector3.zero);
	}
}
[HarmonyPatch(typeof(Enemy), "Awake")]
internal static class EnemyKickReceiverPatch
{
	[HarmonyPostfix]
	private static void Postfix(Enemy __instance)
	{
		if (!((Object)(object)((Component)__instance).GetComponent<EnemyKickReceiver>() != (Object)null))
		{
			((Component)__instance).gameObject.AddComponent<EnemyKickReceiver>();
		}
	}
}
public class KickAnimHandler : MonoBehaviour
{
	private KickAnimationPlayer _animPlayer;

	private PhotonView _photonView;

	private PlayerAvatar _avatar;

	private bool _isLocal;

	private PlayerController pc;

	public PlayerAvatar Avatar => _avatar;

	public int KickLevel { get; private set; }

	public void SetKickLevel(int level)
	{
		SemiKick.LogInfo($"[SemiKick] KickAnimHandler.SetKickLevel: {(((Object)(object)_avatar != (Object)null) ? ((Object)_avatar).name : ((Object)this).name)} -> level={level} (было {KickLevel}).");
		KickLevel = level;
	}

	public void Initialize(KickAnimationPlayer animPlayer, PlayerAvatar avatar)
	{
		GameObject val = GameObject.Find("Controller");
		if ((Object)(object)val != (Object)null)
		{
			pc = val.GetComponent<PlayerController>();
		}
		if ((Object)(object)pc == (Object)null)
		{
			SemiKick.LogWarning("[KickAnimHandler] PlayerController не найден на сцене!");
		}
		_animPlayer = animPlayer;
		_avatar = avatar;
		SemiKick.LogInfo("[SemiKick] KickAnimHandler.Initialize вызван, avatar=" + (((Object)(object)avatar != (Object)null) ? ((Object)avatar).name : "NULL"));
		SemiKick.LogInfo("[JSONAnimation] KickAnimHandler.Initialize: animPlayer передан как " + (((Object)(object)animPlayer != (Object)null) ? "не NULL" : "NULL") + ".");
		if ((Object)(object)avatar == (Object)null)
		{
			SemiKick.LogError("[SemiKick] KickAnimHandler.Initialize: avatar передана как NULL!");
			return;
		}
		_photonView = avatar.photonView ?? ((Component)avatar).GetComponent<PhotonView>() ?? ((Component)avatar).GetComponentInParent<PhotonView>();
		if ((Object)(object)_photonView == (Object)null)
		{
			SemiKick.LogError("[SemiKick] Не удалось найти PhotonView на объекте " + ((Object)avatar).name + "!");
			return;
		}
		_isLocal = !SemiFunc.IsMultiplayer() || _photonView.IsMine;
		SemiKick.LogInfo($"[SemiKick] KickAnimHandler: PhotonView найден, IsMine={_photonView.IsMine}, IsMultiplayer={SemiFunc.IsMultiplayer()}, isLocal={_isLocal}, ViewID={_photonView.ViewID}");
		if (_isLocal)
		{
			SemiKickRunner semiKickRunner = Object.FindObjectOfType<SemiKickRunner>();
			if ((Object)(object)semiKickRunner != (Object)null)
			{
				semiKickRunner.SetLocalPlayer(this);
				SemiKick.LogInfo("[SemiKick] KickAnimHandler: локальный игрок зарегистрирован в SemiKickRunner, Avatar передан.");
			}
			else
			{
				SemiKick.LogWarning("[SemiKick] SemiKickRunner не найден на сцене! Локальный Avatar не будет доступен для knockback.");
			}
		}
		SemiKick.LogInfo($"[SemiKick] KickAnimHandler успешно инициализирован (Local: {_isLocal}, ViewID: {_photonView.ViewID})");
	}

	public void PerformKick(Vector3? stretchTargetWorldPos = null)
	{
		//IL_006c: 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)
		Debug.Log((object)string.Format("[JSONAnimation] KickAnimHandler.PerformKick вызван для {0}: _animPlayer={1}, Multiplayer={2}, stretchTarget={3}.", ((Object)(object)_avatar != (Object)null) ? ((Object)_avatar).name : "NULL", ((Object)(object)_animPlayer != (Object)null) ? "не NULL" : "NULL", GameManager.Multiplayer(), stretchTargetWorldPos.HasValue ? ((object)stretchTargetWorldPos.Value/*cast due to .constrained prefix*/).ToString() : "NULL"));
		if ((Object)(object)_animPlayer != (Object)null)
		{
			_animPlayer.PlayKick(stretchTargetWorldPos);
		}
		else
		{
			Debug.LogWarning((object)"[JSONAnimation] KickAnimHandler.PerformKick: _animPlayer == NULL — анимация физически не может проиграться, т.к. компонент не был передан при Initialize (см. PlayerAvatarVisualsPatch).");
		}
		if ((Object)(object)_photonView != (Object)null && GameManager.Multiplayer())
		{
			_photonView.RPC("RPC_PlayKick", (RpcTarget)1, Array.Empty<object>());
		}
	}

	[PunRPC]
	public void RPC_PlayKick()
	{
		if ((Object)(object)_animPlayer != (Object)null)
		{
			_animPlayer.PlayKick();
		}
	}

	private void TryForceTumble(Vector3 force)
	{
		//IL_0018: 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_0027: 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)
		//IL_003e: 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_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_0061: Unknown result type (might be due to invalid IL or missing references)
		PlayerTumble tumbleComponent = InternalAccessors.GetTumbleComponent(_avatar);
		if (!((Object)(object)tumbleComponent == (Object)null))
		{
			Vector3 val = Vector3.Lerp(((Vector3)(ref force)).normalized, Vector3.up, 0.6f);
			float magnitude = ((Vector3)(ref force)).magnitude;
			tumbleComponent.TumbleRequest(true, false);
			tumbleComponent.TumbleForce(val * magnitude);
			tumbleComponent.TumbleTorque(-((Component)_avatar).transform.right * magnitude);
			tumbleComponent.TumbleOverrideTime(1.5f);
			SemiKick.LogInfo($"[SemiKick] ГАРАНТИРОВАННЫЙ ПОЛЕТ для {((Object)_avatar).name}. Сила: {magnitude}");
		}
	}

	public void RequestGenericKick(Action applyAction)
	{
		if (InternalAccessors.CanDoStuff(Avatar))
		{
			((MonoBehaviour)this).StartCoroutine(DelayedKickCoroutine(applyAction));
		}
	}

	private IEnumerator DelayedKickCoroutine(Action applyAction)
	{
		if ((Object)(object)pc == (Object)null)
		{
			SemiKick.LogWarning("[KickAnimHandler.DelayedKickCoroutine] PlayerController не найден на сцене! Если что сейчас мод ляжет НАХУЙ, хорошо?");
		}
		((Behaviour)pc).enabled = false;
		yield return (object)new WaitForSeconds(0.5f);
		float duration = 0.11f;
		float totalKick = 49.04f;
		float elapsed = 0f;
		float lastHeight = 0f;
		while (elapsed < duration)
		{
			elapsed += Time.deltaTime;
			float num = Mathf.Sin(Mathf.Min(1f, elapsed / duration) * (float)Math.PI * 0.5f);
			float num2 = totalKick * num;
			float num3 = num2 - lastHeight;
			CameraAim.Instance.AdditiveAimY(0f - num3);
			lastHeight = num2;
			yield return null;
		}
		((Behaviour)pc).enabled = true;
		applyAction?.Invoke();
	}

	public void RequestKick(Vector3 force, bool forceTumble = false)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		RequestGenericKick(delegate
		{
			//IL_0013: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				_avatar.ForceImpulse(force);
				if (forceTumble)
				{
					TryForceTumble(force);
				}
			}
			else if ((Object)(object)_photonView != (Object)null)
			{
				_photonView.RPC("RequestKickRPC", (RpcTarget)2, new object[2] { force, forceTumble });
			}
		});
	}

	[PunRPC]
	private void RequestKickRPC(Vector3 force, bool forceTumble, PhotonMessageInfo _info = default(PhotonMessageInfo))
	{
		//IL_0006: 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)
		_avatar.ForceImpulse(force);
		if (forceTumble)
		{
			TryForceTumble(force);
		}
	}
}
internal static class KnockbackCalculator
{
	public static void Apply(PlayerAvatar kicker, float targetMass, float kickForce, Vector3 kickDirection)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: 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_0220: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: 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_01d3: 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_01eb: Unknown result type (might be due to invalid IL or missing references)
		SemiKick.LogInfo(string.Format("[SemiKick] KnockbackCalculator.Apply вызван: kicker={0}, targetMass={1}, kickForce={2}, direction={3}", ((Object)(object)kicker != (Object)null) ? ((Object)kicker).name : "NULL", targetMass, kickForce, kickDirection));
		if ((Object)(object)kicker == (Object)null)
		{
			SemiKick.LogWarning("[SemiKick] KnockbackCalculator.Apply: kicker == null (localPlayerHandler.Avatar не был передан?), выхожу без эффекта.");
			return;
		}
		if (targetMass <= 0f)
		{
			SemiKick.LogWarning($"[SemiKick] KnockbackCalculator.Apply: targetMass={targetMass} <= 0, выхожу без эффекта (масса не найдена или объект и правда невесомый).");
			return;
		}
		if (kickForce <= 0f)
		{
			SemiKick.LogWarning($"[SemiKick] KnockbackCalculator.Apply: kickForce={kickForce} <= 0, выхожу без эффекта.");
			return;
		}
		float num = targetMass / kickForce;
		float num2 = 0.9f;
		float num3 = 4f;
		SemiKick.LogInfo($"[SemiKick] KnockbackCalculator: resistanceRatio={num} (targetMass={targetMass} / kickForce={kickForce}), SoftThreshold={num2}, HardThreshold={num3}");
		if (num <= num2)
		{
			SemiKick.LogInfo("[SemiKick] KnockbackCalculator: resistanceRatio <= SoftThreshold -> без отдачи.");
			return;
		}
		Vector3 val = -((Vector3)(ref kickDirection)).normalized;
		float num4 = targetMass * 3f;
		if (num > num3)
		{
			float num5 = targetMass * 3f;
			float num6 = Mathf.Max(num5, 20f);
			SemiKick.LogInfo($"[SemiKick] KnockbackCalculator: resistanceRatio > HardThreshold -> ТАМБЛ + урон. computedForce={num5}, floor={20f}, итог recoilForce={num6}, direction={val}");
			PlayerTumble tumbleComponent = InternalAccessors.GetTumbleComponent(kicker);
			if ((Object)(object)tumbleComponent != (Object)null)
			{
				int num7 = CalculateDamage(num, num3);
				SemiKick.LogInfo($"[SemiKick] KnockbackCalculator: вызываю tumble.TumbleRequest(true, false) и tumble.ImpactHurtSet(window={0.5f}, damage={num7})");
				tumbleComponent.TumbleRequest(true, false);
				tumbleComponent.ImpactHurtSet(0.5f, num7);
			}
			else
			{
				SemiKick.LogWarning("[SemiKick] KnockbackCalculator: tumble == null, тамбл/урон НЕ применены, будет только импульс.");
			}
			SemiKick.LogInfo($"[SemiKick] KnockbackCalculator: вызываю kicker.ForceImpulse({val * num6})");
			kicker.ForceImpulse(val * num6);
		}
		else
		{
			float num8 = num4 * 0.3f;
			SemiKick.LogInfo($"[SemiKick] KnockbackCalculator: Soft < resistanceRatio <= Hard -> лёгкая отдача без тамбла. force={num8}, direction={val}");
			kicker.ForceImpulse(val * num8);
		}
	}

	private static int CalculateDamage(float resistanceRatio, float hardThreshold)
	{
		float num = Mathf.InverseLerp(hardThreshold, hardThreshold * 2f, resistanceRatio);
		int num2 = Mathf.RoundToInt(Mathf.Lerp(15f, 50f, num));
		SemiKick.LogInfo($"[SemiKick] KnockbackCalculator.CalculateDamage: resistanceRatio={resistanceRatio}, t={num}, damage={num2}");
		return num2;
	}
}
[HarmonyPatch(typeof(PlayerAvatar), "Start")]
public static class PlayerAvatar_Start_Patch
{
	[HarmonyPostfix]
	public static void Postfix(PlayerAvatar __instance)
	{
		Debug.Log((object)$"[JSONAnimation] PlayerAvatar_Start_Patch.Postfix вызван для {((Object)__instance).name}, photonView={(Object)(object)__instance.photonView != (Object)null}.");
		if (!((Object)(object)__instance.photonView == (Object)null))
		{
			KickAnimHandler kickAnimHandler = ((Component)__instance).gameObject.GetComponent<KickAnimHandler>() ?? ((Component)__instance).gameObject.AddComponent<KickAnimHandler>();
			PlayerAvatarVisuals componentInChildren = ((Component)((Component)__instance).transform.root).GetComponentInChildren<PlayerAvatarVisuals>(true);
			Debug.Log((object)($"[JSONAnimation] transform.root.GetComponentInChildren<PlayerAvatarVisuals>(true) на {((Object)__instance).name} (root={((Object)((Component)__instance).transform.root).name}): найдено={(Object)(object)componentInChildren != (Object)null}" + (((Object)(object)componentInChildren != (Object)null) ? $", gameObject.activeSelf={((Component)componentInChildren).gameObject.activeSelf}, activeInHierarchy={((Component)componentInChildren).gameObject.activeInHierarchy}" : "") + "."));
			KickAnimationPlayer kickAnimationPlayer = null;
			if ((Object)(object)componentInChildren != (Object)null)
			{
				kickAnimationPlayer = ((Component)componentInChildren).gameObject.GetComponent<KickAnimationPlayer>() ?? ((Component)componentInChildren).gameObject.AddComponent<KickAnimationPlayer>();
				Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				string text = "SemiKick.Resources.kick_animation.json";
				Debug.Log((object)("[JSONAnimation] Вызываю kickPlayer.InitializeFromEmbeddedResource(jsonPath=" + text + ", rigRoot=" + ((Object)((Component)componentInChildren).transform).name + ") на объекте " + ((Object)((Component)componentInChildren).gameObject).name + "."));
				kickAnimationPlayer.InitializeFromEmbeddedResource(text, ((Component)componentInChildren).transform);
			}
			else
			{
				Debug.LogWarning((object)("[JSONAnimation] PlayerAvatarVisuals НЕ найден на " + ((Object)__instance).name + " (или его детях) — kickPlayer останется NULL, анимация для этого аватара работать не будет."));
			}
			Debug.Log((object)("[JSONAnimation] Передаю kickPlayer=" + (((Object)(object)kickAnimationPlayer != (Object)null) ? "не NULL" : "NULL") + " в KickAnimHandler.Initialize для " + ((Object)__instance).name + "."));
			kickAnimHandler.Initialize(kickAnimationPlayer, __instance);
		}
	}
}
internal static class InternalAccessors
{
	private static readonly FieldRef<PlayerAvatar, bool> IsTumblingRef = AccessTools.FieldRefAccess<PlayerAvatar, bool>("isTumbling");

	private static readonly FieldRef<PlayerAvatar, bool> IsCrouchingRef = AccessTools.FieldRefAccess<PlayerAvatar, bool>("isCrouching");

	private static readonly FieldRef<PlayerAvatar, bool> IsGroundedRef = AccessTools.FieldRefAccess<PlayerAvatar, bool>("isGrounded");

	public static Rigidbody GetEnemyRigidbody(EnemyRigidbody enemyRb)
	{
		if ((Object)(object)enemyRb == (Object)null)
		{
			return null;
		}
		Rigidbody value = Traverse.Create((object)enemyRb).Field("rb").GetValue<Rigidbody>();
		if ((Object)(object)value == (Object)null)
		{
			SemiKick.LogWarning("[SemiKick] InternalAccessors.GetEnemyRigidbody: поле 'rb' вернуло null.");
		}
		return value;
	}

	public static Enemy GetEnemyFromRigidbody(EnemyRigidbody enemyRb)
	{
		if ((Object)(object)enemyRb == (Object)null)
		{
			return null;
		}
		return Traverse.Create((object)enemyRb).Field("enemy").GetValue<Enemy>();
	}

	public static Rigidbody GetPlayerRigidbody(PlayerAvatar player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return null;
		}
		return Traverse.Create((object)player).Field("rb").GetValue<Rigidbody>();
	}

	public static bool GetIsTumbling(PlayerAvatar player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		return Traverse.Create((object)player).Field("isTumbling").GetValue<bool>();
	}

	public static PlayerTumble GetTumbleComponent(PlayerAvatar player)
	{
		if ((Object)(object)player == (Object)null)
		{
			SemiKick.LogWarning("[SemiKick] InternalAccessors.GetTumbleComponent: player == null.");
			return null;
		}
		PlayerTumble value = Traverse.Create((object)player).Field("tumble").GetValue<PlayerTumble>();
		if ((Object)(object)value == (Object)null)
		{
			SemiKick.LogWarning("[SemiKick] InternalAccessors.GetTumbleComponent: поле 'tumble' вернуло null для " + ((Object)player).name + ".");
			return value;
		}
		SemiKick.LogInfo("[SemiKick] InternalAccessors.GetTumbleComponent: tumble найден для " + ((Object)player).name + ".");
		return value;
	}

	public static PhotonView GetEnemyPhotonView(Enemy enemy)
	{
		if ((Object)(object)enemy == (Object)null)
		{
			return null;
		}
		return Traverse.Create((object)enemy).Field("PhotonView").GetValue<PhotonView>();
	}

	public static EnemyStateStunned GetEnemyStateStunned(Enemy enemy)
	{
		if ((Object)(object)enemy == (Object)null)
		{
			return null;
		}
		return Traverse.Create((object)enemy).Field("StateStunned").GetValue<EnemyStateStunned>();
	}

	public static bool CanDoStuff(PlayerAvatar player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		bool num = IsTumblingRef.Invoke(player);
		bool flag = IsCrouchingRef.Invoke(player);
		bool flag2 = IsGroundedRef.Invoke(player);
		return !num && !flag && flag2;
	}
}
internal static class KickNetworking
{
	public static void ApplyKickToPlayer(PlayerAvatar player, Vector3 force, bool forceTumble = false)
	{
		//IL_0039: 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)
		KickAnimHandler component = ((Component)player).gameObject.GetComponent<KickAnimHandler>();
		if ((Object)(object)component != (Object)null)
		{
			component.RequestKick(force, forceTumble);
			return;
		}
		SemiKick.LogWarning("[SemiKick] ApplyKickToPlayer: у " + ((Object)player).name + " нет KickAnimHandler, пинок может не сработать у гостей.");
		player.ForceImpulse(force);
	}

	public static void ApplyKickToValuable(PhysGrabObject physGrabObject, Vector3 force, Vector3 hitPoint)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)physGrabObject == (Object)null) && SemiFunc.IsMasterClientOrSingleplayer())
		{
			Rigidbody rb = physGrabObject.rb;
			if (!((Object)(object)rb == (Object)null))
			{
				rb.AddForceAtPosition(force, hitPoint, (ForceMode)1);
			}
		}
	}
}
internal enum KickTargetType
{
	None,
	Player,
	Enemy,
	Valuable
}
internal struct KickTarget
{
	public KickTargetType Type;

	public Rigidbody Rigidbody;

	public Component Component;
}
internal static class KickTargetClassifier
{
	public static KickTarget ClassifyHit(Collider col)
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Invalid comparison between Unknown and I4
		KickTarget result = new KickTarget
		{
			Type = KickTargetType.None
		};
		PlayerAvatar val = ((Component)col).GetComponentInParent<PlayerAvatar>();
		if ((Object)(object)val == (Object)null)
		{
			val = ((Component)((Component)col).transform.root).GetComponentInChildren<PlayerAvatar>();
		}
		if ((Object)(object)val != (Object)null)
		{
			result.Type = KickTargetType.Player;
			result.Component = (Component)(object)val;
			result.Rigidbody = InternalAccessors.GetPlayerRigidbody(val);
			return result;
		}
		EnemyRigidbody componentInParent = ((Component)col).GetComponentInParent<EnemyRigidbody>();
		if ((Object)(object)componentInParent != (Object)null)
		{
			Enemy enemyFromRigidbody = InternalAccessors.GetEnemyFromRigidbody(componentInParent);
			if ((Object)(object)enemyFromRigidbody != (Object)null)
			{
				if ((int)enemyFromRigidbody.CurrentState == 11)
				{
					return result;
				}
				result.Type = KickTargetType.Enemy;
				result.Component = (Component)(object)enemyFromRigidbody;
				result.Rigidbody = InternalAccessors.GetEnemyRigidbody(componentInParent);
				return result;
			}
		}
		ValuableObject componentInParent2 = ((Component)col).GetComponentInParent<ValuableObject>();
		if ((Object)(object)componentInParent2 != (Object)null)
		{
			PhysGrabObject component = ((Component)componentInParent2).GetComponent<PhysGrabObject>();
			if ((Object)(object)component == (Object)null)
			{
				return result;
			}
			if (component.grabbed)
			{
				return result;
			}
			result.Type = KickTargetType.Valuable;
			result.Component = (Component)(object)component;
			result.Rigidbody = component.rb;
			return result;
		}
		PhysGrabObject componentInParent3 = ((Component)col).GetComponentInParent<PhysGrabObject>();
		if ((Object)(object)componentInParent3 != (Object)null)
		{
			if (componentInParent3.grabbed)
			{
				return result;
			}
			result.Type = KickTargetType.Valuable;
			result.Component = (Component)(object)componentInParent3;
			result.Rigidbody = componentInParent3.rb;
			return result;
		}
		return result;
	}
}
[BepInPlugin("quxxciy.semikick", "SemiKick", "0.1.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class SemiKick : BaseUnityPlugin
{
	private Harmony harmony;

	private Keybind kickKeybind;

	private static bool runnerCreated;

	internal static ManualLogSource LoggerInstance;

	public const string UpgradeId = "SemiKick_KickUpgrade";

	private void Awake()
	{
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Expected O, but got Unknown
		LoggerInstance = ((BaseUnityPlugin)this).Logger;
		kickKeybind = Keybinds.Bind("Kick", "<Keyboard>/f");
		LogInfo("SemiKick загружен, бинд зарегистрирован.");
		ItemContent val = LoadItemContentFromEmbeddedBundle("SemiKick.Resources.SemiKick.repobundle", "REPOLib_Item Upgrade Kick");
		Item val2 = null;
		if ((Object)(object)val != (Object)null)
		{
			Items.RegisterItem(val);
			ItemAttributes component = ((Component)val.Prefab).GetComponent<ItemAttributes>();
			if ((Object)(object)component != (Object)null)
			{
				val2 = component.item;
			}
			else
			{
				LogError("На префабе нет компонента ItemAttributes.");
			}
		}
		Upgrades.RegisterUpgrade("SemiKick_KickUpgrade", val2, (Action<PlayerAvatar, int>)OnUpgradeStart, (Action<PlayerAvatar, int>)OnUpgradeApplied);
		harmony = new Harmony("quxxciy.semikick");
		harmony.PatchAll();
		SceneManager.sceneLoaded += OnSceneLoaded;
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		//IL_0028: 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_0033: Expected O, but got Unknown
		if (!runnerCreated)
		{
			LogInfo("Первая сцена загружена: " + ((Scene)(ref scene)).name + ", создаю Runner.");
			GameObject val = new GameObject("SemiKickRunner");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<SemiKickRunner>().InitKey(kickKeybind);
			runnerCreated = true;
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}
	}

	private ItemContent LoadItemContentFromEmbeddedBundle(string resourceFileName, string itemContentAssetName)
	{
		Assembly executingAssembly = Assembly.GetExecutingAssembly();
		string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string n) => n.EndsWith(resourceFileName));
		if (text == null)
		{
			LogError("Embedded resource '" + resourceFileName + "' не найден.");
			return null;
		}
		Stream? manifestResourceStream = executingAssembly.GetManifestResourceStream(text);
		MemoryStream memoryStream = new MemoryStream();
		manifestResourceStream.CopyTo(memoryStream);
		manifestResourceStream.Dispose();
		AssetBundle val = AssetBundle.LoadFromMemory(memoryStream.ToArray());
		memoryStream.Dispose();
		if ((Object)(object)val == (Object)null)
		{
			LogError("Не удалось загрузить AssetBundle из памяти.");
			return null;
		}
		ItemContent obj = val.LoadAsset<ItemContent>(itemContentAssetName);
		if ((Object)(object)obj == (Object)null)
		{
			LogError("ItemContent '" + itemContentAssetName + "' не найден в бандле.");
		}
		return obj;
	}

	private ItemContent LoadItemContentFromFile(string bundleFileName, string itemContentAssetName)
	{
		string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), bundleFileName);
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Ищу бандл по пути: " + text));
		if (!File.Exists(text))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Файл бандла не найден по пути: " + text));
			return null;
		}
		AssetBundle val = AssetBundle.LoadFromFile(text);
		if ((Object)(object)val == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"AssetBundle.LoadFromFile вернул null — файл повреждён или не тот формат.");
			return null;
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("AssetBundle загружен. Ассеты внутри: " + string.Join(", ", val.GetAllAssetNames())));
		ItemContent obj = val.LoadAsset<ItemContent>(itemContentAssetName);
		if ((Object)(object)obj == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("ItemContent с именем '" + itemContentAssetName + "' НЕ найден в бандле."));
			return obj;
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ItemContent успешно загружен!");
		return obj;
	}

	public static void Log(LogLevel level, object data)
	{
	}

	public static void LogInfo(object data)
	{
		Log((LogLevel)16, data);
	}

	public static void LogDebug(object data)
	{
		Log((LogLevel)32, data);
	}

	public static void LogWarning(object data)
	{
		Log((LogLevel)4, data);
	}

	public static void LogError(object data)
	{
		Log((LogLevel)2, data);
	}

	private static void OnUpgradeStart(PlayerAvatar player, int level)
	{
		LogInfo(string.Format("[Start] {0} имеет {1} уровня {2}", ((Object)player).name, "SemiKick_KickUpgrade", level));
		ApplyKickLevelToPlayer(player, level);
	}

	private static void OnUpgradeApplied(PlayerAvatar player, int level)
	{
		LogInfo(string.Format("[Applied] {0} теперь имеет {1} уровня {2}", ((Object)player).name, "SemiKick_KickUpgrade", level));
		ApplyKickLevelToPlayer(player, level);
	}

	private static void ApplyKickLevelToPlayer(PlayerAvatar player, int level)
	{
		if ((Object)(object)player == (Object)null)
		{
			LogWarning("[SemiKick] ApplyKickLevelToPlayer: player == null.");
		}
		else
		{
			(((Component)player).gameObject.GetComponent<KickAnimHandler>() ?? ((Component)player).gameObject.AddComponent<KickAnimHandler>()).SetKickLevel(level);
		}
	}
}
public class SemiKickRunner : MonoBehaviour
{
	private Keybind kickKeybind;

	private KickAnimHandler localPlayerHandler;

	private float kickCooldown = 1.4f;

	private float cooldownTimer;

	public void InitKey(Keybind keybind)
	{
		kickKeybind = keybind;
	}

	public void SetLocalPlayer(KickAnimHandler handler)
	{
		localPlayerHandler = handler;
		SemiKick.LogInfo(string.Format("SemiKickRunner.SetLocalPlayer: handler={0}, Avatar={1}", (Object)(object)handler != (Object)null, ((Object)(object)handler != (Object)null && (Object)(object)handler.Avatar != (Object)null) ? ((Object)handler.Avatar).name : "NULL"));
	}

	private void Update()
	{
		//IL_0025: 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_008e: Unknown result type (might be due to invalid IL or missing references)
		if (cooldownTimer > 0f)
		{
			cooldownTimer -= Time.deltaTime;
		}
		if (SemiFunc.InputDown(kickKeybind.inputKey) && !(cooldownTimer > 0f))
		{
			RaycastHit hit;
			KickTarget target;
			bool flag = TryFindKickTarget(out hit, out target);
			Vector3? stretchTargetWorldPos = (flag ? new Vector3?(((RaycastHit)(ref hit)).point) : ((Vector3?)null));
			if ((Object)(object)localPlayerHandler != (Object)null)
			{
				localPlayerHandler.PerformKick(stretchTargetWorldPos);
			}
			else
			{
				SemiKick.LogWarning("SemiKickRunner.Update: localPlayerHandler == null, PerformKick пропущен.");
			}
			ApplyKickEffects(flag, hit, target);
		}
	}

	private int GetEffectiveKickLevel()
	{
		if (!((Object)(object)localPlayerHandler != (Object)null))
		{
			return 0;
		}
		return localPlayerHandler.KickLevel;
	}

	private bool TryFindKickTarget(out RaycastHit hit, out KickTarget target)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: 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)
		//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_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		hit = default(RaycastHit);
		target = default(KickTarget);
		RaycastHit[] array = Physics.RaycastAll(new Ray(((Component)Camera.main).transform.position, ((Component)Camera.main).transform.forward), 2.3f);
		if (array.Length == 0)
		{
			SemiKick.LogInfo("TryFindKickTarget: рейкаст ни во что не попал.");
			return false;
		}
		Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
		PlayerAvatar val = (((Object)(object)localPlayerHandler != (Object)null) ? localPlayerHandler.Avatar : null);
		RaycastHit[] array2 = array;
		for (int num = 0; num < array2.Length; num++)
		{
			RaycastHit val2 = array2[num];
			SemiKick.LogInfo("TryFindKickTarget: попадание в коллайдер '" + ((Object)((RaycastHit)(ref val2)).collider).name + "' на объекте '" + ((Object)((Component)((RaycastHit)(ref val2)).collider).gameObject).name + "'.");
			KickTarget kickTarget = KickTargetClassifier.ClassifyHit(((RaycastHit)(ref val2)).collider);
			SemiKick.LogInfo(string.Format("TryFindKickTarget: классификация -> Type={0}, Component={1}", kickTarget.Type, ((Object)(object)kickTarget.Component != (Object)null) ? ((object)kickTarget.Component).GetType().Name : "NULL"));
			if (kickTarget.Type == KickTargetType.Player && (Object)(object)val != (Object)null && (object)kickTarget.Component == val)
			{
				SemiKick.LogInfo("TryFindKickTarget: попадание в СВОЕГО персонажа — игнорирую и продолжаю искать дальше.");
				continue;
			}
			hit = val2;
			target = kickTarget;
			return true;
		}
		SemiKick.LogInfo("TryFindKickTarget: после пропуска своего персонажа других целей не найдено.");
		return false;
	}

	private void ApplyKickEffects(bool found, RaycastHit hit, KickTarget target)
	{
		//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_01d3: 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_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Expected O, but got Unknown
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Expected O, but got Unknown
		//IL_0303: Unknown result type (might be due to invalid IL or missing references)
		//IL_030d: Expected O, but got Unknown
		//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f1: 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)
		//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_03db: Unknown result type (might be due to invalid IL or missing references)
		//IL_040b: Unknown result type (might be due to invalid IL or missing references)
		if (!found)
		{
			SemiKick.LogInfo("ApplyKickEffects: цель не найдена, выхожу без эффектов.");
			return;
		}
		if (!InternalAccessors.CanDoStuff(localPlayerHandler?.Avatar))
		{
			SemiKick.LogInfo("Не устойчивая конструкция - пропуск.");
			return;
		}
		if (target.Type != KickTargetType.Player && target.Type != KickTargetType.Enemy && target.Type != KickTargetType.Valuable)
		{
			SemiKick.LogInfo("ApplyKickEffects: цель не валидна (None/неизвестный тип), выхожу без эффектов.");
			return;
		}
		Vector3 direction = ((Component)Camera.main).transform.forward;
		int effectiveKickLevel = GetEffectiveKickLevel();
		float force = SemiKickSettings.GetKickForce(effectiveKickLevel);
		SemiKick.LogInfo($"ApplyKickEffects: рассчитанная сила force={force} (baseForce={1.4f}, effectiveLevel={effectiveKickLevel}, levelMultiplier={0.7f})");
		float num = Mathf.Clamp(force * 0.05f, 4f, 14f);
		if ((Object)(object)GameDirector.instance != (Object)null && (Object)(object)GameDirector.instance.CameraShake != (Object)null)
		{
			SemiKick.LogInfo($"ApplyKickEffects: вызываю CameraShake.Shake(strength={num}, time={0.05f})");
			GameDirector.instance.CameraShake.Shake(num, 0.05f);
		}
		else
		{
			SemiKick.LogWarning("ApplyKickEffects: GameDirector.instance или CameraShake == null, тряска пропущена.");
		}
		PlayerAvatar kicker = (((Object)(object)localPlayerHandler != (Object)null) ? localPlayerHandler.Avatar : null);
		if ((Object)(object)kicker == (Object)null)
		{
			SemiKick.LogWarning("ApplyKickEffects: kicker (Avatar локального игрока) == null — knockback работать не будет для этого пинка.");
		}
		switch (target.Type)
		{
		case KickTargetType.Player:
		{
			bool flag = effectiveKickLevel >= 2;
			SemiKick.LogInfo($"ApplyKickEffects: цель Player -> KickNetworking.ApplyKickToPlayer (без self-knockback), forceTumble={flag} (effectiveLevel={effectiveKickLevel} >= {2}).");
			KickNetworking.ApplyKickToPlayer((PlayerAvatar)target.Component, direction * force, flag);
			break;
		}
		case KickTargetType.Enemy:
		{
			Enemy enemy = (Enemy)target.Component;
			EnemyKickReceiver enemyReceiver = ((Component)enemy).GetComponent<EnemyKickReceiver>();
			if (!((Object)(object)enemyReceiver != (Object)null))
			{
				break;
			}
			float enemyMass = enemyReceiver.GetMass();
			SemiKick.LogInfo($"ApplyKickEffects: цель Enemy '{((Object)enemy).name}', mass={enemyMass} -> ставлю в очередь.");
			if ((Object)(object)localPlayerHandler != (Object)null)
			{
				localPlayerHandler.RequestGenericKick(delegate
				{
					//IL_0042: 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_0091: Unknown result type (might be due to invalid IL or missing references)
					if ((Object)(object)enemyReceiver == (Object)null || (Object)(object)enemy == (Object)null)
					{
						SemiKick.LogWarning("ApplyKickEffects: Враг исчез до момента удара!");
					}
					else
					{
						enemyReceiver.SendKick(direction * force);
						if ((Object)(object)kicker != (Object)null)
						{
							KnockbackCalculator.Apply(kicker, enemyMass, force, direction);
						}
					}
				});
			}
			else
			{
				enemyReceiver.SendKick(direction * force);
				KnockbackCalculator.Apply(kicker, enemyMass, force, direction);
			}
			break;
		}
		case KickTargetType.Valuable:
		{
			PhysGrabObject physGrabObject = (PhysGrabObject)target.Component;
			ValuableKickReceiver valuableReceiver = ((Component)physGrabObject).GetComponent<ValuableKickReceiver>();
			if (!((Object)(object)valuableReceiver != (Object)null))
			{
				break;
			}
			float valuableMass = (((Object)(object)physGrabObject.rb != (Object)null) ? physGrabObject.rb.mass : 0f);
			Vector3 hitPoint = ((RaycastHit)(ref hit)).point;
			if ((Object)(object)localPlayerHandler != (Object)null)
			{
				localPlayerHandler.RequestGenericKick(delegate
				{
					//IL_0042: 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_0058: Unknown result type (might be due to invalid IL or missing references)
					//IL_00af: Unknown result type (might be due to invalid IL or missing references)
					if ((Object)(object)valuableReceiver == (Object)null || (Object)(object)physGrabObject == (Object)null)
					{
						SemiKick.LogWarning("ApplyKickEffects: Предмет исчез до момента удара!");
					}
					else
					{
						valuableReceiver.RequestKick(direction * force, hitPoint);
						if ((Object)(object)kicker != (Object)null && (Object)(object)physGrabObject.rb != (Object)null)
						{
							KnockbackCalculator.Apply(kicker, valuableMass, force, direction);
						}
					}
				});
			}
			else
			{
				valuableReceiver.RequestKick(direction * force, hitPoint);
				KnockbackCalculator.Apply(kicker, valuableMass, force, direction);
			}
			break;
		}
		}
	}
}
internal static class SemiKickSettings
{
	public const bool EnableLogging = false;

	public const LogLevel MinLogLevel = (LogLevel)16;

	public const float BaseForce = 1.4f;

	public const float LevelMultiplier = 0.7f;

	public const int PlayerTumbleGuaranteeLevel = 2;

	public const float ShakeForceMultiplier = 0.05f;

	public const float ShakeMin = 4f;

	public const float ShakeMax = 14f;

	public const float ShakeTime = 0.05f;

	public const float LegStretchNaturalReach = 0.5f;

	public const float LegStretchMaxMultiplier = 1.8f;

	public const int LegStretchAxis = 1;

	public const float LegStretchLerpSpeed = 8f;

	public const float KnockbackSoftThreshold = 0.9f;

	public const float KnockbackHardThreshold = 4f;

	public const float RecoilForceMultiplier = 3f;

	public const float KnockbackHardMinForce = 20f;

	public const float ImpactHurtWindow = 0.5f;

	public const int ImpactHurtDamageBase = 15;

	public const int ImpactHurtDamageMax = 50;

	public static float GetKickForce(int kickLevel)
	{
		return 1.4f * (1f + (float)kickLevel * 0.7f);
	}
}
internal class ValuableKickReceiver : MonoBehaviourPun
{
	private PhysGrabObject _physGrabObject;

	private void Awake()
	{
		_physGrabObject = ((Component)this).GetComponent<PhysGrabObject>();
	}

	public void RequestKick(Vector3 force, Vector3 hitPoint)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		if (SemiFunc.IsMasterClientOrSingleplayer())
		{
			KickNetworking.ApplyKickToValuable(_physGrabObject, force, hitPoint);
			return;
		}
		PhotonView photonView = ((MonoBehaviourPun)this).photonView;
		if (!((Object)(object)photonView == (Object)null))
		{
			photonView.RPC("RequestKickRPC", (RpcTarget)2, new object[2] { force, hitPoint });
		}
	}

	[PunRPC]
	private void RequestKickRPC(Vector3 force, Vector3 hitPoint, PhotonMessageInfo _info = default(PhotonMessageInfo))
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		KickNetworking.ApplyKickToValuable(_physGrabObject, force, hitPoint);
	}
}
[HarmonyPatch(typeof(PhysGrabObject), "Awake")]
internal static class ValuableKickReceiverPatch
{
	[HarmonyPostfix]
	private static void Postfix(PhysGrabObject __instance)
	{
		if ((Object)(object)((Component)__instance).gameObject.GetComponent<ValuableKickReceiver>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<ValuableKickReceiver>();
		}
	}
}