using System; using System.IO; using UnityEngine; public static class BlinkStartupInitializer { private const string ConfigFileName = "led_startup_config.ini"; private static bool subscribed; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void Register() { if (subscribed) return; subscribed = true; ComWrapper.OnInitialize += ApplyStartupCommands; Application.quitting += Unregister; } private static void Unregister() { ComWrapper.OnInitialize -= ApplyStartupCommands; Application.quitting -= Unregister; subscribed = false; } private static void ApplyStartupCommands() { string configPath = Path.Combine(Application.streamingAssetsPath, ConfigFileName); try { if (!File.Exists(configPath)) { Directory.CreateDirectory(Application.streamingAssetsPath); File.WriteAllText(configPath, GetDefaultConfig()); Debug.Log($"BlinkStartupInitializer: создан файл конфигурации {configPath}"); } string[] lines = File.ReadAllLines(configPath); for (int i = 0; i < lines.Length; i++) ProcessLine(lines[i], i + 1); } catch (Exception ex) { Debug.LogWarning($"BlinkStartupInitializer: ошибка чтения {configPath}: {ex.Message}"); } } private static void ProcessLine(string rawLine, int lineNumber) { if (string.IsNullOrWhiteSpace(rawLine)) return; string line = StripComments(rawLine).Trim(); if (string.IsNullOrWhiteSpace(line)) return; int separatorIndex = line.IndexOf('='); if (separatorIndex < 0) { Debug.LogWarning($"BlinkStartupInitializer: строка {lineNumber} должна быть в формате player1=004 003"); return; } string playerToken = line.Substring(0, separatorIndex).Trim(); string commandsToken = line.Substring(separatorIndex + 1).Trim(); if (!TryParsePlayerId(playerToken, out int playerId)) { Debug.LogWarning($"BlinkStartupInitializer: строка {lineNumber}, неизвестный идентификатор '{playerToken}'"); return; } if (string.IsNullOrWhiteSpace(commandsToken)) { Debug.LogWarning($"BlinkStartupInitializer: строка {lineNumber} не содержит команд"); return; } string[] commands = commandsToken.Split(new[] { ' ', '\t', ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string command in commands) SendValidatedCommand(command, playerId, lineNumber); } private static void SendValidatedCommand(string rawCommand, int playerId, int lineNumber) { if (!TryNormalizeCommand(rawCommand, out string command)) { Debug.LogWarning($"BlinkStartupInitializer: строка {lineNumber}, команда '{rawCommand}' некорректна"); return; } ComWrapper.Send(command, playerId); Debug.Log($"BlinkStartupInitializer: отправлена команда {command} для playerId={playerId}"); } private static bool TryNormalizeCommand(string rawCommand, out string command) { command = null; if (string.IsNullOrWhiteSpace(rawCommand)) return false; string value = rawCommand.Trim(); if (value.StartsWith("89", StringComparison.Ordinal)) value = value.Substring(2); if (value.Length != 3) return false; if (!char.IsDigit(value[0]) || !char.IsDigit(value[1]) || !char.IsDigit(value[2])) return false; int channel = value[0] - '0'; int mode = value[1] - '0'; int sequence = value[2] - '0'; if (channel < 0 || channel > 4) return false; if (mode != 0) return false; if (sequence < 0 || sequence > 5) return false; command = $"89{value}"; return true; } private static bool TryParsePlayerId(string token, out int playerId) { switch (token.Trim().ToLowerInvariant()) { case "1": case "player1": case "plate1": playerId = 1; return true; case "2": case "player2": case "plate2": playerId = 2; return true; default: playerId = 0; return false; } } private static string StripComments(string line) { int hashIndex = line.IndexOf('#'); int slashIndex = line.IndexOf("//", StringComparison.Ordinal); int commentIndex = -1; if (hashIndex >= 0) commentIndex = hashIndex; if (slashIndex >= 0 && (commentIndex < 0 || slashIndex < commentIndex)) commentIndex = slashIndex; return commentIndex >= 0 ? line.Substring(0, commentIndex) : line; } private static string GetDefaultConfig() { return string.Join(Environment.NewLine, new[] { "# Команды инициализации LED-лент.", "# Формат: player1=004 003", "# player1/player2 = номер платы = playerId", "# Команда: X0Z или 89X0Z", "# X: 0 - все каналы, 1-4 - конкретный канал", "# Z: 0-RGB, 1-RBG, 2-BRG, 3-BGR, 4-GRB, 5-GBR", "player1=004", "player2=004" }); } }