--[[ ======================================== DATA STATISTICS - СИСТЕМА СТАТИСТИКИ ДАННЫХ ======================================== Файл: DataStatistics.lua Описание: Система сбора и обработки игровой статистики Автор: Система Версия: 1.0 Функциональность: - Отслеживание денежных операций игроков - Статистика предметов и экипировки - Система квестов и достижений - Глобальные и персональные данные игроков - Статистика подземелий и активности ]] --[[ ======================================== КОНСТАНТЫ И НАСТРОЙКИ ======================================== ]] -- Индексы статистики сервера local STAT_INDEX = { CREATURE_MONEY = 2, -- Деньги от монстров QUEST_MONEY = 3, -- Деньги от квестов ITEM_SPENT_MONEY = 4, -- Деньги потраченные на предметы STRENGTH_SPENT_MONEY = 5, -- Деньги потраченные на усиление COMPOSITION_SPENT_MONEY = 6, -- Деньги потраченные на синтез ARENA_MONEY = 7, -- Деньги от арены ITEM_DISAPPEAR = 39, -- Исчезновение предметов ITEM_DISAPPEAR_DELETE = 40, -- Удаление предметов YAOJING_PLAYERS = 45, -- Игроки в подземелье YAOJING_ENTRIES = 46, -- Входы в подземелье MOZU_DEATHS = 53 -- Смерти в подземелье } -- Индексы персональных данных игроков local ROLE_DATA_INDEX = { FIRST_QUEST_LEVEL = 1, -- Уровень первого квеста FIRST_TRANSFER_LEVEL = 2, -- Уровень первого перехода STRENGTH_COUNT = 3, -- Количество усилений FIRST_STRENGTH_LEVEL = 4, -- Уровень первого усиления FIRST_COMPOSITION_LEVEL = 6, -- Уровень первого синтеза FIRST_DUNGEON_LEVEL = 7, -- Уровень первого подземелья FIRST_SNOW_LEVEL = 8, -- Уровень первого снега MOZU_QUEST_COUNT = 11 -- Количество квестов Мозу } -- Карты для статистики local MAP_IDS = { ARENA = 3373741608, -- Арена YAOJING = "h04", -- Подземелье MOZU_1 = "h03_1", -- Мозу 1 MOZU_2 = "h03_2", -- Мозу 2 MOZU_3 = "h03_3" -- Мозу 3 } -- Квесты для статистики local QUEST_IDS = { FIRST_QUEST = 20200, -- Первый квест SNOW_QUEST = 20300, -- Снежный квест MOZU_QUEST_1 = 30501, -- Квест Мозу 1 MOZU_QUEST_2 = 30502, -- Квест Мозу 2 MOZU_QUEST_3 = 30503 -- Квест Мозу 3 } --[[ ======================================== ТАБЛИЦЫ ПРЕДМЕТОВ ПО КАТЕГОРИЯМ ======================================== Структура: itemTable[category] = {itemID1, itemID2, ...} Категории: - 8-13: Оружие разных уровней - 14: Обычная экипировка - 15-18: Элитная экипировка - 23: Специальные предметы - 58-61: Дополнительные предметы ]] local itemTable = { -- Оружие 8-13 уровня [8] = {8017001,8027001,8037001,8047001,8050801,8051801,8060801,8061801,8070801,8071801,8080801,8081801,8090801,8091801,8101201}, [9] = {8017002,8027002,8037002,8047002,8050802,8051802,8060802,8061802,8070802,8071802,8080802,8081802,8090802,8091802,8101202}, [10] = {8017003,8027003,8037003,8047003,8050803,8051803,8060803,8061803,8070803,8071803,8080803,8081803,8090803,8091803,8101203}, [11] = {8017004,8027004,8037004,8047004,8050804,8051804,8060804,8061804,8070804,8071804,8080804,8081804,8090804,8091804,8101204}, [12] = {8017005,8027005,8037005,8047005,8050805,8051805,8060805,8061805,8070805,8071805,8080805,8081805,8090805,8091805,8101205}, [13] = {8017006,8027006,8037006,8047006,8050806,8051806,8060806,8061806,8070806,8071806,8080806,8081806,8090806,8091806,8101206}, -- Обычная экипировка (14) [14] = { 8011003,8011004,8011005,8011006,8011007,8011008,8011009,8011010,8011011, 8021003,8021004,8021005,8021006,8021007,8021008,8021009,8021010,8021011, 8031003,8031004,8031005,8031006,8031007,8031008,8031009,8031010,8031011, 8041003,8041004,8041005,8041006,8041007,8041008,8041009,8041010,8041011, 8050105,8050106,8050107,8050108,8050109,8050110,8050111, 8051105,8051106,8051107,8051108,8051109,8051110,8051111, 8060103,8060104,8060105,8060106,8060107,8060108,8060109,8060110,8060111, 8061103,8061104,8061105,8061106,8061107,8061108,8061109,8061110,8061111, 8070103,8070104,8070105,8070106,8070107,8070108,8070109,8070110,8070111, 8071103,8071104,8071105,8071106,8071107,8071108,8071109,8071110,8071111, 8080103,8080104,8080105,8080106,8080107,8080108,8080109,8080110,8080111, 8081103,8081104,8081105,8081106,8081107,8081108,8081109,8081110,8081111, 8090103,8090104,8090105,8090106,8090107,8090108,8090109,8090110,8090111, 8091103,8091104,8091105,8091106,8091107,8091108,8091109,8091110,8091111, 8100103,8100104,8100105,8100106,8100107,8100108,8100109,8100110,8100111, 8110103,8110104,8110105,8110106,8110107,8110108,8110109,8110110,8110111, 8111103,8111104,8111105,8111106,8111107,8111108,8111109,8111110,8111111, 8121103,8121104,8121105,8121106,8121107,8121108,8121109,8121110,8121111, 8122103,8122104,8122105,8122106,8122107,8122108,8122109,8122110,8122111, 8130103,8130104,8130105,8130106,8130107,8130108,8130109,8130110,8130111 }, -- Элитная экипировка (15-18) [15] = {8050207,8051207,8060207,8061207,8070207,8071207,8080207,8081207,8090207,8091207,8100207,8110207,8111207,8121207,8122207,8130207}, [16] = {8050208,8051208,8060208,8061208,8070208,8071208,8080208,8081208,8090208,8091208,8100208,8110208,8111208,8121208,8122208,8130208}, [17] = {8050209,8051209,8060209,8061209,8070209,8071209,8080209,8081209,8090209,8091209,8100209,8110209,8111209,8121209,8122209,8130209}, [18] = {8050210,8051210,8060210,8061210,8070210,8071210,8080210,8081210,8090210,8091210,8100210,8110210,8111210,8121210,8122210,8130210}, -- Специальные предметы (23) [23] = { 8161011,8161012,8161013,8161014,8161015,8160021,8160022,8160027,8160032,8160033, 8171011,8171012,8171013,8171014,8171015,8170021,8170022,8170027,8170032,8170033 }, -- Дополнительные предметы (58-61) [58] = { 3100095,3100096,3100097,3100098,3100099,3100100,3100105,3100106,3100107,3100108,3100109,3100110, 3100115,3100116,3100117,3100118,3100119,3100120,3100125,3100126,3100127,3100128,3100129,3100130, 3100135,3100136,3100137,3100138,3100139,3100140,3100145,3100146,3100147,3100148,3100149,3100150, 3100155,3100156,3100157,3100158,3100159,3100160,3100165,3100166,3100167,3100168,3100169,3100170 }, [59] = {4400001,4400002,4400003,4400004,4400005,4400006,4400007,4400008,4400009,4400010,4400011,4400012,4400013,4400014,4400015,4400016,4400017,4400018,4400019,4400020,4400021,4400022,4400023}, [60] = { 4400301,4400302,4400303,4400304,4400305,4400306,4400307,4400308,4400309,4400310,4400311,4400312, 4400313,4400314,4400315,4400316,4400317,4400318,4400319,4400320,4400321,4400322,4400323,4400324, 4400325,4400326,4400327,4400328,4400329,4400330,4400331,4400332 }, [61] = {3070022,3070023,4400031,4400032,4400033,4400034,4400035,4400036,4400037,4400038,4400039,4400040,4400041,4400042,4800053} } --[[ ======================================== ТАБЛИЦЫ ДЛЯ ОТСЛЕЖИВАНИЯ ИГРОКОВ ======================================== ]] -- Таблица для отслеживания игроков по функциям local f_Roles = { [1] = {}, -- Функция 1 [2] = {}, -- Функция 2 [3] = {}, -- Функция 3 [4] = {}, -- Функция 4 [5] = {}, -- Функция 5 [6] = {}, -- Функция 6 [7] = {} -- Функция 7 } -- Таблица для отслеживания игроков в подземельях local yaoJing_Roles = {} -- Подземелье local baiGui_Roles = {} -- Подземелье байгуй local yongChuang_Roles = {} -- Подземелье юнчуан local lianHun_Roles = {} -- Подземелье ляньхун local lianHunQ_Roles = {} -- Подземелье ляньхун квест local arena_Roles = {} -- Арена --[[ ======================================== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ======================================== ]] --[[ Функция: Обновление данных сервера Параметры: - index: Индекс статистики - var: Значение для добавления Действия: - Обновляет глобальную статистику сервера - Проверяет ежедневный сброс данных ]] function UpdateSeverData(index, var) -- Закомментировано для отладки --[[ index = index - 1 local curTime = tonumber(os.date("%j")) if aux.GetWorldDataTable(0) == nil or aux.GetWorldDataTable(0) == 0 then aux.SetWorldDataTable(0, curTime) elseif aux.GetWorldDataTable(0) ~= curTime then -- Сброс данных при смене дня for i = 1, 60 do aux.SetWorldDataTable(i, 0) end aux.SetWorldDataTable(0, curTime) end if aux.GetWorldDataTable(index) == 0 then aux.SetWorldDataTable(index, var) else aux.SetWorldDataTable(index, aux.GetWorldDataTable(index) + var) end --]] end --[[ Функция: Обновление персональных данных игрока Параметры: - RoleID: ID игрока - index: Индекс данных - var: Значение для установки Действия: - Обновляет персональную статистику игрока ]] function UpdateRoleData(RoleID, index, var) -- Закомментировано для отладки --[[ index = index - 1 if aux.GetRoleDataTable(RoleID, index) == nil or aux.GetRoleDataTable(RoleID, index) == 0 then aux.SetRoleDataTable(RoleID, index, var) else aux.SetRoleDataTable(RoleID, index, aux.GetRoleDataTable(RoleID, index) + var) end --]] end --[[ Функция: Проверка и обновление статистики подземелий Параметры: - fIndex: Индекс функции - RoleID: ID игрока - tNumIndex: Индекс количества - tTimesIndex: Индекс времени Действия: - Отслеживает уникальных игроков в подземельях - Обновляет статистику входов ]] local function instanceData(fIndex, RoleID, tNumIndex, tTimesIndex) local curTime = tonumber(os.date("%j")) if f_Roles[fIndex][RoleID] == nil then UpdateSeverData(tNumIndex, 1) f_Roles[fIndex][RoleID] = curTime elseif f_Roles[fIndex][RoleID] ~= curTime then f_Roles[fIndex] = {} f_Roles[fIndex][RoleID] = curTime UpdateSeverData(tNumIndex, 1) end UpdateSeverData(tTimesIndex, 1) end --[[ ======================================== ОБРАБОТЧИКИ ДЕНЕЖНЫХ ОПЕРАЦИЙ ======================================== ]] --[[ Обработчик: Деньги от монстров Параметры: - MapID: ID карты - InstanceID: ID инстанса - RoleID: ID игрока - CreatureID: ID монстра - CreatureTypeID: Тип монстра - money: Количество денег Действия: - Обновляет статистику денег от монстров - Отдельно отслеживает деньги от арены ]] function x_On_CreMoney(MapID, InstanceID, RoleID, CreatureID, CreatureTypeID, money) UpdateSeverData(STAT_INDEX.CREATURE_MONEY, money) -- Отдельная статистика для арены if MapID == MAP_IDS.ARENA then UpdateSeverData(STAT_INDEX.ARENA_MONEY, money) end end --[[ Обработчик: Деньги от квестов Параметры: - MapID: ID карты - InstanceID: ID инстанса - RoleID: ID игрока - QuestID: ID квеста - money: Количество денег Действия: - Обновляет статистику денег от квестов ]] function x_On_ComQuestMoney(MapID, InstanceID, RoleID, QuestID, money) UpdateSeverData(STAT_INDEX.QUEST_MONEY, money) end --[[ Обработчик: Деньги потраченные на предметы Параметры: - MapID: ID карты - InstanceID: ID инстанса - RoleID: ID игрока - ItemID: ID предмета - money: Количество денег Действия: - Обновляет статистику денег потраченных на предметы ]] function x_On_ItemSpent(MapID, InstanceID, RoleID, ItemID, money) UpdateSeverData(STAT_INDEX.ITEM_SPENT_MONEY, money) end --[[ Обработчик: Деньги потраченные на усиление Параметры: - MapID: ID карты - InstanceID: ID инстанса - RoleID: ID игрока - EqTypeID: Тип экипировки - EqGrade: Уровень экипировки - EqBeforLevel: Уровень до усиления - money: Количество денег Действия: - Обновляет статистику денег потраченных на усиление - Отслеживает первое усиление игрока ]] function x_On_StrengthSpent(MapID, InstanceID, RoleID, EqTypeID, EqGrade, EqBeforLevel, money) UpdateSeverData(STAT_INDEX.STRENGTH_SPENT_MONEY, money) -- Отслеживание усилений UpdateRoleData(RoleID, ROLE_DATA_INDEX.STRENGTH_COUNT, 1) -- Уровень первого усиления if aux.GetRoleDataTable(RoleID, ROLE_DATA_INDEX.FIRST_STRENGTH_LEVEL) == nil or aux.GetRoleDataTable(RoleID, ROLE_DATA_INDEX.FIRST_STRENGTH_LEVEL) == 0 then UpdateRoleData(RoleID, ROLE_DATA_INDEX.FIRST_STRENGTH_LEVEL, role.GetRoleLevel(MapID, InstanceID, RoleID)) end end --[[ Обработчик: Деньги потраченные на синтез Параметры: - MapID: ID карты - InstanceID: ID инстанса - RoleID: ID игрока - ComposedTypeID: Тип синтезированного предмета - money: Количество денег Действия: - Обновляет статистику денег потраченных на синтез - Отслеживает первый синтез игрока ]] function x_On_CompositionSpent(MapID, InstanceID, RoleID, ComposedTypeID, money) UpdateSeverData(STAT_INDEX.COMPOSITION_SPENT_MONEY, money) -- Уровень первого синтеза if aux.GetRoleDataTable(RoleID, ROLE_DATA_INDEX.FIRST_COMPOSITION_LEVEL) == nil or aux.GetRoleDataTable(RoleID, ROLE_DATA_INDEX.FIRST_COMPOSITION_LEVEL) == 0 then for k, v in pairs(itemTable[14]) do if ComposedTypeID == v then UpdateRoleData(RoleID, ROLE_DATA_INDEX.FIRST_COMPOSITION_LEVEL, role.GetRoleLevel(MapID, InstanceID, RoleID)) break end end end end --[[ ======================================== ОБРАБОТЧИКИ ПРЕДМЕТОВ ======================================== ]] --[[ Обработчик: Новые предметы Параметры: - MapID: ID карты - InstanceID: ID инстанса - NewTypeID: ID нового предмета - Grade: Уровень предмета Действия: - Обновляет статистику новых предметов по категориям - Учитывает уровень предмета для элитной экипировки ]] function x_NewItem(MapID, InstanceID, NewTypeID, Grade) for k, v in pairs(itemTable) do for m, n in pairs(v) do if n == NewTypeID then if (k >= 15 and k <= 18) and Grade == 4 then UpdateSeverData(k + 4, 1) else UpdateSeverData(k, 1) end return end end end end --[[ Обработчик: Исчезновение предметов Параметры: - DisType: Тип исчезновения (1-удаление, 2-удаление, 3-время, 4-другое) - ItemTypeID: ID предмета - Grade: Уровень предмета Действия: - Отслеживает исчезновение предметов 3+ уровня - Отдельно считает удаленные предметы ]] function x_ItemDisappear(DisType, ItemTypeID, Grade) if Grade >= 3 then UpdateSeverData(STAT_INDEX.ITEM_DISAPPEAR, 1) if DisType == 1 then UpdateSeverData(STAT_INDEX.ITEM_DISAPPEAR_DELETE, 1) end end end --[[ ======================================== ОБРАБОТЧИКИ ПОДЗЕМЕЛИЙ ======================================== ]] --[[ Обработчик: Вход в подземелье Параметры: - MapID: ID карты - InstanceID: ID инстанса - RoleID: ID игрока Действия: - Отслеживает уникальных игроков в подземелье - Считает общее количество входов ]] function h04_OnPlayerEnter(MapID, InstanceID, RoleID) local curTime = tonumber(os.date("%j")) if yaoJing_Roles[RoleID] == nil then UpdateSeverData(STAT_INDEX.YAOJING_PLAYERS, 1) yaoJing_Roles[RoleID] = curTime elseif yaoJing_Roles[RoleID] ~= curTime then yaoJing_Roles = {} yaoJing_Roles[RoleID] = curTime UpdateSeverData(STAT_INDEX.YAOJING_PLAYERS, 1) end UpdateSeverData(STAT_INDEX.YAOJING_ENTRIES, 1) end --[[ Обработчик: Смерть в подземелье Параметры: - MapID: ID карты - InstanceID: ID инстанса - RoleID: ID игрока - KillerID: ID убийцы Действия: - Отслеживает смерти игроков в подземельях Мозу ]] function h03_1_OnRoleDie(MapID, InstanceID, RoleID, KillerID) UpdateSeverData(STAT_INDEX.MOZU_DEATHS, 1) end --[[ ======================================== ОБРАБОТЧИКИ КВЕСТОВ ======================================== ]] --[[ Обработчик: Завершение первого квеста Параметры: - MapID: ID карты - InstanceID: ID инстанса - QuestID: ID квеста - RoleID: ID игрока - NPCID: ID NPC Действия: - Записывает уровень игрока при завершении первого квеста ]] function q20200_Complete(MapID, InstanceID, QuestID, RoleID, NPCID) UpdateRoleData(RoleID, ROLE_DATA_INDEX.FIRST_QUEST_LEVEL, role.GetRoleLevel(MapID, InstanceID, RoleID)) end --[[ Обработчик: Завершение снежного квеста Параметры: - MapID: ID карты - InstanceID: ID инстанса - QuestID: ID квеста - RoleID: ID игрока - NPCID: ID NPC Действия: - Записывает уровень игрока при завершении снежного квеста ]] function q20300_Complete(MapID, InstanceID, QuestID, RoleID, NPCID) UpdateRoleData(RoleID, ROLE_DATA_INDEX.FIRST_SNOW_LEVEL, role.GetRoleLevel(MapID, InstanceID, RoleID)) end --[[ ======================================== РЕГИСТРАЦИЯ ОБРАБОТЧИКОВ ======================================== Регистрируем обработчики для: - Денежных операций (монстры, квесты, предметы, усиление, синтез) - Предметов (новые предметы, исчезновение) - Подземелий (входы, смерти) - Квестов (завершение) ]] -- Регистрация обработчиков денежных операций aux.RegisterWorldEvent(3, "x_On_CreMoney") -- Деньги от монстров aux.RegisterRoleEvent(74, "x_On_ComQuestMoney") -- Деньги от квестов aux.RegisterRoleEvent(75, "x_On_ItemSpent") -- Деньги на предметы aux.RegisterRoleEvent(76, "x_On_StrengthSpent") -- Деньги на усиление aux.RegisterRoleEvent(77, "x_On_CompositionSpent") -- Деньги на синтез -- Регистрация обработчиков предметов aux.RegisterWorldEvent(4, "x_NewItem") -- Новые предметы aux.RegisterWorldEvent(5, "x_ItemDisappear") -- Исчезновение предметов -- Регистрация обработчиков подземелий aux.RegisterMapEvent("h04", 2, "h04_OnPlayerEnter") -- Вход в подземелье aux.RegisterMapEvent("h03_1", 5, "h03_1_OnRoleDie") -- Смерть в Мозу 1 aux.RegisterMapEvent("h03_2", 5, "h03_1_OnRoleDie") -- Смерть в Мозу 2 aux.RegisterMapEvent("h03_3", 5, "h03_1_OnRoleDie") -- Смерть в Мозу 3 -- Регистрация обработчиков квестов aux.RegisterQuestEvent(QUEST_IDS.FIRST_QUEST, 1, "q20200_Complete") -- Первый квест aux.RegisterQuestEvent(QUEST_IDS.SNOW_QUEST, 1, "q20300_Complete") -- Снежный квест --[[ ======================================== ИНФОРМАЦИЯ О СИСТЕМЕ ======================================== Система "DataStatistics" обеспечивает: 1. Статистика денежных операций: - Деньги от монстров (индекс 2) - Деньги от квестов (индекс 3) - Деньги на предметы (индекс 4) - Деньги на усиление (индекс 5) - Деньги на синтез (индекс 6) - Деньги от арены (индекс 7) 2. Статистика предметов: - Новые предметы по категориям (индексы 8-23, 58-61) - Исчезновение предметов (индексы 39-40) - Элитная экипировка с учетом уровня 3. Статистика подземелий: - Уникальные игроки в подземельях (индекс 45) - Общее количество входов (индекс 46) - Смерти в подземельях Мозу (индекс 53) 4. Персональные данные игроков: - Уровень первого квеста (индекс 1) - Уровень первого перехода (индекс 2) - Количество усилений (индекс 3) - Уровень первого усиления (индекс 4) - Уровень первого синтеза (индекс 6) - Уровень первого подземелья (индекс 7) - Уровень первого снега (индекс 8) - Количество квестов Мозу (индекс 11) 5. Особенности системы: - Ежедневный сброс статистики - Отслеживание уникальных игроков - Категоризация предметов - Разделение статистики по типам Система автоматически собирает и обрабатывает игровую статистику для анализа активности игроков и балансировки игрового процесса. ]]