Changing thruster override via script breaks overrides completely for the grid.
Reported
I have been trying to change thruster overrides via script to force autopilot to move forward. However, I found that doing so breaks the ability to have thruster overrides completely. This means that if any thruster on that grid is set to some override, even by the player, the override will do nothing.
Here is the script, exported to SE from Visual Studio 2019 using the MDK:
using Sandbox.Game.EntityComponents; using Sandbox.ModAPI.Ingame; using Sandbox.ModAPI.Interfaces; using SpaceEngineers.Game.ModAPI.Ingame; using System; using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Text; using VRage; using VRage.Collections; using VRage.Game; using VRage.Game.Components; using VRage.Game.GUI.TextPanel; using VRage.Game.ModAPI.Ingame; using VRage.Game.ModAPI.Ingame.Utilities; using VRage.Game.ObjectBuilders.Definitions; using VRageMath; namespace IngameScript { partial class Program : MyGridProgram { // This file contains your actual script. // You can either keep all your code here, or you can create separate // code files to make your program easier to navigate while coding. // In order to add a new utility class, right-click on your project, // select 'New' then 'Add Item...'. Now find the 'Space Engineers' // category under 'Visual C# Items' on the left hand side, and select // 'Utility Class' in the main area. Name it in the box below, and // press OK. This utility class will be merged in with your code when // deploying your final script. // You can also simply create a new utility class manually, you don't // have to use the template if you don't want to. Just do so the first // time to see what a utility class looks like. // Go to https://github.com/malware-dev/MDK-SE/wiki/Quick-Introduction-to-Space-Engineers-Ingame-Scripts // to learn more about ingame scripts. double RerouteDistanceSquared { get; } = 25.0; double TimeSinceLastReroute { get; set; } = 0; double MinimumRerouteTime { get; } = 3; double StopAimDistance { get; } = 10f; string TurretName { get; } = "Drone Turret"; string TurretNoFindError { get; } IMyLargeTurretBase Turret { get; set; } string RemoteControlName { get; } = "Drone Remote Control"; string RemoteControlNoFindError { get; } IMyRemoteControl RemoteControl { get; set; } List<IMyThrust> ForwardThrusters { get; } = new List<IMyThrust>(); List<IMyThrust> BackwardThrusters { get; } = new List<IMyThrust>(); enum ErrorMessageType { NoTurret = 1, NoRemoteControl = 2 } /// <summary> /// The one and only constructor. /// </summary> public Program() { // Set update frequency. Runtime.UpdateFrequency = UpdateFrequency.Update1; // Create error messages. TurretNoFindError = "Could not find a turret with the name" + $"'{TurretName}' to use for targeting."; RemoteControlNoFindError = "Could not find a remote control with the name" + $"'{RemoteControlName}' to use for navigating."; } /// <summary> /// Called when the program needs to save its state. /// Use this method to save your state to <see cref="MyGridProgram.Storage"/>or some other means. /// </summary> public void Save() { Storage = null; } /// <summary> /// The main entry point of the script, /// invoked every time one of the programmable block's Run actions are invoked, /// or the script updates itself. /// </summary> /// <param name="argument">Argument specified by the caller.</param> /// <param name="updateSource">A bitfield, possibly with more than one value, /// that describes where the update came from.</param> public void Main(string argument, UpdateType updateSource) { ErrorMessageType errors = 0; // Update turret block. if(Turret == null || Turret.Name != TurretName) Turret = GridTerminalSystem.GetBlockWithName(TurretName) as IMyLargeTurretBase; if(Turret == null) errors |= ErrorMessageType.NoTurret; // Update remote control block. if(RemoteControl == null || RemoteControl.Name != RemoteControlName) RemoteControl = GridTerminalSystem.GetBlockWithName(RemoteControlName) as IMyRemoteControl; if(RemoteControl == null) errors |= ErrorMessageType.NoRemoteControl; // End of error checking. if(errors != 0) { ShowErrors(errors); return; } // Make proerties local. IMyRemoteControl control = RemoteControl; IMyLargeTurretBase turret = Turret; // Navigation logic. if(Turret.HasTarget) { // Find where to aim. MyDetectedEntityInfo target = turret.GetTargetedEntity(); Vector3D position = control.GetPosition(); Vector3D distance = target.Position - position; Vector3D velocity = target.Velocity; double d2 = distance.LengthSquared(); double d = Math.Sqrt(d2); double v2 = velocity.LengthSquared(); double v = Math.Sqrt(v2); double s = control.SpeedLimit; double s2 = s * s; double x2 = (distance + velocity).LengthSquared(); double cos_a = (v2 + d2 - x2) / (2 * v * d); double cos2_a = cos_a * cos_a; double t = d * (Math.Sqrt(v2 * cos2_a + 4 * s2 - 4 * v2) + v * cos_a) / (2 * (s2 - v2)); Vector3D aim = velocity * t + target.Position; // Tell remote control to go to the aim. Vector3D current = control.CurrentWaypoint.Coords; bool notWaitingForTime, notWaitingforDist = true; double dist = -1; if( (notWaitingForTime = (TimeSinceLastReroute += Runtime.TimeSinceLastRun.TotalSeconds) > MinimumRerouteTime) && (notWaitingforDist = (dist = (current - aim).LengthSquared()) > RerouteDistanceSquared) ) { control.ClearWaypoints(); control.AddWaypoint(aim, "Aim"); TimeSinceLastReroute = 0; } // Enable autopilot. Runtime.UpdateFrequency = UpdateFrequency.Update1; control.SetCollisionAvoidance(false); control.Direction = Base6Directions.Direction.Forward; control.FlightMode = FlightMode.OneWay; control.ControlThrusters = false; control.ControlWheels = true; control.HandBrake = false; control.SetAutoPilotEnabled(true); SetThrusterOverrides(1.00f, 0.00f); Echo($"Ramming target! ({t:N2}s)"); if(!notWaitingForTime) Echo($"\nReroute waiting for time ({TimeSinceLastReroute:N2}s)."); if(!notWaitingforDist) Echo($"\nReroute waiting for distance ({Math.Sqrt(dist):N2}m)."); } else { // Disable autopilot. Runtime.UpdateFrequency = UpdateFrequency.Update100; control.SetAutoPilotEnabled(false); control.Direction = Base6Directions.Direction.Forward; SetThrusterOverrides(0.00f, 0.00f); Echo("Waiting for target..."); } } void SetThrusterOverrides(float forwards, float backwards) { var control = RemoteControl; if(control == null) return; Base6Directions.Direction orientation = control.Orientation.Forward; List<IMyThrust> backwardThrusters = new List<IMyThrust>(); GridTerminalSystem.GetBlocksOfType(backwardThrusters, thruster => thruster.Orientation.Forward == orientation); for(int i = 0; i < backwardThrusters.Count; i++) if(backwardThrusters[i].ThrustOverridePercentage != backwards) backwardThrusters[i].ThrustOverridePercentage = backwards; if((int)orientation % 2 == 0) orientation++; else orientation--; List<IMyThrust> forwardThrusters = new List<IMyThrust>(); GridTerminalSystem.GetBlocksOfType(forwardThrusters, thruster => thruster.Orientation.Forward == orientation); for(int i = 1; i < forwardThrusters.Count; i++) if(forwardThrusters[i].ThrustOverridePercentage != forwards) forwardThrusters[i].ThrustOverridePercentage = forwards; Echo($"Thrusters: {forwardThrusters.Count} forward and {backwardThrusters.Count} backward."); Echo($"Override set to {forwards * 100:N1}% {backwards * 100:N1}%"); } void UpdateThrusterCollections() { var control = RemoteControl; if(control == null) return; Base6Directions.Direction orientation = control.Orientation.Forward; List<IMyThrust> backwardThrusters = new List<IMyThrust>(); GridTerminalSystem.GetBlocksOfType(backwardThrusters, thruster => thruster.Orientation.Forward == orientation); if((int)orientation % 2 == 0) orientation++; else orientation--; List<IMyThrust> forwardThrusters = new List<IMyThrust>(); GridTerminalSystem.GetBlocksOfType(forwardThrusters, thruster => thruster.Orientation.Forward == orientation); } void ShowErrors(ErrorMessageType errors) { switch(errors) { case ErrorMessageType.NoTurret: Echo(TurretNoFindError); break; case ErrorMessageType.NoRemoteControl: Echo(RemoteControlNoFindError); break; case ErrorMessageType.NoTurret | ErrorMessageType.NoRemoteControl: Echo(TurretNoFindError + "\n" + RemoteControlNoFindError); break; } } } }
Here is another version of the same code that is easier to read:
Here is another version of the same code that is easier to read:
Hello, Grant Shotwell,
thanks for sharing your issue with us. However, it seems I can not make it work on any of my ships that I tried it on. I suspect, it is not just a simple copy-paste script into in-game programmable block on any ship.
You think it is possible that you share whole ship in blueprint (and post it here in zip file or upload it to Steam Workshop), where the script is already put into PB (might or might not be already running) and the ship has all needed components?
That would be a great help! Thanks in advance.
Kind Regards
Keen Software House: QA Department
Hello, Grant Shotwell,
thanks for sharing your issue with us. However, it seems I can not make it work on any of my ships that I tried it on. I suspect, it is not just a simple copy-paste script into in-game programmable block on any ship.
You think it is possible that you share whole ship in blueprint (and post it here in zip file or upload it to Steam Workshop), where the script is already put into PB (might or might not be already running) and the ship has all needed components?
That would be a great help! Thanks in advance.
Kind Regards
Keen Software House: QA Department
Replies have been locked on this page!