Decompiled source of Herobrian spells v1.0.0
BepInEx\plugins\Herobrian_spells\Herobrian_spells.dll
Decompiled 15 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FMODUnity; using HarmonyLib; using Mirror; using UnityEngine; using UnityEngine.AI; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using YAPYAP; [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("YapyapFireBall")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("YapyapFireBall")] [assembly: AssemblyTitle("YapyapFireBall")] [assembly: AssemblyVersion("1.0.0.0")] namespace YapyapFireBallMod; internal enum ControlActionKind { HoldInput, Closer, Raise, SlamDown, Throw } internal enum ControlDirection { Forward, Back, Left, Right, Up, Down, UpLeft, UpRight, DownLeft, DownRight, ForwardLeft, ForwardRight, BackLeft, BackRight } internal sealed class ControlActionDefinition { internal string Key { get; } internal string[] Phrase { get; } internal ControlActionKind Kind { get; } internal ControlDirection Direction { get; } internal ControlActionDefinition(string key, string[] phrase, ControlActionKind kind, ControlDirection direction = ControlDirection.Forward) { Key = key; Phrase = phrase; Kind = kind; Direction = direction; } } internal static class ControlActionCatalog { internal static readonly ControlActionDefinition[] VoiceActions = new ControlActionDefinition[19] { new ControlActionDefinition("MOD_CONTROL_CLOSER", new string[1] { "CLOSER" }, ControlActionKind.Closer), new ControlActionDefinition("MOD_CONTROL_RAISE", new string[1] { "RAISE" }, ControlActionKind.Raise), new ControlActionDefinition("MOD_CONTROL_SLAM_DOWN", new string[2] { "SLAM", "DOWN" }, ControlActionKind.SlamDown), Throw("FORWARD", ControlDirection.Forward), Throw("BACK", ControlDirection.Back), Throw("LEFT", ControlDirection.Left), Throw("RIGHT", ControlDirection.Right), Throw("UP", ControlDirection.Up), Throw("DOWN", ControlDirection.Down), Throw("UP_LEFT", ControlDirection.UpLeft, "UP", "LEFT"), Throw("UP_RIGHT", ControlDirection.UpRight, "UP", "RIGHT"), Throw("DOWN_LEFT", ControlDirection.DownLeft, "DOWN", "LEFT"), Throw("DOWN_RIGHT", ControlDirection.DownRight, "DOWN", "RIGHT"), Throw("BOTTOM_LEFT", ControlDirection.DownLeft, "BOTTOM", "LEFT"), Throw("BOTTOM_RIGHT", ControlDirection.DownRight, "BOTTOM", "RIGHT"), Throw("FORWARD_LEFT", ControlDirection.ForwardLeft, "FORWARD", "LEFT"), Throw("FORWARD_RIGHT", ControlDirection.ForwardRight, "FORWARD", "RIGHT"), Throw("BACK_LEFT", ControlDirection.BackLeft, "BACK", "LEFT"), Throw("BACK_RIGHT", ControlDirection.BackRight, "BACK", "RIGHT") }; internal static IEnumerable<KeyValuePair<string, string[]>> GetVoiceCommands() { ControlActionDefinition[] voiceActions = VoiceActions; foreach (ControlActionDefinition controlActionDefinition in voiceActions) { yield return new KeyValuePair<string, string[]>(controlActionDefinition.Key, controlActionDefinition.Phrase); } } private static ControlActionDefinition Throw(string keySuffix, ControlDirection direction, params string[] directionWords) { string[] array = ((directionWords.Length != 0) ? directionWords : new string[1] { keySuffix }); string[] array2 = new string[array.Length + 1]; array2[0] = "THROW"; Array.Copy(array, 0, array2, 1, array.Length); return new ControlActionDefinition("MOD_CONTROL_THROW_" + keySuffix, array2, ControlActionKind.Throw, direction); } } public sealed class ControlActionSpell : Spell { [SerializeField] private ControlActionKind actionKind; [SerializeField] private ControlDirection direction; [SerializeField] private bool holdInputValue; internal ControlActionKind ActionKind => actionKind; internal ControlDirection Direction => direction; internal bool HoldInputValue => holdInputValue; internal bool IsHoldInputAction => ActionKind == ControlActionKind.HoldInput; internal void Configure(SpellData data, ControlActionKind actionKind, ControlDirection direction, bool holdInputValue = false) { base.spellData = data; this.actionKind = actionKind; this.direction = direction; this.holdInputValue = holdInputValue; base.OverrideSecret = true; } public override bool CanCast() { return false; } } public sealed class ControlInputRelay : MonoBehaviour { private static readonly FieldInfo AllSpellsField = AccessTools.Field(typeof(VoiceSpell), "allSpells"); private static readonly MethodInfo CastByIndexMethod = AccessTools.Method(typeof(VoiceSpell), "CmdCastSpellByIndex", (Type[])null, (Type[])null); [SerializeField] private VoiceSpell voiceSpell; private bool inputInitialized; private bool lastRPressed; private float nextSendRetry; internal bool ServerHoldActive { get; private set; } internal void Configure(VoiceSpell ownerVoiceSpell) { voiceSpell = ownerVoiceSpell; } internal void SetServerHold(bool active) { ServerHoldActive = active; if ((Object)(object)voiceSpell != (Object)null && voiceSpell.NetworkcurrentSpell is ControlSpell controlSpell) { controlSpell.SetHoldInput(active); } } private void Update() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)voiceSpell == (Object)null || (Object)(object)((Spell)voiceSpell).CasterIdentity == (Object)null || !((Spell)voiceSpell).CasterIdentity.isLocalPlayer) { inputInitialized = false; lastRPressed = false; return; } bool flag = Keyboard.current != null && ((ButtonControl)Keyboard.current[Plugin.ControlHoldKey]).isPressed; if ((!inputInitialized || flag != lastRPressed) && Time.unscaledTime >= nextSendRetry) { if (SendHoldState(flag)) { inputInitialized = true; lastRPressed = flag; } else { nextSendRetry = Time.unscaledTime + 0.25f; } } } private bool SendHoldState(bool pressed) { if (!(AllSpellsField.GetValue(voiceSpell) is List<Spell> list)) { return false; } int num = list.FindIndex((Spell spell) => spell is ControlActionSpell controlActionSpell && (Object)(object)((Component)controlActionSpell).gameObject == (Object)(object)((Component)voiceSpell).gameObject && controlActionSpell.IsHoldInputAction && controlActionSpell.HoldInputValue == pressed); if (num < 0) { return false; } try { CastByIndexMethod.Invoke(voiceSpell, new object[2] { num, false }); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Control R input relay failed: " + ex.GetBaseException().Message)); return false; } } } internal static class ControlBootstrap { private static readonly FieldInfo VoiceSpellsField = AccessTools.Field(typeof(VoiceSpell), "spells"); private static readonly FieldInfo AllSpellsField = AccessTools.Field(typeof(VoiceSpell), "allSpells"); private static readonly FieldInfo NetworkAssetIdField = AccessTools.Field(typeof(NetworkIdentity), "_assetId"); private static readonly FieldInfo NetworkHasSpawnedField = AccessTools.Field(typeof(NetworkIdentity), "hasSpawned"); private static readonly FieldInfo SpellTagField = AccessTools.Field(typeof(BaseProjectile), "spellTag"); private static readonly FieldInfo PalmField = AccessTools.Field(typeof(ProjectileHand), "palmTransform"); private static readonly FieldInfo RotationSpeedField = AccessTools.Field(typeof(ProjectileHand), "rotationSpeed"); private static GameObject networkHandPrefab; private static SpellData controlSpellData; private static readonly Dictionary<string, SpellData> ActionSpellData = new Dictionary<string, SpellData>(StringComparer.Ordinal); internal static void Install(YapNetworkManager manager) { if ((Object)(object)manager == (Object)null) { return; } GameObject val = FindPrefab(manager, "PropWandOfMinorArcanes"); GameObject val2 = FindPrefab(manager, "SpectralHand"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)"Control was not installed: PropWandOfMinorArcanes or SpectralHand was not found."); return; } NetworkIdentity val3 = default(NetworkIdentity); if (((NetworkManager)manager).spawnPrefabs.Any((GameObject prefab) => (Object)(object)prefab != (Object)null && prefab.TryGetComponent<NetworkIdentity>(ref val3) && val3.assetId == 3229223441u)) { Plugin.Log.LogError((object)$"Control hand asset ID collision: {3229223441u}. Control will not install."); return; } VoiceSpell component = val.GetComponent<VoiceSpell>(); GrabSpell component2 = val.GetComponent<GrabSpell>(); ProjectileHand component3 = val2.GetComponent<ProjectileHand>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { Plugin.Log.LogError((object)"Control was not installed: VoiceSpell, GrabSpell, or ProjectileHand is missing."); return; } EnsureRuntimeData(component2); EnsureHandPrefab(val2, component3); EnsureSpellsOnWand(val, component); } private static GameObject FindPrefab(YapNetworkManager manager, string name) { return ((IEnumerable<GameObject>)((NetworkManager)manager).spawnPrefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject prefab) => (Object)(object)prefab != (Object)null && string.Equals(((Object)prefab).name, name, StringComparison.Ordinal))); } private static void EnsureRuntimeData(GrabSpell grabSpell) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)controlSpellData == (Object)null) { controlSpellData = Object.Instantiate<SpellData>(((Spell)grabSpell).SpellData); ((Object)controlSpellData).name = "SD_ARC_CONTROL_MOD"; controlSpellData.spellName = "CONTROL"; controlSpellData.voiceCommandKey = "MOD_SPELL_ARC_CONTROL"; controlSpellData.cooldown = 2f; controlSpellData.charges = 3; controlSpellData.chargePerCast = 1; controlSpellData.chargeCostPerSecondCast = 0; controlSpellData.chargeRegenInterval = 6f; controlSpellData.chargesRegenPerInterval = 1; controlSpellData.chargeRegenDelay = 0.5f; controlSpellData.spawnLocation = (SpawnLocation)0; controlSpellData.spawnOffset = Vector3.zero; controlSpellData.applyLookTransform = true; controlSpellData.spawnDelay = 0f; } } private static void EnsureHandPrefab(GameObject vanillaHandPrefab, ProjectileHand vanillaHand) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)networkHandPrefab != (Object)null) { controlSpellData.objectToSpawnPrefab = networkHandPrefab; return; } bool activeSelf = vanillaHandPrefab.activeSelf; try { vanillaHandPrefab.SetActive(false); networkHandPrefab = Object.Instantiate<GameObject>(vanillaHandPrefab); } finally { vanillaHandPrefab.SetActive(activeSelf); } ((Object)networkHandPrefab).name = "ControlSpectralHandMod"; networkHandPrefab.SetActive(false); Object.DontDestroyOnLoad((Object)(object)networkHandPrefab); NetworkIdentity component = networkHandPrefab.GetComponent<NetworkIdentity>(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("The cloned SpectralHand has no NetworkIdentity."); } NetworkAssetIdField.SetValue(component, 3229223441u); NetworkHasSpawnedField.SetValue(component, false); component.sceneId = 0uL; NetworkBehaviour[] components = networkHandPrefab.GetComponents<NetworkBehaviour>(); foreach (NetworkBehaviour val in components) { if (((object)val).GetType().Name.IndexOf("NetworkTransform", StringComparison.Ordinal) >= 0) { val.syncDirection = (SyncDirection)0; } } ProjectileHand component2 = networkHandPrefab.GetComponent<ProjectileHand>(); ((Behaviour)component2).enabled = false; ControlProjectileHand obj = networkHandPrefab.GetComponent<ControlProjectileHand>() ?? networkHandPrefab.AddComponent<ControlProjectileHand>(); ProjectileData projectileData = ((BaseProjectile)component2).ProjectileData; SpellData ownerSpellData = controlSpellData; object ownerSpellTag = (object)/*isinst with value type is only supported in some contexts*/; object? value = PalmField.GetValue(component2); obj.Configure(projectileData, ownerSpellData, (GameplayTag)ownerSpellTag, component2, (Transform)((value is Transform) ? value : null), (float)RotationSpeedField.GetValue(component2), Plugin.ControlHoldStrength); controlSpellData.objectToSpawnPrefab = networkHandPrefab; Plugin.Log.LogInfo((object)$"Prepared Control spectral hand with asset ID {3229223441u}."); } private static void EnsureSpellsOnWand(GameObject wandPrefab, VoiceSpell voiceSpell) { ControlSpell controlSpell = wandPrefab.GetComponent<ControlSpell>() ?? wandPrefab.AddComponent<ControlSpell>(); controlSpell.Configure(controlSpellData); ((Behaviour)controlSpell).enabled = true; (wandPrefab.GetComponent<ControlInputRelay>() ?? wandPrefab.AddComponent<ControlInputRelay>()).Configure(voiceSpell); List<Spell> list = ((VoiceSpellsField.GetValue(voiceSpell) as Spell[]) ?? Array.Empty<Spell>()).ToList(); if (!list.Contains((Spell)(object)controlSpell)) { list.Add((Spell)(object)controlSpell); } AddActionSpell(wandPrefab, list, controlSpellData, "MOD_CONTROL_R_PRESS", Array.Empty<string>(), ControlActionKind.HoldInput, ControlDirection.Forward, holdInputValue: true); AddActionSpell(wandPrefab, list, controlSpellData, "MOD_CONTROL_R_RELEASE", Array.Empty<string>(), ControlActionKind.HoldInput, ControlDirection.Forward); ControlActionDefinition[] voiceActions = ControlActionCatalog.VoiceActions; foreach (ControlActionDefinition controlActionDefinition in voiceActions) { AddActionSpell(wandPrefab, list, controlSpellData, controlActionDefinition.Key, controlActionDefinition.Phrase, controlActionDefinition.Kind, controlActionDefinition.Direction); } VoiceSpellsField.SetValue(voiceSpell, list.ToArray()); Plugin.Log.LogInfo((object)($"Added Control, R input relay, and {ControlActionCatalog.VoiceActions.Length} " + $"voice actions to PropWandOfMinorArcanes ({list.Count} entries).")); } private static void AddActionSpell(GameObject wandPrefab, List<Spell> spells, SpellData template, string key, string[] phrase, ControlActionKind actionKind, ControlDirection direction, bool holdInputValue = false) { //IL_00e8: 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) ControlActionSpell controlActionSpell = wandPrefab.GetComponents<ControlActionSpell>().FirstOrDefault((ControlActionSpell action) => action.ActionKind == actionKind && action.Direction == direction && action.HoldInputValue == holdInputValue && (Object)(object)((Spell)action).SpellData != (Object)null && string.Equals(((Object)((Spell)action).SpellData).name, "SD_ARC_" + key, StringComparison.Ordinal)); if ((Object)(object)controlActionSpell == (Object)null) { controlActionSpell = wandPrefab.AddComponent<ControlActionSpell>(); } if (!ActionSpellData.TryGetValue(key, out var value)) { value = Object.Instantiate<SpellData>(template); ((Object)value).name = "SD_ARC_" + key; value.spellName = ((phrase.Length == 0) ? key : string.Join(" ", phrase)); value.voiceCommandKey = ((phrase.Length == 0) ? string.Empty : key); value.cooldown = 0f; value.charges = -1; value.chargePerCast = 0; value.chargeCostPerSecondCast = 0; value.chargesRegenPerInterval = 0; value.objectToSpawnPrefab = null; value.castingAnimationType = (CastingAnimationType)0; value.castingLoopAnimationType = (CastingLoopAnimationType)0; ActionSpellData.Add(key, value); } controlActionSpell.Configure(value, actionKind, direction, holdInputValue); ((Behaviour)controlActionSpell).enabled = true; if (!spells.Contains((Spell)(object)controlActionSpell)) { spells.Add((Spell)(object)controlActionSpell); } } internal static void RegisterClientSpawnHandler() { //IL_0033: 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_0049: Expected O, but got Unknown //IL_0049: Expected O, but got Unknown if ((Object)(object)networkHandPrefab == (Object)null) { Plugin.Log.LogWarning((object)"Cannot register Control client spawn handler: hand prefab is not prepared."); return; } NetworkClient.UnregisterSpawnHandler(3229223441u); NetworkClient.RegisterSpawnHandler(3229223441u, new SpawnHandlerDelegate(SpawnClientHand), new UnSpawnDelegate(UnspawnClientHand)); Plugin.Log.LogInfo((object)$"Registered Control client spawn handler for asset ID {3229223441u}."); } private static GameObject SpawnClientHand(SpawnMessage message) { //IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Object.Instantiate<GameObject>(networkHandPrefab, message.position, message.rotation); obj.SetActive(true); return obj; } private static void UnspawnClientHand(GameObject instance) { if ((Object)(object)instance != (Object)null) { Object.Destroy((Object)(object)instance); } } internal static bool ShouldRunOriginalCastCommand(VoiceSpell voiceSpell, int index) { if (!(AllSpellsField.GetValue(voiceSpell) is List<Spell> list) || index < 0 || index >= list.Count || !(list[index] is ControlActionSpell controlActionSpell)) { return true; } if (controlActionSpell.IsHoldInputAction) { ((Component)voiceSpell).GetComponent<ControlInputRelay>()?.SetServerHold(controlActionSpell.HoldInputValue); Plugin.Log.LogDebug((object)$"Server received Control R state: {controlActionSpell.HoldInputValue}."); return false; } if (!(voiceSpell.NetworkcurrentSpell is ControlSpell controlSpell)) { return false; } if (controlSpell.TryApplyAction(controlActionSpell.ActionKind, controlActionSpell.Direction)) { voiceSpell.NetworkcurrentSpell = null; ((Spell)voiceSpell).NetworkisCasting = false; voiceSpell.StopPrimingAnimation(); } return false; } internal static bool ShouldRunOriginalStopCommand(VoiceSpell voiceSpell) { if (voiceSpell.NetworkcurrentSpell is ControlSpell) { Plugin.Log.LogDebug((object)"Ignored duplicate CONTROL voice-stop; R release owns Control cancellation."); return false; } return true; } } [HarmonyPatch(typeof(VoiceSpell), "UserCode_CmdCastSpellByIndex__Int32__Boolean")] internal static class ControlThrowCommandPatch { [HarmonyPrefix] private static bool Prefix(VoiceSpell __instance, int index) { return ControlBootstrap.ShouldRunOriginalCastCommand(__instance, index); } } [HarmonyPatch(typeof(VoiceSpell), "UserCode_CmdStopCurrentSpell")] internal static class ControlDuplicateVoiceStopPatch { [HarmonyPrefix] private static bool Prefix(VoiceSpell __instance) { return ControlBootstrap.ShouldRunOriginalStopCommand(__instance); } } [HarmonyPatch(typeof(NetworkPuppetWandProp), "SetSpellCasting")] internal static class ControlMouseIsolationPatch { [HarmonyPrefix] private static bool Prefix(NetworkPuppetWandProp __instance, bool wantsToCast) { if (NetworkServer.active) { Spell spell = __instance.Spell; VoiceSpell val = (VoiceSpell)(object)((spell is VoiceSpell) ? spell : null); if (val != null && val.NetworkcurrentSpell is ControlSpell) { __instance.NetworkisCastingSpell = wantsToCast; return false; } } return true; } } public sealed class ControlProjectileHand : BaseProjectile { private enum ControlState { Flying, Captured, Returning, Holding, Ending } private static readonly MethodInfo ReachRpc = AccessTools.Method(typeof(ProjectileHand), "RpcPlayReachAnimation", (Type[])null, (Type[])null); private static readonly MethodInfo GrabRpc = AccessTools.Method(typeof(ProjectileHand), "RpcPlayGrabAnimation", (Type[])null, (Type[])null); private static readonly MethodInfo PullRpc = AccessTools.Method(typeof(ProjectileHand), "RpcPlayPullAnimation", (Type[])null, (Type[])null); private static readonly MethodInfo ObstacleRpc = AccessTools.Method(typeof(ProjectileHand), "RpcPlayHitObstacleAnim", (Type[])null, (Type[])null); [SerializeField] private ProjectileHand visualBridge; [SerializeField] private Transform palmTransform; [SerializeField] private float rotationSpeed = 180f; [SerializeField] private float captureInputWindow = 5f; [SerializeField] private float returnSpeed = 8f; [SerializeField] private float holdStrength = 8f; [SerializeField] private float itemHoldDistance = 0.5f; [SerializeField] private float playerHoldDistance = 1f; [SerializeField] private float enemyHoldDistance = 2.5f; private ControlState state; private Rigidbody grabbedBody; private Pawn grabbedPawn; private NpcBehaviour grabbedNpc; private SpringJoint grabJoint; private GameObject anchorPoint; private Collider[] handColliders; private Collider[] grabbedColliders; private Collider casterCapsule; private Vector3 localGrabPoint; private float captureDeadline; private float nextPawnCorrectionTime; private float holdDistanceAdjustment; private float raisedHeight; private float slamUntil; private bool wasThrown; private bool npcNavigationDisabled; private bool ignoringCasterCollision; public bool HasGrabbedTarget { get { if ((Object)(object)grabbedBody != (Object)null) { if (state != ControlState.Captured && state != ControlState.Returning) { return state == ControlState.Holding; } return true; } return false; } } internal Rigidbody GrabbedBody => grabbedBody; internal NetworkIdentity ControlCaster => base.Caster; internal void Configure(ProjectileData data, SpellData ownerSpellData, GameplayTag ownerSpellTag, ProjectileHand bridge, Transform palm, float rotateSpeed, float configuredHoldStrength) { base.projectileData = data; base.spellData = ownerSpellData; base.spellTag = ownerSpellTag; visualBridge = bridge; palmTransform = palm; rotationSpeed = rotateSpeed; holdStrength = configuredHoldStrength; base.ttl = 5f; base.ignoreCaster = true; base.delayProcessObstacles = true; } public override void Initialize(NetworkIdentity caster, Spell ownerSpell) { ((BaseProjectile)this).Initialize(caster, ownerSpell); state = ControlState.Flying; handColliders = ((Component)this).GetComponents<Collider>(); } public override void Fire(Vector3 direction) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ((BaseProjectile)this).Fire(direction); if (((NetworkBehaviour)this).isServer) { state = ControlState.Flying; InvokeVisualRpc(ReachRpc); } } protected override void FixedUpdate() { //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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: 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_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_0188: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)this).isServer || state == ControlState.Ending || !base.hasBeenFired) { return; } if (state == ControlState.Flying) { ((BaseProjectile)this).FixedUpdate(); if (((BaseProjectile)this).Direction != Vector3.zero) { ((Component)this).transform.rotation = Quaternion.RotateTowards(((Component)this).transform.rotation, Quaternion.LookRotation(((BaseProjectile)this).Direction), rotationSpeed * Time.fixedDeltaTime); } return; } if ((Object)(object)grabbedBody == (Object)null) { DropAndDestroy(); return; } if (state == ControlState.Captured) { ((Component)this).transform.position = ((Component)grabbedBody).transform.TransformPoint(localGrabPoint); if (IsHoldInputActive()) { BeginReturn(); } else if (Time.time >= captureDeadline) { DropAndDestroy(); } return; } if (!IsHoldInputActive()) { DropAndDestroy(); return; } Vector3 aimDirection; Vector3 safePoint = GetSafePoint(out aimDirection); float num = ((Time.time < slamUntil) ? (returnSpeed * 2f) : returnSpeed); float num2 = Vector3.Distance(((Component)this).transform.position, safePoint); if (Time.time >= slamUntil) { num = Mathf.Lerp(1f, num, Mathf.Clamp01(num2 / 1.5f)); } ((Component)this).transform.position = Vector3.MoveTowards(((Component)this).transform.position, safePoint, num * Time.fixedDeltaTime); if (aimDirection != Vector3.zero) { ((Component)this).transform.rotation = Quaternion.LookRotation(aimDirection); } PullTargetToward(((Component)this).transform.position); bool flag = BrakeTargetAtSafePoint(safePoint, aimDirection); state = ((Vector3.Distance(((Component)this).transform.position, safePoint) <= 0.05f && flag) ? ControlState.Holding : ControlState.Returning); } protected override bool ShouldDestroyOnTargetHit() { return false; } protected override bool ShouldDestroyOnWallHit() { return false; } protected override void OnTriggerEnter(Collider other) { //IL_015a: 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) if (!((NetworkBehaviour)this).isServer || state != ControlState.Flying || !base.hasBeenFired || (Object)(object)base.projectileData == (Object)null || (other.isTrigger && !((Component)other).CompareTag("TriggerPhysical")) || ((Component)other).gameObject.CompareTag("IgnoreCollision") || ((Component)other).gameObject.CompareTag("EntityBlocker") || base.hasHit || Time.time - base.spawnTime < base.projectileData.spawnInvulnerability || ((Object)(object)base.Caster != (Object)null && ((Component)other).transform.IsChildOf(((Component)base.Caster).transform))) { return; } NetworkIdentity val = ((Component)other).GetComponent<NetworkIdentity>() ?? ((Component)other).GetComponentInParent<NetworkIdentity>(); Rigidbody attachedRigidbody = other.attachedRigidbody; int num = 1 << ((Component)other).gameObject.layer; if ((((LayerMask)(ref base.projectileData.wallLayer)).value & num) != 0 || (Object)(object)attachedRigidbody == (Object)null) { if (base.delayProcessObstacles) { base.hitObstacleFlag = true; base.hitObstacleFlagCollider = other; } else { ((BaseProjectile)this).OnWallHit(other); } } else if ((((LayerMask)(ref base.projectileData.targetLayer)).value & num) != 0) { ((BaseProjectile)this).OnTargetHit(other, attachedRigidbody, val); if (state == ControlState.Captured && (Object)(object)base.OwnerSpell != (Object)null) { base.OwnerSpell.RpcPlayEffect((SpellEffectType)3, ((Component)this).transform.position, ((Component)this).transform.rotation); } } } protected override void OnWallHit(Collider wall) { if (((NetworkBehaviour)this).isServer && state == ControlState.Flying) { ((BaseProjectile)this).OnWallHit(wall); state = ControlState.Ending; base.stopMoving = true; InvokeVisualRpc(ObstacleRpc); ((MonoBehaviour)this).StartCoroutine(DestroyAfterDelay()); } } protected override void OnTargetHit(Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity) { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_00ed: 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_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) if (!((NetworkBehaviour)this).isServer || state != ControlState.Flying || (Object)(object)targetRigidbody == (Object)null || (Object)(object)((Component)targetRigidbody).GetComponent<ProjectileHand>() != (Object)null || (Object)(object)((Component)targetRigidbody).GetComponent<ControlProjectileHand>() != (Object)null) { return; } UnstickTrigger val = default(UnstickTrigger); if (targetRigidbody.isKinematic && !((Component)targetRigidbody).TryGetComponent<UnstickTrigger>(ref val)) { ((BaseProjectile)this).OnWallHit(target); return; } grabbedBody = targetRigidbody; grabbedPawn = ((Component)targetRigidbody).GetComponent<Pawn>() ?? ((Component)targetRigidbody).GetComponentInParent<Pawn>() ?? (((Object)(object)targetIdentity == (Object)null) ? null : ((Component)targetIdentity).GetComponent<Pawn>()); grabbedNpc = ((Component)targetRigidbody).GetComponent<NpcBehaviour>() ?? ((Component)targetRigidbody).GetComponentInParent<NpcBehaviour>() ?? (((Object)(object)targetIdentity == (Object)null) ? null : ((Component)targetIdentity).GetComponent<NpcBehaviour>()); Transform val2 = (((Object)(object)palmTransform == (Object)null) ? ((Component)this).transform : palmTransform); Vector3 val3 = (target.isTrigger ? ((Component)target).transform.position : target.ClosestPoint(val2.position)); localGrabPoint = ((Component)grabbedBody).transform.InverseTransformPoint(val3); grabbedColliders = ((Component)grabbedBody).GetComponentsInChildren<Collider>(true); captureDeadline = Time.time + captureInputWindow; base.stopMoving = true; state = ControlState.Captured; SetHandCollidersEnabled(enabled: false); if ((Object)(object)targetIdentity != (Object)null) { HandleTargetTags(targetIdentity); } InvokeVisualRpc(GrabRpc); Plugin.Log.LogDebug((object)("Control captured " + GetTargetKind() + "; waiting for R until " + $"{captureDeadline:0.00}.")); if (IsHoldInputActive()) { BeginReturn(); } } private bool IsHoldInputActive() { if (base.OwnerSpell is ControlSpell controlSpell) { return controlSpell.HoldInputActive; } return false; } private void BeginReturn() { if (state == ControlState.Captured && !((Object)(object)grabbedBody == (Object)null)) { UnstickTrigger val = default(UnstickTrigger); if (((Component)grabbedBody).TryGetComponent<UnstickTrigger>(ref val)) { val.TryUnstick(base.Caster); } if ((Object)(object)grabbedPawn == (Object)null && (Object)(object)grabbedNpc == (Object)null) { CreateGrabJoint(); } SetCasterCollisionIgnored(ignore: true); if ((Object)(object)grabbedNpc != (Object)null && (Object)(object)grabbedNpc.npcToggler != (Object)null && grabbedNpc.npcToggler.NetworknavigationEnabled) { grabbedNpc.npcToggler.SvDisableNavigation(false); npcNavigationDisabled = true; } state = ControlState.Returning; InvokeVisualRpc(PullRpc); Plugin.Log.LogDebug((object)("Control returning " + GetTargetKind() + " to " + $"{GetSafeHoldDistance():0.0}m.")); } } private void PullTargetToward(Vector3 targetPoint) { //IL_000f: 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_0020: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0086: 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_0115: 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) if ((Object)(object)grabbedBody == (Object)null) { return; } Vector3 val = targetPoint - grabbedBody.worldCenterOfMass; if ((Object)(object)grabbedPawn != (Object)null) { if (Time.time >= nextPawnCorrectionTime) { nextPawnCorrectionTime = Time.time + 0.1f; Vector3 val2 = Vector3.ClampMagnitude(val * 2.5f, returnSpeed * 0.5f) - grabbedBody.linearVelocity; grabbedPawn.SvAddExternalImpulse(Vector3.ClampMagnitude(val2 * 0.5f, holdStrength * 0.5f)); } } else if ((Object)(object)grabbedNpc != (Object)null) { Vector3 val3 = Vector3.ClampMagnitude(val * 2.5f, returnSpeed * 0.5f); grabbedNpc.AddForce(val3 * Mathf.Max(1f, grabbedBody.mass)); } else if ((Object)(object)grabJoint == (Object)null && !grabbedBody.isKinematic) { grabbedBody.AddForce(val * holdStrength, (ForceMode)5); } } private bool BrakeTargetAtSafePoint(Vector3 safePoint, Vector3 aimDirection) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00c0: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: 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_00f5: 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_0134: 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_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_016c: 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_017b: 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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: 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_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019c: 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_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_021a: 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_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: 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_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)grabbedBody == (Object)null) { return false; } Vector3 val = ((Component)grabbedBody).transform.TransformPoint(localGrabPoint); Vector3 val2 = safePoint - val; if ((Object)(object)grabbedPawn != (Object)null || (Object)(object)grabbedNpc != (Object)null) { return ((Vector3)(ref val2)).sqrMagnitude <= 0.0625f; } if (grabbedBody.isKinematic) { return ((Vector3)(ref val2)).sqrMagnitude <= 0.0144f; } Vector3 val3 = ((((Vector3)(ref aimDirection)).sqrMagnitude < 0.001f) ? ((Component)this).transform.forward : ((Vector3)(ref aimDirection)).normalized); float num = 0f - Vector3.Dot(val - safePoint, val3); bool num2 = num > 0f; if (num2) { Rigidbody obj = grabbedBody; obj.position += val3 * (num + 0.01f); val = ((Component)grabbedBody).transform.TransformPoint(localGrabPoint); val2 = safePoint - val; } float magnitude = ((Vector3)(ref val2)).magnitude; float num3 = ((state == ControlState.Holding) ? 0.75f : Mathf.Clamp(magnitude * 2.5f, 0.75f, returnSpeed * 0.75f)); Vector3 val4 = Vector3.ClampMagnitude(val2 * 4f, num3); float num4 = Mathf.Lerp(30f, 12f, Mathf.Clamp01(magnitude / 2f)); Vector3 val5 = Vector3.MoveTowards(grabbedBody.linearVelocity, val4, num4 * Time.fixedDeltaTime); float num5 = Vector3.Dot(val5, val3); if (num2 && num5 < 0f) { val5 -= val3 * num5; } else if (magnitude <= 0.35f) { float num6 = Mathf.Max(0.15f, magnitude * 2f); if (num5 < 0f - num6) { val5 += val3 * (0f - num6 - num5); } } grabbedBody.linearVelocity = val5; if (magnitude <= 0.35f) { grabbedBody.angularVelocity = Vector3.MoveTowards(grabbedBody.angularVelocity, Vector3.zero, 12f * Time.fixedDeltaTime); } int num7; if (magnitude <= 0.12f) { Vector3 linearVelocity = grabbedBody.linearVelocity; num7 = ((((Vector3)(ref linearVelocity)).sqrMagnitude <= 0.5625f) ? 1 : 0); if (num7 != 0) { grabbedBody.linearVelocity = Vector3.zero; } } else { num7 = 0; } return (byte)num7 != 0; } private Vector3 GetSafePoint(out Vector3 aimDirection) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_00a6: 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) //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_0076: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_00f4: 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_00fe: 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) Pawn val = (((Object)(object)base.Caster == (Object)null) ? null : ((Component)base.Caster).GetComponent<Pawn>()); if ((Object)(object)val != (Object)null) { aimDirection = val.Blackboard.AimDirection; if (aimDirection == Vector3.zero) { aimDirection = ((Component)val).transform.forward; } return val.LookOrigin + ((Vector3)(ref aimDirection)).normalized * GetSafeHoldDistance() + Vector3.up * GetVerticalOffset(); } aimDirection = (((Object)(object)base.Caster == (Object)null) ? ((Component)this).transform.forward : ((Component)base.Caster).transform.forward); return (((Object)(object)base.Caster == (Object)null) ? ((Component)this).transform.position : ((Component)base.Caster).transform.position) + ((Vector3)(ref aimDirection)).normalized * GetSafeHoldDistance() + Vector3.up * GetVerticalOffset(); } private float GetSafeHoldDistance() { float num = (((Object)(object)grabbedNpc != (Object)null) ? enemyHoldDistance : ((!((Object)(object)grabbedPawn != (Object)null)) ? itemHoldDistance : playerHoldDistance)); return Mathf.Max(GetMinimumHoldDistance(), num + holdDistanceAdjustment); } private float GetMinimumHoldDistance() { if ((Object)(object)grabbedNpc != (Object)null) { return 1f; } if ((Object)(object)grabbedPawn != (Object)null) { return 0.5f; } return 0.25f; } private float GetVerticalOffset() { return raisedHeight + ((Time.time < slamUntil) ? (-3f) : 0f); } private string GetTargetKind() { if ((Object)(object)grabbedNpc != (Object)null) { return "enemy"; } if ((Object)(object)grabbedPawn != (Object)null) { return "player"; } return "item"; } private void CreateGrabJoint() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)grabbedBody == (Object)null) && !grabbedBody.isKinematic && !((Object)(object)grabJoint != (Object)null)) { Transform val = (((Object)(object)palmTransform == (Object)null) ? ((Component)this).transform : palmTransform); anchorPoint = new GameObject("ControlAnchor"); anchorPoint.transform.SetParent(val, false); Rigidbody val2 = anchorPoint.AddComponent<Rigidbody>(); val2.isKinematic = true; val2.useGravity = false; grabJoint = ((Component)grabbedBody).gameObject.AddComponent<SpringJoint>(); ((Joint)grabJoint).connectedBody = val2; ((Joint)grabJoint).anchor = localGrabPoint; ((Joint)grabJoint).connectedAnchor = Vector3.zero; grabJoint.spring = 300f; grabJoint.damper = Mathf.Clamp(2f * Mathf.Sqrt(grabJoint.spring * grabbedBody.mass), 35f, 120f); grabJoint.maxDistance = 0f; ((Joint)grabJoint).autoConfigureConnectedAnchor = false; } } private void SetCasterCollisionIgnored(bool ignore) { if (ignoringCasterCollision == ignore) { return; } if ((Object)(object)casterCapsule == (Object)null && (Object)(object)base.Caster != (Object)null) { Pawn component = ((Component)base.Caster).GetComponent<Pawn>(); casterCapsule = (Collider)(object)(((Object)(object)component == (Object)null) ? null : component.CapsuleCollider); } if ((Object)(object)casterCapsule == (Object)null || grabbedColliders == null) { return; } Collider[] array = grabbedColliders; foreach (Collider val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)casterCapsule) { Physics.IgnoreCollision(casterCapsule, val, ignore); } } ignoringCasterCollision = ignore; } private void DestroyGrabJoint() { if ((Object)(object)grabJoint != (Object)null) { Object.Destroy((Object)(object)grabJoint); grabJoint = null; } if ((Object)(object)anchorPoint != (Object)null) { Object.Destroy((Object)(object)anchorPoint); anchorPoint = null; } } private void SetHandCollidersEnabled(bool enabled) { if (handColliders == null) { return; } Collider[] array = handColliders; foreach (Collider val in array) { if ((Object)(object)val != (Object)null) { val.enabled = enabled; } } } [Server] public void DropAndDestroy() { if (NetworkServer.active && state != ControlState.Ending) { state = ControlState.Ending; DestroyGrabJoint(); ClearTargetReferences(); NetworkServer.Destroy(((Component)this).gameObject); } } [Server] internal void MoveCloser() { if (NetworkServer.active && HasGrabbedTarget) { holdDistanceAdjustment -= 0.5f; state = ControlState.Returning; Plugin.Log.LogDebug((object)$"Control CLOSER: {GetSafeHoldDistance():0.00}m."); } } [Server] internal void Raise() { if (NetworkServer.active && HasGrabbedTarget) { raisedHeight = Mathf.Min(4f, raisedHeight + 1f); state = ControlState.Returning; Plugin.Log.LogDebug((object)$"Control RAISE: vertical offset {raisedHeight:0.00}m."); } } [Server] internal void SlamDown(float force) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active && HasGrabbedTarget) { slamUntil = Time.time + 0.5f; state = ControlState.Returning; ApplyActionImpulse(Vector3.down, force); Plugin.Log.LogDebug((object)"Control SLAM DOWN."); } } [Server] internal void ThrowAndDestroy(float force, ControlDirection controlDirection) { //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_0051: 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_0069: 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_0086: 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) if (NetworkServer.active && !((Object)(object)grabbedBody == (Object)null)) { Vector3 throwDirection = GetThrowDirection(controlDirection); Rigidbody val = grabbedBody; Pawn val2 = grabbedPawn; NpcBehaviour val3 = grabbedNpc; wasThrown = true; state = ControlState.Ending; DestroyGrabJoint(); if ((Object)(object)val2 != (Object)null) { val2.SvAddExternalImpulse(throwDirection * force); } else if ((Object)(object)val3 != (Object)null) { val3.AddForce(throwDirection * (force * 2f)); } else if (!val.isKinematic) { val.AddForce(throwDirection * force, (ForceMode)2); } ClearTargetReferences(); NetworkServer.Destroy(((Component)this).gameObject); } } private void ApplyActionImpulse(Vector3 direction, float force) { //IL_0002: 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) //IL_001d: 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) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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) direction = ((Vector3)(ref direction)).normalized; if ((Object)(object)grabbedPawn != (Object)null) { grabbedPawn.SvAddExternalImpulse(direction * force); } else if ((Object)(object)grabbedNpc != (Object)null) { grabbedNpc.AddForce(direction * (force * 2f)); } else if ((Object)(object)grabbedBody != (Object)null && !grabbedBody.isKinematic) { grabbedBody.AddForce(direction * force, (ForceMode)2); } } private Vector3 GetThrowDirection(ControlDirection direction) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00cf: 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_00e3: 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_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_00f7: 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_0102: 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_010b: 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_0117: 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_011f: 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_0126: 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_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0146: 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_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0154: 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) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: 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_0166: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) GetSafePoint(out var aimDirection); aimDirection = ((aimDirection == Vector3.zero) ? ((Component)this).transform.forward : ((Vector3)(ref aimDirection)).normalized); Vector3 val = Vector3.Cross(Vector3.up, aimDirection); if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = (((Object)(object)base.Caster == (Object)null) ? ((Component)this).transform.right : ((Component)base.Caster).transform.right); } ((Vector3)(ref val)).Normalize(); Vector3 val2; switch (direction) { case ControlDirection.Back: return -aimDirection; case ControlDirection.Left: return -val; case ControlDirection.Right: return val; case ControlDirection.Up: return Vector3.up; case ControlDirection.Down: return Vector3.down; case ControlDirection.UpLeft: val2 = Vector3.up - val; return ((Vector3)(ref val2)).normalized; case ControlDirection.UpRight: val2 = Vector3.up + val; return ((Vector3)(ref val2)).normalized; case ControlDirection.DownLeft: val2 = Vector3.down - val; return ((Vector3)(ref val2)).normalized; case ControlDirection.DownRight: val2 = Vector3.down + val; return ((Vector3)(ref val2)).normalized; case ControlDirection.ForwardLeft: val2 = aimDirection - val; return ((Vector3)(ref val2)).normalized; case ControlDirection.ForwardRight: val2 = aimDirection + val; return ((Vector3)(ref val2)).normalized; case ControlDirection.BackLeft: val2 = -aimDirection - val; return ((Vector3)(ref val2)).normalized; case ControlDirection.BackRight: val2 = -aimDirection + val; return ((Vector3)(ref val2)).normalized; default: return aimDirection; } } private void ClearTargetReferences() { SetCasterCollisionIgnored(ignore: false); grabbedBody = null; grabbedPawn = null; grabbedNpc = null; grabbedColliders = null; casterCapsule = null; npcNavigationDisabled = false; } private void HandleTargetTags(NetworkIdentity targetIdentity) { NpcBehaviour val = default(NpcBehaviour); if ((Object)(object)base.Caster != (Object)null && ((Component)targetIdentity).TryGetComponent<NpcBehaviour>(ref val)) { val.OnAggro(base.Caster); } TaggableObject val2 = default(TaggableObject); if (((Component)targetIdentity).TryGetComponent<TaggableObject>(ref val2)) { val2.AddTag(TagReferences.MovedTag); if ((Object)(object)base.spellTag != (Object)null) { val2.AddTag(base.spellTag); } } ValuableObject val3 = default(ValuableObject); if ((Object)(object)base.Caster != (Object)null && ((Component)targetIdentity).TryGetComponent<ValuableObject>(ref val3)) { val3.SetAndPropagateRecentInteractor(base.Caster.netId); } } private IEnumerator DestroyAfterDelay() { yield return (object)new WaitForSeconds(1f); if (NetworkServer.active) { NetworkServer.Destroy(((Component)this).gameObject); } } private void InvokeVisualRpc(MethodInfo method) { if ((Object)(object)visualBridge == (Object)null || method == null) { return; } try { method.Invoke(visualBridge, null); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Control hand visual RPC failed (" + method.Name + "): " + ex.GetBaseException().Message)); } } private void OnDestroy() { SetCasterCollisionIgnored(ignore: false); DestroyGrabJoint(); if (!wasThrown && npcNavigationDisabled) { npcNavigationDisabled = false; } } } public sealed class ControlSpell : SpawnableObjectSpell<ControlProjectileHand> { private bool hasSpawnedHand; private bool holdInputActive; public override bool IsInstantCast => false; internal bool HoldInputActive => holdInputActive; internal void Configure(SpellData data) { ((Spell)this).spellData = data; } public override void OnSpellActivate() { hasSpawnedHand = false; ControlInputRelay component = ((Component)this).GetComponent<ControlInputRelay>(); holdInputActive = (Object)(object)component != (Object)null && component.ServerHoldActive; Plugin.Log.LogDebug((object)$"Control activated on server; R held: {holdInputActive}."); base.OnSpellActivate(); } [Server] internal void SetHoldInput(bool active) { if (NetworkServer.active) { holdInputActive = active; } } [Server] protected override void SpawnSingleObject(Vector3 position, Quaternion rotation) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { Debug.LogWarning((object)"[ControlSpell] Spawn attempted while the server was inactive."); return; } if ((Object)(object)((Spell)this).spellData == (Object)null || (Object)(object)((Spell)this).spellData.objectToSpawnPrefab == (Object)null) { Debug.LogError((object)"[ControlSpell] Runtime SpellData or hand prefab is missing."); ((Spell)this).StopSpell(); return; } GameObject val = Object.Instantiate<GameObject>(((Spell)this).spellData.objectToSpawnPrefab, position, rotation); val.SetActive(true); ControlProjectileHand component = val.GetComponent<ControlProjectileHand>(); if ((Object)(object)component == (Object)null) { Debug.LogError((object)"[ControlSpell] Spawned prefab has no ControlProjectileHand."); Object.Destroy((Object)(object)val); ((Spell)this).StopSpell(); return; } NetworkServer.Spawn(val, (NetworkConnectionToClient)null); ((BaseProjectile)component).Initialize(((Spell)this).NetworkcasterIdentity, (Spell)(object)this); base.activeSpawnedObjects.Add(component); hasSpawnedHand = true; ((SpawnableObjectSpell<ControlProjectileHand>)this).OnObjectInitialized(component); ((Spell)this).RpcPlayEffect((SpellEffectType)1, position, rotation); Plugin.Log.LogDebug((object)$"Control hand spawned; R held: {holdInputActive}."); } [Server] internal bool TryApplyAction(ControlActionKind actionKind, ControlDirection direction) { if (!NetworkServer.active || !holdInputActive || (Object)(object)base.activeSpawnedObject == (Object)null || !base.activeSpawnedObject.HasGrabbedTarget) { return false; } ControlProjectileHand activeSpawnedObject = base.activeSpawnedObject; switch (actionKind) { case ControlActionKind.Closer: activeSpawnedObject.MoveCloser(); return false; case ControlActionKind.Raise: activeSpawnedObject.Raise(); return false; case ControlActionKind.SlamDown: activeSpawnedObject.SlamDown(Plugin.ControlThrowForce); return false; case ControlActionKind.Throw: activeSpawnedObject.ThrowAndDestroy(Plugin.ControlThrowForce, direction); base.activeSpawnedObjects.Clear(); ((Spell)this).StopSpell(); return true; default: return false; } } [Server] public override void OnSpellDeactivate() { if (!NetworkServer.active) { Debug.LogWarning((object)"[ControlSpell] Deactivation attempted while the server was inactive."); return; } ((MonoBehaviour)this).StopAllCoroutines(); ControlProjectileHand activeSpawnedObject = base.activeSpawnedObject; if ((Object)(object)activeSpawnedObject != (Object)null) { activeSpawnedObject.DropAndDestroy(); } base.activeSpawnedObjects.Clear(); hasSpawnedHand = false; holdInputActive = false; Plugin.Log.LogDebug((object)"Control deactivated on server."); base.OnSpellDeactivate(); } public override void Update() { ((Spell)this).Update(); if (((NetworkBehaviour)this).isServer && ((Spell)this).isCasting && hasSpawnedHand && (Object)(object)base.activeSpawnedObject == (Object)null) { ((Spell)this).StopSpell(); VoiceSpell component = ((Component)this).GetComponent<VoiceSpell>(); if ((Object)(object)component != (Object)null && (Object)(object)component.NetworkcurrentSpell == (Object)(object)this) { component.NetworkcurrentSpell = null; ((Spell)component).NetworkisCasting = false; component.StopPrimingAnimation(); } } } } public sealed class FireBallProjectile : BaseProjectile { [SerializeField] private GameObject explosionVfxPrefab; [SerializeField] private NetworkIdentity explosionPrefab; [SerializeField] private EventReference explosionSfx; private bool hasExploded; internal void Configure(ProjectileData data, SpellData ownerSpellData, GameObject igniteBoomExplosionVfx, NetworkIdentity igniteBoomExplosionPrefab, EventReference igniteBoomExplosionSfx, float lifetime) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) base.projectileData = data; base.spellData = ownerSpellData; explosionVfxPrefab = igniteBoomExplosionVfx; explosionPrefab = igniteBoomExplosionPrefab; explosionSfx = igniteBoomExplosionSfx; base.ttl = lifetime; base.ignoreCaster = true; base.delayProcessObstacles = true; } protected override void OnTargetHit(Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity) { if (((NetworkBehaviour)this).isServer && !hasExploded) { TriggerIgniteBoomExplosion(); } } protected override void OnWallHit(Collider wall) { if (((NetworkBehaviour)this).isServer && !hasExploded) { TriggerIgniteBoomExplosion(); } ((BaseProjectile)this).OnWallHit(wall); } [Server] private void TriggerIgniteBoomExplosion() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || hasExploded) { return; } hasExploded = true; Vector3 position = ((Component)this).transform.position; Quaternion rotation = ((Component)this).transform.rotation; if ((Object)(object)explosionVfxPrefab != (Object)null && (Object)(object)VfxManager.Instance != (Object)null) { int vfxId = VfxManager.Instance.GetVfxId(explosionVfxPrefab); if (vfxId != -1) { GameManager.Instance.RpcSpawnVfx(vfxId, position); } } AudioManager val = default(AudioManager); if (!((EventReference)(ref explosionSfx)).IsNull && Service.Get<AudioManager>(ref val)) { int eventId = val.GetEventId(explosionSfx); if (eventId != -1) { GameManager.Instance.RpcPlaySfxEvent(eventId, position); } } if ((Object)(object)explosionPrefab != (Object)null) { GameManager.SpawnNetworkPrefab(explosionPrefab, position, rotation, true); } } } public sealed class FireBallSpell : SpawnableObjectSpell<BaseProjectile> { internal void Configure(SpellData data) { ((Spell)this).spellData = data; } [Server] protected override void SpawnSingleObject(Vector3 position, Quaternion rotation) { //IL_0049: 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_00a2: 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) if (!NetworkServer.active) { Debug.LogWarning((object)"[FireBallSpell] Spawn attempted while the server was inactive."); return; } if ((Object)(object)((Spell)this).spellData == (Object)null || (Object)(object)((Spell)this).spellData.objectToSpawnPrefab == (Object)null) { Debug.LogError((object)"[FireBallSpell] Runtime SpellData or projectile prefab is missing."); return; } GameObject val = Object.Instantiate<GameObject>(((Spell)this).spellData.objectToSpawnPrefab, position, rotation); val.SetActive(true); BaseProjectile component = val.GetComponent<BaseProjectile>(); if ((Object)(object)component == (Object)null) { Debug.LogError((object)"[FireBallSpell] Spawned prefab has no BaseProjectile."); Object.Destroy((Object)(object)val); return; } NetworkServer.Spawn(val, (NetworkConnectionToClient)null); component.Initialize(((Spell)this).NetworkcasterIdentity, (Spell)(object)this); base.activeSpawnedObjects.Add(component); ((SpawnableObjectSpell<BaseProjectile>)this).OnObjectInitialized(component); ((Spell)this).RpcPlayEffect((SpellEffectType)1, position, rotation); } } [BepInPlugin("Hero_brian124.Herobrian_spells", "Herobrian_spells", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "Hero_brian124.Herobrian_spells"; public const string PluginName = "Herobrian_spells"; public const string PluginVersion = "1.0.0"; public const string VoiceCommandKey = "MOD_SPELL_FIR_FIRE_BALL"; public const string ControlVoiceCommandKey = "MOD_SPELL_ARC_CONTROL"; public const string VomitVoiceCommandKey = "MOD_SPELL_GRO_VOMIT"; public const string ZawardoVoiceCommandKey = "MOD_SPELL_BAS_ZAWARDO"; internal const uint ProjectileAssetId = 4051612689u; internal const uint ControlHandAssetId = 3229223441u; internal const uint VomitStreamAssetId = 2963347217u; private Harmony _harmony; internal static ManualLogSource Log { get; private set; } internal static string[] PhraseTokens { get; private set; } = new string[2] { "FIRE", "BALL" }; internal static string[] ControlPhraseTokens { get; private set; } = new string[1] { "CONTROL" }; internal static string[] VomitPhraseTokens { get; private set; } = new string[1] { "VOMIT" }; internal static string[] ZawardoPhraseTokens { get; private set; } = new string[2] { "THE", "WORLD" }; internal static float ProjectileSpeed { get; private set; } internal static float ProjectileRange { get; private set; } internal static float ProjectileLifetime { get; private set; } internal static float Cooldown { get; private set; } internal static int Charges { get; private set; } internal static float ChargeRegenSeconds { get; private set; } internal static float ControlHoldStrength { get; private set; } internal static float ControlThrowForce { get; private set; } internal static Key ControlHoldKey { get; private set; } = (Key)32; private void Awake() { //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Voice", "Phrase", "FIRE BALL", "Words spoken to cast the spell. Restart the game after changing this."); ConfigEntry<float> val2 = ((BaseUnityPlugin)this).Config.Bind<float>("Projectile", "Speed", 15f, "Projectile speed."); ConfigEntry<float> val3 = ((BaseUnityPlugin)this).Config.Bind<float>("Projectile", "Range", 30f, "Maximum travel distance."); ConfigEntry<float> val4 = ((BaseUnityPlugin)this).Config.Bind<float>("Projectile", "Lifetime", 5f, "Maximum projectile lifetime."); ConfigEntry<float> val5 = ((BaseUnityPlugin)this).Config.Bind<float>("Spell", "Cooldown", 1f, "Cooldown after casting."); ConfigEntry<int> val6 = ((BaseUnityPlugin)this).Config.Bind<int>("Spell", "Charges", 3, "Maximum charges."); ConfigEntry<float> val7 = ((BaseUnityPlugin)this).Config.Bind<float>("Spell", "ChargeRegenSeconds", 8f, "Seconds to regenerate one charge."); ConfigEntry<string> obj = ((BaseUnityPlugin)this).Config.Bind<string>("Control Voice", "ControlPhrase", "CONTROL", "Words spoken to start Control. Restart after changing this."); ConfigEntry<string> val8 = ((BaseUnityPlugin)this).Config.Bind<string>("Vomit Voice", "VomitPhrase", "VOMIT", "Words spoken to cast Vomit Spell. Restart after changing this."); ConfigEntry<string> val9 = ((BaseUnityPlugin)this).Config.Bind<string>("The World Voice", "TheWorldPhrase", "THE WORLD", "Words spoken to cast The World. Restart after changing this."); ConfigEntry<float> val10 = ((BaseUnityPlugin)this).Config.Bind<float>("Control", "HoldStrength", 8f, "Correction strength used to keep players, NPCs, and props held."); ConfigEntry<float> val11 = ((BaseUnityPlugin)this).Config.Bind<float>("Control", "ThrowForce", 30f, "Force applied when the caster says THROW."); ConfigEntry<Key> val12 = ((BaseUnityPlugin)this).Config.Bind<Key>("Control", "HoldKey", (Key)32, "Keyboard key held to keep the Control hand attached."); PhraseTokens = NormalizePhrase(val.Value); ControlPhraseTokens = NormalizePhrase(obj.Value, "CONTROL"); VomitPhraseTokens = NormalizePhrase(val8.Value, "VOMIT"); ZawardoPhraseTokens = NormalizePhrase(val9.Value, "THE", "WORLD"); ProjectileSpeed = Math.Max(1f, val2.Value); ProjectileRange = Math.Max(1f, val3.Value); ProjectileLifetime = Math.Max(0.5f, val4.Value); Cooldown = Math.Max(0f, val5.Value); Charges = Math.Max(1, val6.Value); ChargeRegenSeconds = Math.Max(0.1f, val7.Value); ControlHoldStrength = Math.Max(1f, val10.Value); ControlThrowForce = Math.Max(1f, val11.Value); ControlHoldKey = (Key)(((int)val12.Value == 0) ? 32 : ((int)val12.Value)); _harmony = new Harmony("Hero_brian124.Herobrian_spells"); _harmony.PatchAll(typeof(Plugin).Assembly); ((Component)this).gameObject.AddComponent<ZawardoClientController>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded Herobrian_spells 1.0.0; Fire Ball: " + string.Join(" ", PhraseTokens) + "; Control: " + string.Join(" ", ControlPhraseTokens) + "; Vomit Spell: " + string.Join(" ", VomitPhraseTokens) + "; The World: " + string.Join(" ", ZawardoPhraseTokens) + "; " + $"{ControlActionCatalog.VoiceActions.Length} Control voice actions")); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private static string[] NormalizePhrase(string phrase, params string[] fallback) { string[] array = (from token in (phrase ?? string.Empty).Split(new char[3] { ' ', '-', '\t' }, StringSplitOptions.RemoveEmptyEntries) select token.Trim().ToUpperInvariant() into token where token.Length > 0 select token).ToArray(); if (array.Length == 0) { if (fallback.Length != 0) { return fallback; } return new string[2] { "FIRE", "BALL" }; } return array; } internal static IEnumerable<KeyValuePair<string, string[]>> GetVoiceCommands() { yield return new KeyValuePair<string, string[]>("MOD_SPELL_FIR_FIRE_BALL", PhraseTokens); yield return new KeyValuePair<string, string[]>("MOD_SPELL_ARC_CONTROL", ControlPhraseTokens); yield return new KeyValuePair<string, string[]>("MOD_SPELL_GRO_VOMIT", VomitPhraseTokens); yield return new KeyValuePair<string, string[]>("MOD_SPELL_BAS_ZAWARDO", ZawardoPhraseTokens); foreach (KeyValuePair<string, string[]> voiceCommand in ControlActionCatalog.GetVoiceCommands()) { yield return voiceCommand; } } internal static bool TryGetVoiceCommand(string key, out string[] tokens) { foreach (KeyValuePair<string, string[]> voiceCommand in GetVoiceCommands()) { if (string.Equals(key, voiceCommand.Key, StringComparison.Ordinal)) { tokens = voiceCommand.Value; return true; } } tokens = null; return false; } } internal static class FireBallBootstrap { private static readonly FieldInfo VoiceSpellsField = AccessTools.Field(typeof(VoiceSpell), "spells"); private static readonly FieldInfo MinePrefabField = AccessTools.Field(typeof(MineSpell), "minePrefab"); private static readonly FieldInfo MineSpawnSfxField = AccessTools.Field(typeof(MineTrigger), "spawnSfx"); private static readonly FieldInfo MineExplosionSfxField = AccessTools.Field(typeof(MineTrigger), "explosionSfx"); private static readonly FieldInfo NetworkAssetIdField = AccessTools.Field(typeof(NetworkIdentity), "_assetId"); private static readonly FieldInfo NetworkHasSpawnedField = AccessTools.Field(typeof(NetworkIdentity), "hasSpawned"); private static GameObject _networkProjectilePrefab; private static SpellData _spellData; private static ProjectileData _projectileData; private static EventReference _igniteBoomSpawnSfx; private static EventReference _igniteBoomExplosionSfx; internal static void Install(YapNetworkManager manager) { if ((Object)(object)manager == (Object)null) { return; } GameObject val = FindPrefab(manager, "PropWandOfFire"); GameObject val2 = FindPrefab(manager, "Fireball"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)"Fire Ball was not installed: PropWandOfFire or Fireball was not found in YapNetworkManager.spawnPrefabs."); return; } NetworkIdentity val3 = default(NetworkIdentity); if (((NetworkManager)manager).spawnPrefabs.Any((GameObject prefab) => (Object)(object)prefab != (Object)null && prefab.TryGetComponent<NetworkIdentity>(ref val3) && val3.assetId == 4051612689u)) { Plugin.Log.LogError((object)$"Fire Ball asset ID collision: {4051612689u}. The mod will not install."); return; } VoiceSpell component = val.GetComponent<VoiceSpell>(); LaunchSelfSpell component2 = val.GetComponent<LaunchSelfSpell>(); MineSpell component3 = val.GetComponent<MineSpell>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { Plugin.Log.LogError((object)"Fire Ball was not installed: the Fire Wand is missing VoiceSpell, LaunchSelfSpell, or MineSpell."); return; } EnsureRuntimeData(manager, component2, component3); EnsureProjectilePrefab(val2, component3); EnsureSpellOnWand(val, component); } private static GameObject FindPrefab(YapNetworkManager manager, string name) { return ((IEnumerable<GameObject>)((NetworkManager)manager).spawnPrefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject prefab) => (Object)(object)prefab != (Object)null && string.Equals(((Object)prefab).name, name, StringComparison.Ordinal))); } private static void EnsureRuntimeData(YapNetworkManager manager, LaunchSelfSpell launchSelfSpell, MineSpell mineSpell) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_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_00fd: Unknown result type (might be due to invalid IL or missing references) ReadIgniteBoomAudio(mineSpell); if ((Object)(object)_spellData == (Object)null) { _spellData = Object.Instantiate<SpellData>(((Spell)launchSelfSpell).SpellData); ((Object)_spellData).name = "SD_FIR_FIRE_BALL_MOD"; _spellData.spellName = "FIRE BALL"; _spellData.voiceCommandKey = "MOD_SPELL_FIR_FIRE_BALL"; _spellData.cooldown = Plugin.Cooldown; _spellData.charges = Plugin.Charges; _spellData.chargePerCast = 1; _spellData.chargeCostPerSecondCast = 0; _spellData.chargeRegenInterval = Plugin.ChargeRegenSeconds; _spellData.chargesRegenPerInterval = 1; _spellData.chargeRegenDelay = 0.5f; _spellData.spawnLocation = (SpawnLocation)1; _spellData.spawnOffset = Vector3.zero; _spellData.applyLookTransform = true; _spellData.spawnDelay = 0.1f; _spellData.castEvent = _igniteBoomSpawnSfx; _spellData.impactEvent = default(EventReference); _spellData.impactVFXPrefab = null; } if (!((Object)(object)_projectileData == (Object)null)) { return; } BaseProjectile val = (from prefab in ((NetworkManager)manager).spawnPrefabs where (Object)(object)prefab != (Object)null select prefab.GetComponent<BaseProjectile>()).FirstOrDefault((Func<BaseProjectile, bool>)((BaseProjectile projectile) => (Object)(object)projectile != (Object)null && (Object)(object)projectile.ProjectileData != (Object)null && projectile is ProjectileTornado)); if ((Object)(object)val == (Object)null) { val = (from prefab in ((NetworkManager)manager).spawnPrefabs where (Object)(object)prefab != (Object)null select prefab.GetComponent<BaseProjectile>()).FirstOrDefault((Func<BaseProjectile, bool>)((BaseProjectile projectile) => (Object)(object)projectile != (Object)null && (Object)(object)projectile.ProjectileData != (Object)null && ((LayerMask)(ref projectile.ProjectileData.wallLayer)).value != 0)); } if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("No vanilla projectile with a wall collision profile was found."); } _projectileData = Object.Instantiate<ProjectileData>(val.ProjectileData); ((Object)_projectileData).name = "PD_FIR_FIRE_BALL_MOD"; _projectileData.speed = Plugin.ProjectileSpeed; _projectileData.gravity = 0f; _projectileData.maxTravelDistance = Plugin.ProjectileRange; _projectileData.spawnInvulnerability = 0.15f; _projectileData.enablePiercing = false; _projectileData.maxPierceCount = 0; _projectileData.projectileCount = 1; _projectileData.maxProjectileCount = 0; _projectileData.spreadAngle = 0f; _projectileData.useRandomSpread = false; _projectileData.verticalDegreeRandomness = 0f; _projectileData.projectileFireDelay = 0f; _projectileData.chanceForMultiShot = 0f; } private static void ReadIgniteBoomAudio(MineSpell mineSpell) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) object? value = MinePrefabField.GetValue(mineSpell); NetworkIdentity val = (NetworkIdentity)((value is NetworkIdentity) ? value : null); MineTrigger val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<MineTrigger>()); if ((Object)(object)val2 == (Object)null) { throw new InvalidOperationException("Ignite Boom's mine prefab or MineTrigger could not be resolved."); } _igniteBoomSpawnSfx = (EventReference)MineSpawnSfxField.GetValue(val2); _igniteBoomExplosionSfx = (EventReference)MineExplosionSfxField.GetValue(val2); if (((EventReference)(ref _igniteBoomSpawnSfx)).IsNull || ((EventReference)(ref _igniteBoomExplosionSfx)).IsNull) { throw new InvalidOperationException("Ignite Boom's spawn or explosion FMOD event is empty."); } } private static void EnsureProjectilePrefab(GameObject vanillaFireballPrefab, MineSpell mineSpell) { //IL_00e2: 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) if ((Object)(object)_networkProjectilePrefab != (Object)null) { _spellData.objectToSpawnPrefab = _networkProjectilePrefab; return; } bool activeSelf = vanillaFireballPrefab.activeSelf; try { vanillaFireballPrefab.SetActive(false); _networkProjectilePrefab = Object.Instantiate<GameObject>(vanillaFireballPrefab); } finally { vanillaFireballPrefab.SetActive(activeSelf); } ((Object)_networkProjectilePrefab).name = "FireBallModProjectile"; _networkProjectilePrefab.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_networkProjectilePrefab); NetworkIdentity component = _networkProjectilePrefab.GetComponent<NetworkIdentity>(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("The cloned Fireball prefab has no NetworkIdentity."); } NetworkAssetIdField.SetValue(component, 4051612689u); NetworkHasSpawnedField.SetValue(component, false); component.sceneId = 0uL; NetworkBehaviour[] components = _networkProjectilePrefab.GetComponents<NetworkBehaviour>(); foreach (NetworkBehaviour val in components) { if (((object)val).GetType().Name.IndexOf("NetworkTransform", StringComparison.Ordinal) >= 0) { val.syncDirection = (SyncDirection)0; } } Rigidbody[] componentsInChildren = _networkProjectilePrefab.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody obj in componentsInChildren) { obj.useGravity = false; obj.isKinematic = true; obj.detectCollisions = true; } Collider[] componentsInChildren2 = _networkProjectilePrefab.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].isTrigger = true; } DisableIfPresent<Interactable>(_networkProjectilePrefab); DisableIfPresent<NetworkPhysicsPropDestroy>(_networkProjectilePrefab); DisableIfPresent<RigidbodyConfig>(_networkProjectilePrefab); (_networkProjectilePrefab.GetComponent<FireBallProjectile>() ?? _networkProjectilePrefab.AddComponent<FireBallProjectile>()).Configure(_projectileData, _spellData, mineSpell.ExplosionVfxPrefab, mineSpell.ExplosionPrefab, _igniteBoomExplosionSfx, Plugin.ProjectileLifetime); _spellData.objectToSpawnPrefab = _networkProjectilePrefab; Plugin.Log.LogInfo((object)$"Prepared Fire Ball projectile prefab with asset ID {4051612689u}."); } private static void DisableIfPresent<T>(GameObject gameObject) where T : Behaviour { T component = gameObject.GetComponent<T>(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } } private static void EnsureSpellOnWand(GameObject fireWandPrefab, VoiceSpell voiceSpell) { FireBallSpell fireBallSpell = fireWandPrefab.GetComponent<FireBallSpell>() ?? fireWandPrefab.AddComponent<FireBallSpell>(); fireBallSpell.Configure(_spellData); ((Behaviour)fireBallSpell).enabled = true; Spell[] array = (VoiceSpellsField.GetValue(voiceSpell) as Spell[]) ?? Array.Empty<Spell>(); if (!array.Contains((Spell)(object)fireBallSpell)) { VoiceSpellsField.SetValue(voiceSpell, array.Concat((IEnumerable<Spell>)(object)new Spell[1] { (Spell)fireBallSpell }).ToArray()); Plugin.Log.LogInfo((object)$"Added Fire Ball to PropWandOfFire ({array.Length + 1} total spell entries)."); } } internal static void RegisterClientSpawnHandler() { //IL_0033: 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_0049: Expected O, but got Unknown //IL_0049: Expected O, but got Unknown if ((Object)(object)_networkProjectilePrefab == (Object)null) { Plugin.Log.LogWarning((object)"Cannot register Fire Ball client spawn handler: prefab is not prepared."); return; } NetworkClient.UnregisterSpawnHandler(4051612689u); NetworkClient.RegisterSpawnHandler(4051612689u, new SpawnHandlerDelegate(SpawnClientProjectile), new UnSpawnDelegate(UnspawnClientProjectile)); Plugin.Log.LogInfo((object)$"Registered Fire Ball client spawn handler for asset ID {4051612689u}."); } private static GameObject SpawnClientProjectile(SpawnMessage message) { //IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Object.Instantiate<GameObject>(_networkProjectilePrefab, message.position, message.rotation); obj.SetActive(true); return obj; } private static void UnspawnClientProjectile(GameObject instance) { if ((Object)(object)instance != (Object)null) { Object.Destroy((Object)(object)instance); } } } [HarmonyPatch(typeof(YapNetworkManager), "Initialise")] internal static class NetworkManagerInitialisePatch { [HarmonyPrefix] private static void Prefix(YapNetworkManager __instance) { try { FireBallBootstrap.Install(__instance); ControlBootstrap.Install(__instance); VomitBootstrap.Install(__instance); ZawardoBootstrap.Install(__instance); } catch (Exception arg) { Plugin.Log.LogError((object)$"Spell expansion installation failed: {arg}"); } } } [HarmonyPatch(typeof(YapNetworkManager), "OnStartClient")] internal static class NetworkManagerStartClientPatch { [HarmonyPostfix] private static void Postfix() { try { FireBallBootstrap.RegisterClientSpawnHandler(); ControlBootstrap.RegisterClientSpawnHandler(); VomitBootstrap.RegisterClientSpawnHandler(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Spell expansion client registration failed: {arg}"); } } } [HarmonyPatch(typeof(VoiceManager), "LoadLocalisationData")] internal static class VoiceLocalisationLoadPatch { [HarmonyPostfix] private static void Postfix(VoiceManager __instance) { VoicePhraseRegistration.AddToAllTranslators(__instance); } } [HarmonyPatch(typeof(VoiceManager), "SetLanguage")] internal static class VoiceLanguagePatch { [HarmonyPrefix] private static void Prefix(VoiceManager __instance) { VoicePhraseRegistration.AddToCurrentTranslator(__instance); } } [HarmonyPatch(typeof(VoiceManager), "TryGetVoiceCommand")] internal static class VoiceCommandLookupPatch { [HarmonyPrefix] private static bool Prefix(string key, ref string[] command, ref bool __result) { if (!Plugin.TryGetVoiceCommand(key, out var tokens)) { return true; } command = tokens; __result = true; return false; } } internal static class VoicePhraseRegistration { private static readonly FieldInfo TranslatorsField = AccessTools.Field(typeof(VoiceManager), "_voskTranslators"); private static readonly FieldInfo CurrentTranslatorField = AccessTools.Field(typeof(VoiceManager), "_currentVoskTranslator"); internal static void AddToAllTranslators(VoiceManager manager) { try { if (!(TranslatorsField.GetValue(manager) is IEnumerable enumerable)) { return; } foreach (object item in enumerable) { AddToTranslator(item); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not extend all Vosk translators: " + ex.Message)); } } internal static void AddToCurrentTranslator(VoiceManager manager) { try { AddToTranslator(CurrentTranslatorField.GetValue(manager)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not extend the current Vosk translator: " + ex.Message)); } } private static void AddToTranslator(object translator) { if (translator == null) { return; } Type type = translator.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "_commands"); FieldInfo fieldInfo2 = AccessTools.Field(type, "_grammar"); if (fieldInfo.GetValue(translator) is Dictionary<string, string[]> dictionary) { foreach (KeyValuePair<string, string[]> voiceCommand in Plugin.GetVoiceCommands()) { dictionary[voiceCommand.Key] = voiceCommand.Value; } } string[] value = ((fieldInfo2.GetValue(translator) as string[]) ?? Array.Empty<string>()).Concat(Plugin.GetVoiceCommands().SelectMany((KeyValuePair<string, string[]> command) => command.Value)).Distinct<string>(StringComparer.Ordinal).ToArray(); fieldInfo2.SetValue(translator, value); } } internal static class VomitBootstrap { private const float VisualScale = 1.2f; private static readonly FieldInfo VoiceSpellsField = AccessTools.Field(typeof(VoiceSpell), "spells"); private static readonly FieldInfo ControllerSpellDataField = AccessTools.Field(typeof(BaseChanneledController), "spellData"); private static readonly FieldInfo ControllerDataField = AccessTools.Field(typeof(BaseChanneledController), "controllerData"); private static readonly FieldInfo NetworkAssetIdField = AccessTools.Field(typeof(NetworkIdentity), "_assetId"); private static readonly FieldInfo NetworkHasSpawnedField = AccessTools.Field(typeof(NetworkIdentity), "hasSpawned"); private static readonly FieldInfo StreamSizeMultiplierField = AccessTools.Field(typeof(ChanneledStreamView), "sizeMultiplier"); private static readonly FieldInfo StreamViewField = AccessTools.Field(typeof(ChanneledStream), "streamVFX"); private static GameObject networkVomitPrefab; private static SpellData vomitSpellData; internal static void Install(YapNetworkManager manager) { if ((Object)(object)manager == (Object)null) { return; } GameObject val = FindPrefab(manager, "PropWandOfGrotesque"); GameObject val2 = FindPrefab(manager, "PropWandOfFire"); GameObject val3 = FindPrefab(manager, "ChanneledStream"); GameObject val4 = FindPrefab(manager, "ChanneledStream_Lava"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null) { Plugin.Log.LogError((object)"Vomit Spell was not installed: Grotesque, Fire Wand, Grotesque stream, or Ignited Tongue stream was not found."); return; } NetworkIdentity val6 = default(NetworkIdentity); if (((NetworkManager)manager).spawnPrefabs.Any((GameObject prefab) => (Object)(object)prefab != (Object)null && prefab.TryGetComponent<NetworkIdentity>(ref val6) && val6.assetId == 2963347217u)) { Plugin.Log.LogError((object)$"Vomit stream asset ID collision: {2963347217u}. Vomit Spell will not install."); return; } VoiceSpell component = val.GetComponent<VoiceSpell>(); PissSpell val5 = ((IEnumerable<PissSpell>)val.GetComponents<PissSpell>()).FirstOrDefault((Func<PissSpell, bool>)((PissSpell spell) => (Object)(object)((Spell)spell).SpellData != (Object)null && string.Equals(((Spell)spell).SpellData.spellName, "PISS-YUK", StringComparison.Ordinal))); LavaSpell component2 = val2.GetComponent<LavaSpell>(); LavaStream component3 = val4.GetComponent<LavaStream>(); if ((Object)(object)component == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { Plugin.Log.LogError((object)"Vomit Spell was not installed: VoiceSpell, Piss Yuk, Ignited Tongue, or its LavaStream is missing."); return; } EnsureRuntimeData(component2, val5); EnsureVomitPrefab(val3, component3); EnsureSpellOnWand(val, component); } private static GameObject FindPrefab(YapNetworkManager manager, string name) { return ((IEnumerable<GameObject>)((NetworkManager)manager).spawnPrefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject prefab) => (Object)(object)prefab != (Object)null && string.Equals(((Object)prefab).name, name, StringComparison.Ordinal))); } private static void EnsureRuntimeData(LavaSpell ignitedTongue, PissSpell pissYuk) { //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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_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) //IL_00aa: 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) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)vomitSpellData != (Object)null)) { vomitSpellData = Object.Instantiate<SpellData>(((Spell)ignitedTongue).SpellData); ((Object)vomitSpellData).name = "SD_GRO_VOMIT_MOD"; vomitSpellData.spellName = "VOMIT SPELL"; vomitSpellData.voiceCommandKey = "MOD_SPELL_GRO_VOMIT"; vomitSpellData.idleColor = ((Spell)pissYuk).SpellData.idleColor; vomitSpellData.cooldownColor = ((Spell)pissYuk).SpellData.cooldownColor; vomitSpellData.chargeColor = ((Spell)pissYuk).SpellData.chargeColor; vomitSpellData.startEvent = ((Spell)pissYuk).SpellData.startEvent; vomitSpellData.loopEvent = ((Spell)pissYuk).SpellData.loopEvent; vomitSpellData.endEvent = ((Spell)pissYuk).SpellData.endEvent; vomitSpellData.impactEvent = ((Spell)pissYuk).SpellData.impactEvent; Plugin.Log.LogInfo((object)("Prepared Vomit Spell data from Ignited Tongue: " + $"{vomitSpellData.charges} charges, {vomitSpellData.cooldown:0.##}s cooldown, " + "Piss Yuk stream audio and combo interactions.")); } } private static void EnsureVomitPrefab(GameObject grotesqueStreamPrefab, LavaStream vanillaLavaStream) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)networkVomitPrefab != (Object)null) { vomitSpellData.objectToSpawnPrefab = networkVomitPrefab; return; } bool activeSelf = grotesqueStreamPrefab.activeSelf; try { grotesqueStreamPrefab.SetActive(false); networkVomitPrefab = Object.Instantiate<GameObject>(grotesqueStreamPrefab); } finally { grotesqueStreamPrefab.SetActive(activeSelf); } ((Object)networkVomitPrefab).name = "ChanneledStream_VomitMod"; networkVomitPrefab.SetActive(false); Object.DontDestroyOnLoad((Object)(object)networkVomitPrefab); NetworkIdentity component = networkVomitPrefab.GetComponent<NetworkIdentity>(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("The cloned lava stream has no NetworkIdentity."); } NetworkAssetIdField.SetValue(component, 2963347217u); NetworkHasSpawnedField.SetValue(component, false); component.sceneId = 0uL; NetworkBehaviour[] components = networkVomitPrefab.GetComponents<NetworkBehaviour>(); foreach (NetworkBehaviour val in components) { if (((object)val).GetType().Name.IndexOf("NetworkTransform", StringComparison.Ordinal) >= 0) { val.syncDirection = (SyncDirection)0; } } ChanneledStream component2 = networkVomitPrefab.GetComponent<ChanneledStream>(); ChanneledStreamView component3 = networkVomitPrefab.GetComponent<ChanneledStreamView>(); if ((Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { throw new InvalidOperationException("The cloned Grotesque stream is missing ChanneledStream or ChanneledStreamView."); } ControllerDataField.SetValue(component2, ControllerDataField.GetValue(vanillaLavaStream)); ControllerSpellDataField.SetValue(component2, vomitSpellData); StreamSizeMultiplierField.SetValue(component3, 1.2f); ApplyVomitVisuals(networkVomitPrefab); networkVomitPrefab.AddComponent<VomitDamageTracker>(); vomitSpellData.objectToSpawnPrefab = networkVomitPrefab; Plugin.Log.LogInfo((object)("Prepared non-fire Grotesque-colored Vomit stream with asset ID " + $"{2963347217u} and {1.2f:0.0}x visual size.")); } private static void ApplyVomitVisuals(GameObject prefab) { //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) ParticleSystem[] componentsInChildren = prefab.GetComponentsInChildren<ParticleSystem>(true); for (int i = 0; i < componentsInChildren.Length; i++) { MainModule main = componentsInChildren[i].main; ((MainModule)(ref m