DevJeff Posted September 14, 2023 Posted September 14, 2023 (edited) 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. Edited September 14, 2023 by DevJeff 1
DevJeff Posted September 14, 2023 Author Posted September 14, 2023 (edited) Considered Fixed Thanks to the folks on Discord - louzzy, vienna, DaNeo, and Kopra - we found a solution to the problem. The fix: https://wiki.rage.mp/index.php?title=Player::setCustomization We used the code snippet provided on the wiki for testing and the issue hasn't occurred in the dozen of attempts. Edit: When we took the setCustomization code out, the issue came back near immediately, so we can confidently say it is fixed. Edited September 14, 2023 by DevJeff 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now