-
Notifications
You must be signed in to change notification settings - Fork 1
/
create_diff.lua
160 lines (131 loc) · 5.28 KB
/
create_diff.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
local c_air = minetest.get_content_id("air")
local function create_mapblock(mapblock_pos, mapblock, callback)
assert(#mapblock.node_ids == 4096)
assert(#mapblock.param2 == 4096)
for i=1,4096 do
local nodeid = mapblock.node_ids[i]
if nodeid ~= c_air then
-- relative position in the mapblock
local rel_pos = mapsync.mapblock_index_to_pos(i)
-- relative position in the chunk
local rel_chunk_pos = vector.add(rel_pos, vector.multiply(mapblock_pos, 16))
local nodename = minetest.get_name_from_content_id(nodeid)
local node = {
x=rel_chunk_pos.x,
y=rel_chunk_pos.y,
z=rel_chunk_pos.z,
name = nodename,
param2 = mapblock.param2[i]
}
if mapblock.metadata then
local rel_pos_str = minetest.pos_to_string(rel_pos)
if mapblock.metadata.meta then
node.meta = mapblock.metadata.meta[rel_pos_str]
end
if mapblock.metadata.meta then
node.timer = mapblock.metadata.timers[rel_pos_str]
end
end
callback(node)
end
end
end
local function air_mapblock(mapblock_pos, callback)
for i=1,4096 do
-- relative position in the mapblock
local rel_pos = mapsync.mapblock_index_to_pos(i)
-- relative position in the chunk
local rel_chunk_pos = vector.add(rel_pos, vector.multiply(mapblock_pos, 16))
local node = {
x=rel_chunk_pos.x,
y=rel_chunk_pos.y,
z=rel_chunk_pos.z,
name = "air",
param2 = 0
}
callback(node)
end
end
local function diff_mapblock(mapblock_pos, baseline_mapblock, mapblock, callback)
assert(#baseline_mapblock.node_ids == 4096)
assert(#baseline_mapblock.param2 == 4096)
assert(#mapblock.node_ids == 4096)
assert(#mapblock.param2 == 4096)
for i=1,4096 do
-- relative position in the mapblock
local rel_pos = mapsync.mapblock_index_to_pos(i)
-- relative position in the chunk
local rel_chunk_pos = vector.add(rel_pos, vector.multiply(mapblock_pos, 16))
local baseline_nodeid = baseline_mapblock.node_ids[i]
local new_nodeid = mapblock.node_ids[i]
local node = { x=rel_chunk_pos.x, y=rel_chunk_pos.y, z=rel_chunk_pos.z }
local changed = false
-- node id
if baseline_nodeid ~= new_nodeid then
local new_nodename = minetest.get_name_from_content_id(new_nodeid)
node.name = new_nodename
changed = true
end
-- param2
if baseline_mapblock.param2[i] ~= mapblock.param2[i] then
node.param2 = mapblock.param2[i]
changed = true
end
-- metadata
local rel_pos_str = minetest.pos_to_string(rel_pos)
local baseline_meta = baseline_mapblock.metadata
and baseline_mapblock.metadata.meta
and baseline_mapblock.metadata.meta[rel_pos_str]
local new_meta = mapblock.metadata
and mapblock.metadata.meta
and mapblock.metadata.meta[rel_pos_str]
if new_meta then
-- add empty inventory to baseline if not already there
if baseline_meta then
baseline_meta.inventory = baseline_meta.inventory or {}
end
if not mapsync.deep_compare(baseline_meta, new_meta) then
-- metadata not equal or new
node.meta = new_meta
changed = true
end
end
local timer = mapblock.metadata and mapblock.metadata.timers and mapblock.metadata.timers[rel_pos_str]
if timer then
node.timer = timer
end
if changed then
callback(node)
end
end
return true
end
function mapsync.create_diff(baseline_chunk, chunk_pos, callback)
local node_mapping = {}
local mb_pos1, mb_pos2 = mapsync.get_mapblock_bounds_from_chunk(chunk_pos)
for x=mb_pos1.x,mb_pos2.x do
for y=mb_pos1.y,mb_pos2.y do
for z=mb_pos1.z,mb_pos2.z do
local mapblock_pos = {x=x, y=y, z=z}
local rel_mapblock_pos = vector.subtract(mapblock_pos, mb_pos1)
local blockdata = mapsync.serialize_mapblock(mapblock_pos, node_mapping)
local baseline_mapblock = baseline_chunk and
baseline_chunk.mapblocks[minetest.pos_to_string(rel_mapblock_pos)]
if blockdata.empty and baseline_mapblock then
-- block removed
air_mapblock(rel_mapblock_pos, callback)
elseif not blockdata.empty and not baseline_mapblock then
-- block added
create_mapblock(rel_mapblock_pos, blockdata, callback)
elseif not blockdata.empty and baseline_mapblock then
-- both blocks exist, compare
local success, err_msg = diff_mapblock(rel_mapblock_pos,baseline_mapblock,blockdata,callback)
if not success then
return false, err_msg
end
end
end
end
end
return true
end