diff options
Diffstat (limited to 'ch_core/data.lua')
-rw-r--r-- | ch_core/data.lua | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/ch_core/data.lua b/ch_core/data.lua new file mode 100644 index 0000000..84a6bcc --- /dev/null +++ b/ch_core/data.lua @@ -0,0 +1,385 @@ +ch_core.open_submod("data") + +-- POZICE A OBLASTI +-- =========================================================================== + +local function setting_get_pos(name, setting_level) + local result = minetest.setting_get_pos(name) + if result ~= nil then + minetest.log("action", "Position setting "..name.." read: "..minetest.pos_to_string(result)) + elseif setting_level == "required" then + error("Required position setting "..name.." not set or have an invalid format!") + elseif setting_level == "optional" then + minetest.log("action", "Position setting "..name.." not set (optional).") + else + minetest.log("error", "Position setting "..name.." not set! Will be reset to zeroes.") + result = vector.zero() + end + return result +end + +local function setting_get_str(name, setting_level) + local result = minetest.settings:get(name) + if result ~= nil then + minetest.log("action", "String setting "..name.." read: "..result) + elseif setting_level == "required" then + error("Required string setting "..name.." not set!") + elseif setting_level == "optional" then + minetest.log("action", "String setting "..name.." not set (optional).") + else + minetest.log("error", "String setting "..name.." not set! Will be reset to an empty string") + result = "" + end + return result +end + +ch_core.config = { + povinne_vytisky_listname = setting_get_str("ch_povinne_vytisky_listname", "optional") or "main", +} + +ch_core.positions = { + zacatek_1 = setting_get_pos("static_spawnpoint") or vector.new(-70,9.5,40), + zacatek_2 = setting_get_pos("ch_zacatek_2"), + zacatek_3 = setting_get_pos("ch_zacatek_3"), + vezeni_min = setting_get_pos("ch_vezeni_min"), + vezeni_max = setting_get_pos("ch_vezeni_max"), + vezeni_cil = setting_get_pos("ch_vezeni_cil"), + vezeni_dvere = setting_get_pos("ch_vezeni_dvere", "optional"), + povinne_vytisky = setting_get_pos("ch_povinne_vytisky", "optional"), +} + +local zero_by_type = { + int = 0, + float = 0.0, + -- nil = nil, + string = "", + vector = vector.zero(), +} + +-- GLOBÁLNÍ DATA +-- =========================================================================== +local global_data_data_types = { + posun_casu = "int", + povinne_vytisky = "vector", + povinne_vytisky_listname = "string", + pristi_ick = "int", +} + +local initial_global_data = { + pristi_ick = 10000, +} + +for k, t in pairs(global_data_data_types) do + if initial_global_data[k] == nil then + initial_global_data[k] = zero_by_type[t] + end +end + +-- DATA O POSTAVÁCH +-- =========================================================================== +-- key => "int|float", unknown keys are deserialized as strings +local offline_charinfo_data_types = { + ap_level = "int", -- > 0 + ap_xp = "int", -- >= 0 + ap_version = "int", -- >= 0 + discard_drops = "int", -- 0 = nic, 1 = předměty házet do koše + domov = "string", + doslech = "int", -- >= 0 + extended_inventory = "int", -- 0 = normální velikost, 1 = rozšířený inventář + last_ann_shown_date = "string", -- datum, kdy byla hráči/ce naposledy vypsána oznámení po přihlášení do hry (YYYY-MM-DD) + last_login = "int", -- >= 0, in seconds since 1. 1. 2000 UTC; 0 is invalid value + neshybat = "int", -- 0 = shýbat se při stisku Shift, 1 = neshýbat se + no_ch_sky = "int", -- 0 = krásná obloha ano, 1 = ne + past_ap_playtime = "float", -- in seconds + past_playtime = "float", -- in seconds + pending_registration_privs = "string", + pending_registration_type = "string", + rezim_plateb = "int", -- >= 0, význam podle módu ch_bank + skryt_body = "int", -- 0 => zobrazit, 1 => skrýt + skryt_hlad = "int", -- 0 => zobrazovat (výchozí), 1 => skrýt + skryt_zbyv = "int", -- 0 => zobrazovat (výchozí), 1 => skrýt + stavba = "string", + ui_event_filter = "string", + zacatek_kam = "int", -- 1 => Začátek, 2 => Masarykovo náměstí, 3 => Hlavní nádraží + + trest = "int", +} + +local storage = ch_core.storage + +ch_core.global_data = table.copy(initial_global_data) + +local function is_acceptable_name(player_name) + local types = {} + for i = 1, #player_name do + local b = string.byte(player_name, i) + if b == 0x2d or b == 0x5f then + types[i] = '_' + elseif 0x30 <= b and b <= 0x39 then + types[i] = '0' + elseif b < 0x61 then + types[i] = 'A' + else + types[i] = 'a' + end + end + local digits, dashes = 0, 0 + for i = 1, #player_name do + if types[i] == '0' then + digits = digits + 1 + elseif digits > 0 then + -- číslice jsou dovoleny jen na konci jména + return false + elseif types[i] == '_' then + dashes = dashes + 1 + -- pomlčky a podtržítka jsou dovoleny jen mezi písmeny + if i == 1 or i == #player_name or string.lower(types[i - 1]) ~= 'a' or string.lower(types[i + 1]) ~= 'a' then + return false + end + end + end + return digits <= 4 and dashes <= 5 -- omezení počtu +end +ch_data.is_acceptable_name = is_acceptable_name + +local function is_invalid_player_name(player_name) + if type(player_name) == "number" then + player_name = tostring(player_name) + elseif type(player_name) ~= "string" then + return "Invalid player_name type "..type(player_name).."!" + end + if #player_name == 0 then + return "Empty player_name!" + end + if #player_name > 19 then + return "Player name "..player_name.." too long!" + end + if string.find(player_name, "[^_%w-]") then + return "Player name '"..player_name.."' contains an invalid character!" + end + return false +end + +--[[ +local function verify_valid_player_name(player_name) + local message = is_invalid_player_name(player_name) + if message then + error(message) + else + return tostring(player_name) + end +end +]] + +function ch_core.get_offline_charinfo(player_name) + core.log("warning", "Obsolete function ch_core.get_offline_charinfo() called!") + return ch_data.get_offline_charinfo(player_name) +end + +function ch_core.save_global_data(keys) + local ax = type(keys) + if ax == "table" then + ax = ch_core.save_global_data + for _, key in ipairs(keys) do + ax(key) + end + return + elseif ax ~= "string" and ax ~= "number" then + error("save_global_data() called with an argument of invalid type "..ax.."!") + end + + local data_type = global_data_data_types[keys] + if data_type == nil then + minetest.log("warning", "save_global_data() called for unknown key '"..keys.."', ignored.") + return false + end + local full_key = "/"..keys + local value = ch_core.global_data[keys] + if data_type == "int" then + storage:set_int(full_key, value or 0) + elseif data_type == "float" then + storage:set_float(full_key, value or 0.0) + elseif data_type == "vector" then + storage:set_string(full_key, minetest.pos_to_string(vector.round(value))) + else + storage:set_string(full_key, value or "") + end + return true +end + +-- datatype = "string"|"int"|"float"|"vector"|"nil" +function ch_core.save_offline_charinfo(player_name, keys) + core.log("warning", "Obsolete function ch_core.save_offline_charinfo() called!") + return ch_data.save_offline_charinfo(player_name) +end + +function ch_core.set_titul(player_name, titul) + local offline_charinfo = ch_data.get_offline_charinfo(player_name) + offline_charinfo.titul = titul + ch_data.save_offline_charinfo(player_name) + local online_charinfo = ch_data.online_charinfo[player_name] + local player = core.get_player_by_name(player_name) + if player and online_charinfo and ch_core.compute_player_nametag then + player:set_nametag_attributes(ch_core.compute_player_nametag(online_charinfo, offline_charinfo)) + end + return true +end + +-- ch_core.set_temporary_titul() -- Nastaví či zruší dočasný titul postavy. +-- +function ch_core.set_temporary_titul(player_name, titul, titul_enabled) + if type(player_name) ~= "string" then + error("ch_core.set_temporary_titul(): Invalid player_name type: "..type(player_name).."!") + end + local online_charinfo = ch_data.online_charinfo[player_name] + if not online_charinfo or not titul or titul == "" then return false end + local dtituly = ch_core.get_or_add(online_charinfo, "docasne_tituly") + if titul_enabled then + dtituly[titul] = 1 + else + dtituly[titul] = nil + end + local player = core.get_player_by_name(player_name) + if player and ch_core.compute_player_nametag then + player:set_nametag_attributes(ch_core.compute_player_nametag(online_charinfo, ch_data.get_offline_charinfo(player_name))) + return true + else + return false + end +end + +local function restore_value_by_type(data_type, value, value_description) + if data_type == "int" then + return math.round(tonumber(value)) + elseif data_type == "float" then + return tonumber(value) + elseif data_type == "string" then + return value + elseif data_type == "vector" then + local result = minetest.string_to_pos(value) + if result == nil then + minetest.log("warning", "Invalid value ignored on restore! (description = "..(value_description or "nil")..")") + return zero_by_type["vector"] + end + return result + elseif data_type == "nil" then + return nil + else + error("restore_value_by_type() called with invalid data_type "..dump2(data_type).."!") + end +end + +-- restore offline data from the storage +local player_counter, player_field_counter, global_counter, delete_counter = 0, 0, 0, 0 +local player_set = {} +local storage_table = (storage:to_table() or {}).fields or {} +for full_key, value in pairs(storage_table) do + local player_name, key = full_key:match("^([^/]*)/(.+)$") + if player_name == "" and key ~= "" then + local data_type = global_data_data_types[key] + ch_core.global_data[key] = restore_value_by_type(data_type, value, "global property "..key) + global_counter = global_counter + 1 + --[[elseif player_name and not is_invalid_player_name(player_name) and (player_set[player_name] or ch_data.offline_charinfo[player_name] == nil) then + local ch_data_offline_charinfo = ch_data.get_or_add_offline_charinfo(player_name) + local data_type = offline_charinfo_data_types[key] + if data_type == "int" then + ch_data_offline_charinfo[key] = math.round(tonumber(value)) + core.log("warning", "Offline charinfo upgraded from storage: "..player_name.."/"..key.."=(int)"..tostring(ch_data_offline_charinfo[key])) + elseif data_type == "float" then + ch_data_offline_charinfo[key] = tonumber(value) + core.log("warning", "Offline charinfo upgraded from storage: "..player_name.."/"..key.."=(float)"..tostring(ch_data_offline_charinfo[key])) + else + ch_data_offline_charinfo[key] = value + core.log("warning", "Offline charinfo upgraded from storage: "..player_name.."/"..key.."=(string)\""..tostring(ch_data_offline_charinfo[key]).."\"") + end + player_field_counter = player_field_counter + 1 + if player_set[player_name] == nil then + player_set[player_name] = true + player_counter = player_counter + 1 + end]] + else + storage:set_string(full_key, "") + core.log("warning", "Invalid key '"..full_key.."' (value "..value..") removed from mod storage!") + delete_counter = delete_counter + 1 + end +end +print("[ch_core] Restored "..player_field_counter.." data pairs of "..player_counter.." players and "..global_counter.." global pairs from the mod storage. "..delete_counter.." was deleted.") + +for player_name, _ in pairs(player_set) do + ch_data.save_offline_charinfo(player_name) +end + +-- Check and update keys +for key, data_type in pairs(global_data_data_types) do + if ch_core.global_data[key] == nil and data_type ~= "nil" then + ch_core.global_data[key] = zero_by_type[data_type] + end +end + +def = { + description = "Zaznamená do příslušného souboru co nejvíc údajů o aktuálním stavu hráčské postavy. Pouze pro Administraci.", + params = "<Jmeno_postavy>", + privs = {server = true}, + func = function(admin_name, player_name) + local player = core.get_player_by_name(player_name) + if player == nil then + return false, "Postava neexistuje!" + end + player_name = player:get_player_name() + local inv = player:get_inventory() + local result = { + player_name = player_name, + pos = player:get_pos(), + velocity = player:get_velocity(), + hp = player:get_hp(), + inv_main = inv:get_list("main"), + inv_craft = inv:get_list("craft"), + wield_index = player:get_wield_index(), + armor_groups = player:get_armor_groups(), + animation = player:get_animation(), + attachment = {player:get_attach()}, + children = player:get_children(), + bone_overrides = player:get_bone_overrides(), + properties = player:get_properties(), + is_player = player:is_player(), + nametag_attributes = player:get_nametag_attributes(), + look_dir = player:get_look_dir(), + look_vertical = player:get_look_vertical(), + look_horizontal = player:get_look_horizontal(), + breath = player:get_breath(), + fov = {player:get_fov()}, + meta = player:get_meta():to_table(), + player_control = player:get_player_control(), + player_control_bits = player:get_player_control_bits(), + physics_override = player:get_physics_override(), + huds = player:hud_get_all(), + hud_flags = player:hud_get_flags(), + hotbar_size = player:hud_get_hotbar_itemcount(), + hotbar_image = player:hud_get_hotbar_image(), + hotbar_selected_image = player:hud_get_hotbar_selected_image(), + sky = player:get_sky(), + sun = player:get_sun(), + moon = player:get_moon(), + stars = player:get_stars(), + clouds = player:get_clouds(), + day_night_ratio_override = player:get_day_night_ratio(), + local_animation = {player:get_local_animation()}, + eye_offset = {player:get_eye_offset()}, + lighting = player:get_lighting(), + flags = player:get_flags(), + online_charinfo = ch_data.online_charinfo[player_name] or "nil", + offline_charinfo = ch_data.offline_charinfo[player_name] or "nil", + } + result = dump2(result) + local parts = string.split(result, "\n_[") + table.sort(parts) + result = table.concat(parts, "\n_[") + local path = core.get_worldpath().."/_dump_"..player_name..".txt" + core.safe_file_write(path, result) + return true, "Zaznamenáno do: "..path + end, +} + +core.register_chatcommand("dumpplayer", def) + +ch_core.close_submod("data") |