diff --git a/project/assets/database/locales/server/en.json b/project/assets/database/locales/server/en.json index abef4ad7..cd93f1ea 100644 --- a/project/assets/database/locales/server/en.json +++ b/project/assets/database/locales/server/en.json @@ -57,7 +57,7 @@ "event-unhandled_event": "[UNHANDLED EVENT] %s", "executing_startup_callbacks": "Server: executing startup callbacks...", "fence-unable_to_find_assort_by_id": "Unable to find fence assort for id: %s", - "fixer-mod_item_found": "Item %s found that does not exist in items db. You are likely to experience errors, this can be due to using an items mod and removing it without deleting the modded items from your inventory. Do not use this profile", + "fixer-mod_item_found": "Item: %s found in profile that does not exist in items db. You WILL experience errors, this can be due to using an items mod and removing the mod without deleting the modded items from your inventory. DO NOT USE THIS PROFILE. Open Aki_Data\\Server\\configs\\core.json, edit 'removeModItemsFromProfile' to be true. This will allow the server to edit your profile and hopefully remove the bad items", "fixer-updated_pockets": "Updated 'pocket' item to new 18876 version with x3 special slots", "gameevent-bot_not_found": "addEventGearToScavs() - unable to find bot of type %s in database, skipping", "gameevent-no_gear_data": "No gear data in seasonalevents.json config for event %s", diff --git a/project/src/controllers/GameController.ts b/project/src/controllers/GameController.ts index 18be2a7f..e3172ec3 100644 --- a/project/src/controllers/GameController.ts +++ b/project/src/controllers/GameController.ts @@ -154,7 +154,7 @@ export class GameController { this.sendPraporGiftsToNewProfiles(pmcProfile); - this.profileFixerService.checkForOrphanedModdedItems(sessionID, pmcProfile); + this.profileFixerService.checkForOrphanedModdedItems(sessionID, fullProfile); } this.logProfileDetails(fullProfile); diff --git a/project/src/models/eft/common/tables/IProfileTemplate.ts b/project/src/models/eft/common/tables/IProfileTemplate.ts index dad3ae15..674d9325 100644 --- a/project/src/models/eft/common/tables/IProfileTemplate.ts +++ b/project/src/models/eft/common/tables/IProfileTemplate.ts @@ -23,7 +23,7 @@ export interface TemplateSide character: IPmcData suits: string[] dialogues: Record - weaponbuilds: WeaponBuild[] + weaponbuilds: Record trader: ProfileTraderTemplate } diff --git a/project/src/models/eft/profile/IAkiProfile.ts b/project/src/models/eft/profile/IAkiProfile.ts index 018bcb16..860fbcf2 100644 --- a/project/src/models/eft/profile/IAkiProfile.ts +++ b/project/src/models/eft/profile/IAkiProfile.ts @@ -9,7 +9,7 @@ export interface IAkiProfile characters: Characters /** Clothing purchases */ suits: string[] - weaponbuilds: WeaponBuild[] + weaponbuilds: Record dialogues: Record aki: Aki vitality: Vitality diff --git a/project/src/services/ProfileFixerService.ts b/project/src/services/ProfileFixerService.ts index a612054b..333e2742 100644 --- a/project/src/services/ProfileFixerService.ts +++ b/project/src/services/ProfileFixerService.ts @@ -634,9 +634,10 @@ export class ProfileFixerService * @param sessionId Session id * @param pmcProfile Profile to check inventory of */ - public checkForOrphanedModdedItems(sessionId: string, pmcProfile: IPmcData): void + public checkForOrphanedModdedItems(sessionId: string, fullProfile: IAkiProfile): void { const itemsDb = this.databaseServer.getTables().templates.items; + const pmcProfile = fullProfile.characters.pmc; // Get items placed in root of stash // TODO: extend to other areas / sub items @@ -659,8 +660,64 @@ export class ProfileFixerService // Also deletes from insured array this.inventoryHelper.removeItem(pmcProfile, item._id, sessionId); + } + } + } - // TODO: delete item from mail + // Iterate over player-made weapon builds, look for missing items and remove weapon preset if found + for (const buildId in fullProfile.weaponbuilds) + { + for (const item of fullProfile.weaponbuilds[buildId].items) + { + // Check item exists in itemsDb + if (!itemsDb[item._tpl]) + { + this.logger.error(this.localisationService.getText("fixer-mod_item_found", item._tpl)); + + if (this.coreConfig.fixes.removeModItemsFromProfile) + { + delete fullProfile.weaponbuilds[buildId]; + this.logger.warning(`Item: ${item._tpl} has resulted in the deletion of weapon build: ${buildId}`); + } + + break; + } + } + } + + // Iterate over dialogs, looking for messages with items not found in item db, remove message if item found + for (const dialogId in fullProfile.dialogues) + { + const dialog = fullProfile.dialogues[dialogId]; + if (!dialog?.messages) + { + continue; // Skip dialog with no messages + } + + // Iterate over all messages in dialog + for (const message of dialog.messages) + { + if (!message.items?.data) + { + continue; // Skip message with no items + } + + // Iterate over all items in message + for (const item of message.items.data) + { + // Check item exists in itemsDb + if (!itemsDb[item._tpl]) + { + this.logger.error(this.localisationService.getText("fixer-mod_item_found", item._tpl)); + + if (this.coreConfig.fixes.removeModItemsFromProfile) + { + dialog.messages.splice(dialog.messages.findIndex(x => x._id === message._id), 1); + this.logger.warning(`Item: ${item._tpl} has resulted in the deletion of message: ${message._id} from dialog ${dialogId}`); + } + + break; + } } } }