Skip to content

Commit d642c31

Browse files
advtrains compat (#6)
* advtrains compat * save / load * log advtrains data loading * advtrains autosave * save behavior * ts compare * cleanup * cleanup * various fixes --------- Co-authored-by: BuckarooBanzay <BuckarooBanzay@users.noreply.github.com>
1 parent 8dbf737 commit d642c31

File tree

8 files changed

+133
-80
lines changed

8 files changed

+133
-80
lines changed

.luacheckrc

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ globals = {
44
"mapsync",
55
"worldedit",
66
"minetest",
7-
"travelnet"
7+
-- mods
8+
"travelnet",
9+
"advtrains",
10+
"serialize_lib"
811
}
912

1013
read_globals = {

data.lua

+14-3
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,27 @@ function mapsync.load_data(key)
3131
return value
3232
end
3333

34+
-- returns the path of the data file, nil if not available
35+
function mapsync.get_data_file_path(key)
36+
local data_backend_def = mapsync.get_data_backend()
37+
if not data_backend_def then
38+
-- no data backend defined
39+
return
40+
end
41+
42+
return data_backend_def.path .. "/" .. key
43+
end
44+
3445
-- returns a file to write to in the data-storage, nil if not available
3546
function mapsync.get_data_file(key, mode)
3647
-- default to read
3748
mode = mode or "r"
3849

39-
local data_backend_def = mapsync.get_data_backend()
40-
if not data_backend_def then
50+
local path = mapsync.get_data_file_path(key)
51+
if not path then
4152
-- no data backend defined
4253
return
4354
end
4455

45-
return global_env.io.open(data_backend_def.path .. "/" .. key, mode)
56+
return global_env.io.open(path, mode)
4657
end

functions.lua

-44
Original file line numberDiff line numberDiff line change
@@ -156,47 +156,3 @@ end
156156
function mapsync.get_chunk_zip_path(prefix, chunk_pos)
157157
return prefix .. "/chunk_" .. minetest.pos_to_string(chunk_pos) .. ".zip"
158158
end
159-
160-
-- https://gist.github.com/SafeteeWoW/080e784e5ebfda42cad486c58e6d26e4
161-
-- license: zlib
162-
163-
-- Calculate xor for two unsigned 8bit numbers (0 <= a,b <= 255)
164-
local function Xor8(a, b)
165-
local ret = 0
166-
local fact = 128
167-
while fact > a and fact > b do
168-
fact = fact / 2
169-
end
170-
while fact >= 1 do
171-
ret = ret + (((a >= fact or b >= fact)
172-
and (a < fact or b < fact)) and fact or 0)
173-
a = a - ((a >= fact) and fact or 0)
174-
b = b - ((b >= fact) and fact or 0)
175-
fact = fact / 2
176-
end
177-
return ret
178-
end
179-
180-
-- table to cache the result of uint8 xor(x, y) (0<=x,y<=255)
181-
local _xor8_table
182-
183-
local function GenerateXorTable()
184-
assert(not _xor8_table)
185-
_xor8_table = {}
186-
for i = 0, 255 do
187-
local t = {}
188-
_xor8_table[i] = t
189-
for j = 0, 255 do
190-
t[j] = Xor8(i, j)
191-
end
192-
end
193-
end
194-
195-
-- generate xor table on startup, it is only 256*256 bytes long and took about 8ms in the tests
196-
GenerateXorTable()
197-
198-
-- end of library copy
199-
200-
function mapsync.xor(a, b)
201-
return _xor8_table[a][b]
202-
end

functions.spec.lua

-9
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,3 @@ mtt.register("mapsync.deep_compare", function(callback)
5858

5959
callback()
6060
end)
61-
62-
mtt.register("mapsync.xor", function(callback)
63-
assert(mapsync.xor(0x00, 0x00) == 0x00)
64-
assert(mapsync.xor(0x01, 0x01) == 0x00)
65-
assert(mapsync.xor(0xFF, 0x01) == 0xFE)
66-
assert(mapsync.xor(0x55, 0xAA) == 0xFF)
67-
assert(mapsync.xor(0x01, 0x02) == 0x03)
68-
callback()
69-
end)

init.lua

+4
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ if minetest.get_modpath("travelnet") then
6060
dofile(MP.."/integrations/travelnet.lua")
6161
end
6262

63+
if minetest.get_modpath("advtrains") then
64+
dofile(MP.."/integrations/advtrains.lua")
65+
end
66+
6367
-- testing
6468
if minetest.get_modpath("mtt") and mtt.enabled then
6569
dofile(MP.."/init.spec.lua")

integrations/advtrains.lua

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
-- advtrains compat
2+
-- saves a snapshot of the advtrains-data with the `/mapsync_save_advtrains` command
3+
-- loads the snapshot if available on startup, defaults to the worldfolder if no snapshot found
4+
5+
-- sanity checks
6+
assert(type(advtrains.load_version_4) == "function")
7+
assert(type(advtrains.ndb.save_callback) == "function")
8+
assert(type(advtrains.ndb.load_callback) == "function")
9+
assert(type(advtrains.read_component) == "function")
10+
assert(type(advtrains.save_component) == "function")
11+
assert(type(advtrains.save) == "function")
12+
assert(type(serialize_lib.load_atomic) == "function")
13+
assert(type(serialize_lib.save_atomic_multiple) == "function")
14+
assert(type(advtrains.fpath) == "string")
15+
16+
-- local old_advtrains_read_component = advtrains.read_component
17+
function advtrains.read_component(name)
18+
assert(name == "version")
19+
-- currently supported version
20+
return 4
21+
end
22+
23+
-- local old_advtrains_save_component = advtrains.save_component
24+
function advtrains.save_component()
25+
-- no-op
26+
end
27+
28+
-- load from data- or world-path
29+
local old_load_atomic = serialize_lib.load_atomic
30+
function serialize_lib.load_atomic(filename, load_callback)
31+
local relpath = string.sub(filename, #advtrains.fpath + 2)
32+
local timestamp_storage_key = "advtrains_timestamp_" .. relpath
33+
34+
-- check world- and snapshot-timestamp
35+
local snapshot_timestamp = mapsync.load_data("advtrains_timestamp") or 0
36+
local world_timestamp = mapsync.storage:get_int(timestamp_storage_key)
37+
-- snapshot exists and has a different timestamp
38+
local load_snapshot = snapshot_timestamp ~= world_timestamp
39+
40+
local data_file = mapsync.get_data_file("advtrains_" .. relpath)
41+
if data_file and load_snapshot then
42+
-- apply snapshot timestamp to world
43+
mapsync.storage:set_int(timestamp_storage_key, snapshot_timestamp)
44+
-- data-snapshot available, load it
45+
local data_path = mapsync.get_data_file_path("advtrains_" .. relpath)
46+
minetest.log("action", "[mapsync] loading advtrains data from '" .. data_path ..
47+
"' snapshot_timestamp: " .. snapshot_timestamp ..
48+
" world_timestamp: " .. world_timestamp)
49+
return old_load_atomic(data_path, load_callback)
50+
else
51+
-- no data snapshot available, load default from world-folder
52+
return old_load_atomic(filename, load_callback)
53+
end
54+
end
55+
56+
local advtrains_parts = {"atlatc.ls", "interlocking.ls", "core.ls", "lines.ls", "ndb4.ls"}
57+
58+
local function copy_advtrains_files()
59+
if not mapsync.get_data_backend() then
60+
return false, "no data-backend configured"
61+
end
62+
63+
-- copy files to data-directory
64+
local count = 0
65+
for _, part in ipairs(advtrains_parts) do
66+
local path = advtrains.fpath .. "_" .. part
67+
local src = io.open(path, "rb")
68+
if not src then
69+
return false, "open failed for '" .. path .. "'"
70+
end
71+
72+
local dst = mapsync.get_data_file("advtrains_" .. part, "wb")
73+
local data = src:read("*all")
74+
count = count + #data
75+
dst:write(data)
76+
dst:close()
77+
src:close()
78+
end
79+
-- write timestamp
80+
mapsync.save_data("advtrains_timestamp", os.time())
81+
82+
minetest.log("action", "[mapsync] saved " .. count .. " bytes of advtrains data")
83+
return count
84+
end
85+
86+
local old_advtrains_save = advtrains.save
87+
function advtrains.save(remove_players_from_wagons)
88+
-- save advtrains state
89+
old_advtrains_save(remove_players_from_wagons)
90+
91+
if mapsync.autosave then
92+
-- save to data-directory
93+
copy_advtrains_files()
94+
end
95+
end
96+
97+
minetest.register_chatcommand("mapsync_save_advtrains", {
98+
privs = { mapsync = true },
99+
func = function()
100+
-- save advtrains data first
101+
old_advtrains_save()
102+
103+
local count, err = copy_advtrains_files()
104+
if err then
105+
return false, err
106+
end
107+
108+
return true, "saved " .. count .. " bytes of advtrains data"
109+
end
110+
})

mod.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
name = mapsync
22
depends = mtzip
3-
optional_depends = worldedit, screwdriver2, mtt, travelnet
3+
optional_depends = worldedit, screwdriver2, mtt, travelnet, advtrains, serialize_lib

parse_chunk.lua

-22
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,6 @@ local global_env = ...
33
-- local vars for faster access
44
local insert, byte, decode_uint16 = table.insert, string.byte, mapsync.decode_uint16
55

6-
-- parses the key information of the chunk (if available)
7-
function mapsync.parse_chunk_key(filename)
8-
local f = global_env.io.open(filename, "rb")
9-
local zip, err_msg = mtzip.unzip(f)
10-
if not zip then
11-
return false, err_msg
12-
end
13-
14-
local key_entry = zip:get_entry("key.json")
15-
if not key_entry then
16-
-- no key found, unencrypted chunk
17-
return nil
18-
end
19-
20-
-- parse key info
21-
local key_str, m_err_msg = zip:get("key.json")
22-
if not key_str then
23-
return false, m_err_msg
24-
end
25-
return minetest.parse_json(key_str)
26-
end
27-
286
-- parses an exported chunk file
297
function mapsync.parse_chunk(filename)
308
local f = global_env.io.open(filename, "rb")

0 commit comments

Comments
 (0)