XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

AutoMiningScript

【SpaceEngineer】全自动挖矿脚本

公开
关注 0 Fork 0 Star 0
UTF-8
using System;
using System.Collections.Generic;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame.Utilities;

namespace AutoMiningScript
{
    public partial class Program : MyGridProgram
    {
        public Settings Config;
        public Wire Bus;
        public double Now;
        public readonly Queue<string> Events=new Queue<string>();
        RoleLogic role;
        Dashboard dashboard;
        string failure="";
        bool storageFailure;
        double nextDraw,nextSave,nextBudgetNotice;
        public int BudgetDeferrals {get;private set;}
#if !FLEET
        MyIni checkpoint;
#endif
        public const string Version="2.0.0";
        public Program()
        {
            Runtime.UpdateFrequency=UpdateFrequency.Update1;
            Initialize();
        }
        static string CompiledRole()
        {
#if FLEET
            return "fleet";
#elif MARKER
            return "marker";
#elif WATCHDOG
            return "watchdog";
#else
            return "miner";
#endif
        }
        void Initialize()
        {
            dashboard=null;role=null;storageFailure=false;
            try
            {
                string defaultRole=CompiledRole();string id=defaultRole=="fleet"?"base":defaultRole+"-"+Me.EntityId;
                if(string.IsNullOrWhiteSpace(Me.CustomData))Me.CustomData=Settings.Template(defaultRole,id);
                Config=new Settings(Me.CustomData,defaultRole,id);dashboard=new Dashboard(this);Bus=new Wire(this);
#if FLEET
                role=new FleetController(this);
#elif MARKER
                role=new MarkerController(this);
#elif WATCHDOG
                role=new WatchdogController(this);
#else
                role=new MinerController(this);
#endif
                failure="";
                storageFailure=true;Restore();storageFailure=false;
#if FLEET
                if(((FleetController)role).Restoring)Log(((FleetController)role).RestoreStatus);
                else
#endif
                    Log(L.F(L.CommonReady,L.Brand,Version,Config.Id));
            }
            catch(Exception e) {failure=e.Message;SafeClear();role=null;Echo(L.F(L.CommonInitError,failure));DrawInitializationFault();}
        }
        // Hardware self-check errors still leave a useful local console after INI parsing.
        sealed class InitializationFault : RoleLogic
        {
            readonly string reason;
            public InitializationFault(Program p,string message):base(p) {reason=message;}
            public override string Diagnostics {get{return L.F(L.CommonInitError,reason);}}
            public override List<Telemetry> GetTelemetry() {return new List<Telemetry> {new Telemetry {Id=P.Config.Id,State=FlightState.Fault,Reason=reason,ReceivedAt=P.Now}};}
        }
        void DrawInitializationFault()
        {
            if(dashboard==null || Now<nextDraw)return;
            try {dashboard.Draw(new InitializationFault(this,failure));}catch { /* Echo retains the original failure even if screen settings are invalid. */ }
            nextDraw=Now+0.5;
        }
        public void Main(string argument,UpdateType updateSource)
        {
            double elapsed=Runtime.TimeSinceLastRun.TotalSeconds;
            if(!Data.Finite(elapsed)||elapsed<0)elapsed=0;
            Now+=Math.Min(elapsed,60);
            double dt=Data.Clamp(elapsed,1.0/120,0.2);
            try
            {
                if(argument=="init" && role==null) {Initialize();return;}
                if(role==null) {Echo(L.F(storageFailure?L.CommonFixStorage:L.CommonFixConfig,failure));DrawInitializationFault();return;}
#if FLEET
                var fleet=role as FleetController;
                if(fleet!=null && fleet.Restoring)
                {
                    try
                    {
                        bool legacy=fleet.MigratingLegacy;fleet.RestoreStorageStep();
                        Echo(fleet.Restoring?fleet.RestoreStatus:legacy?L.FleetLegacyMigrationComplete:L.FleetStorageRestored);
                        if(Now>=nextDraw&&HasBudget(0.3)) {dashboard.Draw(fleet);nextDraw=Now+0.5;}
                    }
                    catch(Exception e) {storageFailure=true;failure=L.F(L.CommonStorageInvalid,e.Message);role=null;Echo(L.F(L.CommonFixStorage,failure));}
                    return;
                }
#endif
                if(!string.IsNullOrWhiteSpace(argument) && argument!="igc")
                {
                    if(argument=="init") {role.Command("rescan");Log(L.CommonConfigReload);}
                    else if(argument.StartsWith("page",StringComparison.OrdinalIgnoreCase))dashboard.Command(argument);
                    else role.Command(argument.Trim());
                }
                // Physics runs before optional communications, drawing and persistence.
                // The engine resets its counter on the next invocation; it cannot be reset here.
#if WATCHDOG
                // Heartbeats already queued for this frame must precede timeout evaluation.
                Bus.Drain(role.Receive);
#endif
                role.Tick(dt);
                if(!HasBudget()) {DeferBackground();return;}
#if !WATCHDOG
                Bus.Drain(role.Receive);
#endif
                if(!HasBudget()) {DeferBackground();return;}
                Bus.Tick();
                if(!HasBudget()) {DeferBackground();return;}
                dashboard.Update(role);
                if(Now>=nextDraw && HasBudget(0.45))
                {
                    dashboard.Draw(role);nextDraw=Now+0.5;
                    if(HasBudget())Echo(L.F(L.CommonRuntime,L.Brand,Version,Config.Id,role.Diagnostics,Runtime.CurrentInstructionCount,Runtime.MaxInstructionCount));
                }
                if(!HasBudget()) {DeferBackground();return;}
                if(Now>=nextSave && HasBudget(0.35))Checkpoint();
            }
            catch(Exception e)
            {
                failure=e.Message;Log(L.F(L.CommonFault,failure));
                try {if(role!=null)role.Emergency(failure);else SafeClear();}catch {SafeClear();}
                Echo(L.F(L.CommonFault,failure));
            }
        }
        public bool HasBudget(double fraction=0.65)
        {
            return Runtime.CurrentInstructionCount<Math.Max(1,Runtime.MaxInstructionCount)*fraction;
        }
        void DeferBackground()
        {
            BudgetDeferrals++;
            // Discard only replaceable presentation data. Task leases, progress and the
            // last complete checkpoint must survive a busy frame.
            if(dashboard!=null)dashboard.ClearTransientCache();
            if(Now>=nextBudgetNotice && HasBudget(0.85))
            {
                Log(L.CommonBudgetDeferred);nextBudgetNotice=Now+10;
            }
        }
        public void Log(string text)
        {
            if(text==null)return;if(text.Length>240)text=text.Substring(0,240);
            Events.Enqueue(Now.ToString("F1",Data.Culture)+" "+text);while(Events.Count>12)Events.Dequeue();
        }
        public void SafeClear()
        {
#if !FLEET && !MARKER
            var blocks=new List<IMyTerminalBlock>();GridTerminalSystem.GetBlocksOfType(blocks,b=>b.CubeGrid==Me.CubeGrid);
            foreach(var block in blocks)
            {
                var thrust=block as IMyThrust;if(thrust!=null)thrust.ThrustOverridePercentage=0;
                var gyro=block as IMyGyro;if(gyro!=null) {gyro.Pitch=0;gyro.Yaw=0;gyro.Roll=0;gyro.GyroOverride=false;}
                var drill=block as IMyShipDrill;if(drill!=null)drill.Enabled=false;
                var control=block as IMyShipController;if(control!=null)control.DampenersOverride=true;
                var remote=block as IMyRemoteControl;if(remote!=null)remote.SetAutoPilotEnabled(false);
            }
#endif
        }
        public void Save()
        {
            if(role==null)return;
#if !FLEET
            // Small local state can be committed synchronously at world-save/calibration.
            var ini=NewCheckpoint();role.Save(ini);Commit(ini);
#endif
            // Fleet Storage is the last fully completed checkpoint. Never serialize thousands
            // of jobs in a world-save callback or overwrite it with an incomplete snapshot.
        }
        MyIni NewCheckpoint() {var ini=new MyIni();ini.Set("storage","Version",2);ini.Set("storage","Role",Config.Role);ini.Set("storage","Id",Config.Id);return ini;}
        void Checkpoint()
        {
#if FLEET
            string value;
            if(!((FleetController)role).CheckpointStorage(out value))return;
            if(value.Length<=1500000)Storage=value;else Log(L.CommonStorageBudget);
            nextSave=Now+2;
#else
            if(checkpoint==null)checkpoint=NewCheckpoint();
            if(!role.Checkpoint(checkpoint))return;
            Commit(checkpoint);checkpoint=null;nextSave=Now+2;
#endif
        }
        void Commit(MyIni ini)
        {
            string value=ini.ToString();if(value.Length<=1500000)Storage=value;else Log(L.CommonStorageBudget);
        }
        void Restore()
        {
            if(string.IsNullOrWhiteSpace(Storage))return;
#if FLEET
            if(((FleetController)role).BeginRestoreStorage(Storage))return;
#endif
            var ini=new MyIni();
            if(!ini.TryParse(Storage) || Data.ReadLong(ini,"storage","Version")!=2 || ini.Get("storage","Role").ToString()!=Config.Role || ini.Get("storage","Id").ToString()!=Config.Id) {Log(L.CommonStorageIncompatible);return;}
            try {role.Load(ini);}catch(Exception e) {role.Emergency(L.F(L.CommonStorageInvalid,e.Message));}
        }
    }
}