namespace Supercell.Laser.Server.Handler { using Supercell.Laser.Logic.Notification; using Supercell.Laser.Logic.Command; using Supercell.Laser.Logic.Avatar; using Supercell.Laser.Logic.Data; using Supercell.Laser.Logic.Home; using Supercell.Laser.Logic.Message.Account; using Supercell.Laser.Logic.Message.Account.Auth; using Supercell.Laser.Logic.Util; using Supercell.Laser.Server.Database; using Supercell.Laser.Server.Database.Cache; using Supercell.Laser.Server.Database.Models; using Supercell.Laser.Server.Networking.Session; using System.Reflection; using Supercell.Laser.Server.Utils; using Supercell.Laser.Logic.Avatar.Structures; using Supercell.Laser.Logic.Command.Avatar; using Supercell.Laser.Logic.Friends; using Supercell.Laser.Logic.Home.Structures; using Supercell.Laser.Logic.Listener; using Supercell.Laser.Logic.Message.Home; using Supercell.Laser.Logic.Team; using Supercell.Laser.Server.Logic.Game; using Supercell.Laser.Server.Networking; using Supercell.Laser.Server.Message; using Supercell.Laser.Server.Settings; using Supercell.Laser.Server.Logic; using Supercell.Laser.Logic.Battle; using Supercell.Laser.Logic.Message.Battle; using Supercell.Laser.Server.Networking.UDP.Game; using Supercell.Laser.Logic.Home.Items; using Supercell.Laser.Logic.Command.Home; using Supercell.Laser.Logic.Data.Helper; using Newtonsoft.Json.Linq; using System.Linq; public static class CmdHandler { public static void Start() { while (true) { try { string cmd = Console.ReadLine(); if (cmd == null) continue; Execute(cmd); } catch (Exception) { } } } public static void Execute(string cmd) { try { if (string.IsNullOrWhiteSpace(cmd)) return; if (!cmd.StartsWith("/")) return; cmd = cmd.Substring(1); string[] args = cmd.Split(" "); if (args.Length < 1) return; switch (args[0]) { case "unban": ExecuteUnbanAccount(args); break; case "ban": ExecuteBanAccount(args); break; case "kick": ExecuteKickPlayer(args); break; case "changename": case "rename": ExecuteChangeNameForAccount(args); break; case "devtag": Dev(args); break; case "getvalue": ExecuteGetFieldValue(args); break; case "changevalue": ExecuteChangeValueForAccount(args); break; case "PlusTrophies": PlusTrophies(args); break; case "unlockall": ExecuteUnlockAllForAccount(args); break; case "skin": ExecuteGiveSkin(args); break; case "addgold": case "gold": case "coins": ExecuteAddGold(args); break; case "addbrawler": ExecuteAddBrawler(args); break; case "maintenance": Logger.Warning("Starting maintenance..."); ExecuteShutdown(); Logger.Success("Maintenance started!"); break; case "offer": ExecuteGiveMegaGemsToAccount(args); break; case "addemote": ExecuteAddEmote(args); break; case "upgradebrawler": ExecuteUpgradeBrawler(args); break; case "addbrawlerbundle": ExecuteAddBrawlerBundle(args); break; case "battlepass": ExecuteGiveBattlePass(args); break; case "addcreator": ExecuteAddCreator(args); break; case "gems": ExecuteGiveGemsToAccount(args); break; case "starpoints": case "sp": ExecuteGiveStarPointsToAccount(args); break; case "premium": ExecuteGivePremiumToAccount(args); break; case "send": ExecuteSendCommand(args); break; case "stats": ExecuteServerStats(); break; case "audit": ExecuteAuditExport(args, suspiciousOnly: false); break; case "suspicious": ExecuteAuditExport(args, suspiciousOnly: true); break; case "backupdb": ExecuteDatabaseBackup(); break; case "leaderboard": ExecuteLeaderboard(args); break; case "vouchercreate": ExecuteVoucherCreate(args); break; case "bindaccount": ExecuteBindAccount(args); break; case "registerlink": ExecuteRegisterLink(args); break; case "loginlink": ExecuteLoginLink(args); break; case "bindings": ExecuteBindingsList(); break; } } catch (Exception) { } } private static void ExecuteSendCommand(string[] args) { try { if (args.Length < 3) throw new ArgumentException("Недостаточно параметров\nИспользование: /send \nДоступные цели:\n0- Все игроки\n#TAG - Игрок по тегу (например #2PP)\nX-Y - Диапазон ID (например 100-200)\n ID - Конкретный ID игрока"); string target = args[1]; string message = string.Join(" ", args.Skip(2)); int sentCount = 0; switch (DetermineTargetType(target)) { case TargetType.AllPlayers: SendToAllPlayers(message, ref sentCount); break; case TargetType.PlayerTag: SendToPlayerByTag(target, message, ref sentCount); break; case TargetType.Range: SendToRange(target, message, ref sentCount); break; case TargetType.SingleId: SendToSinglePlayer(long.Parse(target), message, ref sentCount); break; } Logger.Success($"Message sent to {sentCount} players"); } catch (Exception ex) { Logger.Error($"Command error: {ex.Message}"); } } private enum TargetType { AllPlayers, PlayerTag, Range, SingleId } private static TargetType DetermineTargetType(string target) { if (target == "0") return TargetType.AllPlayers; if (target.Contains("-")) return TargetType.Range; if (target.StartsWith("#")) return TargetType.PlayerTag; return TargetType.SingleId; } #region Основные методы отправки private static void SendToAllPlayers(string message, ref int counter) { long maxId = Accounts.GetMaxAvatarId(); Logger.Info($"Sending to all players (total {maxId} accounts)..."); SendToRange(1, maxId, message, ref counter); } private static void SendToPlayerByTag(string tag, string message, ref int counter) { if (!tag.StartsWith("#") || tag.Length != 5) throw new ArgumentException("Неверный формат тега! Пример: #2ABCD"); long accountId = LogicLongCodeGenerator.ToId(tag); SendToSinglePlayer(accountId, message, ref counter); } private static void SendToRange(string range, string message, ref int counter) { var parts = range.Split('-'); if (parts.Length != 2 || !long.TryParse(parts[0], out long start) || !long.TryParse(parts[1], out long end)) throw new ArgumentException("Неверный формат диапазона! Пример: 100-200"); SendToRange(Math.Min(start, end), Math.Max(start, end), message, ref counter); } private static void SendToRange(long startId, long endId, string message, ref int counter) { Logger.Info($"Sending to players {startId}-{endId}..."); for (long id = startId; id <= endId; id++) SendToSinglePlayer(id, message, ref counter); } private static void SendToSinglePlayer(long accountId, string message, ref int counter) { try { Account account = Accounts.Load(accountId); if (account == null || account.Home == null) { Logger.Info($"Игрок {accountId} не найден"); return; } var notification = new Notification { Id = 81, MessageEntry = FormatMessage(message) }; account.Home.NotificationFactory.Add(notification); Accounts.Save(account); SendInstantNotification(account, notification); Logger.Info($"Sent to #{accountId}"); counter++; } catch (Exception ex) { Logger.Info($"Ошибка отправки для ID {accountId}: {ex.Message}"); } } #endregion #region Вспомогательные методы private static string FormatMessage(string rawMessage) { return $"[СИСТЕМНОЕ СООБЩЕНИЕ]\n{rawMessage}"; } private static void SendInstantNotification(Account account, Notification notification) { if (!Sessions.IsSessionActive(account.Avatar.AccountId)) return; var session = Sessions.GetSession(account.Avatar.AccountId); session.GameListener.SendTCPMessage(new AvailableServerCommandMessage { Command = new LogicAddNotificationCommand { Notification = notification } }); } #endregion private static void ExecuteGiveSkin(string[] args) { if (args.Length < 4) { Logger.Warning("Usage: /skin [TAG] [SkinID] [Message]"); return; } bool sc = false; long id = 0; if (args[1].StartsWith('#')) { id = LogicLongCodeGenerator.ToId(args[1]); } else { sc = true; id = long.Parse(args[1]); } if (!int.TryParse(args[2], out int skinID)) { Logger.Warning("Error: Invalid SkinID."); return; } Account account = Accounts.Load(id); if (account == null) { Logger.Warning($"Error: Invalid tag: {id}"); return; } string skinMessage = args[3] == "1" ? "Спасибо за поддержку сервера<3" : $"{args[3]}"; Notification n = new Notification { Id = 90, DonationCount = 1, SkinID = 29000000 + skinID, MessageEntry = skinMessage }; account.Home.NotificationFactory.Add(n); LogicAddNotificationCommand acm = new() { Notification = n }; AvailableServerCommandMessage asm = new() { Command = acm }; Accounts.Save(account); if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(asm); } string tag = sc ? LogicLongCodeGenerator.ToCode(id) : args[1]; Logger.Success($"Added Skin {skinID} to {tag}!"); } private static void ExecuteAddBrawlerBundle(string[] args) { if (args.Length < 6) { Logger.Warning("Usage: /addbrawlerbundle [TAG] [BrawlerID] [Donation1] [Donation2] [Message]"); return; } bool sc = false; long id = 0; if (args[1].StartsWith('#')) { id = LogicLongCodeGenerator.ToId(args[1]); } else { sc = true; id = long.Parse(args[1]); } if (!int.TryParse(args[2], out int brawlerID)) { Logger.Warning("Error: Invalid BrawlerID."); return; } if (!int.TryParse(args[3], out int donation1)) { Logger.Warning("Error: Invalid DonationCount 1."); return; } if (!int.TryParse(args[4], out int donation2)) { Logger.Warning("Error: Invalid DonationCount 2."); return; } Account account = Accounts.Load(id); if (account == null) { Logger.Warning($"Error: Invalid tag: {id}"); return; } string bundleMessage = args[5] == "1" ? "Спасибо за поддержку сервера<3" : $"{args[5]}"; List notifications = new List { new Notification { Id = 93, BrawlerID = brawlerID, MessageEntry = bundleMessage }, new Notification { Id = 92, BrawlerID = brawlerID, DonationCount = donation1, MessageEntry = bundleMessage }, new Notification { Id = 89, DonationCount = donation2, MessageEntry = bundleMessage } }; foreach (var notification in notifications) { account.Home.NotificationFactory.Add(notification); LogicAddNotificationCommand acm = new() { Notification = notification }; AvailableServerCommandMessage asm = new() { Command = acm }; if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(asm); } } string tag = sc ? LogicLongCodeGenerator.ToCode(id) : args[1]; Logger.Success($"Added brawler bundle for {tag} (Brawler {brawlerID}, Donations: {donation1}, {donation2})!"); } private static void ExecuteUpgradeBrawler(string[] args) { if (args.Length < 5) { Logger.Warning("Usage: /upgradebrawler [TAG] [BrawlerID] [DonationCount] [Message]"); return; } bool sc = false; long id = 0; if (args[1].StartsWith('#')) { id = LogicLongCodeGenerator.ToId(args[1]); } else { sc = true; id = long.Parse(args[1]); } if (!int.TryParse(args[2], out int brawlerID)) { Logger.Warning("Error: Invalid BrawlerID."); return; } if (!int.TryParse(args[3], out int donationCount)) { Logger.Warning("Error: Invalid DonationCount."); return; } Account account = Accounts.Load(id); if (account == null) { Logger.Warning($"Error: Invalid tag: {id}"); return; } string upgradeMessage = args[4] == "1" ? "Спасибо за поддержку сервера<3" : $"{args[4]}"; Notification n = new Notification { Id = 92, BrawlerID = brawlerID, DonationCount = donationCount, MessageEntry = upgradeMessage }; account.Home.NotificationFactory.Add(n); LogicAddNotificationCommand acm = new() { Notification = n }; AvailableServerCommandMessage asm = new() { Command = acm }; Accounts.Save(account); if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(asm); } string tag = sc ? LogicLongCodeGenerator.ToCode(id) : args[1]; Logger.Success($"Upgraded Brawler {brawlerID} with {donationCount} points for {tag}!"); } private static void ExecuteGiveBattlePass(string[] args) { if (args.Length < 3) { Logger.Warning("Usage: /battlepass [TAG] [Type]"); return; } bool sc = false; long id = 0; if (args[1].StartsWith('#')) { id = LogicLongCodeGenerator.ToId(args[1]); } else { sc = true; id = long.Parse(args[1]); } Account account = Accounts.Load(id); if (account == null) { Logger.Warning($"Error: Invalid tag: {id}"); return; } string gemsMessage = "Спасибо за поддержку сервера<3"; List notifications = new List { new Notification { Id = 73, MessageEntry = gemsMessage } }; if (args[2] == "2") { notifications.AddRange(new[] { new Notification { Id = 90, DonationCount = 1000, MessageEntry = gemsMessage }, new Notification { Id = 89, DonationCount = 100, MessageEntry = gemsMessage }, new Notification { Id = 93, BrawlerID = 11, MessageEntry = gemsMessage } }); } foreach (var n in notifications) { account.Home.NotificationFactory.Add(n); LogicAddNotificationCommand acm = new() { Notification = n }; AvailableServerCommandMessage asm = new() { Command = acm }; if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(asm); } } string tag = sc ? LogicLongCodeGenerator.ToCode(id) : args[1]; Logger.Success($"BattlePass reward sent to {tag}!"); } private static void ExecuteAddEmote(string[] args) { if (args.Length < 3) { Logger.Warning("Usage: /addemote [TAG] [EmoteID] [Message]"); return; } bool sc = false; long id = 0; if (args[1].StartsWith('#')) { id = LogicLongCodeGenerator.ToId(args[1]); } else { sc = true; id = long.Parse(args[1]); } if (!int.TryParse(args[2], out int emoteID)) { Logger.Warning("Error: Invalid EmoteID."); return; } Account account = Accounts.Load(id); if (account == null) { Logger.Warning($"Error: Invalid tag: {id}"); return; } string emoteMessage = args.Length > 3 && args[3] != "1" ? $"{args[3]}" : "Спасибо за поддержку сервера<3"; Notification n = new Notification { Id = 72, BrawlerID = 52000000 + emoteID, MessageEntry = emoteMessage }; account.Home.NotificationFactory.Add(n); LogicAddNotificationCommand acm = new() { Notification = n }; AvailableServerCommandMessage asm = new AvailableServerCommandMessage(); asm.Command = acm; Accounts.Save(account); if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(asm); } string tag = sc ? LogicLongCodeGenerator.ToCode(id) : args[1]; Logger.Success($"added Emote {emoteID} to {tag}!"); } private static void ExecuteAddBrawler(string[] args) { if (args.Length < 3) { Logger.Warning("Usage: /addbrawler [TAG] [BrawlerID] [Message]"); return; } bool sc = false; long id = 0; if (args[1].StartsWith('#')) { id = LogicLongCodeGenerator.ToId(args[1]); } else { sc = true; id = long.Parse(args[1]); } if (!int.TryParse(args[2], out int brawlerID)) { Logger.Warning("Error: Invalid BrawlerID."); return; } Account account = Accounts.Load(id); if (account == null) { Logger.Warning($"Error: Invalid tag: {id}"); return; } string brawlerMessage = args.Length > 3 && args[3] != "1" ? $"{args[3]}" : "Спасибо за поддержку сервера<3"; Notification n = new Notification { Id = 93, BrawlerID = brawlerID, MessageEntry = brawlerMessage }; account.Home.NotificationFactory.Add(n); LogicAddNotificationCommand acm = new() { Notification = n }; AvailableServerCommandMessage asm = new AvailableServerCommandMessage(); asm.Command = acm; Accounts.Save(account); if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(asm); } string tag = sc ? LogicLongCodeGenerator.ToCode(id) : args[1]; Logger.Success($"added Brawler {brawlerID} to {tag}!"); } private static void ExecuteAddSkin(string[] args) { if (args.Length < 4) { Logger.Warning("Usage: /addskin [TAG] [SkinID] [Message]"); return; } bool isCode = false; long id = 0; if (args[1].StartsWith('#')) { id = LogicLongCodeGenerator.ToId(args[1]); } else { isCode = true; id = long.Parse(args[1]); } Account account = Accounts.Load(id); if (account == null) { Logger.Warning($"Error: Invalid tag: {id}"); return; } if (!int.TryParse(args[2], out int skinId)) { Logger.Warning("Error: Invalid SkinID."); return; } string message = args[3] == "1" ? "Cпасибо за поддержку сервера<3" : $"{args[3]}"; Notification notification = new Notification { Id = 90, DonationCount = 1, SkinID = 29000000 + skinId, MessageEntry = message }; account.Home.NotificationFactory.Add(notification); LogicAddNotificationCommand command = new() { Notification = notification }; AvailableServerCommandMessage serverMessage = new AvailableServerCommandMessage { Command = command }; if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(serverMessage); } string tag = isCode ? LogicLongCodeGenerator.ToCode(id) : args[1]; Logger.Success($"added skin {skinId} to {tag}!"); } private static void ExecuteAddGold(string[] args) { if (args.Length != 3) { Logger.Warning("Usage: /gold [TAG|ID] [Amount]"); return; } if (!int.TryParse(args[2], out int amount) || amount <= 0) { Logger.Warning("Error: Invalid amount. Amount must be a positive number."); return; } if (!AdminConsoleTools.TryResolveAccount(args[1], out Account account, out _, out _)) { Logger.Warning($"Error: Invalid tag or ID: {args[1]}"); return; } AdminConsoleTools.GrantCurrency(account, "gold", amount, "admin-gold"); } private static void PlusTrophies(string[] args) { if (args.Length != 3) // Увеличиваем количество аргументов { //Logger.Warning("Usage: /dev [TAG] [TROPHIES]"); return; } long id = LogicLongCodeGenerator.ToId(args[1]); Account account = Accounts.Load(id); if (account == null) { //Logger.Warning("Fail: account not found!"); return; } // Устанавливаем режим разработчика account.Avatar.IsDev = true; // Пытаемся получить количество трофеев из аргументов if (!long.TryParse(args[2], out long trophies)) { //Logger.Warning("Fail: invalid trophy count!"); return; } // Сбрасываем трофеи account.Avatar.PlusTrophies(trophies); // Передаем количество трофеев // Сохраняем изменения в базе данных Accounts.Save(account); // Проверяем активность сессии и уведомляем пользователя if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(new AuthenticationFailedMessage() { Message = "УПС! Тебя заблокировали!" }); Sessions.Remove(id); } } private static void Dev(string[] args) { if (args.Length != 2) { //Logger.Warning("Usage: /dev [TAG]"); return; } long id = LogicLongCodeGenerator.ToId(args[1]); Account account = Accounts.Load(id); if (account == null) { //Logger.Warning("Fail: account not found!"); return; } // Устанавливаем режим разработчика account.Avatar.IsDev = true; // Вызываем функцию для бана аккаунта BanAccount(account); // Сбрасываем трофеи account.Avatar.ResetTrophies(); // Сохраняем изменения в базе данных Accounts.Save(account); // Проверяем активность сессии и уведомляем пользователя if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(new AuthenticationFailedMessage() { Message = "УПС! Тебя заблокировали!" }); Sessions.Remove(id); } } // Метод для бана аккаунта private static void BanAccount(Account account) { // Логика бана аккаунта, например: account.Avatar.Banned = true; // Устанавливаем флаг бана // Можно добавить дополнительные действия, например, запись в логи или уведомления } private static void ExecuteGiveMegaGemsToAccount(string[] args) { if (args.Length != 2) { Logger.Warning("Usage: /offer [TAG]"); return; } bool sc = false; long targetAccountId = 0; if (args[1].StartsWith('#')) { targetAccountId = LogicLongCodeGenerator.ToId(args[1]); } else { sc = true; targetAccountId = long.Parse(args[1]); } Account targetAccount = Accounts.Load(targetAccountId); if (targetAccount == null) { Logger.Warning("Error: Account not found!"); return; } int donationAmount = 10; int itemPrice = 0; ShopItem itemType = ShopItem.MegaBox; Notification gemsNotification = new Notification { Id = 81, MessageEntry = $"Ваши {donationAmount} Мега Ящиков, спасибо за поддержку сервера!" }; targetAccount.Home.NotificationFactory.Add(gemsNotification); LogicAddNotificationCommand gemsNotificationCommand = new() { Notification = gemsNotification }; AvailableServerCommandMessage gemsCommandMessage = new AvailableServerCommandMessage { Command = gemsNotificationCommand }; if (Sessions.IsSessionActive(targetAccountId)) { var session = Sessions.GetSession(targetAccountId); session.GameListener.SendTCPMessage(gemsCommandMessage); } string donationLogEntry = $"Игроку {args[1]} Выдано {donationAmount} Мега Ящиков"; string donationFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "donate.txt"); if (!File.Exists(donationFilePath)) { File.Create(donationFilePath).Dispose(); } File.AppendAllText(donationFilePath, donationLogEntry + Environment.NewLine); OfferBundle megaBoxBundle = new OfferBundle { Title = "АКЦИЯ", IsDailyDeals = false, EndTime = DateTime.UtcNow.AddDays(3), BackgroundExportName = "offer_special", Cost = itemPrice, OldCost = 80 * donationAmount, Currency = 0 }; megaBoxBundle.Items.Add(new Offer(itemType, donationAmount)); targetAccount.Home.OfferBundles.Add(megaBoxBundle); Accounts.Save(targetAccount); string d = sc ? LogicLongCodeGenerator.ToCode(long.Parse(args[1])) : args[1]; Logger.Success($"{donationAmount} Мега Ящиков добавлено в аккаунт {d}!"); } private static void ExecuteUnlockAllForAccount(string[] args) { if (args.Length != 2) { Logger.Warning("Usage: /unlockall [TAG]"); return; } long id = LogicLongCodeGenerator.ToId(args[1]); Account account = Accounts.Load(id); if (account == null) { Logger.Warning("Fail: account not found!"); return; } for (int i = 0; i < HomeMode.UNLOCKABLE_HEROES_COUNT; i++) { if (!account.Avatar.HasHero(16000000 + i)) { CharacterData character = DataTables.Get(16).GetDataWithId(i); CardData card = DataTables.Get(23).GetData(character.Name + "_unlock"); account.Avatar.UnlockHero(character.GetGlobalId(), card.GetGlobalId()); } } Logger.Print($"Successfully unlocked all brawlers for account {account.AccountId.GetHigherInt()}-{account.AccountId.GetLowerInt()} ({args[1]})"); if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(new AuthenticationFailedMessage() { Message = "Your account updated!" }); Sessions.Remove(id); } } private static void ExecuteUnbanAccount(string[] args) { if (args.Length != 2) { Logger.Warning("Usage: /unban [TAG]"); return; } long id = LogicLongCodeGenerator.ToId(args[1]); Account account = Accounts.Load(id); if (account == null) { Logger.Warning("Fail: account not found!"); return; } // Восстанавливаем оригинальный ник если он был сохранён if (!string.IsNullOrEmpty(account.Avatar.BanReason) && account.Avatar.Name == "BANNED") account.Avatar.Name = account.Avatar.BanReason; account.Avatar.Banned = false; account.Avatar.BanReason = null; Accounts.Save(account); AuditLogger.BanRemoved(account.AccountId, account.Avatar.Name, "console"); if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(new AuthenticationFailedMessage() { Message = "Your account updated!" }); Sessions.Remove(id); } } private static void ExecuteBanAccount(string[] args) { if (args.Length != 5) { Logger.Warning("Usage: /ban [TAG] [Reason] [Day] [Month]"); return; } long id = LogicLongCodeGenerator.ToId(args[1]); Account account = Accounts.Load(id); if (account == null) { Logger.Warning("Fail: account not found!"); return; } account.Avatar.Banned = true; account.Avatar.OldBans.Add(int.Parse(args[2])); account.Avatar.BannedReason = int.Parse(args[2]); account.Avatar.BanTime[0] = int.Parse(args[3]); account.Avatar.BanTime[1] = int.Parse(args[4]); // Сохраняем оригинальный ник перед баном (если ещё не сохранён) if (string.IsNullOrEmpty(account.Avatar.BanReason)) account.Avatar.BanReason = account.Avatar.Name; account.Avatar.Name = "BANNED"; if (account.Avatar.BanTime[1] == 99) account.Avatar.ResetTrophies(); Accounts.Save(account); AuditLogger.BanApplied(account.AccountId, account.Avatar.BanReason ?? "?", args[2], "console"); if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(new AuthenticationFailedMessage() { Message = "Привет... сожалению ваш аккаунт был заблокирован из-за нарушения правил Для апелляции обратитесь службу поддержки @JowperDeveloper" }); Sessions.Remove(id); } } private static void ExecuteKickPlayer(string[] args) { if (args.Length != 2) { Logger.Warning("Usage: /kick [TAG]"); return; } long id = LogicLongCodeGenerator.ToId(args[1]); Account account = Accounts.Load(id); if (account == null) { Logger.Warning("Fail: account not found!"); return; } account.Avatar.Banned = true; if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(new OutOfSyncMessage()); } } private static void ExecuteAddCreator(string[] args) { if (args.Length != 3) { Logger.Warning("Usage: /addcreator [TAG] [CODE]"); return; } string tag = args[1].Trim(); string creatorCode = args[2].Trim(); string creatorsFilePath = "/root/27/Supercell.Laser.Server/Code.json"; string rootConfigPath = "/root/27/Supercell.Laser.Server/config.json"; string buildConfigPath = "/root/27/Supercell.Laser.Server/config.json"; try { string result = AddCreatorCommand(tag, creatorCode, creatorsFilePath, rootConfigPath, buildConfigPath); Logger.Info(result); } catch (Exception ex) { Logger.Error($"Command error: {ex.Message}"); } } public static string AddCreatorCommand(string tag, string creatorCode, string creatorsFilePath, string rootConfigPath, string buildConfigPath) { if (string.IsNullOrEmpty(creatorCode)) { return "Невалидный код автора."; } // Проверка наличия файлов if (!File.Exists(creatorsFilePath)) { return $"Файл creators.json не найден: {creatorsFilePath}"; } if (!File.Exists(rootConfigPath)) { return $"Файл конфигурации {rootConfigPath} не найден."; } if (!File.Exists(buildConfigPath)) { return $"Файл конфигурации {buildConfigPath} не найден."; } try { AddCreatorToJsonFile(creatorsFilePath, tag, creatorCode); AddCreatorCodeToConfig(rootConfigPath, creatorCode); AddCreatorCodeToConfig(buildConfigPath, creatorCode); } catch (Exception ex) { return $"Ошибка добавления креатора в файл: {ex.Message}"; } long lowID = LogicLongCodeGenerator.ToId(tag); Account account = Accounts.Load(lowID); if (account == null) { return $"Не удалось найти игрока с ID {tag}."; } if (account.Home.CreatorEndTime < DateTime.UtcNow) { account.Home.CreatorEndTime = DateTime.UtcNow.AddMonths(1337); } else { account.Home.CreatorEndTime = account.Home.CreatorEndTime.AddMonths(1); } account.Avatar.CreatorLevel = 1; Notification nGems = new() { Id = 89, DonationCount = 170, MessageEntry = $"Поздравляем со вступлением на креатора!\nТвой код: {creatorCode}" }; account.Home.NotificationFactory.Add(nGems); LogicAddNotificationCommand acmGems = new() { Notification = nGems }; AvailableServerCommandMessage asmGems = new(); asmGems.Command = acmGems; if (Sessions.IsSessionActive(lowID)) { Session sessionGems = Sessions.GetSession(lowID); sessionGems.GameListener.SendTCPMessage(asmGems); } return $"Успешно: код автора \"{creatorCode}\" добавлен в файлы creators.json и config.json."; } private static void AddCreatorToJsonFile(string filePath, string tag, string creatorCode) { // Проверяем существование файла if (!File.Exists(filePath)) { throw new Exception("Файл creators.json не найден."); } // Чтение содержимого файла string json = File.ReadAllText(filePath); // Если файл пуст, создаём новый объект с пустым массивом "Creators" if (string.IsNullOrWhiteSpace(json)) { json = "{\"Creators\": []}"; } try { // Преобразуем JSON в объект JObject JObject creatorsData = JObject.Parse(json); // Если "Creators" не существует, создаём его if (creatorsData["Creators"] == null) { creatorsData["Creators"] = new JArray(); } JArray creatorsArray = (JArray)creatorsData["Creators"]; // Проверяем, если уже есть такой креатор foreach (var creator in creatorsArray) { if (creator["Name"].ToString() == tag) { throw new Exception($"Креатор с тегом {tag} уже существует."); } } // Создаём новый объект для креатора JObject newCreator = new JObject { { "Name", creatorCode }, { "Tag", tag }, { "RewardCount", 5 }, { "ActivationHistory", new JArray() } }; // Добавляем нового креатора в список creatorsArray.Add(newCreator); // Сохраняем изменения в файл File.WriteAllText(filePath, creatorsData.ToString()); } catch (Exception ex) { throw new Exception($"Ошибка при обработке JSON: {ex.Message}"); } } private static void AddCreatorCodeToConfig(string filePath, string creatorCode) { string json = File.ReadAllText(filePath); JObject config = JObject.Parse(json); if (config["CreatorCodes"] is JValue creatorCodesValue) { string existingCodes = creatorCodesValue.ToString(); string updatedCodes = string.IsNullOrEmpty(existingCodes) ? creatorCode : $"{existingCodes},{creatorCode}"; config["CreatorCodes"] = updatedCodes; // Сохранение изменений File.WriteAllText(filePath, config.ToString()); } else { throw new Exception($"CreatorCodes отсутствует в {filePath}."); } } private static void ExecuteChangeNameForAccount(string[] args) { if (args.Length != 3) { Logger.Warning("Usage: /changename [TAG|ID] [NewName]"); return; } if (!AdminConsoleTools.TryResolveAccount(args[1], out Account account, out long id, out _)) { Logger.Warning("Fail: account not found!"); return; } string oldName = account.Avatar.Name; account.Avatar.Name = args[2]; account.Avatar.NameSetByUser = true; Accounts.Save(account); AuditLogger.NameChanged(account.AccountId, oldName, account.Avatar.Name); AdminConsoleTools.RefreshOnlineAccount(id, "rename"); Logger.Success($"Name changed: {oldName} -> {account.Avatar.Name} for #{LogicLongCodeGenerator.ToCode(id)}"); } private static void ExecuteGetFieldValue(string[] args) { if (args.Length != 3) { Logger.Warning("Usage: /changevalue [TAG] [FieldName]"); return; } long id = LogicLongCodeGenerator.ToId(args[1]); Account account = Accounts.Load(id); if (account == null) { Logger.Warning("Fail: account not found!"); return; } Type type = typeof(ClientAvatar); FieldInfo field = type.GetField(args[2]); if (field == null) { Logger.Warning($"Fail: LogicClientAvatar::{args[2]} not found!"); return; } int value = (int)field.GetValue(account.Avatar); Logger.Info($"LogicClientAvatar::{args[2]} = {value}"); } private static void ExecuteChangeValueForAccount(string[] args) { if (args.Length != 4) { Logger.Warning("Usage: /changevalue [TAG] [FieldName] [Value]"); return; } long id = LogicLongCodeGenerator.ToId(args[1]); Account account = Accounts.Load(id); if (account == null) { Logger.Warning("Fail: account not found!"); return; } Type type = typeof(ClientAvatar); FieldInfo field = type.GetField(args[2]); if (field == null) { Logger.Warning($"Fail: LogicClientAvatar::{args[2]} not found!"); return; } field.SetValue(account.Avatar, int.Parse(args[3])); if (Sessions.IsSessionActive(id)) { var session = Sessions.GetSession(id); session.GameListener.SendTCPMessage(new AuthenticationFailedMessage() { Message = "Your account updated!" }); Sessions.Remove(id); } } private static void ExecuteGivePremiumToAccount(string[] args) { if (args.Length < 2) { Logger.Warning("Usage: /premium [TAG] [days=30]"); return; } bool sc = false; long id = 0; if (args[1].StartsWith('#')) { id = LogicLongCodeGenerator.ToId(args[1]); } else { sc = true; id = long.Parse(args[1]); } int days = 30; if (args.Length >= 3 && int.TryParse(args[2], out int parsedDays) && parsedDays > 0) days = parsedDays; Account account = Accounts.Load(id); if (account == null) { Logger.Warning($"Error: Invalid tag: {id}"); return; } if (account.Home.PremiumEndTime < DateTime.UtcNow) account.Home.PremiumEndTime = DateTime.UtcNow.AddDays(days); else account.Home.PremiumEndTime = account.Home.PremiumEndTime.AddDays(days); account.Avatar.IsPremium = true; account.Avatar.PremiumLevel = 1; account.Avatar.AddDiamonds(170); Accounts.Save(account); AdminConsoleTools.RefreshOnlineAccount(id, "premium"); string d = sc ? LogicLongCodeGenerator.ToCode(long.Parse(args[1])) : args[1]; Logger.Success($"Premium activated for {d} for {days} days (until {account.Home.PremiumEndTime:dd.MM.yyyy} UTC). 170 gems granted."); } private static void ExecuteGiveDevToAccount(string[] args) { if (args.Length < 2) { Logger.Warning("Usage: /dev [TAG] [days=30]"); return; } bool sc = false; long id = 0; if (args[1].StartsWith('#')) { id = LogicLongCodeGenerator.ToId(args[1]); } else { sc = true; id = long.Parse(args[1]); } Account account = Accounts.Load(id); if (account == null) { Logger.Warning($"Error: Invalid tag: {id}"); return; } string d = sc ? LogicLongCodeGenerator.ToCode(long.Parse(args[1])) : args[1]; if (account.Home.IsDev) { account.Home.IsDev = false; Logger.Success($"Dev status removed for {d}."); } else { account.Home.IsDev = true; Logger.Success($"Dev status granted for {d}."); } Accounts.Save(account); AdminConsoleTools.RefreshOnlineAccount(id, "dev"); } private static void ExecuteGiveGemsToAccount(string[] args) { if (args.Length != 3) { Logger.Warning("Usage: /gems [TAG|ID] [Amount]"); return; } if (!int.TryParse(args[2], out int amount) || amount <= 0) { Logger.Warning("Error: Invalid amount. Amount must be a positive number."); return; } if (!AdminConsoleTools.TryResolveAccount(args[1], out Account account, out _, out _)) { Logger.Warning($"Error: Invalid tag or ID: {args[1]}"); return; } AdminConsoleTools.GrantCurrency(account, "gems", amount, "admin-gems"); } private static void ExecuteGiveStarPointsToAccount(string[] args) { if (args.Length != 3) { Logger.Warning("Usage: /starpoints [TAG|ID] [Amount]"); return; } if (!int.TryParse(args[2], out int amount) || amount <= 0) { Logger.Warning("Error: Invalid amount. Amount must be a positive number."); return; } if (!AdminConsoleTools.TryResolveAccount(args[1], out Account account, out _, out _)) { Logger.Warning($"Error: Invalid tag or ID: {args[1]}"); return; } AdminConsoleTools.GrantCurrency(account, "starpoints", amount, "admin-starpoints"); } private static void ExecuteServerStats() { Logger.Info(AdminConsoleTools.BuildServerStats()); } private static void ExecuteAuditExport(string[] args, bool suspiciousOnly) { int count = 100; string filter = null; if (args.Length >= 2 && int.TryParse(args[1], out int parsedCount) && parsedCount > 0) { count = parsedCount; } if (args.Length >= 3) { filter = string.Join(" ", args.Skip(2)); } string path = AdminConsoleTools.ExportAudit(count, filter, suspiciousOnly); Logger.Success($"Audit export saved to: {path}"); } private static void ExecuteDatabaseBackup() { string backupPath = AdminConsoleTools.BackupDatabase(); Logger.Success($"Database backup created: {backupPath}"); } private static void ExecuteLeaderboard(string[] args) { string type = args.Length >= 2 ? args[1] : "players"; int count = 10; if (args.Length >= 3 && int.TryParse(args[2], out int parsedCount) && parsedCount > 0) { count = parsedCount; } Logger.Info(AdminConsoleTools.BuildLeaderboardReport(type, count)); } private static void ExecuteVoucherCreate(string[] args) { if (args.Length < 3) { Logger.Warning("Usage: /vouchercreate [CODE] [gold=500] [gems=100] [starpoints=50] ..."); return; } string path = AdminConsoleTools.CreateVoucher(args[1], args.Skip(2).ToArray()); Logger.Success($"Voucher {args[1]} saved to {path}"); } private static void ExecuteBindAccount(string[] args) { if (args.Length < 3) { Logger.Warning("Usage: /bindaccount [TAG|ID] [TelegramId] [TelegramUsername?]"); return; } if (!AdminConsoleTools.TryResolveAccount(args[1], out Account account, out _, out _)) { Logger.Warning("Account not found."); return; } if (!long.TryParse(args[2], out long telegramId)) { Logger.Warning("Invalid TelegramId."); return; } string telegramUsername = args.Length >= 4 ? args[3] : null; TelegramBot.BindTelegramToAccount(account.AccountId, telegramId, telegramUsername); Logger.Success($"Telegram {telegramId} bound to {account.Avatar.Name}#{account.AccountId}"); } private static void ExecuteRegisterLink(string[] args) { if (args.Length < 2) { Logger.Warning("Usage: /registerlink [TelegramId] [TelegramUsername?] [Minutes=15]"); return; } if (!long.TryParse(args[1], out long telegramId)) { Logger.Warning("Invalid TelegramId."); return; } string telegramUsername = args.Length >= 3 ? args[2] : null; int minutes = 15; if (args.Length >= 4 && int.TryParse(args[3], out int parsedMinutes) && parsedMinutes > 0) { minutes = parsedMinutes; } string url = TelegramBot.CreateRegisterLink(telegramId, telegramUsername, TimeSpan.FromMinutes(minutes)); Logger.Success($"Register link: {url}"); } private static void ExecuteLoginLink(string[] args) { if (args.Length < 2) { Logger.Warning("Usage: /loginlink [TAG|ID] [Minutes=15]"); return; } if (!AdminConsoleTools.TryResolveAccount(args[1], out Account account, out _, out _)) { Logger.Warning("Account not found."); return; } int minutes = 15; if (args.Length >= 3 && int.TryParse(args[2], out int parsedMinutes) && parsedMinutes > 0) { minutes = parsedMinutes; } if (!TelegramBot.TryCreateLoginLinkForAccount(account.AccountId, TimeSpan.FromMinutes(minutes), out string url, out string error)) { Logger.Warning(error); return; } Logger.Success($"Login link: {url}"); } private static void ExecuteBindingsList() { var bindings = TelegramBot.GetBindingsSnapshot(); if (bindings.Length == 0) { Logger.Info("No telegram bindings found."); return; } foreach (var binding in bindings) { Logger.Info($"{binding.TelegramId} @{binding.TelegramUsername ?? "-"} -> {binding.AccountName} ({binding.AccountTag})"); } } private static void ExecuteShutdown() { Sessions.StartShutdown(); AccountCache.SaveAll(); AllianceCache.SaveAll(); AccountCache.Started = false; AllianceCache.Started = false; } } }