Sedrowow

supply drop script help

May 7th, 2025 (edited)
497
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 38.10 KB | None | 0 0
  1. // Move these outside the Program class as top-level methods
  2. public static Vector3D GetNaturalGravity(IMyRemoteControl rc)
  3. {
  4.     return rc.GetTotalGravity();
  5. }
  6.  
  7. public static double GetAltitude(IMyRemoteControl rc)
  8. {
  9.     Vector3D planetCenter;
  10.     return rc.TryGetPlanetPosition(out planetCenter) ?
  11.         Vector3D.Distance(rc.GetPosition(), planetCenter) - rc.GetRadius() : 0;
  12. }
  13.  
  14. public static Vector3D GetVelocity(IMyRemoteControl rc)
  15. {
  16.     return rc.GetShipVelocities().LinearVelocity;
  17. }
  18.  
  19. // Enum for script states
  20. enum DropPodState
  21. {
  22.     Idle,               // Waiting for GOAL
  23.     AwaitingLaunch,     // GOAL set, waiting for LAUNCH
  24.     Initializing,       // Finding blocks, loading settings
  25.     AwaitingPhysicalRelease, // LAUNCH command received, waiting for manual detach ('release' argument)
  26.     Ascending,          // Getting out of gravity
  27.     HighAltitudeCruise, // Navigating to target at high altitude
  28.     Descending,         // Reducing altitude
  29.     Landing,            // Controlled touchdown
  30.     Finished,           // Mission complete
  31.     Error               // Something went wrong
  32. }
  33.  
  34. // Struct to hold settings - Defined only ONCE
  35. public struct DropPodSettings
  36. {
  37.     public double AscentGravityThreshold;
  38.     public double MinCruiseAltitude;
  39.     public double DescentAltitude;
  40.     public double ParachuteAltitude;
  41.     public double LandingSpeedThreshold;
  42.     public double FinalLandingAltitude;
  43.     public double ThrustMultiplier;
  44.     public double GyroMultiplier; // New setting
  45.  
  46.     // Default values
  47.     public DropPodSettings(bool isDefault = true)
  48.     {
  49.         AscentGravityThreshold = 0.1;
  50.         MinCruiseAltitude = 40000; // meters from planet center or surface approx.
  51.         DescentAltitude = 3000; // meters above ground (RC.GetAltitude())
  52.         ParachuteAltitude = 800; // meters above ground
  53.         LandingSpeedThreshold = 5; // m/s
  54.         FinalLandingAltitude = 3; // meters above ground (allow slight height before landing gear touch)
  55.         ThrustMultiplier = 0.8;
  56.         GyroMultiplier = 5.0; // Default gyro sensitivity
  57.     }
  58. }
  59.  
  60.  
  61. DropPodState currentState = DropPodState.Idle;
  62. Vector3D targetGPS;
  63. // Store state data for persistence (CurrentState, TargetGPS, etc.)
  64. string storedState = "";
  65.  
  66. // --- Block Lists (populated in InitializeBlocks) ---
  67. IMyRemoteControl remoteControl;
  68. List<IMyThrust> upThrusters = new List<IMyThrust>();
  69. List<IMyThrust> downThrusters = new List<IMyThrust>();
  70. List<IMyThrust> forwardThrusters = new List<IMyThrust>();
  71. List<IMyThrust> backwardThrusters = new List<IMyThrust>();
  72. List<IMyThrust> leftThrusters = new List<IMyThrust>();
  73. List<IMyThrust> rightThrusters = new List<IMyThrust>();
  74. List<IMyGyro> gyros = new List<IMyGyro>();
  75. List<IMyParachute> parachutes = new List<IMyParachute>();
  76. // Add your release mechanism block reference here (Connector/Merge Block)
  77. // IMyShipConnector releaseConnector;
  78.  
  79. // --- Configuration Settings (Loaded from Custom Data) ---
  80. DropPodSettings settings = new DropPodSettings();
  81.  
  82. bool parachutesAvailable = false;
  83. bool launched = false; // Flag to indicate if the pod has been released (via 'release' argument)
  84.  
  85.  
  86. // --- Constructor ---
  87. public Program()
  88. {
  89.     // Set update frequency
  90.     Runtime.UpdateFrequency = UpdateFrequency.Update10; // Start lower
  91.  
  92.     // Load state from Storage
  93.     LoadState();
  94.  
  95.     // Load settings from Custom Data (or print defaults if empty)
  96.     LoadSettings();
  97.  
  98.     // Initial echo
  99.     Echo("Script loaded. Current State: " + currentState.ToString());
  100.     EchoSettings();
  101.  
  102.     // If not in Idle, try to ensure blocks are found and settings are loaded
  103.     if (currentState != DropPodState.Idle)
  104.     {
  105.         // Re-initialize blocks if needed (e.g., after game load)
  106.         InitializeBlocks(); // This just finds blocks, doesn't change state
  107.         if (remoteControl == null && currentState != DropPodState.Error)
  108.         {
  109.             SetState(DropPodState.Error, "Failed to find Remote Control block on load.");
  110.         }
  111.     }
  112.     else
  113.     {
  114.         // In Idle, prompt user
  115.         Echo("Send 'GOAL GPS:...' to set target.");
  116.     }
  117. }
  118.  
  119. // --- Save/Load State ---
  120. void SaveState()
  121. {
  122.     // Save current state and target GPS to Storage
  123.     storedState = currentState.ToString() + "|" + (targetGPS != Vector3D.Zero ? targetGPS.ToString() : "");
  124.     Storage = storedState;
  125. }
  126.  
  127. void LoadState()
  128. {
  129.     if (!string.IsNullOrWhiteSpace(Storage))
  130.     {
  131.         string[] parts = Storage.Split('|');
  132.         if (parts.Length > 0) Enum.TryParse(parts[0], out currentState);
  133.         if (parts.Length > 1 && !string.IsNullOrWhiteSpace(parts[1]))
  134.         {
  135.             Vector3D.TryParse(parts[1], out targetGPS);
  136.         }
  137.         Echo("Loaded state: " + currentState.ToString());
  138.         if (targetGPS != Vector3D.Zero) Echo("Loaded target: " + targetGPS.ToString());
  139.  
  140.         // Adjust update frequency immediately based on loaded state if necessary
  141.         switch (currentState)
  142.         {
  143.             case DropPodState.Ascending:
  144.             case DropPodState.HighAltitudeCruise:
  145.             case DropPodState.Descending:
  146.             case DropPodState.Landing:
  147.                 Runtime.UpdateFrequency = UpdateFrequency.Update1;
  148.                 break;
  149.             default:
  150.                 Runtime.UpdateFrequency = UpdateFrequency.Update10;
  151.                 break;
  152.         }
  153.     }
  154.     else
  155.     {
  156.         currentState = DropPodState.Idle;
  157.         Echo("No saved state found. Starting in Idle.");
  158.     }
  159. }
  160.  
  161. // --- Custom Data Settings Handling ---
  162. void LoadSettings()
  163. {
  164.     if (string.IsNullOrWhiteSpace(Me.CustomData))
  165.     {
  166.         Echo("Custom Data is empty. Printing default settings.");
  167.         PrintDefaultSettings();
  168.         // Use default settings instance already created
  169.     }
  170.     else
  171.     {
  172.         Echo("Loading settings from Custom Data...");
  173.         settings = ParseSettings(Me.CustomData);
  174.         Echo("Settings loaded.");
  175.     }
  176. }
  177.  
  178. void PrintDefaultSettings()
  179. {
  180.     StringBuilder sb = new StringBuilder();
  181.     sb.AppendLine("# Drop Pod Script Settings");
  182.     sb.AppendLine("# Edit these values to customize behavior.");
  183.     sb.AppendLine("# Lines starting with # are comments.");
  184.     sb.AppendLine("# Use key=value format.");
  185.     sb.AppendLine("");
  186.     sb.AppendLine($"AscentGravityThreshold={settings.AscentGravityThreshold}");
  187.     sb.AppendLine($"MinCruiseAltitude={settings.MinCruiseAltitude}");
  188.     sb.AppendLine($"DescentAltitude={settings.DescentAltitude}");
  189.     sb.AppendLine($"ParachuteAltitude={settings.ParachuteAltitude}");
  190.     sb.AppendLine($"LandingSpeedThreshold={settings.LandingSpeedThreshold}");
  191.     sb.AppendLine($"FinalLandingAltitude={settings.FinalLandingAltitude}");
  192.     sb.AppendLine($"ThrustMultiplier={settings.ThrustMultiplier}");
  193.     sb.AppendLine($"GyroMultiplier={settings.GyroMultiplier}"); // Added setting for gyro sensitivity
  194.     // Add other settings here as needed
  195.     Me.CustomData = sb.ToString();
  196. }
  197.  
  198. DropPodSettings ParseSettings(string customData)
  199. {
  200.     DropPodSettings loadedSettings = new DropPodSettings();
  201.     var lines = customData.Split('\n');
  202.     foreach (var line in lines)
  203.     {
  204.         var trimmedLine = line.Trim();
  205.         if (trimmedLine.StartsWith("#") || string.IsNullOrWhiteSpace(trimmedLine)) continue;
  206.  
  207.         var parts = trimmedLine.Split('=');
  208.         if (parts.Length != 2) continue;
  209.  
  210.         string key = parts[0].Trim();
  211.         string value = parts[1].Trim();
  212.  
  213.         // Parse specific settings
  214.         double doubleVal;
  215.         // Using basic TryParse as Globalization is not available
  216.         if (double.TryParse(value, out doubleVal))
  217.         {
  218.             switch (key)
  219.             {
  220.                 case "AscentGravityThreshold": loadedSettings.AscentGravityThreshold = doubleVal; break;
  221.                 case "MinCruiseAltitude": loadedSettings.MinCruiseAltitude = doubleVal; break;
  222.                 case "DescentAltitude": loadedSettings.DescentAltitude = doubleVal; break;
  223.                 case "ParachuteAltitude": loadedSettings.ParachuteAltitude = doubleVal; break;
  224.                 case "LandingSpeedThreshold": loadedSettings.LandingSpeedThreshold = doubleVal; break;
  225.                 case "FinalLandingAltitude": loadedSettings.FinalLandingAltitude = doubleVal; break;
  226.                 case "ThrustMultiplier": loadedSettings.ThrustMultiplier = doubleVal; break;
  227.                 case "GyroMultiplier": loadedSettings.GyroMultiplier = doubleVal; break;
  228.                     // Add cases for other double settings
  229.             }
  230.         }
  231.         // Add parsing for other types (int, bool, string) if needed
  232.     }
  233.     return loadedSettings;
  234. }
  235.  
  236. void EchoSettings()
  237. {
  238.     Echo("--- Settings ---");
  239.     Echo($"Ascent Gravity: {settings.AscentGravityThreshold:F2} m/s²");
  240.     Echo($"Min Cruise Alt: {settings.MinCruiseAltitude:F0} m");
  241.     Echo($"Descent Alt:    {settings.DescentAltitude:F0} m");
  242.     Echo($"Parachute Alt:  {settings.ParachuteAltitude:F0} m");
  243.     Echo($"Landing Speed:  {settings.LandingSpeedThreshold:F1} m/s");
  244.     Echo($"Final Land Alt: {settings.FinalLandingAltitude:F0} m");
  245.     Echo($"Thrust Multi:   {settings.ThrustMultiplier:F2}");
  246.     Echo($"Gyro Multi:     {settings.GyroMultiplier:F2}");
  247.     Echo("----------------");
  248. }
  249.  
  250.  
  251. // --- Main Method ---
  252. public void Main(string argument, UpdateType updateSource)
  253. {
  254.     Echo("State: " + currentState.ToString());
  255.     Echo("Target: " + (targetGPS != Vector3D.Zero ? targetGPS.ToString() : "None"));
  256.     Echo("Time: " + Runtime.TimeSinceLastRun.TotalSeconds.ToString("F3") + "s"); // Echo last run time
  257.  
  258.     // Handle arguments based on current state
  259.     if (argument.Length > 0)
  260.     {
  261.         string[] args = argument.Split(' ');
  262.         string command = args[0].ToUpper();
  263.  
  264.         switch (currentState)
  265.         {
  266.             case DropPodState.Idle:
  267.                 if (command == "GOAL" && args.Length > 1)
  268.                 {
  269.                     string gpsString = argument.Substring("GOAL ".Length).Trim();
  270.                     Vector3D parsedGps;
  271.                     if (TryParseGps(gpsString, out parsedGps))
  272.                     {
  273.                         targetGPS = parsedGps;
  274.                         SetState(DropPodState.AwaitingLaunch);
  275.                         Echo($"Target set to {targetGPS.ToString()}. Send 'LAUNCH' to begin.");
  276.                     }
  277.                     else
  278.                     {
  279.                         Echo("Invalid GPS format. Use 'GOAL GPS:Name:X:Y:Z:'.");
  280.                     }
  281.                 }
  282.                 else { Echo("Send 'GOAL GPS:...' to set target."); }
  283.                 break;
  284.  
  285.             case DropPodState.AwaitingLaunch:
  286.                 if (command == "LAUNCH")
  287.                 {
  288.                     SetState(DropPodState.Initializing);
  289.                     Echo("Launch command received. Initializing...");
  290.                 }
  291.                 else if (command == "GOAL" && args.Length > 1) // Allow changing target
  292.                 {
  293.                     string gpsString = argument.Substring("GOAL ".Length).Trim();
  294.                     Vector3D parsedGps;
  295.                     if (TryParseGps(gpsString, out parsedGps))
  296.                     {
  297.                         targetGPS = parsedGps;
  298.                         Echo($"Target updated to {targetGPS.ToString()}. Send 'LAUNCH' to begin.");
  299.                     }
  300.                     else
  301.                     {
  302.                         Echo("Invalid GPS format. Use 'GOAL GPS:Name:X:Y:Z:'.");
  303.                     }
  304.                 }
  305.                 else { Echo("Target set. Send 'LAUNCH' to begin."); }
  306.                 break;
  307.  
  308.             case DropPodState.AwaitingPhysicalRelease:
  309.                 if (command == "RELEASE" || command == "LAUNCHED") // Argument to signal manual detachment
  310.                 {
  311.                     launched = true; // Flag set
  312.                     SetState(DropPodState.Ascending);
  313.                     Echo("Release confirmed. Initiating ascent.");
  314.                 }
  315.                 else { Echo("Waiting for physical release. Disconnect and send 'RELEASE' argument."); }
  316.                 break;
  317.  
  318.             case DropPodState.Finished:
  319.             case DropPodState.Error:
  320.                 if (command == "RESET")
  321.                 {
  322.                     targetGPS = Vector3D.Zero; // Clear target
  323.                     launched = false;
  324.                     SetState(DropPodState.Idle);
  325.                     Echo("Script reset. Send 'GOAL GPS:...' to start again.");
  326.                 }
  327.                 break;
  328.  
  329.             default:
  330.                 // Ignore arguments in active flight states unless specifically handled (e.g., abort?)
  331.                 Echo("Flight in progress. Ignoring command.");
  332.                 break;
  333.         }
  334.     }
  335.  
  336.  
  337.     // State Machine Logic (called every update tick if frequency > None)
  338.     switch (currentState)
  339.     {
  340.         case DropPodState.Initializing:
  341.             HandleInitializing();
  342.             break;
  343.         case DropPodState.AwaitingPhysicalRelease:
  344.             // Just waiting for the 'release' argument
  345.             break;
  346.         case DropPodState.Ascending:
  347.             HandleAscending();
  348.             break;
  349.         case DropPodState.HighAltitudeCruise:
  350.             HandleHighAltitudeCruise();
  351.             break;
  352.         case DropPodState.Descending:
  353.             HandleDescending();
  354.             break;
  355.         case DropPodState.Landing:
  356.             HandleLanding();
  357.             break;
  358.         case DropPodState.Finished:
  359.             // Do nothing, waiting for reset
  360.             break;
  361.         case DropPodState.Error:
  362.             // Display error, waiting for reset
  363.             break;
  364.     }
  365.  
  366.     // Save state at the end of Main
  367.     SaveState();
  368. }
  369.  
  370. // --- State Handler Methods ---
  371.  
  372. void SetState(DropPodState newState, string errorMessage = null)
  373. {
  374.     currentState = newState;
  375.     Echo("Transitioned to State: " + currentState.ToString());
  376.  
  377.     // Actions on state entry
  378.     switch (newState)
  379.     {
  380.         case DropPodState.Idle:
  381.         case DropPodState.AwaitingLaunch:
  382.             Runtime.UpdateFrequency = UpdateFrequency.Update10; // Low frequency while waiting
  383.             SetThrusterOverrides(0);
  384.             SetGyroOverride(false);
  385.             // remoteControl?.SetAutoPilotEnabled(false); // Commenting out if RC methods are an issue
  386.             break;
  387.         case DropPodState.Initializing:
  388.             Runtime.UpdateFrequency = UpdateFrequency.Update10; // Still low freq
  389.             InitializeBlocks(); // Find blocks
  390.             LoadSettings(); // Reload settings just in case Custom Data was changed
  391.             break;
  392.         case DropPodState.AwaitingPhysicalRelease:
  393.             Runtime.UpdateFrequency = UpdateFrequency.Update10; // Low freq
  394.             SetThrusterOverrides(0); // Ensure everything is off before release
  395.             SetGyroOverride(false);
  396.             // remoteControl?.SetAutoPilotEnabled(false); // Commenting out if RC methods are an issue
  397.             Echo("Ready for release. Disconnect the pod and send 'RELEASE' argument.");
  398.             break;
  399.         case DropPodState.Ascending:
  400.             Runtime.UpdateFrequency = UpdateFrequency.Update1; // High frequency for flight
  401.             SetGyroOverride(true); // Enable gyro override for orientation control
  402.                                    // remoteControl?.SetAutoPilotEnabled(false); // Commenting out if RC methods are an issue
  403.             break;
  404.         case DropPodState.HighAltitudeCruise:
  405.             Runtime.UpdateFrequency = UpdateFrequency.Update1; // High frequency for navigation/monitoring
  406.             SetGyroOverride(false); // Let RC handle orientation
  407.                                     // RC autopilot setup is done in HandleHighAltitudeCruise
  408.             break;
  409.         case DropPodState.Descending:
  410.             Runtime.UpdateFrequency = UpdateFrequency.Update1; // High frequency for descent control
  411.                                                                // remoteControl?.SetAutoPilotEnabled(false); // Commenting out if RC methods are an issue
  412.             SetGyroOverride(true); // Manual gyro control for descent orientation
  413.             break;
  414.         case DropPodState.Landing:
  415.             Runtime.UpdateFrequency = UpdateFrequency.Update1; // Critical frequency for soft landing
  416.                                                                // Gyros already enabled
  417.             break;
  418.         case DropPodState.Finished:
  419.             Runtime.UpdateFrequency = UpdateFrequency.None; // Stop script execution
  420.             SetThrusterOverrides(0);
  421.             SetGyroOverride(false);
  422.             // remoteControl?.SetAutoPilotEnabled(false); // Commenting out if RC methods are an issue
  423.             Echo("Mission Complete!");
  424.             break;
  425.         case DropPodState.Error:
  426.             Runtime.UpdateFrequency = UpdateFrequency.None; // Stop script execution
  427.             SetThrusterOverrides(0);
  428.             SetGyroOverride(false);
  429.             // remoteControl?.SetAutoPilotEnabled(false); // Commenting out if RC methods are an issue
  430.             Echo("Error: " + errorMessage);
  431.             break;
  432.     }
  433.     SaveState(); // Save state change
  434. }
  435.  
  436. void HandleInitializing()
  437. {
  438.     Echo("Initializing...");
  439.     // Blocks already found in SetState.
  440.     // Settings already loaded in SetState.
  441.  
  442.     if (remoteControl == null)
  443.     {
  444.         SetState(DropPodState.Error, "No Remote Control block found.");
  445.         return;
  446.     }
  447.     if (upThrusters.Count == 0)
  448.     {
  449.         SetState(DropPodState.Error, "No 'Up' thrusters found. (Thrusters pointing down relative to grid)");
  450.         return;
  451.     }
  452.     // Warnings for missing directional thrusters can be echoed but don't need to be fatal errors
  453.  
  454.     parachutesAvailable = parachutes.Count > 0;
  455.     if (parachutesAvailable) Echo("Parachutes found."); else Echo("No parachutes found. Relying on thrusters for landing.");
  456.  
  457.     // Check if a target was actually set before launching
  458.     if (targetGPS == Vector3D.Zero)
  459.     {
  460.         SetState(DropPodState.Error, "No target GPS set. Use 'GOAL GPS:...' first.");
  461.         return;
  462.     }
  463.  
  464.     Echo("Initialization complete. Ready for physical release.");
  465.     SetState(DropPodState.AwaitingPhysicalRelease);
  466. }
  467.  
  468. // Replace your HandleAscending method
  469. void HandleAscending()
  470. {
  471.     if (remoteControl == null) { SetState(DropPodState.Error, "Remote Control lost during ascent."); return; }
  472.  
  473.     Vector3D gravity = remoteControl.GetNaturalGravity();
  474.     double gravityMagnitude = gravity.Length();
  475.     Vector3D currentPos = remoteControl.GetPosition();
  476.     double currentAltitude = remoteControl.GetAltitude();
  477.  
  478.     if (gravityMagnitude < settings.AscentGravityThreshold && currentAltitude > settings.MinCruiseAltitude / 2)
  479.     {
  480.         SetThrusterOverrides(0);
  481.         SetState(DropPodState.HighAltitudeCruise);
  482.         Echo("Reached space altitude. Initiating cruise.");
  483.         return;
  484.     }
  485.  
  486.     // Orient grid straight up
  487.     if (gravityMagnitude > 0.01)
  488.     {
  489.         Vector3D antiGravity = -Vector3D.Normalize(gravity);
  490.         AlignGridToVector(antiGravity, settings.GyroMultiplier);
  491.     }
  492.     else
  493.     {
  494.         SetGyroOverride(true, Vector3D.Zero);
  495.     }
  496.  
  497.     SetThrusterOverrides((float)settings.ThrustMultiplier, Base6Directions.Direction.Up);
  498.     Echo($"Ascending. Gravity: {gravityMagnitude:F2} m/s². Altitude: {currentAltitude:F0} m");
  499. }
  500.  
  501. // Update HandleHighAltitudeCruise method
  502. void HandleHighAltitudeCruise()
  503. {
  504.     if (remoteControl == null) { SetState(DropPodState.Error, "Remote Control lost during cruise."); return; }
  505.  
  506.     Vector3D currentPos = remoteControl.GetPosition();
  507.     Vector3D targetPos = targetGPS;
  508.     Vector3D planetCenter;
  509.     double currentAltitude = GetAltitude(remoteControl);
  510.    
  511.     // Get planet center for orbital navigation
  512.     if (!remoteControl.TryGetPlanetPosition(out planetCenter))
  513.     {
  514.         SetState(DropPodState.Error, "Cannot determine planet position.");
  515.         return;
  516.     }
  517.  
  518.     // Calculate positions relative to planet center
  519.     Vector3D currentPosFromCenter = currentPos - planetCenter;
  520.     Vector3D targetPosFromCenter = targetPos - planetCenter;
  521.  
  522.     // Calculate desired orbit position (above target at cruise altitude)
  523.     double desiredOrbitRadius = Math.Max(settings.MinCruiseAltitude, currentPosFromCenter.Length());
  524.     Vector3D desiredOrbitPos = planetCenter + Vector3D.Normalize(targetPosFromCenter) * desiredOrbitRadius;
  525.  
  526.     // Calculate if we're roughly above the target
  527.     double angleToTarget = Math.Acos(
  528.         Vector3D.Dot(Vector3D.Normalize(currentPosFromCenter), Vector3D.Normalize(targetPosFromCenter))
  529.     );
  530.    
  531.     // Convert to degrees for readable comparison
  532.     double angleToTargetDegrees = angleToTarget * 180 / Math.PI;
  533.  
  534.     // If we're above target (within 5 degrees) and at appropriate altitude, start descent
  535.     if (angleToTargetDegrees < 5 && currentAltitude < settings.MinCruiseAltitude * 1.1)
  536.     {
  537.         SetState(DropPodState.Descending);
  538.         Echo($"Above target. Starting descent from {currentAltitude:F0}m");
  539.         return;
  540.     }
  541.  
  542.     // Otherwise, continue orbital movement
  543.     Vector3D velocityDir = remoteControl.GetShipVelocities().LinearVelocity;
  544.     Vector3D gravity = GetNaturalGravity(remoteControl);
  545.    
  546.     // Calculate desired movement direction (tangent to orbit)
  547.     Vector3D orbitNormal = Vector3D.Cross(currentPosFromCenter, targetPosFromCenter);
  548.     if (orbitNormal.LengthSquared() > 0.1)
  549.     {
  550.         Vector3D desiredDirection = Vector3D.Cross(Vector3D.Normalize(currentPosFromCenter), Vector3D.Normalize(orbitNormal));
  551.        
  552.         // Align to orbital direction
  553.         AlignGridToVector(desiredDirection, settings.GyroMultiplier);
  554.        
  555.         // Apply thrust to maintain orbit
  556.         double gravityMagnitude = gravity.Length();
  557.         float thrustLevel = (float)Math.Min(1.0, gravityMagnitude / 9.81);
  558.         SetThrusterOverrides(thrustLevel, Base6Directions.Direction.Forward);
  559.     }
  560.  
  561.     Echo($"Orbiting. Altitude: {currentAltitude:F0}m, Angle to target: {angleToTargetDegrees:F1}°");
  562. }
  563.  
  564. void HandleDescending()
  565. {
  566.     if (remoteControl == null) { SetState(DropPodState.Error, "Remote Control lost during descent."); return; }
  567.     if (downThrusters.Count == 0 && !parachutesAvailable) { SetState(DropPodState.Error, "No downward thrusters or parachutes for descent."); return; }
  568.  
  569.  
  570.     Vector3D gravity = remoteControl.GetNaturalGravity();
  571.     Vector3D currentPos = remoteControl.GetPosition();
  572.     // If GetVelocity is causing errors, you might need to remove or comment out lines using velocity.
  573.     Vector3D velocity = remoteControl.GetVelocity();
  574.     // If GetAltitude is causing errors, you might need to use a different altitude check.
  575.     double altitudeAboveGround = remoteControl.GetAltitude();
  576.     double verticalSpeed = Vector3D.Dot(velocity, Vector3D.Normalize(gravity)); // Positive if moving down
  577.  
  578.     // Orient grid for descent - point "Down" thrusters towards gravity
  579.     Vector3D gravityDirection = Vector3D.Normalize(gravity); // Desired 'Down' direction for the grid
  580.     AlignGridToVector(gravityDirection, settings.GyroMultiplier); // Use gyros to align grid.WorldMatrix.Down with gravityDirection
  581.  
  582.     // Parachute Deployment
  583.     bool areChutesDeployed = parachutes.Count > 0 && parachutes.Any(chute => chute.Status == DoorStatus.Open); // Check if ANY chute is open
  584.     if (parachutesAvailable && altitudeAboveGround < settings.ParachuteAltitude && !areChutesDeployed)
  585.     {
  586.         DeployParachutes();
  587.         // Reduce/kill thrusters if parachutes are main braking
  588.         SetThrusterOverrides(0); // For now, kill all thrusters on chute deploy
  589.         Echo($"Deploying parachutes at {altitudeAboveGround:F0} m.");
  590.         // Transition to Landing immediately as chutes take over primary braking
  591.         SetState(DropPodState.Landing);
  592.         return; // Exit this frame's descent logic to start landing logic
  593.     }
  594.  
  595.     // If not using chutes or above chute altitude, control descent speed with thrusters
  596.     if (!areChutesDeployed && downThrusters.Count > 0)
  597.     {
  598.         // Simple vertical speed control (P controller)
  599.         double targetVerticalSpeed = 10; // Start with a faster descent speed (m/s)
  600.         if (altitudeAboveGround < settings.ParachuteAltitude * 1.5) targetVerticalSpeed = settings.LandingSpeedThreshold * 2; // Slow down as we get closer
  601.  
  602.         double speedError = targetVerticalSpeed - verticalSpeed; // Positive error means too slow (need more push down)
  603.         double thrustMagnitude = MathHelper.Clamp(speedError * 0.2 + gravity.Length() / 9.81f, 0, 1); // P control + scaled gravity compensation
  604.                                                                                                       // Scale gravity comp by ~Earth gravity to normalize
  605.  
  606.         // Apply thrust opposite the gravity vector ('Up' relative to planet) using 'Down' thrusters on grid
  607.         SetThrusterOverrides((float)thrustMagnitude, Base6Directions.Direction.Down); // Down thrusters push Up
  608.  
  609.         // Basic horizontal braking: Kill horizontal velocity as we descend
  610.         Vector3D gravityDirection = Vector3D.Normalize(gravity);
  611.         Vector3D horizontalVelocity = velocity - verticalSpeed * gravityDirection;
  612.         // Needs SetThrustersInDirection helper or rely on prior RC accuracy
  613.     }
  614.  
  615.  
  616.     // Transition to Landing when close enough
  617.     if (altitudeAboveGround < settings.ParachuteAltitude * 1.2 || areChutesDeployed) // Enter landing phase when close or chutes deployed
  618.     {
  619.         SetState(DropPodState.Landing);
  620.         Echo($"Entering landing phase at {altitudeAboveGround:F0} m.");
  621.         return;
  622.     }
  623.  
  624.     // If GetAltitude and GetVelocity are causing errors, you might need to remove or change this Echo line.
  625.     Echo($"Descending. Altitude (RC): {altitudeAboveGround:F0} m. Vertical Speed: {verticalSpeed:F2} m/s");
  626. }
  627.  
  628. void HandleLanding()
  629. {
  630.     if (remoteControl == null) { SetState(DropPodState.Error, "Remote Control lost during landing."); return; }
  631.     if (downThrusters.Count == 0 && !parachutesAvailable) { SetState(DropPodState.Error, "No downward thrusters or parachutes for landing."); return; }
  632.  
  633.  
  634.     Vector3D gravity = remoteControl.GetNaturalGravity();
  635.     Vector3D currentPos = remoteControl.GetPosition();
  636.     // If GetVelocity is causing errors, you might need to remove or comment out lines using velocity.
  637.     Vector3D velocity = remoteControl.GetVelocity();
  638.     // If GetAltitude is causing errors, you might need to use a different altitude check.
  639.     double altitudeAboveGround = remoteControl.GetAltitude();
  640.     double verticalSpeed = Vector3D.Dot(velocity, Vector3D.Normalize(gravity)); // Positive if moving down
  641.  
  642.     // Orient grid (continue pointing 'Down' thrusters towards gravity)
  643.     AlignGridToVector(Vector3D.Normalize(gravity), settings.GyroMultiplier);
  644.  
  645.     // Check for landing success (low speed, low altitude)
  646.     if (Math.Abs(verticalSpeed) < settings.LandingSpeedThreshold && altitudeAboveGround < settings.FinalLandingAltitude)
  647.     {
  648.         SetState(DropPodState.Finished);
  649.         return;
  650.     }
  651.  
  652.     // Landing Thrust Control (if not relying solely on parachutes)
  653.     bool areChutesDeployed = parachutes.Count > 0 && parachutes.Any(chute => chute.Status == DoorStatus.Open);
  654.     if (!areChutesDeployed && downThrusters.Count > 0) // If no chutes, or they failed, or below chute range
  655.     {
  656.         // PID-like control for vertical speed aiming for -LANDING_SPEED_THRESHOLD (up)
  657.         // This is a simplified P controller
  658.         double targetVerticalVelocity = -settings.LandingSpeedThreshold; // Target velocity UP
  659.         double speedError = targetVerticalVelocity - verticalSpeed; // Positive error means too slow (need more push up)
  660.         double verticalThrust = MathHelper.Clamp(speedError * 1.0 + gravity.Length() / 9.81f, 0, 1); // P control + scaled gravity compensation
  661.  
  662.         SetThrusterOverrides((float)verticalThrust, Base6Directions.Direction.Down); // Use down thrusters to push up
  663.  
  664.         // Horizontal braking: Kill horizontal velocity
  665.         Vector3D gravityDirection = Vector3D.Normalize(gravity);
  666.         Vector3D horizontalVelocity = velocity - verticalSpeed * gravityDirection;
  667.         // Needs SetThrustersInDirection helper or rely on prior RC accuracy
  668.     }
  669.     else // If parachutes are deployed, maybe just use thrusters for fine-tuning/horizontal control
  670.     {
  671.         // Use directional thrusters for horizontal movement to zero out horizontal velocity
  672.         Vector3D gravityDirection = Vector3D.Normalize(gravity);
  673.         Vector3D horizontalVelocity = velocity - verticalSpeed * gravityDirection;
  674.         // Needs SetThrustersInDirection helper
  675.     }
  676.  
  677.     // If GetAltitude and GetVelocity are causing errors, you might need to remove or change this Echo line.
  678.     Echo($"Landing. Altitude (RC): {altitudeAboveGround:F0} m. Vertical Speed: {verticalSpeed:F2} m/s. Total Speed: {velocity.Length():F2} m/s");
  679. }
  680.  
  681. void HandleFinished()
  682. {
  683.     Echo("Drop pod landed safely.");
  684.     // Could add logic here to turn off components, lock landing gear, etc.
  685. }
  686.  
  687. void HandleError()
  688. {
  689.     // Error message already displayed by SetState
  690. }
  691.  
  692.  
  693. // --- Helper Methods ---
  694.  
  695. void InitializeBlocks()
  696. {
  697.     // If GetBlockOfType is causing errors, this is a core API issue.
  698.     // You might need to use GridTerminalSystem.SearchBlocksOfName or GetBlocksOfType
  699.     // with type checks as an alternative, but GetBlockOfType<T>() should work.
  700.     remoteControl = GridTerminalSystem.GetBlockOfType<IMyRemoteControl>();
  701.  
  702.     // Clear lists before repopulating
  703.     upThrusters.Clear();
  704.     downThrusters.Clear();
  705.     forwardThrusters.Clear();
  706.     backwardThrusters.Clear();
  707.     leftThrusters.Clear();
  708.     rightThrusters.Clear();
  709.     gyros.Clear();
  710.     parachutes.Clear();
  711.  
  712.     // Find and group thrusters by their thrust direction relative to the grid's forward (+Z)
  713.     // Thruster's WorldMatrix.Backward is the direction the *thrust* is applied
  714.     // Block's Orientation.TransformDirection(Base6Directions.Direction.Backward) gives
  715.     // the direction the thruster is POINTING relative to the grid's local axes.
  716.     // Thrust is applied opposite the direction the nozzle is pointing.
  717.     // Grid +Y is Up, -Y is Down, +X is Right, -X is Left, +Z is Forward, -Z is Backward by convention.
  718.  
  719.     var allThrusters = new List<IMyThrust>();
  720.     // If GetBlocksOfType is causing errors, this is a core API issue.
  721.     GridTerminalSystem.GetBlocksOfType(allThrusters);
  722.  
  723.     foreach (var thruster in allThrusters)
  724.     {
  725.         // Direction the thruster is POINTING relative to the grid's axes
  726.         Base6Directions.Direction thrusterLocalPointingDirection = thruster.Orientation.TransformDirection(Base6Directions.Direction.Backward);
  727.  
  728.         // Thrust is applied in the opposite direction
  729.         Base6Directions.Direction thrustDirection = Base6Directions.GetOppositeDirection(thrusterLocalPointingDirection);
  730.  
  731.         switch (thrustDirection)
  732.         {
  733.             case Base6Directions.Direction.Up: upThrusters.Add(thruster); break;
  734.             case Base6Directions.Direction.Down: downThrusters.Add(thruster); break;
  735.             case Base6Directions.Direction.Forward: forwardThrusters.Add(thruster); break;
  736.             case Base6Directions.Direction.Backward: backwardThrusters.Add(thruster); break;
  737.             case Base6Directions.Direction.Left: leftThrusters.Add(thruster); break;
  738.             case Base6Directions.Direction.Right: rightThrusters.Add(thruster); break;
  739.         }
  740.     }
  741.  
  742.     // If GetBlocksOfType is causing errors for Gyros and Parachutes, it's a core API issue.
  743.     GridTerminalSystem.GetBlocksOfType(gyros);
  744.     GridTerminalSystem.GetBlocksOfType(parachutes);
  745.     // Find your release block here...
  746.     // releaseConnector = GridTerminalSystem.GetBlockOfType<IMyShipConnector>("MyConnectorName"); // Example
  747.  
  748.     Echo($"Found: RC: {remoteControl != null}, Gyros: {gyros.Count}, Chutes: {parachutes.Count}");
  749.     Echo($"Thrusters: U:{upThrusters.Count} D:{downThrusters.Count} F:{forwardThrusters.Count} B:{backwardThrusters.Count} L:{leftThrusters.Count} R:{rightThrusters.Count}");
  750. }
  751.  
  752. // Sets thrust override for thrusters in a specific direction relative to the grid
  753. // Note: This method takes float percentage, ensure values passed are cast or are floats.
  754. void SetThrusterOverrides(float percentage, Base6Directions.Direction? direction = null)
  755. {
  756.     percentage = MathHelper.Clamp(percentage, 0f, 1f); // Ensure percentage is valid
  757.  
  758.     Action<List<IMyThrust>> setOverride = (list) =>
  759.     {
  760.         foreach (var thruster in list) thruster.ThrustOverridePercentage = percentage;
  761.     };
  762.  
  763.     if (direction == null) // Apply to all thrusters if direction is null
  764.     {
  765.         setOverride(upThrusters);
  766.         setOverride(downThrusters);
  767.         setOverride(forwardThrusters);
  768.         setOverride(backwardThrusters);
  769.         setOverride(leftThrusters);
  770.         setOverride(rightThrusters);
  771.     }
  772.     else
  773.     {
  774.         switch (direction.Value)
  775.         {
  776.             case Base6Directions.Direction.Up: setOverride(upThrusters); break;
  777.             case Base6Directions.Direction.Down: setOverride(downThrusters); break;
  778.             case Base6Directions.Direction.Forward: setOverride(forwardThrusters); break;
  779.             case Base6Directions.Direction.Backward: setOverride(backwardThrusters); break;
  780.             case Base6Directions.Direction.Left: setOverride(leftThrusters); break;
  781.             case Base6Directions.Direction.Right: setOverride(rightThrusters); break;
  782.         }
  783.     }
  784. }
  785.  
  786. // Attempts to apply thrust towards a given world direction using relevant thrusters
  787. // This is a simplified approach and might not provide precise control without more math
  788. void SetThrustersInDirection(Vector3D worldDirection, float strength)
  789. {
  790.     if (remoteControl == null) return;
  791.  
  792.     strength = MathHelper.Clamp(strength, 0f, 1f);
  793.  
  794.     // Convert world direction to grid coordinates
  795.     // Construct a MatrixD from the Matrix3x3 rotation - this should work.
  796.     // If new MatrixD(Matrix3x3) is causing errors, this is a core API issue.
  797.     MatrixD worldToGridRotation = MatrixD.Transpose(new MatrixD(remoteControl.WorldMatrix.Rotation));
  798.     Vector3D gridDirection = Vector3D.TransformNormal(worldDirection, worldToGridRotation);
  799.  
  800.     // Apply thrust component-wise (simplified)
  801.     // Apply strength * absolute value of component to the thrusters in that grid direction
  802.     SetThrusterOverrides((float)(strength * Math.Max(0, gridDirection.Y)), Base6Directions.Direction.Up); // Push up in grid +Y
  803.     SetThrusterOverrides((float)(strength * Math.Max(0, -gridDirection.Y)), Base6Directions.Direction.Down); // Push down in grid -Y
  804.     SetThrusterOverrides((float)(strength * Math.Max(0, gridDirection.Z)), Base6Directions.Direction.Forward); // Push forward in grid +Z
  805.     SetThrusterOverrides((float)(strength * Math.Max(0, -gridDirection.Z)), Base6Directions.Direction.Backward); // Push backward in grid -Z
  806.     SetThrusterOverrides((float)(strength * Math.Max(0, -gridDirection.X)), Base6Directions.Direction.Left); // Push left in grid -X
  807.     SetThrusterOverrides((float)(strength * Math.Max(0, gridDirection.X)), Base6Directions.Direction.Right); // Push right in grid +X
  808. }
  809.  
  810.  
  811. void SetGyroOverride(bool enable, Vector3D? pitchYawRollRates = null)
  812. {
  813.     foreach (var gyro in gyros)
  814.     {
  815.         // If GyroOverride, Pitch, Yaw, Roll are causing errors, this is a core API issue.
  816.         gyro.GyroOverride = enable;
  817.         if (enable && pitchYawRollRates.HasValue)
  818.         {
  819.             // Gyro override takes radians per second
  820.             gyro.Pitch = (float)pitchYawRollRates.Value.X;
  821.             gyro.Yaw = (float)pitchYawRollRates.Value.Y;
  822.             gyro.Roll = (float)pitchYawRollRates.Value.Z;
  823.         }
  824.         else if (enable && !pitchYawRollRates.HasValue)
  825.         {
  826.             // Set rates to 0 if overriding without specific rates
  827.             gyro.Pitch = 0;
  828.             gyro.Yaw = 0;
  829.             gyro.Roll = 0;
  830.         }
  831.     }
  832. }
  833.  
  834. // Aligns the grid's WorldMatrix.Up vector to a desiredWorldUp vector
  835. // Applies angular velocity using gyros proportional to the alignment error
  836. void AlignGridToVector(Vector3D desiredDirection, double multiplier)
  837. {
  838.     if (gyros.Count == 0 || remoteControl == null) return;
  839.  
  840.     Matrix worldMatrix = remoteControl.WorldMatrix;
  841.     Vector3D forward = worldMatrix.Forward;
  842.    
  843.     // Calculate rotation
  844.     double angle = Math.Acos(Vector3D.Dot(forward, desiredDirection));
  845.     Vector3D rotationAxis = Vector3D.Cross(forward, desiredDirection);
  846.    
  847.     if (rotationAxis.LengthSquared() < 0.001)
  848.     {
  849.         SetGyroOverride(true, Vector3D.Zero);
  850.         return;
  851.     }
  852.  
  853.     rotationAxis = Vector3D.Normalize(rotationAxis);
  854.    
  855.     // Calculate angular velocity
  856.     Vector3D worldAngularVelocity = rotationAxis * angle * multiplier;
  857.    
  858.     // Convert to local space
  859.     Vector3D localAngularVelocity = Vector3D.TransformNormal(worldAngularVelocity, Matrix.Transpose(worldMatrix));
  860.    
  861.     Vector3D gyroRates = new Vector3D(
  862.         -localAngularVelocity.X,
  863.         localAngularVelocity.Y,
  864.         -localAngularVelocity.Z
  865.     );
  866.  
  867.     SetGyroOverride(true, gyroRates);
  868. }
  869.  
  870.  
  871. void DeployParachutes()
  872. {
  873.     foreach (var chute in parachutes)
  874.     {
  875.         // If OpenDoor is causing errors, this is a core API issue.
  876.         chute.OpenDoor();
  877.         // chute.AutoDeploy = true; // Could use auto deploy as well, but manual is more controllable
  878.     }
  879. }
  880.  
  881. bool TryParseGps(string gpsString, out Vector3D coords)
  882. {
  883.     coords = Vector3D.Zero;
  884.     if (!gpsString.StartsWith("GPS:", StringComparison.OrdinalIgnoreCase)) return false;
  885.  
  886.     string[] parts = gpsString.Substring(4).Split(':');
  887.     if (parts.Length != 4) return false; // Name, X, Y, Z
  888.  
  889.     double x = 0.0, y = 0.0, z = 0.0; // Initialized variables
  890.  
  891.     // Using basic TryParse as Globalization is not available
  892.     // Note: This version might be sensitive to regional number formats (comma vs dot)
  893.     // If double.TryParse is causing errors here, and the CultureInfo version didn't work,
  894.     // it's a fundamental issue with double parsing in your environment.
  895.     if (double.TryParse(parts[1], out x) &&
  896.         double.TryParse(parts[2], out y) &&
  897.         double.TryParse(parts[3], out z))
  898.     {
  899.         coords = new Vector3D(x, y, z);
  900.         return true;
  901.     }
  902.  
  903.     return false;
  904. }
Advertisement
Add Comment
Please, Sign In to add comment