Hi,
I am experiencing a hair and undershirt coloring bug on my server. It seems to only affect the player whose server ID is 0 (zero). That is, from player zero's perspective, they look fine. From all other players' perspectives, player zero's undershirt and hair will flicker between a variety of colors.
Recording: https://streamable.com/sdk7mf
The steps we've taken to try and resolve the issue:
All component palette values to 0.
All component palette values to 2.
Components that are torso-related to palette value to 2, all else palette value 0.
setHairColor separately.
Single server-side JavaScript script with setClothes.
Single client-side JavaScript script with setComponentVariation.
Single server-side C# script with NAPI.Player.SetPlayerClothes.
Server-side script to set the player's clothing, client-side script to fetch the configuration and apply it in "entityStreamIn" event.
Set undershirt to 15. (Only the hair switches color when this is done.)
Entity data. (+ addDataHandler)
Host server on different Windows 10 machine.
Host server on debian12 VPS.
Clean GTA5 installations, no mods, clean server-files. The server is hosted locally. Second game instance is running on a different computer connected through LAN.
Single server-side JavaScript file:
let playerClothes = new Map();
mp.events.add('playerJoin', (player) => {
const randomHair = Math.floor(Math.random() * 20) + 5;
const clothing = [
{ component: 0, drawable: 0, texture: 0, palette: 0 },
{ component: 1, drawable: 0, texture: 0, palette: 0 },
{ component: 2, drawable: randomHair, texture: 0, palette: 0 },
{ component: 3, drawable: 0, texture: 0, palette: 2 },
{ component: 4, drawable: 0, texture: 0, palette: 0 },
{ component: 5, drawable: 0, texture: 0, palette: 0 },
{ component: 6, drawable: 0, texture: 0, palette: 0 },
{ component: 7, drawable: 0, texture: 0, palette: 0 },
{ component: 8, drawable: 0, texture: 0, palette: 2 },
{ component: 9, drawable: 0, texture: 0, palette: 2 },
{ component: 10, drawable: 0, texture: 0, palette: 2 },
{ component: 11, drawable: 16, texture: 0, palette: 2 }
];
playerClothes.set(player.id, clothing);
});
mp.events.add('playerReady', (player) => {
const clothing = playerClothes.get(player.id);
clothing.forEach((slot) => {
player.setClothes(slot.component, slot.drawable, slot.texture, slot.palette);
});
});
Single client-side JavaScript script:
mp.events.add('playerReady', () => {
const player = mp.players.local;
const clothing = [
{ component: 0, drawable: 0, texture: 0, palette: 2 },
{ component: 1, drawable: 0, texture: 0, palette: 2 },
{ component: 2, drawable: 5, texture: 0, palette: 2 },
{ component: 3, drawable: 0, texture: 0, palette: 2 },
{ component: 4, drawable: 0, texture: 0, palette: 2 },
{ component: 5, drawable: 0, texture: 0, palette: 2 },
{ component: 6, drawable: 0, texture: 0, palette: 2 },
{ component: 7, drawable: 0, texture: 0, palette: 2 },
{ component: 8, drawable: 0, texture: 0, palette: 2 },
{ component: 9, drawable: 0, texture: 0, palette: 2 },
{ component: 10, drawable: 0, texture: 0, palette: 2 },
{ component: 11, drawable: 10, texture: 0, palette: 2 }
];
for (let i = 0; i < clothing.length; i++) {
const slot = clothing[i];
player.setComponentVariation(slot.component, slot.drawable, slot.texture, slot.palette);
}
});
mp.events.add('entityStreamIn', (entity) => {
if (entity.type !== 'player') {
return;
}
const clothing = [
{ component: 0, drawable: 0, texture: 0, palette: 2 },
{ component: 1, drawable: 0, texture: 0, palette: 2 },
{ component: 2, drawable: 17, texture: 0, palette: 2 },
{ component: 3, drawable: 0, texture: 0, palette: 2 },
{ component: 4, drawable: 0, texture: 0, palette: 2 },
{ component: 5, drawable: 0, texture: 0, palette: 2 },
{ component: 6, drawable: 0, texture: 0, palette: 2 },
{ component: 7, drawable: 0, texture: 0, palette: 2 },
{ component: 8, drawable: 0, texture: 0, palette: 2 },
{ component: 9, drawable: 0, texture: 0, palette: 2 },
{ component: 10, drawable: 0, texture: 0, palette: 2 },
{ component: 11, drawable: 33, texture: 0, palette: 2 }
];
for (let i = 0; i < clothing.length; i++) {
const slot = clothing[i];
entity.setComponentVariation(slot.component, slot.drawable, slot.texture, slot.palette);
}
});
Server-side script to store clothing data, client-side script to fetch in "entityStreamIn" event:
/*
* SERVER
*
*/
let playerClothes = new Map();
mp.events.add('clothes::requestForPlayer', (player, id) => {
const clothing = playerClothes.get(id);
player.call('clothes::forPlayer', [id, JSON.stringify(clothing)]);
});
mp.events.add('playerJoin', (player) => {
const randomHair = Math.floor(Math.random() * 20) + 5;
const clothing = [
{ component: 0, drawable: 0, texture: 0, palette: 0 },
{ component: 1, drawable: 0, texture: 0, palette: 0 },
{ component: 2, drawable: randomHair, texture: 0, palette: 0 },
{ component: 3, drawable: 0, texture: 0, palette: 2 },
{ component: 4, drawable: 0, texture: 0, palette: 0 },
{ component: 5, drawable: 0, texture: 0, palette: 0 },
{ component: 6, drawable: 0, texture: 0, palette: 0 },
{ component: 7, drawable: 0, texture: 0, palette: 0 },
{ component: 8, drawable: 0, texture: 0, palette: 2 },
{ component: 9, drawable: 0, texture: 0, palette: 2 },
{ component: 10, drawable: 0, texture: 0, palette: 2 },
{ component: 11, drawable: 16, texture: 0, palette: 2 }
];
playerClothes.set(player.id, clothing);
});
/*
* CLIENT
*
*/
mp.events.add('playerReady', () => {
mp.events.callRemote("clothes::requestForPlayer", mp.players.local.remoteId);
});
mp.events.add('entityStreamIn', (entity) => {
if (entity.type !== 'player') {
return;
}
mp.events.callRemote("clothes::requestForPlayer", entity.remoteId);
});
mp.events.add('clothes::forPlayer', (id, clothesJSON) => {
const forPlayer = mp.players.atRemoteId(id);
const clothing = JSON.parse(clothesJSON);
for (let i = 0; i < clothing.length; i++) {
const slot = clothing[i];
forPlayer.setComponentVariation(slot.component, slot.drawable, slot.texture, slot.palette);
}
});
Single server-side C# script:
using System;
using System.Collections.Generic;
using System.Linq;
using GTANetworkAPI;
namespace ClothingTest
{
public class Class1 : Script
{
public Class1()
{
}
[ServerEvent(Event.PlayerConnected)]
public void OnPlayerConnect(Player player)
{
Dictionary<int, int[]> clothing = new Dictionary<int, int[]>();
clothing.Add(0, new int[2] { 0, 0 });
clothing.Add(1, new int[2] { 0, 0 });
clothing.Add(2, new int[2] { 17, 0 });
clothing.Add(3, new int[2] { 0, 0 });
clothing.Add(4, new int[2] { 0, 0 });
clothing.Add(5, new int[2] { 0, 0 });
clothing.Add(6, new int[2] { 0, 0 });
clothing.Add(7, new int[2] { 0, 0 });
clothing.Add(8, new int[2] { 0, 0 });
clothing.Add(9, new int[2] { 0, 0 });
clothing.Add(10, new int[2] { 0, 0 });
clothing.Add(11, new int[2] { 33, 0 });
for (int i = 0; i < 11; i++)
{
var value = clothing.ElementAt(i).Value;
NAPI.Player.SetPlayerClothes(player, i, value[0], value[1]);
}
}
}
}
I am out of ideas. Thank you for your time.