0b67a9a0e9
Co-authored-by: Dev <dev@dev.sp-tarkov.com> Co-authored-by: Terkoiz <terkoiz@noreply.dev.sp-tarkov.com> Co-authored-by: TheSparta <thesparta@noreply.dev.sp-tarkov.com> Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com> Co-authored-by: Kaeno <e> Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/147
200 lines
8.1 KiB
TypeScript
200 lines
8.1 KiB
TypeScript
import { inject, injectable } from "tsyringe";
|
|
|
|
import { ItemHelper } from "../helpers/ItemHelper";
|
|
import { IPmcData } from "../models/eft/common/IPmcData";
|
|
import { IItemEventRouterResponse } from "../models/eft/itemEvent/IItemEventRouterResponse";
|
|
import {
|
|
IPresetBuildActionRequestData
|
|
} from "../models/eft/presetBuild/IPresetBuildActionRequestData";
|
|
import { IRemoveBuildRequestData } from "../models/eft/presetBuild/IRemoveBuildRequestData";
|
|
import { IUserBuilds, IWeaponBuild } from "../models/eft/profile/IAkiProfile";
|
|
import { ILogger } from "../models/spt/utils/ILogger";
|
|
import { EventOutputHolder } from "../routers/EventOutputHolder";
|
|
import { DatabaseServer } from "../servers/DatabaseServer";
|
|
import { SaveServer } from "../servers/SaveServer";
|
|
import { HashUtil } from "../utils/HashUtil";
|
|
import { JsonUtil } from "../utils/JsonUtil";
|
|
|
|
@injectable()
|
|
export class PresetBuildController
|
|
{
|
|
constructor(
|
|
@inject("WinstonLogger") protected logger: ILogger,
|
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
|
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
|
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
|
@inject("SaveServer") protected saveServer: SaveServer
|
|
)
|
|
{ }
|
|
|
|
/** Handle client/handbook/builds/my/list */
|
|
public getUserBuilds(sessionID: string): IUserBuilds
|
|
{
|
|
const profile = this.saveServer.getProfile(sessionID);
|
|
if (!profile.userbuilds)
|
|
{
|
|
profile.userbuilds = {
|
|
equipmentBuilds: [],
|
|
weaponBuilds: []
|
|
};
|
|
}
|
|
|
|
// Ensure the secure container in the default presets match what the player has equipped
|
|
const defaultEquipmentPresets = this.jsonUtil.clone(this.databaseServer.getTables().templates.defaultEquipmentPresets);
|
|
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find(x => x.slotId === "SecuredContainer");
|
|
const firstDefaultItemsSecureContainer = defaultEquipmentPresets[0]?.items?.find(x => x.slotId === "SecuredContainer");
|
|
if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl)
|
|
{
|
|
// Default equipment presets' secure container tpl doesnt match players secure container tpl
|
|
for (const defaultPreset of defaultEquipmentPresets)
|
|
{
|
|
// Find presets secure container
|
|
const secureContainer = defaultPreset.items.find(x => x.slotId === "SecuredContainer");
|
|
if (secureContainer)
|
|
{
|
|
secureContainer._tpl = playerSecureContainer._tpl;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clone player build data from profile and append the above defaults onto end
|
|
const result = this.jsonUtil.clone(profile.userbuilds);
|
|
result.equipmentBuilds.push(...defaultEquipmentPresets);
|
|
|
|
return result;
|
|
}
|
|
|
|
/** Handle SaveWeaponBuild event */
|
|
public saveWeaponBuild(pmcData: IPmcData, body: IPresetBuildActionRequestData, sessionId: string): IItemEventRouterResponse
|
|
{
|
|
// TODO - could be merged into saveBuild, maybe
|
|
const output = this.eventOutputHolder.getOutput(sessionId);
|
|
|
|
// Replace duplicate Id's. The first item is the base item.
|
|
// The root ID and the base item ID need to match.
|
|
body.items = this.itemHelper.replaceIDs(pmcData, body.items);
|
|
body.root = body.items[0]._id;
|
|
|
|
// Create new object ready to save into profile userbuilds.weaponBuilds
|
|
const newId = this.hashUtil.generate(); // Id is empty, generate it
|
|
const newBuild: IWeaponBuild = {
|
|
id: newId,
|
|
name: body.name,
|
|
root: body.root,
|
|
items: body.items,
|
|
type: "weapon"
|
|
};
|
|
|
|
const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds;
|
|
const existingBuild = savedWeaponBuilds.find(x => x.id === body.id);
|
|
if (existingBuild)
|
|
{
|
|
// exists, replace
|
|
this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds.splice(savedWeaponBuilds.indexOf(existingBuild), 1, newBuild);
|
|
}
|
|
else
|
|
{
|
|
// Add fresh
|
|
this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds.push(newBuild);
|
|
}
|
|
|
|
// Inform client of new weapon preset
|
|
output.profileChanges[sessionId].weaponBuilds.push(newBuild);
|
|
|
|
return output;
|
|
}
|
|
|
|
/** Handle SaveEquipmentBuild event */
|
|
public saveEquipmentBuild(pmcData: IPmcData, body: IPresetBuildActionRequestData, sessionID: string): IItemEventRouterResponse
|
|
{
|
|
return this.saveBuild(pmcData, body, sessionID, "equipmentBuilds");
|
|
}
|
|
|
|
protected saveBuild(pmcData: IPmcData, body: IPresetBuildActionRequestData, sessionID: string, buildType: string): IItemEventRouterResponse
|
|
{
|
|
const output = this.eventOutputHolder.getOutput(sessionID);
|
|
const existingSavedBuilds: any[] = this.saveServer.getProfile(sessionID).userbuilds[buildType];
|
|
|
|
// replace duplicate ID's. The first item is the base item.
|
|
// The root ID and the base item ID need to match.
|
|
body.items = this.itemHelper.replaceIDs(pmcData, body.items);
|
|
|
|
const newBuild = {
|
|
id: this.hashUtil.generate(),
|
|
name: body.name,
|
|
buildType: "Custom",
|
|
root: body.root,
|
|
fastPanel: [],
|
|
items: body.items
|
|
};
|
|
|
|
const existingBuild = existingSavedBuilds.find(x => x.name === body.name);
|
|
if (existingBuild)
|
|
{
|
|
// Already exists, replace
|
|
this.saveServer.getProfile(sessionID).userbuilds[buildType].splice(existingSavedBuilds.indexOf(existingBuild), 1, newBuild);
|
|
}
|
|
else
|
|
{
|
|
// Fresh, add new
|
|
this.saveServer.getProfile(sessionID).userbuilds[buildType].push(newBuild);
|
|
}
|
|
|
|
output.profileChanges[sessionID][buildType].push(newBuild);
|
|
|
|
return output;
|
|
}
|
|
|
|
/** Handle RemoveWeaponBuild event*/
|
|
public removeBuild(pmcData: IPmcData, body: IRemoveBuildRequestData, sessionID: string): IItemEventRouterResponse
|
|
{
|
|
return this.removePlayerBuild(pmcData, body.id, sessionID);
|
|
}
|
|
|
|
/** Handle RemoveWeaponBuild event*/
|
|
public removeWeaponBuild(pmcData: IPmcData, body: IPresetBuildActionRequestData, sessionID: string): IItemEventRouterResponse
|
|
{
|
|
// todo - does this get called?
|
|
return this.removePlayerBuild(pmcData, body.id, sessionID);
|
|
}
|
|
|
|
/** Handle RemoveEquipmentBuild event*/
|
|
public removeEquipmentBuild(pmcData: IPmcData, body: IPresetBuildActionRequestData, sessionID: string): IItemEventRouterResponse
|
|
{
|
|
// todo - does this get called?
|
|
return this.removePlayerBuild(pmcData, body.id, sessionID);
|
|
}
|
|
|
|
protected removePlayerBuild(pmcData: IPmcData, id: string, sessionID: string): IItemEventRouterResponse
|
|
{
|
|
const weaponBuilds = this.saveServer.getProfile(sessionID).userbuilds.weaponBuilds;
|
|
const equipmentBuilds = this.saveServer.getProfile(sessionID).userbuilds.equipmentBuilds;
|
|
|
|
// Check for id in weapon array first
|
|
const matchingWeaponBuild = weaponBuilds.find(x => x.id === id);
|
|
if (matchingWeaponBuild)
|
|
{
|
|
weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1);
|
|
|
|
return this.eventOutputHolder.getOutput(sessionID);
|
|
}
|
|
|
|
// Id not found in weapons, try equipment
|
|
const matchingEquipmentBuild = equipmentBuilds.find(x => x.id === id);
|
|
if (matchingEquipmentBuild)
|
|
{
|
|
equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1);
|
|
}
|
|
|
|
// Not found in weapons or equipment, not good
|
|
if (!(matchingWeaponBuild || matchingEquipmentBuild))
|
|
{
|
|
this.logger.error(`Unable to delete preset, cannot find ${id} in weapon or equipment presets`);
|
|
}
|
|
|
|
|
|
return this.eventOutputHolder.getOutput(sessionID);
|
|
}
|
|
} |