Skip to content

Instantly share code, notes, and snippets.

@YarekTyshchenko
Last active January 16, 2023 23:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YarekTyshchenko/8d5760966fc1b5d56c20 to your computer and use it in GitHub Desktop.
Save YarekTyshchenko/8d5760966fc1b5d56c20 to your computer and use it in GitHub Desktop.
Collection of Space Engineers C# Scripts
public class CruiseControl {
private double targetSpeed = 0.0;
private bool enabled;
private List<IMyThrust> thrusters = new List<IMyThrust>();
public void setTarget(double targetSpeed) {
this.targetSpeed = targetSpeed;
}
public void addThruster(IMyThrust thruster) {
this.thrusters.Add(thruster);
}
public void recompute(double currentSpeed) {
// recompute the thruster override settings based on the current speed
this.simpleImplementation(currentSpeed);
}
private void simpleImplementation(double currentSpeed) {
for(var i = 0; i < this.thrusters.Count; i++) {
IMyTerminalBlock t = (IMyTerminalBlock)this.thrusters[i];
// If going too fast
if (!this.enabled || currentSpeed > targetSpeed) {
// Turn all thrusters off
t.GetActionWithName("OnOff_Off").Apply(t);
} else {
// Turn all thrusters on
t.GetActionWithName("OnOff_On").Apply(t);
}
}
}
public void enable(bool enable = true) {
this.enabled = enable;
this.recompute(this.targetSpeed);
}
}
void Main(string arg) {
// Create an instance
CruiseControl cc = new CruiseControl();
// Find all the thrusters that point in the direction of where you are going
IMyThrust t = GridTerminalSystem.GetBlockWithName("CC (Forward) ") as IMyThrust;
// Add them to the cruise control system
cc.addThruster(t);
// Set its target speed
cc.setTarget(23.5);
// Recompute on every update
cc.recompute(sc.getSpeed());
}
class Delay {
DateTime startTime;
double duration;
public Delay(double seconds) {
this.duration = seconds;
}
public bool expired() {
DateTime finishTime = this.startTime.AddSeconds(this.duration);
return System.DateTime.Now >= finishTime;
}
public void start() {
this.startTime = System.DateTime.Now;
}
}
void Main(string arg) {
// create 60 second delay
Delay d1 = new Delay(60);
if (d1.expired()) {
// 60 seconds have passed
// (Or this is the first time we check the delay)
d1.start();
// Do action
}
}
class Dispatch {
Action<string> log = delegate(string s) {};
Dictionary<string, Action> methods = new Dictionary<string, Action>();
public void addHandler(string method, Action action) {
methods.Add(method, action);
}
public void dispatch(string argument) {
if (! methods.ContainsKey(argument)) {
log("Argument '"+argument+"' doesn't exist in collection");
return;
}
Action action = methods[argument];
action();
}
public void setLogger(Action<string> logger) {
this.log = logger;
}
}
void Main(string arg) {
Dispatch d = new Dispatch();
d.setLogger(delegate(string s) {
Echo("Log: "+s);
});
d.addHandler("foo", delegate() {
Echo("Custom Foo action");
});
d.addHandler("", delegate() {
Echo("Default action");
});
d.dispatch(arg);
}
public class LCD {
IMyTextPanel lcd;
// Grid terminal system is needed here so the search happens in the right grid
public LCD(IMyGridTerminalSystem gts, string panelName) {
this.lcd = gts.GetBlockWithName(panelName) as IMyTextPanel;
this.lcd.ShowPublicTextOnScreen();
}
public LCD writeText(string text) {
this.lcd.WritePublicText(text, true);
return this;
}
public LCD writeLine(string line) {
this.writeText(line+"\n");
return this;
}
public LCD clear() {
this.lcd.WritePublicText("", false);
return this;
}
}
void Main(string arg) {
// Second parameter is the name of the panel to search for
LCD lcd = new LCD(GridTerminalSystem, "LCD Panel").clear();
lcd.writeLine("Speed: "+10);
lcd.writeLine("Seconds Delta: "+2);
}
public class Navigator {
private Dictionary<ushort, IMyGyro> gyros = new Dictionary<ushort, IMyGyro>();
public class Direction {
public const ushort Left = 0;
public const ushort Right = 1;
public const ushort Up = 2;
public const ushort Down = 3;
}
public void addGyro(ushort direction, IMyGyro gyro) {
this.gyros.Add(direction, gyro);
}
public struct Maneuver {
public bool isSet;
public DateTime timeStarted;
public ushort direction;
public double startAngle;
public double duration;
public bool finished() {
DateTime finishTime = this.timeStarted.AddSeconds(this.duration);
return System.DateTime.Now >= finishTime;
}
public bool IsSet() {
return this.isSet;
}
public string ToString() {
DateTime finishTime = this.timeStarted.AddSeconds(this.duration);
double done = (finishTime - System.DateTime.Now).TotalSeconds;
return "D:" + this.direction + ", " + this.timeStarted.ToString() + " \nfor " + this.duration + " Done in "+ Math.Round(done, 3);
}
}
private Maneuver activeManeuver;
private void TurnOnGyro(ushort direction) {
IMyTerminalBlock tb = (IMyTerminalBlock)this.gyros[direction];
tb.GetActionWithName("OnOff_On").Apply(tb);
}
private void TurnOffGyro(ushort direction) {
IMyTerminalBlock tb = (IMyTerminalBlock)this.gyros[direction];
tb.GetActionWithName("OnOff_Off").Apply(tb);
}
public Maneuver Turn(double seconds, ushort direction) {
Maneuver m = new Maneuver();
m.isSet = true;
m.timeStarted = System.DateTime.Now;
m.direction = direction;
m.duration = seconds;
stop();
TurnOnGyro(direction);
return m;
}
public Maneuver MakeRandomTurn() {
// Pick a direction
Random rnd = new Random();
ushort direction = (ushort)rnd.Next(0, 4);
// Pick an angle (duration)
double duration = rnd.NextDouble() * 3;
return Turn(duration, direction);
}
public void stop() {
TurnOffGyro(Direction.Left);
TurnOffGyro(Direction.Right);
TurnOffGyro(Direction.Up);
TurnOffGyro(Direction.Down);
}
}
Navigator.Maneuver m;
void Main(string arg) {
Navigator nav = new Navigator();
// Add in gyros overridden in the correct directions
nav.addGyro(Navigator.Direction.Left, GridTerminalSystem.GetBlockWithName("Gyroscope Left") as IMyGyro);
nav.addGyro(Navigator.Direction.Right, GridTerminalSystem.GetBlockWithName("Gyroscope Right") as IMyGyro);
nav.addGyro(Navigator.Direction.Up, GridTerminalSystem.GetBlockWithName("Gyroscope Up") as IMyGyro);
nav.addGyro(Navigator.Direction.Down, GridTerminalSystem.GetBlockWithName("Gyroscope Down") as IMyGyro);
// Trigger the turn somehow
if (arg == "left") {
m = nav.Turn(5, Navigator.Direction.Left);
}
// If the maneuver is done
if (m.finished()) {
nav.stop();
m.isSet = false;
}
}
public class SpeedCalculator {
public struct Store {
// Previous Time
public DateTime time;
// Previous position
public Vector3D position;
public static Store fromString(string storage) {
Store store = new Store();
// Get the fragments (or get one fragment)
string[] Fragments = storage.Split('|');
if(Fragments.Length == 2) {
// Extract time
store.time = System.DateTime.FromBinary(Convert.ToInt64(Fragments[0]));
// Vomit a bit here because this is how we have to store variables at the moment ...
string[] Coords = Fragments[1].Split(',');
double X = Math.Round(Convert.ToDouble(Coords[0]), 4);
double Y = Math.Round(Convert.ToDouble(Coords[1]), 4);
double Z = Math.Round(Convert.ToDouble(Coords[2]), 4);
store.position = new Vector3D(X, Y, Z);
} else {
store.time = System.DateTime.Now;
store.position = new Vector3D(0);
}
return store;
}
public string ToString() {
// Get coordinates (VRageMath.Vector3D, so pull it in the ugly way)
double x = Math.Round(this.position.GetDim(0), 4);
double y = Math.Round(this.position.GetDim(1), 4);
double z = Math.Round(this.position.GetDim(2), 4);
// Time|X,Y,Z
string newStorage = this.time.ToBinary().ToString() + "|" +
x.ToString() + "," + y.ToString() + "," + z.ToString();
return newStorage;
}
}
IMyTerminalBlock origin;
double delta = 0.0;
double speed = 0.0;
public SpeedCalculator(IMyTerminalBlock origin) {
this.origin = origin;
}
public double getDeltaSeconds() {
return this.delta;
}
public double getSpeed() {
return this.speed;
}
public void calculate(ref Store store) {
// Get times
DateTime TimeNow = System.DateTime.Now;
DateTime OldTime = store.time;
// We have 's' for m/s.
this.delta = (TimeNow - OldTime).TotalSeconds;
// Caluculate distance
Vector3D currentVector = this.origin.GetPosition();
double Distance = Vector3D.Distance(currentVector, store.position);
// If the base coordinates
if (Distance != 0 && this.delta != 0)
{
// We have our distance
double Speed = Distance / this.delta;
this.speed = Speed;
} else {
this.speed = 0.0;
}
// Update the store with current coordinates
store.time = TimeNow;
store.position = currentVector;
}
}
void Main(string arg) {
// Instantiate a speed calculator using the programming block for measurments
// You can use any block, something near the center of the ship so the rotation
// doesn't contribute to the overall speed.
SpeedCalculator sc = new SpeedCalculator((IMyTerminalBlock)Me);
// Storage malarky: Required because we need to store previous 3D Vector and time
// to calculate distance traveled and speed
SpeedCalculator.Store store = SpeedCalculator.Store.fromString(Storage);
sc.calculate(ref store);
Storage = store.ToString();
// Speed in Meters Per Second
double speed = sc.getSpeed();
// Seconds passed since last calculation
double delta = sc.getDeltaSeconds();
}
public class StringStateMachine {
private struct State {
public Action enter;
public Action exit;
public Action update;
}
private Dictionary<string, State> stateHash = new Dictionary<string, State>();
private string currentState = "idle";
private Action<string> log = delegate(string s) {};
public void setState(string state, Action enter, Action exit, Action update) {
State s = new State();
s.enter = enter;
s.exit = exit;
s.update = update;
stateHash.Add(state, s);
}
public void transition(string newState) {
// If transition is valid (New state exists)
if (! stateHash.ContainsKey(newState)) {
// Log invalid state transition
this.log("State '"+newState+"' doesn't exist");
return;
}
// If current state is set
State oldState = stateHash[currentState];
oldState.exit();
// Get new state (Is there a memory leak here?)
State state = stateHash[newState];
this.log("Entering state '"+newState+"'");
currentState = newState;
state.enter();
}
public void update() {
// If current state is set
State state = stateHash[currentState];
state.update();
}
public void setLogger(Action<string> logger) {
this.log = logger;
}
}
StringStateMachine stateMachine;
void Main(string arg) {
stateMachine = new StringStateMachine();
stateMachine.setState("idle", delegate(){}, delegate(){}, delegate(){});
stateMachine.setState("go", delegate() {
// Code run on transition *into* this state
// Example:
// Set thrusters override
// Enable forward sensors
// Lock down connectors for travel
}, delegate() {
// Code run on *exit* from this state
// Example: Stop all engines
}, delegate() {
// Code run every update while in this state
// Example:
// Check for objects on collision course
// If detected: stateMachine.transition("idle");
});
stateMachine.update();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment