From 5c56b52c465dbc321735308dc3643620e87cdfb4 Mon Sep 17 00:00:00 2001 From: stuyk Date: Fri, 19 Apr 2024 22:25:17 -0600 Subject: [PATCH] feat: handle undefined appearance, docs for appearance --- docs/api/server/player-appearance.md | 43 ++++++ src/main/server/player/appearance.ts | 100 ++++++++----- src/main/shared/data/hairOverlay.ts | 202 +++++++++++++++++++++++++++ 3 files changed, 311 insertions(+), 34 deletions(-) create mode 100644 docs/api/server/player-appearance.md create mode 100644 src/main/shared/data/hairOverlay.ts diff --git a/docs/api/server/player-appearance.md b/docs/api/server/player-appearance.md new file mode 100644 index 000000000..e204d85d8 --- /dev/null +++ b/docs/api/server/player-appearance.md @@ -0,0 +1,43 @@ +# Player - Appearance + +Used to set various freeroam character appearance data and store in the database. + +```ts +import { usePlayerAppearance } from '@Server/player/appearance.js'; + +const appearance = usePlayerAppearance(somePlayer); + +// Get hair decorator for style, and save to database +const hairDecorator = appearance.getHairOverlay(0, 5); + +// Set eye color and save to database +appearance.setEyeColor(5); + +// Set eyebrow style and save to database +appearance.setEyebrows({ style: 1, color: 5, opacity: 1 }); + +// Set facial hair style and save to database +appearance.setFacialHair({ style: 5, color: 2, opacity: 1 }); + +// Set a hair style and save to database +appearance.setHairStyle({ hair: 5, color1: 25, color2: 25, decorator: hairDecorator }); + +// Set face appearance data +appearance.setHeadBlendData({ + faceFather: 0, + faceMother: 0, + skinFather: 5, + skinMother: 45, + faceMix: 0.5, + skinMix: 0.5, +}); + +// Set to true to have a more feminine body +appearance.setModel(true); + +// Set tattoos on the player and save to database +appearance.setTattoos([{ collection: 'mpairraces_overlays', overlay: 'MP_Airraces_Tattoo_000_M' }]); + +// Called automatically, but resynchronizes freeroam player appearance +appearance.update(); +``` diff --git a/src/main/server/player/appearance.ts b/src/main/server/player/appearance.ts index d1eebcc50..2cef5b796 100644 --- a/src/main/server/player/appearance.ts +++ b/src/main/server/player/appearance.ts @@ -1,5 +1,6 @@ import * as alt from 'alt-server'; import { useCharacter } from '@Server/document/character.js'; +import { getHairOverlay } from '../../shared/data/hairOverlay.js'; export type Decorator = { overlay: string; collection: string }; export type HairStyle = { hair: number; dlc?: string | number; color1: number; color2: number; decorator: Decorator }; @@ -17,10 +18,14 @@ export function usePlayerAppearance(player: alt.Player) { async function setHairStyle(style: HairStyle) { const document = useCharacter(player); const data = document.get(); - if (!data || !data.appearance) { + if (!data) { return; } + if (!data.appearance) { + data.appearance = {}; + } + data.appearance.hair = style.hair; data.appearance.hairColor1 = style.color1; data.appearance.hairColor2 = style.color2; @@ -51,10 +56,14 @@ export function usePlayerAppearance(player: alt.Player) { async function setFacialHair(choice: BaseStyle) { const document = useCharacter(player); const data = document.get(); - if (!data || !data.appearance) { + if (!data) { return; } + if (!data.appearance) { + data.appearance = {}; + } + data.appearance.facialHair = choice.style; data.appearance.facialHairColor1 = choice.color; data.appearance.facialHairOpacity = choice.opacity; @@ -74,10 +83,14 @@ export function usePlayerAppearance(player: alt.Player) { async function setEyebrows(choice: BaseStyle) { const document = useCharacter(player); const data = document.get(); - if (!data || !data.appearance) { + if (!data) { return; } + if (!data.appearance) { + data.appearance = {}; + } + data.appearance.eyebrows = choice.style; data.appearance.eyebrowsColor1 = choice.color; data.appearance.eyebrowsOpacity = choice.opacity; @@ -97,10 +110,14 @@ export function usePlayerAppearance(player: alt.Player) { async function setModel(isFeminine: boolean) { const document = useCharacter(player); const data = document.get(); - if (!data || !data.appearance) { + if (!data) { return; } + if (!data.appearance) { + data.appearance = {}; + } + data.appearance.sex = isFeminine ? 0 : 1; await document.set('appearance', data.appearance); } @@ -116,10 +133,14 @@ export function usePlayerAppearance(player: alt.Player) { async function setEyeColor(color: number) { const document = useCharacter(player); const data = document.get(); - if (!data || !data.appearance) { + if (!data) { return; } + if (!data.appearance) { + data.appearance = {}; + } + data.appearance.eyes = color; await document.set('appearance', data.appearance); } @@ -148,10 +169,13 @@ export function usePlayerAppearance(player: alt.Player) { }) { const document = useCharacter(player); const data = document.get(); - if (!data || !data.appearance) { + if (!data) { return; } + if (!data.appearance) { + data.appearance = {}; + } data.appearance = { ...data.appearance, ...faceData }; await document.set('appearance', data.appearance); } @@ -186,30 +210,31 @@ export function usePlayerAppearance(player: alt.Player) { } const data = dataDocument.appearance; - if (data.sex === 0) { - player.model = 'mp_f_freemode_01'; - } else { - player.model = 'mp_m_freemode_01'; + + if (typeof data.sex !== undefined) { + player.model = data.sex === 0 ? 'mp_f_freemode_01' : 'mp_m_freemode_01'; } // Set Face player.clearBloodDamage(); player.setHeadBlendData( - data.faceMother, - data.faceFather, + data.faceMother ?? 0, + data.faceFather ?? 0, 0, - data.skinMother, - data.skinFather, + data.skinMother ?? 0, + data.skinFather ?? 0, 0, - parseFloat(data.faceMix.toString()), - parseFloat(data.skinMix.toString()), + parseFloat(data.faceMix.toString()) ?? 0.5, + parseFloat(data.skinMix.toString()) ?? 0.5, 0 ); // Facial Features - for (let i = 0; i < data.structure.length; i++) { - const value = data.structure[i]; - player.setFaceFeature(i, value); + if (Array.isArray(data.structure)) { + for (let i = 0; i < data.structure.length; i++) { + const value = data.structure[i]; + player.setFaceFeature(i, value); + } } // Hair - Tattoo @@ -217,17 +242,19 @@ export function usePlayerAppearance(player: alt.Player) { // Hair - Supports DLC if (typeof data.hairDlc === 'undefined' || data.hairDlc === 0) { - player.setClothes(2, data.hair, 0, 0); + player.setClothes(2, data.hair ?? 0, 0, 0); } else { - player.setDlcClothes(data.hairDlc, 2, data.hair, 0, 0); + player.setDlcClothes(data.hairDlc, 2, data.hair ?? 0, 0, 0); } - player.setHairColor(data.hairColor1); - player.setHairHighlightColor(data.hairColor2); + player.setHairColor(data.hairColor1 ?? 0); + player.setHairHighlightColor(data.hairColor2 ?? 0); // Facial Hair - player.setHeadOverlay(1, data.facialHair, data.facialHairOpacity); - player.setHeadOverlayColor(1, 1, data.facialHairColor1, data.facialHairColor1); + if (typeof data.facialHair !== 'undefined') { + player.setHeadOverlay(1, data.facialHair, data.facialHairOpacity); + player.setHeadOverlayColor(1, 1, data.facialHairColor1, data.facialHairColor1); + } // Chest Hair if (data.chestHair !== null && data.chestHair !== undefined) { @@ -236,20 +263,24 @@ export function usePlayerAppearance(player: alt.Player) { } // Eyebrows - player.setHeadOverlay(2, data.eyebrows, data.eyebrowsOpacity); - player.setHeadOverlayColor(2, 1, data.eyebrowsColor1, data.eyebrowsColor1); + if (typeof data.eyebrows !== 'undefined') { + player.setHeadOverlay(2, data.eyebrows, data.eyebrowsOpacity); + player.setHeadOverlayColor(2, 1, data.eyebrowsColor1, data.eyebrowsColor1); + } // Decor - for (let i = 0; i < data.colorOverlays.length; i++) { - const overlay = data.colorOverlays[i]; - const color2 = overlay.color2 ? overlay.color2 : overlay.color1; - - player.setHeadOverlay(overlay.id, overlay.value, parseFloat(overlay.opacity.toString())); - player.setHeadOverlayColor(overlay.id, 1, overlay.color1, color2); + if (Array.isArray(data.colorOverlays)) { + for (let i = 0; i < data.colorOverlays.length; i++) { + const overlay = data.colorOverlays[i]; + const color2 = overlay.color2 ? overlay.color2 : overlay.color1; + + player.setHeadOverlay(overlay.id, overlay.value, parseFloat(overlay.opacity.toString())); + player.setHeadOverlayColor(overlay.id, 1, overlay.color1, color2); + } } // Eyes - player.setEyeColor(data.eyes); + player.setEyeColor(data.eyes ?? 0); } /** @@ -282,6 +313,7 @@ export function usePlayerAppearance(player: alt.Player) { } return { + getHairOverlay, setEyeColor, setEyebrows, setFacialHair, diff --git a/src/main/shared/data/hairOverlay.ts b/src/main/shared/data/hairOverlay.ts new file mode 100644 index 000000000..499cff15a --- /dev/null +++ b/src/main/shared/data/hairOverlay.ts @@ -0,0 +1,202 @@ +const hairOverlay: { [key: string]: { [key: string]: { collection: string; overlay: string } } } = { + 0: { + 0: { collection: 'mpbeach_overlays', overlay: 'FM_Hair_Fuzz' }, + 1: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_001' }, + 2: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_002' }, + 3: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_003' }, + 4: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_004' }, + 5: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_005' }, + 6: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_006' }, + 7: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_007' }, + 8: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_008' }, + 9: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_009' }, + 10: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_010' }, + 11: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_011' }, + 12: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_012' }, + 13: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_013' }, + 14: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_014' }, + 15: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_015' }, + 16: { collection: 'multiplayer_overlays', overlay: 'NGBea_F_Hair_000' }, + 17: { collection: 'multiplayer_overlays', overlay: 'NGBea_F_Hair_001' }, + 18: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_007' }, + 19: { collection: 'multiplayer_overlays', overlay: 'NGBus_F_Hair_000' }, + 20: { collection: 'multiplayer_overlays', overlay: 'NGBus_F_Hair_001' }, + 21: { collection: 'multiplayer_overlays', overlay: 'NGBea_F_Hair_001' }, + 22: { collection: 'multiplayer_overlays', overlay: 'NGHip_F_Hair_000' }, + 23: { collection: 'multiplayer_overlays', overlay: 'NGInd_F_Hair_000' }, + 24: { collection: 'mpbeach_overlays', overlay: 'FM_Hair_Fuzz' }, + 25: { collection: 'mplowrider_overlays', overlay: 'LR_F_Hair_000' }, + 26: { collection: 'mplowrider_overlays', overlay: 'LR_F_Hair_001' }, + 27: { collection: 'mplowrider_overlays', overlay: 'LR_F_Hair_002' }, + 28: { collection: 'mplowrider2_overlays', overlay: 'LR_F_Hair_003' }, + 29: { collection: 'mplowrider2_overlays', overlay: 'LR_F_Hair_003' }, + 30: { collection: 'mplowrider2_overlays', overlay: 'LR_F_Hair_004' }, + 31: { collection: 'mplowrider2_overlays', overlay: 'LR_F_Hair_006' }, + 32: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_000_F' }, + 33: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_001_F' }, + 34: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_002_F' }, + 35: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_003_F' }, + 36: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_003' }, + 37: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_006_F' }, + 38: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_004_F' }, + 39: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_001' }, + 40: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_002' }, + 41: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_003' }, + 42: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_004' }, + 43: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_005' }, + 44: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_006' }, + 45: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_007' }, + 46: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_008' }, + 47: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_009' }, + 48: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_010' }, + 49: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_011' }, + 50: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_012' }, + 51: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_013' }, + 52: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_014' }, + 53: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_015' }, + 54: { collection: 'multiplayer_overlays', overlay: 'NGBea_F_Hair_000' }, + 55: { collection: 'multiplayer_overlays', overlay: 'NGBea_F_Hair_001' }, + 56: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_007' }, + 57: { collection: 'multiplayer_overlays', overlay: 'NGBus_F_Hair_000' }, + 58: { collection: 'multiplayer_overlays', overlay: 'NGBus_F_Hair_001' }, + 59: { collection: 'multiplayer_overlays', overlay: 'NGBea_F_Hair_001' }, + 60: { collection: 'multiplayer_overlays', overlay: 'NGHip_F_Hair_000' }, + 61: { collection: 'multiplayer_overlays', overlay: 'NGInd_F_Hair_000' }, + 62: { collection: 'mplowrider_overlays', overlay: 'LR_F_Hair_000' }, + 63: { collection: 'mplowrider_overlays', overlay: 'LR_F_Hair_001' }, + 64: { collection: 'mplowrider_overlays', overlay: 'LR_F_Hair_002' }, + 65: { collection: 'mplowrider2_overlays', overlay: 'LR_F_Hair_003' }, + 66: { collection: 'mplowrider2_overlays', overlay: 'LR_F_Hair_003' }, + 67: { collection: 'mplowrider2_overlays', overlay: 'LR_F_Hair_004' }, + 68: { collection: 'mplowrider2_overlays', overlay: 'LR_F_Hair_006' }, + 69: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_000_F' }, + 70: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_001_F' }, + 71: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_002_F' }, + 72: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_003_F' }, + 73: { collection: 'multiplayer_overlays', overlay: 'NG_F_Hair_003' }, + 74: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_006_F' }, + 75: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_004_F' }, + 76: { + collection: 'mpgunrunning_overlays', + overlay: 'MP_Gunrunning_Hair_F_000_F', + }, + 77: { + collection: 'mpgunrunning_overlays', + overlay: 'MP_Gunrunning_Hair_F_001_F', + }, + 78: { + collection: 'mpvinewood_overlays', + overlay: 'MP_Vinewood_Hair_F_000_F', + }, + 79: { + collection: 'mptuner_overlays', + overlay: 'MP_Tuner_Hair_000_F', + }, + 80: { + collection: 'mpsecurity_overlays', + overlay: 'MP_Security_Hair_000_F', + }, + }, + 1: { + 0: { collection: 'mpbeach_overlays', overlay: 'FM_Hair_Fuzz' }, + 1: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_001' }, + 2: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_002' }, + 3: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_003' }, + 4: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_004' }, + 5: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_005' }, + 6: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_006' }, + 7: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_007' }, + 8: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_008' }, + 9: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_009' }, + 10: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_013' }, + 11: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_002' }, + 12: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_011' }, + 13: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_012' }, + 14: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_014' }, + 15: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_015' }, + 16: { collection: 'multiplayer_overlays', overlay: 'NGBea_M_Hair_000' }, + 17: { collection: 'multiplayer_overlays', overlay: 'NGBea_M_Hair_001' }, + 18: { collection: 'multiplayer_overlays', overlay: 'NGBus_M_Hair_000' }, + 19: { collection: 'multiplayer_overlays', overlay: 'NGBus_M_Hair_001' }, + 20: { collection: 'multiplayer_overlays', overlay: 'NGHip_M_Hair_000' }, + 21: { collection: 'multiplayer_overlays', overlay: 'NGHip_M_Hair_001' }, + 22: { collection: 'multiplayer_overlays', overlay: 'NGInd_M_Hair_000' }, + 23: { collection: 'mpbeach_overlays', overlay: 'FM_Hair_Fuzz' }, + 24: { collection: 'mplowrider_overlays', overlay: 'LR_M_Hair_000' }, + 25: { collection: 'mplowrider_overlays', overlay: 'LR_M_Hair_001' }, + 26: { collection: 'mplowrider_overlays', overlay: 'LR_M_Hair_002' }, + 27: { collection: 'mplowrider_overlays', overlay: 'LR_M_Hair_003' }, + 28: { collection: 'mplowrider2_overlays', overlay: 'LR_M_Hair_004' }, + 29: { collection: 'mplowrider2_overlays', overlay: 'LR_M_Hair_005' }, + 30: { collection: 'mplowrider2_overlays', overlay: 'LR_M_Hair_006' }, + 31: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_000_M' }, + 32: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_001_M' }, + 33: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_002_M' }, + 34: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_003_M' }, + 35: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_004_M' }, + 36: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_005_M' }, + 37: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_001' }, + 38: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_002' }, + 39: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_003' }, + 40: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_004' }, + 41: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_005' }, + 42: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_006' }, + 43: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_007' }, + 44: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_008' }, + 45: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_009' }, + 46: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_013' }, + 47: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_002' }, + 48: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_011' }, + 49: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_012' }, + 50: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_014' }, + 51: { collection: 'multiplayer_overlays', overlay: 'NG_M_Hair_015' }, + 52: { collection: 'multiplayer_overlays', overlay: 'NGBea_M_Hair_000' }, + 53: { collection: 'multiplayer_overlays', overlay: 'NGBea_M_Hair_001' }, + 54: { collection: 'multiplayer_overlays', overlay: 'NGBus_M_Hair_000' }, + 55: { collection: 'multiplayer_overlays', overlay: 'NGBus_M_Hair_001' }, + 56: { collection: 'multiplayer_overlays', overlay: 'NGHip_M_Hair_000' }, + 57: { collection: 'multiplayer_overlays', overlay: 'NGHip_M_Hair_001' }, + 58: { collection: 'multiplayer_overlays', overlay: 'NGInd_M_Hair_000' }, + 59: { collection: 'mplowrider_overlays', overlay: 'LR_M_Hair_000' }, + 60: { collection: 'mplowrider_overlays', overlay: 'LR_M_Hair_001' }, + 61: { collection: 'mplowrider_overlays', overlay: 'LR_M_Hair_002' }, + 62: { collection: 'mplowrider_overlays', overlay: 'LR_M_Hair_003' }, + 63: { collection: 'mplowrider2_overlays', overlay: 'LR_M_Hair_004' }, + 64: { collection: 'mplowrider2_overlays', overlay: 'LR_M_Hair_005' }, + 65: { collection: 'mplowrider2_overlays', overlay: 'LR_M_Hair_006' }, + 66: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_000_M' }, + 67: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_001_M' }, + 68: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_002_M' }, + 69: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_003_M' }, + 70: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_004_M' }, + 71: { collection: 'mpbiker_overlays', overlay: 'MP_Biker_Hair_005_M' }, + 72: { + collection: 'mpgunrunning_overlays', + overlay: 'MP_Gunrunning_Hair_M_000_M', + }, + 73: { + collection: 'mpgunrunning_overlays', + overlay: 'MP_Gunrunning_Hair_M_001_M', + }, + 74: { + collection: 'mpvinewood_overlays', + overlay: 'MP_Vinewood_Hair_M_000_M', + }, + 75: { + collection: 'mptuner_overlays', + overlay: 'MP_Tuner_Hair_001_M', + }, + 76: { + collection: 'mpsecurity_overlays', + overlay: 'MP_Security_Hair_001_M', + }, + }, +}; + +export function getHairOverlays(sex: 0 | 1) { + return hairOverlay[sex]; +} + +export function getHairOverlay(sex: 0 | 1, style: number) { + return hairOverlay[sex][style]; +}