1. This forum is obsolete and read-only. Feel free to contact us at support.keenswh.com

Emergency Stop: save your ship even if you get disconnected

Discussion in 'Programming Released Codes' started by Dr. Novikov, Sep 9, 2015.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. Dr. Novikov

    Dr. Novikov Apprentice Engineer

    Messages:
    263
    [​IMG]

    https://steamcommunity.com/sharedfiles/filedetails/?id=515022499

    Cool story: flying with inertia dampeners is good. It saves uranium. But it is also dangerous. If you get disconnected or accidentally press T, you will lose your ship, just like I did.

    So I found a script by Mustardman24's and used it with sensors. It worked, but sometimes unreliably. It did not work on disconnects or game crashes, and sometimes I lagged out of a fast moving ship's sensor field. So I decided to write my own script and developed a method of detecting if a ship is under control.

    Today I updated the script I wrote several months ago, added a gravity drive disabler, turret control detection, etc, and published it on Steam.

    How to use: have a looping timer run a programmable block with this script and also restart itself every second. You can also run the script with the word "manual" as an argument if you want to stop your ship by a quick key, button panel, sensor, timer, etc.

    Additionally, you can place a timer, name it "TriggerOnShipControlLost", and use this timer to set your own actions that need to be performed when ship control is lost. For example:

    - Turn on a beacon or an antenna and increase their radii to maximum.
    - Toggle some blocks on/off for power saving, so the lost ship stays working and broadcasting longer.
    - Turn on an auto-pilot for flying your ship to a predefined GPS location.
    - Turn off gravity drives but leave other gravity generators working (comment out the DisableGravityDrives();).

    Special note: scripts need at least one working cockpit, control station or remote control on a ship in order to enable inertia dampeners. It's a good idea to have a remote control block or another control station hidden away from your main cockpit in case the main one gets destroyed mid-flight.

    What does it do: as soon as the script detects there is no one in control of the ship or any of its turrets, it enables inertia dampeners, turns on gyroscopes and thrusters, cancels their overrides. Also, turns off gravity generators and artificial masses to prevent them from counteracting the inertia dampener.

    Thanks to Mustardman24 for the idea of enabling inertia dampeners by sensors and his script that I initially used for my ships in conjunction with sensors.

    Future plans:
    • If possible, change grid name to show GPS, so a player could find it.
    • Detect if there are no working thrusters in a particular direction and rotate a ship accordingly to use its remaining working thrusters.
     
    Last edited: Sep 9, 2015
    • Like Like x 2
  2. Dr. Novikov

    Dr. Novikov Apprentice Engineer

    Messages:
    263
    By user request, updated the script. Now, you can place a timer, name it "TriggerOnShipControlLost", and use this timer to set your own actions that need to be performed when ship control is lost. For example:

    - Turn on a beacon or an antenna and increase their radii to maximum.
    - Toggle some blocks on/off for power saving, so the lost ship stays working and broadcasting longer.
    - Turn on an auto-pilot for flying your ship to a predefined GPS location.
    - Turn off gravity drives but leave other gravity generators working (comment out the DisableGravityDrives();).
     
  3. DoubleCouponDay

    DoubleCouponDay Apprentice Engineer

    Messages:
    123
    very cool, bro. what is your method of detecting players? sensors? cockpit?
     
  4. Dr. Novikov

    Dr. Novikov Apprentice Engineer

    Messages:
    263
    Cockpit/remote controls. I also have a method of not triggering the dampeners if the pilot is controlling a turret.
     
    • Like Like x 1
  5. AutoMcD

    AutoMcD Senior Engineer

    Messages:
    2,369
    Thanks!
     
  6. DS_Marine

    DS_Marine Apprentice Engineer

    Messages:
    494
    Great script. I have implemented it and added some improvements for myself.
    Added the action passed to the OnControlLost timer as a string parameter, because maybe I don't want the autopilot to kick in as soon as I exit the ship, but after some seconds. So I pass "Start" instead of "TriggerNow".
    When the ship is piloted, i pass "Stop". This way if you exit the ship you have the seconds you define in the timer to get back to your ship without it starting to fly away due to autopilot, or executing other stuff.
    /Edit: added name parameter so I can also disable program timer with same function. Also I define timer names as constants because I have strict blocks naming conventions and suffixes, because otherwise when you connect a bunch of ship the block list is a mess.
    Also added a LCD for debugging. If conditional compile works, might be a good way of enabling/disabling (#IFNDEF blocks)

    Also, when applying disconnect code, I think you should stop the self triggering timer, or it will keep calling "TrigerNow" on every timer run.

    /Edit: Here's My version.
    Special note: when configuring the timer that runs the program, you MUST put the timer start action first, and the run program action second.
    Otherwise the program will disable the timer but the timer will reactivate it!
    There's one bug left! But I think I'll fix it tomorrow,
    Code:
    scrap this shit
    
     
    Last edited: Dec 22, 2015
  7. DS_Marine

    DS_Marine Apprentice Engineer

    Messages:
    494
    Ok now you can exit the cockpit, return before lost timer countdown is done, and all keeps working just fine.
    Cons: you have to comment 3 lines to disable lost timer.
    Code:
    /*
    Space Engineers ship emergency stop script by drNovikov.
    v0.52
     
    Saves your ships if you accidentally get out of your cockpit or if you get disconnected from a server.
    Does not rely on sensors.
    How to use: have a looping timer run a programmable block with this script and also restart itself
    every second. You can also run the script with the word "manual" as an argument if you want to stop
    your ship by a quick key, button panel, sensor, timer, etc.
     
    Additionally, you can place a timer, name it "TriggerOnShipControlLost", and use this timer to set
    your own actions that need to be performed when ship control is lost. For example:
     
    - Turn on a beacon or an antenna and increase their radii to maximum.
    - Toggle some blocks on/off for power saving, so the lost ship stays working and broadcasting longer.
    - Turn on an auto-pilot for flying your ship to a predefined GPS location.
    - Turn off gravity drives but leave other gravity generators working (comment out the DisableGravityDrives();).
     
    Special note: scripts need at least one working cockpit, control station or remote control on a ship
    in order to enable inertia dampeners. It's a good idea to have a remote control block or another
    control station hidden away from your main cockpit in case the main one gets destroyed mid-flight.
    If there are several blocks named "TriggerOnShipControlLost", the script will attempt to trigger
    only the first one.
    What does it do: as soon as the script detects there is no one in control of the ship or any of its
    turrets, it enables inertia dampeners, turns on gyroscopes and thrusters, cancels their overrides.
    Also, turns off gravity generators and artificial masses to prevent them from counteracting
    the inertia dampener.
    Thanks to Mustardman24 for the idea of enabling inertia dampeners by sensors and his script that
    I initially used for my ships in conjunction with sensors, and later wrote my own smaller version with
    a reliable way of detecting loss of control.
    */
    const string LCD_PANEL = "LCD Panel.MiniAtk1";
    const string LOST_TIMER = "Timer ControlLost.MiniAtk1";
    int runtime=0;
    void Main(string argument)
    {
    String text="";
    IMyTextPanel panel_block = GridTerminalSystem.GetBlockWithName(LCD_PANEL) as IMyTextPanel;
    if (panel_block == null)
    { throw new Exception("Failed to find panel with name: " + LCD_PANEL);
    return; }
    IMyTimerBlock timerLost = (IMyTimerBlock)GridTerminalSystem.GetBlockWithName(LOST_TIMER);
    if (timerLost is IMyTimerBlock)
    text +="Deadman check online\n";
    text +=String.Format("Cycles={0}\n",runtime);
    {text +=String.Format("Lost CountDn={0}\n",timerLost.IsCountingDown );};
    if ((!ShipIsControlled() && !TurretsAreControlled()) || argument == "manual")
    {
    text +="No pilot found!!\n";
    if (!timerLost.IsCountingDown) // Comment this out if you don't want to trigger the TriggerOnShipControlLost timer.
    {
    EnableInertiaDampeners();
    DisableThrusterOverrides();
    DisableGyroscopeOverrides();
    DisableGravityDrives(); // Comment this out if you don't have any gravity drives.
    TriggerControl(LOST_TIMER,"Start"); // Comment this out if you don't want to trigger the TriggerOnShipControlLost timer.
    }
    }
    else //Pilot came back before timer lost finished its countdown
    {
    TriggerControl(LOST_TIMER,"Stop"); // Comment this out if you don't want to trigger the TriggerOnShipControlLost timer.
    }
    panel_block.WritePublicText(text);
    runtime++;
    }
     
    // drNovikov's famous pilot detector: checks is a ship is piloted. For example, if a pilot accidentally exits a ship, this could be used to engage inertia dampeners, turn on beacons, etc.
    bool ShipIsControlled()
    {
    List<IMyTerminalBlock> shipControllers = new List<IMyTerminalBlock>();
    GridTerminalSystem.GetBlocksOfType<IMyShipController>(shipControllers);
    for (int i = 0; i < shipControllers.Count; i++)
    {
    if ((shipControllers[i] as IMyShipController).IsUnderControl)
    {
    return true;
    }
    }
    return false;
    }
    bool TurretsAreControlled()
    {
    List<IMyTerminalBlock> turrets = new List<IMyTerminalBlock>();
    GridTerminalSystem.GetBlocksOfType<IMyLargeTurretBase>(turrets);
    for (int i = 0; i < turrets.Count; i++)
    {
    if ((turrets[i] as IMyLargeTurretBase).IsUnderControl)
    {
    return true;
    }
    }
    return false;
    }
    // Control Timer contained in 'target' parameter, set action in 'action' parameter
    void TriggerControl(string target, string action)
    {
    IMyTimerBlock timer1 = (IMyTimerBlock)GridTerminalSystem.GetBlockWithName(target);
    if (timer1 is IMyTimerBlock)
    timer1.GetActionWithName(action).Apply(timer1);
    else
    {throw new Exception("Failed to find timer "+target);
    return;}
    }
     
    // drNovikov's gravity drive disabler for large ships with gravity drives
     
    void DisableGravityDrives()
    {
    DisableGravityGenerators();
    DisableArtificialMasses();
    }
     
    void DisableGravityGenerators()
    {
    List<IMyTerminalBlock> gravgens = new List<IMyTerminalBlock>();
    GridTerminalSystem.GetBlocksOfType<IMyGravityGenerator>(gravgens);
    for (int i = 0; i < gravgens.Count; i++)
    {
    gravgens[i].GetActionWithName("OnOff_Off").Apply(gravgens[i]);
    }
    }
     
    void DisableArtificialMasses()
    {
    List<IMyTerminalBlock> artmasses = new List<IMyTerminalBlock>();
    GridTerminalSystem.GetBlocksOfType<IMyVirtualMass>(artmasses);
    for (int i = 0; i < artmasses.Count; i++)
    {
    artmasses[i].GetActionWithName("OnOff_Off").Apply(artmasses[i]);
    }
    }
     
    // Inertia dampeners enabler, inspired by Mustardman24's script
    void EnableInertiaDampeners()
    {
    List<IMyTerminalBlock> shipControllers = new List<IMyTerminalBlock>();
    GridTerminalSystem.GetBlocksOfType<IMyShipController>(shipControllers);
    for (int i = 0; i < shipControllers.Count; i++)
    {
    if ((shipControllers[i] as IMyShipController).DampenersOverride == false)
    {
    shipControllers[i].GetActionWithName("DampenersOverride").Apply(shipControllers[i]);
    }
    }
    }
     
    void DisableThrusterOverrides()
    {
    List<IMyTerminalBlock> thrusters = new List<IMyTerminalBlock>();
    GridTerminalSystem.GetBlocksOfType<IMyThrust>(thrusters);
    for (int i = 0; i < thrusters.Count; i++)
    {
    thrusters[i].GetActionWithName("OnOff_On").Apply(thrusters[i]);
    thrusters[i].SetValueFloat("Override", 0);
    }
    }
     
    void DisableGyroscopeOverrides()
    {
    List<IMyTerminalBlock> gyroscopes = new List<IMyTerminalBlock>();
    GridTerminalSystem.GetBlocksOfType<IMyGyro>(gyroscopes);
    for (int i = 0; i < gyroscopes.Count; i++)
    {
    gyroscopes[i].GetActionWithName("OnOff_On").Apply(gyroscopes[i]);
    gyroscopes[i].SetValueFloat("Power", 1);
    if ((gyroscopes[i] as IMyGyro).GyroOverride)
    {
    gyroscopes[i].GetActionWithName("Override").Apply(gyroscopes[i]);
    }
    }
    }
    
     
    Last edited: Dec 22, 2015
    • Like Like x 1
  8. DS_Marine

    DS_Marine Apprentice Engineer

    Messages:
    494
    After several hours of more tweaking, I decided to publish my variant for people to use.
    Code is more eficient (scanning for block just once instead of every timer run) and also added a way to delay and turn on autopilot without using a second timer block.
    https://steamcommunity.com/sharedfiles/filedetails/?id=583003355
     
  9. Clunas

    Clunas Junior Engineer

    Messages:
    564
    This is incredibly useful. Thanks for posting it so long ago :D
    Nearly lost a ship last night..
     
Thread Status:
This last post in this thread was made more than 31 days old.