public static bool Prefix(ref GimbalAimer __instance, out float __state) { __state = __instance.aimClampMaxPercent; if (WeaponAimSettings.OctantAim) { __instance.aimClampMaxPercent = Mathf.Min(0.10f, __instance.aimClampMaxPercent); } return(true); }
public static void Postfix(ref GimbalAimer __instance, float __state) { __instance.aimClampMaxPercent = __state; }
public Visible GetFirstVisibleTechIsEnemy(int[] octants, Limits limits, TankBlock block, GimbalAimer XGimbal, GimbalAimer YGimbal, Func <Vector3, Vector3> aimDelegate) { Visible overallBest = null; bool hasX = limits.XConstraints[0] != limits.XConstraints[1]; bool hasY = limits.YConstraints[0] != limits.YConstraints[1]; List <int> sortedOctantId = new List <int>(); int[] indices = new int[octants.Length]; for (int i = 0; i < octants.Length; i++) { indices[i] = 0; if (this.m_Visibles[octants[i]].Count > 0) { sortedOctantId.Add(i); } } sortedOctantId.Sort((int a, int b) => (int)(this.m_Visibles[octants[a]][indices[a]].distSq * 1000f - this.m_Visibles[octants[b]][indices[b]].distSq * 1000f)); // Continuously keep a sorted list of visibles to go through while (sortedOctantId.Count > 0) { int currentOctantId = sortedOctantId[0]; sortedOctantId.RemoveAt(0); int octant = octants[currentOctantId]; int index = indices[currentOctantId]; // Check if targetable. If it is, then return it Visible.ConeFiltered filteredVisible = this.m_Visibles[octant][index]; if (filteredVisible.visible != null) { Visible visible = filteredVisible.visible; Tank tank = filteredVisible.visible.tank; bool canAim = true; Vector3 targetWorld = tank.transform.position; if (aimDelegate != null) { targetWorld = aimDelegate(targetWorld); } float leeway = Mathf.Max(5.0f, (float)Math.Atan2(tank.blockBounds.size.magnitude / 2, (targetWorld - block.transform.position).magnitude) * Mathf.Rad2Deg); float YAngle = 0f, XAngle = 0f; if (hasY && YGimbal) { Vector3 targetRelative = YGimbal.transform.parent.InverseTransformDirection(targetWorld - YGimbal.transform.position); YAngle = Mathf.Atan2(targetRelative.x, targetRelative.z) * Mathf.Rad2Deg; canAim = YAngle >= limits.YConstraints[0] - leeway && YAngle <= limits.YConstraints[1] + leeway; } if (canAim && hasX && XGimbal) { Vector3 targetRelative = XGimbal.transform.parent.InverseTransformDirection(targetWorld - XGimbal.transform.position); XAngle = Mathf.Atan2(-targetRelative.y, targetRelative.z) * Mathf.Rad2Deg; canAim = XAngle >= limits.XConstraints[0] - leeway && XAngle <= limits.XConstraints[1] + leeway; } if (canAim) { RaycastHit raycastHit; float length = Mathf.Max(block.tank.blockBounds.size.magnitude, 1f); Vector3 barrelRelative = limits.localToBarrel + limits.localToGimbal + limits.localToBlock; Vector3 ray = (targetWorld - block.transform.position).normalized; if (!Physics.Raycast(block.transform.position + (ray * barrelRelative.magnitude), ray, out raycastHit, length, Globals.inst.layerTank.mask, QueryTriggerInteraction.Ignore) || raycastHit.rigidbody != block.tank.rbody) { float sqrMagnitude = (base.Tech.trans.position - tank.trans.position).sqrMagnitude; return(visible); } } } indices[currentOctantId]++; // If stuff left in visibles, add to sorted list if (this.m_Visibles[octant].Count > index + 1) { int sortIndex = sortedOctantId.BinarySearch(currentOctantId, (int a, int b) => (int)(this.m_Visibles[octants[a]][indices[a]].distSq * 1000f - this.m_Visibles[octants[b]][indices[b]].distSq * 1000f)); if (sortIndex < 0) { sortIndex = ~sortIndex; } sortedOctantId.Insert(sortIndex, currentOctantId); } } return(overallBest); }
public static bool Prefix(ref TargetAimer __instance, ref float rotateSpeed) { TankBlock block = (TankBlock)m_Block.GetValue(__instance); // Has a target if (WeaponAimSettings.OctantAim && block && block.tank && __instance.HasTarget) { Tank tank = block.tank; bool enemyWeapon = !ManSpawn.IsPlayerTeam(tank.Team); if (enemyWeapon && WeaponAimSettings.EnemyLead || !enemyWeapon && WeaponAimSettings.PlayerLead) { Vector3 targetWorld = (Vector3)m_TargetPosition.GetValue(__instance); Func <Vector3, Vector3> aimDelegate = (Func <Vector3, Vector3>)AimDelegate.GetValue(__instance); if (__instance.HasTarget && aimDelegate != null) { targetWorld = aimDelegate(targetWorld); } // Check if we can aim List <GimbalAimer> gimbalAimers = (List <GimbalAimer>)m_GimbalAimers.GetValue(__instance); bool canAim = true; foreach (GimbalAimer aimer in gimbalAimers) { if (__instance.Target && canAim) { canAim = aimer.CanAim(targetWorld); if (!canAim) { break; } } } // If we can aim, is all good - continue as normal (will do aim calculation for gimbals twice) if (canAim) { return(true); } IModuleWeapon moduleWeapon = block.GetComponent <IModuleWeapon>(); OctantVision octantVision = tank.GetComponent <OctantVision>(); if (octantVision && gimbalAimers.Count > 0) { float[] XConstraints = new float[2]; float[] YConstraints = new float[2]; GimbalAimer XGimbal = null; GimbalAimer YGimbal = null; GimbalAimer FreeGimbal = null; bool free = false; foreach (GimbalAimer aimer in gimbalAimers) { if (aimer.rotationAxis == GimbalAimer.AxisConstraint.X) { XConstraints = aimer.rotationLimits; XGimbal = aimer; } else if (aimer.rotationAxis == GimbalAimer.AxisConstraint.Y) { YConstraints = aimer.rotationLimits; YGimbal = aimer; } else { FreeGimbal = aimer; free = true; break; } } int[] octants; if (free) { octants = new int[8] { 0, 1, 2, 3, 4, 5, 6, 7 }; OctantVision.Limits limits = new OctantVision.Limits { localToBlock = block.trans.InverseTransformPoint(FreeGimbal.transform.position), localToGimbal = Vector3.zero, localToBarrel = Vector3.zero, XConstraints = new float[2], YConstraints = new float[2] }; Visible betterTarget = octantVision.GetFirstVisibleTechIsEnemy(octants, limits, block, null, null, aimDelegate); if (betterTarget) { Target.SetValue(__instance, betterTarget); UpdateTarget.Invoke(__instance, null); } } else if (XGimbal || YGimbal) { if (moduleWeapon != null) { GimbalAimer parentGimbal = null; GimbalAimer childGimbal = null; if (XGimbal) { if (YGimbal) { if (YGimbal.transform.IsChildOf(XGimbal.transform)) { parentGimbal = XGimbal; childGimbal = YGimbal; } else { parentGimbal = YGimbal; childGimbal = XGimbal; } } else { parentGimbal = XGimbal; } } else { parentGimbal = YGimbal; } Vector3 gimbalBlockLocalPosition = block.trans.InverseTransformPoint(parentGimbal.transform.position); Vector3 gimbalLocalPosition = Vector3.zero; if (parentGimbal && childGimbal) { gimbalLocalPosition = parentGimbal.transform.InverseTransformPoint(childGimbal.transform.position); } Vector3 fireLocalPosition = Vector3.zero; GimbalAimer localChildGimbal = childGimbal ? childGimbal : parentGimbal; if (moduleWeapon is ModuleWeaponGun moduleWeaponGun) { CannonBarrel[] cannonBarrels = (CannonBarrel[])m_CannonBarrels.GetValue(moduleWeaponGun); foreach (CannonBarrel cannonBarrel in cannonBarrels) { fireLocalPosition += localChildGimbal.transform.InverseTransformPoint(cannonBarrel.projectileSpawnPoint.position); } fireLocalPosition /= cannonBarrels.Length; } else if (moduleWeapon is ModuleWeaponFlamethrower moduleWeaponFlamethrower) { fireLocalPosition = localChildGimbal.transform.InverseTransformPoint(moduleWeaponFlamethrower.GetFireTransform().position); } OctantVision.Limits limits = new OctantVision.Limits { localToBlock = gimbalBlockLocalPosition, localToGimbal = gimbalLocalPosition, localToBarrel = fireLocalPosition, XConstraints = XConstraints, YConstraints = YConstraints }; octants = OctantVision.GetOctants(limits, parentGimbal, block); Visible betterTarget = octantVision.GetFirstVisibleTechIsEnemy(octants, limits, block, XGimbal, YGimbal, aimDelegate); if (betterTarget != null) { Target.SetValue(__instance, betterTarget); UpdateTarget.Invoke(__instance, null); } } } } } } return(true); }
public static int[] GetOctants(Limits limits, GimbalAimer parentGimbal, TankBlock block) { Vector3 up = block.transform.up; Vector3 forward = block.transform.forward; if (parentGimbal) { Quaternion localRotation = (Quaternion)restingOrientation.GetValue(parentGimbal); Quaternion currentRotation = parentGimbal.transform.localRotation; Quaternion reverseCurrent = Quaternion.Inverse(currentRotation); up = (reverseCurrent * parentGimbal.transform.up); forward = (reverseCurrent * parentGimbal.transform.forward); } Transform tankTransform = block.tank.transform; float rightTest = up.Dot(tankTransform.right); float frontTest = up.Dot(tankTransform.forward); float topTest = up.Dot(tankTransform.up); float xTest, yTest; int[] leftPair; int[] rightPair; int[] topQuad; int[] bottomQuad; if (rightTest > 0.5) // On the right { xTest = forward.Dot(tankTransform.forward); yTest = forward.Dot(tankTransform.up); topQuad = new int[4] { 4, 5, 6, 7 }; bottomQuad = new int[4] { 0, 1, 2, 3 }; if (xTest > 0.5) // right { DebugPrint(block, $"{block.name} ON RIGHT FACING RIGHT"); leftPair = new int[2] { 2, 6 }; rightPair = new int[2] { 0, 4 }; } else if (yTest > 0.5) // up { DebugPrint(block, $"{block.name} ON RIGHT FACING FRONT"); leftPair = new int[2] { 0, 4 }; rightPair = new int[2] { 1, 5 }; } else if (xTest < -0.5) // left { DebugPrint(block, $"{block.name} ON RIGHT FACING LEFT"); leftPair = new int[2] { 1, 5 }; rightPair = new int[2] { 3, 7 }; } else // down { DebugPrint(block, $"{block.name} ON RIGHT FACING BACK"); leftPair = new int[2] { 3, 7 }; rightPair = new int[2] { 2, 6 }; } } else if (rightTest < -0.5) // On the left { xTest = -forward.Dot(tankTransform.forward); yTest = forward.Dot(tankTransform.up); bottomQuad = new int[4] { 4, 5, 6, 7 }; topQuad = new int[4] { 0, 1, 2, 3 }; if (xTest > 0.5) // right { DebugPrint(block, $"{block.name} ON LEFT FACING RIGHT"); rightPair = new int[2] { 2, 6 }; leftPair = new int[2] { 0, 4 }; } else if (yTest > 0.5) // up { DebugPrint(block, $"{block.name} ON LEFT FACING FRONT"); rightPair = new int[2] { 0, 4 }; leftPair = new int[2] { 1, 5 }; } else if (xTest < -0.5) // left { DebugPrint(block, $"{block.name} ON LEFT FACING LEFT"); rightPair = new int[2] { 1, 5 }; leftPair = new int[2] { 3, 7 }; } else // down { DebugPrint(block, $"{block.name} ON LEFT FACING BACK"); rightPair = new int[2] { 3, 7 }; leftPair = new int[2] { 2, 6 }; } } else if (frontTest > 0.5) // On the front { xTest = forward.Dot(tankTransform.right); yTest = forward.Dot(tankTransform.up); topQuad = new int[4] { 1, 3, 5, 7 }; bottomQuad = new int[4] { 0, 2, 4, 6 }; if (xTest > 0.5) // right { DebugPrint(block, $"{block.name} ON FRONT FACING RIGHT"); leftPair = new int[2] { 6, 7 }; rightPair = new int[2] { 4, 5 }; } else if (yTest > 0.5) // up { DebugPrint(block, $"{block.name} ON FRONT FACING FRONT"); leftPair = new int[2] { 4, 5 }; rightPair = new int[2] { 0, 1 }; } else if (xTest < -0.5) // left { DebugPrint(block, $"{block.name} ON FRONT FACING LEFT"); leftPair = new int[2] { 0, 1 }; rightPair = new int[2] { 2, 3 }; } else // down { DebugPrint(block, $"{block.name} ON FRONT FACING BACK"); leftPair = new int[2] { 2, 3 }; rightPair = new int[2] { 6, 7 }; } } else if (frontTest < -0.5) // On the back { xTest = -forward.Dot(tankTransform.right); yTest = forward.Dot(tankTransform.up); bottomQuad = new int[4] { 1, 3, 5, 7 }; topQuad = new int[4] { 0, 2, 4, 6 }; if (xTest > 0.5) // right { DebugPrint(block, $"{block.name} ON BACK FACING RIGHT"); rightPair = new int[2] { 6, 7 }; leftPair = new int[2] { 4, 5 }; } else if (yTest > 0.5) // up { DebugPrint(block, $"{block.name} ON BACK FACING FRONT"); rightPair = new int[2] { 4, 5 }; leftPair = new int[2] { 0, 1 }; } else if (xTest < -0.5) // left { DebugPrint(block, $"{block.name} ON BACK FACING LEFT"); rightPair = new int[2] { 0, 1 }; leftPair = new int[2] { 2, 3 }; } else // down { DebugPrint(block, $"{block.name} ON BACK FACING BACK"); rightPair = new int[2] { 2, 3 }; leftPair = new int[2] { 6, 7 }; } } else if (topTest > 0.5) // On the top { xTest = forward.Dot(tankTransform.right); yTest = forward.Dot(tankTransform.forward); bottomQuad = new int[4] { 0, 1, 4, 5 }; topQuad = new int[4] { 2, 3, 6, 7 }; if (xTest > 0.5) // right { DebugPrint(block, $"{block.name} ON TOP FACING RIGHT"); leftPair = new int[2] { 3, 1 }; rightPair = new int[2] { 2, 0 }; } else if (yTest > 0.5) // up { DebugPrint(block, $"{block.name} ON TOP FACING FRONT"); leftPair = new int[2] { 2, 0 }; rightPair = new int[2] { 6, 4 }; } else if (xTest < -0.5) // left { DebugPrint(block, $"{block.name} ON TOP FACING LEFT"); leftPair = new int[2] { 6, 4 }; rightPair = new int[2] { 7, 5 }; } else // down { DebugPrint(block, $"{block.name} ON TOP FACING BACK"); leftPair = new int[2] { 7, 5 }; rightPair = new int[2] { 3, 1 }; } } else // On the bottom { xTest = -forward.Dot(tankTransform.right); yTest = forward.Dot(tankTransform.forward); topQuad = new int[4] { 0, 1, 4, 5 }; bottomQuad = new int[4] { 2, 3, 6, 7 }; if (xTest > 0.5) // right { DebugPrint(block, $"{block.name} ON BOTTOM FACING RIGHT"); rightPair = new int[2] { 3, 1 }; leftPair = new int[2] { 2, 0 }; } else if (yTest > 0.5) // up { DebugPrint(block, $"{block.name} ON BOTTOM FACING FRONT"); rightPair = new int[2] { 2, 0 }; leftPair = new int[2] { 6, 4 }; } else if (xTest < -0.5) // left { DebugPrint(block, $"{block.name} ON BOTTOM FACING LEFT"); rightPair = new int[2] { 6, 4 }; leftPair = new int[2] { 7, 5 }; } else // down { DebugPrint(block, $"{block.name} ON BOTTOM FACING BACK"); rightPair = new int[2] { 7, 5 }; leftPair = new int[2] { 3, 1 }; } } List <int> octants = new List <int>() { 0, 1, 2, 3, 4, 5, 6, 7 }; if (limits.YConstraints[0] != limits.YConstraints[1]) { if (limits.YConstraints[0] >= -90) { foreach (int octant in leftPair) { octants.Remove(octant); } } if (limits.YConstraints[1] <= 90) { foreach (int octant in rightPair) { octants.Remove(octant); } } } if (limits.XConstraints[0] != limits.XConstraints[1]) { if (limits.XConstraints[0] >= 0) { foreach (int octant in bottomQuad) { octants.Remove(octant); } } if (limits.XConstraints[1] <= 0) { foreach (int octant in topQuad) { octants.Remove(octant); } } } return(octants.ToArray()); }