forked from DFHack/scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathitem-occupancy.lua
131 lines (109 loc) · 3.73 KB
/
item-occupancy.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
-- Verify item occupancy and block item list integrity.
--[====[
fix/item-occupancy
==================
Diagnoses and fixes issues with nonexistant 'items occupying site', usually
caused by `autodump` bugs or other hacking mishaps. Checks that:
#. Item has ``flags.on_ground`` <=> it is in the correct block item list
#. A tile has items in block item list <=> it has ``occupancy.item``
#. 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(item.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
qerror('Invalid option: '..opt)
end
end
print("Checking item occupancy - this will take a few seconds.")
check_block_items(fix)