private void AiLoop() { //Fully Inlined due to keen's mod profiler foreach (var ai in GridTargetingAIs.Values) { /// /// GridAi update section /// ai.MyProjectiles = 0; ai.ProInMinCacheRange = 0; ai.AccelChecked = false; if (ai.MarkedForClose || !ai.GridInit || ai.MyGrid == null || ai.Construct.RootAi == null || ai.MyGrid.MarkedForClose) { continue; } ai.Concealed = ((uint)ai.MyGrid.Flags & 4) > 0; if (ai.Concealed) { continue; } if (!ai.ScanInProgress && Tick - ai.TargetsUpdatedTick > 100 && DbTask.IsComplete) { ai.RequestDbUpdate(); } if (ai.DeadProjectiles.Count > 0) { for (int i = 0; i < ai.DeadProjectiles.Count; i++) { ai.LiveProjectile.Remove(ai.DeadProjectiles[i]); } ai.DeadProjectiles.Clear(); ai.LiveProjectileTick = Tick; } var enemyProjectiles = ai.LiveProjectile.Count > 0; ai.CheckProjectiles = Tick - ai.NewProjectileTick <= 1; if (ai.UpdatePowerSources || !ai.HadPower && ai.MyGrid.IsPowered || ai.HasPower && !ai.MyGrid.IsPowered || Tick10) { ai.UpdateGridPower(); } if (!ai.HasPower || Settings.Enforcement.ServerSleepSupport && IsServer && ai.AwakeComps == 0 && ai.WeaponsTracking == 0 && ai.SleepingComps > 0 && !ai.CheckProjectiles && ai.AiSleep && !ai.DbUpdated) { continue; } if (IsServer) { if (ai.Construct.RootAi.Construct.NewInventoryDetected) { ai.Construct.RootAi.Construct.CheckForMissingAmmo(); } else if (Tick60 && ai.Construct.RootAi.Construct.RecentItems.Count > 0) { ai.Construct.RootAi.Construct.CheckEmptyWeapons(); } } /// /// Comp update section /// for (int i = 0; i < ai.Weapons.Count; i++) { var comp = ai.Weapons[i]; if (comp.Status != Started) { comp.HealthCheck(); } if (ai.DbUpdated || !comp.UpdatedState) { comp.DetectStateChanges(); } if (comp.Platform.State != CorePlatform.PlatformState.Ready || comp.IsAsleep || !comp.IsWorking || comp.MyCube.MarkedForClose || comp.IsDisabled) { continue; } if (IsServer && comp.Data.Repo.Base.State.PlayerId > 0 && !ai.Data.Repo.ControllingPlayers.ContainsKey(comp.Data.Repo.Base.State.PlayerId)) { comp.ResetPlayerControl(); } if (HandlesInput) { var wasTrack = comp.Data.Repo.Base.State.TrackingReticle; var isControllingPlayer = comp.Data.Repo.Base.State.PlayerId == PlayerId; var track = (isControllingPlayer && (comp.Data.Repo.Base.Set.Overrides.Control != GroupOverrides.ControlModes.Auto) && TargetUi.DrawReticle && !InMenu && comp.Ai.Construct.RootAi.Data.Repo.ControllingPlayers.ContainsKey(PlayerId)); if (IsServer) { comp.Data.Repo.Base.State.TrackingReticle = track; } if (MpActive && track != wasTrack) { comp.Session.SendTrackReticleUpdate(comp, track); } } var trackReticle = comp.Data.Repo.Base.State.TrackingReticle; comp.WasControlled = comp.UserControlled; comp.UserControlled = comp.Data.Repo.Base.State.Control != ControlMode.None; if (!PlayerMouseStates.TryGetValue(comp.Data.Repo.Base.State.PlayerId, out comp.InputState)) { comp.InputState = DefaultInputStateData; } var compManualMode = comp.Data.Repo.Base.State.Control == ControlMode.Camera || (comp.Data.Repo.Base.Set.Overrides.Control == GroupOverrides.ControlModes.Manual && trackReticle); var canManualShoot = !ai.SuppressMouseShoot && !comp.InputState.InMenu; /// /// Weapon update section /// for (int j = 0; j < comp.Platform.Weapons.Length; j++) { var w = comp.Platform.Weapons[j]; if (w.WeaponReadyTick > Tick) { if (w.Target.HasTarget && !IsClient) { w.Target.Reset(comp.Session.Tick, States.WeaponNotReady); } continue; } if (w.AvCapable && Tick20) { var avWasEnabled = w.PlayTurretAv; double distSqr; Vector3D.DistanceSquared(ref CameraPos, ref w.MyPivotPos, out distSqr); w.PlayTurretAv = distSqr < w.System.HardPointAvMaxDistSqr; if (avWasEnabled != w.PlayTurretAv) { w.StopBarrelAvTick = Tick; } } if (!ai.HadPower && w.ActiveAmmoDef.ConsumableDef.Const.MustCharge && w.State.Action != ShootOff) { if (IsServer) { w.State.WeaponMode(comp, ShootOff); w.Ammo.CurrentAmmo = 0; } w.Reloading = false; w.FinishBurst = false; if (w.IsShooting) { w.StopShooting(); } } /// ///Check Reload /// if (w.ActiveAmmoDef.ConsumableDef.Const.Reloadable && !w.System.DesignatorWeapon && !w.Reloading) { if (IsServer && (w.Ammo.CurrentAmmo == 0 || w.CheckInventorySystem)) { w.ComputeServerStorage(); } else if (IsClient) { if (w.ClientReloading && w.Reload.EndId > w.ClientEndId && w.Reload.StartId == w.ClientStartId) { w.Reloaded(); } else { w.ClientReload(); } } } /// /// Update Weapon Hud Info /// var isWaitingForBurstDelay = w.ShowBurstDelayAsReload && !w.Reloading && w.ShootTick > Tick && w.ShootTick >= w.LastShootTick + w.System.Values.HardPoint.Loading.DelayAfterBurst; if (HandlesInput && (w.Reloading || w.HeatPerc >= 0.01 || isWaitingForBurstDelay) && Tick - w.LastLoadedTick > 30 && !Session.Config.MinimalHud && ActiveControlBlock != null && ai.SubGrids.Contains(ActiveControlBlock.CubeGrid)) { HudUi.TexturesToAdd++; HudUi.WeaponsToDisplay.Add(w); } if (w.System.Armor != ArmorState.IsWeapon) { continue; } if (w.Target.ClientDirty) { w.Target.ClientUpdate(w, w.TargetData); } /// /// Check target for expire states /// bool targetLock = false; var noAmmo = w.NoMagsToLoad && w.Ammo.CurrentAmmo == 0 && w.ActiveAmmoDef.ConsumableDef.Const.Reloadable && !w.System.DesignatorWeapon && Tick - w.LastMagSeenTick > 600; if (w.Target.HasTarget) { if (w.PosChangedTick != Tick) { w.UpdatePivotPos(); } if (!IsClient && noAmmo) { w.Target.Reset(Tick, States.Expired); } else if (!IsClient && w.Target.Entity == null && w.Target.Projectile == null && (!trackReticle || Tick - PlayerDummyTargets[comp.Data.Repo.Base.State.PlayerId].LastUpdateTick > 120)) { w.Target.Reset(Tick, States.Expired, !trackReticle); } else if (!IsClient && w.Target.Entity != null && (comp.UserControlled && !w.System.SuppressFire || w.Target.Entity.MarkedForClose)) { w.Target.Reset(Tick, States.Expired); } else if (!IsClient && w.Target.Projectile != null && (!ai.LiveProjectile.Contains(w.Target.Projectile) || w.Target.IsProjectile && w.Target.Projectile.State != Projectile.ProjectileState.Alive)) { w.Target.Reset(Tick, States.Expired); } else if (w.AiEnabled) { if (!Weapon.TrackingTarget(w, w.Target, out targetLock) && !IsClient && w.Target.ExpiredTick != Tick) { w.Target.Reset(Tick, States.LostTracking, !trackReticle && (w.Target.CurrentState != States.RayCheckFailed && !w.Target.HasTarget)); } } else { Vector3D targetPos; if (w.IsTurret) { if (!w.TrackTarget && !IsClient) { if ((comp.TrackingWeapon.Target.Projectile != w.Target.Projectile || w.Target.IsProjectile && w.Target.Projectile.State != Projectile.ProjectileState.Alive || comp.TrackingWeapon.Target.Entity != w.Target.Entity || comp.TrackingWeapon.Target.IsFakeTarget != w.Target.IsFakeTarget)) { w.Target.Reset(Tick, States.Expired); } else { targetLock = true; } } else if (!Weapon.TargetAligned(w, w.Target, out targetPos) && !IsClient) { w.Target.Reset(Tick, States.Expired); } } else if (w.TrackTarget && !Weapon.TargetAligned(w, w.Target, out targetPos) && !IsClient) { w.Target.Reset(Tick, States.Expired); } } } w.ProjectilesNear = enemyProjectiles && w.System.TrackProjectile && w.Comp.Data.Repo.Base.Set.Overrides.Projectiles && !w.Target.HasTarget && (w.Target.TargetChanged || SCount == w.ShortLoadId); if (comp.Data.Repo.Base.State.Control == ControlMode.Camera && UiInput.MouseButtonPressed) { w.Target.TargetPos = Vector3D.Zero; } /// /// Queue for target acquire or set to tracking weapon. /// var seek = trackReticle && !w.Target.IsFakeTarget || (!noAmmo && !w.Target.HasTarget && w.TrackTarget && (comp.TargetNonThreats && ai.TargetingInfo.OtherInRange || ai.TargetingInfo.ThreatInRange) && (!comp.UserControlled || w.State.Action == ShootClick)); if (!IsClient && (seek || w.TrackTarget && ai.TargetResetTick == Tick && !comp.UserControlled) && !w.AcquiringTarget && (comp.Data.Repo.Base.State.Control == ControlMode.None || comp.Data.Repo.Base.State.Control == ControlMode.Ui)) { w.AcquiringTarget = true; AcquireTargets.Add(w); } if (w.Target.TargetChanged) // Target changed { w.TargetChanged(); } /// /// Check weapon's turret to see if its time to go home /// if (w.TurretMode && !w.IsHome && !w.ReturingHome && !w.Target.HasTarget && Tick - w.Target.ResetTick > 239 && !comp.UserControlled && w.State.Action == ShootOff) { w.ScheduleWeaponHome(); } /// /// Determine if its time to shoot /// /// w.AiShooting = targetLock && !comp.UserControlled && !w.System.SuppressFire; var reloading = w.ActiveAmmoDef.ConsumableDef.Const.Reloadable && w.ClientMakeUpShots == 0 && (w.Reloading || w.Ammo.CurrentAmmo == 0); var canShoot = !w.State.Overheated && !reloading && !w.System.DesignatorWeapon && (!w.LastEventCanDelay || w.AnimationDelayTick <= Tick || w.ClientMakeUpShots > 0); var fakeTarget = comp.Data.Repo.Base.Set.Overrides.Control == GroupOverrides.ControlModes.Painter && trackReticle && w.Target.IsFakeTarget && w.Target.IsAligned; var validShootStates = fakeTarget || w.State.Action == ShootOn || w.AiShooting && w.State.Action == ShootOff; var manualShot = (compManualMode || w.State.Action == ShootClick) && canManualShoot && comp.InputState.MouseButtonLeft; var delayedFire = w.System.DelayCeaseFire && !w.Target.IsAligned && Tick - w.CeaseFireDelayTick <= w.System.CeaseFireDelay; var shoot = (validShootStates || manualShot || w.FinishBurst || delayedFire); w.LockOnFireState = !shoot && w.System.LockOnFocus && ai.Construct.Data.Repo.FocusData.HasFocus && ai.Construct.Focus.FocusInRange(w); var shotReady = canShoot && (shoot || w.LockOnFireState); if ((shotReady || w.ShootOnce) && ai.CanShoot) { if (w.ShootOnce && IsServer && (shotReady || w.State.Action != ShootOnce)) { w.ShootOnce = false; } if (MpActive && HandlesInput && !ManualShot) { ManualShot = !validShootStates && !w.FinishBurst && !delayedFire; } if (w.System.DelayCeaseFire && (validShootStates || manualShot || w.FinishBurst)) { w.CeaseFireDelayTick = Tick; } if ((ai.AvailablePowerChanged || ai.RequestedPowerChanged || (w.RecalcPower && Tick60)) && !w.ActiveAmmoDef.ConsumableDef.Const.MustCharge) { if ((!ai.RequestIncrease || ai.PowerIncrease) && !Tick60) { w.RecalcPower = true; } else { w.RecalcPower = false; w.ChargeDelayTicks = 0; } } if (w.ChargeDelayTicks == 0 || w.ChargeUntilTick <= Tick) { if (!w.RequestedPower && !w.ActiveAmmoDef.ConsumableDef.Const.MustCharge && !w.System.DesignatorWeapon) { if (!comp.UnlimitedPower) { ai.RequestedWeaponsDraw += w.RequiredPower; } w.RequestedPower = true; } ShootingWeapons.Add(w); } else if (w.ChargeUntilTick > Tick && !w.ActiveAmmoDef.ConsumableDef.Const.MustCharge) { w.Charging = true; w.StopShooting(false); } } else if (w.IsShooting) { w.StopShooting(); } else if (w.BarrelSpinning) { w.SpinBarrel(true); } if (comp.Debug && !DedicatedServer) { WeaponDebug(w); } } } ai.OverPowered = ai.RequestedWeaponsDraw > 0 && ai.RequestedWeaponsDraw > ai.GridMaxPower; ai.DbUpdated = false; } if (DbTask.IsComplete && DbsToUpdate.Count > 0 && !DbUpdating) { UpdateDbsInQueue(); } }
private void AiLoop() { //Fully Inlined due to keen's mod profiler foreach (var aiPair in GridTargetingAIs) { /// /// GridAi update section /// var gridAi = aiPair.Value; using (gridAi.MyGrid.Pin()) { if (!gridAi.GridInit || gridAi.MyGrid.MarkedForClose || gridAi.Concealed) { continue; } var readyToUpdate = Tick - gridAi.TargetsUpdatedTick > 100 && DbCallBackComplete && DbTask.IsComplete; if (readyToUpdate && gridAi.UpdateOwner()) { gridAi.RequestDbUpdate(); } if (gridAi.DeadProjectiles.Count > 0) { for (int i = 0; i < gridAi.DeadProjectiles.Count; i++) { gridAi.LiveProjectile.Remove(gridAi.DeadProjectiles[i]); } gridAi.DeadProjectiles.Clear(); gridAi.LiveProjectileTick = Tick; } gridAi.CheckProjectiles = Tick - gridAi.NewProjectileTick <= 1; if (!gridAi.HasPower && gridAi.HadPower || gridAi.UpdatePowerSources || !gridAi.WasPowered && gridAi.MyGrid.IsPowered || Tick10) { gridAi.UpdateGridPower(); } if (!gridAi.HasPower) { continue; } /// /// Comp update section /// for (int i = 0; i < gridAi.Weapons.Count; i++) { var comp = gridAi.Weapons[i]; using (comp.MyCube.Pin()) { if (comp.MyCube.MarkedForClose || comp.Platform.State != MyWeaponPlatform.PlatformState.Ready) { continue; } if (!comp.State.Value.Online || !comp.Set.Value.Overrides.Activate || comp.Status != Started) { if (comp.Status != Started) { comp.HealthCheck(); } continue; } if (InMenu && Tick20 && gridAi.LastTerminal == comp.MyCube) { comp.TerminalRefresh(); } var overRides = comp.Set.Value.Overrides; var compCurPlayer = comp.State.Value.CurrentPlayerControl; if (HandlesInput) { comp.WasTrackReticle = comp.TrackReticle; var isControllingPlayer = comp.State.Value.CurrentPlayerControl.PlayerId == PlayerId; comp.TrackReticle = comp.OtherPlayerTrackingReticle || (isControllingPlayer && (overRides.TargetPainter || overRides.ManualControl) && TargetUi.DrawReticle && !InMenu && comp.Ai.ControllingPlayers.ContainsKey(PlayerId)); if (MpActive && isControllingPlayer && comp.TrackReticle != comp.WasTrackReticle) { comp.Session.SendTrackReticleUpdate(comp); } } comp.WasControlled = comp.UserControlled; comp.UserControlled = compCurPlayer.ControlType != ControlType.None; var leftClick = false; var rightClick = false; MouseStateData mouseState; if (PlayerMouseStates.TryGetValue(compCurPlayer.PlayerId, out mouseState)) { leftClick = mouseState.MouseButtonLeft; // && currentControl; rightClick = mouseState.MouseButtonRight; // && currentControl; } /// /// Weapon update section /// for (int j = 0; j < comp.Platform.Weapons.Length; j++) { var w = comp.Platform.Weapons[j]; if (!w.Set.Enable) { if (w.Target.HasTarget && !IsClient) { w.Target.Reset(comp.Session.Tick, States.Expired); } continue; } if (w.Timings.WeaponReadyTick > Tick) { continue; } if (w.AvCapable && (!w.PlayTurretAv || Tick60)) { var avWasEnabled = w.PlayTurretAv; w.PlayTurretAv = Vector3D.DistanceSquared(CameraPos, w.MyPivotPos) < w.System.HardPointAvMaxDistSqr; if (avWasEnabled != w.PlayTurretAv) { w.StopBarrelAv = !w.PlayTurretAv; } } /// /// Check target for expire states /// if (w.Target.HasTarget && !(IsClient && w.Target.CurrentState == States.Invalid)) { if (w.PosChangedTick != Tick) { w.UpdatePivotPos(); } if (!IsClient && w.Target.Entity == null && w.Target.Projectile == null && (!comp.TrackReticle || gridAi.DummyTarget.ClearTarget)) { w.Target.Reset(Tick, States.Expired, !comp.TrackReticle); } else if (!IsClient && w.Target.Entity != null && (comp.UserControlled || w.Target.Entity.MarkedForClose)) { w.Target.Reset(Tick, States.Expired); } else if (!IsClient && w.Target.Projectile != null && (!gridAi.LiveProjectile.Contains(w.Target.Projectile) || w.Target.IsProjectile && w.Target.Projectile.State != Projectile.ProjectileState.Alive)) { w.Target.Reset(Tick, States.Expired); } else if (w.AiEnabled) { if (!Weapon.TrackingTarget(w, w.Target) && !IsClient) { w.Target.Reset(Tick, States.Expired, !comp.TrackReticle); } } else { Vector3D targetPos; if (w.IsTurret) { if (!w.TrackTarget && !IsClient) { if ((comp.TrackingWeapon.Target.Projectile != w.Target.Projectile || w.Target.IsProjectile && w.Target.Projectile.State != Projectile.ProjectileState.Alive || comp.TrackingWeapon.Target.Entity != w.Target.Entity || comp.TrackingWeapon.Target.IsFakeTarget != w.Target.IsFakeTarget)) { w.Target.Reset(Tick, States.Expired); } } else if (!Weapon.TargetAligned(w, w.Target, out targetPos) && !IsClient) { w.Target.Reset(Tick, States.Expired); } } else if (w.TrackTarget && !Weapon.TargetAligned(w, w.Target, out targetPos) && !IsClient) { w.Target.Reset(Tick, States.Expired); } } } else if (w.Target.HasTarget && MyEntities.EntityExists(comp.WeaponValues.Targets[w.WeaponId].EntityId)) { w.Target.HasTarget = false; comp.Session.ClientGridResyncRequests.Add(comp); } w.ProjectilesNear = w.TrackProjectiles && !w.Target.HasTarget && (w.Target.TargetChanged || SCount == w.ShortLoadId && gridAi.LiveProjectile.Count > 0); if (compCurPlayer.ControlType == ControlType.Camera && UiInput.MouseButtonPressed) { w.Target.TargetPos = Vector3D.Zero; } /// /// Queue for target acquire or set to tracking weapon. /// w.SeekTarget = (!IsClient && !w.Target.HasTarget && w.TrackTarget && gridAi.TargetingInfo.TargetInRange && !comp.UserControlled) || comp.TrackReticle && !w.Target.IsFakeTarget; if (!IsClient && (w.SeekTarget || w.TrackTarget && gridAi.TargetResetTick == Tick && !comp.UserControlled) && !w.AcquiringTarget && (compCurPlayer.ControlType == ControlType.None || compCurPlayer.ControlType == ControlType.Ui)) { w.AcquiringTarget = true; AcquireTargets.Add(w); } else if (w.IsTurret && !w.TrackTarget && !w.Target.HasTarget && gridAi.TargetingInfo.TargetInRange) { w.Target = w.Comp.TrackingWeapon.Target; } if (w.Target.TargetChanged) // Target changed { w.TargetChanged(); } /// /// Check weapon's turret to see if its time to go home /// if (w.TurretMode && (!w.Target.HasTarget && !w.ReturingHome && !w.IsHome && Tick - w.Target.ExpiredTick > 300) || comp.UserControlled != comp.WasControlled && !comp.UserControlled) { w.TurretHomePosition(comp.WasControlled); } /// /// Determine if its time to shoot /// /// w.AiShooting = (w.Target.TargetLock || w.System.DelayCeaseFire && !w.Target.IsAligned && Tick - w.CeaseFireDelayTick <= w.System.CeaseFireDelay) && !comp.UserControlled; var reloading = (!w.ActiveAmmoDef.AmmoDef.Const.EnergyAmmo || w.ActiveAmmoDef.AmmoDef.Const.MustCharge) && (w.State.Sync.Reloading || w.OutOfAmmo); var canShoot = !w.State.Sync.Overheated && !reloading; var fakeTarget = overRides.TargetPainter && comp.TrackReticle && w.Target.IsFakeTarget && w.Target.IsAligned; var validShootStates = fakeTarget || w.State.ManualShoot == ShootOn || w.State.ManualShoot == ShootOnce || w.AiShooting && w.State.ManualShoot == ShootOff; var manualShot = (compCurPlayer.ControlType == ControlType.Camera || (overRides.ManualControl && comp.TrackReticle) || w.State.ManualShoot == ShootClick) && !gridAi.SupressMouseShoot && (j % 2 == 0 && leftClick || j == 1 && rightClick); var shoot = (validShootStates || manualShot || w.FinishBurst); w.LockOnFireState = !shoot && w.System.LockOnFocus && gridAi.Focus.HasFocus; if (canShoot && (shoot || w.LockOnFireState)) { if ((gridAi.AvailablePowerChanged || gridAi.RequestedPowerChanged || (w.RecalcPower && Tick60)) && !w.ActiveAmmoDef.AmmoDef.Const.MustCharge) { if ((!gridAi.RequestIncrease || gridAi.PowerIncrease) && !Tick60) { w.RecalcPower = true; } else { w.RecalcPower = false; w.Timings.ChargeDelayTicks = 0; } } if (w.Timings.ChargeDelayTicks == 0 || w.Timings.ChargeUntilTick <= Tick) { if (!w.RequestedPower && !w.ActiveAmmoDef.AmmoDef.Const.MustCharge && !w.System.DesignatorWeapon) { gridAi.RequestedWeaponsDraw += w.RequiredPower; w.RequestedPower = true; } ShootingWeapons.Add(w); } else if (w.Timings.ChargeUntilTick > Tick && !w.ActiveAmmoDef.AmmoDef.Const.MustCharge) { w.State.Sync.Charging = true; w.StopShooting(false, false); } } else if (w.IsShooting) { if (!w.System.DelayCeaseFire || !w.Target.IsAligned && Tick - w.CeaseFireDelayTick > w.System.CeaseFireDelay) { w.StopShooting(); } else if (w.System.DelayCeaseFire && w.Target.IsAligned) { w.CeaseFireDelayTick = Tick; } } else if (w.BarrelSpinning) { w.SpinBarrel(true); } if (comp.Debug && !DedicatedServer) { WeaponDebug(w); } } } } gridAi.OverPowered = gridAi.RequestedWeaponsDraw > 0 && gridAi.RequestedWeaponsDraw > gridAi.GridMaxPower; } } if (DbCallBackComplete && DbsToUpdate.Count > 0 && DbTask.IsComplete) { UpdateDbsInQueue(); } }