-
Notifications
You must be signed in to change notification settings - Fork 6
/
database_storage.lua
181 lines (153 loc) · 4.12 KB
/
database_storage.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
local sp = simple_protection
local store = minetest.get_mod_storage()
local version
local function json_read(key)
local list = store:get(key)
if not list then
return
end
list = minetest.parse_json(list)
if type(list) ~= "table" then
-- parse_json already prints the error -> give backtrace.
minetest.log("error", "Source: " .. key)
return
end
return list
end
local function json_write(key, value)
assert(type(value) == "table")
local str, msg = minetest.write_json(value)
if not str then
minetest.log("error", "Source: " .. key .. ": " .. (msg or "<nil>"))
return
end
store:set_string(key, str)
return true
end
function sp.load_db()
local world = minetest.get_worldpath()
local backend = Settings(world .. "/world.mt"):get("mod_storage_backend") or "files"
if backend == "files" then
minetest.log("warning", "[simple_protection] Ineffective mod storage is being used! " ..
"Please migrate the 'files' backend to a database like 'sqlite3'. Example: " ..
"minetest --server --worldname <NAME> --migrate-mod-storage sqlite3")
end
version = store:get_int("!_VERSION") -- 0 if not existing
assert(version < 1000, "Incompatible store format.")
if version == 0 then
version = 1
store:set_int("!_VERSION", version)
end
minetest.log("action", "[simple_protection] Loaded claim data (storage: " .. backend .. ")")
end
--===================-- Player data --===================--
function sp.get_player_data(player_name)
local pdata = json_read("P" .. player_name) or {}
pdata.shared = pdata.shared or {}
return pdata
end
function sp.set_player_data(player_name, pdata)
if not pdata then
-- Data removal
store:set_string("P" .. player_name, "")
return
end
json_write("P" .. player_name, pdata)
end
--===================-- Claim management --===================--
-- Speed up the function access
local get_location = sp.get_location
function sp.get_claim(pos, direct, z)
if not direct then
-- Get current grind position
pos = get_location(pos)
-- Convert position vector to database key
pos = "C"..pos.x..","..pos.y..","..pos.z
elseif z then
pos = "C"..pos..","..direct.. ","..z
end
-- type(pos) == number
local claim = json_read(pos)
if claim then
claim.shared = claim.shared or {}
end
return claim, pos
end
function sp.set_claim(data, index)
if not data then
-- Claim removal
store:set_string(index, "")
return
end
-- Update claim
json_write(index, data)
end
-- Internal function
function sp.claim_index_to_gridpos(index)
local x, y, z = index:match("^C([%d-]+),([%d-]+),([%d-]+)$")
return vector.new(
tonumber(x),
tonumber(y),
tonumber(z)
)
end
function sp.get_player_claims(owner)
-- This is rather inefficient
local count = 0
local claims = {}
local all = store:to_table()
for index in pairs(all.fields) do
local first = index:byte()
if first == 67 then -- "C"
local cdata = sp.get_claim(index, true)
if cdata.owner == owner then
claims[index] = cdata
count = count + 1
end
end
end
return claims, count
end
-- Bulk update
function sp.update_claims(updated)
for index, data in pairs(updated) do
sp.set_claim(data, index)
end
end
--===================-- Sharing system --===================--
function sp.is_shared(id, player_name)
if type(id) == "table" and id.shared then
-- Find shared information in ClaimData
return table.indexof(id.shared, player_name) > 0
end
-- Provided owner name -> find in globally shared data
assert(type(id) == "string", "is_shared(): Either ClaimData or string expected")
local list = json_read(id)
return table.indexof(list or {}, player_name) > 0
end
function sp.update_share_all(owner, modify)
local updated = 0
local pdata = sp.get_player_data(owner)
local list = pdata.shared -- by table reference
if modify == "erase" then
updated = #list
list = {}
modify = {}
end
for name, status in pairs(modify) do
local index = table.indexof(list, name)
if (index > 0) ~= status then
-- Mismatch -> update list
if status then
table.insert(list, name)
else
table.remove(list, index)
end
updated = updated + 1
end
end
if updated > 0 then
sp.set_player_data(owner, pdata)
end
return updated
end