diff --git a/worldedit/serialization.lua b/worldedit/serialization.lua index 58c0001..57749fc 100644 --- a/worldedit/serialization.lua +++ b/worldedit/serialization.lua @@ -85,27 +85,27 @@ function worldedit.serialize(pos1, pos2) array[1] = first_value return {first_value} end - local function match_try(cache, value) + local function match_try(array, cache, value) local i = #cache while i >= 1 do if cache[i] == value then - return -(#cache - i + 1) + local ret = -(#cache - i + 1) + return ret, array[#array] == ret end i = i - 1 end - return nil + return nil, false end local function match_push(array, cache, match, value) - if match ~= nil then -- don't advance cache - array[#array + 1] = match - return + if match ~= nil then -- don't advance ringbuffer + return match end local idx = #cache + 1 cache[idx] = value if idx > MATCH_DIST then table.remove(cache, 1) end - array[#array + 1] = value + return value end -- Helper functions (2) local function cur_new(pos, pos1) @@ -119,15 +119,33 @@ function worldedit.serialize(pos1, pos2) } end local function cur_finish(result, cur) - if #cur.param1 == 1 and cur.param1[1] == 0 then + -- TODO: wouldn't be needed if param1, param2 supported omit (see below) + local i = #cur.param1 + while i > 1 and cur.param1[i] == -1 do + cur.param1[i] = nil + i = i - 1 + end + if i == 1 and cur.param1[1] == 0 then cur.param1 = nil end - if #cur.param2 == 1 and cur.param2[1] == 0 then + + i = #cur.param2 + while i > 1 and cur.param2[i] == -1 do + cur.param2[i] = nil + i = i - 1 + end + if i == 1 and cur.param2[1] == 0 then cur.param2 = nil end + -- Drop unneeded ref from data table (FIXME?) + i = #cur.data + if cur.data[i] == -1 then + cur.data[i] = nil + end + -- add to result table result[#result + 1] = cur end - --magic number: 24 + local OMIT_MIN_LIMIT = 18 -- Serialize stuff local pos = {} @@ -135,6 +153,7 @@ function worldedit.serialize(pos1, pos2) local result = {} local cur local cache_data, cache_param1, cache_param2 + local is_omit -- applies to data only pos[other1] = pos1[other1] while pos[other1] <= pos2[other1] do pos[other2] = pos1[other2] @@ -144,26 +163,65 @@ function worldedit.serialize(pos1, pos2) local node = get_node(pos) if node.name ~= "air" and node.name ~= "ignore" then - if cur == nil then -- Start a new row + local new_row = false + if cur == nil then + new_row = true + else -- See if we want to push to existing row + local next_c = cur.c + 1 + cur.c = next_c + local value, m, can_omit + + value = node.name + m, can_omit = match_try(cur.data, cache_data, node.name) + if is_omit and not can_omit then + -- we have omitted previous entries, but can't omit this one + if next_c - #cur.data > OMIT_MIN_LIMIT then + -- just starting a new row will take less space, do that + new_row = true + else + -- fill up omitted data and proceed as usual + local last = cur.data[#cur.data] + for i = #cur.data + 1, next_c - 1 do + cur.data[i] = last + end + cur.data[next_c] = match_push(cur.data, cache_data, m, value) + is_omit = false + end + elseif can_omit then + is_omit = true + else + cur.data[next_c] = match_push(cur.data, cache_data, m, value) + end + + -- TODO: implement omit for param1, param2 too + if not new_row then + value = node.param1 + m, can_omit = match_try(cur.param1, cache_param1, value) + cur.param1[next_c] = match_push(cur.param1, cache_param1, m, value) + + value = node.param2 + m, can_omit = match_try(cur.param2, cache_param2, value) + cur.param2[next_c] = match_push(cur.param2, cache_param2, m, value) + else -- Undo changes and finish row + cur.c = next_c - 1 + cur_finish(result, cur) + cur = nil + is_omit = false + end + end + + if new_row then -- Start a new row cur = cur_new(pos, pos1, axis, other1, other2) cache_data = match_init(cur.data, node.name) cache_param1 = match_init(cur.param1, node.param1) cache_param2 = match_init(cur.param2, node.param2) - else -- Push to existing row - local next_c = cur.c + 1 - cur.c = next_c - local v = node.name - match_push(cur.data, cache_data, match_try(cache_data, v), v) - v = node.param1 - match_push(cur.param1, cache_param1, match_try(cache_param1, v), v) - v = node.param2 - match_push(cur.param2, cache_param2, match_try(cache_param2, v), v) end count = count + 1 else if cur ~= nil then -- Finish row cur_finish(result, cur) cur = nil + is_omit = false end end pos[axis] = pos[axis] + 1 @@ -172,11 +230,13 @@ function worldedit.serialize(pos1, pos2) if cur ~= nil then -- Finish leftover row cur_finish(result, cur) cur = nil + is_omit = false end pos[other2] = pos[other2] + 1 end pos[other1] = pos[other1] + 1 end + -- Serialize entries result = minetest.serialize(result) return tonumber(worldedit.LATEST_SERIALIZATION_VERSION) .. "," ..