Модуль:PlayerStats

Материал из ЧТМ
Версия от 20:05, 4 июня 2026; Lord (обсуждение | вклад) (пробуем перевести на принципиально иную архитектуру с помощью Cron/GenerateStats)
Перейти к навигации Перейти к поиску
Документация Документация
Пожалуйста, добавляйте категории на страницу документации.

Общее описание

Module:PlayerStats — это центральный фронтенд-контроллер для генерации полной личной страницы игрока ЧТМ. Модуль мгновенно выводит абсолютно всю статистику по игроку за все годы, достижения, рекорды, мегарейтинг, медали, навигационные шаблоны и хронологию матчей.

Главное достижение системы — архитектура глобального JSON-кэширования.

Модуль больше не занимается тяжелыми математическими вычислениями и не перебирает базы данных на лету. Вместо этого он за долю секунды читает предварительно сгенерированный и сжатый текстовый файл Module:Data/GrandStats.json.Это позволило снизить потребление оперативной памяти сервером в 6 раз, а скорость загрузки страниц увеличить в десятки раз.

Использование

На странице игрока (например, Диман) модуль вызывается через шаблон (или напрямую через #invoke):

{{#invoke:PlayerStats|main|Диман}}

Или с указанием всех тонких параметров:

{{#invoke:PlayerStats|main<!-- Запуск модуля
-->|Диман<!-- Имя игрока, обязательный параметр, НЕ ПЕРЕНОСИТЕ СТРОКУ ПОСЛЕ ИМЕНИ, если нужен визуальный перенос, то используйте комментарии, как в этом примере<!-- 
-->|achievements=yes<!-- Вычислять и показывать ли блок «Достижения и Рекорды» (по умолчанию-yes)<!-- 
-->|ach_list=yes<!-- Если achievements=no, то показать только блок достижений: ach_list=yes. Если achievements=yes, то не показывать блок достижений: ach_list=no.
-->|records_list=yes<!-- Если achievements=no, то показать только блок рекордов: records_list=yes. Если achievements=yes, то не показывать блок рекордов: records_list=no.<!-- 
-->|main_table=yes<!-- Отключает расчёт и вывод таблицы статистики (по умолчанию — yes)
-->|sortable=no<!-- Отключает сортировку таблицы статистики, делая её более компактной (по умолчанию — no)
-->|medals=yes<!-- Показывать ли медали в таблице статистики (по умолчанию — no)
-->|matches_list=no<!-- Отключает расчёт и вывод полного списка матчей (по умолчанию — yes)
-->|matches_link=<!-- В случае отключения списка матчей необходимо задать ссылку на подстраницу.
-->|navboxes=yes<!-- Отключает расчёт и вывод навигационных шаблонов (по умолчанию — yes)
-->|СГ=1<!-- Если статья заняла какое-то место в голосовании за статью года, то оно указывается
-->|Год=2020<!-- Год, когда происходило голосование
-->|Качество=ИС<!-- Избранная (ИС) или хорошая (ХС) статья
-->}}

Оптимизация (Разделение контента)

Для удобства навигации (и чтобы не перегружать страницу визуально) рекомендуется выносить рекорды, достижения и полный список матчей ветеранов турнира на отдельную подстраницу.

Заполняйте шаблон основной статьи так:

== Достижения и рекорды ==
{{ОС|Достижения, рекорды и список матчей}}.
{{#invoke:PlayerStats|main<!--
-->|ИМЯ<!--
-->|achievements = no
   |main_table   = yes
   |sortable     = no
   |medals       = yes
   |matches_list = no
   |matches_link = Достижения, рекорды и список матчей 
   |navboxes     = yes
}}

А на подстранице (например, /Достижения, рекорды и список матчей) заполните так:

{{#invoke:PlayerStats|main<!--
-->|ИМЯ<!--
-->|achievements = yes
   |main_table   = no
   |matches_list = yes
   |navboxes     = no
}}

Архитектура системы (MVC + Cache)

Система разделена на независимые слои для обеспечения максимальной производительности:

Слой 1: Базы Данных (Data)

  • Module:Data/2006 ... Module:Data/2046: Сырые массивы матчей. Никакой логики, только факты (кто играл, кто забил, минуты, пенальти).
  • Module:Data/Teams: Справочник команд (коды, полные названия, падежи).

Слой 2: Настройки и Правила (Config)

  • Module:Config: Мозг проекта. Здесь лежат списки годов, массивы чемпионов, цвета для таблиц, параметры эпох (с какого года считается статистика), а также «Костыли» (ручные корректировки вроде +11 к полезности для отдельного матча).

Слой 3: Вычислительные движки (Engines)

  • Module:StatEngine/Pure (Харвестер): Математик. Берет сырые базы и перемалывает их в готовую статистику.
  • Module:StatEngine/TournamentAwards: Логика судейства (кто получил Башмак, кто MVP игрового дня, как разрешать равенство очков).
  • Module:Megarating: Сложный калькулятор мегарейтинга по формулам ЧТМ.
  • Module:StatEngine/StreaksCore: Анализатор серий (сухие серии, победные серии, матчи подряд).

Слой 4: Генератор и Кэш (Backend)

  • Module:Cron/GenerateStats: Тяжеловоз. Вызывается только вручную администратором. Загружает БД, прогоняет через все движки и собирает GrandStats и глобальные рекорды. Сжимает результат в текст формата JSON.
  • Module:Data/GrandStats.json: Тетрадка бухгалтера. Обычная текстовая страница, хранящая итог работы генератора. Именно её читают страницы игроков.

Слой 5: Интерфейс (Frontend)

  • Module:PlayerStats: Роутер. Быстро считывает нужный кусок из GrandStats.json и раздает данные отрисовщикам.
  • Module:PlayerAchievements: Строит маркированные списки текстовых достижений и рекордов.
  • Module:Автоматическая статистика: Рисует таблицу по годам и сворачиваемый список матчей.

Инструкция по поддержке и обслуживанию

⚠️ ГЛАВНОЕ ПРАВИЛО НОВОЙ АРХИТЕКТУРЫ: Поскольку PlayerStats берет данные из закэшированного файла, любое изменение в базах данных (добавили гол) или в конфигах (изменили эпоху) требует ручного перевыпуска кэша! Без этого страницы игроков не увидят изменений.

🔄 Как обновить кэш (Пересчитать всю вики)

Если вы сыграли новый игровой день или исправили ошибку в старом матче:

  1. Перейдите на служебную страницу Служебная:Развёртка_шаблонов (Special:ExpandTemplates).
  2. В верхнее окно вставьте код: {{#invoke:Cron/GenerateStats|main}}
  3. Нажмите «ОК».
  4. В нижнем окне появится огромный текстовый массив (начинается с {"Players":{...). Скопируйте его целиком.
  5. Откройте на редактирование Module:Data/GrandStats.json.
  6. Удалите старый текст, вставьте новый и сохраните. Страницы всех игроков мгновенно обновятся!

➕ Как добавить новый турнир (например, ЧТМ-2050)

  1. Создайте Module:Data/2050 и залейте туда матчи.
  2. Откройте Module:Config:
    • Добавьте 2050 в Config.years и Config.all_years.
    • Если турнир не закончен, поставьте Config.is_latest_finished = false. Как только сыгран финал — меняйте на true.
    • Пропишите чемпионов в Config.champions_teams и Config.champions_players (когда они станут известны).
  3. Обновите кэш (см. инструкцию выше).

🛠 Как скорректировать статистику (ручные добавки)

Иногда история ЧТМ требует ручного вмешательства (матчи без протоколов, технические решения). Для этого не нужно ломать код:

  1. Зайдите в Module:Config.
  2. В массиве Config.metrics найдите нужный показатель (например, clearances).
  3. Добавьте игрока в секцию adjustments -> players:

   ["clearances"] = {
       start = 2022,
       get_val = function(stats) return stats.clearances end,
       adjustments = {
           players = {
               ["Имя_Игрока"] = { [2050] = 5 }, -- Добавит 5 выносов в 2050 году
           }
       }
   }

  1. Обновите кэш (см. инструкцию выше). Система сама плюсанёт эти цифры в общую историю и в конкретный год.

📈 Что делать, если появляется совершенно новый показатель?

Если в 2050 году вы решите считать, например, «Голы с центра поля»:

  1. В Module:StatEngine/Pure в функции create_empty_stats добавьте поле center_goals = 0.
  2. Там же в extract_goals пропишите условие: if goal.goal_type == "с центра" then p.goals.center_goals = ... end.
  3. В Module:Config в Config.metrics создайте словарь ["center_goals"].
  4. В Module:Автоматическая статистика добавьте строчку в p.row_defs.
  5. Обновите кэш. Колонка автоматически появится во всех таблицах, а лучший по этому показателю получит медаль.


-- ==========================================
-- Модуль:PlayerStats
-- Архитектура: Быстрое чтение JSON-кэша
-- ==========================================
local PlayerStats = {}

local PA = require('Module:PlayerAchievements')
local AS = require('Module:Автоматическая статистика')

function PlayerStats.main(frame)
    local args = frame.args[1] and frame.args or frame:getParent().args
    local player_name = args[1] or args.player or args["игрок"]
    if not player_name or player_name == "" then return "Ошибка: не указано имя игрока." end

    local Cache
    local success, res = pcall(mw.loadJsonData, 'Module:Data/GrandStats.json')
    if success and res then Cache = res else return "Ошибка: не удалось загрузить кэш Module:Data/GrandStats.json. Пожалуйста, сгенерируйте его заново." end

    local pc = Cache.Players[player_name]
    if not pc then return "Нет статистики для игрока " .. player_name end

    local PA_data = {
        Players = { [player_name] = pc.PA_Player },
        GlobalRecords = Cache.Global.PA_GlobalRecords,
        CustomStats = Cache.Global.PA_CustomStats,
        Leaders = Cache.Global.PA_Leaders,
        TeamLeaders = Cache.Global.PA_TeamLeaders,
        StadiumLeaders = Cache.Global.PA_StadiumLeaders,
        ShoeTeams = Cache.Global.PA_ShoeTeams,
        AssistTeams = Cache.Global.PA_AssistTeams,
        MegaratingHistory = { players = { [player_name] = pc.mr_history } },
    }

    pc.AS_compiled.navbox_data = Cache.Global.navbox_data

    local final_output = {}

    local show_achievements = (args.achievements ~= "no" and args.achievements ~= "0")
    if show_achievements then
        local ach_html = PA.render(player_name, PA_data, args)
        if ach_html and ach_html ~= "" then table.insert(final_output, ach_html) end
    end

    local show_main = (args.main_table ~= "no" and args.main_table ~= "0")
    local show_matches = (args.matches_list ~= "no" and args.matches_list ~= "0")
    if show_main or show_matches or (args.navboxes ~= "no" and args.navboxes ~= "0") then
        local as_html = AS.build_ui(player_name, args, pc.AS_compiled)
        if as_html and as_html ~= "" then 
            if #final_output > 0 then table.insert(final_output, "") end
            table.insert(final_output, as_html) 
        end
    end

    return frame:preprocess(table.concat(final_output, "\n"))
end

return PlayerStats