- Клиентская часть Vue 3 + Vite - Серверная часть Node.js + WebSocket - Система авторизации и смен - Управление игровыми портами - Поддержка тем (светлая/темная) - Адаптивный дизайн 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
178 lines
7.1 KiB
JavaScript
178 lines
7.1 KiB
JavaScript
const fs = require('node:fs/promises');
|
||
const path = require('path');
|
||
|
||
/**
|
||
* Утилита инициализации конфигурационных файлов
|
||
* Создает необходимые INI файлы с правильной структурой и значениями по умолчанию
|
||
*/
|
||
|
||
const defaultConfigs = {
|
||
// ESP настройки - согласно документации CFG_SETTINGS_DOCUMENTATION.md
|
||
'esp.ini': {
|
||
hz: 14000, // Частота ESP контроллера
|
||
maxA: 80, // Максимальный ток на каждый порт
|
||
MaxTime: 140000, // Максимальное время выстрела
|
||
maxShot: 2, // Максимальное количество одновременных выстрелов
|
||
zvtime: 95000, // Заданное время выстрела
|
||
otime: 4 // Заданное время осечки
|
||
},
|
||
|
||
// Состояние игровых портов - согласно документации INI_FILES_STRUCTURE_DOCUMENTATION.md
|
||
'game.ini': [
|
||
{
|
||
"_testing": 12345, // Проверка целостности файла
|
||
"pause": false, // Пауза системы
|
||
"gamersCounter": 0, // Счетчик игроков в смене
|
||
"init": null, // Кто поставил паузу
|
||
"sharik": { // Настройки игры "Шарик"
|
||
"playersCounter": 0,
|
||
"startTime": null,
|
||
"playerId": null
|
||
},
|
||
"tehSmenaMaxDuration": 8, // Максимальная длительность тех. смены в часах (по умолчанию 8)
|
||
"gameTimeouts": { // Настройки таймаутов для разных типов игр
|
||
"default": 1, // Обычные игры - 1 час
|
||
"operatorPristrelka": 1, // Пристрелка оператора - 1 час
|
||
"technicianPristrelka": 12 // Пристрелка техника - 12 часов
|
||
}
|
||
},
|
||
// Порты 1-6 с начальным состоянием
|
||
...Array(6).fill(null).map(() => ({
|
||
"game": 0, // ID активной игры (0 = нет игры)
|
||
"patr": 0, // Оставшиеся патроны
|
||
"gamer": { // Данные игрока
|
||
"gamerId": null,
|
||
"games": []
|
||
}
|
||
}))
|
||
],
|
||
|
||
// Информация об играх
|
||
'info.ini': {
|
||
"groups": {
|
||
"1": { "title": "Технические", "img": "tech.png" },
|
||
"10": { "title": "По банкам", "img": "po_bankam.png" },
|
||
"11": { "title": "По мишеням", "img": "po_mish.png" },
|
||
"12": { "title": "Беспроигрышные", "img": "bez_proig.png" }
|
||
},
|
||
"games": {
|
||
// Технические игры (добавляются автоматически)
|
||
"1": {
|
||
"_id": 1,
|
||
"group": 1,
|
||
"patr": 999,
|
||
"title": "Пристрелка",
|
||
"info": "техническая игра",
|
||
"cost": 0,
|
||
"color": "red",
|
||
"priz": 0,
|
||
"isGameActive": "вкл",
|
||
"gpriz": false,
|
||
"ver": 1
|
||
},
|
||
"2": {
|
||
"_id": 2,
|
||
"group": 1,
|
||
"patr": 999,
|
||
"title": "Пристрелка",
|
||
"info": "пристрелка для техников",
|
||
"cost": 0,
|
||
"color": "red",
|
||
"priz": 0,
|
||
"isGameActive": "вкл",
|
||
"gpriz": false,
|
||
"ver": 1
|
||
},
|
||
// Пример основной игры
|
||
"11": {
|
||
"_id": 11,
|
||
"group": 10,
|
||
"patr": "20",
|
||
"title": "Малая призовая",
|
||
"info": "20 выстрелов, малый приз с выбором",
|
||
"cost": "400",
|
||
"color": "#fa0000",
|
||
"priz": 1,
|
||
"isGameActive": "вкл",
|
||
"gpriz": false,
|
||
"ver": 1
|
||
}
|
||
}
|
||
},
|
||
|
||
// Кэш авторизованных администраторов
|
||
'avt.ini': {},
|
||
|
||
// Версия ПО для системы обновлений
|
||
'verSoft.ini': { "ver": 1 }
|
||
};
|
||
|
||
/**
|
||
* Проверяет существование файла и создает его с дефолтным содержимым если не существует
|
||
* @param {string} filename - имя файла
|
||
* @param {any} defaultContent - содержимое по умолчанию
|
||
*/
|
||
async function ensureConfigFile(filename, defaultContent) {
|
||
const filePath = path.join('./data', filename);
|
||
|
||
try {
|
||
// Проверяем существование файла
|
||
await fs.access(filePath);
|
||
|
||
// Файл существует, проверяем его содержимое
|
||
const content = await fs.readFile(filePath, 'utf-8');
|
||
const parsedContent = JSON.parse(content);
|
||
|
||
// Если файл пустой или содержит только {}, инициализируем его
|
||
if (Object.keys(parsedContent).length === 0) {
|
||
console.log(`[init-config] 📝 Файл ${filename} пустой, инициализирую значениями по умолчанию`);
|
||
await fs.writeFile(filePath, JSON.stringify(defaultContent, null, 2));
|
||
} else {
|
||
console.log(`[init-config] ✅ Файл ${filename} уже существует и содержит данные`);
|
||
}
|
||
|
||
} catch (error) {
|
||
if (error.code === 'ENOENT') {
|
||
// Файл не существует, создаем его
|
||
console.log(`[init-config] 🆕 Создаю файл ${filename} с настройками по умолчанию`);
|
||
await fs.writeFile(filePath, JSON.stringify(defaultContent, null, 2));
|
||
} else {
|
||
console.error(`[init-config] ❌ Ошибка при работе с файлом ${filename}:`, error);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Инициализирует все конфигурационные файлы
|
||
*/
|
||
async function initializeConfigs() {
|
||
console.log('[init-config] 🚀 Начинаю инициализацию конфигурационных файлов');
|
||
|
||
// Создаем папку data если не существует
|
||
try {
|
||
await fs.mkdir('./data', { recursive: true });
|
||
console.log('[init-config] 📁 Папка data создана или уже существует');
|
||
} catch (error) {
|
||
console.error('[init-config] ❌ Ошибка создания папки data:', error);
|
||
return;
|
||
}
|
||
|
||
// Инициализируем все файлы
|
||
for (const [filename, defaultContent] of Object.entries(defaultConfigs)) {
|
||
await ensureConfigFile(filename, defaultContent);
|
||
}
|
||
|
||
console.log('[init-config] ✅ Инициализация конфигурационных файлов завершена');
|
||
}
|
||
|
||
// Экспортируем функции для использования в других модулях
|
||
module.exports = {
|
||
initializeConfigs,
|
||
ensureConfigFile,
|
||
defaultConfigs
|
||
};
|
||
|
||
// Если модуль запущен напрямую, выполняем инициализацию
|
||
if (require.main === module) {
|
||
initializeConfigs().catch(console.error);
|
||
}
|