using System; using System.Collections.Generic; using Sandbox.ModAPI.Ingame; using VRage.Game.ModAPI.Ingame; using VRage.Game.ModAPI.Ingame.Utilities; using VRageMath; namespace AutoMiningScript { public partial class Program { public static class Marking { public static double Number(string text) { double n;if(!double.TryParse(text,System.Globalization.NumberStyles.Float,Data.Culture,out n)||!Data.Finite(n)) throw Data.Invalid(L.F(L.FleetNumericArgumentInvalid,text));return n; } public static MyIni Parse(Program p,string command) { command=Settings.NormalizeCommand(command); int gps=command.IndexOf("GPS:",Data.Ordinal); var prefix=gps<0?command:command.Substring(0,gps); var parts=prefix.Trim().Split(new[]{' '},StringSplitOptions.RemoveEmptyEntries); if(parts.Length!=4) throw Data.Invalid(L.FleetMarkUsage); double width=Number(parts[1]),height=Number(parts[2]),depth=Number(parts[3]); if(width<=0||height<=0||depth<=0||width>1000||height>1000||depth>1000) throw Data.Invalid(L.FleetMarkDimensions); Vector3D entry,direction,up=p.Me.WorldMatrix.Up; if(gps>=0) { int second=command.IndexOf("GPS:",gps+4,Data.Ordinal);Vector3D inside; if(second<0||!Data.TryGps(command.Substring(gps,second-gps),out entry)||!Data.TryGps(command.Substring(second),out inside)) throw Data.Invalid(L.FleetTwoGpsRequired); direction=inside-entry;if(direction.LengthSquared()<0.01) throw Data.Invalid(L.FleetGpsPointsDiffer); } else { var name=p.Config.Text("Marker","Camera","");var cameras=new List(); p.GridTerminalSystem.GetBlocksOfType(cameras,c=>c.CubeGrid==p.Me.CubeGrid&&c.IsFunctional&&(name.Length==0||c.CustomName==name)); if(cameras.Count==0) throw Data.Invalid(L.FleetMarkerCameraMissing); var camera=cameras[0];camera.EnableRaycast=true; var distance=p.Config.Number("Marker","ScanDistance",1000,10,10000); if(!camera.CanScan(distance)) throw Data.Invalid(L.F(L.FleetMarkerCameraCharging,camera.AvailableScanRange)); var hit=camera.Raycast(distance); if(hit.IsEmpty()||!hit.HitPosition.HasValue||(hit.Type!=MyDetectedEntityType.Asteroid&&hit.Type!=MyDetectedEntityType.Planet)) throw Data.Invalid(L.FleetMarkerSurfaceRequired); entry=hit.HitPosition.Value;direction=entry-camera.GetPosition();up=camera.WorldMatrix.Up; } var i=new MyIni();Data.PutVector(i,"mark","Entry",entry);i.Set("mark","Direction",Data.Vector(Data.Unit(direction,Data.Forward)));i.Set("mark","Up",Data.Vector(Data.Perpendicular(direction,up))); i.Set("mark","Width",width);i.Set("mark","Height",height);i.Set("mark","Depth",depth);return i; } } public class MarkerController : RoleLogic { string last=L.FleetMarkerGuidance; string lastStatus="Guidance",lastWidth="",lastHeight="",lastDepth="",lastEntry=""; public MarkerController(Program p):base(p) {EnableCameras();} void EnableCameras() { var cameras=new List();P.GridTerminalSystem.GetBlocksOfType(cameras,c=>c.CubeGrid==P.Me.CubeGrid); foreach(var camera in cameras) camera.EnableRaycast=true; } public override string Diagnostics => L.F(L.FleetMarkerDiagnostics,P.Config.BaseId,last); public override void Receive(Packet packet) { if(packet.From!=P.Config.BaseId || packet.Epoch<=P.Bus.Epoch)return; P.Bus.Epoch=packet.Epoch;P.Bus.CancelPending(null,P.Config.BaseId);lastStatus="Guidance";UpdateLast(); } public override void Command(string command) { command=Settings.NormalizeCommand(command); var parts=command.Trim().Split(new[]{' '},StringSplitOptions.RemoveEmptyEntries);if(parts.Length==0) return; var verb=parts[0].ToLowerInvariant(); if(verb=="init"||verb=="rescan"||verb=="diagnose") {EnableCameras();P.Log(Diagnostics);return;} if(verb=="mark") { var body=Marking.Parse(P,command);P.Bus.Send("MARK",P.Config.BaseId,body,true); lastStatus="Manual";lastWidth=Data.Text(body,"mark","Width");lastHeight=Data.Text(body,"mark","Height");lastDepth=Data.Text(body,"mark","Depth");lastEntry=Data.Text(body,"mark","Entry");UpdateLast();P.Log(last);return; } if(verb=="survey") { var radius=parts.Length>1?Marking.Number(parts[1]):0;if(radius!=0&&(radius<20||radius>20000)) throw Data.Invalid(L.FleetSurveyRadius); var body=new MyIni();body.Set("survey","Radius",radius);P.Bus.Send("SURVEY_REQUEST",P.Config.BaseId,body,true);lastStatus="Survey";UpdateLast();P.Log(last);return; } P.Log(L.FleetMarkerCommands); } void UpdateLast() { last=lastStatus=="Manual"?L.F(L.FleetMarkerSubmitted,lastWidth,lastHeight,lastDepth,lastEntry):lastStatus=="Survey"?L.FleetMarkerSurveySubmitted:L.FleetMarkerGuidance; } public override void Save(MyIni ini) { ini.Set("marker","FleetEpoch",P.Bus.Epoch); ini.Set("marker","Last",last);ini.Set("marker","Status",lastStatus);ini.Set("marker","Width",lastWidth);ini.Set("marker","Height",lastHeight);ini.Set("marker","Depth",lastDepth);ini.Set("marker","Entry",lastEntry); } public override void Load(MyIni ini) { var epoch=Data.ReadLong(ini,"marker","FleetEpoch");if(epoch<0 || epoch>DateTime.MaxValue.Ticks)throw Data.Invalid("marker.FleetEpoch");P.Bus.Epoch=epoch; // Persist stable status tokens so replacing the script's language changes the UI immediately. lastStatus=ini.Get("marker","Status").ToString("Guidance");lastWidth=Data.Text(ini,"marker","Width");lastHeight=Data.Text(ini,"marker","Height");lastDepth=Data.Text(ini,"marker","Depth");lastEntry=Data.Text(ini,"marker","Entry");UpdateLast(); } } } }