Add more lua scripts.
							parent
							
								
									fca618ff1b
								
							
						
					
					
						commit
						191071beb6
					
				| @ -0,0 +1,234 @@ | |||||||
|  | --[[ DataDumper.lua | ||||||
|  | Copyright (c) 2007 Olivetti-Engineering SA | ||||||
|  | 
 | ||||||
|  | Permission is hereby granted, free of charge, to any person | ||||||
|  | obtaining a copy of this software and associated documentation | ||||||
|  | files (the "Software"), to deal in the Software without | ||||||
|  | restriction, including without limitation the rights to use, | ||||||
|  | copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the | ||||||
|  | Software is furnished to do so, subject to the following | ||||||
|  | conditions: | ||||||
|  | 
 | ||||||
|  | The above copyright notice and this permission notice shall be | ||||||
|  | included in all copies or substantial portions of the Software. | ||||||
|  | 
 | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||||||
|  | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|  | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||||||
|  | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||||
|  | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||||
|  | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||||
|  | OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  | ]] | ||||||
|  | 
 | ||||||
|  | local _ENV = mkmodule('dumper') | ||||||
|  | 
 | ||||||
|  | local dumplua_closure = [[ | ||||||
|  | local closures = {} | ||||||
|  | local function closure(t)  | ||||||
|  |   closures[#closures+1] = t | ||||||
|  |   t[1] = assert(loadstring(t[1])) | ||||||
|  |   return t[1] | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | for _,t in pairs(closures) do | ||||||
|  |   for i = 2,#t do  | ||||||
|  |     debug.setupvalue(t[1], i-1, t[i])  | ||||||
|  |   end  | ||||||
|  | end | ||||||
|  | ]] | ||||||
|  | 
 | ||||||
|  | local lua_reserved_keywords = { | ||||||
|  |   'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for',  | ||||||
|  |   'function', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',  | ||||||
|  |   'return', 'then', 'true', 'until', 'while' } | ||||||
|  | 
 | ||||||
|  | local function keys(t) | ||||||
|  |   local res = {} | ||||||
|  |   local oktypes = { stringstring = true, numbernumber = true } | ||||||
|  |   local function cmpfct(a,b) | ||||||
|  |     if oktypes[type(a)..type(b)] then | ||||||
|  |       return a < b | ||||||
|  |     else | ||||||
|  |       return type(a) < type(b) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  |   for k in pairs(t) do | ||||||
|  |     res[#res+1] = k | ||||||
|  |   end | ||||||
|  |   table.sort(res, cmpfct) | ||||||
|  |   return res | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local c_functions = {} | ||||||
|  | for _,lib in pairs{'_G', 'string', 'table', 'math',  | ||||||
|  |     'io', 'os', 'coroutine', 'package', 'debug'} do | ||||||
|  |   local t = _G[lib] or {} | ||||||
|  |   lib = lib .. "." | ||||||
|  |   if lib == "_G." then lib = "" end | ||||||
|  |   for k,v in pairs(t) do | ||||||
|  |     if type(v) == 'function' and not pcall(string.dump, v) then | ||||||
|  |       c_functions[v] = lib..k | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | function DataDumper(value, varname, fastmode, ident, indent_step) | ||||||
|  |   indent_step = indent_step or 2 | ||||||
|  |   local defined, dumplua = {} | ||||||
|  |   -- Local variables for speed optimization | ||||||
|  |   local string_format, type, string_dump, string_rep =  | ||||||
|  |         string.format, type, string.dump, string.rep | ||||||
|  |   local tostring, pairs, table_concat =  | ||||||
|  |         tostring, pairs, table.concat | ||||||
|  |   local keycache, strvalcache, out, closure_cnt = {}, {}, {}, 0 | ||||||
|  |   setmetatable(strvalcache, {__index = function(t,value) | ||||||
|  |     local res = string_format('%q', value) | ||||||
|  |     t[value] = res | ||||||
|  |     return res | ||||||
|  |   end}) | ||||||
|  |   local fcts = { | ||||||
|  |     string = function(value) return strvalcache[value] end, | ||||||
|  |     number = function(value) return value end, | ||||||
|  |     boolean = function(value) return tostring(value) end, | ||||||
|  |     ['nil'] = function(value) return 'nil' end, | ||||||
|  |     ['function'] = function(value)  | ||||||
|  |       return string_format("loadstring(%q)", string_dump(value))  | ||||||
|  |     end, | ||||||
|  |     userdata = function() error("Cannot dump userdata") end, | ||||||
|  |     thread = function() error("Cannot dump threads") end, | ||||||
|  |   } | ||||||
|  |   local function test_defined(value, path) | ||||||
|  |     if defined[value] then | ||||||
|  |       if path:match("^getmetatable.*%)$") then | ||||||
|  |         out[#out+1] = string_format("s%s, %s)\n", path:sub(2,-2), defined[value]) | ||||||
|  |       else | ||||||
|  |         out[#out+1] = path .. " = " .. defined[value] .. "\n" | ||||||
|  |       end | ||||||
|  |       return true | ||||||
|  |     end | ||||||
|  |     defined[value] = path | ||||||
|  |   end | ||||||
|  |   local function make_key(t, key) | ||||||
|  |     local s | ||||||
|  |     if type(key) == 'string' and key:match('^[_%a][_%w]*$') then | ||||||
|  |       s = key .. "=" | ||||||
|  |     else | ||||||
|  |       s = "[" .. dumplua(key, 0) .. "]=" | ||||||
|  |     end | ||||||
|  |     t[key] = s | ||||||
|  |     return s | ||||||
|  |   end | ||||||
|  |   for _,k in ipairs(lua_reserved_keywords) do | ||||||
|  |     keycache[k] = '["'..k..'"] = ' | ||||||
|  |   end | ||||||
|  |   if fastmode then  | ||||||
|  |     fcts.table = function (value) | ||||||
|  |       -- Table value | ||||||
|  |       local numidx = 1 | ||||||
|  |       out[#out+1] = "{" | ||||||
|  |       for key,val in pairs(value) do | ||||||
|  |         if key == numidx then | ||||||
|  |           numidx = numidx + 1 | ||||||
|  |         else | ||||||
|  |           out[#out+1] = keycache[key] | ||||||
|  |         end | ||||||
|  |         local str = dumplua(val) | ||||||
|  |         out[#out+1] = str.."," | ||||||
|  |       end | ||||||
|  |       if string.sub(out[#out], -1) == "," then | ||||||
|  |         out[#out] = string.sub(out[#out], 1, -2); | ||||||
|  |       end | ||||||
|  |       out[#out+1] = "}" | ||||||
|  |       return ""  | ||||||
|  |     end | ||||||
|  |   else  | ||||||
|  |     fcts.table = function (value, ident, path) | ||||||
|  |       if test_defined(value, path) then return "nil" end | ||||||
|  |       -- Table value | ||||||
|  |       local sep, str, numidx, totallen = " ", {}, 1, 0 | ||||||
|  |       local meta, metastr = (debug or getfenv()).getmetatable(value) | ||||||
|  |       if meta then | ||||||
|  |         ident = ident + 1 | ||||||
|  |         metastr = dumplua(meta, ident, "getmetatable("..path..")") | ||||||
|  |         totallen = totallen + #metastr + 16 | ||||||
|  |       end | ||||||
|  |       for _,key in pairs(keys(value)) do | ||||||
|  |         local val = value[key] | ||||||
|  |         local s = "" | ||||||
|  |         local subpath = path | ||||||
|  |         if key == numidx then | ||||||
|  |           subpath = subpath .. "[" .. numidx .. "]" | ||||||
|  |           numidx = numidx + 1 | ||||||
|  |         else | ||||||
|  |           s = keycache[key] | ||||||
|  |           if not s:match "^%[" then subpath = subpath .. "." end | ||||||
|  |           subpath = subpath .. s:gsub("%s*=%s*$","") | ||||||
|  |         end | ||||||
|  |         s = s .. dumplua(val, ident+1, subpath) | ||||||
|  |         str[#str+1] = s | ||||||
|  |         totallen = totallen + #s + 2 | ||||||
|  |       end | ||||||
|  |       if totallen > 80 then | ||||||
|  |         sep = "\n" .. string_rep(' ', indent_step*(ident+1)) | ||||||
|  |       end | ||||||
|  |       str = "{"..sep..table_concat(str, ","..sep).." "..sep:sub(1,-1-indent_step).."}"  | ||||||
|  |       if meta then | ||||||
|  |         sep = sep:sub(1,-3) | ||||||
|  |         return "setmetatable("..sep..str..","..sep..metastr..sep:sub(1,-3)..")" | ||||||
|  |       end | ||||||
|  |       return str | ||||||
|  |     end | ||||||
|  |     fcts['function'] = function (value, ident, path) | ||||||
|  |       if test_defined(value, path) then return "nil" end | ||||||
|  |       if c_functions[value] then | ||||||
|  |         return c_functions[value] | ||||||
|  |       elseif debug == nil or debug.getupvalue(value, 1) == nil then | ||||||
|  |         return string_format("loadstring(%q)", string_dump(value)) | ||||||
|  |       end | ||||||
|  |       closure_cnt = closure_cnt + 1 | ||||||
|  |       local res = {string.dump(value)} | ||||||
|  |       for i = 1,math.huge do | ||||||
|  |         local name, v = debug.getupvalue(value,i) | ||||||
|  |         if name == nil then break end | ||||||
|  |         res[i+1] = v | ||||||
|  |       end | ||||||
|  |       return "closure " .. dumplua(res, ident, "closures["..closure_cnt.."]") | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  |   function dumplua(value, ident, path) | ||||||
|  |     return fcts[type(value)](value, ident, path) | ||||||
|  |   end | ||||||
|  |   if varname == nil then | ||||||
|  |     varname = "return " | ||||||
|  |   elseif varname:match("^[%a_][%w_]*$") then | ||||||
|  |     varname = varname .. " = " | ||||||
|  |   end | ||||||
|  |   if fastmode then | ||||||
|  |     setmetatable(keycache, {__index = make_key }) | ||||||
|  |     out[1] = varname | ||||||
|  |     table.insert(out,dumplua(value, 0)) | ||||||
|  |     return table.concat(out) | ||||||
|  |   else | ||||||
|  |     setmetatable(keycache, {__index = make_key }) | ||||||
|  |     local items = {} | ||||||
|  |     for i=1,10 do items[i] = '' end | ||||||
|  |     items[3] = dumplua(value, ident or 0, "t") | ||||||
|  |     if closure_cnt > 0 then | ||||||
|  |       items[1], items[6] = dumplua_closure:match("(.*\n)\n(.*)") | ||||||
|  |       out[#out+1] = "" | ||||||
|  |     end | ||||||
|  |     if #out > 0 then | ||||||
|  |       items[2], items[4] = "local t = ", "\n" | ||||||
|  |       items[5] = table.concat(out) | ||||||
|  |       items[7] = varname .. "t" | ||||||
|  |     else | ||||||
|  |       items[2] = varname | ||||||
|  |     end | ||||||
|  |     return table.concat(items) | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | return _ENV | ||||||
| @ -0,0 +1,96 @@ | |||||||
|  | -- List input items for the building currently being built. | ||||||
|  | 
 | ||||||
|  | local dumper = require 'dumper' | ||||||
|  | 
 | ||||||
|  | local function copy_flags(tgt,src,name) | ||||||
|  |     local val = src[name] | ||||||
|  |     if val.whole == 0 then | ||||||
|  |         return | ||||||
|  |     end | ||||||
|  |     local out = {} | ||||||
|  |     tgt[name] = out | ||||||
|  |     for k,v in pairs(val) do | ||||||
|  |         if v then | ||||||
|  |             out[k] = v | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local function copy_value(tgt,src,name,defval) | ||||||
|  |     if src[name] ~= defval then | ||||||
|  |         tgt[name] = src[name] | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | local function copy_enum(tgt,src,name,defval,ename,enum) | ||||||
|  |     if src[name] ~= defval then | ||||||
|  |         tgt[name] = ename..'.'..enum[src[name]] | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local lookup = {} | ||||||
|  | 
 | ||||||
|  | for i=df.job_item_vector_id._first_item,df.job_item_vector_id._last_item do | ||||||
|  |     local id = df.job_item_vector_id.attrs[i].other | ||||||
|  |     local ptr | ||||||
|  |     if id == df.items_other_id.ANY then | ||||||
|  |         ptr = df.global.world.items.all | ||||||
|  |     elseif id == df.items_other_id.BAD then | ||||||
|  |         ptr = df.global.world.items.bad | ||||||
|  |     else | ||||||
|  |         ptr = df.global.world.items.other[id] | ||||||
|  |     end | ||||||
|  |     if ptr then | ||||||
|  |         local _,addr = df.sizeof(ptr) | ||||||
|  |         lookup[addr] = 'df.job_item_vector_id.'..df.job_item_vector_id[i] | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local function clone_filter(src,quantity) | ||||||
|  |     local tgt = {} | ||||||
|  |     src.flags2.allow_artifact = false | ||||||
|  |     if quantity ~= 1 then | ||||||
|  |         tgt.quantity = quantity | ||||||
|  |     end | ||||||
|  |     copy_enum(tgt, src, 'item_type', -1, 'df.item_type', df.item_type) | ||||||
|  |     copy_value(tgt, src, 'item_subtype', -1) | ||||||
|  |     copy_value(tgt, src, 'mat_type', -1) | ||||||
|  |     copy_value(tgt, src, 'mat_index', -1) | ||||||
|  |     copy_flags(tgt, src, 'flags1') | ||||||
|  |     copy_flags(tgt, src, 'flags2') | ||||||
|  |     copy_flags(tgt, src, 'flags3') | ||||||
|  |     copy_value(tgt, src, 'reaction_class', '') | ||||||
|  |     copy_value(tgt, src, 'has_material_reaction_product', '') | ||||||
|  |     copy_value(tgt, src, 'metal_ore', -1) | ||||||
|  |     copy_value(tgt, src, 'min_dimension', -1) | ||||||
|  |     copy_enum(tgt, src, 'has_tool_use', -1, 'df.tool_uses', df.tool_uses) | ||||||
|  |     local ptr = src.item_vector | ||||||
|  |     if ptr and ptr ~= df.global.world.items.other[0] then | ||||||
|  |         local _,addr = df.sizeof(ptr) | ||||||
|  |         tgt.vector_id = lookup[addr] | ||||||
|  |     end | ||||||
|  |     return tgt | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local function dump(name) | ||||||
|  |     local out = {} | ||||||
|  |     for i,v in ipairs(df.global.ui_build_selector.requirements) do | ||||||
|  |         out[#out+1] = clone_filter(v.filter, v.count_required) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     local fmt = dumper.DataDumper(out,name,false,1,4) | ||||||
|  |     local out = string.gsub(fmt, '"', '') | ||||||
|  |     print(out) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local itype = df.global.ui_build_selector.building_type | ||||||
|  | local stype = df.global.ui_build_selector.building_subtype | ||||||
|  | 
 | ||||||
|  | if itype == df.building_type.Workshop then | ||||||
|  |     dump('    [df.workshop_type.'..df.workshop_type[stype]..'] = ') | ||||||
|  | elseif itype == df.building_type.Furnace then | ||||||
|  |     dump('    [df.furnace_type.'..df.furnace_type[stype]..'] = ') | ||||||
|  | elseif itype == df.building_type.Trap then | ||||||
|  |     dump('    [df.trap_type.'..df.trap_type[stype]..'] = ') | ||||||
|  | else | ||||||
|  |     dump('    [df.building_type.'..df.building_type[itype]..'] = ') | ||||||
|  | end | ||||||
| @ -0,0 +1,125 @@ | |||||||
|  | -- Verify item occupancy and block item list integrity. | ||||||
|  | -- | ||||||
|  | -- Checks: | ||||||
|  | -- 1) Item has flags.on_ground <=> it is in the correct block item list | ||||||
|  | -- 2) A tile has items in block item list <=> it has occupancy.item | ||||||
|  | -- 3) The block item lists are sorted. | ||||||
|  | 
 | ||||||
|  | local utils = require 'utils' | ||||||
|  | 
 | ||||||
|  | function check_block_items(fix) | ||||||
|  |     local cnt = 0 | ||||||
|  |     local icnt = 0 | ||||||
|  |     local found = {} | ||||||
|  |     local found_somewhere = {} | ||||||
|  | 
 | ||||||
|  |     local should_fix = false | ||||||
|  |     local can_fix = true | ||||||
|  | 
 | ||||||
|  |     for _,block in ipairs(df.global.world.map.map_blocks) do | ||||||
|  |         local itable = {} | ||||||
|  |         local bx,by,bz = pos2xyz(block.map_pos) | ||||||
|  | 
 | ||||||
|  |         -- Scan the block item vector | ||||||
|  |         local last_id = nil | ||||||
|  |         local resort = false | ||||||
|  | 
 | ||||||
|  |         for _,id in ipairs(block.items) do | ||||||
|  |             local item = df.item.find(id) | ||||||
|  |             local ix,iy,iz = pos2xyz(item.pos) | ||||||
|  |             local dx,dy,dz = ix-bx,iy-by,iz-bz | ||||||
|  | 
 | ||||||
|  |             -- Check sorted order | ||||||
|  |             if last_id and last_id >= id then | ||||||
|  |                 print(bx,by,bz,last_id,id,'block items not sorted') | ||||||
|  |                 resort = true | ||||||
|  |             else | ||||||
|  |                 last_id = id | ||||||
|  |             end | ||||||
|  | 
 | ||||||
|  |             -- Check valid coordinates and flags | ||||||
|  |             if not item.flags.on_ground then | ||||||
|  |                 print(bx,by,bz,id,dx,dy,'in block & not on ground') | ||||||
|  |             elseif dx < 0 or dx >= 16 or dy < 0 or dy >= 16 or dz ~= 0 then | ||||||
|  |                 found_somewhere[id] = true | ||||||
|  |                 print(bx,by,bz,id,dx,dy,dz,'invalid pos') | ||||||
|  |                 can_fix = false | ||||||
|  |             else | ||||||
|  |                 found[id] = true | ||||||
|  |                 itable[dx + dy*16] = true; | ||||||
|  | 
 | ||||||
|  |                 -- Check missing occupancy | ||||||
|  |                 if not block.occupancy[dx][dy].item then | ||||||
|  |                     print(bx,by,bz,dx,dy,'item & not occupied') | ||||||
|  |                     if fix then | ||||||
|  |                         block.occupancy[dx][dy].item = true | ||||||
|  |                     else | ||||||
|  |                         should_fix = true | ||||||
|  |                     end | ||||||
|  |                 end | ||||||
|  |             end | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         -- Sort the vector if needed | ||||||
|  |         if resort then | ||||||
|  |             if fix then | ||||||
|  |                 utils.sort_vector(block.items) | ||||||
|  |             else | ||||||
|  |                 should_fix = true | ||||||
|  |             end | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         icnt = icnt + #block.items | ||||||
|  | 
 | ||||||
|  |         -- Scan occupancy for spurious marks | ||||||
|  |         for x=0,15 do | ||||||
|  |             local ocx = block.occupancy[x] | ||||||
|  |             for y=0,15 do | ||||||
|  |                 if ocx[y].item and not itable[x + y*16] then | ||||||
|  |                     print(bx,by,bz,x,y,'occupied & no item') | ||||||
|  |                     if fix then | ||||||
|  |                         ocx[y].item = false | ||||||
|  |                     else | ||||||
|  |                         should_fix = true | ||||||
|  |                     end | ||||||
|  |                 end | ||||||
|  |             end | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         cnt = cnt + 256 | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     -- Check if any items are missing from blocks | ||||||
|  |     for _,item in ipairs(df.global.world.items.all) do | ||||||
|  |         if item.flags.on_ground and not found[item.id] then | ||||||
|  |             can_fix = false | ||||||
|  |             if not found_somewhere[item.id] then | ||||||
|  |                 print(id,item.pos.x,item.pos.y,item.pos.z,'on ground & not in block') | ||||||
|  |             end | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     -- Report | ||||||
|  |     print(cnt.." tiles and "..icnt.." items checked.") | ||||||
|  | 
 | ||||||
|  |     if should_fix and can_fix then | ||||||
|  |         print("Use 'fix/item-occupancy --fix' to fix the listed problems.") | ||||||
|  |     elseif should_fix then | ||||||
|  |         print("The problems are too severe to be fixed by this script.") | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local opt = ... | ||||||
|  | local fix = false | ||||||
|  | 
 | ||||||
|  | if opt then | ||||||
|  |     if opt == '--fix' then | ||||||
|  |         fix = true | ||||||
|  |     else | ||||||
|  |         dfhack.printerr('Invalid option: '..opt) | ||||||
|  |         return | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | print("Checking item occupancy - this will take a few seconds.") | ||||||
|  | check_block_items(fix) | ||||||
		Loading…
	
		Reference in New Issue