using Core.Annotations; using Core.Models.Eft.Common.Tables; using Core.Models.Spt.Bots; using Core.Helpers; using Core.Models.Enums; using Core.Models.Spt.Config; using Core.Models.Utils; using Core.Servers; using Core.Utils; namespace Core.Services; [Injectable(InjectionType.Singleton)] public class BotNameService { protected ISptLogger _logger; protected BotHelper _botHelper; protected RandomUtil _randomUtil; protected LocalisationService _localisationService; protected DatabaseService _databaseService; protected ConfigServer _configServer; protected BotConfig _botConfig; protected HashSet _usedNameCache; public BotNameService( ISptLogger logger, BotHelper botHelper, RandomUtil randomUtil, LocalisationService localisationService, DatabaseService databaseService, ConfigServer configServer) { _logger = logger; _botHelper = botHelper; _randomUtil = randomUtil; _localisationService = localisationService; _databaseService = databaseService; _configServer = configServer; _botConfig = _configServer.GetConfig(); _usedNameCache = new HashSet(); } /// /// Clear out any entries in Name Set /// public void ClearNameCache() { throw new NotImplementedException(); } /// /// Create a unique bot nickname /// /// bot JSON data from db /// /// role of bot e.g. assault /// Lowercase roles to always make unique /// Nickname for bot public string GenerateUniqueBotNickname( BotType botJsonTemplate, BotGenerationDetails botGenerationDetails, string botRole, List uniqueRoles = null) { var isPmc = botGenerationDetails.IsPmc; // Never show for players var showTypeInNickname = !botGenerationDetails.IsPlayerScav.GetValueOrDefault(false) && _botConfig.ShowTypeInNickname; var roleShouldBeUnique = uniqueRoles?.Contains(botRole.ToLower()); var isUnique = true; var attempts = 0; while (attempts <= 5) { // Get bot name with leading/trailing whitespace removed var name = (isPmc.GetValueOrDefault(false)) // Explicit handling of PMCs, all other bots will get "first_name last_name" ? _botHelper.GetPmcNicknameOfMaxLength(_botConfig.BotNameLengthLimit, botGenerationDetails.Side) : $"{ _randomUtil.GetArrayValue(botJsonTemplate.FirstNames)} {_randomUtil.GetArrayValue(botJsonTemplate.LastNames)}"; name = name.Trim(); // Config is set to add role to end of bot name if (showTypeInNickname) { name += $" { botRole}"; } // Replace pmc bot names with player name + prefix if (botGenerationDetails.IsPmc.GetValueOrDefault(false) && botGenerationDetails.AllPmcsHaveSameNameAsPlayer.GetValueOrDefault(false)) { var prefix = _localisationService.GetRandomTextThatMatchesPartialKey("pmc-name_prefix_"); name = $"{prefix} { name}"; } // Is this a role that must be unique if (roleShouldBeUnique.GetValueOrDefault(false)) { // Check name in cache isUnique = _usedNameCache.Contains(name); if (!isUnique) { // Not unique if (attempts >= 5) { // 5 attempts to generate a name, pool probably isn't big enough var genericName = $"{ botGenerationDetails.Side} { _randomUtil.GetInt(100000, 999999)}"; _logger.Debug($"Failed to find unique name for: { botRole} ${ botGenerationDetails.Side} after 5 attempts, using: ${ genericName}"); return genericName; } attempts++; // Try again continue; } } // Add bot name to cache to prevent being used again _usedNameCache.Add(name); return name; } // Should never reach here return $"BOT {botRole} {botGenerationDetails.BotDifficulty}"; } /// /// Add random PMC name to bots MainProfileNickname property /// /// Bot to update public void AddRandomPmcNameToBotMainProfileNicknameProperty(BotBase bot) { // Simulate bot looking like a player scav with the PMC name in brackets. // E.g. "ScavName (PMC Name)" bot.Info.MainProfileNickname = GetRandomPmcName(); } /// /// Choose a random PMC name from bear or usec bot jsons /// /// PMC name as string protected string GetRandomPmcName() { var bots = _databaseService.GetBots().Types; var pmcNames = new List(); pmcNames.AddRange(bots["usec"].FirstNames); pmcNames.AddRange(bots["bear"].FirstNames); return _randomUtil.GetArrayValue(pmcNames); } }