Test public pve
This commit is contained in:
Degradin 2025-01-14 20:09:13 +03:00
parent 7813a7cde0
commit d0dbf635ec
6 changed files with 1256 additions and 86 deletions

12
bot.js
View File

@ -23,7 +23,8 @@ const {
SaleModel, SaleModel,
ResourcePriceModel, ResourcePriceModel,
SkillsModel, SkillsModel,
DailyModel DailyModel,
logMiddleware
} = global.config } = global.config
const bot = new Telegraf(process.env.BOT_TOKEN) const bot = new Telegraf(process.env.BOT_TOKEN)
const rpg = require('./rpg'); // Подключение RPG-механик const rpg = require('./rpg'); // Подключение RPG-механик
@ -76,7 +77,6 @@ bot.telegram.setMyCommands([{
description: "Создать жалобу/обращение/идею." description: "Создать жалобу/обращение/идею."
} }
]) ])
bot.use(stage.middleware()) bot.use(stage.middleware())
bot.use(rpg) bot.use(rpg)
@ -211,11 +211,19 @@ bot.command('start', async (ctx) => {
['🎁 Бонус'], ['🎁 Бонус'],
['📦 Контейнеры'], ['📦 Контейнеры'],
['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'], ['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'],
['🛡️ Test'],
]) ])
.resize() .resize()
) )
}) })
bot.hears('🛡️ Test', async (ctx) => {
const buttons = [
[Markup.button.callback('PVE', 'locations')],
];
ctx.reply(`🚨 Добро пожаловать в тестовый режим 🚨\nВесь функционал в этом режиме еще не сбалансирован\n`, Markup.inlineKeyboard(buttons));
})
bot.hears('Криминал', async (ctx) => { bot.hears('Криминал', async (ctx) => {
await ctx.scene.enter('Crime') await ctx.scene.enter('Crime')
}) })

View File

@ -57,4 +57,6 @@ module.exports = {
343500, 349550, 355650, 361800, 368000 343500, 349550, 355650, 361800, 368000
], ],
topSym : ['🥇', '🥈', '🥉', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🔟', '🌫️', '🌫️', '🌫️', '🌫️', '🌫️'], topSym : ['🥇', '🥈', '🥉', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🔟', '🌫️', '🌫️', '🌫️', '🌫️', '🌫️'],
logs: require('../utils/logs'),
logMiddleware: require('../utils/logMiddleware'),
} }

1122
json/logs.json Normal file

File diff suppressed because it is too large Load Diff

120
rpg.js
View File

@ -28,7 +28,8 @@ const {
TruckModel, TruckModel,
ResourcePriceModel, ResourcePriceModel,
SkillsModel, SkillsModel,
DailyModel DailyModel,
logs
} = global.config } = global.config
const rpg = new Composer(); const rpg = new Composer();
@ -37,7 +38,6 @@ rpg.use(async (ctx, next) => {
let id = ctx.from.id let id = ctx.from.id
let username = ctx.from.username; let username = ctx.from.username;
if (username == null) username = ctx.from.id; if (username == null) username = ctx.from.id;
const currentTime = utils.getCurrentTime(); const currentTime = utils.getCurrentTime();
switch (ctx.updateType) { switch (ctx.updateType) {
@ -482,7 +482,6 @@ rpg.action(/brutecard_/, async (ctx) => {
if (!emulator) { if (!emulator) {
return ctx.reply('Для запуска брутфорса вам нужен "Эмулятор картридера".'); return ctx.reply('Для запуска брутфорса вам нужен "Эмулятор картридера".');
} }
// Удаляем "Эмулятор картридера" из инвентаря // Удаляем "Эмулятор картридера" из инвентаря
await InventoryModel.destroy({ where: { id: emulator.id } }); await InventoryModel.destroy({ where: { id: emulator.id } });
@ -519,7 +518,7 @@ rpg.action(/brutecard_/, async (ctx) => {
const keyboard = Markup.inlineKeyboard( const keyboard = Markup.inlineKeyboard(
rows.sort(() => Math.random() - 0.5).map((row) => row) // Сортируем строки кнопок случайным образом rows.sort(() => Math.random() - 0.5).map((row) => row) // Сортируем строки кнопок случайным образом
); );
logs(ctx, "Брутфорс карты", {card: card, keyboard: keyboard, emulator: emulator});
// Отправляем сообщение с клавиатурой // Отправляем сообщение с клавиатурой
await ctx.reply( await ctx.reply(
`💳 Брутфорс карты\n `💳 Брутфорс карты\n
@ -587,6 +586,7 @@ rpg.action(/brute_fail_/, async (ctx) => {
const keyboard = Markup.inlineKeyboard( const keyboard = Markup.inlineKeyboard(
rows.sort(() => Math.random() - 0.5).map((row) => row) rows.sort(() => Math.random() - 0.5).map((row) => row)
); );
logs(ctx, "Брутфорс карты (Fail)", {card: card, keyboard: keyboard});
// Обновляем сообщение с клавиатурой // Обновляем сообщение с клавиатурой
await ctx.editMessageText( await ctx.editMessageText(
@ -616,7 +616,7 @@ rpg.action(/brute_success_/, async (ctx) => {
delete attempts[ctx.from.id]; delete attempts[ctx.from.id];
const amount = card.balance; // Сумма денег за карточку const amount = card.balance; // Сумма денег за карточку
const character = await CharacterModel.findByPk(ctx.from.id); const character = await CharacterModel.findByPk(ctx.from.id);
logs(ctx, "Брутфорс карты (Success)", {card: card, amount: amount});
// Увеличиваем грязные деньги пользователя // Увеличиваем грязные деньги пользователя
character.dirtymoney += amount; character.dirtymoney += amount;
await character.save(); await character.save();
@ -670,6 +670,7 @@ rpg.action(`POCKET_ACTION`, async (ctx) => {
if (character.pocketstealcd > cooldown.currentTime) return ctx.editMessageText(`📛 Данное действие будет доступно через ${cooldown.timeLeftInMinutes} мин.`); if (character.pocketstealcd > cooldown.currentTime) return ctx.editMessageText(`📛 Данное действие будет доступно через ${cooldown.timeLeftInMinutes} мин.`);
character.pocketstealcd = cooldown.endTime character.pocketstealcd = cooldown.endTime
character.stamina -= 10 character.stamina -= 10
logs(ctx, "Карманная кража (Start)", { cdBefore: pocketsteal, cdAfter: character.pocketstealcd, stamina: character.stamina });
character.save() character.save()
ctx.editMessageText('Выберите объект', Markup.inlineKeyboard([ ctx.editMessageText('Выберите объект', Markup.inlineKeyboard([
[ [
@ -710,6 +711,7 @@ rpg.action(`MONEY_IN_POCKET`, async (ctx) => {
let moneyIn = utils.rand(5, 1000); let moneyIn = utils.rand(5, 1000);
Exp(ctx, character, character.intelligence + 3) Exp(ctx, character, character.intelligence + 3)
character.dirtymoney += moneyIn; character.dirtymoney += moneyIn;
logs(ctx, "Карманная кража (Кошелек)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, moneyIn: moneyIn});
await character.save(); await character.save();
return ctx.editMessageText(`Вы успешно украли Ð${utils.spaces(moneyIn)} из кармана.`); return ctx.editMessageText(`Вы успешно украли Ð${utils.spaces(moneyIn)} из кармана.`);
}); });
@ -735,6 +737,7 @@ rpg.action(`PHONE`, async (ctx) => {
return await ctx.reply(`Вы сбыли украденный ${phones[randPhone].name} за Ð${utils.spaces(dirtyMoney)}`) return await ctx.reply(`Вы сбыли украденный ${phones[randPhone].name} за Ð${utils.spaces(dirtyMoney)}`)
} }
property.mobile = phones[randPhone] property.mobile = phones[randPhone]
logs(ctx, "Карманная кража (Телефон)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, phone: phones[randPhone]});
await character.save() await character.save()
await property.save() await property.save()
return ctx.editMessageText(`Вы успешно украли ${phones[randPhone].name} из кармана.`) return ctx.editMessageText(`Вы успешно украли ${phones[randPhone].name} из кармана.`)
@ -763,6 +766,7 @@ rpg.action(`MONEY_IN_WALLET`, async (ctx) => {
let moneyIn = utils.rand(1000, 10000) let moneyIn = utils.rand(1000, 10000)
Exp(ctx, character, character.intelligence + 5) Exp(ctx, character, character.intelligence + 5)
character.dirtymoney += moneyIn character.dirtymoney += moneyIn
logs(ctx, "Карманная кража (Бумажник)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, moneyIn: moneyIn});
character.save() character.save()
return ctx.editMessageText(`Вы успешно украли Ð${utils.spaces(moneyIn)} из бумажника.`) return ctx.editMessageText(`Вы успешно украли Ð${utils.spaces(moneyIn)} из бумажника.`)
}); });
@ -778,7 +782,8 @@ rpg.action(`CARD_IN_WALLET`, async (ctx) => {
return ctx.editMessageText('Вы были замечены во время кражи.') return ctx.editMessageText('Вы были замечены во время кражи.')
} }
Exp(ctx, character, character.intelligence + 7) Exp(ctx, character, character.intelligence + 7)
generateCard(ctx.from.id) let newCard = generateCard(ctx.from.id)
logs(ctx, "Карманная кража (Карта)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, card: newCard});
character.save() character.save()
return ctx.editMessageText(`Вы успешно украли 💳 из бумажника.`) return ctx.editMessageText(`Вы успешно украли 💳 из бумажника.`)
}); });
@ -820,6 +825,7 @@ rpg.action(`POCKET_BAG`, async (ctx) => {
} }
Exp(ctx, character, character.intelligence + times) Exp(ctx, character, character.intelligence + times)
character.dirtymoney += moneyIn character.dirtymoney += moneyIn
logs(ctx, "Карманная кража (Сумка)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, moneyIn: moneyIn});
character.save() character.save()
return ctx.editMessageText(`Вы успешно украли сумку и сбыли все ценности из нее:\n${text}\nОбщий куш: Ð${utils.spaces(moneyIn)}`) return ctx.editMessageText(`Вы успешно украли сумку и сбыли все ценности из нее:\n${text}\nОбщий куш: Ð${utils.spaces(moneyIn)}`)
}); });
@ -848,6 +854,7 @@ rpg.action('SHOP_ACTION', async (ctx) => {
if (character.shoprobcd > cooldown.currentTime) return ctx.editMessageText(`📛 Данное действие будет доступно через ${cooldown.timeLeftInMinutes} мин.`); if (character.shoprobcd > cooldown.currentTime) return ctx.editMessageText(`📛 Данное действие будет доступно через ${cooldown.timeLeftInMinutes} мин.`);
character.shoprobcd = cooldown.endTime character.shoprobcd = cooldown.endTime
character.stamina -= 25 character.stamina -= 25
logs(ctx, "Ограбление магазина (Start)", {cdBefore: shoprobcd, cdAfter: character.shoprobcd, stamina: character.stamina});
character.save() character.save()
return ctx.editMessageText('Стадии:', Markup.inlineKeyboard([ return ctx.editMessageText('Стадии:', Markup.inlineKeyboard([
[{ text: 'Взлом кассы', callback_data: `SHOP_CASH_BREAK` }], [{ text: 'Взлом кассы', callback_data: `SHOP_CASH_BREAK` }],
@ -865,6 +872,7 @@ rpg.action(`SHOP_CASH_BREAK`, async (ctx) => {
if (chance < randomRoll) { if (chance < randomRoll) {
const keyboard = generateKeyboard(); const keyboard = generateKeyboard();
ctx.deleteMessage() ctx.deleteMessage()
logs(ctx, "Ограбление магазина (Взлом кассы ручной)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, keyboard: keyboard, cashIn: cashIn});
return ctx.reply('Касса закрыта, вы начали взлом замка:', keyboard); return ctx.reply('Касса закрыта, вы начали взлом замка:', keyboard);
//ctx.editMessageText('Вы начали взлом кассы.'); //ctx.editMessageText('Вы начали взлом кассы.');
//return ctx.scene.enter('LOCKPICK') //return ctx.scene.enter('LOCKPICK')
@ -884,6 +892,7 @@ rpg.action(`SHOP_CASH_BREAK`, async (ctx) => {
[{ text: 'Завершить ограбление', callback_data: `SHOP_END` }] [{ text: 'Завершить ограбление', callback_data: `SHOP_END` }]
])) ]))
}, timer + 300) }, timer + 300)
logs(ctx, "Ограбление магазина (Взлом кассы быстро)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, cashIn: cashIn});
}); });
rpg.action(`SHOP_CASH_SMASH`, async (ctx) => { rpg.action(`SHOP_CASH_SMASH`, async (ctx) => {
@ -913,6 +922,7 @@ rpg.action(`SHOP_CASH_SMASH`, async (ctx) => {
[{ text: 'Завершить ограбление', callback_data: `SHOP_END` }] [{ text: 'Завершить ограбление', callback_data: `SHOP_END` }]
])) ]))
}, timer + 300) }, timer + 300)
logs(ctx, "Ограбление магазина (Разбитие кассы)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, cashIn: cashIn});
}); });
rpg.action(`SHOP_CASH_BREAK_SUCCESS`, async (ctx) => { rpg.action(`SHOP_CASH_BREAK_SUCCESS`, async (ctx) => {
@ -936,6 +946,7 @@ rpg.action(`SHOP_CASH_BREAK_SUCCESS`, async (ctx) => {
[{ text: 'Завершить ограбление', callback_data: `SHOP_END` }] [{ text: 'Завершить ограбление', callback_data: `SHOP_END` }]
])) ]))
}, timer + 300) }, timer + 300)
logs(ctx, "Ограбление магазина (Взлом кассы)", {cashIn: cashIn});
}); });
rpg.action(`SHOP_END`, async (ctx) => { rpg.action(`SHOP_END`, async (ctx) => {
@ -959,9 +970,10 @@ rpg.action(/lock_*/, async (ctx) => {
// Проверяем, не исчерпаны ли попытки // Проверяем, не исчерпаны ли попытки
if (attempts[userId] >= 5) { if (attempts[userId] >= 5) {
delete attempts[userId]; // Сбрасываем попытки после провала delete attempts[userId]; // Сбрасываем попытки после провала
logs(ctx, "Взлом замка (Full Fail)", {attempts: attempts[userId]});
return ctx.editMessageText('Взлом провалился. Замок остается нетронутым.'); return ctx.editMessageText('Взлом провалился. Замок остается нетронутым.');
} }
logs(ctx, "Взлом замка (Fail)", {attempts: attempts[userId]});
// Ответ на нажатие кнопки // Ответ на нажатие кнопки
ctx.answerCbQuery(`Штифт не сдвинулся. Попыток осталось: ${5 - attempts[userId]}`); ctx.answerCbQuery(`Штифт не сдвинулся. Попыток осталось: ${5 - attempts[userId]}`);
removeButton(ctx, buttonId); removeButton(ctx, buttonId);
@ -1014,7 +1026,6 @@ rpg.action('inventory', async (ctx) => {
), ),
]; ];
buttons.push(Markup.button.callback('🔙 В меню', 'crime_menu')); buttons.push(Markup.button.callback('🔙 В меню', 'crime_menu'));
await ctx.editMessageText(message, Markup.inlineKeyboard(buttons, { columns: 2 })); await ctx.editMessageText(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
} catch (error) { } catch (error) {
console.error('Ошибка при выводе инвентаря:', error); console.error('Ошибка при выводе инвентаря:', error);
@ -1048,8 +1059,8 @@ rpg.action(/view_item_(\d+)/, async (ctx) => {
if (item.equipped && item.canBeEquipped) { if (item.equipped && item.canBeEquipped) {
buttons.push([Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_item_${item.id}`)]); buttons.push([Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_item_${item.id}`)]);
} }
logs(ctx, "Просмотр предмета", {item: item});
await ctx.replyWithMarkdown(message, Markup.inlineKeyboard(buttons, { columns: 2 })); await ctx.reply(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
}); });
rpg.action(/use_item_(\d+)/, async (ctx) => { rpg.action(/use_item_(\d+)/, async (ctx) => {
@ -1521,32 +1532,6 @@ const fillEnemies = async () => {
console.log("Enemies filled."); console.log("Enemies filled.");
}; };
const fillLocations = async () => {
const locations = [
{
name: "Заброшенный склад",
description: "Темный склад с кучей мусора.",
enemies: [1, 2, 3],
level: 1,
loot: [6, 7],
rarity: 1
},
{
name: "Лесопосадка",
description: "Густой лес с опасными тропами.",
enemies: [2, 3, 4],
level: 2,
loot: [8, 9],
rarity: 2
},
];
for (const location of locations) {
await Location.create(location);
}
console.log("Locations filled.");
};
const generateBattles = async () => { const generateBattles = async () => {
const locations = await Location.findAll(); const locations = await Location.findAll();
@ -1592,14 +1577,17 @@ const generateBattles = async () => {
generateBattles() generateBattles()
schedule.scheduleJob('0 * * * *', generateBattles); // Каждый час в начале часа schedule.scheduleJob('0 * * * *', generateBattles); // Каждый час в начале часа
rpg.command("locations", async (ctx) => {
rpg.action("locations", async (ctx) => {
const locations = await Location.findAll(); const locations = await Location.findAll();
if (!locations.length) { if (!locations.length) {
return ctx.reply("Нет доступных локаций для исследования."); return ctx.reply("Нет доступных локаций для исследования.");
} }
const locationButtons = locations.map((location) => ({ const locationButtons = locations.map((location) => ({
text: location.name, text: location.name + ` (${location.level} lvl.)`,
callback_data: `viewlocation_${location.id}`, callback_data: `viewlocation_${location.id}`,
})); }));
@ -1628,7 +1616,7 @@ rpg.action(/viewlocation_\d+/, async (ctx) => {
[{ text: "Охота", callback_data: `hunt_location_${location.id}` }], [{ text: "Охота", callback_data: `hunt_location_${location.id}` }],
]); ]);
await ctx.reply(description, keyboard); await ctx.editMessageText(description, keyboard);
}); });
rpg.action(/hunt_location_\d+/, async (ctx) => { rpg.action(/hunt_location_\d+/, async (ctx) => {
@ -1643,7 +1631,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
if (!character) { if (!character) {
return ctx.reply("Ваш персонаж не найден."); return ctx.reply("Ваш персонаж не найден.");
} }
logs(ctx, "Охота", {location: location});
const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } }); const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } });
const hasGrenadeLow = inventory.some((item) => item.text_id === "grenade_low"); const hasGrenadeLow = inventory.some((item) => item.text_id === "grenade_low");
const hasGrenadeMedium = inventory.some((item) => item.text_id === "grenade_medium"); const hasGrenadeMedium = inventory.some((item) => item.text_id === "grenade_medium");
@ -1651,7 +1639,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
const enemyIds = location.enemies || []; const enemyIds = location.enemies || [];
if (enemyIds.length === 0) { if (enemyIds.length === 0) {
return ctx.reply("В этой локации сейчас нет врагов. Попробуйте позже."); return ctx.answerCbQuery("В этой локации сейчас нет врагов. Попробуйте позже.");
} }
const activeBattles = await Battle.findAll({ const activeBattles = await Battle.findAll({
@ -1659,14 +1647,14 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
}); });
if (activeBattles.length === 0) { if (activeBattles.length === 0) {
return ctx.reply("В этой локации сейчас нет активных врагов. Попробуйте позже."); return ctx.answerCbQuery("В этой локации сейчас нет активных врагов. Попробуйте позже.");
} }
const activeEnemyIds = activeBattles.map((battle) => battle.enemy); const activeEnemyIds = activeBattles.map((battle) => battle.enemy);
const enemies = await Enemy.findAll({ where: { id: activeEnemyIds } }); const enemies = await Enemy.findAll({ where: { id: activeEnemyIds } });
if (enemies.length === 0) { if (enemies.length === 0) {
return ctx.reply("В этой локации сейчас нет врагов."); return ctx.answerCbQuery("В этой локации сейчас нет врагов.");
} }
const buttons = activeBattles.map((battle) => { const buttons = activeBattles.map((battle) => {
@ -1686,7 +1674,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
const keyboard = Markup.inlineKeyboard(buttons.map((btn) => [btn])); const keyboard = Markup.inlineKeyboard(buttons.map((btn) => [btn]));
await ctx.reply( await ctx.editMessageText(
`🔍 Локация: ${location.name}\n\nВыберите врага для охоты:`, `🔍 Локация: ${location.name}\n\nВыберите врага для охоты:`,
keyboard keyboard
); );
@ -1749,7 +1737,7 @@ rpg.action(/use_grenade_\d+/, async (ctx) => {
// Удаляем гранату из инвентаря // Удаляем гранату из инвентаря
await InventoryModel.destroy({ where: { id: grenade.id } }); await InventoryModel.destroy({ where: { id: grenade.id } });
await ctx.reply(message); await ctx.answerCbQuery(message, { show_alert: true });
}); });
@ -1920,20 +1908,20 @@ function generateBattleButtons(character, battle) {
// Генерация кнопки с критическим уроном // Генерация кнопки с критическим уроном
buttons.push({ buttons.push({
text: `💥`, text: `🎯`,
callback_data: `critical_${battle.id}`, callback_data: `critical_${battle.id}`,
}); });
// Гарантированная кнопка промаха // Гарантированная кнопка промаха
buttons.push({ buttons.push({
text: "", text: "🎯",
callback_data: `miss_${battle.id}`, callback_data: `miss_${battle.id}`,
}); });
// Заполнение оставшихся кнопок (если не хватает до totalButtons) // Заполнение оставшихся кнопок (если не хватает до totalButtons)
while (buttons.length < totalButtons) { while (buttons.length < totalButtons) {
buttons.push({ buttons.push({
text: "", text: "🎯",
callback_data: `miss_${battle.id}`, callback_data: `miss_${battle.id}`,
}); });
} }
@ -2055,40 +2043,4 @@ rpg.action(/miss_\d+/, async (ctx) => {
const fillItemsTable = async () => {
try {
const items = [];
// Генерируем 10 случайных предметов
for (let i = 0; i < 10; i++) {
const item = {
name: fakerRU.commerce.productName(), // Название товара
description: fakerRU.lorem.sentence(), // Описание товара
price: fakerRU.commerce.price({ dec: 0 }), // Цена товара
rarity: 1, // Редкость (от 1 до 5)
type: 'other', // Тип предмета
};
items.push(item);
}
// Вставляем все 10 предметов в таблицу
await ItemsModel.bulkCreate(items);
console.log('Таблица предметов успешно заполнена!');
} catch (error) {
console.error('Ошибка при заполнении таблицы предметов:', error);
}
};
// Запускаем функцию
//fillItemsTable();
module.exports = rpg; module.exports = rpg;

52
utils/logMiddleware.js Normal file
View File

@ -0,0 +1,52 @@
const fs = require("fs");
/**
* Middleware для логирования всех действий в боте.
*/
function logMiddleware(ctx, next) {
const logEntry = {
timestamp: new Date().toISOString(),
user: {
id: ctx.from?.id || "unknown",
username: ctx.from?.username || "unknown",
first_name: ctx.from?.first_name || "unknown",
last_name: ctx.from?.last_name || "",
},
chat: ctx.chat ? { id: ctx.chat.id, type: ctx.chat.type } : null,
type: ctx.updateType, // Тип обновления (message, callback_query и т.д.)
data: getDataFromContext(ctx), // Извлечение данных из контекста
};
const logString = JSON.stringify(logEntry, null, 2);
// Сохраняем лог в файл
fs.appendFile('./json/logs.json', logString + "\n", (err) => {
if (err) {
console.error("Ошибка при записи лога:", err);
}
});
// Вызываем следующий middleware
return next();
}
/**
* Извлечение данных из контекста (например, текст сообщения или данные кнопки).
*/
function getDataFromContext(ctx) {
if (ctx.message) {
return { text: ctx.message.text || "нет текста", message_id: ctx.message.message_id };
}
if (ctx.callbackQuery) {
return { data: ctx.callbackQuery.data || "нет данных", id: ctx.callbackQuery.id };
}
if (ctx.inlineQuery) {
return { query: ctx.inlineQuery.query || "пустой запрос" };
}
return "неизвестное событие";
}
module.exports = logMiddleware;

34
utils/logs.js Normal file
View File

@ -0,0 +1,34 @@
const fs = require("fs");
const path = require("path");
/**
* Функция для записи логов.
* @param {Object} ctx - Контекст Telegraf (содержит данные о пользователе и сообщении).
* @param {String} action - Описание действия, например, "Начало битвы", "Использована граната".
* @param {Object} [extraData] - Дополнительные данные для логов.
*/
function logAction(ctx, action, extraData = {}) {
const logEntry = {
timestamp: new Date().toISOString(),
user: {
id: ctx.from.id,
username: ctx.from.username || "unknown",
first_name: ctx.from.first_name || "unknown",
last_name: ctx.from.last_name || "",
},
chat: ctx.chat ? { id: ctx.chat.id, type: ctx.chat.type } : null,
action,
extraData,
};
const logString = JSON.stringify(logEntry, null, 2);
// Сохраняем лог в файл
fs.appendFile('./json/logs.json', logString + "\n", (err) => {
if (err) {
console.error("Ошибка при записи лога:", err);
}
});
}
module.exports = logAction;