From 0ade8f4b9c4420395b08a34cca46de50a074733b Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 25 Dec 2023 08:38:42 +0000 Subject: [PATCH] Added configs and simplification to ChatBot (!180) Co-authored-by: clodan Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/180 Co-authored-by: Alex Co-committed-by: Alex --- project/assets/configs/core.json | 9 ++- project/src/controllers/DialogueController.ts | 59 ++++++++++-------- project/src/di/Container.ts | 21 ++++--- .../Dialogue/Commando/ICommandoAction.ts | 7 --- .../Dialogue/Commando/ICommandoCommand.ts | 5 +- .../Dialogue/Commando/SptCommandoCommands.ts | 47 ++++++++++++--- .../Commando/SptCommands/GiveSptCommand.ts | 2 +- .../Commando/SptCommands/ISptCommand.ts | 6 +- .../Dialogue/CommandoDialogueChatBot.ts | 60 +++++++------------ project/src/models/spt/config/ICoreConfig.ts | 13 ++++ 10 files changed, 136 insertions(+), 93 deletions(-) delete mode 100644 project/src/helpers/Dialogue/Commando/ICommandoAction.ts diff --git a/project/assets/configs/core.json b/project/assets/configs/core.json index 4f4f8bd9..56b94fcc 100644 --- a/project/assets/configs/core.json +++ b/project/assets/configs/core.json @@ -12,6 +12,13 @@ }, "features": { "autoInstallModDependencies": false, - "compressProfile": false + "compressProfile": false, + "chatbotFeatures": { + "sptFriendEnabled": true, + "commandoEnabled": true, + "commandoFeatures": { + "giveCommandEnabled": false + } + } } } diff --git a/project/src/controllers/DialogueController.ts b/project/src/controllers/DialogueController.ts index 1407d3d6..51125bcb 100644 --- a/project/src/controllers/DialogueController.ts +++ b/project/src/controllers/DialogueController.ts @@ -8,8 +8,11 @@ import { IGetMailDialogViewRequestData } from "@spt-aki/models/eft/dialog/IGetMa import { IGetMailDialogViewResponseData } from "@spt-aki/models/eft/dialog/IGetMailDialogViewResponseData"; import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; import { Dialogue, DialogueInfo, IAkiProfile, IUserDialogInfo, Message } from "@spt-aki/models/eft/profile/IAkiProfile"; +import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { MessageType } from "@spt-aki/models/enums/MessageType"; +import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; +import { ConfigServer } from "@spt-aki/servers/ConfigServer"; import { SaveServer } from "@spt-aki/servers/SaveServer"; import { MailSendService } from "@spt-aki/services/MailSendService"; import { TimeUtil } from "@spt-aki/utils/TimeUtil"; @@ -17,28 +20,39 @@ import { TimeUtil } from "@spt-aki/utils/TimeUtil"; @injectable() export class DialogueController { - protected registeredDialogueChatBots: Map = new Map(); - constructor( @inject("WinstonLogger") protected logger: ILogger, @inject("SaveServer") protected saveServer: SaveServer, @inject("TimeUtil") protected timeUtil: TimeUtil, @inject("DialogueHelper") protected dialogueHelper: DialogueHelper, @inject("MailSendService") protected mailSendService: MailSendService, + @inject("ConfigServer") protected configServer: ConfigServer, @injectAll("DialogueChatBot") protected dialogueChatBots: IDialogueChatBot[], ) { - for (const dialogueChatBot of dialogueChatBots) + const coreConfigs = this.configServer.getConfig(ConfigTypes.CORE); + // if give command is disabled or commando commands are disabled + if (!coreConfigs.features?.chatbotFeatures?.commandoEnabled) { - if (this.registeredDialogueChatBots.has(dialogueChatBot.getChatBot()._id)) - { - this.logger.error( - `Could not register ${dialogueChatBot.getChatBot()._id} as it is already in use. Skipping.`, - ); - continue; - } - this.registeredDialogueChatBots.set(dialogueChatBot.getChatBot()._id, dialogueChatBot); + const sptCommando = this.dialogueChatBots.find((c) => + c.getChatBot()._id.toLocaleLowerCase() === "sptcommando" + ); + this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1); } + if (!coreConfigs.features?.chatbotFeatures?.sptFriendEnabled) + { + const sptFriend = this.dialogueChatBots.find((c) => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend"); + this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptFriend), 1); + } + } + + public registerChatBot(chatBot: IDialogueChatBot): void + { + if (this.dialogueChatBots.some((cb) => cb.getChatBot()._id === chatBot.getChatBot()._id)) + { + throw new Error(`The chat bot ${chatBot.getChatBot()._id} being registered already exists!`); + } + this.dialogueChatBots.push(chatBot); } /** Handle onUpdate spt event */ @@ -59,11 +73,7 @@ export class DialogueController public getFriendList(sessionID: string): IGetFriendListDataResponse { // Force a fake friend called SPT into friend list - return { - Friends: Array.from(this.registeredDialogueChatBots.values()).map((v) => v.getChatBot()), - Ignore: [], - InIgnoreList: [], - }; + return { Friends: this.dialogueChatBots.map((v) => v.getChatBot()), Ignore: [], InIgnoreList: [] }; } /** @@ -196,11 +206,10 @@ export class DialogueController if (request.type === MessageType.USER_MESSAGE) { profile.dialogues[request.dialogId].Users = []; - if (this.registeredDialogueChatBots.has(request.dialogId)) + const chatBot = this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId); + if (chatBot) { - profile.dialogues[request.dialogId].Users.push( - this.registeredDialogueChatBots.get(request.dialogId).getChatBot(), - ); + profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot()); } } } @@ -364,12 +373,10 @@ export class DialogueController { this.mailSendService.sendPlayerMessageToNpc(sessionId, request.dialogId, request.text); - if (this.registeredDialogueChatBots.has(request.dialogId)) - { - return this.registeredDialogueChatBots.get(request.dialogId).handleMessage(sessionId, request); - } - - return request.dialogId; + return this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId)?.handleMessage( + sessionId, + request, + ) ?? request.dialogId; } /** diff --git a/project/src/di/Container.ts b/project/src/di/Container.ts index 59585894..990d1d39 100644 --- a/project/src/di/Container.ts +++ b/project/src/di/Container.ts @@ -86,6 +86,10 @@ import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper"; import { BotHelper } from "@spt-aki/helpers/BotHelper"; import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper"; import { ContainerHelper } from "@spt-aki/helpers/ContainerHelper"; +import { SptCommandoCommands } from "@spt-aki/helpers/Dialogue/Commando/SptCommandoCommands"; +import { GiveSptCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/GiveSptCommand"; +import { CommandoDialogueChatBot } from "@spt-aki/helpers/Dialogue/CommandoDialogueChatBot"; +import { SptDialogueChatBot } from "@spt-aki/helpers/Dialogue/SptDialogueChatBot"; import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper"; import { DurabilityLimitsHelper } from "@spt-aki/helpers/DurabilityLimitsHelper"; import { GameEventHelper } from "@spt-aki/helpers/GameEventHelper"; @@ -246,10 +250,6 @@ import { VFS } from "@spt-aki/utils/VFS"; import { Watermark, WatermarkLocale } from "@spt-aki/utils/Watermark"; import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger"; import { WinstonRequestLogger } from "@spt-aki/utils/logging/WinstonRequestLogger"; -import {SptDialogueChatBot} from "@spt-aki/helpers/Dialogue/SptDialogueChatBot"; -import {CommandoDialogueChatBot} from "@spt-aki/helpers/Dialogue/CommandoDialogueChatBot"; -import {GiveSptCommand} from "@spt-aki/helpers/Dialogue/Commando/SptCommands/GiveSptCommand"; -import {SptCommandoCommands} from "@spt-aki/helpers/Dialogue/Commando/SptCommandoCommands"; /** * Handle the registration of classes to be used by the Dependency Injection code @@ -583,12 +583,15 @@ export class Container // ChatBots depContainer.register("SptDialogueChatBot", SptDialogueChatBot); - depContainer.register("CommandoDialogueChatBot", CommandoDialogueChatBot); + depContainer.register("CommandoDialogueChatBot", CommandoDialogueChatBot, { + lifecycle: Lifecycle.Singleton, + }); // SptCommando - depContainer.register("SptCommandoCommands", SptCommandoCommands); + depContainer.register("SptCommandoCommands", SptCommandoCommands, { + lifecycle: Lifecycle.Singleton, + }); // SptCommands depContainer.register("GiveSptCommand", GiveSptCommand); - } private static registerLoaders(depContainer: DependencyContainer): void @@ -753,7 +756,9 @@ export class Container depContainer.register("CustomizationController", { useClass: CustomizationController, }); - depContainer.register("DialogueController", { useClass: DialogueController }); + depContainer.register("DialogueController", { useClass: DialogueController }, { + lifecycle: Lifecycle.Singleton, + }); depContainer.register("GameController", { useClass: GameController }); depContainer.register("HandbookController", { useClass: HandbookController }); depContainer.register("HealthController", { useClass: HealthController }); diff --git a/project/src/helpers/Dialogue/Commando/ICommandoAction.ts b/project/src/helpers/Dialogue/Commando/ICommandoAction.ts deleted file mode 100644 index 62cfaf01..00000000 --- a/project/src/helpers/Dialogue/Commando/ICommandoAction.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; -import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile"; - -export interface ICommandoAction -{ - handle(commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string; -} diff --git a/project/src/helpers/Dialogue/Commando/ICommandoCommand.ts b/project/src/helpers/Dialogue/Commando/ICommandoCommand.ts index 39338bb0..03083f3b 100644 --- a/project/src/helpers/Dialogue/Commando/ICommandoCommand.ts +++ b/project/src/helpers/Dialogue/Commando/ICommandoCommand.ts @@ -1,9 +1,10 @@ -import { ICommandoAction } from "@spt-aki/helpers/Dialogue/Commando/ICommandoAction"; +import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; +import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile"; export interface ICommandoCommand { getCommandPrefix(): string; getCommandHelp(command: string): string; getCommands(): Set; - getCommandAction(command: string): ICommandoAction; + handle(command: string, commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string; } diff --git a/project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts b/project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts index a087880d..82017853 100644 --- a/project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts +++ b/project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts @@ -1,22 +1,44 @@ -import { ICommandoAction } from "@spt-aki/helpers/Dialogue/Commando/ICommandoAction"; import { ICommandoCommand } from "@spt-aki/helpers/Dialogue/Commando/ICommandoCommand"; import { ISptCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/ISptCommand"; import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile"; -import { injectAll, injectable } from "tsyringe"; +import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; +import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig"; +import { ConfigServer } from "@spt-aki/servers/ConfigServer"; +import { inject, injectAll, injectable } from "tsyringe"; @injectable() export class SptCommandoCommands implements ICommandoCommand { constructor( - @injectAll("SptCommand") protected sptCommands: ISptCommand[] + @inject("ConfigServer") protected configServer: ConfigServer, + @injectAll("SptCommand") protected sptCommands: ISptCommand[], ) { + const coreConfigs = this.configServer.getConfig(ConfigTypes.CORE); + // if give command is disabled or commando commands are disabled + if ( + !(coreConfigs.features?.chatbotFeatures?.commandoFeatures?.giveCommandEnabled + && coreConfigs.features?.chatbotFeatures?.commandoEnabled) + ) + { + const giveCommand = this.sptCommands.find((c) => c.getCommand().toLocaleLowerCase() === "give"); + this.sptCommands.splice(this.sptCommands.indexOf(giveCommand), 1); + } + } + + public registerSptCommandoCommand(command: ISptCommand): void + { + if (this.sptCommands.some((c) => c.getCommand() === command.getCommand())) + { + throw new Error(`The command ${command.getCommand()} being registered for SPT Commands already exists!`); + } + this.sptCommands.push(command); } public getCommandHelp(command: string): string { - return this.sptCommands.find(c => c.getCommand() === command)?.getCommandHelp(); + return this.sptCommands.find((c) => c.getCommand() === command)?.getCommandHelp(); } public getCommandPrefix(): string @@ -26,13 +48,20 @@ export class SptCommandoCommands implements ICommandoCommand public getCommands(): Set { - return new Set(this.sptCommands.map(c => c.getCommand())); + return new Set(this.sptCommands.map((c) => c.getCommand())); } - public getCommandAction(command: string): ICommandoAction + public handle( + command: string, + commandHandler: IUserDialogInfo, + sessionId: string, + request: ISendMessageRequest, + ): string { - return this.sptCommands.find(c => c.getCommand() === command); + return this.sptCommands.find((c) => c.getCommand() === command).performAction( + commandHandler, + sessionId, + request, + ); } - - } diff --git a/project/src/helpers/Dialogue/Commando/SptCommands/GiveSptCommand.ts b/project/src/helpers/Dialogue/Commando/SptCommands/GiveSptCommand.ts index e19f732e..a9731beb 100644 --- a/project/src/helpers/Dialogue/Commando/SptCommands/GiveSptCommand.ts +++ b/project/src/helpers/Dialogue/Commando/SptCommands/GiveSptCommand.ts @@ -35,7 +35,7 @@ export class GiveSptCommand implements ISptCommand return "Usage: spt give tplId quantity"; } - public handle(commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string + public performAction(commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string { const giveCommand = request.text.split(" "); if (giveCommand[1] !== "give") diff --git a/project/src/helpers/Dialogue/Commando/SptCommands/ISptCommand.ts b/project/src/helpers/Dialogue/Commando/SptCommands/ISptCommand.ts index b187b62e..8aedd1ab 100644 --- a/project/src/helpers/Dialogue/Commando/SptCommands/ISptCommand.ts +++ b/project/src/helpers/Dialogue/Commando/SptCommands/ISptCommand.ts @@ -1,7 +1,9 @@ -import { ICommandoAction } from "@spt-aki/helpers/Dialogue/Commando/ICommandoAction"; +import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; +import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile"; -export interface ISptCommand extends ICommandoAction +export interface ISptCommand { getCommand(): string; getCommandHelp(): string; + performAction(commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string; } diff --git a/project/src/helpers/Dialogue/CommandoDialogueChatBot.ts b/project/src/helpers/Dialogue/CommandoDialogueChatBot.ts index 8bbaff1d..e73cda1c 100644 --- a/project/src/helpers/Dialogue/CommandoDialogueChatBot.ts +++ b/project/src/helpers/Dialogue/CommandoDialogueChatBot.ts @@ -1,6 +1,5 @@ import { inject, injectAll, injectable } from "tsyringe"; -import { ICommandoAction } from "@spt-aki/helpers/Dialogue/Commando/ICommandoAction"; import { ICommandoCommand } from "@spt-aki/helpers/Dialogue/Commando/ICommandoCommand"; import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot"; import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; @@ -12,42 +11,30 @@ import { MailSendService } from "@spt-aki/services/MailSendService"; @injectable() export class CommandoDialogueChatBot implements IDialogueChatBot { - - // A map that contains the command prefix. That contains a map that contains the prefix commands with their respective actions. - protected registeredCommands: Map> = new Map>(); public constructor( @inject("WinstonLogger") protected logger: ILogger, @inject("MailSendService") protected mailSendService: MailSendService, - @injectAll("CommandoCommand") protected commandoCommands: ICommandoCommand[] + @injectAll("CommandoCommand") protected commandoCommands: ICommandoCommand[], ) { - for (const commandoCommand of commandoCommands) - { - if (this.registeredCommands.has(commandoCommand.getCommandPrefix()) || commandoCommand.getCommandPrefix().toLowerCase() === "help") - { - this.logger.error(`Could not registered command prefix ${commandoCommand.getCommandPrefix()} as it already has been registered. Skipping.`); - continue; - } + } - const commandMap = new Map(); - this.registeredCommands.set(commandoCommand.getCommandPrefix(), commandMap); - for (const command of commandoCommand.getCommands()) - { - commandMap.set(command, commandoCommand.getCommandAction(command)) - } + public registerCommandoCommand(commandoCommand: ICommandoCommand): void + { + if (this.commandoCommands.some((cc) => cc.getCommandPrefix() === commandoCommand.getCommandPrefix())) + { + throw new Error( + `The commando command ${commandoCommand.getCommandPrefix()} being registered already exists!`, + ); } + this.commandoCommands.push(commandoCommand); } public getChatBot(): IUserDialogInfo { return { _id: "sptCommando", - info: { - Level: 1, - MemberCategory: MemberCategory.DEVELOPER, - Nickname: "Commando", - Side: "Usec", - }, + info: { Level: 1, MemberCategory: MemberCategory.DEVELOPER, Nickname: "Commando", Side: "Usec" }, }; } @@ -61,28 +48,27 @@ export class CommandoDialogueChatBot implements IDialogueChatBot const splitCommand = request.text.split(" "); - if (this.registeredCommands.has(splitCommand[0]) && this.registeredCommands.get(splitCommand[0]).has(splitCommand[1])) - return this.registeredCommands.get(splitCommand[0]).get(splitCommand[1]).handle(this.getChatBot(), sessionId, request); + const commandos = this.commandoCommands.filter((c) => c.getCommandPrefix() === splitCommand[0]); + if (commandos[0]?.getCommands().has(splitCommand[1])) + { + return commandos[0].handle(splitCommand[1], this.getChatBot(), sessionId, request); + } if (splitCommand[0].toLowerCase() === "help") { - const helpMessage = this.commandoCommands.filter(c => this.registeredCommands.has(c.getCommandPrefix())) - .filter(c => Array.from(c.getCommands()).some(com => this.registeredCommands.get(c.getCommandPrefix()).has(com))) - .map(c => `Help for ${c.getCommandPrefix()}:\n${Array.from(c.getCommands()).map(command => c.getCommandHelp(command)).join("\n")}`) - .join("\n"); - this.mailSendService.sendUserMessageToPlayer( - sessionId, - this.getChatBot(), - helpMessage - ); + const helpMessage = this.commandoCommands.map((c) => + `Help for ${c.getCommandPrefix()}:\n${ + Array.from(c.getCommands()).map((command) => c.getCommandHelp(command)).join("\n") + }` + ).join("\n"); + this.mailSendService.sendUserMessageToPlayer(sessionId, this.getChatBot(), helpMessage); return request.dialogId; } this.mailSendService.sendUserMessageToPlayer( sessionId, this.getChatBot(), - `Im sorry soldier, I dont recognize the command you are trying to use! Type "help" to see available commands.` + `Im sorry soldier, I dont recognize the command you are trying to use! Type "help" to see available commands.`, ); } - } diff --git a/project/src/models/spt/config/ICoreConfig.ts b/project/src/models/spt/config/ICoreConfig.ts index 13cebaec..e5ef1e81 100644 --- a/project/src/models/spt/config/ICoreConfig.ts +++ b/project/src/models/spt/config/ICoreConfig.ts @@ -32,4 +32,17 @@ export interface IServerFeatures /* Controls whether or not the server attempts to download mod dependencies not included in the server's executable */ autoInstallModDependencies: boolean; compressProfile: boolean; + chatbotFeatures: IChatbotFeatures; +} + +export interface IChatbotFeatures +{ + sptFriendEnabled: boolean; + commandoEnabled: boolean; + commandoFeatures: ICommandoFeatures; +} + +export interface ICommandoFeatures +{ + giveCommandEnabled: boolean; }