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 class Packet
        {
            public string Kind="",From="",Target="",Id="",Session="";
            public long Seq,Source;
            public bool Reliable;
            public MyIni Body=new MyIni();
            public string Encode(string fleet)
            {
                var i=new MyIni();i.Set("wire","Version",2);i.Set("wire","Fleet",fleet);i.Set("wire","Kind",Kind);i.Set("wire","From",From);i.Set("wire","Target",Target);i.Set("wire","Id",Id);i.Set("wire","Session",Session);i.Set("wire","Seq",Seq);i.Set("wire","Reliable",Reliable);i.Set("wire","Payload",Body.ToString());return i.ToString();
            }
            public static bool TryDecode(string text,string fleet,out Packet packet)
            {
                packet=null;if(text==null || text.Length>24000)return false;
                try
                {
                    var i=new MyIni(); if(!i.TryParse(text) || Data.ReadLong(i,"wire","Version")!=2 || i.Get("wire","Fleet").ToString()!=fleet)return false;
                    var p=new Packet { Kind=i.Get("wire","Kind").ToString(),From=i.Get("wire","From").ToString(),Target=i.Get("wire","Target").ToString(),Id=i.Get("wire","Id").ToString(),Session=i.Get("wire","Session").ToString(),Seq=Data.ReadLong(i,"wire","Seq"),Reliable=i.Get("wire","Reliable").ToBoolean() };
                    if(p.From.Length==0 || p.From.Length>64 || p.Kind.Length==0 || p.Kind.Length>32 || p.Id.Length>160 || p.Session.Length==0 || p.Session.Length>160 || p.Seq<1 || !p.Body.TryParse(i.Get("wire","Payload").ToString()))return false;
                    packet=p;return true;
                }
                catch(ArgumentException) { return false; }
            }
        }
        public class Wire
        {
            class Pending { public Packet Packet;public long Address;public double Sent;public int Tries; }
            readonly Program p;
            readonly IMyBroadcastListener broadcast;
            readonly string tag,session;
            readonly Dictionary<string,Dictionary<string,long>> streams=new Dictionary<string,Dictionary<string,long>>();
            readonly Dictionary<string,Pending> pending=new Dictionary<string,Pending>();
            readonly Dictionary<string,long> peers=new Dictionary<string,long>();
            readonly Dictionary<string,string> peerSessions=new Dictionary<string,string>();
            readonly HashSet<string> retired=new HashSet<string>();
            long sequence;
            int retryCursor;
            public string Session { get {return session;} }
            public int PendingCount { get {return pending.Count;} }
            public Wire(Program owner)
            {
                p=owner;tag="AMS2/"+p.Config.FleetId;session=p.Me.EntityId.ToString()+"-"+DateTime.UtcNow.Ticks.ToString();
                broadcast=p.IGC.RegisterBroadcastListener(tag);broadcast.SetMessageCallback("igc");p.IGC.UnicastListener.SetMessageCallback("igc");
            }
            public void Send(string kind,string target,MyIni body,bool reliable=false,long address=0)
            {
                var packet=new Packet { Kind=kind,From=p.Config.Id,Target=target??"",Session=session,Seq=++sequence,Body=body??new MyIni(),Reliable=reliable };
                packet.Id=session+"-"+packet.Seq;
                if(address==0 && packet.Target.Length>0)peers.TryGetValue(packet.Target,out address);
                if(reliable && packet.Target.Length==0)throw new ArgumentException(L.CommonReliableTarget);
                if(reliable && pending.Count>=64) {p.Log(L.F(L.CommonReliableQueue,kind));return;}
                Transmit(packet,address);
                if(reliable)pending[packet.Id]=new Pending {Packet=packet,Address=address,Sent=p.Now,Tries=1};
            }
            void Transmit(Packet packet,long address)
            {
                string text=packet.Encode(p.Config.FleetId);
                if(text.Length>24000)throw new ArgumentException(L.CommonMessageBudget);
                if(address!=0)p.IGC.SendUnicastMessage(address,tag,text);else p.IGC.SendBroadcastMessage(tag,text,TransmissionDistance.TransmissionDistanceMax);
            }
            public void Tick()
            {
                if(!p.HasBudget(0.55))return;
                var keys=new List<string>(pending.Keys);
                int sent=0;
                for(int n=0;n<keys.Count && sent<2 && p.HasBudget(0.6);n++)
                {
                    retryCursor%=keys.Count;string key=keys[retryCursor++];Pending item=pending[key];
                    if(p.Now-item.Sent<1.5)continue;
                    if(item.Tries>=6) {p.Log(L.F(L.CommonNoAck,item.Packet.Kind,item.Packet.Target));pending.Remove(key);continue;}
                    if(item.Address==0)peers.TryGetValue(item.Packet.Target,out item.Address);
                    Transmit(item.Packet,item.Address);item.Sent=p.Now;item.Tries++;sent++;
                }
            }
            public void Drain(Action<Packet> receive)
            {
                int budget=4,start=p.Runtime.CurrentInstructionCount;
                while(budget-->0 && p.HasBudget(0.55) && p.Runtime.CurrentInstructionCount-start<p.Runtime.MaxInstructionCount*0.2 && (broadcast.HasPendingMessage || p.IGC.UnicastListener.HasPendingMessage))
                {
                    MyIGCMessage message=p.IGC.UnicastListener.HasPendingMessage?p.IGC.UnicastListener.AcceptMessage():broadcast.AcceptMessage();
                    if(message.Tag!=tag)continue;
                    Packet packet;if(!Packet.TryDecode(message.Data as string,p.Config.FleetId,out packet) || packet.From==p.Config.Id || (packet.Target.Length>0 && packet.Target!=p.Config.Id))continue;
                    packet.Source=message.Source;
                    long known;
                    if(peers.TryGetValue(packet.From,out known) && known!=message.Source) {p.Log(L.F(L.CommonDuplicateNode,packet.From));continue;}
                    if(peers.Count>=64 && !peers.ContainsKey(packet.From))continue;
                    string oldSession;
                    if(peerSessions.TryGetValue(packet.From,out oldSession) && oldSession!=packet.Session)
                    {
                        if(retired.Contains(packet.From+"/"+packet.Session))continue;
                        retired.Add(packet.From+"/"+oldSession);
                        // Session replacement automatically drops obsolete sequence-cache entries.
                        // Retired session identities still reject late/replayed old packets.
                        streams.Remove(packet.From);
                    }
                    peers[packet.From]=message.Source;peerSessions[packet.From]=packet.Session;
                    if(packet.Kind=="ACK")
                    {
                        string ack=packet.Body.Get("ack","Id").ToString();Pending item;
                        if(pending.TryGetValue(ack,out item) && item.Packet.Target==packet.From)pending.Remove(ack);continue;
                    }
                    Dictionary<string,long> peerStreams;
                    if(!streams.TryGetValue(packet.From,out peerStreams)) {peerStreams=new Dictionary<string,long>();streams[packet.From]=peerStreams;}
                    long seen;bool duplicate=peerStreams.TryGetValue(packet.Kind,out seen)&&packet.Seq<=seen;
                    if(!duplicate && peerStreams.Count>=32 && !peerStreams.ContainsKey(packet.Kind)) {p.Log(L.CommonStreamLimit);continue;}
                    if(packet.Reliable) {var ack=new MyIni();ack.Set("ack","Id",packet.Id);Send("ACK",packet.From,ack,false,message.Source);}
                    if(duplicate)continue;
                    peerStreams[packet.Kind]=packet.Seq;
                    try {receive(packet);}catch(ArgumentException e) {p.Log(L.F(L.CommonRejectedPacket,packet.Kind,e.Message));}
                }
            }
        }
    }
}