├── .gitattributes ├── .gitignore ├── CSharpMinifier ├── CSharpMinifier.dll ├── CSharpMinify.exe ├── ICSharpCode.NRefactory.CSharp.dll ├── ICSharpCode.NRefactory.Cecil.dll ├── ICSharpCode.NRefactory.dll └── Mono.Cecil.dll ├── EasyAPI.cs ├── EasyAPI.debug.cs ├── README.md ├── build.bat └── modules ├── BootstrapEasyAPI ├── BootstrapEasyAPI.cs └── module.json ├── BootstrapMain ├── EmptyMain.cs └── module.json ├── EasyAPI ├── EasyAPI.cs ├── build.bat ├── examples │ ├── auto_close_doors.cs │ ├── event_on_door_open_close.cs │ └── toggle_doors_on_damage.cs ├── module.json └── src │ ├── EasyAPI.cs │ ├── EasyBlock.cs │ ├── EasyBlocks.cs │ ├── EasyCommands.cs │ ├── EasyEvent.cs │ ├── EasyInterval.cs │ ├── EasyInventory.cs │ ├── EasyItem.cs │ └── EasyMessage.cs ├── EasyLCD ├── EasyLCD.cs └── module.json ├── EasyMenu ├── EasyMenu.cs ├── examples │ ├── CALMenu.cs │ ├── DHDDialer.cs │ ├── Example.cs │ ├── Example2.cs │ ├── PBMenu.cs │ └── ShipExplorer.cs └── module.json └── EasyUtils ├── EasyUtils.cs └── module.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /CSharpMinifier/CSharpMinifier.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockyjvec/EasyAPI/78d0a14b04eec6c32dc784839103d4a576fd999a/CSharpMinifier/CSharpMinifier.dll -------------------------------------------------------------------------------- /CSharpMinifier/CSharpMinify.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockyjvec/EasyAPI/78d0a14b04eec6c32dc784839103d4a576fd999a/CSharpMinifier/CSharpMinify.exe -------------------------------------------------------------------------------- /CSharpMinifier/ICSharpCode.NRefactory.CSharp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockyjvec/EasyAPI/78d0a14b04eec6c32dc784839103d4a576fd999a/CSharpMinifier/ICSharpCode.NRefactory.CSharp.dll -------------------------------------------------------------------------------- /CSharpMinifier/ICSharpCode.NRefactory.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockyjvec/EasyAPI/78d0a14b04eec6c32dc784839103d4a576fd999a/CSharpMinifier/ICSharpCode.NRefactory.Cecil.dll -------------------------------------------------------------------------------- /CSharpMinifier/ICSharpCode.NRefactory.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockyjvec/EasyAPI/78d0a14b04eec6c32dc784839103d4a576fd999a/CSharpMinifier/ICSharpCode.NRefactory.dll -------------------------------------------------------------------------------- /CSharpMinifier/Mono.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockyjvec/EasyAPI/78d0a14b04eec6c32dc784839103d4a576fd999a/CSharpMinifier/Mono.Cecil.dll -------------------------------------------------------------------------------- /EasyAPI.cs: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | EasyAPI - Documentation: http://steamcommunity.com/sharedfiles/filedetails/?id=381043 3 | *************************************************************************************/ 4 | 5 | public class Example : EasyAPI 6 | { 7 | public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) 8 | { 9 | // Start your code here 10 | } 11 | } 12 | 13 | 14 | /*********************************************/ 15 | /*** Advanced users only beyond this point ***/ 16 | /*********************************************/ 17 | 18 | Example state; 19 | 20 | public Program() 21 | { 22 | state = new Example(GridTerminalSystem, Me, Echo, Runtime.TimeSinceLastRun); 23 | 24 | Runtime.UpdateFrequency = UpdateFrequency.Update100; 25 | } 26 | 27 | public void Main(string argument, UpdateType updateType) 28 | { 29 | if(state == null) 30 | { 31 | state = new Example(GridTerminalSystem, Me, Echo, Runtime.TimeSinceLastRun); 32 | } 33 | 34 | // Set the minimum time between ticks here to prevent lag. 35 | // To utilize onSingleTap and onDoubleTap, set the minimum time to the same 36 | // time period of the timer running this script (e.g. 1 * EasyAPI.Seconds). 37 | state.Tick(100 * EasyAPI.Milliseconds, argument); 38 | } 39 | 40 | 41 | /*** Ignore minified library code below ***/ 42 | public abstract class EasyAPI{private long d=0;private long f=0;private long g=0;public EasyBlock Self;public IMyGridTerminalSystem GridTerminalSystem;public ActionEcho;public TimeSpan ElapsedTime;static public IMyGridTerminalSystem grid;private Dictionary>h;private Dictionary>>l;private Listp;private Listq;private EasyCommands r;public virtual void onRunThrottled(float intervalTranspiredPercentage){}public virtual void onTickStart(){}public virtual void onTickComplete(){}public virtual bool onSingleTap(){return false;}public virtual bool onDoubleTap(){return false;}private int u=0;public EasyBlocks Blocks;public const long Microseconds=10;public const long Milliseconds=1000*Microseconds;public const long Seconds=1000*Milliseconds;public const long Minutes=60*Seconds;public const long Hours=60*Minutes;public const long Days=24*Hours;public const long Years=365*Days;public EasyAPI(IMyGridTerminalSystem grid,IMyProgrammableBlock me,Actionecho,TimeSpan elapsedTime,string commandArgument="EasyCommand"){this.f=this.d=DateTime.Now.Ticks;this.g=0;this.GridTerminalSystem=EasyAPI.grid=grid;this.Echo=echo;this.ElapsedTime=elapsedTime;this.h=new Dictionary>();this.l=new Dictionary>>();this.p=new List();this.q=new List();this.r=new EasyCommands(this);this.Self=new EasyBlock(me);this.Reset();}public void AddEvent(EasyEvent e){EasyEvent.add(e);}public void AddEvent(EasyBlock block,Funcevnt,Funcaction,bool onChange=false){this.AddEvent(new EasyEvent(block,evnt,action,onChange));}public void AddEvents(EasyBlocks blocks,Funcevnt,Funcaction,bool onChange=false){for(int i=0;iGetMessages(){var mymessages=new List();var parts=this.Self.Name().Split('\0');if(parts.Length>1){for(int n=1;n1){this.Self.SetName(parts[0]);}}public EasyMessage ComposeMessage(String Subject,String Message){return new EasyMessage(this.Self,Subject,Message);}public void Tick(long interval=0,string argument=""){if(argument!=""){if(this.h.ContainsKey(argument)){for(int n=0;n0){int argc=0;var matches=System.Text.RegularExpressions.Regex.Matches(argument,@"(?[^\s""]+)|""(?[^""]*)""");string[]argv=new string[matches.Count];for(int n=0;n0&&this.l.ContainsKey(argv[0])){for(int n=0;n12&&argument.Substring(0,12)=="EasyCommand "){this.r.handle(argument.Substring(12));}}long now=DateTime.Now.Ticks;if(this.f>this.d&&now-this.f1){if(onDoubleTap()){return;}}u=0;onTickStart();long lastClock=this.f;this.f=now;this.g=this.f-lastClock;EasyEvent.handle();for(int n=0;n=this.q[n].time){long time=this.f+this.q[n].interval-(this.f-this.q[n].time);(this.q[n].action)();this.q[n]=new EasyInterval(time,this.q[n].interval,this.q[n].action);}}for(int n=0;n=this.p[n].time){(this.p[n].action)();p.Remove(this.p[n]);}}onTickComplete();}public long GetDelta(){return this.g;}public long GetClock(){return f;}public void On(string argument,Action callback){if(!this.h.ContainsKey(argument)){this.h.Add(argument,new List());}this.h[argument].Add(callback);}public void OnCommand(string argument,Actioncallback){if(!this.l.ContainsKey(argument)){this.l.Add(argument,new List>());}this.l[argument].Add(callback);}public void At(long time,Action callback){long t=this.d+time;p.Add(new EasyInterval(t,0,callback));}public void Every(long time,Action callback){q.Add(new EasyInterval(this.f+time,time,callback));}public void In(long time,Action callback){this.At(this.f-this.d+time,callback);}public void Reset(){this.d=this.f;this.ClearMessages();this.Refresh();}public void Refresh(){ListkBlocks=new List();GridTerminalSystem.GetBlocks(kBlocks);Blocks=new EasyBlocks(kBlocks);}}public class EasyBlocks{public ListBlocks;public EasyBlocks(ListTBlocks){this.Blocks=new List();for(int i=0;iBlocks){this.Blocks=Blocks;}public EasyBlocks(){this.Blocks=new List();}public int Count(){return this.Blocks.Count;}public EasyBlock GetBlock(int i){return this.Blocks[i];}public EasyBlocks WithInterface()where T:class{ListFilteredList=new List();for(int i=0;iFilteredList=new List();for(int i=0;iFilteredList=new List();for(int i=0;iFilteredList=new List();Listgroups=new List();EasyAPI.grid.GetBlockGroups(groups);ListmatchedGroups=new List();ListgroupBlocks=new List();for(int n=0;nFilteredList=new List();for(int i=0;iFilteredList=new List();for(int i=0;iaction){ListFilteredList=new List();for(int i=0;iFilteredList=new List();if(this.Blocks.Count>0){FilteredList.Add(Blocks[0]);}return new EasyBlocks(FilteredList);}public EasyBlocks Add(EasyBlock Block){this.Blocks.Add(Block);return this;}public EasyBlocks Plus(EasyBlocks Blocks){ListFilteredList=new List();FilteredList.AddRange(this.Blocks);for(int i=0;iFilteredList=new List();FilteredList.AddRange(this.Blocks);for(int i=0;iFilteredList=new List();FilteredList.AddRange(this.Blocks);if(!FilteredList.Contains(Block)){FilteredList.Add(Block);}return new EasyBlocks(FilteredList);}public EasyBlocks Minus(EasyBlock Block){ListFilteredList=new List();FilteredList.AddRange(this.Blocks);FilteredList.Remove(Block);return new EasyBlocks(FilteredList);}public static EasyBlocks operator+(EasyBlocks a,EasyBlock b){return a.Plus(b);}public static EasyBlocks operator-(EasyBlocks a,EasyBlock b){return a.Minus(b);}public EasyBlocks FindOrFail(string message){if(this.Count()==0)throw new Exception(message);return this;}public EasyBlocks Run(EasyAPI api,string type="public"){for(int i=0;i(String PropertyId,T value,int bleh=0){for(int i=0;i(PropertyId,value);}return this;}public EasyBlocks SetFloatValue(String PropertyId,float value,int bleh=0){for(int i=0;i(String PropertyId,int bleh=0){return this.Blocks[0].GetProperty(PropertyId);}public EasyBlocks On(){for(int i=0;iactions=this.Blocks[i].GetActions();for(int j=0;jproperties=this.Blocks[i].GetProperties();for(int j=0;jevnt,Funcaction,bool onChange=false){for(int i=0;iNameParameters(char start='[',char end=']'){Listmatches;this.NameRegex(@"\"+start+@"(.*?)\"+end,out matches);return matches;}public bool RoomPressure(String op,Single percent){String roomPressure=DetailedInfo()["Room pressure"];Single pressure=0;if(roomPressure!="Not pressurized"){pressure=Convert.ToSingle(roomPressure.TrimEnd('%'));}switch(op){case "<":return pressure=":return pressure>=percent;case ">":return pressure>percent;case "==":return pressure==percent;case "!=":return pressure!=percent;}return false;}public DictionaryDetailedInfo(){Dictionaryproperties=new Dictionary();var statements=this.Block.DetailedInfo.Split('\n');for(int n=0;nMatches){System.Text.RegularExpressions.Match m=(new System.Text.RegularExpressions.Regex(Pattern)).Match(this.Block.CustomName);Matches=new List();bool success=false;while(m.Success){if(m.Groups.Count>1){Matches.Add(m.Groups[1].Value);}success=true;m=m.NextMatch();}return success;}public bool NameRegex(String Pattern){Listmatches;return this.NameRegex(Pattern,out matches);}public ITerminalAction GetAction(String Name){return this.Block.GetActionWithName(Name);}public EasyBlock ApplyAction(String Name){ITerminalAction Action=this.GetAction(Name);if(Action!=null){Action.Apply(this.Block);}return this;}public T GetProperty(String PropertyId){return Sandbox.ModAPI.Interfaces.TerminalPropertyExtensions.GetValue(this.Block,PropertyId);}public EasyBlock SetProperty(String PropertyId,T value){try{var prop=this.GetProperty(PropertyId);Sandbox.ModAPI.Interfaces.TerminalPropertyExtensions.SetValue(this.Block,PropertyId,value);}catch(Exception e){}return this;}public EasyBlock SetFloatValue(String PropertyId,float value){try{Sandbox.ModAPI.Interfaces.TerminalPropertyExtensions.SetValueFloat(this.Block,PropertyId,value);}catch(Exception e){}return this;}public EasyBlock On(){this.ApplyAction("OnOff_On");return this;}public EasyBlock Off(){this.ApplyAction("OnOff_Off");return this;}public EasyBlock Toggle(){if(this.Block.IsWorking){this.Off();}else{this.On();}return this;}public EasyBlock Run(EasyAPI api,string type="public"){var cmd=new EasyCommands(api);switch(type){case "private":cmd.handle(this.GetCustomData());break;default:cmd.handle(this.GetPublicText());break;}return this;}public EasyBlock RunPB(string argument=""){IMyProgrammableBlock pb=Block as IMyProgrammableBlock;if(pb!=null){pb.TryRun(argument);}return this;}public string GetPublicText(){string ret="";IMyTextPanel textPanel=Block as IMyTextPanel;if(textPanel!=null){ret=textPanel.GetPublicText();}return ret;}public string GetCustomData(){string ret="";IMyTextPanel textPanel=Block as IMyTextPanel;if(textPanel!=null){ret=textPanel.CustomData;}return ret;}public EasyBlock WritePublicTitle(string text){IMyTextPanel textPanel=Block as IMyTextPanel;if(textPanel!=null){textPanel.WritePublicTitle(text);}return this;}public EasyBlock WritePublicText(string text){IMyTextPanel textPanel=Block as IMyTextPanel;if(textPanel!=null){textPanel.WritePublicText(text,false);}return this;}public EasyBlock WriteCustomData(string text){IMyTextPanel textPanel=Block as IMyTextPanel;if(textPanel!=null){textPanel.CustomData=text;}return this;}public EasyBlock AppendPublicText(string text){IMyTextPanel textPanel=Block as IMyTextPanel;if(textPanel!=null){textPanel.WritePublicText(text,true);}return this;}public EasyBlock SetName(String Name){this.Block.CustomName=Name;return this;}public ListGetActions(){Listactions=new List();this.Block.GetActions(actions);return actions;}public ListGetProperties(){Listproperties=new List();this.Block.GetProperties(properties);return properties;}public EasyBlock AddEvent(Funcevnt,Funcaction,bool onChange=false){EasyEvent.add(new EasyEvent(this,evnt,action,onChange));return this;}public EasyInventory Items(Nullablefix_duplicate_name_bug=null){ListBlocks=new List();Blocks.Add(this);return new EasyInventory(Blocks);}public static bool operator==(EasyBlock a,EasyBlock b){return a.Block==b.Block;}public override bool Equals(object o){return(EasyBlock)o==this;}public override int GetHashCode(){return Block.GetHashCode();}public static bool operator!=(EasyBlock a,EasyBlock b){return a.Block!=b.Block;}}public class EasyInventory{public ListItems;public EasyInventory(ListBlocks){this.Items=new List();for(int i=0;iItems=Inventory.GetItems();for(int k=0;kItems){this.Items=Items;}public EasyInventory OfType(String SubTypeId){ListFilteredItems=new List();for(int i=0;iFilteredItems=new List();for(int i=0;iFilteredItems=new List();if(this.Items.Count>0){FilteredItems.Add(this.Items[0]);}return new EasyInventory(FilteredItems);}public void MoveTo(EasyBlocks Blocks,int Inventory=0){for(int i=0;i();EasyAPI.grid.GetBlocksOfType(blocks,delegate(IMyTerminalBlock block){return(block as IMyProgrammableBlock).NumberInGrid==numberInGrid;});if(blocks.Count==0){throw new Exception("Message sender no longer exits!");}this.From=new EasyBlock((IMyTerminalBlock)blocks[0]);this.Subject=System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[1]));this.Message=System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[2]));this.Timestamp=Convert.ToInt64(System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[3])));}public EasyMessage(EasyBlock From,String Subject,String Message){this.From=From;this.Subject=Subject;this.Message=Message;this.Timestamp=DateTime.Now.Ticks;}public String Serialize(){String text="";text+=System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(""+From.Block.NumberInGrid));text+=":"+System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Subject));text+=":"+System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Message));text+=":"+System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(""+Timestamp));return text;}}public class EasyCommands{private EasyAPI d;private EasyBlocks f;public Dictionaryfunctions=new Dictionary();private int g=0;private string h="";public EasyCommands(EasyAPI api){this.d=api;}public void handle(string text){this.g=0;this.h=text;while(gd;private EasyBlock f;private Funcg;private bool h=false;private bool l=false;public EasyEvent(EasyBlock block,Funcop,Funccallback,bool onChange=false){this.d=op;this.g=callback;this.f=block;this.l=onChange;}public bool process(){bool result=(this.d)(this.f);if(result&&(!l||!h)){h=result;return(this.g)(this.f);}h=result;return true;}private static Listp=new List();public static void handle(){for(int i=0;iecho=null,IMyProgrammableBlock me=null,string label=null,IMyTextPanel mirrorLcd=null,bool truncateForLcd=true){String output="";if(echo==null){output="\n";output+=logMessage;throw new Exception(output);}if(LogBuffer==null){LogBuffer=new StringBuilder();}if(label!=null){logMessage=label+": "+logMessage;}if(mirrorLcd!=null){string currentlyMirrored=mirrorLcd.GetPublicText();if(truncateForLcd&&LogBuffer.Length+logMessage.Length>LOG_MAX_LCD_LENGTH_CHARS){StringBuilder lcdBuffer=new StringBuilder(LogBuffer.ToString());int charAmountToOffset=fullLineCharsExceeding(lcdBuffer,logMessage.Length,LogBuffer.Length-(LOG_MAX_LCD_LENGTH_CHARS-logMessage.Length));lcdBuffer.Remove(0,LogBuffer.Length-LOG_MAX_LCD_LENGTH_CHARS+charAmountToOffset-2);lcdBuffer.AppendLine();lcdBuffer.Append(logMessage);mirrorLcd.WritePublicText(lcdBuffer.ToString(),false);}else{string potentialNewLine=(currentlyMirrored.Length>0)?"\n":"";mirrorLcd.WritePublicText(potentialNewLine+logMessage,true);}}if(LogBuffer.Length+logMessage.Length*2>LOG_MAX_ECHO_LENGTH_CHARS){int charAmountToRemove=fullLineCharsExceeding(LogBuffer,logMessage.Length);LogBuffer.Remove(0,charAmountToRemove);LogBuffer.Append(output);}if(LogBuffer.Length>0){LogBuffer.AppendLine();}LogBuffer.Append(logMessage);echo(LogBuffer.ToString());}public static int fullLineCharsExceeding(StringBuilder sb,int maxLength,int offset=0){int runningCount=0;for(int i=offset;imaxLength){break;}}}return runningCount;}public static void ClearLogBuffer(){LogBuffer.Clear();}public static double Max(double[]values){double runningMax=values[0];for(int i=1;i("FontSize");this.width=(int)((double)this.g/this.l);this.height=(int)((double)this.h/this.l);this.buffer=new char[this.width*this.height];this.clear();this.update();}public void SetText(String text,bool append=false){this.d.WritePublicText(text,append);}public void plot(EasyBlocks blocks,double x,double y,double scale=1.0,char brush='o',bool showBounds=true,char boundingBrush='?'){VRageMath.Vector3D max=new Vector3D(this.d.CubeGrid.Max);VRageMath.Vector3D min=new Vector3D(this.d.CubeGrid.Min);VRageMath.Vector3D size=new Vector3D(max-min);int width=(int)size.GetDim(0);int height=(int)size.GetDim(1);int depth=(int)size.GetDim(2);int minX=(int)min.GetDim(0);int minY=(int)min.GetDim(1);int minZ=(int)min.GetDim(2);int maxX=(int)max.GetDim(0);int maxY=(int)max.GetDim(1);int maxZ=(int)max.GetDim(2);double s=(double)depth+0.01;if(width>depth){s=(double)width+0.01;}if(showBounds){box(x+-(((0-(width/2.0))/s)*scale),y+-(((0-(depth/2.0))/s)*scale),x+-(((maxX-minX-(width/2.0))/s)*scale),y+-(((maxZ-minZ-(depth/2.0))/s)*scale),boundingBrush);}for(int n=0;n=0&&x<1&&y>=0&&y<1){this.buffer[this.q(x,y)]=brush;}}private void p(int x,int y,char brush='0'){if(x>=0&&x=0&&yMath.Abs(x1-x0);if(steep){int tmp=x0;x0=y0;y0=tmp;tmp=x1;x1=y1;y1=tmp;}if(x0>x1){int tmp=x0;x0=x1;x1=tmp;tmp=y0;y0=y1;y1=tmp;}int dX=(x1-x0),dY=Math.Abs(y1-y0),err=(dX/2),ystep=(y0 EasyAPI.min.cs 10 | echo.>> EasyAPI.min.cs 11 | echo /*** Ignore minified library code below ***/ >> EasyAPI.min.cs 12 | CSharpMinifier\CSharpMinify --locals --members --types --spaces --regions --comments --namespaces --to-string-methods --enum-to-int --line-length 100000 --skip-compile EasyAPI.lib.cs >> EasyAPI.min.cs 13 | copy /b ^ 14 | modules\BootstrapEasyAPI\BootstrapEasyAPI.cs +^ 15 | EasyAPI.min.cs ^ 16 | EasyAPI.cs 17 | copy /b ^ 18 | modules\BootstrapEasyAPI\BootstrapEasyAPI.cs +^ 19 | EasyAPI.lib.cs ^ 20 | EasyAPI.debug.cs 21 | del EasyAPI.lib.cs 22 | del EasyAPI.min.cs 23 | pause 24 | -------------------------------------------------------------------------------- /modules/BootstrapEasyAPI/BootstrapEasyAPI.cs: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | EasyAPI - Documentation: http://steamcommunity.com/sharedfiles/filedetails/?id=381043 3 | *************************************************************************************/ 4 | 5 | public class Example : EasyAPI 6 | { 7 | public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) 8 | { 9 | // Start your code here 10 | } 11 | } 12 | 13 | 14 | /*********************************************/ 15 | /*** Advanced users only beyond this point ***/ 16 | /*********************************************/ 17 | 18 | Example state; 19 | 20 | public Program() 21 | { 22 | state = new Example(GridTerminalSystem, Me, Echo, Runtime.TimeSinceLastRun); 23 | 24 | Runtime.UpdateFrequency = UpdateFrequency.Update100; 25 | } 26 | 27 | public void Main(string argument, UpdateType updateType) 28 | { 29 | if(state == null) 30 | { 31 | state = new Example(GridTerminalSystem, Me, Echo, Runtime.TimeSinceLastRun); 32 | } 33 | 34 | // Set the minimum time between ticks here to prevent lag. 35 | // To utilize onSingleTap and onDoubleTap, set the minimum time to the same 36 | // time period of the timer running this script (e.g. 1 * EasyAPI.Seconds). 37 | state.Tick(100 * EasyAPI.Milliseconds, argument); 38 | } 39 | -------------------------------------------------------------------------------- /modules/BootstrapEasyAPI/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bootstrap EasyAPI", 3 | "description": "Blank template to quickly get started with EasyAPI.", 4 | "type": "script", 5 | "version": "1.0", 6 | "require": { 7 | "EasyAPI" 8 | }, 9 | "conflict": { 10 | "BootstrapMain" 11 | }, 12 | "suggest": { 13 | } 14 | } -------------------------------------------------------------------------------- /modules/BootstrapMain/EmptyMain.cs: -------------------------------------------------------------------------------- 1 | void Main(string argument) 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /modules/BootstrapMain/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bootstrap Main", 3 | "description": "Blank template script with only Main function.", 4 | "type": "script", 5 | "version": "1.0", 6 | "require": { 7 | }, 8 | "conflict": { 9 | "BootstrapEasyAPI" 10 | }, 11 | "suggest": { 12 | } 13 | } -------------------------------------------------------------------------------- /modules/EasyAPI/EasyAPI.cs: -------------------------------------------------------------------------------- 1 | /**************************************************/ 2 | /*** EasyAPI class. Extend for easier scripting ***/ 3 | /**************************************************/ 4 | public abstract class EasyAPI 5 | { 6 | private long start = 0; // Time at start of program 7 | private long clock = 0; // Current time in ticks 8 | private long delta = 0; // Time since last call to Tick in ticks 9 | 10 | public EasyBlock Self; // Reference to the Programmable Block that is running this script 11 | 12 | public IMyGridTerminalSystem GridTerminalSystem; 13 | public Action Echo; 14 | public TimeSpan ElapsedTime; 15 | 16 | static public IMyGridTerminalSystem grid; 17 | 18 | /*** Events ***/ 19 | private Dictionary> ArgumentActions; 20 | private Dictionary>> CommandActions; 21 | private List Schedule; 22 | private List Intervals; 23 | private EasyCommands commands; 24 | 25 | /*** Overridable lifecycle methods ***/ 26 | public virtual void onRunThrottled(float intervalTranspiredPercentage) {} 27 | public virtual void onTickStart() {} 28 | public virtual void onTickComplete() {} 29 | public virtual bool onSingleTap() { return false; } 30 | public virtual bool onDoubleTap() { return false; } 31 | private int InterTickRunCount = 0; 32 | 33 | /*** Cache ***/ 34 | public EasyBlocks Blocks; 35 | 36 | /*** Constants ***/ 37 | public const long Microseconds = 10; // Ticks (100ns) 38 | public const long Milliseconds = 1000 * Microseconds; 39 | public const long Seconds = 1000 * Milliseconds; 40 | public const long Minutes = 60 * Seconds; 41 | public const long Hours = 60 * Minutes; 42 | public const long Days = 24 * Hours; 43 | public const long Years = 365 * Days; 44 | 45 | /*** Constructor ***/ 46 | public EasyAPI(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime, string commandArgument = "EasyCommand") 47 | { 48 | this.clock = this.start = DateTime.Now.Ticks; 49 | this.delta = 0; 50 | 51 | this.GridTerminalSystem = EasyAPI.grid = grid; 52 | this.Echo = echo; 53 | this.ElapsedTime = elapsedTime; 54 | this.ArgumentActions = new Dictionary>(); 55 | this.CommandActions = new Dictionary>>(); 56 | this.Schedule = new List(); 57 | this.Intervals = new List(); 58 | this.commands = new EasyCommands(this); 59 | 60 | // Get the Programmable Block that is running this script (thanks to LordDevious and LukeStrike) 61 | this.Self = new EasyBlock(me); 62 | 63 | this.Reset(); 64 | } 65 | 66 | public void AddEvent(EasyEvent e) 67 | { 68 | EasyEvent.add(e); 69 | } 70 | 71 | public void AddEvent(EasyBlock block, Func evnt, Func action, bool onChange = false) 72 | { 73 | this.AddEvent(new EasyEvent(block, evnt, action, onChange)); 74 | } 75 | 76 | public void AddEvents(EasyBlocks blocks, Func evnt, Func action, bool onChange = false) 77 | { 78 | for(int i = 0; i < blocks.Count(); i++) 79 | { 80 | this.AddEvent(new EasyEvent(blocks.GetBlock(i), evnt, action, onChange)); 81 | } 82 | } 83 | 84 | // Get messages sent to this block 85 | public List GetMessages() 86 | { 87 | var mymessages = new List(); 88 | 89 | var parts = this.Self.Name().Split('\0'); 90 | 91 | if(parts.Length > 1) 92 | { 93 | for(int n = 1; n < parts.Length; n++) 94 | { 95 | EasyMessage m = new EasyMessage(parts[n]); 96 | mymessages.Add(m); 97 | } 98 | 99 | // Delete the messages once they are received 100 | this.Self.SetName(parts[0]); 101 | } 102 | return mymessages; 103 | } 104 | 105 | // Clear messages sent to this block 106 | public void ClearMessages() 107 | { 108 | var parts = this.Self.Name().Split('\0'); 109 | 110 | if(parts.Length > 1) 111 | { 112 | // Delete the messages 113 | this.Self.SetName(parts[0]); 114 | } 115 | } 116 | 117 | public EasyMessage ComposeMessage(String Subject, String Message) 118 | { 119 | return new EasyMessage(this.Self, Subject, Message); 120 | } 121 | 122 | /*** Execute one tick of the program (interval is the minimum time between ticks) ***/ 123 | public void Tick(long interval = 0, string argument = "") 124 | { 125 | /*** Handle Arguments ***/ 126 | 127 | if(argument != "") 128 | { 129 | if(this.ArgumentActions.ContainsKey(argument)) 130 | { 131 | for(int n = 0; n < this.ArgumentActions[argument].Count; n++) 132 | { 133 | this.ArgumentActions[argument][n](); 134 | } 135 | } 136 | else if(this.CommandActions.Count > 0) 137 | { 138 | int argc = 0; 139 | var matches = System.Text.RegularExpressions.Regex.Matches(argument, @"(?[^\s""]+)|""(?[^""]*)"""); 140 | 141 | string[] argv = new string[matches.Count]; 142 | for(int n = 0; n < matches.Count; n++) 143 | { 144 | argv[n] = matches[n].Groups["match"].Value; 145 | } 146 | 147 | argc = argv.Length; 148 | 149 | if(argc > 0 && this.CommandActions.ContainsKey(argv[0])) 150 | { 151 | for(int n = 0; n < this.CommandActions[argv[0]].Count; n++) 152 | { 153 | this.CommandActions[argv[0]][n](argc, argv); 154 | } 155 | } 156 | } 157 | else if(argument.Length > 12 && argument.Substring(0, 12) == "EasyCommand ") 158 | { 159 | this.commands.handle(argument.Substring(12)); 160 | } 161 | } 162 | 163 | long now = DateTime.Now.Ticks; 164 | if(this.clock > this.start && now - this.clock < interval) { 165 | InterTickRunCount++; 166 | float transpiredPercentage = ((float)((double)(now - this.clock) / interval)); 167 | onRunThrottled(transpiredPercentage); 168 | return; // Don't run until the minimum time between ticks 169 | } 170 | if(InterTickRunCount == 1) { 171 | if(onSingleTap()) { 172 | return; // Override has postponed this Tick to next Run 173 | } 174 | } else if(InterTickRunCount > 1) { 175 | if(onDoubleTap()) { 176 | return; // Override has postponed this Tick to next Run 177 | } 178 | } 179 | InterTickRunCount = 0; 180 | onTickStart(); 181 | 182 | long lastClock = this.clock; 183 | this.clock = now; 184 | this.delta = this.clock - lastClock; 185 | 186 | /*** Handle Events ***/ 187 | EasyEvent.handle(); 188 | 189 | /*** Handle Intervals ***/ 190 | for(int n = 0; n < this.Intervals.Count; n++) 191 | { 192 | if(this.clock >= this.Intervals[n].time) 193 | { 194 | long time = this.clock + this.Intervals[n].interval - (this.clock - this.Intervals[n].time); 195 | 196 | (this.Intervals[n].action)(); 197 | this.Intervals[n] = new EasyInterval(time, this.Intervals[n].interval, this.Intervals[n].action); // reset time interval 198 | } 199 | } 200 | 201 | /*** Handle Schedule ***/ 202 | for(int n = 0; n < this.Schedule.Count; n++) 203 | { 204 | if(this.clock >= this.Schedule[n].time) 205 | { 206 | (this.Schedule[n].action)(); 207 | Schedule.Remove(this.Schedule[n]); 208 | } 209 | } 210 | 211 | onTickComplete(); 212 | } 213 | 214 | public long GetDelta() {return this.delta;} 215 | 216 | public long GetClock() {return clock;} 217 | 218 | public void On(string argument, Action callback) 219 | { 220 | if(!this.ArgumentActions.ContainsKey(argument)) 221 | { 222 | this.ArgumentActions.Add(argument, new List()); 223 | } 224 | 225 | this.ArgumentActions[argument].Add(callback); 226 | } 227 | 228 | public void OnCommand(string argument, Action callback) 229 | { 230 | if(!this.CommandActions.ContainsKey(argument)) 231 | { 232 | this.CommandActions.Add(argument, new List>()); 233 | } 234 | 235 | this.CommandActions[argument].Add(callback); 236 | } 237 | 238 | /*** Call a function at the specified time ***/ 239 | public void At(long time, Action callback) 240 | { 241 | long t = this.start + time; 242 | Schedule.Add(new EasyInterval(t, 0, callback)); 243 | } 244 | 245 | /*** Call a function every interval of time ***/ 246 | public void Every(long time, Action callback) 247 | { 248 | Intervals.Add(new EasyInterval(this.clock + time, time, callback)); 249 | } 250 | 251 | /*** Call a function in "time" seconds ***/ 252 | public void In(long time, Action callback) 253 | { 254 | this.At(this.clock - this.start + time, callback); 255 | } 256 | 257 | /*** Resets the clock and refreshes the blocks. ***/ 258 | public void Reset() 259 | { 260 | this.start = this.clock; 261 | this.ClearMessages(); // clear messages 262 | this.Refresh(); 263 | } 264 | 265 | /*** Refreshes blocks. If you add or remove blocks, call this. ***/ 266 | public void Refresh() 267 | { 268 | List kBlocks = new List(); 269 | GridTerminalSystem.GetBlocks(kBlocks); 270 | Blocks = new EasyBlocks(kBlocks); 271 | } 272 | } 273 | 274 | 275 | public class EasyBlocks 276 | { 277 | public List Blocks; 278 | 279 | // Constructor with IMyTerminalBlock list 280 | public EasyBlocks(List TBlocks) 281 | { 282 | this.Blocks = new List(); 283 | 284 | for(int i = 0; i < TBlocks.Count; i++) 285 | { 286 | EasyBlock Block = new EasyBlock(TBlocks[i]); 287 | this.Blocks.Add(Block); 288 | } 289 | } 290 | 291 | // Constructor with EasyBlock list 292 | public EasyBlocks(List Blocks) 293 | { 294 | this.Blocks = Blocks; 295 | } 296 | 297 | public EasyBlocks() 298 | { 299 | this.Blocks = new List(); 300 | } 301 | 302 | // Get number of blocks in list 303 | public int Count() 304 | { 305 | return this.Blocks.Count; 306 | } 307 | 308 | // Get a specific block from the list 309 | public EasyBlock GetBlock(int i) 310 | { 311 | return this.Blocks[i]; 312 | } 313 | 314 | /*********************/ 315 | /*** Block Filters ***/ 316 | /*********************/ 317 | 318 | /*** Interface Filters ***/ 319 | 320 | public EasyBlocks WithInterface() where T: class 321 | { 322 | List FilteredList = new List(); 323 | 324 | for(int i = 0; i < this.Blocks.Count; i++) 325 | { 326 | T block = this.Blocks[i].Block as T; 327 | 328 | if(block != null) 329 | { 330 | FilteredList.Add(this.Blocks[i]); 331 | } 332 | } 333 | 334 | return new EasyBlocks(FilteredList); 335 | } 336 | 337 | /*** Type Filters ***/ 338 | 339 | public EasyBlocks OfType(String Type) 340 | { 341 | return TypeFilter("==", Type); 342 | } 343 | 344 | public EasyBlocks NotOfType(String Type) 345 | { 346 | return TypeFilter("!=", Type); 347 | } 348 | 349 | public EasyBlocks OfTypeLike(String Type) 350 | { 351 | return TypeFilter("~", Type); 352 | } 353 | 354 | public EasyBlocks NotOfTypeLike(String Type) 355 | { 356 | return TypeFilter("!~", Type); 357 | } 358 | 359 | public EasyBlocks OfTypeRegex(String Pattern) 360 | { 361 | return TypeFilter("R", Pattern); 362 | } 363 | 364 | public EasyBlocks NotOfTypeRegex(String Pattern) 365 | { 366 | return TypeFilter("!R", Pattern); 367 | } 368 | 369 | protected EasyBlocks TypeFilter(String op, String Type) 370 | { 371 | List FilteredList = new List(); 372 | 373 | for(int i = 0; i < this.Blocks.Count; i++) 374 | { 375 | if(EasyCompare(op, this.Blocks[i].Type(), Type)) 376 | { 377 | FilteredList.Add(this.Blocks[i]); 378 | } 379 | } 380 | 381 | return new EasyBlocks(FilteredList); 382 | } 383 | 384 | /*** Name Filters ***/ 385 | 386 | public EasyBlocks Named(String Name) 387 | { 388 | return NameFilter("==", Name); 389 | } 390 | 391 | public EasyBlocks NotNamed(String Name) 392 | { 393 | return NameFilter("!=", Name); 394 | } 395 | 396 | public EasyBlocks NamedLike(String Name) 397 | { 398 | return NameFilter("~", Name); 399 | } 400 | 401 | public EasyBlocks NotNamedLike(String Name) 402 | { 403 | return NameFilter("!~", Name); 404 | } 405 | 406 | public EasyBlocks NamedRegex(String Pattern) 407 | { 408 | return NameFilter("R", Pattern); 409 | } 410 | 411 | public EasyBlocks NotNamedRegex(String Pattern) 412 | { 413 | return NameFilter("!R", Pattern); 414 | } 415 | 416 | protected EasyBlocks NameFilter(String op, String Name) 417 | { 418 | List FilteredList = new List(); 419 | 420 | for(int i = 0; i < this.Blocks.Count; i++) 421 | { 422 | if(EasyCompare(op, this.Blocks[i].Name(), Name)) 423 | { 424 | FilteredList.Add(this.Blocks[i]); 425 | } 426 | } 427 | 428 | return new EasyBlocks(FilteredList); 429 | } 430 | 431 | /*** Group Filters ***/ 432 | 433 | public EasyBlocks InGroupsNamed(String Group) 434 | { 435 | return GroupFilter("==", Group); 436 | } 437 | 438 | public EasyBlocks InGroupsNotNamed(String Group) 439 | { 440 | return GroupFilter("!=", Group); 441 | } 442 | 443 | public EasyBlocks InGroupsNamedLike(String Group) 444 | { 445 | return GroupFilter("~", Group); 446 | } 447 | 448 | public EasyBlocks InGroupsNotNamedLike(String Group) 449 | { 450 | return GroupFilter("!~", Group); 451 | } 452 | 453 | public EasyBlocks InGroupsNamedRegex(String Pattern) 454 | { 455 | return GroupFilter("R", Pattern); 456 | } 457 | 458 | public EasyBlocks InGroupsNotNamedRegex(String Pattern) 459 | { 460 | return GroupFilter("!R", Pattern); 461 | } 462 | 463 | public EasyBlocks GroupFilter(String op, String Group) 464 | { 465 | List FilteredList = new List(); 466 | 467 | List groups = new List(); 468 | EasyAPI.grid.GetBlockGroups(groups); 469 | List matchedGroups = new List(); 470 | List groupBlocks = new List(); 471 | 472 | for(int n = 0; n < groups.Count; n++) 473 | { 474 | if(EasyCompare(op, groups[n].Name, Group)) 475 | { 476 | matchedGroups.Add(groups[n]); 477 | } 478 | } 479 | 480 | for(int n = 0; n < matchedGroups.Count; n++) 481 | { 482 | for(int i = 0; i < this.Blocks.Count; i++) 483 | { 484 | IMyTerminalBlock block = this.Blocks[i].Block; 485 | matchedGroups[n].GetBlocks(groupBlocks); 486 | for(int j = 0; j < groupBlocks.Count; j++) 487 | { 488 | if(block == groupBlocks[j]) 489 | { 490 | FilteredList.Add(this.Blocks[i]); 491 | } 492 | } 493 | groupBlocks.Clear(); 494 | } 495 | } 496 | 497 | return new EasyBlocks(FilteredList); 498 | } 499 | 500 | /*** Sensor Filters ***/ 501 | 502 | public EasyBlocks SensorsActive(bool isActive = true) 503 | { 504 | List FilteredList = new List(); 505 | 506 | for(int i = 0; i < this.Blocks.Count; i++) 507 | { 508 | if(this.Blocks[i].Type() == "Sensor" && ((IMySensorBlock)this.Blocks[i].Block).IsActive == isActive) 509 | { 510 | FilteredList.Add(this.Blocks[i]); 511 | } 512 | } 513 | 514 | return new EasyBlocks(FilteredList); 515 | } 516 | 517 | public EasyBlocks RoomPressure(String op, Single percent) 518 | { 519 | List FilteredList = new List(); 520 | 521 | for(int i = 0; i < this.Blocks.Count; i++) 522 | { 523 | if(this.Blocks[i].RoomPressure(op, percent)) 524 | { 525 | FilteredList.Add(this.Blocks[i]); 526 | } 527 | } 528 | 529 | return new EasyBlocks(FilteredList); 530 | } 531 | 532 | 533 | /*** Advanced Filters ***/ 534 | 535 | public EasyBlocks FilterBy(Func action) 536 | { 537 | List FilteredList = new List(); 538 | 539 | for(int i = 0; i < this.Blocks.Count; i++) 540 | { 541 | if(action(this.Blocks[i])) 542 | { 543 | FilteredList.Add(this.Blocks[i]); 544 | } 545 | } 546 | 547 | return new EasyBlocks(FilteredList); 548 | } 549 | 550 | 551 | /*** Other ***/ 552 | 553 | public EasyBlocks First() 554 | { 555 | List FilteredList = new List(); 556 | 557 | if(this.Blocks.Count > 0) 558 | { 559 | FilteredList.Add(Blocks[0]); 560 | } 561 | 562 | return new EasyBlocks(FilteredList); 563 | } 564 | 565 | public EasyBlocks Add(EasyBlock Block) 566 | { 567 | this.Blocks.Add(Block); 568 | 569 | return this; 570 | } 571 | 572 | public EasyBlocks Plus(EasyBlocks Blocks) 573 | { 574 | List FilteredList = new List(); 575 | 576 | FilteredList.AddRange(this.Blocks); 577 | for(int i = 0; i < Blocks.Count(); i++) 578 | { 579 | if(!FilteredList.Contains(Blocks.GetBlock(i))) 580 | { 581 | FilteredList.Add(Blocks.GetBlock(i)); 582 | } 583 | } 584 | 585 | return new EasyBlocks(FilteredList); 586 | } 587 | 588 | public EasyBlocks Minus(EasyBlocks Blocks) 589 | { 590 | List FilteredList = new List(); 591 | 592 | FilteredList.AddRange(this.Blocks); 593 | for(int i = 0; i < Blocks.Count(); i++) 594 | { 595 | FilteredList.Remove(Blocks.GetBlock(i)); 596 | } 597 | 598 | return new EasyBlocks(FilteredList); 599 | } 600 | 601 | public static EasyBlocks operator +(EasyBlocks a, EasyBlocks b) 602 | { 603 | return a.Plus(b); 604 | } 605 | 606 | public static EasyBlocks operator -(EasyBlocks a, EasyBlocks b) 607 | { 608 | return a.Minus(b); 609 | } 610 | 611 | public EasyBlocks Plus(EasyBlock Block) 612 | { 613 | List FilteredList = new List(); 614 | 615 | FilteredList.AddRange(this.Blocks); 616 | 617 | if(!FilteredList.Contains(Block)) 618 | { 619 | FilteredList.Add(Block); 620 | } 621 | 622 | return new EasyBlocks(FilteredList); 623 | } 624 | 625 | public EasyBlocks Minus(EasyBlock Block) 626 | { 627 | List FilteredList = new List(); 628 | 629 | FilteredList.AddRange(this.Blocks); 630 | FilteredList.Remove(Block); 631 | 632 | return new EasyBlocks(FilteredList); 633 | } 634 | 635 | public static EasyBlocks operator +(EasyBlocks a, EasyBlock b) 636 | { 637 | return a.Plus(b); 638 | } 639 | 640 | public static EasyBlocks operator -(EasyBlocks a, EasyBlock b) 641 | { 642 | return a.Minus(b); 643 | } 644 | 645 | /*** Operations ***/ 646 | 647 | public EasyBlocks FindOrFail(string message) 648 | { 649 | if(this.Count() == 0) throw new Exception(message); 650 | 651 | return this; 652 | } 653 | 654 | public EasyBlocks Run(EasyAPI api, string type = "public") 655 | { 656 | for(int i = 0; i < this.Blocks.Count; i++) 657 | { 658 | this.Blocks[i].Run(api, type); 659 | } 660 | 661 | return this; 662 | } 663 | 664 | public EasyBlocks SendMessage(EasyMessage message) 665 | { 666 | for(int i = 0; i < this.Blocks.Count; i++) 667 | { 668 | this.Blocks[i].SendMessage(message); 669 | } 670 | 671 | return this; 672 | } 673 | 674 | 675 | public EasyBlocks ApplyAction(String Name) 676 | { 677 | for(int i = 0; i < this.Blocks.Count; i++) 678 | { 679 | this.Blocks[i].ApplyAction(Name); 680 | } 681 | 682 | return this; 683 | } 684 | 685 | public EasyBlocks SetProperty(String PropertyId, T value, int bleh = 0) 686 | { 687 | for(int i = 0; i < this.Blocks.Count; i++) 688 | { 689 | this.Blocks[i].SetProperty(PropertyId, value); 690 | } 691 | 692 | return this; 693 | } 694 | 695 | public EasyBlocks SetFloatValue(String PropertyId, float value, int bleh = 0) 696 | { 697 | for(int i = 0; i < this.Blocks.Count; i++) 698 | { 699 | this.Blocks[i].SetFloatValue(PropertyId, value); 700 | } 701 | 702 | return this; 703 | } 704 | 705 | public T GetProperty(String PropertyId, int bleh = 0) 706 | { 707 | return this.Blocks[0].GetProperty(PropertyId); 708 | } 709 | 710 | public EasyBlocks On() 711 | { 712 | for(int i = 0; i < this.Blocks.Count; i++) 713 | { 714 | this.Blocks[i].On(); 715 | } 716 | 717 | return this; 718 | } 719 | 720 | public EasyBlocks Off() 721 | { 722 | for(int i = 0; i < this.Blocks.Count; i++) 723 | { 724 | this.Blocks[i].Off(); 725 | } 726 | 727 | return this; 728 | } 729 | 730 | public EasyBlocks Toggle() 731 | { 732 | for(int i = 0; i < this.Blocks.Count; i++) 733 | { 734 | this.Blocks[i].Toggle(); 735 | } 736 | 737 | return this; 738 | } 739 | 740 | public EasyBlocks RunPB(string argument = "") 741 | { 742 | for(int i = 0; i < this.Blocks.Count; i++) 743 | { 744 | this.Blocks[i].RunPB(argument); 745 | } 746 | 747 | return this; 748 | } 749 | 750 | public EasyBlocks WritePublicText(string text) 751 | { 752 | for(int i = 0; i < this.Blocks.Count; i++) 753 | { 754 | this.Blocks[i].WritePublicText(text); 755 | } 756 | 757 | return this; 758 | } 759 | 760 | public EasyBlocks WriteCustomData(string text) 761 | { 762 | for(int i = 0; i < this.Blocks.Count; i++) 763 | { 764 | this.Blocks[i].WriteCustomData(text); 765 | } 766 | 767 | return this; 768 | } 769 | 770 | public EasyBlocks WritePublicTitle(string text) 771 | { 772 | for(int i = 0; i < this.Blocks.Count; i++) 773 | { 774 | this.Blocks[i].WritePublicTitle(text); 775 | } 776 | 777 | return this; 778 | } 779 | 780 | public EasyBlocks WritePrivateTitle(string text) 781 | { 782 | for(int i = 0; i < this.Blocks.Count; i++) 783 | { 784 | this.Blocks[i].WritePublicTitle(text); 785 | } 786 | 787 | return this; 788 | } 789 | 790 | public EasyBlocks AppendPublicText(string text) 791 | { 792 | for(int i = 0; i < this.Blocks.Count; i++) 793 | { 794 | this.Blocks[i].AppendPublicText(text); 795 | } 796 | 797 | return this; 798 | } 799 | 800 | public EasyInventory Items() 801 | { 802 | return new EasyInventory(this.Blocks); 803 | } 804 | 805 | public string DebugDump(bool throwIt = true) 806 | { 807 | String output = "\n"; 808 | 809 | for(int i = 0; i < this.Blocks.Count; i++) 810 | { 811 | output += this.Blocks[i].Type() + ": " + this.Blocks[i].Name() + "\n"; 812 | } 813 | 814 | if(throwIt) 815 | throw new Exception(output); 816 | else 817 | return output; 818 | } 819 | 820 | public string DebugDumpActions(bool throwIt = true) 821 | { 822 | String output = "\n"; 823 | 824 | for(int i = 0; i < this.Blocks.Count; i++) 825 | { 826 | output += "[ " + this.Blocks[i].Type() + ": " + this.Blocks[i].Name() + " ]\n"; 827 | output += "*** ACTIONS ***\n"; 828 | List actions = this.Blocks[i].GetActions(); 829 | 830 | for(int j = 0; j < actions.Count; j++) 831 | { 832 | output += actions[j].Id + ":" + actions[j].Name + "\n"; 833 | } 834 | 835 | output += "\n\n"; 836 | } 837 | 838 | if(throwIt) 839 | throw new Exception(output); 840 | else 841 | return output; 842 | } 843 | 844 | public string DebugDumpProperties(bool throwIt = true) 845 | { 846 | String output = "\n"; 847 | 848 | for(int i = 0; i < this.Blocks.Count; i++) 849 | { 850 | output += "[ " + this.Blocks[i].Type() + ": " + this.Blocks[i].Name() + " ]\n"; 851 | output += "*** PROPERTIES ***\n"; 852 | List properties = this.Blocks[i].GetProperties(); 853 | 854 | for(int j = 0; j < properties.Count; j++) 855 | { 856 | output += properties[j].TypeName + ": " + properties[j].Id + "\n"; 857 | } 858 | 859 | output += "\n\n"; 860 | } 861 | 862 | if(throwIt) 863 | throw new Exception(output); 864 | else 865 | return output; 866 | } 867 | 868 | /*** Events ***/ 869 | 870 | public EasyBlocks AddEvent(Func evnt, Func action, bool onChange = false) 871 | { 872 | for(int i = 0; i < this.Blocks.Count; i++) 873 | { 874 | this.Blocks[i].AddEvent(evnt, action, onChange); 875 | } 876 | 877 | return this; 878 | } 879 | 880 | private bool EasyCompare(String op, String a, String b) 881 | { 882 | switch(op) 883 | { 884 | case "==": 885 | return (a == b); 886 | case "!=": 887 | return (a != b); 888 | case "~": 889 | return a.Contains(b); 890 | case "!~": 891 | return !a.Contains(b); 892 | case "R": 893 | System.Text.RegularExpressions.Match m = (new System.Text.RegularExpressions.Regex(b)).Match(a); 894 | while(m.Success) 895 | { 896 | return true; 897 | } 898 | return false; 899 | case "!R": 900 | return !EasyCompare("R", a, b); 901 | } 902 | return false; 903 | } 904 | 905 | } 906 | public struct EasyBlock 907 | { 908 | public IMyTerminalBlock Block; 909 | private IMySlimBlock slim; 910 | 911 | public EasyBlock(IMyTerminalBlock Block) 912 | { 913 | this.Block = Block; 914 | this.slim = null; 915 | } 916 | 917 | public IMySlimBlock Slim() 918 | { 919 | if(this.slim == null) 920 | { 921 | this.slim = this.Block.CubeGrid.GetCubeBlock(this.Block.Position); 922 | } 923 | 924 | return this.slim; 925 | } 926 | 927 | public String Type() 928 | { 929 | return this.Block.DefinitionDisplayNameText; 930 | } 931 | 932 | public Single Damage() 933 | { 934 | return this.CurrentDamage() / this.MaxIntegrity() * (Single)100.0; 935 | } 936 | 937 | public Single CurrentDamage() 938 | { 939 | return this.Slim().CurrentDamage; 940 | } 941 | 942 | public Single MaxIntegrity() 943 | { 944 | return this.Slim().MaxIntegrity; 945 | } 946 | 947 | public bool Open() 948 | { 949 | IMyDoor door = Block as IMyDoor; 950 | 951 | if(door != null) 952 | { 953 | return door.Status == DoorStatus.Open; 954 | } 955 | 956 | return false; 957 | } 958 | 959 | public String Name() 960 | { 961 | return this.Block.CustomName; 962 | } 963 | 964 | public void SendMessage(EasyMessage message) 965 | { 966 | // only programmable blocks can receive messages 967 | if(Type() == "Programmable block") 968 | { 969 | SetName(Name() + "\0" + message.Serialize()); 970 | } 971 | } 972 | 973 | public List NameParameters(char start = '[', char end = ']') 974 | { 975 | List matches; 976 | 977 | this.NameRegex(@"\" + start + @"(.*?)\" + end, out matches); 978 | 979 | return matches; 980 | } 981 | 982 | public bool RoomPressure(String op, Single percent) 983 | { 984 | String roomPressure = DetailedInfo()["Room pressure"]; 985 | 986 | Single pressure = 0; 987 | 988 | if(roomPressure != "Not pressurized") 989 | { 990 | pressure = Convert.ToSingle(roomPressure.TrimEnd('%')); 991 | } 992 | 993 | switch(op) 994 | { 995 | case "<": 996 | return pressure < percent; 997 | case "<=": 998 | return pressure <= percent; 999 | case ">=": 1000 | return pressure >= percent; 1001 | case ">": 1002 | return pressure > percent; 1003 | case "==": 1004 | return pressure == percent; 1005 | case "!=": 1006 | return pressure != percent; 1007 | } 1008 | 1009 | return false; 1010 | } 1011 | 1012 | public Dictionary DetailedInfo() 1013 | { 1014 | Dictionary properties = new Dictionary(); 1015 | 1016 | var statements = this.Block.DetailedInfo.Split('\n'); 1017 | 1018 | for(int n = 0; n < statements.Length; n++) 1019 | { 1020 | var pair = statements[n].Split(':'); 1021 | 1022 | properties.Add(pair[0], pair[1].Substring(1)); 1023 | } 1024 | 1025 | return properties; 1026 | } 1027 | 1028 | 1029 | public bool NameRegex(String Pattern, out List Matches) 1030 | { 1031 | System.Text.RegularExpressions.Match m = (new System.Text.RegularExpressions.Regex(Pattern)).Match(this.Block.CustomName); 1032 | 1033 | Matches = new List(); 1034 | 1035 | bool success = false; 1036 | while(m.Success) 1037 | { 1038 | if(m.Groups.Count > 1) 1039 | { 1040 | Matches.Add(m.Groups[1].Value); 1041 | } 1042 | success = true; 1043 | 1044 | m = m.NextMatch(); 1045 | } 1046 | 1047 | return success; 1048 | } 1049 | 1050 | public bool NameRegex(String Pattern) 1051 | { 1052 | List matches; 1053 | 1054 | return this.NameRegex(Pattern, out matches); 1055 | } 1056 | 1057 | public ITerminalAction GetAction(String Name) 1058 | { 1059 | return this.Block.GetActionWithName(Name); 1060 | } 1061 | 1062 | public EasyBlock ApplyAction(String Name) 1063 | { 1064 | ITerminalAction Action = this.GetAction(Name); 1065 | 1066 | if(Action != null) 1067 | { 1068 | Action.Apply(this.Block); 1069 | } 1070 | 1071 | return this; 1072 | } 1073 | 1074 | public T GetProperty(String PropertyId) 1075 | { 1076 | return Sandbox.ModAPI.Interfaces.TerminalPropertyExtensions.GetValue(this.Block, PropertyId); 1077 | } 1078 | 1079 | public EasyBlock SetProperty(String PropertyId, T value) 1080 | { 1081 | try 1082 | { 1083 | var prop = this.GetProperty(PropertyId); 1084 | Sandbox.ModAPI.Interfaces.TerminalPropertyExtensions.SetValue(this.Block, PropertyId, value); 1085 | } 1086 | catch(Exception e) 1087 | { 1088 | 1089 | } 1090 | 1091 | return this; 1092 | } 1093 | 1094 | public EasyBlock SetFloatValue(String PropertyId, float value) 1095 | { 1096 | try 1097 | { 1098 | Sandbox.ModAPI.Interfaces.TerminalPropertyExtensions.SetValueFloat(this.Block, PropertyId, value); 1099 | } 1100 | catch(Exception e) 1101 | { 1102 | 1103 | } 1104 | 1105 | return this; 1106 | } 1107 | 1108 | public EasyBlock On() 1109 | { 1110 | this.ApplyAction("OnOff_On"); 1111 | 1112 | return this; 1113 | } 1114 | 1115 | public EasyBlock Off() 1116 | { 1117 | this.ApplyAction("OnOff_Off"); 1118 | 1119 | return this; 1120 | } 1121 | 1122 | public EasyBlock Toggle() 1123 | { 1124 | if(this.Block.IsWorking) 1125 | { 1126 | this.Off(); 1127 | } 1128 | else 1129 | { 1130 | this.On(); 1131 | } 1132 | 1133 | return this; 1134 | } 1135 | 1136 | public EasyBlock Run(EasyAPI api, string type = "public") 1137 | { 1138 | var cmd = new EasyCommands(api); 1139 | switch(type) 1140 | { 1141 | case "private": 1142 | cmd.handle(this.GetCustomData()); 1143 | break; 1144 | default: 1145 | cmd.handle(this.GetPublicText()); 1146 | break; 1147 | } 1148 | 1149 | return this; 1150 | } 1151 | 1152 | public EasyBlock RunPB(string argument = "") 1153 | { 1154 | IMyProgrammableBlock pb = Block as IMyProgrammableBlock; 1155 | 1156 | if(pb != null) 1157 | { 1158 | pb.TryRun(argument); 1159 | } 1160 | 1161 | return this; 1162 | } 1163 | 1164 | public string GetPublicText() 1165 | { 1166 | string ret = ""; 1167 | 1168 | IMyTextPanel textPanel = Block as IMyTextPanel; 1169 | 1170 | if(textPanel != null) 1171 | { 1172 | ret = textPanel.GetPublicText(); 1173 | } 1174 | 1175 | return ret; 1176 | } 1177 | 1178 | public string GetCustomData() 1179 | { 1180 | string ret = ""; 1181 | 1182 | IMyTextPanel textPanel = Block as IMyTextPanel; 1183 | 1184 | if(textPanel != null) 1185 | { 1186 | ret = textPanel.CustomData; 1187 | } 1188 | 1189 | return ret; 1190 | } 1191 | 1192 | public EasyBlock WritePublicTitle(string text) 1193 | { 1194 | IMyTextPanel textPanel = Block as IMyTextPanel; 1195 | 1196 | if(textPanel != null) 1197 | { 1198 | textPanel.WritePublicTitle(text); 1199 | } 1200 | 1201 | return this; 1202 | } 1203 | 1204 | public EasyBlock WritePublicText(string text) 1205 | { 1206 | IMyTextPanel textPanel = Block as IMyTextPanel; 1207 | 1208 | if(textPanel != null) 1209 | { 1210 | textPanel.WritePublicText(text, false); 1211 | } 1212 | 1213 | return this; 1214 | } 1215 | 1216 | public EasyBlock WriteCustomData(string text) 1217 | { 1218 | IMyTextPanel textPanel = Block as IMyTextPanel; 1219 | 1220 | if(textPanel != null) 1221 | { 1222 | textPanel.CustomData = text; 1223 | } 1224 | 1225 | return this; 1226 | } 1227 | 1228 | public EasyBlock AppendPublicText(string text) 1229 | { 1230 | IMyTextPanel textPanel = Block as IMyTextPanel; 1231 | 1232 | if(textPanel != null) 1233 | { 1234 | textPanel.WritePublicText(text, true); 1235 | } 1236 | 1237 | return this; 1238 | } 1239 | 1240 | public EasyBlock SetName(String Name) 1241 | { 1242 | this.Block.CustomName = Name; 1243 | 1244 | return this; 1245 | } 1246 | 1247 | public List GetActions() 1248 | { 1249 | List actions = new List(); 1250 | this.Block.GetActions(actions); 1251 | return actions; 1252 | } 1253 | 1254 | public List GetProperties() 1255 | { 1256 | List properties = new List(); 1257 | this.Block.GetProperties(properties); 1258 | return properties; 1259 | } 1260 | 1261 | /*** Events ***/ 1262 | 1263 | public EasyBlock AddEvent(Func evnt, Func action, bool onChange = false) 1264 | { 1265 | EasyEvent.add(new EasyEvent(this, evnt, action, onChange)); 1266 | 1267 | return this; 1268 | } 1269 | 1270 | public EasyInventory Items(Nullable fix_duplicate_name_bug = null) 1271 | { 1272 | List Blocks = new List(); 1273 | Blocks.Add(this); 1274 | 1275 | return new EasyInventory(Blocks); 1276 | } 1277 | 1278 | public static bool operator ==(EasyBlock a, EasyBlock b) 1279 | { 1280 | return a.Block == b.Block; 1281 | } 1282 | 1283 | public override bool Equals(object o) 1284 | { 1285 | return (EasyBlock)o == this; 1286 | } 1287 | 1288 | public override int GetHashCode() 1289 | { 1290 | return Block.GetHashCode(); 1291 | } 1292 | 1293 | public static bool operator !=(EasyBlock a, EasyBlock b) 1294 | { 1295 | return a.Block != b.Block; 1296 | } 1297 | 1298 | 1299 | } 1300 | // Stores all items in matched block inventories for later filtering 1301 | public class EasyInventory 1302 | { 1303 | public List Items; 1304 | 1305 | public EasyInventory(List Blocks) 1306 | { 1307 | this.Items = new List(); 1308 | 1309 | // Get contents of all inventories in list and add them to EasyItems list. 1310 | for(int i = 0; i < Blocks.Count; i++) 1311 | { 1312 | EasyBlock Block = Blocks[i]; 1313 | 1314 | for(int j = 0; j < Block.Block.InventoryCount; j++) 1315 | { 1316 | IMyInventory Inventory = Block.Block.GetInventory(j); 1317 | 1318 | List Items = Inventory.GetItems(); 1319 | 1320 | for(int k = 0; k < Items.Count; k++) 1321 | { 1322 | this.Items.Add(new EasyItem(Block, j, Inventory, k, Items[k])); 1323 | } 1324 | } 1325 | } 1326 | } 1327 | 1328 | public EasyInventory(List Items) 1329 | { 1330 | this.Items = Items; 1331 | } 1332 | 1333 | public EasyInventory OfType(String SubTypeId) 1334 | { 1335 | List FilteredItems = new List(); 1336 | 1337 | for(int i = 0; i < this.Items.Count; i++) 1338 | { 1339 | if(this.Items[i].Type() == SubTypeId) 1340 | { 1341 | FilteredItems.Add(this.Items[i]); 1342 | } 1343 | } 1344 | 1345 | return new EasyInventory(FilteredItems); 1346 | } 1347 | 1348 | public EasyInventory InInventory(int Index) 1349 | { 1350 | List FilteredItems = new List(); 1351 | 1352 | for(int i = 0; i < this.Items.Count; i++) 1353 | { 1354 | if(this.Items[i].InventoryIndex == Index) 1355 | { 1356 | FilteredItems.Add(this.Items[i]); 1357 | } 1358 | } 1359 | 1360 | return new EasyInventory(FilteredItems); 1361 | } 1362 | 1363 | public VRage.MyFixedPoint Count() 1364 | { 1365 | VRage.MyFixedPoint Total = 0; 1366 | 1367 | for(int i = 0; i < Items.Count; i++) 1368 | { 1369 | Total += Items[i].Amount(); 1370 | } 1371 | 1372 | return Total; 1373 | } 1374 | 1375 | public EasyInventory First() 1376 | { 1377 | List FilteredItems = new List(); 1378 | 1379 | if(this.Items.Count > 0) 1380 | { 1381 | FilteredItems.Add(this.Items[0]); 1382 | } 1383 | 1384 | return new EasyInventory(FilteredItems); 1385 | } 1386 | 1387 | public void MoveTo(EasyBlocks Blocks, int Inventory = 0) 1388 | { 1389 | for(int i = 0; i < Items.Count; i++) 1390 | { 1391 | Items[i].MoveTo(Blocks, Inventory); 1392 | } 1393 | } 1394 | } 1395 | // This represents a single stack of items in the inventory 1396 | public struct EasyItem 1397 | { 1398 | private EasyBlock Block; 1399 | public int InventoryIndex; 1400 | private IMyInventory Inventory; 1401 | public int ItemIndex; 1402 | private IMyInventoryItem Item; 1403 | 1404 | public EasyItem(EasyBlock Block, int InventoryIndex, IMyInventory Inventory, int ItemIndex, IMyInventoryItem Item) 1405 | { 1406 | this.Block = Block; 1407 | this.InventoryIndex = InventoryIndex; 1408 | this.Inventory = Inventory; 1409 | this.ItemIndex = ItemIndex; 1410 | this.Item = Item; 1411 | } 1412 | 1413 | public String Type(int dummy = 0) 1414 | { 1415 | return this.Item.Content.SubtypeId.ToString(); 1416 | } 1417 | 1418 | public VRage.MyFixedPoint Amount() 1419 | { 1420 | return this.Item.Amount; 1421 | } 1422 | 1423 | public void MoveTo(EasyBlocks Blocks, int Inventory = 0, int dummy = 0) 1424 | { 1425 | // Right now it moves them to all of them. Todo: determine if the move was successful an exit for if it was. 1426 | // In the future you will be able to sort EasyBlocks and use this to prioritize where the items get moved. 1427 | for(int i = 0; i < Blocks.Count(); i++) 1428 | { 1429 | this.Inventory.TransferItemTo(Blocks.GetBlock(i).Block.GetInventory(Inventory), ItemIndex); 1430 | } 1431 | } 1432 | } 1433 | public struct EasyInterval 1434 | { 1435 | public long interval; 1436 | public long time; 1437 | public Action action; 1438 | 1439 | public EasyInterval(long t, long i, Action a) 1440 | { 1441 | this.time = t; 1442 | this.interval = i; 1443 | this.action = a; 1444 | } 1445 | } 1446 | public struct EasyMessage 1447 | { 1448 | public EasyBlock From; 1449 | public String Subject; 1450 | public String Message; 1451 | public long Timestamp; 1452 | 1453 | // unserialize 1454 | public EasyMessage(String serialized) 1455 | { 1456 | var parts = serialized.Split(':'); 1457 | if(parts.Length < 4) 1458 | { 1459 | throw new Exception("Error unserializing message."); 1460 | } 1461 | int numberInGrid = Convert.ToInt32(System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[0]))); 1462 | var blocks = new List(); 1463 | EasyAPI.grid.GetBlocksOfType(blocks, delegate(IMyTerminalBlock block) { 1464 | return (block as IMyProgrammableBlock).NumberInGrid == numberInGrid; 1465 | }); 1466 | if(blocks.Count == 0) 1467 | { 1468 | throw new Exception("Message sender no longer exits!"); 1469 | } 1470 | this.From = new EasyBlock((IMyTerminalBlock)blocks[0]); 1471 | this.Subject = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[1])); 1472 | this.Message = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[2])); 1473 | this.Timestamp = Convert.ToInt64(System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[3]))); 1474 | } 1475 | 1476 | public EasyMessage(EasyBlock From, String Subject, String Message) 1477 | { 1478 | this.From = From; 1479 | this.Subject = Subject; 1480 | this.Message = Message; 1481 | this.Timestamp = DateTime.Now.Ticks; 1482 | } 1483 | 1484 | public String Serialize() 1485 | { 1486 | String text = ""; 1487 | 1488 | text += System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("" + From.Block.NumberInGrid)); 1489 | text += ":" + System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Subject)); 1490 | text += ":" + System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Message)); 1491 | text += ":" + System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("" + Timestamp)); 1492 | 1493 | return text; 1494 | } 1495 | } 1496 | /*** Commands ***/ 1497 | 1498 | // Base EasyCommands class 1499 | public class EasyCommands 1500 | { 1501 | /*** Private Properties ***/ 1502 | 1503 | private EasyAPI api; // The selected menu item (child) 1504 | private EasyBlocks blocks; 1505 | public Dictionary functions = new Dictionary(); 1506 | private int pos = 0; 1507 | private string text = ""; 1508 | 1509 | /*** Constructors ***/ 1510 | 1511 | public EasyCommands(EasyAPI api) 1512 | { 1513 | this.api = api; 1514 | } 1515 | 1516 | /*** Private Methods ***/ 1517 | 1518 | public void handle(string text) 1519 | { 1520 | this.pos = 0; 1521 | this.text = text; 1522 | 1523 | while(pos < text.Length) 1524 | { 1525 | doCommand(); 1526 | pos++; 1527 | } 1528 | } 1529 | 1530 | private void failure(string message) 1531 | { 1532 | throw new Exception("EasyCommand Error: " + message); 1533 | } 1534 | 1535 | private void skipWhitespace() 1536 | { 1537 | while(pos < text.Length && char.IsWhiteSpace(text, pos)) 1538 | { 1539 | pos++; 1540 | } 1541 | } 1542 | 1543 | private void skipLineComment() 1544 | { 1545 | pos += 2; 1546 | while(pos < text.Length) 1547 | { 1548 | if(text[pos] == "\n"[0]) 1549 | { 1550 | pos++; 1551 | break; 1552 | } 1553 | pos++; 1554 | } 1555 | } 1556 | 1557 | private void skipBlockComment() 1558 | { 1559 | pos += 2; 1560 | while(pos < text.Length && pos + 1 < text.Length) 1561 | { 1562 | if(text[pos] == '*' && text[pos+1] == '/') 1563 | { 1564 | pos += 2; 1565 | break; 1566 | } 1567 | pos++; 1568 | } 1569 | } 1570 | 1571 | private void skipNonCode() 1572 | { 1573 | while(pos < text.Length) 1574 | { 1575 | if(char.IsWhiteSpace(text, pos)) skipWhitespace(); 1576 | else if(pos + 1 < text.Length && text[pos] == '/') 1577 | { 1578 | if(text[pos+1] == '/') skipLineComment(); 1579 | else if(text[pos+1] == '*') skipBlockComment(); 1580 | else break; 1581 | } 1582 | else break; 1583 | } 1584 | } 1585 | 1586 | private string getIdentifier() 1587 | { 1588 | string identifier = ""; 1589 | while(pos < text.Length && char.IsLetterOrDigit(text[pos])) 1590 | { 1591 | identifier += text[pos]; 1592 | pos++; 1593 | } 1594 | return identifier; 1595 | } 1596 | 1597 | private string getParm() 1598 | { 1599 | string param = ""; 1600 | skipNonCode(); 1601 | if(pos < text.Length && text[pos] == '(') 1602 | { 1603 | pos++; 1604 | skipNonCode(); 1605 | if(pos < text.Length && text[pos] == '"') 1606 | { 1607 | pos++; 1608 | while(pos < text.Length) 1609 | { 1610 | if(text[pos] == '"') 1611 | { 1612 | pos++; 1613 | break; 1614 | } 1615 | else if(text[pos] == '\\' && pos + 1 < text.Length) 1616 | { 1617 | if(text[pos + 1] == '"') 1618 | { 1619 | param += '"'; 1620 | pos++; 1621 | } 1622 | else if(text[pos + 1] == 'n') 1623 | { 1624 | param += "\n"; 1625 | pos++; 1626 | } 1627 | else 1628 | { 1629 | param += text[pos]; 1630 | } 1631 | } 1632 | else 1633 | { 1634 | param += text[pos]; 1635 | } 1636 | pos++; 1637 | } 1638 | } 1639 | skipNonCode(); 1640 | 1641 | if(pos < text.Length && text[pos]== ')') 1642 | { 1643 | pos++; 1644 | } 1645 | } 1646 | 1647 | return param; 1648 | } 1649 | 1650 | private string getFunction() 1651 | { 1652 | // Todo this is REALLY basic and it should do a lot more parsing instead of just looking for the end curly brace. Functions will break if a curly brace appears anywhere inside them 1653 | string code = ""; 1654 | while(pos < text.Length) 1655 | { 1656 | if(text[pos] == '}') 1657 | { 1658 | pos++; 1659 | break; 1660 | } 1661 | code += text[pos]; 1662 | pos++; 1663 | } 1664 | return code; 1665 | } 1666 | 1667 | private void require(char c) 1668 | { 1669 | if(pos < text.Length && text[pos] == c) 1670 | { 1671 | pos++; 1672 | return; 1673 | } 1674 | failure("Required: " + c); 1675 | } 1676 | 1677 | private void doCommand() 1678 | { 1679 | while(pos < text.Length && text[pos] != ';') 1680 | { 1681 | skipNonCode(); 1682 | string command = getIdentifier(); 1683 | 1684 | if(command == "") 1685 | { 1686 | return; 1687 | } 1688 | 1689 | string parm = ""; 1690 | 1691 | switch(command) 1692 | { 1693 | case "function": 1694 | skipNonCode(); 1695 | string identifier = getIdentifier(); 1696 | skipNonCode(); 1697 | require('('); 1698 | skipNonCode(); 1699 | require(')'); 1700 | skipNonCode(); 1701 | require('{'); 1702 | skipNonCode(); 1703 | string function = getFunction(); 1704 | if(functions.ContainsKey(identifier)) 1705 | { 1706 | failure("Function " + identifier + " already defined!"); 1707 | } 1708 | functions.Add(identifier, function); 1709 | return; 1710 | case "Echo": 1711 | parm = getParm(); 1712 | api.Echo(parm); 1713 | break; 1714 | case "Blocks": 1715 | api.Refresh(); 1716 | this.blocks = api.Blocks; 1717 | break; 1718 | /*** Actions ***/ 1719 | case "ApplyAction": 1720 | parm = getParm(); 1721 | blocks.ApplyAction(parm); 1722 | break; 1723 | case "WritePublicText": 1724 | parm = getParm(); 1725 | blocks.WritePublicText(parm); 1726 | break; 1727 | case "WriteCustomData": 1728 | case "WritePrivateText": 1729 | parm = getParm(); 1730 | blocks.WriteCustomData(parm); 1731 | break; 1732 | case "AppendPublicText": 1733 | parm = getParm(); 1734 | blocks.AppendPublicText(parm); 1735 | break; 1736 | case "On": 1737 | parm = getParm(); 1738 | blocks.On(); 1739 | break; 1740 | case "Off": 1741 | parm = getParm(); 1742 | blocks.Off(); 1743 | break; 1744 | case "Toggle": 1745 | parm = getParm(); 1746 | blocks.Toggle(); 1747 | break; 1748 | case "DebugDump": 1749 | parm = getParm(); 1750 | blocks.DebugDump(); 1751 | break; 1752 | case "DebugDumpActions": 1753 | parm = getParm(); 1754 | blocks.DebugDumpActions(); 1755 | break; 1756 | case "DebugDumpProperties": 1757 | parm = getParm(); 1758 | blocks.DebugDumpProperties(); 1759 | break; 1760 | case "Run": 1761 | parm = getParm(); 1762 | blocks.Run(api, parm); 1763 | break; 1764 | case "RunPB": 1765 | parm = getParm(); 1766 | blocks.RunPB(parm); 1767 | break; 1768 | 1769 | /*** Filters ***/ 1770 | case "Named": 1771 | parm = getParm(); 1772 | blocks = blocks.Named(parm); 1773 | break; 1774 | case "NamedLike": 1775 | parm = getParm(); 1776 | blocks = blocks.NamedLike(parm); 1777 | break; 1778 | case "NotNamed": 1779 | parm = getParm(); 1780 | blocks = blocks.NotNamed(parm); 1781 | break; 1782 | case "NotNamedLike": 1783 | parm = getParm(); 1784 | blocks = blocks.NotNamedLike(parm); 1785 | break; 1786 | case "InGroupsNamed": 1787 | parm = getParm(); 1788 | blocks = blocks.InGroupsNamed(parm); 1789 | break; 1790 | case "InGroupsNamedLike": 1791 | parm = getParm(); 1792 | blocks = blocks.InGroupsNamedLike(parm); 1793 | break; 1794 | case "InGroupsNotNamed": 1795 | parm = getParm(); 1796 | blocks = blocks.InGroupsNotNamed(parm); 1797 | break; 1798 | case "InGroupsNotNamedLike": 1799 | parm = getParm(); 1800 | blocks = blocks.InGroupsNotNamedLike(parm); 1801 | break; 1802 | case "OfType": 1803 | parm = getParm(); 1804 | blocks = blocks.OfType(parm); 1805 | break; 1806 | case "OfTypeLike": 1807 | parm = getParm(); 1808 | blocks = blocks.OfTypeLike(parm); 1809 | break; 1810 | case "NotOfType": 1811 | parm = getParm(); 1812 | blocks = blocks.NotOfType(parm); 1813 | break; 1814 | case "NotOfTypeLike": 1815 | parm = getParm(); 1816 | blocks = blocks.OfTypeLike(parm); 1817 | break; 1818 | default: 1819 | failure("Invalid command: '" + command + "'"); 1820 | break; 1821 | } 1822 | 1823 | skipNonCode(); 1824 | 1825 | if(pos < text.Length && text[pos] == '.') pos++; 1826 | } 1827 | } 1828 | } 1829 | public class EasyEvent 1830 | { 1831 | private Func op; // The comparison function 1832 | 1833 | private EasyBlock block; // Object to pass through to the callback when the event is triggered 1834 | 1835 | private Func callback; // What to call when the event occurs 1836 | 1837 | private bool last = false; 1838 | 1839 | private bool onChange = false; 1840 | 1841 | public EasyEvent(EasyBlock block, Func op, Func callback, bool onChange = false) 1842 | { 1843 | this.op = op; 1844 | this.callback = callback; 1845 | this.block = block; 1846 | this.onChange = onChange; 1847 | } 1848 | 1849 | public bool process() 1850 | { 1851 | bool result = (this.op)(this.block); 1852 | 1853 | if(result && (!onChange || !last)) 1854 | { 1855 | last = result; 1856 | return (this.callback)(this.block); 1857 | } 1858 | 1859 | last = result; 1860 | return true; 1861 | } 1862 | 1863 | /*** static ***/ 1864 | 1865 | private static List events = new List(); 1866 | 1867 | public static void handle() 1868 | { 1869 | for(int i = 0; i < events.Count; i++) 1870 | { 1871 | if(!events[i].process()) 1872 | { 1873 | events.Remove(events[i]); 1874 | } 1875 | } 1876 | } 1877 | 1878 | public static void add(EasyEvent e) 1879 | { 1880 | events.Add(e); 1881 | } 1882 | } 1883 | -------------------------------------------------------------------------------- /modules/EasyAPI/build.bat: -------------------------------------------------------------------------------- 1 | copy /b ^ 2 | src\EasyAPI.cs +^ 3 | src\EasyBlocks.cs +^ 4 | src\EasyBlock.cs +^ 5 | src\EasyInventory.cs +^ 6 | src\EasyItem.cs +^ 7 | src\EasyInterval.cs +^ 8 | src\EasyMessage.cs +^ 9 | src\EasyUtils.cs +^ 10 | src\EasyCommands.cs +^ 11 | src\EasyEvent.cs ^ 12 | EasyAPI.cs 13 | -------------------------------------------------------------------------------- /modules/EasyAPI/examples/auto_close_doors.cs: -------------------------------------------------------------------------------- 1 | public class Example : EasyAPI 2 | { 3 | EasyBlocks doors; 4 | 5 | public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) 6 | { 7 | doors = Blocks.OfType("Door"); 8 | 9 | // split work over time so it doesn't throw a complexity error (tested with 384 doors) 10 | In(1 * EasyAPI.Seconds, delegate() { // In one second, create the events. 11 | doors.AddEvent( 12 | delegate(EasyBlock block) { // When a door is opened 13 | return block.Open(); 14 | }, 15 | delegate(EasyBlock block) { // Do the following 16 | In(2 * EasyAPI.Seconds, delegate() { // In 2 seconds 17 | block.ApplyAction("Open_Off"); // close the door 18 | }); 19 | 20 | return true; 21 | }, 22 | true // only trigger event when the condition (door open) goes from false to true 23 | ); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /modules/EasyAPI/examples/event_on_door_open_close.cs: -------------------------------------------------------------------------------- 1 | public class Example : EasyAPI 2 | { 3 | public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) 4 | { 5 | Blocks.OfTypeLike("Door").AddEvent( 6 | delegate(EasyBlock block) { 7 | return block.Open(); 8 | }, 9 | doorOpened, 10 | true 11 | ).AddEvent( 12 | delegate(EasyBlock block) { 13 | return !block.Open(); 14 | }, 15 | doorClosed, 16 | true 17 | ); 18 | } 19 | 20 | public bool doorOpened(EasyBlock door) 21 | { 22 | // Do something when door is opened 23 | 24 | return true; 25 | } 26 | 27 | public bool doorClosed(EasyBlock door) 28 | { 29 | // Do something when door is closed 30 | 31 | return true; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /modules/EasyAPI/examples/toggle_doors_on_damage.cs: -------------------------------------------------------------------------------- 1 | public class Example : EasyAPI 2 | { 3 | public bool damaged1Percent(EasyBlock b) 4 | { 5 | // Get parameters from the name (separated by '[' and ']') 6 | var parameters = b.NameParameters('[', ']'); 7 | 8 | // Close doors specified in parameters 9 | for(int i = 0; i < parameters.Count; i++) 10 | { 11 | Blocks.Named(parameters[i]).ApplyAction("Open_Off"); 12 | } 13 | 14 | // Add event when the damage is repaired so we can reopen the doors 15 | AddEvent( 16 | b, // add it to this block 17 | delegate(EasyBlock block) { 18 | return block.Damage() < 1; 19 | }, 20 | notDamaged1Percent 21 | ); 22 | 23 | return false; // Remove the event once it is triggered 24 | } 25 | 26 | public bool notDamaged1Percent(EasyBlock b) 27 | { 28 | // Get parameters from the name (separated by '[' and ']') 29 | var parameters = b.NameParameters('[', ']'); 30 | 31 | // Open doors specified in parameters 32 | for(int i = 0; i < parameters.Count; i++) 33 | { 34 | Blocks.Named(parameters[i]).ApplyAction("Open_On"); 35 | } 36 | 37 | // Add back the original event to close doors on damage. 38 | AddEvent( 39 | b, // add it to this block 40 | delegate(EasyBlock block) { 41 | return block.Damage() > 1; 42 | }, 43 | damaged1Percent 44 | ); 45 | 46 | return false; // Remove the event once it is triggered. 47 | } 48 | 49 | public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) 50 | { 51 | EasyBlocks monitoredBlocks = Blocks; // The event will be added to all these blocks 52 | 53 | AddEvents( 54 | monitoredBlocks, 55 | delegate(EasyBlock block) { // When this function returns true, the event is triggered 56 | return block.Damage() > 1; // when the block is damage more than 1% 57 | }, 58 | damaged1Percent // this is called when the event is triggered 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /modules/EasyAPI/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EasyAPI", 3 | "description": "Abstraction library that makes programming in Space Engineers much easier.", 4 | "type": "library", 5 | "version": "1.0", 6 | "require": { 7 | }, 8 | "conflict": { 9 | }, 10 | "suggest": { 11 | "BootstrapEasyAPI" 12 | } 13 | } -------------------------------------------------------------------------------- /modules/EasyAPI/src/EasyAPI.cs: -------------------------------------------------------------------------------- 1 | /**************************************************/ 2 | /*** EasyAPI class. Extend for easier scripting ***/ 3 | /**************************************************/ 4 | public abstract class EasyAPI 5 | { 6 | private long start = 0; // Time at start of program 7 | private long clock = 0; // Current time in ticks 8 | private long delta = 0; // Time since last call to Tick in ticks 9 | 10 | public EasyBlock Self; // Reference to the Programmable Block that is running this script 11 | 12 | public IMyGridTerminalSystem GridTerminalSystem; 13 | public Action Echo; 14 | public TimeSpan ElapsedTime; 15 | 16 | static public IMyGridTerminalSystem grid; 17 | 18 | /*** Events ***/ 19 | private Dictionary> ArgumentActions; 20 | private Dictionary>> CommandActions; 21 | private List Schedule; 22 | private List Intervals; 23 | private EasyCommands commands; 24 | 25 | /*** Overridable lifecycle methods ***/ 26 | public virtual void onRunThrottled(float intervalTranspiredPercentage) {} 27 | public virtual void onTickStart() {} 28 | public virtual void onTickComplete() {} 29 | public virtual bool onSingleTap() { return false; } 30 | public virtual bool onDoubleTap() { return false; } 31 | private int InterTickRunCount = 0; 32 | 33 | /*** Cache ***/ 34 | public EasyBlocks Blocks; 35 | 36 | /*** Constants ***/ 37 | public const long Microseconds = 10; // Ticks (100ns) 38 | public const long Milliseconds = 1000 * Microseconds; 39 | public const long Seconds = 1000 * Milliseconds; 40 | public const long Minutes = 60 * Seconds; 41 | public const long Hours = 60 * Minutes; 42 | public const long Days = 24 * Hours; 43 | public const long Years = 365 * Days; 44 | 45 | /*** Constructor ***/ 46 | public EasyAPI(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime, string commandArgument = "EasyCommand") 47 | { 48 | this.clock = this.start = DateTime.Now.Ticks; 49 | this.delta = 0; 50 | 51 | this.GridTerminalSystem = EasyAPI.grid = grid; 52 | this.Echo = echo; 53 | this.ElapsedTime = elapsedTime; 54 | this.ArgumentActions = new Dictionary>(); 55 | this.CommandActions = new Dictionary>>(); 56 | this.Schedule = new List(); 57 | this.Intervals = new List(); 58 | this.commands = new EasyCommands(this); 59 | 60 | // Get the Programmable Block that is running this script (thanks to LordDevious and LukeStrike) 61 | this.Self = new EasyBlock(me); 62 | 63 | this.Reset(); 64 | } 65 | 66 | public void AddEvent(EasyEvent e) 67 | { 68 | EasyEvent.add(e); 69 | } 70 | 71 | public void AddEvent(EasyBlock block, Func evnt, Func action, bool onChange = false) 72 | { 73 | this.AddEvent(new EasyEvent(block, evnt, action, onChange)); 74 | } 75 | 76 | public void AddEvents(EasyBlocks blocks, Func evnt, Func action, bool onChange = false) 77 | { 78 | for(int i = 0; i < blocks.Count(); i++) 79 | { 80 | this.AddEvent(new EasyEvent(blocks.GetBlock(i), evnt, action, onChange)); 81 | } 82 | } 83 | 84 | // Get messages sent to this block 85 | public List GetMessages() 86 | { 87 | var mymessages = new List(); 88 | 89 | var parts = this.Self.Name().Split('\0'); 90 | 91 | if(parts.Length > 1) 92 | { 93 | for(int n = 1; n < parts.Length; n++) 94 | { 95 | EasyMessage m = new EasyMessage(parts[n]); 96 | mymessages.Add(m); 97 | } 98 | 99 | // Delete the messages once they are received 100 | this.Self.SetName(parts[0]); 101 | } 102 | return mymessages; 103 | } 104 | 105 | // Clear messages sent to this block 106 | public void ClearMessages() 107 | { 108 | var parts = this.Self.Name().Split('\0'); 109 | 110 | if(parts.Length > 1) 111 | { 112 | // Delete the messages 113 | this.Self.SetName(parts[0]); 114 | } 115 | } 116 | 117 | public EasyMessage ComposeMessage(String Subject, String Message) 118 | { 119 | return new EasyMessage(this.Self, Subject, Message); 120 | } 121 | 122 | /*** Execute one tick of the program (interval is the minimum time between ticks) ***/ 123 | public void Tick(long interval = 0, string argument = "") 124 | { 125 | /*** Handle Arguments ***/ 126 | 127 | if(argument != "") 128 | { 129 | if(this.ArgumentActions.ContainsKey(argument)) 130 | { 131 | for(int n = 0; n < this.ArgumentActions[argument].Count; n++) 132 | { 133 | this.ArgumentActions[argument][n](); 134 | } 135 | } 136 | else if(this.CommandActions.Count > 0) 137 | { 138 | int argc = 0; 139 | var matches = System.Text.RegularExpressions.Regex.Matches(argument, @"(?[^\s""]+)|""(?[^""]*)"""); 140 | 141 | string[] argv = new string[matches.Count]; 142 | for(int n = 0; n < matches.Count; n++) 143 | { 144 | argv[n] = matches[n].Groups["match"].Value; 145 | } 146 | 147 | argc = argv.Length; 148 | 149 | if(argc > 0 && this.CommandActions.ContainsKey(argv[0])) 150 | { 151 | for(int n = 0; n < this.CommandActions[argv[0]].Count; n++) 152 | { 153 | this.CommandActions[argv[0]][n](argc, argv); 154 | } 155 | } 156 | } 157 | else if(argument.Length > 12 && argument.Substring(0, 12) == "EasyCommand ") 158 | { 159 | this.commands.handle(argument.Substring(12)); 160 | } 161 | } 162 | 163 | long now = DateTime.Now.Ticks; 164 | if(this.clock > this.start && now - this.clock < interval) { 165 | InterTickRunCount++; 166 | float transpiredPercentage = ((float)((double)(now - this.clock) / interval)); 167 | onRunThrottled(transpiredPercentage); 168 | return; // Don't run until the minimum time between ticks 169 | } 170 | if(InterTickRunCount == 1) { 171 | if(onSingleTap()) { 172 | return; // Override has postponed this Tick to next Run 173 | } 174 | } else if(InterTickRunCount > 1) { 175 | if(onDoubleTap()) { 176 | return; // Override has postponed this Tick to next Run 177 | } 178 | } 179 | InterTickRunCount = 0; 180 | onTickStart(); 181 | 182 | long lastClock = this.clock; 183 | this.clock = now; 184 | this.delta = this.clock - lastClock; 185 | 186 | /*** Handle Events ***/ 187 | EasyEvent.handle(); 188 | 189 | /*** Handle Intervals ***/ 190 | for(int n = 0; n < this.Intervals.Count; n++) 191 | { 192 | if(this.clock >= this.Intervals[n].time) 193 | { 194 | long time = this.clock + this.Intervals[n].interval - (this.clock - this.Intervals[n].time); 195 | 196 | (this.Intervals[n].action)(); 197 | this.Intervals[n] = new EasyInterval(time, this.Intervals[n].interval, this.Intervals[n].action); // reset time interval 198 | } 199 | } 200 | 201 | /*** Handle Schedule ***/ 202 | for(int n = 0; n < this.Schedule.Count; n++) 203 | { 204 | if(this.clock >= this.Schedule[n].time) 205 | { 206 | (this.Schedule[n].action)(); 207 | Schedule.Remove(this.Schedule[n]); 208 | } 209 | } 210 | 211 | onTickComplete(); 212 | } 213 | 214 | public long GetDelta() {return this.delta;} 215 | 216 | public long GetClock() {return clock;} 217 | 218 | public void On(string argument, Action callback) 219 | { 220 | if(!this.ArgumentActions.ContainsKey(argument)) 221 | { 222 | this.ArgumentActions.Add(argument, new List()); 223 | } 224 | 225 | this.ArgumentActions[argument].Add(callback); 226 | } 227 | 228 | public void OnCommand(string argument, Action callback) 229 | { 230 | if(!this.CommandActions.ContainsKey(argument)) 231 | { 232 | this.CommandActions.Add(argument, new List>()); 233 | } 234 | 235 | this.CommandActions[argument].Add(callback); 236 | } 237 | 238 | /*** Call a function at the specified time ***/ 239 | public void At(long time, Action callback) 240 | { 241 | long t = this.start + time; 242 | Schedule.Add(new EasyInterval(t, 0, callback)); 243 | } 244 | 245 | /*** Call a function every interval of time ***/ 246 | public void Every(long time, Action callback) 247 | { 248 | Intervals.Add(new EasyInterval(this.clock + time, time, callback)); 249 | } 250 | 251 | /*** Call a function in "time" seconds ***/ 252 | public void In(long time, Action callback) 253 | { 254 | this.At(this.clock - this.start + time, callback); 255 | } 256 | 257 | /*** Resets the clock and refreshes the blocks. ***/ 258 | public void Reset() 259 | { 260 | this.start = this.clock; 261 | this.ClearMessages(); // clear messages 262 | this.Refresh(); 263 | } 264 | 265 | /*** Refreshes blocks. If you add or remove blocks, call this. ***/ 266 | public void Refresh() 267 | { 268 | List kBlocks = new List(); 269 | GridTerminalSystem.GetBlocks(kBlocks); 270 | Blocks = new EasyBlocks(kBlocks); 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /modules/EasyAPI/src/EasyBlock.cs: -------------------------------------------------------------------------------- 1 | public struct EasyBlock 2 | { 3 | public IMyTerminalBlock Block; 4 | private IMySlimBlock slim; 5 | 6 | public EasyBlock(IMyTerminalBlock Block) 7 | { 8 | this.Block = Block; 9 | this.slim = null; 10 | } 11 | 12 | public IMySlimBlock Slim() 13 | { 14 | if(this.slim == null) 15 | { 16 | this.slim = this.Block.CubeGrid.GetCubeBlock(this.Block.Position); 17 | } 18 | 19 | return this.slim; 20 | } 21 | 22 | public String Type() 23 | { 24 | return this.Block.DefinitionDisplayNameText; 25 | } 26 | 27 | public Single Damage() 28 | { 29 | return this.CurrentDamage() / this.MaxIntegrity() * (Single)100.0; 30 | } 31 | 32 | public Single CurrentDamage() 33 | { 34 | return this.Slim().CurrentDamage; 35 | } 36 | 37 | public Single MaxIntegrity() 38 | { 39 | return this.Slim().MaxIntegrity; 40 | } 41 | 42 | public bool Open() 43 | { 44 | IMyDoor door = Block as IMyDoor; 45 | 46 | if(door != null) 47 | { 48 | return door.Status == DoorStatus.Open; 49 | } 50 | 51 | return false; 52 | } 53 | 54 | public String Name() 55 | { 56 | return this.Block.CustomName; 57 | } 58 | 59 | public void SendMessage(EasyMessage message) 60 | { 61 | // only programmable blocks can receive messages 62 | if(Type() == "Programmable block") 63 | { 64 | SetName(Name() + "\0" + message.Serialize()); 65 | } 66 | } 67 | 68 | public List NameParameters(char start = '[', char end = ']') 69 | { 70 | List matches; 71 | 72 | this.NameRegex(@"\" + start + @"(.*?)\" + end, out matches); 73 | 74 | return matches; 75 | } 76 | 77 | public bool RoomPressure(String op, Single percent) 78 | { 79 | String roomPressure = DetailedInfo()["Room pressure"]; 80 | 81 | Single pressure = 0; 82 | 83 | if(roomPressure != "Not pressurized") 84 | { 85 | pressure = Convert.ToSingle(roomPressure.TrimEnd('%')); 86 | } 87 | 88 | switch(op) 89 | { 90 | case "<": 91 | return pressure < percent; 92 | case "<=": 93 | return pressure <= percent; 94 | case ">=": 95 | return pressure >= percent; 96 | case ">": 97 | return pressure > percent; 98 | case "==": 99 | return pressure == percent; 100 | case "!=": 101 | return pressure != percent; 102 | } 103 | 104 | return false; 105 | } 106 | 107 | public Dictionary DetailedInfo() 108 | { 109 | Dictionary properties = new Dictionary(); 110 | 111 | var statements = this.Block.DetailedInfo.Split('\n'); 112 | 113 | for(int n = 0; n < statements.Length; n++) 114 | { 115 | var pair = statements[n].Split(':'); 116 | 117 | properties.Add(pair[0], pair[1].Substring(1)); 118 | } 119 | 120 | return properties; 121 | } 122 | 123 | 124 | public bool NameRegex(String Pattern, out List Matches) 125 | { 126 | System.Text.RegularExpressions.Match m = (new System.Text.RegularExpressions.Regex(Pattern)).Match(this.Block.CustomName); 127 | 128 | Matches = new List(); 129 | 130 | bool success = false; 131 | while(m.Success) 132 | { 133 | if(m.Groups.Count > 1) 134 | { 135 | Matches.Add(m.Groups[1].Value); 136 | } 137 | success = true; 138 | 139 | m = m.NextMatch(); 140 | } 141 | 142 | return success; 143 | } 144 | 145 | public bool NameRegex(String Pattern) 146 | { 147 | List matches; 148 | 149 | return this.NameRegex(Pattern, out matches); 150 | } 151 | 152 | public ITerminalAction GetAction(String Name) 153 | { 154 | return this.Block.GetActionWithName(Name); 155 | } 156 | 157 | public EasyBlock ApplyAction(String Name) 158 | { 159 | ITerminalAction Action = this.GetAction(Name); 160 | 161 | if(Action != null) 162 | { 163 | Action.Apply(this.Block); 164 | } 165 | 166 | return this; 167 | } 168 | 169 | public T GetProperty(String PropertyId) 170 | { 171 | return Sandbox.ModAPI.Interfaces.TerminalPropertyExtensions.GetValue(this.Block, PropertyId); 172 | } 173 | 174 | public EasyBlock SetProperty(String PropertyId, T value) 175 | { 176 | try 177 | { 178 | var prop = this.GetProperty(PropertyId); 179 | Sandbox.ModAPI.Interfaces.TerminalPropertyExtensions.SetValue(this.Block, PropertyId, value); 180 | } 181 | catch(Exception e) 182 | { 183 | 184 | } 185 | 186 | return this; 187 | } 188 | 189 | public EasyBlock SetFloatValue(String PropertyId, float value) 190 | { 191 | try 192 | { 193 | Sandbox.ModAPI.Interfaces.TerminalPropertyExtensions.SetValueFloat(this.Block, PropertyId, value); 194 | } 195 | catch(Exception e) 196 | { 197 | 198 | } 199 | 200 | return this; 201 | } 202 | 203 | public EasyBlock On() 204 | { 205 | this.ApplyAction("OnOff_On"); 206 | 207 | return this; 208 | } 209 | 210 | public EasyBlock Off() 211 | { 212 | this.ApplyAction("OnOff_Off"); 213 | 214 | return this; 215 | } 216 | 217 | public EasyBlock Toggle() 218 | { 219 | if(this.Block.IsWorking) 220 | { 221 | this.Off(); 222 | } 223 | else 224 | { 225 | this.On(); 226 | } 227 | 228 | return this; 229 | } 230 | 231 | public EasyBlock Run(EasyAPI api, string type = "public") 232 | { 233 | var cmd = new EasyCommands(api); 234 | switch(type) 235 | { 236 | case "private": 237 | cmd.handle(this.GetCustomData()); 238 | break; 239 | default: 240 | cmd.handle(this.GetPublicText()); 241 | break; 242 | } 243 | 244 | return this; 245 | } 246 | 247 | public EasyBlock RunPB(string argument = "") 248 | { 249 | IMyProgrammableBlock pb = Block as IMyProgrammableBlock; 250 | 251 | if(pb != null) 252 | { 253 | pb.TryRun(argument); 254 | } 255 | 256 | return this; 257 | } 258 | 259 | public string GetPublicText() 260 | { 261 | string ret = ""; 262 | 263 | IMyTextPanel textPanel = Block as IMyTextPanel; 264 | 265 | if(textPanel != null) 266 | { 267 | ret = textPanel.GetPublicText(); 268 | } 269 | 270 | return ret; 271 | } 272 | 273 | public string GetCustomData() 274 | { 275 | string ret = ""; 276 | 277 | IMyTextPanel textPanel = Block as IMyTextPanel; 278 | 279 | if(textPanel != null) 280 | { 281 | ret = textPanel.CustomData; 282 | } 283 | 284 | return ret; 285 | } 286 | 287 | public EasyBlock WritePublicTitle(string text) 288 | { 289 | IMyTextPanel textPanel = Block as IMyTextPanel; 290 | 291 | if(textPanel != null) 292 | { 293 | textPanel.WritePublicTitle(text); 294 | } 295 | 296 | return this; 297 | } 298 | 299 | public EasyBlock WritePublicText(string text) 300 | { 301 | IMyTextPanel textPanel = Block as IMyTextPanel; 302 | 303 | if(textPanel != null) 304 | { 305 | textPanel.WritePublicText(text, false); 306 | } 307 | 308 | return this; 309 | } 310 | 311 | public EasyBlock WriteCustomData(string text) 312 | { 313 | IMyTextPanel textPanel = Block as IMyTextPanel; 314 | 315 | if(textPanel != null) 316 | { 317 | textPanel.CustomData = text; 318 | } 319 | 320 | return this; 321 | } 322 | 323 | public EasyBlock AppendPublicText(string text) 324 | { 325 | IMyTextPanel textPanel = Block as IMyTextPanel; 326 | 327 | if(textPanel != null) 328 | { 329 | textPanel.WritePublicText(text, true); 330 | } 331 | 332 | return this; 333 | } 334 | 335 | public EasyBlock SetName(String Name) 336 | { 337 | this.Block.CustomName = Name; 338 | 339 | return this; 340 | } 341 | 342 | public List GetActions() 343 | { 344 | List actions = new List(); 345 | this.Block.GetActions(actions); 346 | return actions; 347 | } 348 | 349 | public List GetProperties() 350 | { 351 | List properties = new List(); 352 | this.Block.GetProperties(properties); 353 | return properties; 354 | } 355 | 356 | /*** Events ***/ 357 | 358 | public EasyBlock AddEvent(Func evnt, Func action, bool onChange = false) 359 | { 360 | EasyEvent.add(new EasyEvent(this, evnt, action, onChange)); 361 | 362 | return this; 363 | } 364 | 365 | public EasyInventory Items(Nullable fix_duplicate_name_bug = null) 366 | { 367 | List Blocks = new List(); 368 | Blocks.Add(this); 369 | 370 | return new EasyInventory(Blocks); 371 | } 372 | 373 | public static bool operator ==(EasyBlock a, EasyBlock b) 374 | { 375 | return a.Block == b.Block; 376 | } 377 | 378 | public override bool Equals(object o) 379 | { 380 | return (EasyBlock)o == this; 381 | } 382 | 383 | public override int GetHashCode() 384 | { 385 | return Block.GetHashCode(); 386 | } 387 | 388 | public static bool operator !=(EasyBlock a, EasyBlock b) 389 | { 390 | return a.Block != b.Block; 391 | } 392 | 393 | 394 | } 395 | -------------------------------------------------------------------------------- /modules/EasyAPI/src/EasyBlocks.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | public class EasyBlocks 4 | { 5 | public List Blocks; 6 | 7 | // Constructor with IMyTerminalBlock list 8 | public EasyBlocks(List TBlocks) 9 | { 10 | this.Blocks = new List(); 11 | 12 | for(int i = 0; i < TBlocks.Count; i++) 13 | { 14 | EasyBlock Block = new EasyBlock(TBlocks[i]); 15 | this.Blocks.Add(Block); 16 | } 17 | } 18 | 19 | // Constructor with EasyBlock list 20 | public EasyBlocks(List Blocks) 21 | { 22 | this.Blocks = Blocks; 23 | } 24 | 25 | public EasyBlocks() 26 | { 27 | this.Blocks = new List(); 28 | } 29 | 30 | // Get number of blocks in list 31 | public int Count() 32 | { 33 | return this.Blocks.Count; 34 | } 35 | 36 | // Get a specific block from the list 37 | public EasyBlock GetBlock(int i) 38 | { 39 | return this.Blocks[i]; 40 | } 41 | 42 | /*********************/ 43 | /*** Block Filters ***/ 44 | /*********************/ 45 | 46 | /*** Interface Filters ***/ 47 | 48 | public EasyBlocks WithInterface() where T: class 49 | { 50 | List FilteredList = new List(); 51 | 52 | for(int i = 0; i < this.Blocks.Count; i++) 53 | { 54 | T block = this.Blocks[i].Block as T; 55 | 56 | if(block != null) 57 | { 58 | FilteredList.Add(this.Blocks[i]); 59 | } 60 | } 61 | 62 | return new EasyBlocks(FilteredList); 63 | } 64 | 65 | /*** Type Filters ***/ 66 | 67 | public EasyBlocks OfType(String Type) 68 | { 69 | return TypeFilter("==", Type); 70 | } 71 | 72 | public EasyBlocks NotOfType(String Type) 73 | { 74 | return TypeFilter("!=", Type); 75 | } 76 | 77 | public EasyBlocks OfTypeLike(String Type) 78 | { 79 | return TypeFilter("~", Type); 80 | } 81 | 82 | public EasyBlocks NotOfTypeLike(String Type) 83 | { 84 | return TypeFilter("!~", Type); 85 | } 86 | 87 | public EasyBlocks OfTypeRegex(String Pattern) 88 | { 89 | return TypeFilter("R", Pattern); 90 | } 91 | 92 | public EasyBlocks NotOfTypeRegex(String Pattern) 93 | { 94 | return TypeFilter("!R", Pattern); 95 | } 96 | 97 | protected EasyBlocks TypeFilter(String op, String Type) 98 | { 99 | List FilteredList = new List(); 100 | 101 | for(int i = 0; i < this.Blocks.Count; i++) 102 | { 103 | if(EasyCompare(op, this.Blocks[i].Type(), Type)) 104 | { 105 | FilteredList.Add(this.Blocks[i]); 106 | } 107 | } 108 | 109 | return new EasyBlocks(FilteredList); 110 | } 111 | 112 | /*** Name Filters ***/ 113 | 114 | public EasyBlocks Named(String Name) 115 | { 116 | return NameFilter("==", Name); 117 | } 118 | 119 | public EasyBlocks NotNamed(String Name) 120 | { 121 | return NameFilter("!=", Name); 122 | } 123 | 124 | public EasyBlocks NamedLike(String Name) 125 | { 126 | return NameFilter("~", Name); 127 | } 128 | 129 | public EasyBlocks NotNamedLike(String Name) 130 | { 131 | return NameFilter("!~", Name); 132 | } 133 | 134 | public EasyBlocks NamedRegex(String Pattern) 135 | { 136 | return NameFilter("R", Pattern); 137 | } 138 | 139 | public EasyBlocks NotNamedRegex(String Pattern) 140 | { 141 | return NameFilter("!R", Pattern); 142 | } 143 | 144 | protected EasyBlocks NameFilter(String op, String Name) 145 | { 146 | List FilteredList = new List(); 147 | 148 | for(int i = 0; i < this.Blocks.Count; i++) 149 | { 150 | if(EasyCompare(op, this.Blocks[i].Name(), Name)) 151 | { 152 | FilteredList.Add(this.Blocks[i]); 153 | } 154 | } 155 | 156 | return new EasyBlocks(FilteredList); 157 | } 158 | 159 | /*** Group Filters ***/ 160 | 161 | public EasyBlocks InGroupsNamed(String Group) 162 | { 163 | return GroupFilter("==", Group); 164 | } 165 | 166 | public EasyBlocks InGroupsNotNamed(String Group) 167 | { 168 | return GroupFilter("!=", Group); 169 | } 170 | 171 | public EasyBlocks InGroupsNamedLike(String Group) 172 | { 173 | return GroupFilter("~", Group); 174 | } 175 | 176 | public EasyBlocks InGroupsNotNamedLike(String Group) 177 | { 178 | return GroupFilter("!~", Group); 179 | } 180 | 181 | public EasyBlocks InGroupsNamedRegex(String Pattern) 182 | { 183 | return GroupFilter("R", Pattern); 184 | } 185 | 186 | public EasyBlocks InGroupsNotNamedRegex(String Pattern) 187 | { 188 | return GroupFilter("!R", Pattern); 189 | } 190 | 191 | public EasyBlocks GroupFilter(String op, String Group) 192 | { 193 | List FilteredList = new List(); 194 | 195 | List groups = new List(); 196 | EasyAPI.grid.GetBlockGroups(groups); 197 | List matchedGroups = new List(); 198 | List groupBlocks = new List(); 199 | 200 | for(int n = 0; n < groups.Count; n++) 201 | { 202 | if(EasyCompare(op, groups[n].Name, Group)) 203 | { 204 | matchedGroups.Add(groups[n]); 205 | } 206 | } 207 | 208 | for(int n = 0; n < matchedGroups.Count; n++) 209 | { 210 | for(int i = 0; i < this.Blocks.Count; i++) 211 | { 212 | IMyTerminalBlock block = this.Blocks[i].Block; 213 | matchedGroups[n].GetBlocks(groupBlocks); 214 | for(int j = 0; j < groupBlocks.Count; j++) 215 | { 216 | if(block == groupBlocks[j]) 217 | { 218 | FilteredList.Add(this.Blocks[i]); 219 | } 220 | } 221 | groupBlocks.Clear(); 222 | } 223 | } 224 | 225 | return new EasyBlocks(FilteredList); 226 | } 227 | 228 | /*** Sensor Filters ***/ 229 | 230 | public EasyBlocks SensorsActive(bool isActive = true) 231 | { 232 | List FilteredList = new List(); 233 | 234 | for(int i = 0; i < this.Blocks.Count; i++) 235 | { 236 | if(this.Blocks[i].Type() == "Sensor" && ((IMySensorBlock)this.Blocks[i].Block).IsActive == isActive) 237 | { 238 | FilteredList.Add(this.Blocks[i]); 239 | } 240 | } 241 | 242 | return new EasyBlocks(FilteredList); 243 | } 244 | 245 | public EasyBlocks RoomPressure(String op, Single percent) 246 | { 247 | List FilteredList = new List(); 248 | 249 | for(int i = 0; i < this.Blocks.Count; i++) 250 | { 251 | if(this.Blocks[i].RoomPressure(op, percent)) 252 | { 253 | FilteredList.Add(this.Blocks[i]); 254 | } 255 | } 256 | 257 | return new EasyBlocks(FilteredList); 258 | } 259 | 260 | 261 | /*** Advanced Filters ***/ 262 | 263 | public EasyBlocks FilterBy(Func action) 264 | { 265 | List FilteredList = new List(); 266 | 267 | for(int i = 0; i < this.Blocks.Count; i++) 268 | { 269 | if(action(this.Blocks[i])) 270 | { 271 | FilteredList.Add(this.Blocks[i]); 272 | } 273 | } 274 | 275 | return new EasyBlocks(FilteredList); 276 | } 277 | 278 | 279 | /*** Other ***/ 280 | 281 | public EasyBlocks First() 282 | { 283 | List FilteredList = new List(); 284 | 285 | if(this.Blocks.Count > 0) 286 | { 287 | FilteredList.Add(Blocks[0]); 288 | } 289 | 290 | return new EasyBlocks(FilteredList); 291 | } 292 | 293 | public EasyBlocks Add(EasyBlock Block) 294 | { 295 | this.Blocks.Add(Block); 296 | 297 | return this; 298 | } 299 | 300 | public EasyBlocks Plus(EasyBlocks Blocks) 301 | { 302 | List FilteredList = new List(); 303 | 304 | FilteredList.AddRange(this.Blocks); 305 | for(int i = 0; i < Blocks.Count(); i++) 306 | { 307 | if(!FilteredList.Contains(Blocks.GetBlock(i))) 308 | { 309 | FilteredList.Add(Blocks.GetBlock(i)); 310 | } 311 | } 312 | 313 | return new EasyBlocks(FilteredList); 314 | } 315 | 316 | public EasyBlocks Minus(EasyBlocks Blocks) 317 | { 318 | List FilteredList = new List(); 319 | 320 | FilteredList.AddRange(this.Blocks); 321 | for(int i = 0; i < Blocks.Count(); i++) 322 | { 323 | FilteredList.Remove(Blocks.GetBlock(i)); 324 | } 325 | 326 | return new EasyBlocks(FilteredList); 327 | } 328 | 329 | public static EasyBlocks operator +(EasyBlocks a, EasyBlocks b) 330 | { 331 | return a.Plus(b); 332 | } 333 | 334 | public static EasyBlocks operator -(EasyBlocks a, EasyBlocks b) 335 | { 336 | return a.Minus(b); 337 | } 338 | 339 | public EasyBlocks Plus(EasyBlock Block) 340 | { 341 | List FilteredList = new List(); 342 | 343 | FilteredList.AddRange(this.Blocks); 344 | 345 | if(!FilteredList.Contains(Block)) 346 | { 347 | FilteredList.Add(Block); 348 | } 349 | 350 | return new EasyBlocks(FilteredList); 351 | } 352 | 353 | public EasyBlocks Minus(EasyBlock Block) 354 | { 355 | List FilteredList = new List(); 356 | 357 | FilteredList.AddRange(this.Blocks); 358 | FilteredList.Remove(Block); 359 | 360 | return new EasyBlocks(FilteredList); 361 | } 362 | 363 | public static EasyBlocks operator +(EasyBlocks a, EasyBlock b) 364 | { 365 | return a.Plus(b); 366 | } 367 | 368 | public static EasyBlocks operator -(EasyBlocks a, EasyBlock b) 369 | { 370 | return a.Minus(b); 371 | } 372 | 373 | /*** Operations ***/ 374 | 375 | public EasyBlocks FindOrFail(string message) 376 | { 377 | if(this.Count() == 0) throw new Exception(message); 378 | 379 | return this; 380 | } 381 | 382 | public EasyBlocks Run(EasyAPI api, string type = "public") 383 | { 384 | for(int i = 0; i < this.Blocks.Count; i++) 385 | { 386 | this.Blocks[i].Run(api, type); 387 | } 388 | 389 | return this; 390 | } 391 | 392 | public EasyBlocks SendMessage(EasyMessage message) 393 | { 394 | for(int i = 0; i < this.Blocks.Count; i++) 395 | { 396 | this.Blocks[i].SendMessage(message); 397 | } 398 | 399 | return this; 400 | } 401 | 402 | 403 | public EasyBlocks ApplyAction(String Name) 404 | { 405 | for(int i = 0; i < this.Blocks.Count; i++) 406 | { 407 | this.Blocks[i].ApplyAction(Name); 408 | } 409 | 410 | return this; 411 | } 412 | 413 | public EasyBlocks SetProperty(String PropertyId, T value, int bleh = 0) 414 | { 415 | for(int i = 0; i < this.Blocks.Count; i++) 416 | { 417 | this.Blocks[i].SetProperty(PropertyId, value); 418 | } 419 | 420 | return this; 421 | } 422 | 423 | public EasyBlocks SetFloatValue(String PropertyId, float value, int bleh = 0) 424 | { 425 | for(int i = 0; i < this.Blocks.Count; i++) 426 | { 427 | this.Blocks[i].SetFloatValue(PropertyId, value); 428 | } 429 | 430 | return this; 431 | } 432 | 433 | public T GetProperty(String PropertyId, int bleh = 0) 434 | { 435 | return this.Blocks[0].GetProperty(PropertyId); 436 | } 437 | 438 | public EasyBlocks On() 439 | { 440 | for(int i = 0; i < this.Blocks.Count; i++) 441 | { 442 | this.Blocks[i].On(); 443 | } 444 | 445 | return this; 446 | } 447 | 448 | public EasyBlocks Off() 449 | { 450 | for(int i = 0; i < this.Blocks.Count; i++) 451 | { 452 | this.Blocks[i].Off(); 453 | } 454 | 455 | return this; 456 | } 457 | 458 | public EasyBlocks Toggle() 459 | { 460 | for(int i = 0; i < this.Blocks.Count; i++) 461 | { 462 | this.Blocks[i].Toggle(); 463 | } 464 | 465 | return this; 466 | } 467 | 468 | public EasyBlocks RunPB(string argument = "") 469 | { 470 | for(int i = 0; i < this.Blocks.Count; i++) 471 | { 472 | this.Blocks[i].RunPB(argument); 473 | } 474 | 475 | return this; 476 | } 477 | 478 | public EasyBlocks WritePublicText(string text) 479 | { 480 | for(int i = 0; i < this.Blocks.Count; i++) 481 | { 482 | this.Blocks[i].WritePublicText(text); 483 | } 484 | 485 | return this; 486 | } 487 | 488 | public EasyBlocks WriteCustomData(string text) 489 | { 490 | for(int i = 0; i < this.Blocks.Count; i++) 491 | { 492 | this.Blocks[i].WriteCustomData(text); 493 | } 494 | 495 | return this; 496 | } 497 | 498 | public EasyBlocks WritePublicTitle(string text) 499 | { 500 | for(int i = 0; i < this.Blocks.Count; i++) 501 | { 502 | this.Blocks[i].WritePublicTitle(text); 503 | } 504 | 505 | return this; 506 | } 507 | 508 | public EasyBlocks WritePrivateTitle(string text) 509 | { 510 | for(int i = 0; i < this.Blocks.Count; i++) 511 | { 512 | this.Blocks[i].WritePublicTitle(text); 513 | } 514 | 515 | return this; 516 | } 517 | 518 | public EasyBlocks AppendPublicText(string text) 519 | { 520 | for(int i = 0; i < this.Blocks.Count; i++) 521 | { 522 | this.Blocks[i].AppendPublicText(text); 523 | } 524 | 525 | return this; 526 | } 527 | 528 | public EasyInventory Items() 529 | { 530 | return new EasyInventory(this.Blocks); 531 | } 532 | 533 | public string DebugDump(bool throwIt = true) 534 | { 535 | String output = "\n"; 536 | 537 | for(int i = 0; i < this.Blocks.Count; i++) 538 | { 539 | output += this.Blocks[i].Type() + ": " + this.Blocks[i].Name() + "\n"; 540 | } 541 | 542 | if(throwIt) 543 | throw new Exception(output); 544 | else 545 | return output; 546 | } 547 | 548 | public string DebugDumpActions(bool throwIt = true) 549 | { 550 | String output = "\n"; 551 | 552 | for(int i = 0; i < this.Blocks.Count; i++) 553 | { 554 | output += "[ " + this.Blocks[i].Type() + ": " + this.Blocks[i].Name() + " ]\n"; 555 | output += "*** ACTIONS ***\n"; 556 | List actions = this.Blocks[i].GetActions(); 557 | 558 | for(int j = 0; j < actions.Count; j++) 559 | { 560 | output += actions[j].Id + ":" + actions[j].Name + "\n"; 561 | } 562 | 563 | output += "\n\n"; 564 | } 565 | 566 | if(throwIt) 567 | throw new Exception(output); 568 | else 569 | return output; 570 | } 571 | 572 | public string DebugDumpProperties(bool throwIt = true) 573 | { 574 | String output = "\n"; 575 | 576 | for(int i = 0; i < this.Blocks.Count; i++) 577 | { 578 | output += "[ " + this.Blocks[i].Type() + ": " + this.Blocks[i].Name() + " ]\n"; 579 | output += "*** PROPERTIES ***\n"; 580 | List properties = this.Blocks[i].GetProperties(); 581 | 582 | for(int j = 0; j < properties.Count; j++) 583 | { 584 | output += properties[j].TypeName + ": " + properties[j].Id + "\n"; 585 | } 586 | 587 | output += "\n\n"; 588 | } 589 | 590 | if(throwIt) 591 | throw new Exception(output); 592 | else 593 | return output; 594 | } 595 | 596 | /*** Events ***/ 597 | 598 | public EasyBlocks AddEvent(Func evnt, Func action, bool onChange = false) 599 | { 600 | for(int i = 0; i < this.Blocks.Count; i++) 601 | { 602 | this.Blocks[i].AddEvent(evnt, action, onChange); 603 | } 604 | 605 | return this; 606 | } 607 | 608 | private bool EasyCompare(String op, String a, String b) 609 | { 610 | switch(op) 611 | { 612 | case "==": 613 | return (a == b); 614 | case "!=": 615 | return (a != b); 616 | case "~": 617 | return a.Contains(b); 618 | case "!~": 619 | return !a.Contains(b); 620 | case "R": 621 | System.Text.RegularExpressions.Match m = (new System.Text.RegularExpressions.Regex(b)).Match(a); 622 | while(m.Success) 623 | { 624 | return true; 625 | } 626 | return false; 627 | case "!R": 628 | return !EasyCompare("R", a, b); 629 | } 630 | return false; 631 | } 632 | 633 | } 634 | -------------------------------------------------------------------------------- /modules/EasyAPI/src/EasyCommands.cs: -------------------------------------------------------------------------------- 1 | /*** Commands ***/ 2 | 3 | // Base EasyCommands class 4 | public class EasyCommands 5 | { 6 | /*** Private Properties ***/ 7 | 8 | private EasyAPI api; // The selected menu item (child) 9 | private EasyBlocks blocks; 10 | public Dictionary functions = new Dictionary(); 11 | private int pos = 0; 12 | private string text = ""; 13 | 14 | /*** Constructors ***/ 15 | 16 | public EasyCommands(EasyAPI api) 17 | { 18 | this.api = api; 19 | } 20 | 21 | /*** Private Methods ***/ 22 | 23 | public void handle(string text) 24 | { 25 | this.pos = 0; 26 | this.text = text; 27 | 28 | while(pos < text.Length) 29 | { 30 | doCommand(); 31 | pos++; 32 | } 33 | } 34 | 35 | private void failure(string message) 36 | { 37 | throw new Exception("EasyCommand Error: " + message); 38 | } 39 | 40 | private void skipWhitespace() 41 | { 42 | while(pos < text.Length && char.IsWhiteSpace(text, pos)) 43 | { 44 | pos++; 45 | } 46 | } 47 | 48 | private void skipLineComment() 49 | { 50 | pos += 2; 51 | while(pos < text.Length) 52 | { 53 | if(text[pos] == "\n"[0]) 54 | { 55 | pos++; 56 | break; 57 | } 58 | pos++; 59 | } 60 | } 61 | 62 | private void skipBlockComment() 63 | { 64 | pos += 2; 65 | while(pos < text.Length && pos + 1 < text.Length) 66 | { 67 | if(text[pos] == '*' && text[pos+1] == '/') 68 | { 69 | pos += 2; 70 | break; 71 | } 72 | pos++; 73 | } 74 | } 75 | 76 | private void skipNonCode() 77 | { 78 | while(pos < text.Length) 79 | { 80 | if(char.IsWhiteSpace(text, pos)) skipWhitespace(); 81 | else if(pos + 1 < text.Length && text[pos] == '/') 82 | { 83 | if(text[pos+1] == '/') skipLineComment(); 84 | else if(text[pos+1] == '*') skipBlockComment(); 85 | else break; 86 | } 87 | else break; 88 | } 89 | } 90 | 91 | private string getIdentifier() 92 | { 93 | string identifier = ""; 94 | while(pos < text.Length && char.IsLetterOrDigit(text[pos])) 95 | { 96 | identifier += text[pos]; 97 | pos++; 98 | } 99 | return identifier; 100 | } 101 | 102 | private string getParm() 103 | { 104 | string param = ""; 105 | skipNonCode(); 106 | if(pos < text.Length && text[pos] == '(') 107 | { 108 | pos++; 109 | skipNonCode(); 110 | if(pos < text.Length && text[pos] == '"') 111 | { 112 | pos++; 113 | while(pos < text.Length) 114 | { 115 | if(text[pos] == '"') 116 | { 117 | pos++; 118 | break; 119 | } 120 | else if(text[pos] == '\\' && pos + 1 < text.Length) 121 | { 122 | if(text[pos + 1] == '"') 123 | { 124 | param += '"'; 125 | pos++; 126 | } 127 | else if(text[pos + 1] == 'n') 128 | { 129 | param += "\n"; 130 | pos++; 131 | } 132 | else 133 | { 134 | param += text[pos]; 135 | } 136 | } 137 | else 138 | { 139 | param += text[pos]; 140 | } 141 | pos++; 142 | } 143 | } 144 | skipNonCode(); 145 | 146 | if(pos < text.Length && text[pos]== ')') 147 | { 148 | pos++; 149 | } 150 | } 151 | 152 | return param; 153 | } 154 | 155 | private string getFunction() 156 | { 157 | // Todo this is REALLY basic and it should do a lot more parsing instead of just looking for the end curly brace. Functions will break if a curly brace appears anywhere inside them 158 | string code = ""; 159 | while(pos < text.Length) 160 | { 161 | if(text[pos] == '}') 162 | { 163 | pos++; 164 | break; 165 | } 166 | code += text[pos]; 167 | pos++; 168 | } 169 | return code; 170 | } 171 | 172 | private void require(char c) 173 | { 174 | if(pos < text.Length && text[pos] == c) 175 | { 176 | pos++; 177 | return; 178 | } 179 | failure("Required: " + c); 180 | } 181 | 182 | private void doCommand() 183 | { 184 | while(pos < text.Length && text[pos] != ';') 185 | { 186 | skipNonCode(); 187 | string command = getIdentifier(); 188 | 189 | if(command == "") 190 | { 191 | return; 192 | } 193 | 194 | string parm = ""; 195 | 196 | switch(command) 197 | { 198 | case "function": 199 | skipNonCode(); 200 | string identifier = getIdentifier(); 201 | skipNonCode(); 202 | require('('); 203 | skipNonCode(); 204 | require(')'); 205 | skipNonCode(); 206 | require('{'); 207 | skipNonCode(); 208 | string function = getFunction(); 209 | if(functions.ContainsKey(identifier)) 210 | { 211 | failure("Function " + identifier + " already defined!"); 212 | } 213 | functions.Add(identifier, function); 214 | return; 215 | case "Echo": 216 | parm = getParm(); 217 | api.Echo(parm); 218 | break; 219 | case "Blocks": 220 | api.Refresh(); 221 | this.blocks = api.Blocks; 222 | break; 223 | /*** Actions ***/ 224 | case "ApplyAction": 225 | parm = getParm(); 226 | blocks.ApplyAction(parm); 227 | break; 228 | case "WritePublicText": 229 | parm = getParm(); 230 | blocks.WritePublicText(parm); 231 | break; 232 | case "WriteCustomData": 233 | case "WritePrivateText": 234 | parm = getParm(); 235 | blocks.WriteCustomData(parm); 236 | break; 237 | case "AppendPublicText": 238 | parm = getParm(); 239 | blocks.AppendPublicText(parm); 240 | break; 241 | case "On": 242 | parm = getParm(); 243 | blocks.On(); 244 | break; 245 | case "Off": 246 | parm = getParm(); 247 | blocks.Off(); 248 | break; 249 | case "Toggle": 250 | parm = getParm(); 251 | blocks.Toggle(); 252 | break; 253 | case "DebugDump": 254 | parm = getParm(); 255 | blocks.DebugDump(); 256 | break; 257 | case "DebugDumpActions": 258 | parm = getParm(); 259 | blocks.DebugDumpActions(); 260 | break; 261 | case "DebugDumpProperties": 262 | parm = getParm(); 263 | blocks.DebugDumpProperties(); 264 | break; 265 | case "Run": 266 | parm = getParm(); 267 | blocks.Run(api, parm); 268 | break; 269 | case "RunPB": 270 | parm = getParm(); 271 | blocks.RunPB(parm); 272 | break; 273 | 274 | /*** Filters ***/ 275 | case "Named": 276 | parm = getParm(); 277 | blocks = blocks.Named(parm); 278 | break; 279 | case "NamedLike": 280 | parm = getParm(); 281 | blocks = blocks.NamedLike(parm); 282 | break; 283 | case "NotNamed": 284 | parm = getParm(); 285 | blocks = blocks.NotNamed(parm); 286 | break; 287 | case "NotNamedLike": 288 | parm = getParm(); 289 | blocks = blocks.NotNamedLike(parm); 290 | break; 291 | case "InGroupsNamed": 292 | parm = getParm(); 293 | blocks = blocks.InGroupsNamed(parm); 294 | break; 295 | case "InGroupsNamedLike": 296 | parm = getParm(); 297 | blocks = blocks.InGroupsNamedLike(parm); 298 | break; 299 | case "InGroupsNotNamed": 300 | parm = getParm(); 301 | blocks = blocks.InGroupsNotNamed(parm); 302 | break; 303 | case "InGroupsNotNamedLike": 304 | parm = getParm(); 305 | blocks = blocks.InGroupsNotNamedLike(parm); 306 | break; 307 | case "OfType": 308 | parm = getParm(); 309 | blocks = blocks.OfType(parm); 310 | break; 311 | case "OfTypeLike": 312 | parm = getParm(); 313 | blocks = blocks.OfTypeLike(parm); 314 | break; 315 | case "NotOfType": 316 | parm = getParm(); 317 | blocks = blocks.NotOfType(parm); 318 | break; 319 | case "NotOfTypeLike": 320 | parm = getParm(); 321 | blocks = blocks.OfTypeLike(parm); 322 | break; 323 | default: 324 | failure("Invalid command: '" + command + "'"); 325 | break; 326 | } 327 | 328 | skipNonCode(); 329 | 330 | if(pos < text.Length && text[pos] == '.') pos++; 331 | } 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /modules/EasyAPI/src/EasyEvent.cs: -------------------------------------------------------------------------------- 1 | public class EasyEvent 2 | { 3 | private Func op; // The comparison function 4 | 5 | private EasyBlock block; // Object to pass through to the callback when the event is triggered 6 | 7 | private Func callback; // What to call when the event occurs 8 | 9 | private bool last = false; 10 | 11 | private bool onChange = false; 12 | 13 | public EasyEvent(EasyBlock block, Func op, Func callback, bool onChange = false) 14 | { 15 | this.op = op; 16 | this.callback = callback; 17 | this.block = block; 18 | this.onChange = onChange; 19 | } 20 | 21 | public bool process() 22 | { 23 | bool result = (this.op)(this.block); 24 | 25 | if(result && (!onChange || !last)) 26 | { 27 | last = result; 28 | return (this.callback)(this.block); 29 | } 30 | 31 | last = result; 32 | return true; 33 | } 34 | 35 | /*** static ***/ 36 | 37 | private static List events = new List(); 38 | 39 | public static void handle() 40 | { 41 | for(int i = 0; i < events.Count; i++) 42 | { 43 | if(!events[i].process()) 44 | { 45 | events.Remove(events[i]); 46 | } 47 | } 48 | } 49 | 50 | public static void add(EasyEvent e) 51 | { 52 | events.Add(e); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /modules/EasyAPI/src/EasyInterval.cs: -------------------------------------------------------------------------------- 1 | public struct EasyInterval 2 | { 3 | public long interval; 4 | public long time; 5 | public Action action; 6 | 7 | public EasyInterval(long t, long i, Action a) 8 | { 9 | this.time = t; 10 | this.interval = i; 11 | this.action = a; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /modules/EasyAPI/src/EasyInventory.cs: -------------------------------------------------------------------------------- 1 | // Stores all items in matched block inventories for later filtering 2 | public class EasyInventory 3 | { 4 | public List Items; 5 | 6 | public EasyInventory(List Blocks) 7 | { 8 | this.Items = new List(); 9 | 10 | // Get contents of all inventories in list and add them to EasyItems list. 11 | for(int i = 0; i < Blocks.Count; i++) 12 | { 13 | EasyBlock Block = Blocks[i]; 14 | 15 | for(int j = 0; j < Block.Block.InventoryCount; j++) 16 | { 17 | IMyInventory Inventory = Block.Block.GetInventory(j); 18 | 19 | List Items = Inventory.GetItems(); 20 | 21 | for(int k = 0; k < Items.Count; k++) 22 | { 23 | this.Items.Add(new EasyItem(Block, j, Inventory, k, Items[k])); 24 | } 25 | } 26 | } 27 | } 28 | 29 | public EasyInventory(List Items) 30 | { 31 | this.Items = Items; 32 | } 33 | 34 | public EasyInventory OfType(String SubTypeId) 35 | { 36 | List FilteredItems = new List(); 37 | 38 | for(int i = 0; i < this.Items.Count; i++) 39 | { 40 | if(this.Items[i].Type() == SubTypeId) 41 | { 42 | FilteredItems.Add(this.Items[i]); 43 | } 44 | } 45 | 46 | return new EasyInventory(FilteredItems); 47 | } 48 | 49 | public EasyInventory InInventory(int Index) 50 | { 51 | List FilteredItems = new List(); 52 | 53 | for(int i = 0; i < this.Items.Count; i++) 54 | { 55 | if(this.Items[i].InventoryIndex == Index) 56 | { 57 | FilteredItems.Add(this.Items[i]); 58 | } 59 | } 60 | 61 | return new EasyInventory(FilteredItems); 62 | } 63 | 64 | public VRage.MyFixedPoint Count() 65 | { 66 | VRage.MyFixedPoint Total = 0; 67 | 68 | for(int i = 0; i < Items.Count; i++) 69 | { 70 | Total += Items[i].Amount(); 71 | } 72 | 73 | return Total; 74 | } 75 | 76 | public EasyInventory First() 77 | { 78 | List FilteredItems = new List(); 79 | 80 | if(this.Items.Count > 0) 81 | { 82 | FilteredItems.Add(this.Items[0]); 83 | } 84 | 85 | return new EasyInventory(FilteredItems); 86 | } 87 | 88 | public void MoveTo(EasyBlocks Blocks, int Inventory = 0) 89 | { 90 | for(int i = 0; i < Items.Count; i++) 91 | { 92 | Items[i].MoveTo(Blocks, Inventory); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /modules/EasyAPI/src/EasyItem.cs: -------------------------------------------------------------------------------- 1 | // This represents a single stack of items in the inventory 2 | public struct EasyItem 3 | { 4 | private EasyBlock Block; 5 | public int InventoryIndex; 6 | private IMyInventory Inventory; 7 | public int ItemIndex; 8 | private IMyInventoryItem Item; 9 | 10 | public EasyItem(EasyBlock Block, int InventoryIndex, IMyInventory Inventory, int ItemIndex, IMyInventoryItem Item) 11 | { 12 | this.Block = Block; 13 | this.InventoryIndex = InventoryIndex; 14 | this.Inventory = Inventory; 15 | this.ItemIndex = ItemIndex; 16 | this.Item = Item; 17 | } 18 | 19 | public String Type(int dummy = 0) 20 | { 21 | return this.Item.Content.SubtypeId.ToString(); 22 | } 23 | 24 | public VRage.MyFixedPoint Amount() 25 | { 26 | return this.Item.Amount; 27 | } 28 | 29 | public void MoveTo(EasyBlocks Blocks, int Inventory = 0, int dummy = 0) 30 | { 31 | // Right now it moves them to all of them. Todo: determine if the move was successful an exit for if it was. 32 | // In the future you will be able to sort EasyBlocks and use this to prioritize where the items get moved. 33 | for(int i = 0; i < Blocks.Count(); i++) 34 | { 35 | this.Inventory.TransferItemTo(Blocks.GetBlock(i).Block.GetInventory(Inventory), ItemIndex); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /modules/EasyAPI/src/EasyMessage.cs: -------------------------------------------------------------------------------- 1 | public struct EasyMessage 2 | { 3 | public EasyBlock From; 4 | public String Subject; 5 | public String Message; 6 | public long Timestamp; 7 | 8 | // unserialize 9 | public EasyMessage(String serialized) 10 | { 11 | var parts = serialized.Split(':'); 12 | if(parts.Length < 4) 13 | { 14 | throw new Exception("Error unserializing message."); 15 | } 16 | int numberInGrid = Convert.ToInt32(System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[0]))); 17 | var blocks = new List(); 18 | EasyAPI.grid.GetBlocksOfType(blocks, delegate(IMyTerminalBlock block) { 19 | return (block as IMyProgrammableBlock).NumberInGrid == numberInGrid; 20 | }); 21 | if(blocks.Count == 0) 22 | { 23 | throw new Exception("Message sender no longer exits!"); 24 | } 25 | this.From = new EasyBlock((IMyTerminalBlock)blocks[0]); 26 | this.Subject = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[1])); 27 | this.Message = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[2])); 28 | this.Timestamp = Convert.ToInt64(System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(parts[3]))); 29 | } 30 | 31 | public EasyMessage(EasyBlock From, String Subject, String Message) 32 | { 33 | this.From = From; 34 | this.Subject = Subject; 35 | this.Message = Message; 36 | this.Timestamp = DateTime.Now.Ticks; 37 | } 38 | 39 | public String Serialize() 40 | { 41 | String text = ""; 42 | 43 | text += System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("" + From.Block.NumberInGrid)); 44 | text += ":" + System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Subject)); 45 | text += ":" + System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Message)); 46 | text += ":" + System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("" + Timestamp)); 47 | 48 | return text; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /modules/EasyLCD/EasyLCD.cs: -------------------------------------------------------------------------------- 1 | public class EasyLCD 2 | { 3 | public char[] buffer; 4 | IMyTextPanel screen; 5 | EasyBlock block; 6 | 7 | public int width; 8 | public int height; 9 | 10 | public int xDisplays = 0; 11 | public int yDisplays = 0; 12 | 13 | private int wPanel = 36; 14 | private int hPanel = 18; 15 | 16 | Single fontSize; 17 | 18 | public EasyLCD(EasyBlocks block, double scale = 1.0) 19 | { 20 | this.block = block.GetBlock(0); 21 | if(this.block.Type() == "Wide LCD panel") this.wPanel = 72; 22 | 23 | this.screen = (IMyTextPanel)(block.GetBlock(0).Block); 24 | this.fontSize = block.GetProperty("FontSize"); 25 | 26 | this.width = (int)((double)this.wPanel / this.fontSize); 27 | this.height = (int)((double)this.hPanel / this.fontSize); 28 | this.buffer = new char[this.width * this.height]; 29 | this.clear(); 30 | this.update(); 31 | } 32 | 33 | public void SetText(String text, bool append = false) 34 | { 35 | this.screen.WritePublicText(text, append); 36 | } 37 | 38 | public void plot(EasyBlocks blocks, double x, double y, double scale = 1.0, char brush = 'o', bool showBounds = true, char boundingBrush = '?') 39 | { 40 | VRageMath.Vector3D max = new Vector3D(this.screen.CubeGrid.Max); 41 | VRageMath.Vector3D min = new Vector3D(this.screen.CubeGrid.Min); 42 | VRageMath.Vector3D size = new Vector3D(max - min); 43 | 44 | int width = (int)size.GetDim(0); 45 | int height = (int)size.GetDim(1); 46 | int depth = (int)size.GetDim(2); 47 | 48 | int minX = (int)min.GetDim(0); 49 | int minY = (int)min.GetDim(1); 50 | int minZ = (int)min.GetDim(2); 51 | 52 | int maxX = (int)max.GetDim(0); 53 | int maxY = (int)max.GetDim(1); 54 | int maxZ = (int)max.GetDim(2); 55 | 56 | double s = (double)depth + 0.01; 57 | if(width > depth) 58 | { 59 | s = (double)width + 0.01; 60 | } 61 | 62 | if(showBounds) 63 | { 64 | box(x + -(((0 - (width / 2.0)) / s) * scale), 65 | y + -(((0 - (depth / 2.0)) / s) * scale), 66 | x + -(((maxX - minX - (width / 2.0)) / s) * scale), 67 | y + -(((maxZ - minZ - (depth / 2.0)) / s) * scale), boundingBrush); 68 | } 69 | 70 | for(int n = 0; n < blocks.Count(); n++) 71 | { 72 | var block = blocks.GetBlock(n); 73 | 74 | Vector3D pos = new Vector3D(block.Block.Position); 75 | 76 | pset(x + -((((double)(pos.GetDim(0) - minX - (width / 2.0)) / s)) * scale), 77 | y + -((((double)(pos.GetDim(2) - minZ - (depth / 2.0)) / s)) * scale), brush); 78 | } 79 | } 80 | 81 | // draw a pixel to the buffer 82 | public void pset(double x, double y, char brush = 'o') 83 | { 84 | if(x >= 0 && x < 1 && y >= 0 && y < 1) 85 | { 86 | this.buffer[this.linear(x, y)] = brush; 87 | } 88 | } 89 | 90 | private void pset(int x, int y, char brush = '0') 91 | { 92 | if(x >= 0 && x < this.width && y >= 0 && y < this.height) 93 | { 94 | this.buffer[x + (y * this.width)] = brush; 95 | } 96 | } 97 | 98 | public void text(double x, double y, String text) 99 | { 100 | int xx = (int)(x * (this.width - 1)); 101 | int yy = (int)(y * (this.height - 1)); 102 | 103 | for(int xs = 0; xs < text.Length; xs++) 104 | { 105 | pset(xx + xs, yy, text[xs]); 106 | } 107 | } 108 | 109 | // clear the buffer 110 | public void clear(char brush = ' ') 111 | { 112 | for(int n = 0; n < this.buffer.Length; n++) 113 | { 114 | this.buffer[n] = brush; 115 | } 116 | } 117 | 118 | // Transfer buffer contents to the lcd 119 | public void update() 120 | { 121 | String s = ""; 122 | String space = ""; 123 | 124 | //this.screen.WritePublicText(clearBuf); 125 | 126 | for(int y = 0; y < this.height; y++) 127 | { 128 | space = ""; 129 | for(int x = 0; x < this.width; x++) 130 | { 131 | if(buffer[x + (y * this.width)] == ' ') 132 | { 133 | space += " "; 134 | } 135 | else 136 | { 137 | s += space + buffer[x + (y * this.width)]; 138 | space = ""; 139 | } 140 | } 141 | s += "\n"; 142 | } 143 | 144 | this.screen.WritePublicText(s); 145 | } 146 | 147 | private int linear(double x, double y) 148 | { 149 | int xx = (int)(x * (this.width - 1)); 150 | int yy = (int)(y * (this.height - 1)); 151 | return xx + yy * this.width; 152 | } 153 | 154 | public void line(double xx0, double yy0, double xx1, double yy1, char brush = 'o') 155 | { 156 | int x0 = (int)Math.Floor(xx0 * (this.width)); 157 | int y0 = (int)Math.Floor(yy0 * (this.height)); 158 | int x1 = (int)Math.Floor(xx1 * (this.width)); 159 | int y1 = (int)Math.Floor(yy1 * (this.height)); 160 | 161 | bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0); 162 | if (steep) 163 | { 164 | int tmp = x0; 165 | x0 = y0; 166 | y0 = tmp; 167 | tmp = x1; 168 | x1 = y1; 169 | y1 = tmp; 170 | } 171 | 172 | if (x0 > x1) 173 | { 174 | int tmp = x0; 175 | x0 = x1; 176 | x1 = tmp; 177 | tmp = y0; 178 | y0 = y1; 179 | y1 = tmp; 180 | } 181 | 182 | int dX = (x1 - x0), dY = Math.Abs(y1 - y0), err = (dX / 2), ystep = (y0 < y1 ? 1 : -1), y = y0; 183 | 184 | for (int x = x0; x <= x1; ++x) 185 | { 186 | if(steep) 187 | pset(y, x, brush); 188 | else 189 | pset(x, y, brush); 190 | err = err - dY; 191 | if (err < 0) { y += ystep; err += dX; } 192 | } 193 | } 194 | 195 | public void box(double x0, double y0, double x1, double y1, char brush = 'o') 196 | { 197 | line(x0, y0, x1, y0, brush); 198 | line(x1, y0, x1, y1, brush); 199 | line(x1, y1, x0, y1, brush); 200 | line(x0, y1, x0, y0, brush); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /modules/EasyLCD/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EasyLCD", 3 | "description": "Class that makes drawing to LCDs easy.", 4 | "type": "library", 5 | "version": "1.0", 6 | "require": { 7 | "EasyAPI" 8 | }, 9 | "conflict": { 10 | }, 11 | "suggest": { 12 | "EasyMenu": "Make menus to display on the LCD." 13 | } 14 | } -------------------------------------------------------------------------------- /modules/EasyMenu/EasyMenu.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockyjvec/EasyAPI/78d0a14b04eec6c32dc784839103d4a576fd999a/modules/EasyMenu/EasyMenu.cs -------------------------------------------------------------------------------- /modules/EasyMenu/examples/CALMenu.cs: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | CAL Menu - powered by EasyAPI and EasyMenu 3 | *************************************************************************************/ 4 | 5 | static string calBlockName = "CAL"; // Name of CAL programmable block which contains the CAL script (No timer needed) 6 | static string lcdBlockName = "MenuLCD [LCD]"; // Name of the LCD where you want the menu to display (with standard [LCD] tag for CAL) (Display ON) 7 | static string menuTitle = "CAL Menu"; // The menu title which shows up at the top 8 | 9 | /*** Modify menu items here - first column is menu title, second is CAL command ***/ 10 | 11 | static Dictionary menuItems = new Dictionary 12 | { 13 | {"Power Summary", "PowerSummary;PowerTime"}, 14 | {"Cargo", "CargoAll"}, 15 | {"Inventory", "Inventory"}, 16 | {"Damaged Blocks", "Damage"}, 17 | {"Oxygen", "Oxygen"}, 18 | }; 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | public class Example : EasyAPI 37 | { 38 | // Cache all the different blocks 39 | 40 | EasyBlock lcd; 41 | EasyBlock cal; 42 | EasyMenu menu; 43 | 44 | bool inCAL = false; 45 | string calCommand = ""; 46 | 47 | public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) 48 | { 49 | var children = new List(); 50 | 51 | children.Clear(); 52 | 53 | foreach(var title in menuItems.Keys) 54 | { 55 | children.Add(new EasyMenuItem(title, delegate(EasyMenuItem menuItem) { 56 | 57 | menuItem.children.Clear(); 58 | menuItem.children.Add(new EasyMenuItem("hidden")); 59 | 60 | this.inCAL = true; 61 | 62 | this.calCommand = menuItems[menuItem.GetText()]; 63 | 64 | return true; 65 | })); 66 | } 67 | 68 | // Create menu 69 | this.menu = new EasyMenu(menuTitle, children.ToArray()); 70 | 71 | this.lcd = Blocks.Named(lcdBlockName).FindOrFail("Menu LCD not found!").GetBlock(0); 72 | this.cal = Blocks.Named(calBlockName).FindOrFail("CAL Programmable block not found!").GetBlock(0); 73 | 74 | lcd.WritePublicTitle(""); 75 | 76 | // Handle Arguments 77 | On("Up", delegate() { 78 | this.menu.Up(); 79 | doUpdates(); 80 | }); 81 | 82 | On("Down", delegate() { 83 | this.menu.Down(); 84 | doUpdates(); 85 | }); 86 | 87 | On("Choose", delegate() { 88 | this.menu.Choose(); 89 | doUpdates(); 90 | }); 91 | 92 | On("Back", delegate() { 93 | this.menu.Back(); 94 | this.inCAL = false; 95 | doUpdates(); 96 | }); 97 | 98 | Every(100 * EasyAPI.Milliseconds, delegate () { 99 | doUpdates(); 100 | }); 101 | } 102 | 103 | public void doUpdates() 104 | { 105 | if(this.inCAL) 106 | { 107 | lcd.WritePublicTitle(calCommand); 108 | } 109 | else 110 | { 111 | var lines = menu.Draw().Split("\n".ToCharArray()); 112 | string cmd = ""; 113 | foreach(var line in lines) 114 | { 115 | cmd += "Echo " + line + ";"; 116 | } 117 | cmd = cmd.Substring(0, cmd.Length - 1); 118 | lcd.WritePublicTitle(cmd); 119 | } 120 | 121 | cal.RunPB(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /modules/EasyMenu/examples/Example.cs: -------------------------------------------------------------------------------- 1 | public class Example : EasyAPI 2 | { 3 | // Cache all the different blocks 4 | 5 | EasyLCD lcd; 6 | EasyMenu menu; 7 | 8 | EasyBlocks timer; 9 | EasyBlocks screen; 10 | EasyBlocks speaker; 11 | 12 | public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) 13 | { 14 | // Create menu 15 | this.menu = new EasyMenu("Test Menu", new [] { 16 | new EasyMenuItem("Play Sound", playSound), 17 | new EasyMenuItem("Door Status", new[] { 18 | new EasyMenuItem("Door 1", toggleDoor, doorStatus), 19 | new EasyMenuItem("Door 2", toggleDoor, doorStatus), 20 | new EasyMenuItem("Door 3", toggleDoor, doorStatus), 21 | new EasyMenuItem("Door 4", toggleDoor, doorStatus) 22 | }), 23 | new EasyMenuItem("Do Nothing") 24 | }); 25 | 26 | // Get blocks 27 | this.timer = Blocks.Named("MenuTimer").FindOrFail("MenuTimer not found!"); 28 | this.screen = Blocks.Named("MenuLCD").FindOrFail("MenuLCD not found!"); 29 | this.speaker = Blocks.Named("MenuSpeaker").FindOrFail("MenuSpeaker not found!"); 30 | 31 | this.lcd = new EasyLCD(this.screen); 32 | 33 | Every(100 * Milliseconds, doUpdates); 34 | } 35 | 36 | public bool toggleDoor(EasyMenuItem item) 37 | { 38 | EasyBlock door = Blocks.Named(item.Text).FindOrFail(item.Text + " not found!").GetBlock(0); 39 | 40 | if(door.Open()) 41 | door.ApplyAction("Open_Off"); 42 | else 43 | door.ApplyAction("Open_On"); 44 | 45 | return false; // don't go to a sub-menu if one is available 46 | } 47 | 48 | public string doorStatus(EasyMenuItem item) 49 | { 50 | EasyBlock door = Blocks.Named(item.Text).GetBlock(0); 51 | 52 | return item.Text + ": " + ((door.Open())?"Open":"Closed"); 53 | } 54 | 55 | public bool playSound(EasyMenuItem item) 56 | { 57 | speaker.ApplyAction("PlaySound"); 58 | 59 | return false; 60 | } 61 | 62 | public void doUpdates() 63 | { 64 | Single slider = screen.GetProperty("ChangeIntervalSlider"); 65 | 66 | if(slider < 5) 67 | { 68 | menu.Up(); 69 | screen.SetProperty("ChangeIntervalSlider", (Single)5); 70 | } 71 | 72 | if(slider > 5) 73 | { 74 | menu.Down(); 75 | screen.SetProperty("ChangeIntervalSlider", (Single)5); 76 | } 77 | 78 | Single delay = timer.GetProperty("TriggerDelay"); 79 | 80 | if(delay > 5) 81 | { 82 | menu.Choose(); 83 | timer.SetProperty("TriggerDelay", (Single)5); 84 | } 85 | if(delay < 5) 86 | { 87 | menu.Back(); 88 | timer.SetProperty("TriggerDelay", (Single)5); 89 | } 90 | 91 | lcd.clear(); 92 | lcd.update(); 93 | lcd.SetText(menu.Draw()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /modules/EasyMenu/examples/Example2.cs: -------------------------------------------------------------------------------- 1 | public class Example : EasyAPI 2 | { 3 | // Cache all the different blocks 4 | 5 | EasyLCD lcd; 6 | EasyMenu menu; 7 | 8 | EasyBlocks speaker; 9 | 10 | public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) 11 | { 12 | // Create menu 13 | this.menu = new EasyMenu("Test Menu", new [] { 14 | new EasyMenuItem("Play Sound", playSound), 15 | new EasyMenuItem("Door Status", new[] { 16 | new EasyMenuItem("Door 1", toggleDoor, doorStatus), 17 | new EasyMenuItem("Door 2", toggleDoor, doorStatus), 18 | new EasyMenuItem("Door 3", toggleDoor, doorStatus), 19 | new EasyMenuItem("Door 4", toggleDoor, doorStatus) 20 | }), 21 | new EasyMenuItem("Do Nothing") 22 | }); 23 | 24 | // Get blocks 25 | this.speaker = Blocks.Named("MenuSpeaker").FindOrFail("MenuSpeaker not found!"); 26 | 27 | this.lcd = new EasyLCD(Blocks.Named("MenuLCD").FindOrFail("MenuLCD not found!")); 28 | 29 | 30 | // Handle Arguments 31 | On("Up", delegate() { 32 | this.menu.Up(); 33 | doUpdates(); 34 | }); 35 | 36 | On("Down", delegate() { 37 | this.menu.Down(); 38 | doUpdates(); 39 | }); 40 | 41 | On("Choose", delegate() { 42 | this.menu.Choose(); 43 | doUpdates(); 44 | }); 45 | 46 | On("Back", delegate() { 47 | this.menu.Back(); 48 | doUpdates(); 49 | }); 50 | 51 | On("Update", delegate() { 52 | doUpdates(); 53 | }); 54 | } 55 | 56 | public bool toggleDoor(EasyMenuItem item) 57 | { 58 | EasyBlock door = Blocks.Named(item.Text).FindOrFail(item.Text + " not found!").GetBlock(0); 59 | 60 | if(door.Open()) 61 | door.ApplyAction("Open_Off"); 62 | else 63 | door.ApplyAction("Open_On"); 64 | 65 | return false; // don't go to a sub-menu if one is available 66 | } 67 | 68 | public string doorStatus(EasyMenuItem item) 69 | { 70 | EasyBlock door = Blocks.Named(item.Text).GetBlock(0); 71 | 72 | return item.Text + ": " + ((door.Open())?"Open":"Closed"); 73 | } 74 | 75 | public bool playSound(EasyMenuItem item) 76 | { 77 | speaker.ApplyAction("PlaySound"); 78 | 79 | return false; 80 | } 81 | 82 | public void doUpdates() 83 | { 84 | lcd.clear(); 85 | lcd.update(); 86 | lcd.SetText(menu.Draw()); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /modules/EasyMenu/examples/PBMenu.cs: -------------------------------------------------------------------------------- 1 | EasyMenu menu; 2 | 3 | void Main(string arg) 4 | { 5 | if(menu == null) 6 | { 7 | menu = new EasyMenu("Menu Title", new [] { 8 | new EasyMenuItem("Run PB 1", delegate(EasyMenuItem item) { 9 | IMyProgrammableBlock PB = GridTerminalSystem.GetBlockWithName("EAP") as IMyProgrammableBlock; 10 | 11 | PB.TryRun("Argument 1"); 12 | return false; 13 | }), 14 | new EasyMenuItem("Run PB 2", delegate(EasyMenuItem item) { 15 | IMyProgrammableBlock PB = GridTerminalSystem.GetBlockWithName("EAP") as IMyProgrammableBlock; 16 | 17 | PB.TryRun("Argument 2"); 18 | return false; 19 | }) 20 | }); 21 | } 22 | 23 | if(arg == "Up") menu.Up(); 24 | if(arg == "Down") menu.Down(); 25 | if(arg == "Choose") menu.Choose(); 26 | if(arg == "Back") menu.Back(); 27 | 28 | var lcd = GridTerminalSystem.GetBlockWithName("LCD") as IMyTextPanel; 29 | 30 | lcd.WritePublicText(menu.Draw(), false); 31 | } -------------------------------------------------------------------------------- /modules/EasyMenu/examples/ShipExplorer.cs: -------------------------------------------------------------------------------- 1 | public class Example : EasyAPI 2 | { 3 | EasyLCD lcd; 4 | 5 | EasyBlocks screen; 6 | 7 | EasyMenu menu; 8 | 9 | public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) 10 | { 11 | // Create menu 12 | this.menu = new EasyMenu("Explore", new [] { 13 | new EasyMenuItem("Actions", delegate(EasyMenuItem actionsItem) { 14 | 15 | List types = new List(); 16 | 17 | for(int n = 0; n < Blocks.Count(); n++) 18 | { 19 | var block = Blocks.GetBlock(n); 20 | 21 | if(!types.Contains(block.Type())) 22 | { 23 | types.Add(block.Type()); 24 | } 25 | } 26 | 27 | types.Sort(); 28 | actionsItem.children.Clear(); 29 | 30 | for(int n = 0; n < types.Count; n++) 31 | { 32 | actionsItem.children.Add(new EasyMenuItem(types[n], delegate(EasyMenuItem typeItem) { 33 | 34 | typeItem.children.Clear(); 35 | var blocks = Blocks.OfType(typeItem.Text); 36 | for(int o = 0; o < blocks.Count(); o++) 37 | { 38 | var block = blocks.GetBlock(o); 39 | typeItem.children.Add(new EasyMenuItem(block.Name(), delegate(EasyMenuItem blockItem) { 40 | 41 | blockItem.children.Clear(); 42 | 43 | var actions = block.GetActions(); 44 | for(int p = 0; p < actions.Count; p++) 45 | { 46 | var action = actions[p]; 47 | 48 | blockItem.children.Add(new EasyMenuItem(action.Name + "", delegate(EasyMenuItem actionItem) { 49 | block.ApplyAction(action.Id); 50 | 51 | return false; 52 | })); 53 | } 54 | 55 | blockItem.children.Sort(); 56 | return true; 57 | })); 58 | } 59 | 60 | typeItem.children.Sort(); 61 | return true; 62 | })); 63 | } 64 | actionsItem.children.Sort(); 65 | return true; 66 | }) 67 | }); 68 | 69 | // Get blocks 70 | this.screen = Blocks.Named("MenuLCD").FindOrFail("MenuLCD not found!"); 71 | 72 | this.lcd = new EasyLCD(this.screen); 73 | 74 | // Handle Arguments 75 | On("Up", delegate() { 76 | this.menu.Up(); 77 | doUpdates(); 78 | }); 79 | 80 | On("Down", delegate() { 81 | this.menu.Down(); 82 | doUpdates(); 83 | }); 84 | 85 | On("Choose", delegate() { 86 | this.menu.Choose(); 87 | doUpdates(); 88 | }); 89 | 90 | On("Back", delegate() { 91 | this.menu.Back(); 92 | doUpdates(); 93 | }); 94 | 95 | On("Update", delegate() { 96 | doUpdates(); 97 | }); 98 | } 99 | 100 | public void doUpdates() 101 | { 102 | lcd.clear(); 103 | lcd.update(); 104 | lcd.SetText(menu.Draw()); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /modules/EasyMenu/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EasyMenu", 3 | "description": "Generates interactive menus. Returns string which can be displayed on LCDs or used in other scripts.", 4 | "type": "library", 5 | "version": "1.0", 6 | "require": { 7 | }, 8 | "conflict": { 9 | }, 10 | "suggest": { 11 | "EasyAPI": "Makes it easier to create menus.", 12 | "EasyLCD": "You can use EasyLCD to display the menu." 13 | } 14 | } -------------------------------------------------------------------------------- /modules/EasyUtils/EasyUtils.cs: -------------------------------------------------------------------------------- 1 | public class EasyUtils { 2 | public const int LOG_MAX_ECHO_LENGTH_CHARS = 8000; // Mirrored value from MyProgrammableBlock.cs 3 | public const int LOG_MAX_LCD_LENGTH_CHARS = 4200; // Mirrored value from MyTextPanel.cs 4 | public static StringBuilder LogBuffer; 5 | public static void Log(string logMessage, Action echo = null, IMyProgrammableBlock me = null, string label = null, IMyTextPanel mirrorLcd = null, bool truncateForLcd = true) 6 | { 7 | String output = ""; 8 | if(echo == null) { 9 | output = "\n"; 10 | output += logMessage; 11 | throw new Exception(output); 12 | } 13 | if(LogBuffer == null) { 14 | LogBuffer = new StringBuilder(); 15 | } 16 | if(label != null) { 17 | logMessage = label+": "+logMessage; 18 | } 19 | if(mirrorLcd != null) { 20 | string currentlyMirrored = mirrorLcd.GetPublicText(); 21 | if(truncateForLcd && LogBuffer.Length + logMessage.Length > LOG_MAX_LCD_LENGTH_CHARS) { 22 | StringBuilder lcdBuffer = new StringBuilder(LogBuffer.ToString()); 23 | int charAmountToOffset = fullLineCharsExceeding(lcdBuffer, logMessage.Length, LogBuffer.Length - (LOG_MAX_LCD_LENGTH_CHARS - logMessage.Length)); 24 | lcdBuffer.Remove(0, LogBuffer.Length - LOG_MAX_LCD_LENGTH_CHARS + charAmountToOffset - 2); 25 | lcdBuffer.AppendLine(); 26 | lcdBuffer.Append(logMessage); 27 | mirrorLcd.WritePublicText(lcdBuffer.ToString(), false); 28 | } else { 29 | string potentialNewLine = (currentlyMirrored.Length > 0)? "\n" : ""; 30 | mirrorLcd.WritePublicText(potentialNewLine+logMessage, true); 31 | } 32 | } 33 | if(LogBuffer.Length + logMessage.Length * 2 > LOG_MAX_ECHO_LENGTH_CHARS) { 34 | int charAmountToRemove = fullLineCharsExceeding(LogBuffer, logMessage.Length); 35 | LogBuffer.Remove(0, charAmountToRemove); 36 | LogBuffer.Append(output); 37 | } 38 | if(LogBuffer.Length > 0) { 39 | LogBuffer.AppendLine(); 40 | } 41 | LogBuffer.Append(logMessage); 42 | echo(LogBuffer.ToString()); 43 | } 44 | public static int fullLineCharsExceeding(StringBuilder sb, int maxLength, int offset = 0) { 45 | int runningCount = 0; 46 | for(int i=offset; i maxLength) { 50 | break; 51 | } 52 | } 53 | } 54 | return runningCount; 55 | } 56 | public static void ClearLogBuffer() { 57 | LogBuffer.Clear(); 58 | } 59 | 60 | //because "System.array does not contain a definition for .Max()" 61 | public static double Max(double[] values) { 62 | double runningMax = values[0]; 63 | for(int i=1; i