From 78488b6f39b069a518c301cab83a13c8013605a2 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sat, 12 Jan 2019 19:30:52 +0200 Subject: [PATCH] flatfile town saving --- chat.lua | 2 +- flatfile.lua | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++ init.lua | 1 + town.lua | 28 ++++++++---- 4 files changed, 140 insertions(+), 10 deletions(-) diff --git a/chat.lua b/chat.lua index c0a6b79..9d80eed 100644 --- a/chat.lua +++ b/chat.lua @@ -39,7 +39,7 @@ local function town_command (name, param) elseif param == "visualize" then towny.regions:visualize_town(town) return true - elseif param == "delete" or param == "abandon" then + elseif (param == "delete" or param == "abandon") or (pr1 == "delete" or pr1 == "abandon") then if towny.chat['delete_verify_' .. name] and pr2 == "I WANT TO DELETE MY TOWN" then towny.chat['delete_verify_' .. name] = nil return towny:delete_town(nil, name) diff --git a/flatfile.lua b/flatfile.lua index e69de29..4397ecc 100644 --- a/flatfile.lua +++ b/flatfile.lua @@ -0,0 +1,119 @@ + +function towny.flatfile:write_meta(town,dir,data) + local world = minetest.get_worldpath() + local directory = world.."/towny/"..dir + local filepath = town..".json" + minetest.mkdir(directory) + + if data.dirty then data.dirty = nil end + + local serialized = minetest.serialize(data) + if not serialized then return end + + minetest.safe_file_write(directory.."/"..filepath, serialized) +end + +function towny.flatfile:load_meta(filepath) + local file = io.open(filepath) + + if not file then + return nil + end + + local str = "" + for line in file:lines() do + str = str..line + end + + file:close() + return minetest.deserialize(str) +end + +function towny.flatfile:save_town_meta(town) + if not towny.towns[town] then return end + local tmeta = towny.towns[town] + if tmeta.dirty then + minetest.after(0.1, function () + towny.flatfile:write_meta(town,"meta",tmeta) + tmeta.dirty = false + end) + end + + if not towny.regions.memloaded[town] then return end + local rmeta = towny.regions.memloaded[town] + if rmeta.dirty then + minetest.after(0.2, function () + towny.flatfile:write_meta(town,"region",rmeta) + rmeta.dirty = false + end) + end +end + +local ldirs = { "meta", "region" } +function towny.flatfile:load_all_towns() + local world = minetest.get_worldpath() + local metadir = world.."/towny/"..ldirs[1] + minetest.mkdir(metadir) + + local metas = minetest.get_dir_list(metadir, false) + for _,file in pairs(metas) do + if file:match(".json$") then + local town = file:gsub(".json","") + minetest.after(0.1, function () + local towndata = towny.flatfile:load_meta(metadir.."/"..file) + if not towndata then return end + towny.towns[town] = towndata + end) + end + end + + local regiondir = world.."/towny/"..ldirs[2] + minetest.mkdir(regiondir) + + local regions = minetest.get_dir_list(regiondir, false) + for _,file in pairs(regions) do + if file:match(".json$") then + local town = file:gsub(".json","") + minetest.after(0.1, function () + local regiondata = towny.flatfile:load_meta(regiondir.."/"..file) + if not regiondata then return end + towny.regions.memloaded[town] = regiondata + end) + end + end +end + +function towny.flatfile:delete_all_meta(town) + local world = minetest.get_worldpath() + local file = town..".json" + + for _,d in pairs(ldirs) do + local dir = world.."/towny/"..d + local path = dir.."/"..file + minetest.after(0.1, os.remove, path) + end +end + +local clock = 0 +local function carrier_tick() + if not towny.dirty then return end + for town,data in pairs(towny.towns) do + if data.dirty then + towny.flatfile:save_town_meta(town) + end + end + towny.dirty = false +end + +-- Register +minetest.register_globalstep(function (dt) + clock = clock + ((1 * dt) + 1) + if clock >= 60 then + carrier_tick() + clock = 0 + end +end) + +minetest.after(0.1, function () + towny.flatfile:load_all_towns() +end) diff --git a/init.lua b/init.lua index a4203f1..ec24733 100644 --- a/init.lua +++ b/init.lua @@ -13,6 +13,7 @@ towny = { memloaded = {}, }, -- See "Town data structure" + flatfile = {}, towns = {}, chat = {}, diff --git a/town.lua b/town.lua index b306cf4..e6da5a0 100644 --- a/town.lua +++ b/town.lua @@ -34,6 +34,14 @@ function towny:get_town_by_name(name) return nil end +function towny:mark_dirty(town, areas) + towny.dirty = true + towny.towns[town].dirty = true + if areas and towny.regions.memloaded[town] then + towny.regions.memloaded[town].dirty = true + end +end + function towny:create_town(pos, player, name) local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then @@ -58,7 +66,7 @@ function towny:create_town(pos, player, name) -- New town information local p1 = vector.add(pos, {x=tr / 2,y=tr - 1,z=tr / 2}) local p2 = vector.subtract(pos, {x=tr / 2,y=1,z=tr / 2}) - local id = minetest.hash_node_position(pos) + local id = minetest.sha1(minetest.hash_node_position(pos)) local data = { name = name, mayor = player, @@ -82,7 +90,7 @@ function towny:create_town(pos, player, name) towny.towns[id] = data towny.regions.memloaded[id] = regions - towny.dirty = true + towny:mark_dirty(id, true) minetest.chat_send_player(player, "Your town has successfully been founded!") minetest.chat_send_all(player .. " has started a new town called '" .. name .. "'!") @@ -127,7 +135,7 @@ function towny:extend_town(pos,player) table.insert(towny.regions.memloaded[town].blocks, p1) data.flags["claim_blocks"] = data.flags["claim_blocks"] - 1 minetest.chat_send_player(player, "Successfully claimed this block!") - towny.dirty = true + towny:mark_dirty(town, true) towny.regions:visualize_radius(vector.subtract(p1, {x=tr/2,y=tr/2,z=tr/2})) return true @@ -162,7 +170,7 @@ function towny:abridge_town(pos,player) table.insert(towny.regions.memloaded[t].blocks, p1) data.flags["claim_blocks"] = data.flags["claim_blocks"] + 1 minetest.chat_send_player(player, "Successfully abandoned this claim block!") - towny.dirty = true + towny:mark_dirty(t, true) return true end @@ -209,7 +217,7 @@ function towny:leave_town(player) pdata.members = members end - towny.dirty = true + towny:mark_dirty(town, false) minetest.chat_send_player(player, "You successfully left the town.") return true end @@ -240,7 +248,7 @@ function towny:delete_town(pos,player) -- Wipe the town towny.towns[t] = nil towny.regions.memloaded[t] = nil - towny.dirty = true + towny.flatfile:delete_all_meta(t) minetest.chat_send_player(player, "Successfully deleted the town!") minetest.chat_send_all("The town '" .. name .. "' has fell into ruin.") @@ -271,7 +279,7 @@ function towny:delete_plot(pos,player) towny.regions:set_plot(c,t,nil) data.plots[p] = nil - towny.dirty = true + towny:mark_dirty(t, true) minetest.chat_send_player(player, "Successfully removed the plot.") return true @@ -302,7 +310,7 @@ function towny:create_plot(pos,player) return err_msg(player, "You do not have permission to create plots in this town.") end - local pid = minetest.hash_node_position(c) + local pid = minetest.sha1(minetest.hash_node_position(c)) local success,message = towny.regions:set_plot(c,t,pid) if not success then @@ -315,7 +323,7 @@ function towny:create_plot(pos,player) members = {[player] = {}}, flags = {}, } - towny.dirty = true + towny:mark_dirty(t, true) minetest.chat_send_player(player, "Successfully created a plot!") towny.regions:visualize_radius(vector.subtract(c, {x=tr/2,y=tr/2,z=tr/2})) @@ -352,6 +360,7 @@ function towny:set_plot_flags(pos,player,flag,value) if type(value) == "string" and minetest.string_to_pos(value) then value = minetest.string_to_pos(value) end + towny:mark_dirty(t, false) plot_data.flags[flag] = value end @@ -384,6 +393,7 @@ function towny:set_town_flags(pos,player,flag,value) if type(value) == "string" and minetest.string_to_pos(value) then value = minetest.string_to_pos(value) end + towny:mark_dirty(t, false) data.flags[flag] = value end