0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 09:10:43 -05:00

Correctly implemented:

`client/builds/delete`
`client/builds/equipment/save`
`client/builds/weapon/save`

Updated `defaultEquipmentPresets` json data

Removed old 0.13 preset implementation files

profile-breaking change
This commit is contained in:
Dev 2024-01-06 11:11:04 +00:00
parent d3afe0b6f3
commit 8ef405e551
11 changed files with 2864 additions and 3417 deletions

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@ import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequ
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
import { INullResponseData } from "@spt-aki/models/eft/httpResponse/INullResponseData";
import { IPresetBuildActionRequestData } from "@spt-aki/models/eft/presetBuild/IPresetBuildActionRequestData";
import { IRemoveBuildRequestData } from "@spt-aki/models/eft/presetBuild/IRemoveBuildRequestData";
import { IUserBuilds } from "@spt-aki/models/eft/profile/IAkiProfile";
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
import { inject, injectable } from "tsyringe";
@ -40,26 +42,32 @@ export class BuildsCallbacks
* Handle client/builds/weapon/save
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public setWeapon(url: string, info: IEmptyRequestData, sessionID: string): any
public setWeapon(url: string, info: IPresetBuildActionRequestData, sessionID: string): INullResponseData
{
// this.httpResponse.getBody(this.buildController.saveWeaponBuild(sessionID, info));
this.buildController.saveWeaponBuild(sessionID, info);
return this.httpResponse.nullResponse();
}
/**
* Handle client/builds/equipment/save
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public setEquipment(url: string, info: IEmptyRequestData, sessionID: string): any
public setEquipment(url: string, info: IPresetBuildActionRequestData, sessionID: string): INullResponseData
{
throw new Error("Not implemented");
this.buildController.saveEquipmentBuild(sessionID, info);
return this.httpResponse.nullResponse();
}
/**
* Handle client/builds/delete
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public deleteBuild(url: string, info: IEmptyRequestData, sessionID: string): any
public deleteBuild(url: string, info: IRemoveBuildRequestData, sessionID: string): INullResponseData
{
throw new Error("Not implemented");
this.buildController.removeBuild(sessionID, info);
return this.httpResponse.nullResponse();
}
}

View File

@ -1,77 +0,0 @@
import { inject, injectable } from "tsyringe";
import { BuildController } from "@spt-aki/controllers/BuildController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
import { IPresetBuildActionRequestData } from "@spt-aki/models/eft/presetBuild/IPresetBuildActionRequestData";
import { IRemoveBuildRequestData } from "@spt-aki/models/eft/presetBuild/IRemoveBuildRequestData";
import { IUserBuilds } from "@spt-aki/models/eft/profile/IAkiProfile";
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
@injectable()
export class PresetBuildCallbacks
{
constructor(
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
//@inject("PresetBuildController") protected presetBuildController: BuildController,
)
{}
// /** Handle client/handbook/builds/my/list */
// public getHandbookUserlist(
// url: string,
// info: IEmptyRequestData,
// sessionID: string,
// ): IGetBodyResponseData<IUserBuilds>
// {
// return this.httpResponse.getBody(this.presetBuildController.getUserBuilds(sessionID));
// }
// /** Handle SaveWeaponBuild event */
// public saveWeaponBuild(
// pmcData: IPmcData,
// body: IPresetBuildActionRequestData,
// sessionID: string,
// ): IItemEventRouterResponse
// {
// return this.presetBuildController.saveWeaponBuild(pmcData, body, sessionID);
// }
// /** Handle removeBuild event*/
// public removeBuild(pmcData: IPmcData, body: IRemoveBuildRequestData, sessionID: string): IItemEventRouterResponse
// {
// return this.presetBuildController.removeBuild(pmcData, body, sessionID);
// }
// /** Handle RemoveWeaponBuild event*/
// public removeWeaponBuild(
// pmcData: IPmcData,
// body: IPresetBuildActionRequestData,
// sessionID: string,
// ): IItemEventRouterResponse
// {
// return this.presetBuildController.removeWeaponBuild(pmcData, body, sessionID);
// }
// /** Handle SaveEquipmentBuild event */
// public saveEquipmentBuild(
// pmcData: IPmcData,
// body: IPresetBuildActionRequestData,
// sessionID: string,
// ): IItemEventRouterResponse
// {
// return this.presetBuildController.saveEquipmentBuild(pmcData, body, sessionID);
// }
// /** Handle RemoveEquipmentBuild event*/
// public removeEquipmentBuild(
// pmcData: IPmcData,
// body: IPresetBuildActionRequestData,
// sessionID: string,
// ): IItemEventRouterResponse
// {
// return this.presetBuildController.removeEquipmentBuild(pmcData, body, sessionID);
// }
}

View File

@ -7,7 +7,8 @@ import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
import { IPresetBuildActionRequestData } from "@spt-aki/models/eft/presetBuild/IPresetBuildActionRequestData";
import { IRemoveBuildRequestData } from "@spt-aki/models/eft/presetBuild/IRemoveBuildRequestData";
import { IMagazineBuild, IUserBuilds, IWeaponBuild } from "@spt-aki/models/eft/profile/IAkiProfile";
import { IEquipmentBuild, IMagazineBuild, IUserBuilds, IWeaponBuild } from "@spt-aki/models/eft/profile/IAkiProfile";
import { EquipmentBuildType } from "@spt-aki/models/enums/EquipmentBuildType";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
@ -46,7 +47,7 @@ export class BuildController
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find((x) =>
x.slotId === "SecuredContainer"
);
const firstDefaultItemsSecureContainer = defaultEquipmentPresets[0]?.items?.find((x) =>
const firstDefaultItemsSecureContainer = defaultEquipmentPresets[0]?.Items?.find((x) =>
x.slotId === "SecuredContainer"
);
if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl)
@ -55,7 +56,7 @@ export class BuildController
for (const defaultPreset of defaultEquipmentPresets)
{
// Find presets secure container
const secureContainer = defaultPreset.items.find((x) => x.slotId === "SecuredContainer");
const secureContainer = defaultPreset.Items.find((item) => item.slotId === "SecuredContainer");
if (secureContainer)
{
secureContainer._tpl = playerSecureContainer._tpl;
@ -70,33 +71,29 @@ export class BuildController
return result;
}
/** Handle SaveWeaponBuild event */
/** Handle client/builds/weapon/save */
public saveWeaponBuild(
pmcData: IPmcData,
body: IPresetBuildActionRequestData,
sessionId: string,
): IItemEventRouterResponse
body: IPresetBuildActionRequestData,
): void
{
// TODO: Could be merged into saveBuild, maybe
const output = this.eventOutputHolder.getOutput(sessionId);
const pmcData = this.profileHelper.getPmcProfile(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;
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",
Id: body.Id,
Name: body.Name,
Root: body.Root,
Items: body.Items,
};
const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds;
const existingBuild = savedWeaponBuilds.find((x) => x.id === body.id);
const existingBuild = savedWeaponBuilds.find((x) => x.Id === body.Id);
if (existingBuild)
{
// exists, replace
@ -111,52 +108,37 @@ export class BuildController
// 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 */
/** Handle client/builds/equipment/save event */
public saveEquipmentBuild(
pmcData: IPmcData,
body: IPresetBuildActionRequestData,
sessionID: string,
): IItemEventRouterResponse
request: IPresetBuildActionRequestData,
): void
{
return this.saveBuild(pmcData, body, sessionID, "equipmentBuilds");
}
const buildType = "equipmentBuilds";
const pmcData = this.profileHelper.getPmcProfile(sessionID);
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];
const existingSavedEquipmentBuilds: IEquipmentBuild[] = 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);
// 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);
const newBuild = {
id: this.hashUtil.generate(),
name: body.name,
buildType: "Custom",
root: body.root,
fastPanel: [],
items: body.items,
const newBuild: IEquipmentBuild = {
Id: request.Id,
Name: request.Name,
BuildType: EquipmentBuildType.CUSTOM,
Root: request.Root,
Items: request.Items,
};
const existingBuild = existingSavedBuilds.find((x) => x.name === body.name);
const existingBuild = existingSavedEquipmentBuilds.find((x) => x.Name === request.Name);
if (existingBuild)
{
// Already exists, replace
this.saveServer.getProfile(sessionID).userbuilds[buildType].splice(
existingSavedBuilds.indexOf(existingBuild),
existingSavedEquipmentBuilds.indexOf(existingBuild),
1,
newBuild,
);
@ -166,68 +148,50 @@ export class BuildController
// 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
/** Handle client/builds/delete*/
public removeBuild(sessionID: string, request: IRemoveBuildRequestData): void
{
return this.removePlayerBuild(pmcData, body.id, sessionID);
this.removePlayerBuild(request.id, sessionID);
}
/** Handle RemoveWeaponBuild event*/
public removeWeaponBuild(
pmcData: IPmcData,
body: IPresetBuildActionRequestData,
sessionID: string,
): IItemEventRouterResponse
protected removePlayerBuild(id: string, sessionID: string): void
{
// 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;
const profile = this.saveServer.getProfile(sessionID);
const weaponBuilds = profile.userbuilds.weaponBuilds;
const equipmentBuilds = profile.userbuilds.equipmentBuilds;
const magazineBuilds = profile.userbuilds.magazineBuilds;
// Check for id in weapon array first
const matchingWeaponBuild = weaponBuilds.find((x) => x.id === id);
const matchingWeaponBuild = weaponBuilds.find((x) => x.Id === id);
if (matchingWeaponBuild)
{
weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1);
return this.eventOutputHolder.getOutput(sessionID);
return;
}
// Id not found in weapons, try equipment
const matchingEquipmentBuild = equipmentBuilds.find((x) => x.id === id);
const matchingEquipmentBuild = equipmentBuilds.find((x) => x.Id === id);
if (matchingEquipmentBuild)
{
equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1);
return;
}
// Not found in weapons or equipment, not good
if (!(matchingWeaponBuild || matchingEquipmentBuild))
// Id not found in weapons/equipment, try mags
const matchingMagazineBuild = magazineBuilds.find((x) => x.Id === id);
if (matchingMagazineBuild)
{
this.logger.error(`Unable to delete preset, cannot find ${id} in weapon or equipment presets`);
magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1);
return;
}
return this.eventOutputHolder.getOutput(sessionID);
// 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`);
}
public createMagazineTemplate(sessionId: string, request: ISetMagazineRequest): void
@ -239,7 +203,6 @@ export class BuildController
TopCount: request.TopCount,
BottomCount: request.BottomCount,
Items: request.Items,
type: "magazine"
};
const profile = this.profileHelper.getFullProfile(sessionId);

View File

@ -23,7 +23,6 @@ import { MatchCallbacks } from "@spt-aki/callbacks/MatchCallbacks";
import { ModCallbacks } from "@spt-aki/callbacks/ModCallbacks";
import { NoteCallbacks } from "@spt-aki/callbacks/NoteCallbacks";
import { NotifierCallbacks } from "@spt-aki/callbacks/NotifierCallbacks";
import { PresetBuildCallbacks } from "@spt-aki/callbacks/PresetBuildCallbacks";
import { PresetCallbacks } from "@spt-aki/callbacks/PresetCallbacks";
import { ProfileCallbacks } from "@spt-aki/callbacks/ProfileCallbacks";
import { QuestCallbacks } from "@spt-aki/callbacks/QuestCallbacks";
@ -150,7 +149,6 @@ import { HideoutItemEventRouter } from "@spt-aki/routers/item_events/HideoutItem
import { InsuranceItemEventRouter } from "@spt-aki/routers/item_events/InsuranceItemEventRouter";
import { InventoryItemEventRouter } from "@spt-aki/routers/item_events/InventoryItemEventRouter";
import { NoteItemEventRouter } from "@spt-aki/routers/item_events/NoteItemEventRouter";
import { PresetBuildItemEventRouter } from "@spt-aki/routers/item_events/PresetBuildItemEventRouter";
import { QuestItemEventRouter } from "@spt-aki/routers/item_events/QuestItemEventRouter";
import { RagfairItemEventRouter } from "@spt-aki/routers/item_events/RagfairItemEventRouter";
import { RepairItemEventRouter } from "@spt-aki/routers/item_events/RepairItemEventRouter";
@ -350,7 +348,6 @@ export class Container
depContainer.registerType("IERouters", "InsuranceItemEventRouter");
depContainer.registerType("IERouters", "InventoryItemEventRouter");
depContainer.registerType("IERouters", "NoteItemEventRouter");
depContainer.registerType("IERouters", "PresetBuildItemEventRouter");
depContainer.registerType("IERouters", "QuestItemEventRouter");
depContainer.registerType("IERouters", "RagfairItemEventRouter");
depContainer.registerType("IERouters", "RepairItemEventRouter");
@ -443,9 +440,6 @@ export class Container
useClass: InventoryItemEventRouter,
});
depContainer.register<NoteItemEventRouter>("NoteItemEventRouter", { useClass: NoteItemEventRouter });
depContainer.register<PresetBuildItemEventRouter>("PresetBuildItemEventRouter", {
useClass: PresetBuildItemEventRouter,
});
depContainer.register<QuestItemEventRouter>("QuestItemEventRouter", { useClass: QuestItemEventRouter });
depContainer.register<RagfairItemEventRouter>("RagfairItemEventRouter", { useClass: RagfairItemEventRouter });
depContainer.register<RepairItemEventRouter>("RepairItemEventRouter", { useClass: RepairItemEventRouter });
@ -632,7 +626,6 @@ export class Container
depContainer.register<PostDBModLoader>("PostDBModLoader", { useClass: PostDBModLoader });
depContainer.register<NoteCallbacks>("NoteCallbacks", { useClass: NoteCallbacks });
depContainer.register<NotifierCallbacks>("NotifierCallbacks", { useClass: NotifierCallbacks });
depContainer.register<PresetBuildCallbacks>("PresetBuildCallbacks", { useClass: PresetBuildCallbacks });
depContainer.register<PresetCallbacks>("PresetCallbacks", { useClass: PresetCallbacks });
depContainer.register<ProfileCallbacks>("ProfileCallbacks", { useClass: ProfileCallbacks });
depContainer.register<QuestCallbacks>("QuestCallbacks", { useClass: QuestCallbacks });

View File

@ -3,8 +3,9 @@ import { Item } from "@spt-aki/models/eft/common/tables/IItem";
export interface IPresetBuildActionRequestData
{
Action: string;
id: string;
name: string;
root: string;
items: Item[];
Id: string;
/** name of preset given by player */
Name: string;
Root: string;
Items: Item[];
}

View File

@ -1,5 +1,4 @@
export interface IRemoveBuildRequestData
{
Action: "RemoveBuild";
id: string;
}
}

View File

@ -48,6 +48,7 @@ export interface Characters
scav: IPmcData;
}
/** used by profile.userbuilds */
export interface IUserBuilds
{
weaponBuilds: IWeaponBuild[];
@ -55,35 +56,32 @@ export interface IUserBuilds
magazineBuilds: IMagazineBuild[]
}
export interface IWeaponBuild
{
id: string;
name: string;
root: string;
items: Item[];
type: string;
}
export interface IEquipmentBuild
{
id: string;
name: string;
root: string;
items: Item[]; // same as PMC inventory items
type: string;
fastPanel: Record<string, string>;
buildType: EquipmentBuildType;
}
export interface IMagazineBuild
export interface IUserBuild
{
Id: string;
Name: string;
}
export interface IWeaponBuild extends IUserBuild
{
Root: string;
Items: Item[]; // Same as PMC inventory items
}
export interface IEquipmentBuild extends IUserBuild
{
Root: string;
Items: Item[]; // Same as PMC inventory items
BuildType: EquipmentBuildType;
}
export interface IMagazineBuild extends IUserBuild
{
Caliber: string
TopCount: number
BottomCount: number
Items: IMagazineTemplateAmmoItem[]
type: string
}
export interface IMagazineTemplateAmmoItem
@ -92,6 +90,15 @@ export interface IMagazineTemplateAmmoItem
Count: number
}
/** Used by defaultEquipmentPresets.json */
export interface IDefaultEquipmentPreset extends IUserBuild
{
Items: Item[]
Root: string
BuildType: EquipmentBuildType
type: string
}
export interface Dialogue
{
attachmentsNew: number;

View File

@ -17,7 +17,7 @@ import { IHideoutProduction } from "@spt-aki/models/eft/hideout/IHideoutProducti
import { IHideoutScavCase } from "@spt-aki/models/eft/hideout/IHideoutScavCase";
import { IHideoutSettingsBase } from "@spt-aki/models/eft/hideout/IHideoutSettingsBase";
import { IQteData } from "@spt-aki/models/eft/hideout/IQteData";
import { IEquipmentBuild } from "@spt-aki/models/eft/profile/IAkiProfile";
import { IDefaultEquipmentPreset } from "@spt-aki/models/eft/profile/IAkiProfile";
import { ILocaleBase } from "@spt-aki/models/spt/server/ILocaleBase";
import { ILocations } from "@spt-aki/models/spt/server/ILocations";
import { IServerBase } from "@spt-aki/models/spt/server/IServerBase";
@ -52,7 +52,7 @@ export interface IDatabaseTables
prices: Record<string, number>;
/** Default equipment loadouts that show on main inventory screen */
defaultEquipmentPresets: IEquipmentBuild[];
defaultEquipmentPresets: IDefaultEquipmentPreset[];
/** Achievements */
achievements: IAchievement[]

View File

@ -1,49 +0,0 @@
import { inject, injectable } from "tsyringe";
import { BuildsCallbacks } from "@spt-aki/callbacks/BuildsCallbacks";
import { HandledRoute, ItemEventRouterDefinition } from "@spt-aki/di/Router";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
import { ItemEventActions } from "@spt-aki/models/enums/ItemEventActions";
@injectable()
export class PresetBuildItemEventRouter extends ItemEventRouterDefinition
{
constructor(@inject("BuildsCallbacks") protected buildCallbacks: BuildsCallbacks)
{
super();
}
public override getHandledRoutes(): HandledRoute[]
{
return [
new HandledRoute(ItemEventActions.SAVE_WEAPON_BUILD, false),
new HandledRoute(ItemEventActions.REMOVE_WEAPON_BUILD, false),
new HandledRoute(ItemEventActions.SAVE_EQUIPMENT_BUILD, false),
new HandledRoute(ItemEventActions.REMOVE_EQUIPMENT_BUILD, false),
new HandledRoute(ItemEventActions.REMOVE_BUILD, false),
];
}
// public override handleItemEvent(
// url: string,
// pmcData: IPmcData,
// body: any,
// sessionID: string,
// ): IItemEventRouterResponse
// {
// switch (url)
// {
// case ItemEventActions.SAVE_WEAPON_BUILD:
// return this.buildCallbacks.setWeapon(pmcData, body, sessionID);
// case ItemEventActions.REMOVE_WEAPON_BUILD:
// return this.buildCallbacks.deleteBuild(pmcData, body, sessionID);
// case ItemEventActions.REMOVE_BUILD:
// return this.buildCallbacks.deleteBuild(pmcData, body, sessionID);
// case ItemEventActions.SAVE_EQUIPMENT_BUILD:
// return this.buildCallbacks.setEquipment(pmcData, body, sessionID);
// case ItemEventActions.REMOVE_EQUIPMENT_BUILD:
// return this.buildCallbacks.deleteBuild(pmcData, body, sessionID);
// }
// }
}

View File

@ -953,7 +953,7 @@ export class ProfileFixerService
// Iterate over player-made weapon builds, look for missing items and remove weapon preset if found
for (const buildId in fullProfile.userbuilds?.weaponBuilds)
{
for (const item of fullProfile.userbuilds.weaponBuilds[buildId].items)
for (const item of fullProfile.userbuilds.weaponBuilds[buildId].Items)
{
// Check item exists in itemsDb
if (!itemsDb[item._tpl])