mirror of
https://github.com/sp-tarkov/server.git
synced 2025-02-13 05:50:44 -05:00
528 lines
23 KiB
TypeScript
528 lines
23 KiB
TypeScript
import { ApplicationContext } from "@spt/context/ApplicationContext";
|
|
import { ContextVariableType } from "@spt/context/ContextVariableType";
|
|
import { HideoutHelper } from "@spt/helpers/HideoutHelper";
|
|
import { HttpServerHelper } from "@spt/helpers/HttpServerHelper";
|
|
import { InventoryHelper } from "@spt/helpers/InventoryHelper";
|
|
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
|
|
import { PreSptModLoader } from "@spt/loaders/PreSptModLoader";
|
|
import { IEmptyRequestData } from "@spt/models/eft/common/IEmptyRequestData";
|
|
import { IPmcData } from "@spt/models/eft/common/IPmcData";
|
|
import { IBodyPartHealth } from "@spt/models/eft/common/tables/IBotBase";
|
|
import { ICheckVersionResponse } from "@spt/models/eft/game/ICheckVersionResponse";
|
|
import { ICurrentGroupResponse } from "@spt/models/eft/game/ICurrentGroupResponse";
|
|
import { IGameConfigResponse } from "@spt/models/eft/game/IGameConfigResponse";
|
|
import { IGameKeepAliveResponse } from "@spt/models/eft/game/IGameKeepAliveResponse";
|
|
import { IGameModeRequestData } from "@spt/models/eft/game/IGameModeRequestData";
|
|
import { ESessionMode } from "@spt/models/eft/game/IGameModeResponse";
|
|
import { IGetRaidTimeRequest } from "@spt/models/eft/game/IGetRaidTimeRequest";
|
|
import { IGetRaidTimeResponse } from "@spt/models/eft/game/IGetRaidTimeResponse";
|
|
import { IServerDetails } from "@spt/models/eft/game/IServerDetails";
|
|
import { ISptProfile } from "@spt/models/eft/profile/ISptProfile";
|
|
import { BonusType } from "@spt/models/enums/BonusType";
|
|
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
|
import { HideoutAreas } from "@spt/models/enums/HideoutAreas";
|
|
import { SkillTypes } from "@spt/models/enums/SkillTypes";
|
|
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
|
|
import { ICoreConfig } from "@spt/models/spt/config/ICoreConfig";
|
|
import { IHideoutConfig } from "@spt/models/spt/config/IHideoutConfig";
|
|
import { IHttpConfig } from "@spt/models/spt/config/IHttpConfig";
|
|
import { IRagfairConfig } from "@spt/models/spt/config/IRagfairConfig";
|
|
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
|
import { ConfigServer } from "@spt/servers/ConfigServer";
|
|
import { CustomLocationWaveService } from "@spt/services/CustomLocationWaveService";
|
|
import { DatabaseService } from "@spt/services/DatabaseService";
|
|
import { GiftService } from "@spt/services/GiftService";
|
|
import { ItemBaseClassService } from "@spt/services/ItemBaseClassService";
|
|
import { LocalisationService } from "@spt/services/LocalisationService";
|
|
import { OpenZoneService } from "@spt/services/OpenZoneService";
|
|
import { PostDbLoadService } from "@spt/services/PostDbLoadService";
|
|
import { ProfileActivityService } from "@spt/services/ProfileActivityService";
|
|
import { ProfileFixerService } from "@spt/services/ProfileFixerService";
|
|
import { RaidTimeAdjustmentService } from "@spt/services/RaidTimeAdjustmentService";
|
|
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
|
|
import { HashUtil } from "@spt/utils/HashUtil";
|
|
import { RandomUtil } from "@spt/utils/RandomUtil";
|
|
import { TimeUtil } from "@spt/utils/TimeUtil";
|
|
import { ICloner } from "@spt/utils/cloners/ICloner";
|
|
import { inject, injectable } from "tsyringe";
|
|
|
|
@injectable()
|
|
export class GameController {
|
|
protected httpConfig: IHttpConfig;
|
|
protected coreConfig: ICoreConfig;
|
|
protected ragfairConfig: IRagfairConfig;
|
|
protected hideoutConfig: IHideoutConfig;
|
|
protected botConfig: IBotConfig;
|
|
|
|
constructor(
|
|
@inject("PrimaryLogger") protected logger: ILogger,
|
|
@inject("DatabaseService") protected databaseService: DatabaseService,
|
|
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
|
@inject("PreSptModLoader") protected preSptModLoader: PreSptModLoader,
|
|
@inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper,
|
|
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
|
@inject("HideoutHelper") protected hideoutHelper: HideoutHelper,
|
|
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
|
@inject("ProfileFixerService") protected profileFixerService: ProfileFixerService,
|
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
|
@inject("PostDbLoadService") protected postDbLoadService: PostDbLoadService,
|
|
@inject("CustomLocationWaveService") protected customLocationWaveService: CustomLocationWaveService,
|
|
@inject("OpenZoneService") protected openZoneService: OpenZoneService,
|
|
@inject("SeasonalEventService") protected seasonalEventService: SeasonalEventService,
|
|
@inject("ItemBaseClassService") protected itemBaseClassService: ItemBaseClassService,
|
|
@inject("GiftService") protected giftService: GiftService,
|
|
@inject("RaidTimeAdjustmentService") protected raidTimeAdjustmentService: RaidTimeAdjustmentService,
|
|
@inject("ProfileActivityService") protected profileActivityService: ProfileActivityService,
|
|
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
|
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
|
@inject("PrimaryCloner") protected cloner: ICloner,
|
|
) {
|
|
this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP);
|
|
this.coreConfig = this.configServer.getConfig(ConfigTypes.CORE);
|
|
this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR);
|
|
this.hideoutConfig = this.configServer.getConfig(ConfigTypes.HIDEOUT);
|
|
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
|
|
}
|
|
|
|
public load(): void {
|
|
this.postDbLoadService.performPostDbLoadActions();
|
|
}
|
|
|
|
/**
|
|
* Handle client/game/start
|
|
*/
|
|
public gameStart(_url: string, _info: IEmptyRequestData, sessionID: string, startTimeStampMS: number): void {
|
|
// Store client start time in app context
|
|
this.applicationContext.addValue(
|
|
ContextVariableType.CLIENT_START_TIMESTAMP,
|
|
`${sessionID}_${startTimeStampMS}`,
|
|
);
|
|
|
|
this.profileActivityService.setActivityTimestamp(sessionID);
|
|
|
|
// repeatableQuests are stored by in profile.Quests due to the responses of the client (e.g. Quests in
|
|
// offraidData). Since we don't want to clutter the Quests list, we need to remove all completed (failed or
|
|
// successful) repeatable quests. We also have to remove the Counters from the repeatableQuests
|
|
if (sessionID) {
|
|
const fullProfile = this.profileHelper.getFullProfile(sessionID);
|
|
if (fullProfile.info.wipe) {
|
|
// Don't bother doing any fixes, we're resetting profile
|
|
return;
|
|
}
|
|
|
|
if (typeof fullProfile.spt.migrations === "undefined") {
|
|
fullProfile.spt.migrations = {};
|
|
}
|
|
|
|
//3.9 migrations
|
|
if (fullProfile.spt.version.includes("3.9.") && !fullProfile.spt.migrations["39x"]) {
|
|
// Check every item has a valid mongoid
|
|
this.inventoryHelper.validateInventoryUsesMonogoIds(fullProfile.characters.pmc.Inventory.items);
|
|
|
|
this.migrate39xProfile(fullProfile);
|
|
|
|
// Flag as migrated
|
|
fullProfile.spt.migrations["39x"] = this.timeUtil.getTimestamp();
|
|
|
|
this.logger.success(`Migration of 3.9.x profile: ${fullProfile.info.username} completed successfully`);
|
|
}
|
|
|
|
if (Array.isArray(fullProfile.characters.pmc.WishList)) {
|
|
fullProfile.characters.pmc.WishList = {};
|
|
}
|
|
|
|
if (Array.isArray(fullProfile.characters.scav.WishList)) {
|
|
fullProfile.characters.scav.WishList = {};
|
|
}
|
|
|
|
this.logger.debug(`Started game with sessionId: ${sessionID} ${fullProfile.info.username}`);
|
|
|
|
const pmcProfile = fullProfile.characters.pmc;
|
|
|
|
if (this.coreConfig.fixes.fixProfileBreakingInventoryItemIssues) {
|
|
this.profileFixerService.fixProfileBreakingInventoryItemIssues(pmcProfile);
|
|
}
|
|
|
|
if (pmcProfile.Health) {
|
|
this.updateProfileHealthValues(pmcProfile);
|
|
}
|
|
|
|
if (pmcProfile.Inventory) {
|
|
this.sendPraporGiftsToNewProfiles(pmcProfile);
|
|
|
|
this.profileFixerService.checkForOrphanedModdedItems(sessionID, fullProfile);
|
|
}
|
|
|
|
this.profileFixerService.checkForAndFixPmcProfileIssues(pmcProfile);
|
|
|
|
if (pmcProfile.Hideout) {
|
|
this.profileFixerService.addMissingHideoutBonusesToProfile(pmcProfile);
|
|
this.hideoutHelper.setHideoutImprovementsToCompleted(pmcProfile);
|
|
this.hideoutHelper.unlockHideoutWallInProfile(pmcProfile);
|
|
}
|
|
|
|
this.logProfileDetails(fullProfile);
|
|
|
|
this.saveActiveModsToProfile(fullProfile);
|
|
|
|
if (pmcProfile.Info) {
|
|
this.addPlayerToPMCNames(pmcProfile);
|
|
|
|
this.checkForAndRemoveUndefinedDialogs(fullProfile);
|
|
}
|
|
|
|
if (pmcProfile?.Skills?.Common) {
|
|
this.warnOnActiveBotReloadSkill(pmcProfile);
|
|
}
|
|
|
|
this.seasonalEventService.givePlayerSeasonalGifts(sessionID);
|
|
}
|
|
}
|
|
|
|
protected migrate39xProfile(fullProfile: ISptProfile) {
|
|
// Karma & Favorite items
|
|
if (typeof fullProfile.characters.pmc.karmaValue === "undefined") {
|
|
this.logger.warning("Migration: Added karma value of 0.2 to profile");
|
|
fullProfile.characters.pmc.karmaValue = 0.2;
|
|
|
|
// Reset the PMC's favorite items, as the previous data was incorrect.
|
|
this.logger.warning("Migration: Emptied out favoriteItems array on profile.");
|
|
fullProfile.characters.pmc.Inventory.favoriteItems = [];
|
|
}
|
|
|
|
// Remove wall debuffs
|
|
const wallAreaDb = this.databaseService
|
|
.getHideout()
|
|
.areas.find((area) => area.type === HideoutAreas.EMERGENCY_WALL);
|
|
this.hideoutHelper.removeHideoutWallBuffsAndDebuffs(wallAreaDb, fullProfile.characters.pmc);
|
|
|
|
// Equipment area
|
|
const equipmentArea = fullProfile.characters.pmc.Hideout.Areas.find(
|
|
(area) => area.type === HideoutAreas.EQUIPMENT_PRESETS_STAND,
|
|
);
|
|
if (!equipmentArea) {
|
|
this.logger.warning("Migration: Added equipment preset stand hideout area to profile, level 0");
|
|
fullProfile.characters.pmc.Hideout.Areas.push({
|
|
active: true,
|
|
completeTime: 0,
|
|
constructing: false,
|
|
lastRecipe: "",
|
|
level: 0,
|
|
passiveBonusesEnabled: true,
|
|
slots: [],
|
|
type: HideoutAreas.EQUIPMENT_PRESETS_STAND,
|
|
});
|
|
}
|
|
|
|
// Cultist circle area
|
|
const circleArea = fullProfile.characters.pmc.Hideout.Areas.find(
|
|
(area) => area.type === HideoutAreas.CIRCLE_OF_CULTISTS,
|
|
);
|
|
if (!circleArea) {
|
|
this.logger.warning("Migration: Added cultist circle hideout area to profile, level 0");
|
|
fullProfile.characters.pmc.Hideout.Areas.push({
|
|
active: true,
|
|
completeTime: 0,
|
|
constructing: false,
|
|
lastRecipe: "",
|
|
level: 0,
|
|
passiveBonusesEnabled: true,
|
|
slots: [],
|
|
type: HideoutAreas.CIRCLE_OF_CULTISTS,
|
|
});
|
|
}
|
|
|
|
// Hideout Improvement property changed name
|
|
if ((fullProfile.characters.pmc.Hideout as any).Improvement) {
|
|
fullProfile.characters.pmc.Hideout.Improvements = (fullProfile.characters.pmc.Hideout as any).Improvement;
|
|
delete (fullProfile.characters.pmc.Hideout as any).Improvement;
|
|
this.logger.warning(`Migration: Moved Hideout Improvement data to new property 'Improvements'`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle client/game/config
|
|
*/
|
|
public getGameConfig(sessionID: string): IGameConfigResponse {
|
|
const profile = this.profileHelper.getPmcProfile(sessionID);
|
|
const gameTime =
|
|
profile.Stats?.Eft.OverallCounters.Items?.find(
|
|
(counter) => counter.Key.includes("LifeTime") && counter.Key.includes("Pmc"),
|
|
)?.Value ?? 0;
|
|
|
|
const config: IGameConfigResponse = {
|
|
languages: this.databaseService.getLocales().languages,
|
|
ndaFree: false,
|
|
reportAvailable: false,
|
|
twitchEventMember: false,
|
|
lang: "en",
|
|
aid: profile.aid,
|
|
taxonomy: 6,
|
|
activeProfileId: sessionID,
|
|
backend: {
|
|
Lobby: this.httpServerHelper.getBackendUrl(),
|
|
Trading: this.httpServerHelper.getBackendUrl(),
|
|
Messaging: this.httpServerHelper.getBackendUrl(),
|
|
Main: this.httpServerHelper.getBackendUrl(),
|
|
RagFair: this.httpServerHelper.getBackendUrl(),
|
|
},
|
|
useProtobuf: false,
|
|
utc_time: new Date().getTime() / 1000,
|
|
totalInGame: gameTime,
|
|
};
|
|
|
|
return config;
|
|
}
|
|
|
|
/**
|
|
* Handle client/game/mode
|
|
*/
|
|
public getGameMode(sessionID: string, info: IGameModeRequestData): any {
|
|
return { gameMode: ESessionMode.PVE, backendUrl: this.httpServerHelper.getBackendUrl() };
|
|
}
|
|
|
|
/**
|
|
* Handle client/server/list
|
|
*/
|
|
public getServer(sessionId: string): IServerDetails[] {
|
|
return [{ ip: this.httpConfig.backendIp, port: Number.parseInt(this.httpConfig.backendPort) }];
|
|
}
|
|
|
|
/**
|
|
* Handle client/match/group/current
|
|
*/
|
|
public getCurrentGroup(sessionId: string): ICurrentGroupResponse {
|
|
return { squad: [] };
|
|
}
|
|
|
|
/**
|
|
* Handle client/checkVersion
|
|
*/
|
|
public getValidGameVersion(sessionId: string): ICheckVersionResponse {
|
|
return { isvalid: true, latestVersion: this.coreConfig.compatibleTarkovVersion };
|
|
}
|
|
|
|
/**
|
|
* Handle client/game/keepalive
|
|
*/
|
|
public getKeepAlive(sessionId: string): IGameKeepAliveResponse {
|
|
this.profileActivityService.setActivityTimestamp(sessionId);
|
|
return { msg: "OK", utc_time: new Date().getTime() / 1000 };
|
|
}
|
|
|
|
/**
|
|
* Handle singleplayer/settings/getRaidTime
|
|
*/
|
|
public getRaidTime(sessionId: string, request: IGetRaidTimeRequest): IGetRaidTimeResponse {
|
|
// Set interval times to in-raid value
|
|
this.ragfairConfig.runIntervalSeconds = this.ragfairConfig.runIntervalValues.inRaid;
|
|
|
|
this.hideoutConfig.runIntervalSeconds = this.hideoutConfig.runIntervalValues.inRaid;
|
|
|
|
return this.raidTimeAdjustmentService.getRaidAdjustments(sessionId, request);
|
|
}
|
|
|
|
/**
|
|
* Players set botReload to a high value and don't expect the crazy fast reload speeds, give them a warn about it
|
|
* @param pmcProfile Player profile
|
|
*/
|
|
protected warnOnActiveBotReloadSkill(pmcProfile: IPmcData): void {
|
|
const botReloadSkill = this.profileHelper.getSkillFromProfile(pmcProfile, SkillTypes.BOT_RELOAD);
|
|
if (botReloadSkill?.Progress > 0) {
|
|
this.logger.warning(this.localisationService.getText("server_start_player_active_botreload_skill"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* When player logs in, iterate over all active effects and reduce timer
|
|
* @param pmcProfile Profile to adjust values for
|
|
*/
|
|
protected updateProfileHealthValues(pmcProfile: IPmcData): void {
|
|
const healthLastUpdated = pmcProfile.Health.UpdateTime;
|
|
const currentTimeStamp = this.timeUtil.getTimestamp();
|
|
const diffSeconds = currentTimeStamp - healthLastUpdated;
|
|
|
|
// Last update is in past
|
|
if (healthLastUpdated < currentTimeStamp) {
|
|
// Base values
|
|
let energyRegenPerHour = 60;
|
|
let hydrationRegenPerHour = 60;
|
|
let hpRegenPerHour = 456.6;
|
|
|
|
// Set new values, whatever is smallest
|
|
energyRegenPerHour += pmcProfile.Bonuses.filter(
|
|
(bonus) => bonus.type === BonusType.ENERGY_REGENERATION,
|
|
).reduce((sum, curr) => sum + (curr.value ?? 0), 0);
|
|
hydrationRegenPerHour += pmcProfile.Bonuses.filter(
|
|
(bonus) => bonus.type === BonusType.HYDRATION_REGENERATION,
|
|
).reduce((sum, curr) => sum + (curr.value ?? 0), 0);
|
|
hpRegenPerHour += pmcProfile.Bonuses.filter((bonus) => bonus.type === BonusType.HEALTH_REGENERATION).reduce(
|
|
(sum, curr) => sum + (curr.value ?? 0),
|
|
0,
|
|
);
|
|
|
|
// Player has energy deficit
|
|
if (pmcProfile.Health.Energy.Current !== pmcProfile.Health.Energy.Maximum) {
|
|
// Set new value, whatever is smallest
|
|
pmcProfile.Health.Energy.Current += Math.round(energyRegenPerHour * (diffSeconds / 3600));
|
|
if (pmcProfile.Health.Energy.Current > pmcProfile.Health.Energy.Maximum) {
|
|
pmcProfile.Health.Energy.Current = pmcProfile.Health.Energy.Maximum;
|
|
}
|
|
}
|
|
|
|
// Player has hydration deficit
|
|
if (pmcProfile.Health.Hydration.Current !== pmcProfile.Health.Hydration.Maximum) {
|
|
pmcProfile.Health.Hydration.Current += Math.round(hydrationRegenPerHour * (diffSeconds / 3600));
|
|
if (pmcProfile.Health.Hydration.Current > pmcProfile.Health.Hydration.Maximum) {
|
|
pmcProfile.Health.Hydration.Current = pmcProfile.Health.Hydration.Maximum;
|
|
}
|
|
}
|
|
|
|
// Check all body parts
|
|
for (const bodyPartKey in pmcProfile.Health.BodyParts) {
|
|
const bodyPart = pmcProfile.Health.BodyParts[bodyPartKey] as IBodyPartHealth;
|
|
|
|
// Check part hp
|
|
if (bodyPart.Health.Current < bodyPart.Health.Maximum) {
|
|
bodyPart.Health.Current += Math.round(hpRegenPerHour * (diffSeconds / 3600));
|
|
}
|
|
if (bodyPart.Health.Current > bodyPart.Health.Maximum) {
|
|
bodyPart.Health.Current = bodyPart.Health.Maximum;
|
|
}
|
|
|
|
// Look for effects
|
|
if (Object.keys(bodyPart.Effects ?? {}).length > 0) {
|
|
for (const effectKey in bodyPart.Effects) {
|
|
// remove effects below 1, .e.g. bleeds at -1
|
|
if (bodyPart.Effects[effectKey].Time < 1) {
|
|
// More than 30 mins has passed
|
|
if (diffSeconds > 1800) {
|
|
delete bodyPart.Effects[effectKey];
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Decrement effect time value by difference between current time and time health was last updated
|
|
bodyPart.Effects[effectKey].Time -= diffSeconds;
|
|
if (bodyPart.Effects[effectKey].Time < 1) {
|
|
// effect time was sub 1, set floor it can be
|
|
bodyPart.Effects[effectKey].Time = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update both values as they've both been updated
|
|
pmcProfile.Health.UpdateTime = currentTimeStamp;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send starting gifts to profile after x days
|
|
* @param pmcProfile Profile to add gifts to
|
|
*/
|
|
protected sendPraporGiftsToNewProfiles(pmcProfile: IPmcData): void {
|
|
const timeStampProfileCreated = pmcProfile.Info.RegistrationDate;
|
|
const oneDaySeconds = this.timeUtil.getHoursAsSeconds(24);
|
|
const currentTimeStamp = this.timeUtil.getTimestamp();
|
|
|
|
// One day post-profile creation
|
|
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds) {
|
|
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 1);
|
|
}
|
|
|
|
// Two day post-profile creation
|
|
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds * 2) {
|
|
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 2);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a list of installed mods and save their details to the profile being used
|
|
* @param fullProfile Profile to add mod details to
|
|
*/
|
|
protected saveActiveModsToProfile(fullProfile: ISptProfile): void {
|
|
// Add empty mod array if undefined
|
|
if (!fullProfile.spt.mods) {
|
|
fullProfile.spt.mods = [];
|
|
}
|
|
|
|
// Get active mods
|
|
const activeMods = this.preSptModLoader.getImportedModDetails();
|
|
for (const modKey in activeMods) {
|
|
const modDetails = activeMods[modKey];
|
|
if (
|
|
fullProfile.spt.mods.some(
|
|
(mod) =>
|
|
mod.author === modDetails.author &&
|
|
mod.name === modDetails.name &&
|
|
mod.version === modDetails.version,
|
|
)
|
|
) {
|
|
// Exists already, skip
|
|
continue;
|
|
}
|
|
|
|
fullProfile.spt.mods.push({
|
|
author: modDetails.author,
|
|
dateAdded: Date.now(),
|
|
name: modDetails.name,
|
|
version: modDetails.version,
|
|
url: modDetails.url,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add the logged in players name to PMC name pool
|
|
* @param pmcProfile Profile of player to get name from
|
|
*/
|
|
protected addPlayerToPMCNames(pmcProfile: IPmcData): void {
|
|
const playerName = pmcProfile.Info.Nickname;
|
|
if (playerName) {
|
|
const bots = this.databaseService.getBots().types;
|
|
|
|
// Official names can only be 15 chars in length
|
|
if (playerName.length > this.botConfig.botNameLengthLimit) {
|
|
return;
|
|
}
|
|
|
|
// Skip if player name exists already
|
|
if (bots.bear?.firstName.some((x) => x === playerName)) {
|
|
return;
|
|
}
|
|
|
|
if (bots.bear) {
|
|
bots.bear.firstName.push(playerName);
|
|
}
|
|
|
|
if (bots.usec) {
|
|
bots.usec.firstName.push(playerName);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check for a dialog with the key 'undefined', and remove it
|
|
* @param fullProfile Profile to check for dialog in
|
|
*/
|
|
protected checkForAndRemoveUndefinedDialogs(fullProfile: ISptProfile): void {
|
|
const undefinedDialog = fullProfile.dialogues.undefined;
|
|
if (undefinedDialog) {
|
|
delete fullProfile.dialogues.undefined;
|
|
}
|
|
}
|
|
|
|
protected logProfileDetails(fullProfile: ISptProfile): void {
|
|
this.logger.debug(`Profile made with: ${fullProfile.spt.version}`);
|
|
this.logger.debug(
|
|
`Server version: ${globalThis.G_SPTVERSION || this.coreConfig.sptVersion} ${globalThis.G_COMMIT}`,
|
|
);
|
|
this.logger.debug(`Debug enabled: ${globalThis.G_DEBUG_CONFIGURATION}`);
|
|
this.logger.debug(`Mods enabled: ${globalThis.G_MODS_ENABLED}`);
|
|
}
|
|
}
|