class_name LbView extends VBoxContainer # Таблица рейтинга карты (топ-10 + «Вы: N-й»), данные берутся из Net.boards и обновляются сами по сигналу. # Одна и та же таблица в панели Tab, в итогах гонки, итогах Parkour и будущей карты Metro: LbView.create("metro"). # Ники выводятся обычными Label (не RichText), поэтому «[b]» в чужом нике оформление не ломает. const TEXT := Color(0.92, 0.88, 0.8) const DIM := Color(0.62, 0.6, 0.56) const MINE := Color(0.96, 0.76, 0.44) const GOOD := Color(0.5, 0.85, 0.4) var map_id := "" var font_size := 18 var banner := false # сверху пометка «НОВЫЙ РЕКОРД КАРТЫ / ЛИЧНЫЙ РЕКОРД» (после submit_record) var name_width := 190.0 static func create(id: String, size := 18, with_banner := false) -> LbView: var v := LbView.new() v.map_id = id v.font_size = size v.banner = with_banner v.add_theme_constant_override("separation", 6) return v static func make_label(text: String, size: int, color: Color) -> Label: var l := Label.new() l.text = text l.add_theme_font_size_override("font_size", size) l.add_theme_color_override("font_color", color) l.add_theme_constant_override("outline_size", 3) l.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.85)) l.mouse_filter = Control.MOUSE_FILTER_IGNORE return l # Тёмная полупрозрачная подложка в мрачном стиле static func panel_style(margin := 20) -> StyleBoxFlat: var sb := StyleBoxFlat.new() sb.bg_color = Color(0.035, 0.04, 0.045, 0.86) sb.border_color = Color(0.45, 0.30, 0.16, 0.9) sb.set_border_width_all(2) sb.set_content_margin_all(margin) return sb func _ready() -> void: Net.leaderboard_updated.connect(_on_updated) Net.record_result.connect(_on_record) render() func set_map(id: String) -> void: map_id = id render() func _on_updated(id: String) -> void: if id == map_id: render() func _on_record(id: String, _t: float, _rank: int, _pb: bool, _mr: bool) -> void: if id == map_id: render() func render() -> void: for c in get_children(): remove_child(c) c.queue_free() if banner: var rec = Net.last_record.get(map_id) if rec != null: var txt := "" if rec.map_record: txt = "НОВЫЙ РЕКОРД КАРТЫ" elif rec.personal: txt = "НОВЫЙ ЛИЧНЫЙ РЕКОРД" if txt != "": var b := make_label(txt, font_size + 4, GOOD) b.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER add_child(b) var board = Net.boards.get(map_id) if board == null: add_child(make_label("—" if Net.connected else "Нет связи с сервером", font_size, DIM)) return var top: Array = board.top if top.is_empty(): add_child(make_label("Пока нет результатов", font_size, DIM)) var grid := GridContainer.new() grid.columns = 3 grid.add_theme_constant_override("h_separation", 16) grid.add_theme_constant_override("v_separation", 2) add_child(grid) for i in top.size(): var mine: bool = board.my_rank == i + 1 var col := MINE if mine else TEXT var place := make_label("%d" % (i + 1), font_size, col if mine else DIM) place.custom_minimum_size.x = font_size * 1.4 place.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT grid.add_child(place) var nm := make_label(str(top[i][0]), font_size, col) nm.custom_minimum_size.x = name_width nm.clip_text = true nm.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS grid.add_child(nm) var tm := make_label(Net.fmt_time(float(top[i][1])), font_size, col) tm.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT grid.add_child(tm) if board.my_rank > top.size(): add_child(make_label("Вы: %d-й, %s" % [board.my_rank, Net.fmt_time(board.my_time)], font_size, MINE)) elif board.my_rank == 0 and not top.is_empty(): add_child(make_label("Вы: нет результата", font_size, DIM))