Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --XT V2.0 by negamartin
- setfenv(1,setmetatable({},{__index=getfenv(1)}));
- local xt={};
- xt.version=2.0;
- --Serialization
- function xt.escapeString(unescaped,esctab)
- local escstr="";
- for c in unescaped:gmatch(".") do
- escstr=escstr..(esctab[c] or c);
- end
- return escstr;
- end
- function xt.descapeString(escaped,desctab,escchar)
- local descstr="";
- local descNext=false;
- if escchar then --1 escape char method (more efficient)
- for c in escaped:gmatch(".") do
- if descNext then
- descstr=descstr..desctab[c];
- descNext=false;
- else
- if c==escchar then
- descNext=true;
- else
- descstr=descstr..c;
- end
- end
- end
- else --Multiple escape chars method (slower)
- for c in escaped:gmatch(".") do
- if descNext then
- descstr=descstr..descNext[c];
- descNext=false;
- else
- descNext=desctab[c];
- if not descNext then
- descstr=descstr..c;
- end
- end
- end
- end
- return descstr;
- end
- --Build safestring escapers
- local char30=string.char(30);
- local char31=string.char(31);
- xt.safeEscaper={["\\"]="\\\\",["\n"]="\\n",["\r"]="\\r",[char30]="\\"..char30,[char31]="\\"..char31};
- xt.safeDescaper={["\\"]={["\\"]="\\",["n"]="\n",["r"]="\r",[char30]=char30,[char31]=char31},[char30]={},[char31]={}};
- for i=128,255 do
- if i==138 then --Will be safed into newline char
- xt.safeEscaper[string.char(138)]=char31.."n";
- xt.safeDescaper[char31]["n"]=string.char(138);
- elseif i==141 then --Will be safed into carriage return char
- xt.safeEscaper[string.char(141)]=char31.."r";
- xt.safeDescaper[char31]["r"]=string.char(141);
- else
- xt.safeEscaper[string.char(i)]=char30..string.char(i-128);
- xt.safeDescaper[char30][string.char(i-128)]=string.char(i);
- end
- end
- function xt.safeString(unsafe) return xt.escapeString(unsafe,xt.safeEscaper); end
- function xt.unsafeString(safe) return xt.descapeString(safe,xt.safeDescaper); end
- function xt.isUnsafe(str)
- for c in str:gmatch(".") do
- local b=c:byte();
- if b==10 or b==13 or b>127 then return true; end
- end
- return false;
- end
- xt.nativeFuncs={};
- xt.serializeEscaper={[","]="|.",["="]="|-",["{"]="|[",["}"]="|]",["|"]="||"};
- xt.serializeDescaper={["."]=",",["-"]="=",["["]="{",["]"]="}",["|"]="|"};
- function xt.stringify(val,lvl,tabs,dofunc,dometa,donative)
- local t=type(val);
- local sval;
- if t=="string" then
- local pre="s";
- if xt.isUnsafe(val) then val=xt.safeString(val);pre="u"; end
- sval=pre..xt.escapeString(val,xt.serializeEscaper);
- elseif t=="number" then
- sval="n"..tostring(val);
- elseif t=="boolean" then
- if val then sval="bt";
- else sval="bf"; end
- elseif t=="table" then
- if tabs[val] then --If table has already been stringified, make a pointer to it
- sval="p"..tabs[val];
- else
- tabs[0]=tabs[0]+1;
- tabs[val]=tabs[0];
- sval="{";
- for k,v in pairs(val) do
- local skey,svalue;
- skey=xt.stringify(k,lvl+1,tabs,dofunc,dometa,donative);
- svalue=xt.stringify(v,lvl+1,tabs,dofunc,dometa,donative);
- sval=sval..skey.."="..svalue..",";
- end
- if dometa and type(getmetatable(val))=="table" then
- sval=sval.."}:"..xt.stringify(getmetatable(val),lvl+1,tabs,dofunc,dometa,donative);
- else
- sval=sval.."}";
- end
- end
- elseif t=="function" then
- if dofunc then
- local ok,dump=pcall(string.dump,val);
- if ok then
- sval="f"..xt.escapeString(xt.safeString(dump),xt.serializeEscaper);
- elseif donative then
- local funcname=false;
- funcname=xt.nativeFuncs[val]; --Check for previously serialized nativefuncs
- if funcname then --And test if they still exist where they should
- local test=_G or (type(getfenv)=="function" and getfenv(1));
- for word in funcname:gmatch("[^%.]+") do
- if type(test)~="table" then test=false;break; end
- test=test[word];
- if type(test)~="table" and type(test)~="function" then test=false;break; end
- end
- if not test then
- xt.nativeFuncs[val]=nil;
- funcname=false;
- end
- end
- if not funcname then --If the nativefunc was not serialized before, find it in _G
- local donetabs={};
- function inspectTab(tab)
- for k,v in pairs(tab) do
- if type(k)=="string" then
- if v==val then return k;
- elseif type(v)=="table" then
- if not donetabs[v] then
- donetabs[v]=true;
- local result=inspectTab(v);
- if result then
- return k.."."..result;
- end
- end
- end
- end
- end
- end
- funcname=inspectTab(_G);
- xt.nativeFuncs[val]=funcname; --And save it for future serializations
- end
- if funcname then
- sval="j"..funcname;
- else
- error("Could not serialize native function ["..tostring(val).."], nested "..(lvl-1).." tables deep",lvl+1);
- end
- else
- error("Serializing native functions is not enabled",lvl+1);
- end
- else error("Serializing functions is not enabled",lvl+1); end
- elseif t=="nil" then
- sval="l";
- else error("Cannot serialize type "..tostring(t)..", nested "..(lvl-1).." tables",lvl+1); end
- return sval;
- end
- function xt.valuefy(str,lvl,tabs,dofunc,dometa,donative)
- local pre=str:sub(1,1);
- local sval=str:sub(2).."";
- local val;
- if pre=="s" then --Safe string
- val=xt.descapeString(sval,xt.serializeDescaper,"|");
- elseif pre=="u" then --Unsafe string
- val=xt.unsafeString(xt.descapeString(sval,xt.serializeDescaper,"|"));
- elseif pre=="n" then --Number
- val=tonumber(sval);
- elseif pre=="b" then --Boolean
- val=sval=="t";
- elseif pre=="{" then --Table
- val={};
- tabs[0]=tabs[0]+1;
- tabs[tabs[0] ]=val;
- local blvl=1;
- local lastStart=1;
- local cur=0;
- local equal=false;
- local metatab=false;
- for c in sval:gmatch(".") do
- cur=cur+1;
- if c=="{" then blvl=blvl+1;
- elseif c=="}" then blvl=blvl-1;
- elseif c=="=" and blvl==1 then
- equal=cur;
- elseif c=="," and blvl==1 then
- local key,value;
- key=xt.valuefy(sval:sub(lastStart,equal-1).."",lvl+1,tabs,dofunc,dometa,donative);
- value=xt.valuefy(sval:sub(equal+1,cur-1).."",lvl+1,tabs,dofunc,dometa,donative);
- val[key]=value;
- lastStart=cur+1;
- elseif blvl==0 and c==":" then
- if dometa then
- metatab=xt.valuefy(sval:sub(cur+1).."",lvl+1,tabs,dofunc,dometa,donative);
- break;
- else error("Unserializing metatables is not enabled",lvl+1); end
- end
- end
- if metatab then setmetatable(val,metatab); end
- elseif pre=="p" then --table Pointer
- val=tabs[tonumber(sval)];
- elseif pre=="f" then --Function
- if dofunc then
- val=loadstring(xt.unsafeString(xt.descapeString(sval,xt.serializeDescaper,"|")));
- else error("Unserializing functions is not enabled",lvl+1); end
- elseif pre=="j" then --Java function
- if donative then
- local curval=_G or (type(getfenv)=="function" and getfenv(1));
- for word in sval:gmatch("[^%.]+") do
- if type(curval)~="table" then curval=false;break; end
- curval=curval[word];
- if type(curval)~="table" and type(curval)~="function" then curval=false;break; end
- end
- if type(curval)=="function" and not pcall(string.dump,curval) then
- val=curval;
- else error("Could not unserialize native function["..sval.."], nested "..(lvl-1).." tables",lvl+1); end
- else error("Unserializing native functions is not enabled",lvl+1); end
- elseif pre=="l" then --niL
- else error("Unknown prefix "..tostring(pre)..", nested "..(lvl-1).." tables",lvl+1); end
- return val;
- end
- function xt.serialize(val,df,dm,dn) return xt.stringify(val,1,{[0]=0},df,dm,dn); end
- function xt.unserialize(str,df,dm,dn) return xt.valuefy(str,1,{[0]=0},df,dm,dn); end
- function xt.fserialize(val,df,dm,dn) return xt.stringify(val,1,{[0]=0},not df,not dm,not dn); end
- function xt.funserialize(str,df,dm,dn) return xt.valuefy(str,1,{[0]=0},not df,not dm,not dn); end
- --Saving
- function xt.setUser(user,lvl)
- if type(user)~="string" then error("User must be a string",2);
- elseif user=="global" then error("User cant be \"global\"",2); end
- local prevenv=getfenv(lvl or 2);
- if rawget(prevenv,"___Xt__UsEr___") then
- rawset(prevenv,"___Xt__UsEr___",user);
- else
- setfenv(lvl or 2,setmetatable({___Xt__UsEr___=user},{__index=prevenv,__newindex=prevenv}));
- end
- end
- function xt.loadValue(user,name)
- if fs.isDir("/xtdata") then
- if type(user)~="string" then error("Attempt to load value with invalid user (maybe call xt.setUser?)",2); end
- user="/xtdata/"..user.."/";
- if fs.isDir(user) then
- if fs.exists(user..name) and not fs.isDir(user..name) then
- local handle=fs.open(user..name,"r");
- local val=handle.readLine();
- handle.close();
- return xt.unserialize(val);
- end
- end
- end
- end
- function xt.saveValue(user,name,val)
- if type(user)~="string" then error("Attempt to save value with invalid user (maybe call xt.setUser?)",2); end
- local sval=xt.serialize(val);
- if not fs.isDir("/xtdata") then
- fs.delete("/xtdata");
- fs.makeDir("/xtdata");
- end
- if not fs.isDir("/xtdata/"..user) then
- fs.delete("/xtdata/"..user);
- fs.makeDir("/xtdata/"..user);
- end
- if fs.isDir("/xtdata/"..user.."/"..name) then
- fs.delete("/xtdata/"..user.."/"..name);
- end
- local h=fs.open("/xtdata/"..user.."/"..name,"w");
- h.writeLine(sval);
- h.close();
- end
- function xt.deleteValue(name,user)
- if user==nil then
- user=getfenv(2).___Xt__UsEr___;
- elseif user==true then
- user="global";
- end
- if type(user)~="string" then error("Attempt to delete value with invalid user (maybe call xt.setUser?)",2); end
- xt.values[user][name]=nil;
- local delUser=#xt.values[user]==0;
- if fs.isDir("/xtdata") then
- user="/xtdata/"..user.."/";
- if fs.isDir(user) then
- fs.delete(user..name);
- end
- if delUser then fs.delete(user); end
- end
- if delUser then
- xt.values[user]=nil;
- end
- end
- xt.values={global={}};
- setmetatable(xt,{__newindex=function(_,k,v)
- if xt.values.global[k]~=nil then
- if v==nil then
- xt.deleteValue(k,"global");
- elseif xt.values.global[k]~=v then
- xt.saveValue("global",k,v);
- xt.values.global[k]=v;
- end
- return;
- end
- local user=getfenv(2).___Xt__UsEr___;
- if xt.values[user] then
- if xt.values[user][k]~=nil then
- if v==nil then
- xt.deleteValue(k,user);
- elseif xt.values[user][k]~=v then
- xt.saveValue(user,k,v);
- xt.values[user][k]=v;
- end
- return;
- end
- end
- rawset(xt,k,v);
- end,__index=function(_,k)
- if xt.values.global[k]~=nil then
- return xt.values.global[k];
- end
- local user=getfenv(2).___Xt__UsEr___;
- if xt.values[user] and xt.values[user][k]~=nil then
- return xt.values[user][k];
- end
- end});
- function xt.addValue(name,val,global,user)
- if user==nil then
- user=getfenv(2).___Xt__UsEr___;
- end
- if type(user)~="string" then error("Attempt to add value with invalid user (maybe call xt.setUser?)",2); end
- if global then user="global"; end
- if type(name)~="string" then error("Value name must be a string",2);
- elseif user~="global" and xt.values.global[name]~=nil then error("A global value named \""..name.."\" is already registered",2);
- --elseif xt.values[user] and xt.values[user][name]~=nil then error("Value \""..name.."\" is already registered to user \""..user.."\"",2);
- elseif rawget(xt,name)~=nil then error("xt."..tostring(name).." already exists as a non-value key",2);
- end
- if type(xt.values[user])~="table" then xt.values[user]={}; end
- local prevVal=xt.loadValue(user,name);
- if prevVal==nil then
- if val~=nil then
- xt.saveValue(user,name,val);
- xt.values[user][name]=val;
- end
- return true;
- else
- xt.values[user][name]=prevVal;
- return false;
- end
- end
- function xt.save(name)
- local user=getfenv(2).___Xt__UsEr___;
- if type(user)~="string" then error("Attempt to save value with invalid user (maybe call xt.setUser?)",2);
- elseif type(name)~="string" then error("Name should be a string",2); end
- if xt.values.global[name]~=nil then
- xt.saveValue("global",name,xt.values.global[name]);
- elseif xt.values[user][name]~=nil then
- xt.saveValue(user,name,xt.values[user][name]);
- end
- end
- --Stackgroup system
- xt.stackgroup={};
- xt.priorities={};
- xt.stacknames={};
- function xt.addStack(stackgroup,priorities,stacknames,name,priority)
- priority=priority or 0;
- if stackgroup[name] then error("Stack "..name.." already exists",2); end
- local myIndex=false;
- for i,p in ipairs(priorities) do
- if p<priority then myIndex=i;break; end
- end
- myIndex=myIndex or (#priorities+1);
- table.insert(priorities,myIndex,priority);
- table.insert(stacknames,myIndex,name);
- stackgroup[name]={};
- return true;
- end
- function xt.pushStack(stackgroup,sname,handler)
- local stack=stackgroup[sname];
- if stack then
- stack[#stack+1]=handler;
- else error("Attempt to push unexisting stack "..tostring(sname),2); end
- return true;
- end
- function xt.popStack(stackgroup,sname)
- local stack=stackgroup[sname];
- if not stack then error("Attempt to pop unexisting stack "..tostring(sname),2); end
- local h=stack[#stack];
- stack[#stack]=nil;
- return h;
- end
- function xt.peekStack(stackgroup,sname)
- local stack=stackgroup[sname];
- if not stack then error("Attempt to peek unexisting stack "..tostring(sname),2); end
- return stack[#stack];
- end
- function xt.peekAllStacks(stackgroup,stacknames)
- local i=1;
- return function()
- while true do
- local name=stacknames[i];
- if name==nil then return; end
- local stack=stackgroup[name];
- i=i+1;
- if #stack~=0 then return name,stack[#stack]; end
- end
- end;
- end
- function xt.callStackgroup(stackgroup,stacknames,...)
- for i=1,#stacknames do
- local stack=stackgroup[stacknames[i]];
- if #stack~=0 then stack[#stack](...); end
- end
- end
- function xt.addStackgroup(name)
- local stackgroup={};
- local priorities={};
- local stacknames={};
- xt.stackgroup[name]=stackgroup;
- xt.priorities[name]=priorities;
- xt.stacknames[name]=stacknames;
- --Main functions
- xt["add"..name]=function(n,p)
- return xt.addStack(stackgroup,priorities,stacknames,n,p);
- end
- xt["push"..name]=function(n,h)
- return xt.pushStack(stackgroup,n,h);
- end
- xt["pop"..name]=function(n)
- return xt.popStack(stackgroup,n);
- end
- xt["peek"..name]=function(n)
- return xt.peekStack(stackgroup,n);
- end
- xt["peekAll"..name]=function()
- return xt.peekAllStacks(stackgroup,stacknames);
- end
- xt["call"..name]=function(...)
- return xt.callStackgroup(stackgroup,stacknames,...);
- end
- --Helper functions
- xt["check"..name]=function(n,dp)
- if stackgroup[n]==nil then
- return xt.addStack(stackgroup,priorities,stacknames,n,dp);
- end
- return false;
- end
- xt["fpush"..name]=function(n,h,dp)
- if stackgroup[n]==nil then
- xt.addStack(stackgroup,priorities,stacknames,n,dp);
- end
- return xt.pushStack(stackgroup,n,h);
- end
- xt["delete"..name]=function(n)
- if stackgroup[n] then
- for i,tn in ipairs(stacknames) do
- if tn==n then
- table.remove(priorities,i);
- table.remove(stacknames,i);
- break;
- end
- end
- stackgroup[n]=nil;
- end
- end
- end
- --Program restoration
- function xt.enableRestoration(path,prevdo)
- path=path or shell.getRunningProgram();
- if type(path)~="string" then error("Expected program pathname",2);
- elseif not fs.exists(path) or fs.isDir(path) then error("Pathname must be a file",2);
- elseif prevdo and prevdo~="p" and prevdo~="b" and prevdo~="a" and prevdo~="i" then error("Invalid old startup handling, "..tostring(prevdo),2); end
- xt.disableRestoration();
- if fs.exists("/startup") then
- if fs.isDir("/startup") then
- prevdo="i";
- else
- if not prevdo then
- print("What do you wish to do with the previous startup program?");
- print("[P] Run it alongside this program on startup");
- print("[B] Run it before this program on startup");
- print("[A] Run it after this program on startup");
- print("[I] Don't run it at all, just restore it after");
- while true do
- local ev,k=os.pullEvent("key");
- if k==keys.p then prevdo="p";break; --Parallel
- elseif k==keys.b then prevdo="b";break; --Before
- elseif k==keys.a then prevdo="a";break; --After
- elseif k==keys.i then prevdo="i";break; --Ignore
- end
- end
- sleep(0); --Clear event queue, including key pressed
- end
- end
- if fs.exists("/xt_active_startup") then
- local i=1;
- while true do
- if not fs.exists("/xt_startup_backup_"..i) then break; end
- i=i+1;
- end
- fs.move("/xt_active_startup","/xt_startup_backup_"..i);
- end
- fs.move("/startup","/xt_active_startup");
- else prevdo="i"; end
- local contents;
- if prevdo=="p" then
- contents=[[parallel.waitForAll(function()shell.run("/xt_active_startup")end,function()shell.run("]]..path..[[")end)]];
- elseif prevdo=="b" then
- contents=[[local ok,err=pcall(shell.run,"/xt_active_startup")if not ok then printError(tostring(err))sleep(2) end shell.run("]]..path..[[")]];
- elseif prevdo=="a" then
- contents=[[local ok,err=pcall(shell.run,"]]..path..[[")if not ok then printError(tostring(err))sleep(2) end shell.run("/xt_active_startup")]];
- elseif prevdo=="i" then
- contents=[[shell.run("]]..path..[[");]];
- else error("what?"); end
- local handle=fs.open("/startup","w");
- handle.writeLine("--XT's restore-on-startup program");
- handle.writeLine("--DO NOT CHANGE OR REMOVE THESE COMMENTS");
- handle.writeLine("--Running "..path);
- if prevdo=="i" then handle.writeLine("--and nothing else");
- else handle.writeLine("--and /xt_active_startup"); end
- handle.writeLine(contents);
- handle.close();
- if not fs.exists("/restore") then
- local handle=fs.open("/restore","w");
- handle.writeLine("--XT's easy startup disabler program");
- handle.writeLine("--DO NOT CHANGE OR REMOVE THESE COMMENTS");
- handle.writeLine([[if type(xt)=="table" and type(xt.disableRestoration)=="function" then xt.disableRestoration(); else printError("Failed to restore"); end]]);
- handle.close();
- end
- return true;
- end
- function xt.disableRestoration()
- local didDo=false;
- if fs.exists("/startup") and not fs.isDir("/startup") then
- local handle=fs.open("/startup","r");
- local first=handle.readLine();
- local second=handle.readLine();
- handle.close();
- if first=="--XT's restore-on-startup program" and second=="--DO NOT CHANGE OR REMOVE THESE COMMENTS" then
- fs.delete("/startup");
- didDo=true;
- end
- end
- if fs.exists("/restore") and not fs.isDir("/restore") then
- local handle=fs.open("/restore","r");
- local first=handle.readLine();
- local second=handle.readLine();
- handle.close();
- if first=="--XT's easy startup disabler program" and second=="--DO NOT CHANGE OR REMOVE THESE COMMENTS" then
- fs.delete("/restore");
- end
- end
- if fs.exists("/xt_active_startup") and not fs.exists("/startup") then
- fs.move("/xt_active_startup","/startup");
- end
- return didDo;
- end
- --Turtle functions that dont require turtle api
- xt.fc={
- south=0,
- west=1,
- north=2,
- east=3,
- [0]="south",
- [1]="west",
- [2]="north",
- [3]="east",
- ["z+"]=0,
- ["x-"]=1,
- ["z-"]=2,
- ["x+"]=3,
- zplus=0,
- xminus=1,
- zminus=2,
- xplus=3,
- };
- function xt.invertFace(facing)
- return (facing+2)%4;
- end
- function xt.getFX(f)
- f=f or xt.f;
- if f==nil then error("F must be a number",2);
- elseif f==1 then return -1;
- elseif f==3 then return 1;
- else return 0; end
- end
- function xt.getFZ(f)
- f=f or xt.f;
- if f==nil then error("F must be a number",2);
- elseif f==0 then return 1;
- elseif f==2 then return -1;
- else return 0; end
- end
- --Turtle functions that do require turtle api
- if turtle then
- --Set values
- ___Xt__UsEr___="xt";
- xt.addValue("x",0,true);
- xt.addValue("y",0,true);
- xt.addValue("z",0,true);
- xt.addValue("f",0,true);
- --Movement handling
- xt.addStackgroup("Premove");
- xt.addStackgroup("Preturn");
- xt.addStackgroup("Refuel");
- xt.addPremove("err",0);
- xt.pushPremove("err",function()error("Attempt to move without reloading stacks (maybe call xt.setTurtleUser?)");end);
- xt.addPreturn("err",0);
- xt.pushPreturn("err",function()error("Attempt to turn without reloading stacks (maybe call xt.setTurtleUser?)");end);
- xt.addRefuel("err",0);
- xt.pushRefuel("err",function()error("Refueled without reloading stacks (maybe call xt.setTurtleUser?)");end);
- --Position saving
- xt.addValue("moveData",{false,0});
- function xt.doMove(dir,mult)
- if dir=="fw" then
- if xt.getFX()==0 then
- xt.z=xt.z+xt.getFZ()*mult;
- else
- xt.x=xt.x+xt.getFX()*mult;
- end
- elseif dir=="bk" then
- if xt.getFX()==0 then
- xt.z=xt.z-xt.getFZ()*mult;
- else
- xt.x=xt.x-xt.getFX()*mult;
- end
- elseif dir=="up" then
- xt.y=xt.y+mult;
- elseif dir=="dn" then
- xt.y=xt.y-mult;
- end
- end
- function xt.premoveSaving(dir)
- if xt.moveData[1] then xt.correctPosition(); end
- xt.moveData[2]=xt.getFuelLevel();
- xt.moveData[1]=dir;
- xt.save("moveData");
- end
- function xt.postmoveSaving(dir,ok)
- if ok then
- xt.doMove(dir,1);
- end
- xt.moveData[1]=false;
- xt.save("moveData");
- end
- function xt.preturnSaving(dir)
- if dir=="r" then xt.f=(xt.f+1)%4;
- elseif dir=="l" then xt.f=(xt.f-1)%4;
- else error("suspicious..."); end
- end
- function xt.preturnChecking(dir)
- xt.wasTurning=xt.wasTurning+1;
- end
- function xt.postturnChecking(dir)
- xt.wasTurning=xt.wasTurning-1;
- end
- xt.fuelUpdated=false;
- function xt.postmoveFuel(dir,ok)
- if ok and xt.fuelUpdated then
- xt.fuelUpdated=xt.fuelUpdated-1;
- end
- end
- function xt.refuelFuel()
- xt.fuelUpdated=false;
- end
- function xt.reloadStacks(dontsave,checkturns)
- xt.stackgroup={};
- xt.priorities={};
- xt.stacknames={};
- xt.addStackgroup("Premove");
- xt.addStackgroup("Forcemove");
- xt.addStackgroup("Postmove");
- xt.addStackgroup("Preturn");
- xt.addStackgroup("Postturn");
- xt.addStackgroup("Refuel");
- if not dontsave then
- xt.addPremove("pos_save",100);
- xt.pushPremove("pos_save",xt.premoveSaving);
- xt.addPostmove("pos_save",100);
- xt.pushPostmove("pos_save",xt.postmoveSaving);
- xt.addPreturn("face_save",100);
- xt.pushPreturn("face_save",xt.preturnSaving);
- end
- if checkturns then
- xt.addValue("wasTurning",0);
- xt.addPreturn("face_check",100);
- xt.pushPreturn("face_check",xt.preturnChecking);
- xt.addPostturn("face_check",100);
- xt.pushPostturn("face_check",xt.postturnChecking);
- else
- xt.deleteValue("wasTurning");
- end
- xt.addPostmove("quick_fuel",90);
- xt.pushPostmove("quick_fuel",xt.postmoveFuel);
- xt.addRefuel("quick_fuel",90);
- xt.pushRefuel("quick_fuel",xt.refuelFuel);
- end
- function xt.setTurtleUser(user,dontsave,checkturns)
- xt.setUser(user,3);
- xt.reloadStacks(dontsave,checkturns);
- end
- --Movement functions
- function xt.move(count,mfunc,dir,invfunc,invdir,force,...)
- count=count or 1;
- if count<0 then return xt.move(-count,invfunc,invdir,mfunc,dir,force,...); end
- for i=1,count do
- xt.callPremove(dir,...);
- local ok=true;
- if force then
- while not mfunc() do
- xt.callForcemove(dir,...);
- end
- else ok=mfunc(); end
- xt.callPostmove(dir,ok,...);
- if not ok then return false; end
- end
- return true;
- end
- function xt.turn(count,tfunc,dir,invfunc,invdir,...)
- count=count or 1;
- if count<0 then return xt.turn(-count,invfunc,invdir,tfunc,dir,...); end
- for i=1,count do
- xt.callPreturn(dir,...);
- tfunc();
- xt.callPostturn(dir,...);
- end
- return true;
- end
- --Movement shortcuts
- function xt.fw(count,...) return xt.move(count,xt.native.forward,"fw",xt.native.back,"bk",false,...); end
- function xt.bk(count,...) return xt.move(count,xt.native.back,"bk",xt.native.forward,"fw",false,...); end
- function xt.up(count,...) return xt.move(count,xt.native.up,"up",xt.native.down,"dn",false,...); end
- function xt.dn(count,...) return xt.move(count,xt.native.down,"dn",xt.native.up,"up",false,...); end
- function xt.ffw(count,...) return xt.move(count,xt.native.forward,"fw",xt.native.back,"bk",true,...); end
- function xt.fbk(count,...) return xt.move(count,xt.native.back,"bk",xt.native.forward,"fw",true,...); end
- function xt.fup(count,...) return xt.move(count,xt.native.up,"up",xt.native.down,"dn",true,...); end
- function xt.fdn(count,...) return xt.move(count,xt.native.down,"dn",xt.native.up,"up",true,...); end
- function xt.left(count,...) return xt.turn(count,xt.native.turnLeft,"l",xt.native.turnRight,"r",...); end
- function xt.right(count,...) return xt.turn(count,xt.native.turnRight,"r",xt.native.turnLeft,"l",...); end
- --Facing management
- function xt.quickTurn(dist)
- dist=dist%4;
- if dist==0 then
- elseif dist==1 then xt.right();
- elseif dist==2 then xt.right(2);
- elseif dist==3 then xt.left();
- else error("what?"); end
- return true;
- end
- function xt.face(nf)
- if nf==nil then return false,"Not enough arguments"; end
- return xt.quickTurn(nf-xt.f);
- end
- --Position management
- function xt.gotoX(nx)
- if nx>xt.x+0.1 then xt.face(3) elseif nx<xt.x-0.1 then xt.face(1); else return true; end
- local dif=math.abs(nx-xt.x);
- return xt.fw(dif);
- end
- function xt.gotoZ(nz)
- if nz>xt.z+0.1 then xt.face(0) elseif nz<xt.z-0.1 then xt.face(2); else return true; end
- local dif=math.abs(nz-xt.z);
- return xt.fw(dif);
- end
- function xt.gotoXZ(nx,nz)
- local fx=xt.getFX();
- local fz=xt.getFZ();
- if (fz==1 and nz>xt.z) or (fz==-1 and nz<xt.z) or (fx==1 and nx<xt.x) or (fx==-1 and nx>xt.x) then
- xt.gotoZ(nz);
- xt.gotoX(nx);
- else
- xt.gotoX(nx);
- xt.gotoZ(nz);
- end
- end
- function xt.gotoY(ny)
- local func;
- if ny>xt.y then func=xt.up; elseif ny<xt.y then func=xt.dn; else return true; end
- local dif=math.abs(ny-xt.y);
- return func(dif);
- end
- function xt.gotoXZY(nx,ny,nz)
- xt.gotoXZ(nx,nz);
- xt.gotoY(ny);
- end
- function xt.gotoYXZ(nx,ny,nz)
- xt.gotoY(ny);
- xt.gotoXZ(nx,nz);
- end
- function xt.fgotoX(nx)
- if nx>xt.x+0.1 then xt.face(3) elseif nx<xt.x-0.1 then xt.face(1); else return true; end
- local dif=math.abs(nx-xt.x);
- return xt.ffw(dif);
- end
- function xt.fgotoZ(nz)
- if nz>xt.z+0.1 then xt.face(0) elseif nz<xt.z-0.1 then xt.face(2); else return true; end
- local dif=math.abs(nz-xt.z);
- return xt.ffw(dif);
- end
- function xt.fgotoXZ(nx,nz)
- local fx=xt.getFX();
- local fz=xt.getFZ();
- if (fz==1 and nz>xt.z) or (fz==-1 and nz<xt.z) or (fx==1 and nx<xt.x) or (fx==-1 and nx>xt.x) then
- xt.fgotoZ(nz);
- xt.fgotoX(nx);
- else
- xt.fgotoX(nx);
- xt.fgotoZ(nz);
- end
- end
- function xt.fgotoY(ny)
- local func;
- if ny>xt.y then func=xt.fup; elseif ny<xt.y then func=xt.fdn; else return true; end
- local dif=math.abs(ny-xt.y);
- return func(dif);
- end
- function xt.fgotoXZY(nx,ny,nz)
- xt.fgotoXZ(nx,nz);
- xt.fgotoY(ny);
- end
- function xt.fgotoYXZ(nx,ny,nz)
- xt.fgotoY(ny);
- xt.fgotoXZ(nx,nz);
- end
- function xt.navigate(coord,goal)
- local movePlus=true;
- if coord=="x" then
- if goal<xt.x then
- xt.face(xt.fc.xminus);
- movePlus=false;
- elseif goal>xt.x then
- xt.face(xt.fc.xplus);
- movePlus=true;
- else return; end
- elseif coord=="z" then
- if goal<xt.z then
- xt.face(xt.fc.zminus);
- movePlus=false;
- elseif goal>xt.z then
- xt.face(xt.fc.zplus);
- movePlus=true;
- else return; end
- else error("Invalid navigate coord",2); end
- while (movePlus and xt[coord]-0.1<goal) or (not movePlus and xt[coord]-0.1>goal) do
- while xt.dn() do end
- while not xt.fw() do
- while not xt.up() do
- while not xt.bk() do
- xt.dn();
- end
- end
- end
- end
- end
- --[[function xt.nav(coord,goal) --Untested method
- local moveCount;
- xt.correctPosition();
- if coord=="x" then
- if goal>xt.x then
- xt.face(xt.fc.xplus);
- moveCount=goal-xt.x;
- elseif goal<xt.x then
- xt.face(xt.fc.xminus);
- moveCount=xt.x-goal;
- else return true; end
- elseif coord=="z" then
- if goal>xt.z then
- xt.face(xt.fc.zplus);
- moveCount=goal-xt.z;
- elseif goal<xt.z then
- xt.face(xt.fc.zminus);
- moveCount=xt.z-goal;
- else return true; end
- else error("Invalid coord "..tostring(coord),2); end
- local counter=1;
- while counter<=moveCount do
- while xt.dn() do end
- while not xt.fw() do
- while not xt.up() do
- while not xt.bk() do
- while not xt.dn() do
- sleep(0.2);
- end
- end
- counter=counter-1;
- end
- end
- counter=counter+1;
- end
- return true;
- end]]
- function xt.navXZ(nx,nz)
- local fx=xt.getFX();
- local fz=xt.getFZ();
- if (fz==1 and nz>xt.z) or (fz==-1 and nz<xt.z) or (fx==1 and nx<xt.x) or (fx==-1 and nx>xt.x) then
- xt.navigate("z",nz);
- xt.navigate("x",nx);
- else
- xt.navigate("x",nx);
- xt.navigate("z",nz);
- end
- end
- --Orientation functions
- function xt.locateGPS()
- local tx;
- local ty;
- local tz;
- tx,ty,tz=gps.locate();
- if tx==nil or ty==nil or tz==nil then return false; end
- xt.x=tx;
- xt.z=tz;
- xt.y=ty;
- return true;
- end
- function xt.orientGPS(forward,back,donealready) --Orient facing using
- if xt.getFuelLevel()~="unlimited" then
- if xt.getFuel()<2 then return false,"Not enough fuel"; end
- end
- if donealready==nil then donealready=false; end
- if forward==nil then forward=xt.fw; end
- if back==nil then back=xt.bk; end
- local tx;
- local tz;
- if not xt.locate() then return false,"Could not reach GPS"; end
- tx=xt.x;tz=xt.z;
- if not forward() then
- if donealready then return false,"Could not go forward";
- else return xt.calibrateGPS(back,forward,true); end
- end
- if not xt.locate() then back(); return false,"Could not reach GPS"; end
- local dx=xt.x-tx;
- local dz=xt.z-tz;
- if donealready then dx=-dx;dz=-dz; end
- if dz==1 then xt.f=0;
- elseif dz==-1 then xt.f=2;
- elseif dx==1 then xt.f=3;
- elseif dx==-1 then xt.f=1;
- end
- back();
- xt.wasTurning=0;
- return true;
- end
- --Uses an inspected table of a torch, lever, ladder, sign or button with a known direction relative to the turtle to orient
- --Dir must be "front", "left", "right" or "back"
- function xt.orientTorch(tab,dir)
- local tdir;
- local meta=tab.metadata;
- local block=tab.name;
- if block=="minecraft:torch" or block=="minecraft:redstone_torch" or block=="minecraft:lever" or
- block=="minecraft:stone_button" or block=="minecraft:wooden_button" then
- if meta==1 then tdir=xt.fc.xplus;
- elseif meta==2 then tdir=xt.fc.xminus;
- elseif meta==3 then tdir=xt.fc.zplus;
- elseif meta==4 then tdir=xt.fc.zminus;
- else return false; end
- elseif block=="minecraft:ladder" or block=="minecraft:wall_sign" then
- if meta==5 then tdir=xt.fc.xplus;
- elseif meta==4 then tdir=xt.fc.xminus;
- elseif meta==3 then tdir=xt.fc.zplus;
- elseif meta==2 then tdir=xt.fc.zminus;
- else return false; end
- else return false; end
- if dir=="front" then xt.f=tdir;
- elseif dir=="back" then xt.f=(tdir+2)%4;
- elseif dir=="left" then xt.f=(tdir+1)%4;
- elseif dir=="right" then xt.f=(tdir-1)%4;
- else return false; end
- xt.wasTurning=0;
- return true;
- end
- --Orient using torches or ladders. WILL TRY DIGGING BLOCKS
- --Signs, levers and buttons cant be used, they arent placed properly from above
- --XT will learn from its mistakes, and save a table of blocks that cant be placed or torches may be placed
- xt.addValue("cantOrientOn",{
- ["minecraft:glass"]={[0]=true},
- ["ComputerCraft:CC-Peripheral"]={[1]=true},
- });
- function xt.canOrientOn(tab)
- if not tab then return false; end
- if xt.cantOrientOn[tab.name] then
- return not xt.cantOrientOn[tab.name][tab.metadata or tab.damage];
- else return true; end
- end
- function xt.setCantOrientOn(tab)
- if not xt.cantOrientOn[tab.name] then xt.cantOrientOn[tab.name]={}; end
- xt.cantOrientOn[tab.name][tab.metadata or tab.damage]=true;
- xt.save("cantOrientOn");
- end
- function xt.orientDigging()
- --Search for orienting items
- local lastS=xt.s;
- local bslot=false;
- for i=1,16 do
- local tab=xt.getItemDetail(i);
- if tab then
- if tab.name=="minecraft:torch" or tab.name=="minecraft:redstone_torch" or tab.name=="minecraft:ladder" then
- bslot=i;
- break;
- end
- end
- end
- --And if we found them, setup the place so that placing the torch will only allow it to face in 1 direction
- if bslot then
- local lastF=xt.f;
- --Search for blocks already placed
- local foundBlock=false;
- for i=1,4 do
- local tab=xt.inspect();
- if tab then
- if xt.canOrientOn(tab) then
- foundBlock=tab;
- break;
- else
- if not xt.dig() then
- xt.face(lastF);
- return false,"Found undiggable block";
- end
- end
- end
- xt.right();
- end
- xt.checkForcemove("justdig",0);
- xt.pushForcemove("justdig",xt.forceDig);
- function finish()
- xt.popForcemove("justdig");
- xt.sel(lastS);
- end
- function tryBlock()
- xt.fup();
- xt.sel(bslot);
- if xt.placeDn() then return true;
- else
- xt.fdn();
- return false;
- end
- end
- if foundBlock then
- --Remove all other blocks
- for i=1,3 do
- xt.right();
- if not xt.dig() then
- if xt.detect() then
- xt.face(lastF);
- finish();
- return false,"Found undiggable block";
- end
- end
- end
- xt.right();
- if not xt.digDn() and xt.detectDn() then
- xt.face(lastF);
- finish();
- return
- end
- --Try the found block
- if tryBlock() then
- local nowF=xt.f;
- if xt.orientTorch(xt.inspectDn(),"back") then
- xt.fdn();
- xt.quickTurn(lastF-nowF);
- finish();
- return true;
- end
- else
- xt.setCantOrientOn(foundBlock);
- end
- end
- --If the already-placed blocks failed, try the blocks in inventory
- for i=1,16 do
- if i~=bslot and xt.getItemCount(i)~=0 then
- local tab=xt.getItemDetail(i);
- if xt.canOrientOn(tab) then
- xt.dig();
- xt.sel(i);
- if xt.place() then
- if not xt.digDn() and xt.detectDn() then
- xt.dig();
- xt.face(lastF);
- finish();
- return false,"Found undiggable block";
- end
- if tryBlock() then
- local nowF=xt.f;
- if xt.orientTorch(xt.inspectDn(),"back") then
- xt.fdn();
- xt.sel(i);
- xt.dig();
- xt.quickTurn(lastF-nowF);
- finish();
- return true;
- end
- else
- xt.setCantOrientOn(tab);
- end
- xt.sel(i);
- xt.dig();
- else
- xt.setCantOrientOn(tab);
- end
- end
- end
- end
- finish();
- return false,"Could not place orienting item";
- else return false,"Could not find orienting item"; end
- end
- --Misc functions
- function xt.refuel(count,...)
- local ok,ret;
- if count then ok,ret=xt.native.refuel(count);
- else ok,ret=xt.native.refuel(); end
- if ok then
- for n,h in xt.peekAllRefuel() do
- h(...);
- end
- end
- return ok,ret;
- end
- function xt.getFuel()
- if xt.fuelUpdated then return xt.fuelUpdated;
- else return xt.getFuelLevel(); end
- end
- function xt.getFuelLevel()
- xt.fuelUpdated=xt.native.getFuelLevel();
- return xt.fuelUpdated;
- end
- function xt.getCurSlot()
- xt.s=xt.native.getSelectedSlot();
- return xt.s;
- end
- function xt.sel(s)
- xt.native.select(s);
- xt.s=s;
- return true;
- end
- function xt.restoreTurtle()
- if type(turtle.native)~="table" then return false; end
- for k,v in pairs(turtle.native) do
- turtle[k]=v;
- end
- turtle.xt_replaced=nil;
- return true;
- end
- function xt.unloadXT()
- xt.restoreTurtle();
- _G.xt=nil;
- return "Bye Bye";
- end
- function xt.inspectBase(ifunc)
- local ok,tab=ifunc();
- if ok then
- return tab;
- else
- return false,tab;
- end
- end
- function xt.inspect() return xt.inspectBase(xt.native.inspect); end
- function xt.inspectDn() return xt.inspectBase(xt.native.inspectDown); end
- function xt.inspectUp() return xt.inspectBase(xt.native.inspectUp); end
- function xt.addDir(name)
- if type(name)~="string" then error("name must be a string",2); end
- local func=xt[name];
- if type(func)~="function" then error("No "..name.."() function in XT api",2); end
- local funcUp=xt[name.."Up"];
- if type(funcUp)~="function" then error("No "..name.."Up() function in XT api",2); end
- local funcDn=xt[name.."Dn"];
- if type(funcDn)~="function" then error("No "..name.."Dn() function in XT api",2); end
- xt[name.."Dir"]=function(dir,...)
- if dir=="fw" then return func(...);
- elseif dir=="up" then return funcUp(...);
- elseif dir=="dn" then return funcDn(...);
- elseif dir=="bk" then
- xt.right(2);
- local ok=func(...);
- xt.right(2);
- return ok;
- end
- end
- end
- --Check if previous xt replaced turtle
- if turtle.xt_replaced then xt.restoreTurtle(); end
- --Copy any missing turtle functions
- for k,v in pairs(turtle) do
- if k=="forward" then xt.forward=xt.fw;
- elseif k=="back" then xt.back=xt.bk;
- elseif k=="up" then
- elseif k=="down" then xt.down=xt.dn;
- elseif k=="turnLeft" then xt.turnLeft=xt.left;
- elseif k=="turnRight" then xt.turnRight=xt.right;
- elseif k=="select" then xt.select=xt.sel;
- elseif k=="inspect" then
- elseif k=="inspectUp" then
- elseif k=="inspectDown" then xt.inspectDown=xt.inspectDn;
- elseif k=="attack" then xt.attack=v;xt.atk=v;xt.attackDir=xt.atkDir;
- elseif k=="attackUp" then xt.attackUp=v;xt.atkUp=v;
- elseif k=="attackDown" then xt.attackDown=v;xt.atkDn=v;xt.attackDn=v;
- elseif k=="digDown" then xt.digDown=v;xt.digDn=v;
- elseif k=="placeDown" then xt.placeDown=v;xt.placeDn=v;
- elseif k=="detectDown" then xt.detectDown=v;xt.detectDn=v;
- elseif k=="compareDown" then xt.compareDown=v;xt.compareDn=v;
- elseif k=="dropDown" then xt.dropDown=v;xt.dropDn=v;
- elseif k=="suckDown" then xt.suckDown=v;xt.suckDn=v;
- elseif k=="refuel" then
- elseif k=="getFuelLevel" then
- elseif k=="getSelectedSlot" then xt.getSelectedSlot=xt.getCurSlot;
- else xt[k]=v; end
- end
- --Add ***Dir functions
- xt.go=xt.fw;
- xt.goUp=xt.up;
- xt.goDn=xt.dn;
- xt.fgo=xt.ffw;
- xt.fgoUp=xt.fup;
- xt.fgoDn=xt.fdn;
- xt.addDir("go");
- xt.addDir("fgo");
- xt.addDir("atk");
- xt.addDir("attack");
- xt.addDir("dig");
- xt.addDir("place");
- xt.addDir("detect");
- xt.addDir("inspect");
- xt.addDir("compare");
- xt.addDir("drop");
- xt.addDir("suck");
- xt.forceDig=xt.digDir;
- xt.forceAtk=xt.atkDir;
- xt.forceAttack=xt.attackDir;
- --Replace turtle functions
- turtle.forward=xt.fw;
- turtle.back=xt.bk;
- turtle.up=xt.up;
- turtle.down=xt.dn;
- turtle.turnLeft=xt.left;
- turtle.turnRight=xt.right;
- turtle.refuel=xt.refuel;
- turtle.getFuelLevel=xt.getFuelLevel;
- turtle.select=xt.sel;
- turtle.xt_replaced=true;
- xt.getCurSlot(); --Set xt.s
- --Position error correction
- function xt.shouldReorient()
- if xt.wasTurning==nil then error("Orientation checking is not enabled",2); end
- return xt.wasTurning>0;
- end
- function xt.shouldRelocate()
- return not not xt.moveData[1]; --Returns true or false only (so relocation isnt manually, and wrongly, done)
- end
- function xt.correctPosition()
- if xt.shouldRelocate() then
- local b=xt.detect(); --Make sure previous move finishes (and gather data!)
- local fuel=xt.getFuelLevel();
- if fuel=="unlimited" then
- if not b then xt.doMove(xt.moveData[1],1); end --Try our best
- else
- if xt.moveData[2]-fuel==1 then
- xt.doMove(xt.moveData[1],1);
- end
- end
- xt.moveData[1]=false;
- xt.save("moveData");
- end
- end
- xt.correctPosition();
- end
- _G.xt=xt; --Export xt api to global environment
Advertisement
Add Comment
Please, Sign In to add comment