Added service to ensure bot names are unique to a raid
This commit is contained in:
parent
ebe9c0daac
commit
eaa16259ae
@ -201,6 +201,7 @@ import { BotEquipmentFilterService } from "@spt/services/BotEquipmentFilterServi
|
|||||||
import { BotEquipmentModPoolService } from "@spt/services/BotEquipmentModPoolService";
|
import { BotEquipmentModPoolService } from "@spt/services/BotEquipmentModPoolService";
|
||||||
import { BotGenerationCacheService } from "@spt/services/BotGenerationCacheService";
|
import { BotGenerationCacheService } from "@spt/services/BotGenerationCacheService";
|
||||||
import { BotLootCacheService } from "@spt/services/BotLootCacheService";
|
import { BotLootCacheService } from "@spt/services/BotLootCacheService";
|
||||||
|
import { BotNameService } from "@spt/services/BotNameService";
|
||||||
import { BotWeaponModLimitService } from "@spt/services/BotWeaponModLimitService";
|
import { BotWeaponModLimitService } from "@spt/services/BotWeaponModLimitService";
|
||||||
import { CircleOfCultistService } from "@spt/services/CircleOfCultistService";
|
import { CircleOfCultistService } from "@spt/services/CircleOfCultistService";
|
||||||
import { CustomLocationWaveService } from "@spt/services/CustomLocationWaveService";
|
import { CustomLocationWaveService } from "@spt/services/CustomLocationWaveService";
|
||||||
@ -797,6 +798,9 @@ export class Container {
|
|||||||
depContainer.register<CircleOfCultistService>("CircleOfCultistService", CircleOfCultistService, {
|
depContainer.register<CircleOfCultistService>("CircleOfCultistService", CircleOfCultistService, {
|
||||||
lifecycle: Lifecycle.Singleton,
|
lifecycle: Lifecycle.Singleton,
|
||||||
});
|
});
|
||||||
|
depContainer.register<BotNameService>("BotNameService", BotNameService, {
|
||||||
|
lifecycle: Lifecycle.Singleton,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static registerServers(depContainer: DependencyContainer): void {
|
private static registerServers(depContainer: DependencyContainer): void {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { BotInventoryGenerator } from "@spt/generators/BotInventoryGenerator";
|
import { BotInventoryGenerator } from "@spt/generators/BotInventoryGenerator";
|
||||||
import { BotLevelGenerator } from "@spt/generators/BotLevelGenerator";
|
import { BotLevelGenerator } from "@spt/generators/BotLevelGenerator";
|
||||||
import { BotDifficultyHelper } from "@spt/helpers/BotDifficultyHelper";
|
|
||||||
import { BotHelper } from "@spt/helpers/BotHelper";
|
import { BotHelper } from "@spt/helpers/BotHelper";
|
||||||
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
|
||||||
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
||||||
@ -27,9 +26,9 @@ import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig";
|
|||||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||||
import { BotEquipmentFilterService } from "@spt/services/BotEquipmentFilterService";
|
import { BotEquipmentFilterService } from "@spt/services/BotEquipmentFilterService";
|
||||||
|
import { BotNameService } from "@spt/services/BotNameService";
|
||||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||||
import { ItemFilterService } from "@spt/services/ItemFilterService";
|
import { ItemFilterService } from "@spt/services/ItemFilterService";
|
||||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
|
||||||
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
|
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
|
||||||
import { HashUtil } from "@spt/utils/HashUtil";
|
import { HashUtil } from "@spt/utils/HashUtil";
|
||||||
import { RandomUtil } from "@spt/utils/RandomUtil";
|
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||||
@ -54,10 +53,9 @@ export class BotGenerator {
|
|||||||
@inject("BotEquipmentFilterService") protected botEquipmentFilterService: BotEquipmentFilterService,
|
@inject("BotEquipmentFilterService") protected botEquipmentFilterService: BotEquipmentFilterService,
|
||||||
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
|
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
|
||||||
@inject("BotHelper") protected botHelper: BotHelper,
|
@inject("BotHelper") protected botHelper: BotHelper,
|
||||||
@inject("BotDifficultyHelper") protected botDifficultyHelper: BotDifficultyHelper,
|
|
||||||
@inject("SeasonalEventService") protected seasonalEventService: SeasonalEventService,
|
@inject("SeasonalEventService") protected seasonalEventService: SeasonalEventService,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
|
||||||
@inject("ItemFilterService") protected itemFilterService: ItemFilterService,
|
@inject("ItemFilterService") protected itemFilterService: ItemFilterService,
|
||||||
|
@inject("BotNameService") protected botNameService: BotNameService,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
@inject("PrimaryCloner") protected cloner: ICloner,
|
@inject("PrimaryCloner") protected cloner: ICloner,
|
||||||
) {
|
) {
|
||||||
@ -170,7 +168,14 @@ export class BotGenerator {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.Info.Nickname = this.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole, sessionId);
|
bot.Info.Nickname = this.botNameService.generateUniqueBotNickname(
|
||||||
|
botJsonTemplate.firstName,
|
||||||
|
botJsonTemplate.lastName,
|
||||||
|
botGenerationDetails,
|
||||||
|
botRole,
|
||||||
|
["assault", "pmcusec", "pmcbear"],
|
||||||
|
sessionId,
|
||||||
|
);
|
||||||
|
|
||||||
if (!this.seasonalEventService.christmasEventEnabled()) {
|
if (!this.seasonalEventService.christmasEventEnabled()) {
|
||||||
// Process all bots EXCEPT gifter, he needs christmas items
|
// Process all bots EXCEPT gifter, he needs christmas items
|
||||||
@ -299,62 +304,6 @@ export class BotGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a bot nickname
|
|
||||||
* @param botJsonTemplate x.json from database
|
|
||||||
* @param botGenerationDetails
|
|
||||||
* @param botRole role of bot e.g. assault
|
|
||||||
* @param sessionId OPTIONAL: profile session id
|
|
||||||
* @returns Nickname for bot
|
|
||||||
*/
|
|
||||||
protected generateBotNickname(
|
|
||||||
botJsonTemplate: IBotType,
|
|
||||||
botGenerationDetails: BotGenerationDetails,
|
|
||||||
botRole: string,
|
|
||||||
sessionId?: string,
|
|
||||||
): string {
|
|
||||||
const isPlayerScav = botGenerationDetails.isPlayerScav;
|
|
||||||
|
|
||||||
let name = `${this.randomUtil.getArrayValue(botJsonTemplate.firstName)} ${
|
|
||||||
this.randomUtil.getArrayValue(botJsonTemplate.lastName) || ""
|
|
||||||
}`;
|
|
||||||
name = name.trim();
|
|
||||||
|
|
||||||
// Simulate bot looking like a player scav with the PMC name in brackets.
|
|
||||||
// E.g. "ScavName (PMCName)"
|
|
||||||
if (this.shouldSimulatePlayerScavName(botRole, isPlayerScav)) {
|
|
||||||
return this.addPlayerScavNameSimulationSuffix(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.botConfig.showTypeInNickname && !isPlayerScav) {
|
|
||||||
name += ` ${botRole}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want to replace pmc bot names with player name + prefix
|
|
||||||
if (botGenerationDetails.isPmc && botGenerationDetails.allPmcsHaveSameNameAsPlayer) {
|
|
||||||
const prefix = this.localisationService.getRandomTextThatMatchesPartialKey("pmc-name_prefix_");
|
|
||||||
name = `${prefix} ${name}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected shouldSimulatePlayerScavName(botRole: string, isPlayerScav: boolean): boolean {
|
|
||||||
return (
|
|
||||||
botRole === "assault" &&
|
|
||||||
this.randomUtil.getChance100(this.botConfig.chanceAssaultScavHasPlayerScavName) &&
|
|
||||||
!isPlayerScav
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected addPlayerScavNameSimulationSuffix(nickname: string): string {
|
|
||||||
const pmcNames = [
|
|
||||||
...this.databaseService.getBots().types.usec.firstName,
|
|
||||||
...this.databaseService.getBots().types.bear.firstName,
|
|
||||||
];
|
|
||||||
return `${nickname} (${this.randomUtil.getArrayValue(pmcNames)})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log the number of PMCs generated to the debug console
|
* Log the number of PMCs generated to the debug console
|
||||||
* @param output Generated bot array, ready to send to client
|
* @param output Generated bot array, ready to send to client
|
||||||
|
129
project/src/services/BotNameService.ts
Normal file
129
project/src/services/BotNameService.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
|
||||||
|
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||||
|
import { BotGenerationDetails } from "@spt/models/spt/bots/BotGenerationDetails";
|
||||||
|
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
|
||||||
|
import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig";
|
||||||
|
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||||
|
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||||
|
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||||
|
import { ICloner } from "@spt/utils/cloners/ICloner";
|
||||||
|
import { inject, injectable } from "tsyringe";
|
||||||
|
import { DatabaseService } from "./DatabaseService";
|
||||||
|
import { LocalisationService } from "./LocalisationService";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class BotNameService {
|
||||||
|
protected botConfig: IBotConfig;
|
||||||
|
protected pmcConfig: IPmcConfig;
|
||||||
|
protected usedNameCache: Set<string>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@inject("PrimaryLogger") protected logger: ILogger,
|
||||||
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||||
|
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||||
|
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||||
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
|
@inject("PrimaryCloner") protected cloner: ICloner,
|
||||||
|
) {
|
||||||
|
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
|
||||||
|
this.pmcConfig = this.configServer.getConfig(ConfigTypes.PMC);
|
||||||
|
|
||||||
|
this.usedNameCache = new Set<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear out any entries in Name Set
|
||||||
|
*/
|
||||||
|
public clearNameCache() {
|
||||||
|
this.usedNameCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a unique bot nickname
|
||||||
|
* @param firstNames FIRST names to choose from
|
||||||
|
* @param lastNames OPTIONAL: Names to choose from
|
||||||
|
* @param botGenerationDetails
|
||||||
|
* @param botRole role of bot e.g. assault
|
||||||
|
* @param uniqueRoles Lowercase roles to always make unique
|
||||||
|
* @param sessionId OPTIONAL: profile session id
|
||||||
|
* @returns Nickname for bot
|
||||||
|
*/
|
||||||
|
public generateUniqueBotNickname(
|
||||||
|
firstNames: string[],
|
||||||
|
lastNames: string[],
|
||||||
|
botGenerationDetails: BotGenerationDetails,
|
||||||
|
botRole: string,
|
||||||
|
uniqueRoles?: string[],
|
||||||
|
sessionId?: string,
|
||||||
|
): string {
|
||||||
|
let isUnique = true;
|
||||||
|
let attempts = 0;
|
||||||
|
|
||||||
|
while (attempts < 5) {
|
||||||
|
const isPlayerScav = botGenerationDetails.isPlayerScav;
|
||||||
|
const simulateScavName = isPlayerScav ? false : this.shouldSimulatePlayerScavName(botRole);
|
||||||
|
|
||||||
|
// Get basic name with no whitespace trimmed off sides
|
||||||
|
let name = `${this.randomUtil.getArrayValue(firstNames)} ${this.randomUtil.getArrayValue(lastNames) || ""}`;
|
||||||
|
name = name.trim();
|
||||||
|
|
||||||
|
// Simulate bot looking like a player scav with the PMC name in brackets.
|
||||||
|
// E.g. "ScavName (PMC Name)"
|
||||||
|
if (simulateScavName) {
|
||||||
|
return this.addPlayerScavNameSimulationSuffix(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is set to add role to end of bot name
|
||||||
|
if (this.botConfig.showTypeInNickname && !isPlayerScav) {
|
||||||
|
name += ` ${botRole}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace pmc bot names with player name + prefix
|
||||||
|
if (botGenerationDetails.isPmc && botGenerationDetails.allPmcsHaveSameNameAsPlayer) {
|
||||||
|
const prefix = this.localisationService.getRandomTextThatMatchesPartialKey("pmc-name_prefix_");
|
||||||
|
name = `${prefix} ${name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this a role that must be unique
|
||||||
|
if (uniqueRoles.includes(botRole.toLowerCase())) {
|
||||||
|
// Check name in cache
|
||||||
|
isUnique = !this.usedNameCache.has(name);
|
||||||
|
if (!isUnique) {
|
||||||
|
// Not unique
|
||||||
|
if (attempts >= 5) {
|
||||||
|
// 5 attempts to generate a name, pool probably isn't big enough
|
||||||
|
this.logger.debug(`Failed to find unique name for: ${name} after 5 attempts`);
|
||||||
|
}
|
||||||
|
|
||||||
|
attempts++;
|
||||||
|
|
||||||
|
// Try again
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add bot name to cache to prevent being used again
|
||||||
|
this.usedNameCache.add(name);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should this bot have a name like "name (Pmc Name)"
|
||||||
|
* @param botRole Role bot has
|
||||||
|
* @returns True if name should be simulated pscav
|
||||||
|
*/
|
||||||
|
protected shouldSimulatePlayerScavName(botRole: string): boolean {
|
||||||
|
return botRole === "assault" && this.randomUtil.getChance100(this.botConfig.chanceAssaultScavHasPlayerScavName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected addPlayerScavNameSimulationSuffix(nickname: string): string {
|
||||||
|
const pmcNames = [
|
||||||
|
...this.databaseService.getBots().types.usec.firstName,
|
||||||
|
...this.databaseService.getBots().types.bear.firstName,
|
||||||
|
];
|
||||||
|
return `${nickname} (${this.randomUtil.getArrayValue(pmcNames)})`;
|
||||||
|
}
|
||||||
|
}
|
@ -29,6 +29,7 @@ import { ConfigServer } from "@spt/servers/ConfigServer";
|
|||||||
import { SaveServer } from "@spt/servers/SaveServer";
|
import { SaveServer } from "@spt/servers/SaveServer";
|
||||||
import { BotGenerationCacheService } from "@spt/services/BotGenerationCacheService";
|
import { BotGenerationCacheService } from "@spt/services/BotGenerationCacheService";
|
||||||
import { BotLootCacheService } from "@spt/services/BotLootCacheService";
|
import { BotLootCacheService } from "@spt/services/BotLootCacheService";
|
||||||
|
import { BotNameService } from "@spt/services/BotNameService";
|
||||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||||
import { InsuranceService } from "@spt/services/InsuranceService";
|
import { InsuranceService } from "@spt/services/InsuranceService";
|
||||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||||
@ -71,6 +72,7 @@ export class LocationLifecycleService {
|
|||||||
@inject("BotGenerationCacheService") protected botGenerationCacheService: BotGenerationCacheService,
|
@inject("BotGenerationCacheService") protected botGenerationCacheService: BotGenerationCacheService,
|
||||||
@inject("MailSendService") protected mailSendService: MailSendService,
|
@inject("MailSendService") protected mailSendService: MailSendService,
|
||||||
@inject("RaidTimeAdjustmentService") protected raidTimeAdjustmentService: RaidTimeAdjustmentService,
|
@inject("RaidTimeAdjustmentService") protected raidTimeAdjustmentService: RaidTimeAdjustmentService,
|
||||||
|
@inject("BotNameService") protected botNameService: BotNameService,
|
||||||
@inject("LootGenerator") protected lootGenerator: LootGenerator,
|
@inject("LootGenerator") protected lootGenerator: LootGenerator,
|
||||||
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
|
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
|
||||||
@inject("LocationLootGenerator") protected locationLootGenerator: LocationLootGenerator,
|
@inject("LocationLootGenerator") protected locationLootGenerator: LocationLootGenerator,
|
||||||
@ -95,6 +97,7 @@ export class LocationLifecycleService {
|
|||||||
|
|
||||||
// Clear bot cache ready for a fresh raid
|
// Clear bot cache ready for a fresh raid
|
||||||
this.botGenerationCacheService.clearStoredBots();
|
this.botGenerationCacheService.clearStoredBots();
|
||||||
|
this.botNameService.clearNameCache();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user