techage_modpack/techage/basis/numbers_sqlite.lua
2020-10-25 21:32:47 +01:00

143 lines
3.4 KiB
Lua

--[[
TechAge
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Storage backend for node number mapping via sqlite database
]]--
-- for lazy programmers
local M = minetest.get_meta
local storage = techage.storage
-------------------------------------------------------------------
-- Database
-------------------------------------------------------------------
local MN = minetest.get_current_modname()
local WP = minetest.get_worldpath()
local MAR_MAGIC = 0x8e
if not techage.IE then
error("Please add 'secure.trusted_mods = techage' to minetest.conf!")
end
local sqlite3 = techage.IE.require("lsqlite3")
local marshal = techage.IE.require("marshal")
if not sqlite3 then
error("Please install sqlite3 via 'luarocks install lsqlite3'")
end
if not marshal then
error("Please install marshal via 'luarocks install lua-marshal'")
end
local db = sqlite3.open(WP.."/techage_numbers.sqlite")
local ROW = sqlite3.ROW
-- Prevent use of this db instance.
if sqlite3 then sqlite3 = nil end
db:exec[[
CREATE TABLE numbers(id INTEGER PRIMARY KEY, number INTEGER, x INTEGER, y INTEGER, z INTEGER);
CREATE UNIQUE INDEX idx ON numbers(number);
]]
local set = db:prepare("INSERT or REPLACE INTO numbers VALUES(NULL, ?, ?, ?, ?);")
local get = db:prepare("SELECT * FROM numbers WHERE number=?;")
local function set_block(number, pos)
set:reset()
set:bind(1, number)
set:bind(2, pos.x)
set:bind(3, pos.y)
set:bind(4, pos.z)
set:step()
return true
end
local function get_block(number)
get:reset()
get:bind(1, number)
if get:step() == ROW then
return {x = get:get_value(2), y = get:get_value(3), z = get:get_value(4)}
end
end
local function del_block(number)
db:exec("DELETE FROM numbers WHERE number="..number..";")
end
-------------------------------------------------------------------
-- Migration from mod storage
-------------------------------------------------------------------
local Version = storage:get_int("Version") or 0
local NextNumber = 0
if Version == 0 then
Version = 4
end
if Version == 3 then
Version = 4
NextNumber = storage:get_int("NextNumber")
for i = 1, NextNumber do
local number = tostring(i)
if storage:contains(number) then
local pos = minetest.string_to_pos(storage:get_string(number))
set_block(number, pos)
storage:set_string(number, "")
end
end
elseif Version == 4 then
NextNumber = storage:get_int("NextNumber")
else
error("[] Invalid version number for 'number to pos mapping' table!")
end
-------------------------------------------------------------------
-- API functions
-------------------------------------------------------------------
local api = {}
function api.get_nodepos(number)
return get_block(number)
end
function api.set_nodepos(number, pos)
set_block(number, pos)
end
function api.add_nodepos(pos)
local num = tostring(NextNumber)
NextNumber = NextNumber + 1
storage:set_int("NextNumber", NextNumber)
set_block(num, pos)
return num
end
function api.del_nodepos(number)
del_block(number)
end
-- delete invalid entries
function api.delete_invalid_entries(node_def)
minetest.log("info", "[TechAge] Data maintenance started")
for id, num, x, y, z in db:urows('SELECT * FROM numbers') do
local pos = {x = x, y = y, z = z}
local name = techage.get_node_lvm(pos).name
if not node_def[name] then
del_block(num)
end
end
minetest.log("info", "[TechAge] Data maintenance finished")
end
return api