2023-03-03 15:23:46 +00:00
|
|
|
import { inject, injectable } from "tsyringe";
|
|
|
|
|
2023-10-19 17:21:17 +00:00
|
|
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
2023-12-28 12:02:37 +00:00
|
|
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
|
|
|
import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequest";
|
2023-10-19 17:21:17 +00:00
|
|
|
import { IPresetBuildActionRequestData } from "@spt-aki/models/eft/presetBuild/IPresetBuildActionRequestData";
|
|
|
|
import { IRemoveBuildRequestData } from "@spt-aki/models/eft/presetBuild/IRemoveBuildRequestData";
|
2024-01-06 11:11:04 +00:00
|
|
|
import { IEquipmentBuild, IMagazineBuild, IUserBuilds, IWeaponBuild } from "@spt-aki/models/eft/profile/IAkiProfile";
|
|
|
|
import { EquipmentBuildType } from "@spt-aki/models/enums/EquipmentBuildType";
|
2023-10-19 17:21:17 +00:00
|
|
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
|
|
|
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
|
|
|
|
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
|
|
|
import { SaveServer } from "@spt-aki/servers/SaveServer";
|
|
|
|
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
|
|
|
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
2023-03-03 15:23:46 +00:00
|
|
|
|
|
|
|
@injectable()
|
2023-12-27 20:19:17 +00:00
|
|
|
export class BuildController
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
|
|
|
constructor(
|
2023-10-10 11:03:20 +00:00
|
|
|
@inject("WinstonLogger") protected logger: ILogger,
|
2023-03-03 15:23:46 +00:00
|
|
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
|
|
|
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
2023-10-10 11:03:20 +00:00
|
|
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
|
|
|
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
2023-12-28 12:02:37 +00:00
|
|
|
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
2023-03-03 15:23:46 +00:00
|
|
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
2023-11-10 16:49:29 -05:00
|
|
|
@inject("SaveServer") protected saveServer: SaveServer,
|
2023-03-03 15:23:46 +00:00
|
|
|
)
|
2023-11-10 16:49:29 -05:00
|
|
|
{}
|
2023-03-03 15:23:46 +00:00
|
|
|
|
2023-07-15 14:49:25 +01:00
|
|
|
/** Handle client/handbook/builds/my/list */
|
2023-10-10 11:03:20 +00:00
|
|
|
public getUserBuilds(sessionID: string): IUserBuilds
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
2024-01-10 09:13:34 +00:00
|
|
|
const secureContainerSlotId = "SecuredContainer";
|
2023-10-10 11:03:20 +00:00
|
|
|
const profile = this.saveServer.getProfile(sessionID);
|
|
|
|
if (!profile.userbuilds)
|
|
|
|
{
|
2023-12-27 20:19:17 +00:00
|
|
|
profile.userbuilds = { equipmentBuilds: [], weaponBuilds: [], magazineBuilds: [] };
|
2023-10-10 11:03:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the secure container in the default presets match what the player has equipped
|
2023-11-10 16:49:29 -05:00
|
|
|
const defaultEquipmentPresets = this.jsonUtil.clone(
|
|
|
|
this.databaseServer.getTables().templates.defaultEquipmentPresets,
|
|
|
|
);
|
|
|
|
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find((x) =>
|
2024-01-10 09:13:34 +00:00
|
|
|
x.slotId === secureContainerSlotId
|
2023-11-10 16:49:29 -05:00
|
|
|
);
|
2024-01-06 11:11:04 +00:00
|
|
|
const firstDefaultItemsSecureContainer = defaultEquipmentPresets[0]?.Items?.find((x) =>
|
2024-01-10 09:13:34 +00:00
|
|
|
x.slotId === secureContainerSlotId
|
2023-11-10 16:49:29 -05:00
|
|
|
);
|
2023-10-10 11:03:20 +00:00
|
|
|
if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl)
|
|
|
|
{
|
2023-11-10 16:49:29 -05:00
|
|
|
// Default equipment presets' secure container tpl doesn't match players secure container tpl
|
2023-10-10 11:03:20 +00:00
|
|
|
for (const defaultPreset of defaultEquipmentPresets)
|
|
|
|
{
|
|
|
|
// Find presets secure container
|
2024-01-10 09:13:34 +00:00
|
|
|
const secureContainer = defaultPreset.Items.find((item) => item.slotId === secureContainerSlotId);
|
2023-10-10 11:03:20 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-01-06 11:11:04 +00:00
|
|
|
/** Handle client/builds/weapon/save */
|
2024-02-02 13:54:07 -05:00
|
|
|
public saveWeaponBuild(sessionId: string, body: IPresetBuildActionRequestData): void
|
2023-10-10 11:03:20 +00:00
|
|
|
{
|
2024-01-06 11:11:04 +00:00
|
|
|
const pmcData = this.profileHelper.getPmcProfile(sessionId);
|
2023-10-10 11:03:20 +00:00
|
|
|
|
|
|
|
// Replace duplicate Id's. The first item is the base item.
|
|
|
|
// The root ID and the base item ID need to match.
|
2024-01-06 11:11:04 +00:00
|
|
|
body.Items = this.itemHelper.replaceIDs(pmcData, body.Items);
|
|
|
|
body.Root = body.Items[0]._id;
|
2023-10-10 11:03:20 +00:00
|
|
|
|
|
|
|
// Create new object ready to save into profile userbuilds.weaponBuilds
|
2024-02-02 13:54:07 -05:00
|
|
|
const newBuild: IWeaponBuild = { Id: body.Id, Name: body.Name, Root: body.Root, Items: body.Items };
|
2023-10-10 11:03:20 +00:00
|
|
|
|
|
|
|
const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds;
|
2024-01-06 11:11:04 +00:00
|
|
|
const existingBuild = savedWeaponBuilds.find((x) => x.Id === body.Id);
|
2023-10-10 11:03:20 +00:00
|
|
|
if (existingBuild)
|
|
|
|
{
|
|
|
|
// exists, replace
|
2023-11-10 16:49:29 -05:00
|
|
|
this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds.splice(
|
|
|
|
savedWeaponBuilds.indexOf(existingBuild),
|
|
|
|
1,
|
|
|
|
newBuild,
|
|
|
|
);
|
2023-10-10 11:03:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Add fresh
|
|
|
|
this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds.push(newBuild);
|
|
|
|
}
|
2023-03-03 15:23:46 +00:00
|
|
|
}
|
|
|
|
|
2024-01-06 11:11:04 +00:00
|
|
|
/** Handle client/builds/equipment/save event */
|
2024-02-02 13:54:07 -05:00
|
|
|
public saveEquipmentBuild(sessionID: string, request: IPresetBuildActionRequestData): void
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
2024-01-06 11:11:04 +00:00
|
|
|
const buildType = "equipmentBuilds";
|
|
|
|
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
2023-03-03 15:23:46 +00:00
|
|
|
|
2024-02-02 13:54:07 -05:00
|
|
|
const existingSavedEquipmentBuilds: IEquipmentBuild[] =
|
|
|
|
this.saveServer.getProfile(sessionID).userbuilds[buildType];
|
2023-03-03 15:23:46 +00:00
|
|
|
|
2024-01-06 11:11:04 +00:00
|
|
|
// Replace duplicate ID's. The first item is the base item.
|
|
|
|
// Root ID and the base item ID need to match.
|
|
|
|
request.Items = this.itemHelper.replaceIDs(pmcData, request.Items);
|
2023-03-03 15:23:46 +00:00
|
|
|
|
2024-01-06 11:11:04 +00:00
|
|
|
const newBuild: IEquipmentBuild = {
|
|
|
|
Id: request.Id,
|
|
|
|
Name: request.Name,
|
|
|
|
BuildType: EquipmentBuildType.CUSTOM,
|
2024-01-12 17:18:10 +00:00
|
|
|
Root: request.Items[0]._id,
|
2024-01-06 11:11:04 +00:00
|
|
|
Items: request.Items,
|
2023-10-10 11:03:20 +00:00
|
|
|
};
|
|
|
|
|
2024-02-05 09:13:37 +00:00
|
|
|
const existingBuild = existingSavedEquipmentBuilds.find((build) =>
|
|
|
|
build.Name === request.Name || build.Id === request.Id
|
|
|
|
);
|
2023-10-10 11:03:20 +00:00
|
|
|
if (existingBuild)
|
|
|
|
{
|
|
|
|
// Already exists, replace
|
2023-11-10 16:49:29 -05:00
|
|
|
this.saveServer.getProfile(sessionID).userbuilds[buildType].splice(
|
2024-01-06 11:11:04 +00:00
|
|
|
existingSavedEquipmentBuilds.indexOf(existingBuild),
|
2023-11-10 16:49:29 -05:00
|
|
|
1,
|
|
|
|
newBuild,
|
|
|
|
);
|
2023-10-10 11:03:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Fresh, add new
|
|
|
|
this.saveServer.getProfile(sessionID).userbuilds[buildType].push(newBuild);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-06 11:11:04 +00:00
|
|
|
/** Handle client/builds/delete*/
|
|
|
|
public removeBuild(sessionID: string, request: IRemoveBuildRequestData): void
|
2023-10-10 11:03:20 +00:00
|
|
|
{
|
2024-01-06 11:11:04 +00:00
|
|
|
this.removePlayerBuild(request.id, sessionID);
|
2023-10-10 11:03:20 +00:00
|
|
|
}
|
2023-11-10 16:49:29 -05:00
|
|
|
|
2024-01-06 11:11:04 +00:00
|
|
|
protected removePlayerBuild(id: string, sessionID: string): void
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
2024-01-06 11:11:04 +00:00
|
|
|
const profile = this.saveServer.getProfile(sessionID);
|
|
|
|
const weaponBuilds = profile.userbuilds.weaponBuilds;
|
|
|
|
const equipmentBuilds = profile.userbuilds.equipmentBuilds;
|
|
|
|
const magazineBuilds = profile.userbuilds.magazineBuilds;
|
2023-03-03 15:23:46 +00:00
|
|
|
|
2023-10-10 11:03:20 +00:00
|
|
|
// Check for id in weapon array first
|
2024-01-06 11:11:04 +00:00
|
|
|
const matchingWeaponBuild = weaponBuilds.find((x) => x.Id === id);
|
2023-10-10 11:03:20 +00:00
|
|
|
if (matchingWeaponBuild)
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
2023-10-10 11:03:20 +00:00
|
|
|
weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1);
|
|
|
|
|
2024-01-06 11:11:04 +00:00
|
|
|
return;
|
2023-10-10 11:03:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Id not found in weapons, try equipment
|
2024-01-06 11:11:04 +00:00
|
|
|
const matchingEquipmentBuild = equipmentBuilds.find((x) => x.Id === id);
|
2023-10-10 11:03:20 +00:00
|
|
|
if (matchingEquipmentBuild)
|
|
|
|
{
|
|
|
|
equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1);
|
2024-01-06 11:11:04 +00:00
|
|
|
|
|
|
|
return;
|
2023-10-10 11:03:20 +00:00
|
|
|
}
|
|
|
|
|
2024-01-06 11:11:04 +00:00
|
|
|
// Id not found in weapons/equipment, try mags
|
|
|
|
const matchingMagazineBuild = magazineBuilds.find((x) => x.Id === id);
|
|
|
|
if (matchingMagazineBuild)
|
2023-10-10 11:03:20 +00:00
|
|
|
{
|
2024-01-06 11:11:04 +00:00
|
|
|
magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1);
|
|
|
|
|
|
|
|
return;
|
2023-03-03 15:23:46 +00:00
|
|
|
}
|
|
|
|
|
2024-01-06 11:11:04 +00:00
|
|
|
// Not found in weapons,equipment or magazines, not good
|
|
|
|
this.logger.error(`Unable to delete preset, cannot find ${id} in weapon, equipment or magazine presets`);
|
2023-03-03 15:23:46 +00:00
|
|
|
}
|
2023-12-28 12:02:37 +00:00
|
|
|
|
2024-01-11 11:53:19 +00:00
|
|
|
/**
|
|
|
|
* Handle client/builds/magazine/save
|
|
|
|
*/
|
2023-12-28 12:02:37 +00:00
|
|
|
public createMagazineTemplate(sessionId: string, request: ISetMagazineRequest): void
|
|
|
|
{
|
|
|
|
const result: IMagazineBuild = {
|
|
|
|
Id: request.Id,
|
|
|
|
Name: request.Name,
|
|
|
|
Caliber: request.Caliber,
|
|
|
|
TopCount: request.TopCount,
|
|
|
|
BottomCount: request.BottomCount,
|
2023-12-28 12:22:06 +00:00
|
|
|
Items: request.Items,
|
2023-12-28 12:02:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const profile = this.profileHelper.getFullProfile(sessionId);
|
2023-12-28 12:19:52 +00:00
|
|
|
|
2024-01-11 11:53:19 +00:00
|
|
|
if (!profile.userbuilds.magazineBuilds)
|
|
|
|
{
|
|
|
|
profile.userbuilds.magazineBuilds = [];
|
|
|
|
}
|
|
|
|
|
2024-02-02 13:54:07 -05:00
|
|
|
const existingArrayId = profile.userbuilds.magazineBuilds.findIndex((item) => item.Name === request.Name);
|
2023-12-28 12:19:52 +00:00
|
|
|
|
|
|
|
if (existingArrayId === -1)
|
|
|
|
{
|
|
|
|
profile.userbuilds.magazineBuilds.push(result);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-02-02 13:54:07 -05:00
|
|
|
profile.userbuilds.magazineBuilds.splice(existingArrayId, 1, result);
|
2023-12-28 12:19:52 +00:00
|
|
|
}
|
2023-12-28 12:02:37 +00:00
|
|
|
}
|
2023-11-10 16:49:29 -05:00
|
|
|
}
|