Skip to content

Commit

Permalink
feat: handle undefined appearance, docs for appearance
Browse files Browse the repository at this point in the history
  • Loading branch information
Stuyk committed Apr 20, 2024
1 parent e8a6969 commit 5c56b52
Show file tree
Hide file tree
Showing 3 changed files with 311 additions and 34 deletions.
43 changes: 43 additions & 0 deletions docs/api/server/player-appearance.md
Original file line number Diff line number Diff line change
@@ -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();
```
100 changes: 66 additions & 34 deletions src/main/server/player/appearance.ts
Original file line number Diff line number Diff line change
@@ -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 };
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -186,48 +210,51 @@ 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
updateTattoos();

// 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) {
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -282,6 +313,7 @@ export function usePlayerAppearance(player: alt.Player) {
}

return {
getHairOverlay,
setEyeColor,
setEyebrows,
setFacialHair,
Expand Down
Loading

0 comments on commit 5c56b52

Please sign in to comment.