From 58f66e061350bfa38c6a8bb4805ba2106d66e86f Mon Sep 17 00:00:00 2001 From: stuyk Date: Sun, 16 Apr 2023 10:46:20 -0600 Subject: [PATCH] Move Systems to Session Storage --- CHANGELOG.md | 3 + .../controllers/dynamicDoors/cooldowns.ts | 25 ++++-- .../server/controllers/dynamicDoors/player.ts | 19 ++-- src/core/server/document/accountData.ts | 78 ++++++++-------- src/core/server/document/character.ts | 89 +++++++++---------- src/core/server/document/vehicle.ts | 68 +++++++------- src/core/server/session/player.ts | 34 ++++--- src/core/server/session/vehicle.ts | 30 +++++-- 8 files changed, 199 insertions(+), 147 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de2759847f..66ddc705a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,11 +79,14 @@ Dynamic Doors - Dynamic doors can teleport to any dimension, or position. - Dynamic doors also have onEnter, or beforeEnter callbacks for additional door functionality. - Includes better handling of ytyp, and ipl loading; no more falling through map. +- Utilizes Session Storage Drop Tables - Create a drop table and pull random loot from it. - Athena.systems.dropTable.get +Documents (Account, Character, Vehicle) +- Utilizes Session Storage ``` diff --git a/src/core/server/controllers/dynamicDoors/cooldowns.ts b/src/core/server/controllers/dynamicDoors/cooldowns.ts index 7338f50b40..3f56a2bd4e 100644 --- a/src/core/server/controllers/dynamicDoors/cooldowns.ts +++ b/src/core/server/controllers/dynamicDoors/cooldowns.ts @@ -1,6 +1,15 @@ import * as alt from 'alt-server'; +import * as Athena from '@AthenaServer/api'; -const cooldowns: { [id: string]: number } = {}; +const SessionKey = 'athena-dd-cooldown-instance'; + +declare global { + namespace AthenaSession { + interface Player { + [SessionKey]: number; + } + } +} /** * Register a cooldown, with predetermiend @@ -9,7 +18,7 @@ const cooldowns: { [id: string]: number } = {}; * @param {alt.Player} player */ export function updateCooldown(player: alt.Player) { - cooldowns[player.id] = Date.now() + 2000; + Athena.session.player.set(player, SessionKey, Date.now() + 2000); } /** @@ -20,11 +29,11 @@ export function updateCooldown(player: alt.Player) { * @return {*} */ export function isCooldownDone(player: alt.Player) { - if (!cooldowns[player.id]) { + if (!Athena.session.player.has(player, SessionKey)) { return true; } - return Date.now() > cooldowns[player.id]; + return Date.now() > Athena.session.player.get(player, SessionKey); } /** @@ -34,7 +43,7 @@ export function isCooldownDone(player: alt.Player) { * @param {alt.Player} player */ export function clearCooldown(player: alt.Player) { - delete cooldowns[player.id]; + Athena.session.player.clearKey(player, SessionKey); } /** @@ -45,11 +54,9 @@ export function clearCooldown(player: alt.Player) { * @return {*} */ export function getExpiration(player: alt.Player) { - if (!cooldowns[player.id]) { + if (!Athena.session.player.has(player, SessionKey)) { return Date.now(); } - return cooldowns[player.id]; + return Athena.session.player.get(player, SessionKey); } - -alt.on('playerDisconnect', clearCooldown); diff --git a/src/core/server/controllers/dynamicDoors/player.ts b/src/core/server/controllers/dynamicDoors/player.ts index 916bada325..d4c5ddcfb1 100644 --- a/src/core/server/controllers/dynamicDoors/player.ts +++ b/src/core/server/controllers/dynamicDoors/player.ts @@ -1,6 +1,15 @@ import * as alt from 'alt-server'; +import * as Athena from '@AthenaServer/api'; -const playerLoadingInstance: { [id: string]: boolean } = {}; +const SessionKey = 'athena-dd-loading-instance'; + +declare global { + namespace AthenaSession { + interface Player { + [SessionKey]: boolean; + } + } +} /** * Unregister a player that is loading. @@ -8,7 +17,7 @@ const playerLoadingInstance: { [id: string]: boolean } = {}; * @param {alt.Player} player */ export function unregister(player: alt.Player) { - delete playerLoadingInstance[player.id]; + Athena.session.player.clearKey(player, SessionKey); } /** @@ -18,7 +27,7 @@ export function unregister(player: alt.Player) { * @param {alt.Player} player */ export function register(player: alt.Player) { - playerLoadingInstance[player.id] = true; + Athena.session.player.set(player, SessionKey, true); } /** @@ -29,7 +38,5 @@ export function register(player: alt.Player) { * @return {*} */ export function isLoading(player: alt.Player) { - return playerLoadingInstance[player.id] ? true : false; + return Athena.session.player.has(player, SessionKey); } - -alt.on('playerDisconnect', unregister); diff --git a/src/core/server/document/accountData.ts b/src/core/server/document/accountData.ts index f7048f09d9..ace247317e 100644 --- a/src/core/server/document/accountData.ts +++ b/src/core/server/document/accountData.ts @@ -9,10 +9,17 @@ import { deepCloneObject } from '@AthenaShared/utility/deepCopy'; export type KeyChangeCallback = (player: alt.Player, newValue: any, oldValue: any) => void; -const callbacks: { [key: string]: Array } = {}; -const cache: { [id: string]: Account } = {}; -const DEBUG_MODE = false; // Use this to see what state is being set. +const SessionKey = 'athena-document-account-data'; + +declare global { + namespace AthenaSession { + interface Player { + [SessionKey]: Account; + } + } +} +const callbacks: { [key: string]: Array } = {}; const restrictedFields = ['username', 'password', 'salt', 'hardware', 'ips', 'banned']; /** @@ -51,10 +58,10 @@ export function bind(player: alt.Player, document: Account) { return; } - cache[player.id] = document; + Athena.session.player.set(player, SessionKey, document); try { - const dataCopy = deepCloneObject(cache[player.id]); + const dataCopy = deepCloneObject(document); const cleanedData = removeRestrictedFields(dataCopy); Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_ACCOUNT_STATE, cleanedData); Athena.config.player.set(player, 'account-data', cleanedData); @@ -71,7 +78,7 @@ export function unbind(id: number) { return Overrides.unbind(id); } - delete cache[id]; + Athena.session.player.clearKey(id, SessionKey); } /** @@ -86,9 +93,11 @@ export function get(player: alt.Player): T | undefined { return Overrides.get(player); } - return cache[player.id] as T; + return Athena.session.player.get(player, SessionKey); } +type Combine = A & B; + /** * Get the current value of a specific field inside of the player data object. * Can be extended to obtain any value easily. @@ -106,11 +115,11 @@ export function getField( return Overrides.getField(player, fieldName); } - if (!cache[player.id]) { + if (!Athena.session.player.has(player, SessionKey)) { return undefined; } - return cache[player.id][String(fieldName)]; + return Athena.session.player.get(player, SessionKey)[String(fieldName)]; } /** @@ -132,30 +141,26 @@ export async function set>( return Overrides.set(player, fieldName, value); } - if (!cache[player.id]) { + if (!Athena.session.player.has(player, SessionKey)) { return undefined; } const typeSafeFieldName = String(fieldName); + let data = Athena.session.player.get(player, SessionKey); let oldValue = undefined; - if (cache[player.id][typeSafeFieldName]) { - oldValue = JSON.parse(JSON.stringify(cache[player.id][typeSafeFieldName])); + + if (data[typeSafeFieldName]) { + oldValue = JSON.parse(JSON.stringify(data[typeSafeFieldName])); } + const newData = { [typeSafeFieldName]: value }; - cache[player.id] = Object.assign(cache[player.id], newData); - await Database.updatePartialData(cache[player.id]._id, newData, Athena.database.collections.Accounts); - - if (DEBUG_MODE) { - alt.logWarning( - `DEBUG: ${cache[player.id]._id} state updated for ${typeSafeFieldName} with value: ${JSON.stringify( - newData, - )}`, - ); - } + data = Object.assign(data, newData); + Athena.session.player.set(player, SessionKey, data); + await Database.updatePartialData(data._id, newData, Athena.database.collections.Accounts); try { - const dataCopy = deepCloneObject(cache[player.id]); + const dataCopy = deepCloneObject(data); const cleanedData = removeRestrictedFields(dataCopy); Athena.config.player.set(player, 'account-data', cleanedData); Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_ACCOUNT_STATE, cleanedData); @@ -184,22 +189,29 @@ export async function setBulk>(player: alt.P return Overrides.setBulk(player, fields); } + if (!Athena.session.player.has(player, SessionKey)) { + return undefined; + } + + let data = Athena.session.player.get(player, SessionKey); + const oldValues = {}; Object.keys(fields).forEach((key) => { - if (typeof cache[player.id][key] === 'undefined') { + if (typeof data[key] === 'undefined') { oldValues[key] = undefined; return; } - oldValues[key] = JSON.parse(JSON.stringify(cache[player.id][key])); + oldValues[key] = JSON.parse(JSON.stringify(data[key])); }); - cache[player.id] = Object.assign(cache[player.id], fields); - await Database.updatePartialData(cache[player.id]._id, fields, Athena.database.collections.Accounts); + data = Object.assign(data, fields); + Athena.session.player.set(player, SessionKey, data); + await Database.updatePartialData(data._id, fields, Athena.database.collections.Accounts); try { - const dataCopy = deepCloneObject(cache[player.id]); + const dataCopy = deepCloneObject(data); const cleanedData = removeRestrictedFields(dataCopy); Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_ACCOUNT_STATE, cleanedData); Athena.config.player.set(player, 'account-data', cleanedData); @@ -211,7 +223,7 @@ export async function setBulk>(player: alt.P } for (let cb of callbacks[key]) { - cb(player, cache[player.id][key], oldValues[key]); + cb(player, data[key], oldValues[key]); } }); } @@ -237,14 +249,6 @@ export function onChange(fieldName: keyof KnownKeys, callba } } -alt.on('playerDisconnect', (player: alt.Player) => { - if (typeof player.id === 'undefined' || player.id === null) { - return; - } - - unbind(player.id); -}); - interface AccountDataDocFuncs { bind: typeof bind; unbind: typeof unbind; diff --git a/src/core/server/document/character.ts b/src/core/server/document/character.ts index 60d2657bc7..7e2feaf94f 100644 --- a/src/core/server/document/character.ts +++ b/src/core/server/document/character.ts @@ -7,9 +7,17 @@ import Database from '@stuyk/ezmongodb'; export type KeyChangeCallback = (player: alt.Player, newValue: any, oldValue: any) => void; +const SessionKey = 'athena-document-character-data'; + +declare global { + namespace AthenaSession { + interface Player { + [SessionKey]: Character; + } + } +} + const callbacks: { [key: string]: Array } = {}; -const cache: { [id: string]: Character } = {}; -const DEBUG_MODE = false; // Use this to see what state is being set. /** * Binds a player identifier to a Character document. @@ -41,8 +49,8 @@ export function bind(player: alt.Player, document: Character) { document._id = document._id.toString(); } - cache[player.id] = document; - Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_STATE, cache[player.id]); + Athena.session.player.set(player, SessionKey, document); + Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_STATE, document); } /** @@ -62,7 +70,7 @@ export function unbind(id: number) { return Overrides.unbind(id); } - delete cache[id]; + Athena.session.player.clearKey(id, SessionKey); } /** @@ -98,7 +106,7 @@ export function get(player: alt.Player): T | undefined { return Overrides.get(player); } - return cache[player.id] as T; + return Athena.session.player.get(player, SessionKey); } /** @@ -142,11 +150,11 @@ export function getField( return Overrides.getField(player, fieldName); } - if (!cache[player.id]) { + if (!Athena.session.player.has(player, SessionKey)) { return undefined; } - return cache[player.id][String(fieldName)]; + return Athena.session.player.get(player, SessionKey)[String(fieldName)]; } /** @@ -185,31 +193,25 @@ export async function set>( return Overrides.set(player, fieldName, value, skipCallbacks); } - if (!cache[player.id]) { + if (!Athena.session.player.has(player, SessionKey)) { return undefined; } const typeSafeFieldName = String(fieldName); let oldValue = undefined; - if (cache[player.id][typeSafeFieldName]) { - oldValue = JSON.parse(JSON.stringify(cache[player.id][typeSafeFieldName])); + let data = Athena.session.player.get(player, SessionKey); + if (data[typeSafeFieldName]) { + oldValue = JSON.parse(JSON.stringify(data[typeSafeFieldName])); } const newData = { [typeSafeFieldName]: value }; - cache[player.id] = Object.assign(cache[player.id], newData); - await Database.updatePartialData(cache[player.id]._id, newData, Athena.database.collections.Characters); + data = Object.assign(data, newData); + Athena.session.player.set(player, SessionKey, data); + await Database.updatePartialData(data._id, newData, Athena.database.collections.Characters); - if (DEBUG_MODE) { - alt.logWarning( - `DEBUG: ${cache[player.id].name} state updated for ${typeSafeFieldName} with value: ${JSON.stringify( - newData, - )}`, - ); - } - - Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_STATE, cache[player.id]); - Athena.config.player.set(player, 'character-data', cache[player.id]); + Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_STATE, data); + Athena.config.player.set(player, 'character-data', data); if (typeof callbacks[typeSafeFieldName] === 'undefined') { return; @@ -247,20 +249,23 @@ export async function setBulk>(player: alt const oldValues = {}; + let data = Athena.session.player.get(player, SessionKey); + Object.keys(fields).forEach((key) => { - if (typeof cache[player.id][key] === 'undefined') { + if (typeof data[key] === 'undefined') { oldValues[key] = undefined; return; } - oldValues[key] = JSON.parse(JSON.stringify(cache[player.id][key])); + oldValues[key] = JSON.parse(JSON.stringify(data[key])); }); - cache[player.id] = Object.assign(cache[player.id], fields); - await Database.updatePartialData(cache[player.id]._id, fields, Athena.database.collections.Characters); + data = Object.assign(data, fields); + Athena.session.player.set(player, SessionKey, data); + await Database.updatePartialData(data._id, fields, Athena.database.collections.Characters); - Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_STATE, cache[player.id]); - Athena.config.player.set(player, 'character-data', cache[player.id]); + Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_STATE, data); + Athena.config.player.set(player, 'character-data', data); Object.keys(fields).forEach((key) => { if (typeof callbacks[key] === 'undefined') { @@ -268,7 +273,7 @@ export async function setBulk>(player: alt } for (let cb of callbacks[key]) { - cb(player, cache[player.id][key], oldValues[key]); + cb(player, data[key], oldValues[key]); } }); } @@ -314,29 +319,19 @@ export function onChange(fieldName: keyof KnownKeys, call */ export function getAllOnline(): Array<{ id: number; document: Character & T }> { const dataSet: Array<{ id: number; document: Character & T }> = []; - const ids = Object.keys(cache); - for (let id of ids) { - dataSet.push({ id: parseInt(id), document: cache[id] as Character & T }); + for (let player of alt.Player.all) { + const data = Athena.session.player.get(player, SessionKey); + if (typeof data === 'undefined') { + continue; + } + + dataSet.push({ id: player.id, document: data as Character & T }); } return dataSet; } -alt.on('playerDisconnect', (player: alt.Player) => { - if (typeof player.id === 'undefined' || player.id === null) { - return; - } - - const id = player.id; - if (!cache[id]) { - return; - } - - Athena.player.events.trigger('player-disconnected', player, id, cache[id]); - unbind(id); -}); - interface CharacterDocFuncs { bind: typeof bind; unbind: typeof unbind; diff --git a/src/core/server/document/vehicle.ts b/src/core/server/document/vehicle.ts index c0bc9bbb49..f06f171ecc 100644 --- a/src/core/server/document/vehicle.ts +++ b/src/core/server/document/vehicle.ts @@ -7,9 +7,17 @@ import Database from '@stuyk/ezmongodb'; export type KeyChangeCallback = (vehicle: alt.Vehicle, newValue: any, oldValue: any) => void; +const SessionKey = 'athena-document-vehicle-data'; + +declare global { + namespace AthenaSession { + interface Vehicle { + [SessionKey]: OwnedVehicle; + } + } +} + const callbacks: { [key: string]: Array } = {}; -const cache: { [id: string]: OwnedVehicle } = {}; -const DEBUG_MODE = false; /** * Used to unbind vehicle cache for an id once the vehicle is deleted @@ -21,7 +29,7 @@ export function unbind(id: number) { return Overrides.unbind(id); } - delete cache[id]; + Athena.session.vehicle.clearKey(id, SessionKey); } /** @@ -39,7 +47,7 @@ export function bind(vehicle: alt.Vehicle, document: OwnedVehicle) { document._id = document._id.toString(); } - cache[vehicle.id] = document; + Athena.session.vehicle.set(vehicle, SessionKey, document); } /** @@ -54,7 +62,7 @@ export function get(vehicle: alt.Vehicle): T | undefined { return Overrides.get(vehicle); } - return cache[vehicle.id] as T; + return Athena.session.vehicle.get(vehicle, SessionKey); } /** @@ -74,11 +82,11 @@ export function getField( return Overrides.getField(vehicle, fieldName); } - if (!cache[vehicle.id]) { + if (!Athena.session.vehicle.has(vehicle, SessionKey)) { return undefined; } - return cache[vehicle.id][String(fieldName)]; + return Athena.session.vehicle.get(vehicle, SessionKey)[String(fieldName)]; } /** @@ -102,28 +110,22 @@ export async function set>( return Overrides.set(vehicle, fieldName, value, skipCallbacks); } - if (!cache[vehicle.id]) { + if (!Athena.session.vehicle.get(vehicle, SessionKey)) { return undefined; } const typeSafeFieldName = String(fieldName); let oldValue = undefined; - if (cache[vehicle.id][typeSafeFieldName]) { - oldValue = JSON.parse(JSON.stringify(cache[vehicle.id][typeSafeFieldName])); + let data = Athena.session.vehicle.get(vehicle, SessionKey); + if (data[typeSafeFieldName]) { + oldValue = JSON.parse(JSON.stringify(data[typeSafeFieldName])); } const newData = { [typeSafeFieldName]: value }; - cache[vehicle.id] = Object.assign(cache[vehicle.id], newData); - await Database.updatePartialData(cache[vehicle.id]._id, newData, Athena.database.collections.Vehicles); - - if (DEBUG_MODE) { - alt.logWarning( - `DEBUG: ${cache[vehicle.id]._id} state updated for ${typeSafeFieldName} with value: ${JSON.stringify( - newData, - )}`, - ); - } + data = Object.assign(data, newData); + Athena.session.vehicle.set(vehicle, SessionKey, data); + await Database.updatePartialData(data._id, newData, Athena.database.collections.Vehicles); if (typeof callbacks[typeSafeFieldName] === 'undefined') { return; @@ -153,18 +155,20 @@ export async function setBulk>(vehicle: } const oldValues = {}; + let data = Athena.session.vehicle.get(vehicle, SessionKey); Object.keys(fields).forEach((key) => { - if (typeof cache[vehicle.id][key] === 'undefined') { + if (typeof data[key] === 'undefined') { oldValues[key] = undefined; return; } - oldValues[key] = JSON.parse(JSON.stringify(cache[vehicle.id][key])); + oldValues[key] = JSON.parse(JSON.stringify(data[key])); }); - cache[vehicle.id] = Object.assign(cache[vehicle.id], fields); - await Database.updatePartialData(cache[vehicle.id]._id, fields, Athena.database.collections.Vehicles); + data = Object.assign(data, fields); + Athena.session.vehicle.set(vehicle, SessionKey, data); + await Database.updatePartialData(data._id, fields, Athena.database.collections.Vehicles); Object.keys(fields).forEach((key) => { if (typeof callbacks[key] === 'undefined') { @@ -172,7 +176,7 @@ export async function setBulk>(vehicle: } for (let cb of callbacks[key]) { - cb(vehicle, cache[vehicle.id][key], oldValues[key]); + cb(vehicle, data[key], oldValues[key]); } }); } @@ -209,10 +213,14 @@ export function onChange(fieldName: keyof KnownKeys, c */ export function getAllOnline(): Array<{ id: number; document: OwnedVehicle & T }> { const dataSet: Array<{ id: number; document: OwnedVehicle & T }> = []; - const ids = Object.keys(cache); - for (let id of ids) { - dataSet.push({ id: parseInt(id), document: cache[id] as OwnedVehicle & T }); + for (let vehicle of alt.Vehicle.all) { + const data = Athena.session.vehicle.get(vehicle, SessionKey); + if (typeof data === 'undefined') { + continue; + } + + dataSet.push({ id: vehicle.id, document: data as OwnedVehicle & T }); } return dataSet; @@ -221,12 +229,12 @@ export function getAllOnline(): Array<{ id: number; document: OwnedVehic /** * Check if a vehicle document already exists and a vehicle is attached to it. * - * * @param {string} _id * @return {boolean} */ export function exists(_id: string): boolean { - return Object.values(cache).find((x) => x._id.toString() === _id.toString()) !== undefined; + const sessions = Athena.session.vehicle.getAll(SessionKey); + return sessions.find((x) => x._id === _id) ? true : false; } alt.on('removeEntity', (entity: alt.Entity) => { diff --git a/src/core/server/session/player.ts b/src/core/server/session/player.ts index 704d31de4e..38b51d579e 100644 --- a/src/core/server/session/player.ts +++ b/src/core/server/session/player.ts @@ -41,7 +41,7 @@ export function set( return; } - if (!sessionStorage[player.id]) { + if (typeof sessionStorage[player.id] === 'undefined') { sessionStorage[player.id] = {}; } @@ -63,7 +63,7 @@ export function get( return undefined; } - if (!sessionStorage[player.id]) { + if (typeof sessionStorage[player.id] === 'undefined') { return undefined; } @@ -82,11 +82,11 @@ export function has(player: alt.Player, key: keyof AthenaSession.Player) { return false; } - if (!sessionStorage[player.id]) { + if (typeof sessionStorage[player.id] === 'undefined') { return false; } - return typeof sessionStorage[player.id][key] ? true : false; + return typeof sessionStorage[player.id][key] !== 'undefined' ? true : false; } /** @@ -96,16 +96,20 @@ export function has(player: alt.Player, key: keyof AthenaSession.Player) { * @param {alt.Player} player * @param {string} key */ -export function clearKey(player: alt.Player, key: keyof AthenaSession.Player) { - if (!player || !player.valid) { - return; +export function clearKey(player: alt.Player | number, key: keyof AthenaSession.Player) { + if (player instanceof alt.Player) { + if (!player || !player.valid) { + return; + } + + player = player.id; } - if (!sessionStorage[player.id]) { + if (typeof sessionStorage[player] === 'undefined') { return; } - delete sessionStorage[player.id][key]; + delete sessionStorage[player][key]; } /** @@ -119,11 +123,21 @@ export function clearAll(player: alt.Player) { return; } - if (!sessionStorage[player.id]) { + if (typeof sessionStorage[player.id] === 'undefined') { return; } delete sessionStorage[player.id]; } +/** + * Get all player's that have a specific key. + * + * @export + * @param {string} key + */ +export function getAll(key: K): Array { + return Object.values(sessionStorage).filter((x) => x[key]) as Array; +} + alt.on('playerDisconnect', clearAll); diff --git a/src/core/server/session/vehicle.ts b/src/core/server/session/vehicle.ts index b43dd37cc9..2e50d196bc 100644 --- a/src/core/server/session/vehicle.ts +++ b/src/core/server/session/vehicle.ts @@ -65,7 +65,7 @@ export function has(vehicle: alt.Vehicle, key: string) { return false; } - return typeof sessionStorage[vehicle.id][key] ? true : false; + return typeof sessionStorage[vehicle.id][key] !== 'undefined' ? true : false; } /** @@ -83,7 +83,7 @@ export function get( return undefined; } - if (!sessionStorage[vehicle.id]) { + if (typeof sessionStorage[vehicle.id] === 'undefined') { return undefined; } @@ -97,16 +97,20 @@ export function get( * @param {alt.Vehicle} vehicle * @param {string} key */ -export function clearKey(vehicle: alt.Vehicle, key: keyof AthenaSession.Vehicle) { - if (!vehicle || !vehicle.valid) { - return; +export function clearKey(vehicle: alt.Vehicle | number, key: keyof AthenaSession.Vehicle) { + if (vehicle instanceof alt.Vehicle) { + if (!vehicle || !vehicle.valid) { + return; + } + + vehicle = vehicle.id; } - if (!sessionStorage[vehicle.id]) { + if (typeof sessionStorage[vehicle] === 'undefined') { return; } - delete sessionStorage[vehicle.id][key]; + delete sessionStorage[vehicle][key]; } /** @@ -120,11 +124,21 @@ export function clearAll(vehicle: alt.Vehicle) { return; } - if (!sessionStorage[vehicle.id]) { + if (typeof sessionStorage[vehicle.id] === 'undefined') { return; } delete sessionStorage[vehicle.id]; } +/** + * Get all vehicles's that have a specific key. + * + * @export + * @param {string} key + */ +export function getAll(key: K): Array { + return Object.values(sessionStorage).filter((x) => x[key]) as Array; +} + alt.on('vehicleDestroy', clearAll);