--local bc = better_commands local S = minetest.get_translator(minetest.get_current_modname()) ---Gets matching names in a scoreboard ---@param selector splitParam ---@param context contextTable ---@param objective string? ---@param require_one boolean? ---@return table? result ---@return string? err ---@nodiscard function better_commands.get_scoreboard_names(selector, context, objective, require_one) local result = {} local objectives = better_commands.scoreboard.objectives if objective and not objectives[objective] then return nil, S("Invalid objective '@1'", objective) end if selector[3] == "*" then if objective then for name in pairs(objectives[objective].scores) do result[name] = true end else for _, data in pairs(objectives) do for name in pairs(data.scores) do result[name] = true end end end elseif selector.type == "selector" and selector[3]:sub(1,1) == "@" then local targets, err = better_commands.parse_selector(selector, context) if err or not targets then return nil, err end for _, target in ipairs(targets) do if target.is_player and target:is_player() then result[target:get_player_name()] = true end end else result = {[selector[3]] = true} end local result_count = better_commands.count_table(result) if result_count < 1 then return nil, S("No targets found") end if require_one then if result_count > 1 then return nil, S("Multiple targets found") else result = {next(result)} return {result[1]} end else return result end end local sidebar_template = { bg = { hud_elem_type = "image", position = {x = 1, y = 0.5}, alignment = {x = 0, y = 1}, offset = {x = -70, y = 0}, text = "better_commands_scoreboard_bg.png", scale = {x = 10, y = 10}, z_index = -1 }, title = { hud_elem_type = "text", text = "Title", position = {x = 1, y = 0.5}, alignment = {x = 0, y = -1}, offset = {x = -70, y = 10}, number = 0xffffff, }, names = { hud_elem_type = "text", position = {x = 1, y = 0.5}, alignment = {x = 1, y = 1}, offset = {x = -120, y = 0}, text = "Score\nScore2", number = 0xffffff, }, scores = { hud_elem_type = "text", position = {x = 1, y = 0.5}, alignment = {x = -1, y = 1}, offset = {x = -20, y = 0}, text = "5\n20", number = 0xffffff, } } local function sort_scores(a, b) return (a.score == b.score) and (a.name < b.name) or (tonumber(a.score) > tonumber(b.score)) end function better_commands.format_score(objective, name) if not (objective and name and better_commands.scoreboard.objectives[objective]) then return end local objective_data = better_commands.scoreboard.objectives[objective] local score_data = objective_data.scores[name] if not score_data then return end local format_data = score_data.format or objective_data.format local score if format_data then if format_data.type == "blank" then score = "" elseif format_data.type == "fixed" then score = minetest.colorize("#ffffff", format_data.data) else score = minetest.colorize(format_data.data, tostring(score_data.score)) end else score = tostring(score_data.score) end return score end function better_commands.update_nametags() local display = better_commands.scoreboard.displays.below_name local objective if display then objective = display.objective end for _, player in ipairs(minetest.get_connected_players()) do local nametag = better_commands.get_entity_name(player) if objective then local score = better_commands.format_score(objective, player:get_player_name()) if score then local display_name = better_commands.scoreboard.objectives[objective].display_name or objective nametag = string.format("%s\n%s %s", nametag, score, display_name) end end player:set_nametag_attributes({text = nametag}) end end function better_commands.update_hud() local bg_width = 16 for _, player in ipairs(minetest.get_connected_players()) do local playername = player:get_player_name() local sidebar = better_commands.sidebars[playername] if not sidebar then sidebar = {} better_commands.sidebars[playername] = sidebar end local team = better_commands.teams.players[playername] local team_color, display, objective if team then team_color = better_commands.teams.teams[team].color display = better_commands.scoreboard.displays.colors[team_color] or better_commands.scoreboard.displays.sidebar else display = better_commands.scoreboard.displays.sidebar end objective = display and display.objective local objective_data = better_commands.scoreboard.objectives[objective] if objective_data then local name_text, score_text, max_width = "", "", #objective local title = objective_data.display_name or objective local scores = objective_data.scores local count = 0 local sortable_scores = {} for name in pairs(scores) do count = count + 1 local display_name = better_commands.format_name(name) local score = better_commands.format_score(objective, name) or "???" local width = #minetest.strip_colors(display_name) + #minetest.strip_colors(score) max_width = math.max(width + 2, max_width) table.insert(sortable_scores, {name = display_name, score = score}) end if not display.ascending then table.sort(sortable_scores, sort_scores) else table.sort(sortable_scores, function(...) return not sort_scores(...) end) end for _, data in ipairs(sortable_scores) do name_text = name_text..data.name.."\n" score_text = score_text..data.score.."\n" end if not title then if sidebar.title then for name, id in pairs(sidebar) do player:hud_remove(id) sidebar[name] = nil end return end end if not sidebar.title then for name, def in pairs(sidebar_template) do sidebar[name] = player:hud_add(def) end end local pixel_width = max_width*13 local pixel_height = (count+2)*21 local center_x_offset = -(pixel_width/2 + 10) player:hud_change(sidebar.title, "text", title) player:hud_change(sidebar.title, "offset", {x = center_x_offset, y = -10}) player:hud_change(sidebar.bg, "scale", {x = pixel_width/bg_width, y = pixel_height/bg_width}) player:hud_change(sidebar.bg, "offset", {x = center_x_offset, y = -30}) player:hud_change(sidebar.names, "text", name_text) player:hud_change(sidebar.names, "offset", {x = center_x_offset*2+20, y = 0}) player:hud_change(sidebar.scores, "text", score_text) else minetest.log(dump(better_commands.scoreboard.objectivest)) for name, id in pairs(sidebar) do player:hud_remove(id) sidebar[name] = nil end return end end end better_commands.sidebars = {} ---Gets the display name, given a name and objective ---@param name string ---@param objective? string ---@return string function better_commands.get_display_name(name, objective) if not objective then return name end local objective_data = better_commands.scoreboard.objectives[objective] if not objective_data then return name end if not objective_data.players[name] then return name end if objective_data.display_name then return objective_data.display_name elseif objective_data.players[name].display_name then return objective_data.players[name].display_name end return name end better_commands.register_on_update(better_commands.update_hud) better_commands.register_on_update(better_commands.update_nametags)