Server/project/src/helpers/DialogueHelper.ts
TheSparta 418d9f2a8f Import path alias on the whole project (!157)
- Ability to use @spt-aki path alias on the whole project.
- Swapped all imports from relative paths, for imports using the path alias.

Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/157
Co-authored-by: TheSparta <thesparta@noreply.dev.sp-tarkov.com>
Co-committed-by: TheSparta <thesparta@noreply.dev.sp-tarkov.com>
2023-10-19 17:21:17 +00:00

243 lines
8.5 KiB
TypeScript

import { inject, injectable } from "tsyringe";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { NotificationSendHelper } from "@spt-aki/helpers/NotificationSendHelper";
import { NotifierHelper } from "@spt-aki/helpers/NotifierHelper";
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
import { Dialogue, Message, MessageContent, MessageItems, MessagePreview } from "@spt-aki/models/eft/profile/IAkiProfile";
import { MessageType } from "@spt-aki/models/enums/MessageType";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
import { SaveServer } from "@spt-aki/servers/SaveServer";
import { LocalisationService } from "@spt-aki/services/LocalisationService";
import { HashUtil } from "@spt-aki/utils/HashUtil";
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
@injectable()
export class DialogueHelper
{
constructor(
@inject("WinstonLogger") protected logger: ILogger,
@inject("HashUtil") protected hashUtil: HashUtil,
@inject("SaveServer") protected saveServer: SaveServer,
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
@inject("NotifierHelper") protected notifierHelper: NotifierHelper,
@inject("NotificationSendHelper") protected notificationSendHelper: NotificationSendHelper,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("ItemHelper") protected itemHelper: ItemHelper
)
{ }
/**
* @deprecated Use MailSendService.sendMessage() or helpers
*/
public createMessageContext(templateId: string, messageType: MessageType, maxStoreTime = null): MessageContent
{
const result: MessageContent = {
templateId: templateId,
type: messageType
};
if (maxStoreTime)
{
result.maxStorageTime = maxStoreTime * TimeUtil.oneHourAsSeconds;
}
return result;
}
/**
* @deprecated Use MailSendService.sendMessage() or helpers
*/
public addDialogueMessage(dialogueID: string, messageContent: MessageContent, sessionID: string, rewards: Item[] = [], messageType = MessageType.NPC_TRADER): void
{
const dialogueData = this.saveServer.getProfile(sessionID).dialogues;
const isNewDialogue = !(dialogueID in dialogueData);
let dialogue: Dialogue = dialogueData[dialogueID];
if (isNewDialogue)
{
dialogue = {
_id: dialogueID,
type: messageType,
messages: [],
pinned: false,
new: 0,
attachmentsNew: 0
};
dialogueData[dialogueID] = dialogue;
}
dialogue.new += 1;
// Generate item stash if we have rewards.
let items: MessageItems = {};
if (rewards.length > 0)
{
const stashId = this.hashUtil.generate();
items = {
stash: stashId,
data: []
};
rewards = this.itemHelper.replaceIDs(null, rewards);
for (const reward of rewards)
{
if (!("slotId" in reward) || reward.slotId === "hideout")
{
reward.parentId = stashId;
reward.slotId = "main";
}
const itemTemplate = this.databaseServer.getTables().templates.items[reward._tpl];
if (!itemTemplate)
{
// Can happen when modded items are insured + mod is removed
this.logger.error(this.localisationService.getText("dialog-missing_item_template", {tpl: reward._tpl, type: MessageType[messageContent.type]}));
continue;
}
items.data.push(reward);
if ("StackSlots" in itemTemplate._props)
{
const stackSlotItems = this.itemHelper.generateItemsFromStackSlot(itemTemplate, reward._id);
for (const itemToAdd of stackSlotItems)
{
items.data.push(itemToAdd);
}
}
}
if (items.data.length === 0)
{
delete items.data;
}
dialogue.attachmentsNew += 1;
}
const message: Message = {
_id: this.hashUtil.generate(),
uid: dialogueID,
type: messageContent.type,
dt: Math.round(Date.now() / 1000),
text: messageContent.text ?? "",
templateId: messageContent.templateId,
hasRewards: items.data?.length > 0,
rewardCollected: false,
items: items,
maxStorageTime: messageContent.maxStorageTime,
systemData: messageContent.systemData ? messageContent.systemData : undefined,
profileChangeEvents: (messageContent.profileChangeEvents?.length === 0) ? messageContent.profileChangeEvents : undefined
};
if (!message.templateId)
{
delete message.templateId;
}
dialogue.messages.push(message);
// Offer Sold notifications are now separate from the main notification
if (messageContent.type === MessageType.FLEAMARKET_MESSAGE && messageContent.ragfair)
{
const offerSoldMessage = this.notifierHelper.createRagfairOfferSoldNotification(message, messageContent.ragfair);
this.notificationSendHelper.sendMessage(sessionID, offerSoldMessage);
message.type = MessageType.MESSAGE_WITH_ITEMS; // Should prevent getting the same notification popup twice
}
const notificationMessage = this.notifierHelper.createNewMessageNotification(message);
this.notificationSendHelper.sendMessage(sessionID, notificationMessage);
}
/**
* Get the preview contents of the last message in a dialogue.
* @param dialogue
* @returns MessagePreview
*/
public getMessagePreview(dialogue: Dialogue): MessagePreview
{
// The last message of the dialogue should be shown on the preview.
const message = dialogue.messages[dialogue.messages.length - 1];
const result: MessagePreview = {
dt: message?.dt,
type: message?.type,
templateId: message?.templateId,
uid: dialogue._id
};
if (message?.text)
{
result.text = message.text;
}
if (message?.systemData)
{
result.systemData = message.systemData;
}
return result;
}
/**
* Get the item contents for a particular message.
* @param messageID
* @param sessionID
* @param itemId Item being moved to inventory
* @returns
*/
public getMessageItemContents(messageID: string, sessionID: string, itemId: string): Item[]
{
const dialogueData = this.saveServer.getProfile(sessionID).dialogues;
for (const dialogueId in dialogueData)
{
const message = dialogueData[dialogueId].messages.find(x => x._id === messageID);
if (!message)
{
continue;
}
if (message._id === messageID)
{
const attachmentsNew = this.saveServer.getProfile(sessionID).dialogues[dialogueId].attachmentsNew;
if (attachmentsNew > 0)
{
this.saveServer.getProfile(sessionID).dialogues[dialogueId].attachmentsNew = attachmentsNew - 1;
}
// Check reward count when item being moved isn't in reward list
// if count is 0, it means after this move the reward array will be empty and all rewards collected
const rewardItemCount = message.items.data.filter(x => x._id !== itemId );
if (rewardItemCount.length === 0)
{
message.rewardCollected = true;
message.hasRewards = false;
}
return message.items.data;
}
}
return [];
}
/**
* Get the dialogs dictionary for a profile, create if doesnt exist
* @param sessionId Session/player id
* @returns Dialog dictionary
*/
public getDialogsForProfile(sessionId: string): Record<string, Dialogue>
{
const profile = this.saveServer.getProfile(sessionId);
if (!profile.dialogues)
{
profile.dialogues = {};
}
return profile.dialogues;
}
}