'use strict'; /** * ╔══════════════════════════════════════════════════════════════════════════╗ * Server Optimizer — v1.0 | تحسين السيرفر في الأوقات الحرجة والمتوسطة ║ * ╠══════════════════════════════════════════════════════════════════════════╣ * ✅ مراقبة مستمرة: TPS + RAM + Entities + Chunks + Players ║ * ✅ 3 أوضاع: CRITICAL / MODERATE / NORMAL ║ * ✅ تحسين تلقائي: تقليل البوتات + تعطيل Pathfinding + تقليل الرسائل ║ * ✅ تحليل ذكي: أنماط الأداء + توصيات + تنبؤ بالمشاكل ║ * ✅ تنسيق مع البوتات: إرسال أوامر تعطيل/تفعيل حسب الحالة ║ * ✅ تقارير دورية: ملخص أداء كل 5 دقائق ║ * ╚══════════════════════════════════════════════════════════════════════════╝ */ const { EventEmitter } = require('events'); const tsNow = () => new Date().toISOString().replace('T', ' ').slice(0, 19); const sleep = ms => new Promise(r => setTimeout(r, Math.max(0, ms))); // ═══════════════════════════════════════════════════════════════════════════ // الحدود والعتبات (Thresholds) // ═══════════════════════════════════════════════════════════════════════════ const THRESHOLDS = { // ─── CRITICAL (أقل من كده السيرفر بيموت) ─────────────────────────────── critical: { tps: 10, // TPS أقل من 10 ram: 92, // RAM أعلى من 92% entities: 200, // Entities أعلى من 200 chunkRate: 50, // Chunks per second أقل من 50 playerPing: 500, // Ping أعلى من 500ms }, // ─── MODERATE (فيه ضغط بس لسه شغال) ─────────────────────────────────── moderate: { tps: 16, // TPS أقل من 16 ram: 80, // RAM أعلى من 80% entities: 120, // Entities أعلى من 120 chunkRate: 100, // Chunks per second أقل من 100 playerPing: 300, // Ping أعلى من 300ms }, // ─── NORMAL (كل حاجة تمام) ───────────────────────────────────────────── normal: { tps: 19, ram: 65, entities: 60, chunkRate: 200, playerPing: 150, } }; // ═══════════════════════════════════════════════════════════════════════════ // إعدادات كل وضع // ═══════════════════════════════════════════════════════════════════════════ const MODE_CONFIGS = { // ─── CRITICAL: أقل نشاط ممكن ──────────────────────────────────────────── critical: { label: '🔴 حرج', botActivity: 'minimal', // أقل نشاط pathfinding: false, // تعطيل Pathfinding تماماً chatFrequency: 0, // تعطيل الرسائل taskInterval: 60000, // المهام كل دقيقة maxActiveBots: 2, // أقل عدد بوتات شغالة autoEat: true, // الأكل شغال دايماً autoSleep: true, // النوم شغال combatResponse: 'flee', // الهروب بس miningEnabled: false, // تعطيل التعدين buildingEnabled: false, // تعطيل البناء farmingEnabled: false, // تعطيل الزراعة explorationEnabled: false, // تعطيل الاستكشاف tradingEnabled: false, // تعطيل التجارة socialEnabled: false, // تعطيل التفاعل dailyRoutine: false, // تعطيل الروتين اليومي antiAfk: 'sleep', // بس نوم viewDistance: 'tiny', // أقل مسافة رؤية }, // ─── MODERATE: نشاط متوسط ─────────────────────────────────────────────── moderate: { label: '🟡 متوسط', botActivity: 'reduced', // نشاط مخفف pathfinding: true, // Pathfinding شغال بس بطيء chatFrequency: 0.3, // 30% من الرسائل العادية taskInterval: 30000, // المهام كل 30 ثانية maxActiveBots: 4, // 4 بوتات كحد أقصى autoEat: true, autoSleep: true, combatResponse: 'fight', // قتال عادي miningEnabled: true, buildingEnabled: true, farmingEnabled: true, explorationEnabled: false, // الاستكشاف متوقف tradingEnabled: false, // التجارة متوقفة socialEnabled: true, dailyRoutine: true, antiAfk: 'moderate', // حركة متوسطة viewDistance: 'short', // مسافة رؤية قصيرة }, // ─── NORMAL: كل حاجة شغالة ────────────────────────────────────────────── normal: { label: '🟢 طبيعي', botActivity: 'full', // نشاط كامل pathfinding: true, chatFrequency: 1.0, // كل الرسائل taskInterval: 15000, // المهام كل 15 ثانية maxActiveBots: 10, // كل البوتات autoEat: true, autoSleep: true, combatResponse: 'fight', miningEnabled: true, buildingEnabled: true, farmingEnabled: true, explorationEnabled: true, tradingEnabled: true, socialEnabled: true, dailyRoutine: true, antiAfk: 'full', // حركة كاملة viewDistance: 'normal', // مسافة رؤية عادية } }; // ═══════════════════════════════════════════════════════════════════════════ // ServerOptimizer Class // ═══════════════════════════════════════════════════════════════════════════ class ServerOptimizer extends EventEmitter { constructor(config = {}) { super(); this.config = { checkInterval: config.checkInterval || 10000, // فحص كل 10 ثواني reportInterval: config.reportInterval || 300000, // تقرير كل 5 دقائق historySize: config.historySize || 300, // 50 دقيقة من البيانات recoveryDelay: config.recoveryDelay || 60000, // دقيقة قبل الرجوع من CRITICAL autoModeSwitch: config.autoModeSwitch !== false, // تغيير تلقائي للوضع ...config }; // ─── الحالة الحالية ─────────────────────────────────────────────────── this.currentMode = 'normal'; // الوضع الحالي this.previousMode = 'normal'; // الوضع السابق this.modeStartTime = Date.now(); // وقت بدء الوضع الحالي this.modeTransitionPending = null; // تغيير وشيك this.modeTransitionTimer = null; // مؤقت التغيير // ─── البيانات ───────────────────────────────────────────────────────── this.metrics = { tps: 20, ram: 50, entities: 0, chunks: 0, players: 0, ping: 0, worldTime: 0, uptime: 0, botCount: 0, activeBots: 0, }; this.history = []; this.alerts = []; this.optimizations = []; this.stats = { modeChanges: 0, optimizationsApplied: 0, criticalEvents: 0, moderateEvents: 0, normalEvents: 0, totalChecks: 0, avgTps: 20, avgRam: 50, worstTps: 20, worstRam: 50, }; // ─── البوتات المتصلة ────────────────────────────────────────────────── this.connectedBots = new Map(); // botId → { bot, mode, lastAction } this._running = false; this._checkTimer = null; this._reportTimer = null; this._log('OPTIMIZER', 'تم إنشاء Server Optimizer v1.0'); } _log(tag, msg) { console.log(`[${tsNow()}] [OPTIMIZER] ${tag} ${msg}`); } // ═══════════════════════════════════════════════════════════════════════════ // بدء/إيقاف التحسين // ═══════════════════════════════════════════════════════════════════════════ start() { if (this._running) return; this._running = true; this._log('🟢', 'بدء مراقبة وتحسين السيرفر...'); this._checkTimer = setInterval(() => this._check(), this.config.checkInterval); this._reportTimer = setInterval(() => this._report(), this.config.reportInterval); this._optimCycleTimer = setInterval(() => this._runOptimizationCycle(), 30000); this._check(); this._report(); } stop() { this._running = false; if (this._checkTimer) { clearInterval(this._checkTimer); this._checkTimer = null; } if (this._reportTimer) { clearInterval(this._reportTimer); this._reportTimer = null; } if (this.modeTransitionTimer) { clearTimeout(this.modeTransitionTimer); this.modeTransitionTimer = null; } if (this._optimCycleTimer) { clearInterval(this._optimCycleTimer); this._optimCycleTimer = null; } this._log('🔴', 'إيقاف Server Optimizer'); } // ═══════════════════════════════════════════════════════════════════════════ // التحقق الرئيسي (كل 10 ثواني) // ═══════════════════════════════════════════════════════════════════════════ async _check() { if (!this._running) return; this.stats.totalChecks++; try { // ─── تحليل الحالة ─────────────────────────────────────────────────── const analysis = this._analyzeMetrics(); const newMode = analysis.recommendedMode; // ─── تحديث الإحصائيات ─────────────────────────────────────────────── this._updateStats(); // ─── حفظ في التاريخ ───────────────────────────────────────────────── this.history.push({ time: Date.now(), mode: this.currentMode, tps: this.metrics.tps, ram: this.metrics.ram, entities: this.metrics.entities, players: this.metrics.players, analysis: analysis.reasons }); if (this.history.length > this.config.historySize) this.history.shift(); // ─── تغيير الوضع إذا لزم ────────────────────────────────────────── if (this.config.autoModeSwitch && newMode !== this.currentMode) { this._requestModeChange(newMode, analysis.reasons); } // ─── تطبيق التحسينات على البوتات ──────────────────────────────────── this._applyOptimizations(); // ─── إرسال الأحداث ────────────────────────────────────────────────── this.emit('check', { mode: this.currentMode, metrics: { ...this.metrics }, analysis }); } catch (err) { this._log('❌', `خطأ في الفحص: ${err.message}`); } } // ═══════════════════════════════════════════════════════════════════════════ // تحليل المقاييس وتحديد الوضع // ═══════════════════════════════════════════════════════════════════════════ _analyzeMetrics() { const m = this.metrics; const reasons = []; let score = 0; // 0-100 (0=حرج, 100=ممتاز) // ─── تحليل TPS ──────────────────────────────────────────────────────── if (m.tps <= THRESHOLDS.critical.tps) { score -= 40; reasons.push(`TPS حرج: ${m.tps}`); } else if (m.tps <= THRESHOLDS.moderate.tps) { score -= 20; reasons.push(`TPS منخفض: ${m.tps}`); } else { score += 20; } // ─── تحليل RAM ──────────────────────────────────────────────────────── if (m.ram >= THRESHOLDS.critical.ram) { score -= 30; reasons.push(`RAM حرج: ${m.ram}%`); } else if (m.ram >= THRESHOLDS.moderate.ram) { score -= 15; reasons.push(`RAM مرتفع: ${m.ram}%`); } else { score += 15; } // ─── تحليل Entities ─────────────────────────────────────────────────── if (m.entities >= THRESHOLDS.critical.entities) { score -= 15; reasons.push(`Entities كتير: ${m.entities}`); } else if (m.entities >= THRESHOLDS.moderate.entities) { score -= 8; reasons.push(`Entities متوسط: ${m.entities}`); } else { score += 10; } // ─── تحليل اللاعبين ────────────────────────────────────────────────── if (m.players > 10) { score -= 10; reasons.push(`لاعبين كتير: ${m.players}`); } else if (m.players > 5) { score -= 5; } else { score += 5; } // ─── تحليل البوتات ──────────────────────────────────────────────────── const activeBots = this.connectedBots.size; if (activeBots > 6) { score -= 10; reasons.push(`بوتات كتير شغالة: ${activeBots}`); } else if (activeBots > 3) { score -= 5; } else { score += 5; } // ─── تحديد الوضع ────────────────────────────────────────────────────── let recommendedMode; if (score <= 20) { recommendedMode = 'critical'; } else if (score <= 35) { recommendedMode = 'moderate'; } else { recommendedMode = 'normal'; } // ─── تحليل الاتجاه (هل Situation بتتحسن أو بت tệ؟) ────────────────── const trend = this._analyzeTrend(); return { score: Math.max(0, Math.min(100, score)), recommendedMode, reasons, trend, details: { tpsStatus: m.tps >= 19 ? '🟢' : m.tps >= 16 ? '🟡' : '🔴', ramStatus: m.ram <= 65 ? '🟢' : m.ram <= 80 ? '🟡' : '🔴', entityStatus: m.entities <= 60 ? '🟢' : m.entities <= 120 ? '🟡' : '🔴', } }; } _analyzeTrend() { if (this.history.length < 10) return 'stable'; const recent = this.history.slice(-10); const older = this.history.slice(-20, -10); if (older.length === 0) return 'stable'; const recentAvgTps = recent.reduce((s, h) => s + h.tps, 0) / recent.length; const olderAvgTps = older.reduce((s, h) => s + h.tps, 0) / older.length; if (recentAvgTps > olderAvgTps + 2) return 'improving'; if (recentAvgTps < olderAvgTps - 2) return 'worsening'; return 'stable'; } // ═══════════════════════════════════════════════════════════════════════════ // تغيير الوضع // ═══════════════════════════════════════════════════════════════════════════ _requestModeChange(newMode, reasons) { // ─── CRITICAL: تغيير فوري ────────────────────────────────────────────── if (newMode === 'critical') { this._switchMode(newMode, reasons); return; } // ─── MODERATE → NORMAL: انتظار 30 ثانية للتأكد ────────────────────────── if (this.currentMode === 'critical' && newMode === 'moderate') { if (this.modeTransitionPending === 'moderate') { // انتظر أكثر return; } this.modeTransitionPending = 'moderate'; this._log('⏳', 'انتظار 30 ثانية للرجوع من CRITICAL...'); this.modeTransitionTimer = setTimeout(() => { this._switchMode('moderate', reasons); this.modeTransitionPending = null; }, 30000); return; } // ─── MODERATE → NORMAL: انتظار دقيقة ──────────────────────────────────── if (this.currentMode === 'moderate' && newMode === 'normal') { if (this.modeTransitionPending === 'normal') return; this.modeTransitionPending = 'normal'; this._log('⏳', 'انتظار 60 ثانية للرجوع من MODERATE...'); this.modeTransitionTimer = setTimeout(() => { this._switchMode('normal', reasons); this.modeTransitionPending = null; }, 60000); return; } // ─── أي تغيير تاني: فوري ────────────────────────────────────────────── this._switchMode(newMode, reasons); } _switchMode(newMode, reasons) { if (this.modeTransitionTimer) { clearTimeout(this.modeTransitionTimer); this.modeTransitionTimer = null; } this.modeTransitionPending = null; const oldMode = this.currentMode; this.previousMode = oldMode; this.currentMode = newMode; this.modeStartTime = Date.now(); this.stats.modeChanges++; if (newMode === 'critical') this.stats.criticalEvents++; else if (newMode === 'moderate') this.stats.moderateEvents++; else this.stats.normalEvents++; const config = MODE_CONFIGS[newMode]; this._log('🔄', `تغيير الوضع: ${MODE_CONFIGS[oldMode].label} → ${config.label}`); this._log('📋', `الأسباب: ${reasons.join(', ')}`); // ─── إرسال أحداث ────────────────────────────────────────────────────── this.emit('modeChange', { from: oldMode, to: newMode, config, reasons, timestamp: Date.now() }); // ─── إشعار البوتات ──────────────────────────────────────────────────── this._notifyBotsModeChange(newMode, config); } // ═══════════════════════════════════════════════════════════════════════════ // إدارة البوتات المتصلة // ═══════════════════════════════════════════════════════════════════════════ registerBot(botId, bot) { this.connectedBots.set(botId, { bot, mode: this.currentMode, lastAction: Date.now(), disabled: false, pathfindingEnabled: true, chatEnabled: true, }); this._log('🤖', `بوت مسجل: ${botId} (${this.connectedBots.size} بوت)`); this._applyBotMode(botId); } unregisterBot(botId) { this.connectedBots.delete(botId); this._log('👋', `بوت انفصل: ${botId} (${this.connectedBots.size} بوت)`); } _notifyBotsModeChange(newMode, config) { this.connectedBots.forEach((data, botId) => { data.mode = newMode; this._applyBotMode(botId); }); } _applyBotMode(botId) { const data = this.connectedBots.get(botId); if (!data || !data.bot) return; const config = MODE_CONFIGS[this.currentMode]; try { // ─── تعطيل/تفعيل Pathfinding ──────────────────────────────────────── data.pathfindingEnabled = config.pathfinding; // ─── تعطيل/تفعيل الرسائل ──────────────────────────────────────────── data.chatEnabled = config.chatFrequency > 0; // ─── تقليل نشاط البوت ──────────────────────────────────────────────── if (config.botActivity === 'minimal') { data.bot._optimizerMode = 'minimal'; } else if (config.botActivity === 'reduced') { data.bot._optimizerMode = 'reduced'; } else { data.bot._optimizerMode = 'full'; } this._log('⚙️', ` Bot ${botId}: وضع ${config.label}`); } catch (err) { this._log('❌', `خطأ في تطبيق الوضع على ${botId}: ${err.message}`); } } _runOptimizationCycle() { const bots = [...this.connectedBots.values()].filter(d => d.bot && !d.disabled); if (bots.length === 0) return; const b = bots[0].bot; if (!b) return; try { b.chat('/tps'); } catch(_) {} setTimeout(() => { if (!b) return; try { b.chat('/lagg clear'); } catch(_) {} if (this.currentMode === 'critical') { setTimeout(() => { if (!b) return; try { b.chat('/lagg clear'); } catch(_) {} setTimeout(() => { if (!b) return; try { b.chat('/minecraft:kill @e[type=item]'); } catch(_) {} }, 500); }, 500); } }, 500); } _applyOptimizations() { const config = MODE_CONFIGS[this.currentMode]; this.connectedBots.forEach((data, botId) => { if (!data.bot) return; try { // ─── في الوضع الحرج: تقليل كل حاجة ──────────────────────────────── if (this.currentMode === 'critical') { // ─── إيقاف أي حركة ────────────────────────────────────────────── if (data.bot.pathfinder && data.pathfindingEnabled) { data.pathfindingEnabled = false; } // ─── إيقاف التعدين ────────────────────────────────────────────── if (data.bot._mining && config.miningEnabled === false) { data.bot._mining = false; } // ─── إيقاف البناء ────────────────────────────────────────────── if (data.bot._building && config.buildingEnabled === false) { data.bot._building = false; } } // ─── في الوضع المتوسط: تقليل النشاط ────────────────────────────── if (this.currentMode === 'moderate') { // ─── تقليل سرعة Pathfinding ───────────────────────────────────── if (data.bot.pathfinder && data.pathfindingEnabled) { data.bot.pathfinder.setTicksPerTick(2); // بطيء } } // ─── في الوضع الطبيعي: كل حاجة شغالة ────────────────────────────── if (this.currentMode === 'normal') { if (data.bot.pathfinder && !data.pathfindingEnabled) { data.pathfindingEnabled = true; } if (data.bot.pathfinder) { data.bot.pathfinder.setTicksPerTick(1); // عادي } } } catch (err) { // تجاهل الأخطاء } }); } // ═══════════════════════════════════════════════════════════════════════════ // تحديث المقاييس (يتم استدعاؤه من внешние أنظمة) // ═══════════════════════════════════════════════════════════════════════════ updateMetrics(newMetrics) { Object.assign(this.metrics, newMetrics); } updateTps(tps) { this.metrics.tps = tps; } updateRam(ramPercent) { this.metrics.ram = ramPercent; } updateEntities(count) { this.metrics.entities = count; } updatePlayers(count) { this.metrics.players = count; } // ═══════════════════════════════════════════════════════════════════════════ // تحديث الإحصائيات // ═══════════════════════════════════════════════════════════════════════════ _updateStats() { const m = this.metrics; const n = this.stats.totalChecks; this.stats.avgTps = ((this.stats.avgTps * (n - 1)) + m.tps) / n; this.stats.avgRam = ((this.stats.avgRam * (n - 1)) + m.ram) / n; this.stats.worstTps = Math.min(this.stats.worstTps, m.tps); this.stats.worstRam = Math.max(this.stats.worstRam, m.ram); } // ═══════════════════════════════════════════════════════════════════════════ // التقارير الدورية // ═══════════════════════════════════════════════════════════════════════════ _report() { if (!this._running) return; const m = this.metrics; const config = MODE_CONFIGS[this.currentMode]; const uptime = Date.now() - this.modeStartTime; const uptimeMin = Math.floor(uptime / 60000); this._log('📊', '═══════════════════════════════════════════════'); this._log('📊', `الوضع الحالي: ${config.label}`); this._log('📊', `TPS: ${m.tps} | RAM: ${m.ram}% | Entities: ${m.entities} | Players: ${m.players}`); this._log('📊', `بوتات متصلة: ${this.connectedBots.size}`); this._log('📊', `مدة الوضع الحالي: ${uptimeMin} دقيقة`); this._log('📊', `تغييرات الوضع: ${this.stats.modeChanges} | أحداث حرجة: ${this.stats.criticalEvents}`); this._log('📊', `TPS المتوسط: ${this.stats.avgTps.toFixed(1)} | Worst: ${this.stats.worstTps}`); this._log('📊', `RAM المتوسط: ${this.stats.avgRam.toFixed(1)}% | Worst: ${this.stats.worstRam}%`); this._log('📊', '═══════════════════════════════════════════════'); this.emit('report', this.getStatus()); } // ═══════════════════════════════════════════════════════════════════════════ // الحصول على الحالة الكاملة // ═══════════════════════════════════════════════════════════════════════════ getStatus() { const config = MODE_CONFIGS[this.currentMode]; const uptime = Date.now() - this.modeStartTime; return { running: this._running, currentMode: this.currentMode, modeLabel: config.label, previousMode: this.previousMode, modeUptime: uptime, modeUptimeMin: Math.floor(uptime / 60000), metrics: { ...this.metrics }, config: { ...config }, stats: { ...this.stats }, connectedBots: this.connectedBots.size, historySize: this.history.length, analysis: this._analyzeMetrics(), recommendations: this._getRecommendations(), }; } // ═══════════════════════════════════════════════════════════════════════════ // التوصيات الذكية // ═══════════════════════════════════════════════════════════════════════════ _getRecommendations() { const recs = []; const m = this.metrics; if (m.tps < 14) { recs.push({ priority: 'high', type: 'tps', message: 'TPS منخفض جداً — قلل عدد البوتات أو عطّل بعض الميزات', action: 'reduce_bots' }); } if (m.ram > 85) { recs.push({ priority: 'high', type: 'ram', message: 'RAM عالي جداً — شغّل GC يدوياً أو قلل الكاش', action: 'force_gc' }); } if (m.entities > 150) { recs.push({ priority: 'medium', type: 'entities', message: 'عدد Entities كبير — قلل مسافة الرؤية أو عطّل بعض الميزات', action: 'reduce_view' }); } if (this.connectedBots.size > 5) { recs.push({ priority: 'medium', type: 'bots', message: `عدد البوتات كبير (${this.connectedBots.size}) — قلل العدد`, action: 'reduce_bots' }); } if (this.stats.worstTps < 8) { recs.push({ priority: 'low', type: 'history', message: `وصل TPS لـ ${this.stats.worstTps} قبل كده — راقب الأسباب`, action: 'monitor' }); } return recs; } // ═══════════════════════════════════════════════════════════════════════════ // التحكم اليدوي // ═══════════════════════════════════════════════════════════════════════════ setMode(mode) { if (!MODE_CONFIGS[mode]) { this._log('❌', `وضع غير صحيح: ${mode}`); return false; } this._switchMode(mode, ['manual_override']); this._log(' manual', `تم تغيير الوضع يدوياً إلى: ${MODE_CONFIGS[mode].label}`); return true; } forceOptimization() { this._log('🔧', 'تحسين إجباري...'); this._applyOptimizations(); this.stats.optimizationsApplied++; return true; } getModeConfig(mode) { return MODE_CONFIGS[mode] ? { ...MODE_CONFIGS[mode] } : null; } getHistory(minutes = 30) { const cutoff = Date.now() - (minutes * 60000); return this.history.filter(h => h.time >= cutoff); } destroy() { this.stop(); this.connectedBots.clear(); this.history = []; this.alerts = []; this.optimizations = []; this.removeAllListeners(); } } module.exports = { ServerOptimizer, THRESHOLDS, MODE_CONFIGS };