diff --git a/.luacheckrc b/.luacheckrc index 875e259..20c67a1 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -10,6 +10,7 @@ read_globals = { "AreaStore", "default", "mesecon", + "utf8", table = { fields = { "copy", "getn", "indexof" } } } diff --git a/chatcommands.lua b/chatcommands.lua index 616c502..4f0d39b 100644 --- a/chatcommands.lua +++ b/chatcommands.lua @@ -1,5 +1,6 @@ local S = areas.S +local sub8 = utf8.sub local anticurse_exists = minetest.global_exists("chat_anticurse") minetest.register_chatcommand("protect", { @@ -22,6 +23,8 @@ minetest.register_chatcommand("protect", { end end + param = sub8(param, 1, areas.config.max_area_name_length) + minetest.log("action", "/protect invoked, owner="..name.. " AreaName="..param.. " StartPos="..minetest.pos_to_string(pos1).. @@ -112,6 +115,8 @@ minetest.register_chatcommand("add_owner", { end end + areaName = sub8(param, 1, areas.config.max_area_name_length) + minetest.log("action", name.." runs /add_owner. Owner = "..ownerName.. " AreaName = "..areaName.." ParentID = "..pid.. " StartPos = "..pos1.x..","..pos1.y..","..pos1.z.. @@ -125,7 +130,7 @@ minetest.register_chatcommand("add_owner", { end local id = areas:add(ownerName, areaName, pos1, pos2, pid) - areas.areas[id].name = areaName .. " " .. S("(by @1)", name) + areas.areas[id].prev_owner = name areas:save() minetest.chat_send_player(ownerName, @@ -161,7 +166,10 @@ minetest.register_chatcommand("rename_area", { end end + newName = sub8(newName, 1, areas.config.max_area_name_length) + areas.areas[id].name = newName + areas.areas[id].prev_owner = nil areas:save() return true, S("Area renamed.") end @@ -302,7 +310,7 @@ minetest.register_chatcommand("change_owner", { .." or is not owned by you.", id) end areas.areas[id].owner = newOwner - areas.areas[id].name = areas.areas[id].name .. " " .. S("(by @1)", name) + areas.areas[id].prev_owner = name areas:save() minetest.chat_send_player(newOwner, S("@1 has given you control over the area \"@2\" (ID @3).", diff --git a/hud.lua b/hud.lua index 442c5c9..817350c 100644 --- a/hud.lua +++ b/hud.lua @@ -6,10 +6,19 @@ areas.hud = {} local vround = vector.round local tconcat, tinsert = table.concat, table.insert +local sub8 = utf8.sub local creative_mode = minetest.settings:get_bool("creative_mode") +local function trim_area_name(name) + return sub8(name, 1, areas.config.max_area_name_length) +end + local function createAreaString(area, id) - local parts = {"🛡️ ", area.name, " [", id, "] (", area.owner, ")"} + local parts = {"🛡️ ", trim_area_name(area.name), " [", id, "] (", area.owner, ")"} + if area.prev_owner then + tinsert(parts, 3, " " .. S("(by @1)", area.prev_owner)) + end + if area.open then tinsert(parts, " [" .. S("Open") .. "]") end @@ -25,7 +34,7 @@ local function createAreaString(area, id) end end - return tconcat(parts):trim() + return tconcat(parts) end local function updateHud(player, name, pos) diff --git a/internal.lua b/internal.lua index 82d8a82..d6d50dc 100644 --- a/internal.lua +++ b/internal.lua @@ -9,7 +9,10 @@ end -- Save the areas table to a file function areas:save() - local datastr = minetest.write_json(self.areas, true) + -- HACK: Add the version code at the end so that areas can be downgraded + -- without issue, minetest.parse_json ignores extra data at the end of the + -- string. + local datastr = minetest.write_json(self.areas, true) .. "\nv2" if not datastr then minetest.log("error", "[areas] Failed to serialize area data!") return @@ -17,6 +20,38 @@ function areas:save() return minetest.safe_file_write(self.config.filename, datastr) end +local function migrate_by_strings(self) + local migrated = 0 + for _, area in pairs(self.areas) do + -- Search without a pattern (the "true" argument) as it is much faster + local position = area.name:find("\27(T@areas)", 1, true) + if position then + -- Parse the "(by )" suffix and store in the "prev_owner" field + if not area.prev_owner then + area.prev_owner = area.name:match("\27%(T@areas%)%(by \27F([A-Za-z0-9_%-]-)\27E%)\27E$") + end + + -- Remove the translation escape sequence from the area name + area.name = area.name:sub(1, position - 1):gsub(" $", "") + + migrated = migrated + 1 + end + + -- Remove broken by strings + position = area.name:find(" (by ", 1, true) + if position then + area.name = area.name:sub(1, position - 1) + end + end + + if migrated > 0 then + minetest.log("action", "[areas] Migrated " .. migrated .. + " \"(by )\" strings in area names") + + self:save() + end +end + -- Load the areas table from the save file function areas:load() local file, err = io.open(self.config.filename, "r") @@ -25,7 +60,12 @@ function areas:load() return err end local data = file:read("*a") + local need_migration = true if data:sub(1, 1) == "[" then + if data:sub(-3) == "\nv2" then + data = data:sub(1, -4) + need_migration = false + end self.areas, err = minetest.parse_json(data) else self.areas, err = minetest.deserialize(data) @@ -38,6 +78,9 @@ function areas:load() tostring(err)) end file:close() + if need_migration then + migrate_by_strings(self) + end self:populateStore() end diff --git a/settings.lua b/settings.lua index 01edc63..aaa6e2b 100644 --- a/settings.lua +++ b/settings.lua @@ -27,8 +27,9 @@ end -- Settings -- -------------- -setting("string", "filename", world_path.."/areas.dat") +setting("string", "filename", world_path.."/areas.dat") setting("boolean", "pvp_by_default", false) +setting("number", "max_area_name_length", 40) -- Allow players with a privilege create their own areas -- within the maximum size and number. diff --git a/settingtypes.txt b/settingtypes.txt index cbf9b6b..7873092 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -6,6 +6,9 @@ # Turn on PvP everywhere areas.pvp_by_default (PvP by default) bool false +# Maximum length of the area name +max_area_name_length (max area name length) int 40 + # Allow players with a privilege create their own areas using /protect # within the specified size and amount limits. areas.self_protection (Self protection) bool false