namespace Supercell.Laser.Server.Message { using Supercell.Laser.Server.Networking; using Supercell.Laser.Server.Settings; using System.Collections.Concurrent; using Supercell.Laser.Logic.Message; public static class Processor { private static BlockingCollection IncomingQueue; private static BlockingCollection OutgoingQueue; private static CancellationTokenSource Cts; private static List ReceiveTasks; private static List SendTasks; private struct QueueItem { public readonly Connection Connection; public readonly GameMessage Message; public QueueItem(Connection connection, GameMessage message) { Connection = connection; Message = message; } } public static void Init() { // Лимит очереди управляется из config.json (queue_limit_enabled). // Выключен => безлимитные очереди, пакеты принимаются бесконечно. // Включён => ограничены queue_limit_size (по умолчанию 4096). bool limitEnabled = Configuration.Instance != null && Configuration.Instance.QueueLimitEnabled; if (limitEnabled) { int size = Configuration.Instance.QueueLimitSize > 0 ? Configuration.Instance.QueueLimitSize : 4096; IncomingQueue = new BlockingCollection(size); OutgoingQueue = new BlockingCollection(size); Logger.Print($"[Processor] Лимит очереди ВКЛЮЧЁН: {size}"); } else { IncomingQueue = new BlockingCollection(); OutgoingQueue = new BlockingCollection(); Logger.Print("[Processor] Лимит очереди ВЫКЛЮЧЕН (безлимит, приём бесконечный)"); } Cts = new CancellationTokenSource(); ReceiveTasks = new List(); SendTasks = new List(); int cores = Environment.ProcessorCount; // ИСПРАВЛЕНИЕ #3: используем все ядра для обработки пакетов. // Было: Math.Min(cores, 4) — на 6-ядерном CPU = 4 потока (2 ядра простаивали). // Стало: cores receive + max(cores/2, 2) send — все ядра в деле. int receiveThreads = cores; int sendThreads = Math.Max(cores / 2, 2); Logger.Print($"[Processor] Потоки: receive={receiveThreads}, send={sendThreads} (ядер: {cores})"); for (int i = 0; i < receiveThreads; i++) ReceiveTasks.Add(Task.Run(UpdateReceive)); for (int i = 0; i < sendThreads; i++) SendTasks.Add(Task.Run(UpdateSend)); } public static void Shutdown() { Cts.Cancel(); IncomingQueue.CompleteAdding(); OutgoingQueue.CompleteAdding(); Task.WaitAll(ReceiveTasks.ToArray(), 5000); Task.WaitAll(SendTasks.ToArray(), 5000); Cts.Dispose(); IncomingQueue.Dispose(); OutgoingQueue.Dispose(); } public static bool Receive(Connection connection, GameMessage message) { if (message == null || Cts.IsCancellationRequested) return false; return IncomingQueue.TryAdd(new QueueItem(connection, message)); } public static void Send(Connection connection, GameMessage message) { if (message == null || Cts.IsCancellationRequested) return; OutgoingQueue.TryAdd(new QueueItem(connection, message)); } private static void UpdateReceive() { try { foreach (var item in IncomingQueue.GetConsumingEnumerable(Cts.Token)) { try { item.Connection.MessageManager.ReceiveMessage(item.Message); } catch (Exception e) { Logger.Print($"Receive error: {e.Message}"); } } } catch (OperationCanceledException) { } } private static void UpdateSend() { try { foreach (var item in OutgoingQueue.GetConsumingEnumerable(Cts.Token)) { try { item.Connection.Messaging.EncryptAndWrite(item.Message); } catch (Exception e) { Logger.Print($"Send error: {e.Message}"); } } } catch (OperationCanceledException) { } } } }