This is a mobile optimized page that loads fast, if you want to load the real page, click this text.

Проблема Код rootcause-a синхронизации компонентов между игроками

Robert_Easter

Активный участник
17 Июл 2024
103
13
28
Здраствуйте,

Есть одна маленькая проблема с открытым кодом rootcause на компоненты оружие. На самом деле он рабочий для близких дистанции но когда росстояние между игроками большая и они встречают потом друг друга их Компоненты не видно для друг друга. Ну крч там зашёл чел купил оружие в магазине потом пришёл к другу компоненты не видно(но передать итд все может). Крч визуально просто не видно но когда он в близи всё это делает то все видно норм работает. Надо эту проблему решить если кто то имеет знание в этом сфере пожалуйста помогите.
Client side :
Код:
const Natives = {
    GIVE_WEAPON_COMPONENT_TO_PED: "0xD966D51AA5B28BB9",
    REMOVE_WEAPON_COMPONENT_FROM_PED: "0x1E8BE90C74FB4C09",
    SET_CURRENT_PED_WEAPON: "0xADF692B254977C0C"
};


function addComponentToPlayer(player, weaponHash, componentHash) {
    if (!player.hasOwnProperty("__weaponComponentData")) player.__weaponComponentData = {};
    if (!player.__weaponComponentData.hasOwnProperty(weaponHash)) player.__weaponComponentData[weaponHash] = new Set();


    player.__weaponComponentData[weaponHash].add(componentHash);
    mp.game.invoke(Natives.GIVE_WEAPON_COMPONENT_TO_PED, player.handle, weaponHash >> 0, componentHash >> 0);
}


function removeComponentFromPlayer(player, weaponHash, componentHash) {
    if (!player.hasOwnProperty("__weaponComponentData")) player.__weaponComponentData = {};
    if (!player.__weaponComponentData.hasOwnProperty(weaponHash)) player.__weaponComponentData[weaponHash] = new Set();


    player.__weaponComponentData[weaponHash].delete(componentHash);
    mp.game.invoke(Natives.REMOVE_WEAPON_COMPONENT_FROM_PED, player.handle, weaponHash >> 0, componentHash >> 0);
}


mp.events.add("updatePlayerWeaponComponent", (player, weaponHash, componentHash, removeComponent) => {
    weaponHash = parseInt(weaponHash, 36);
    componentHash = parseInt(componentHash, 36);


    if (removeComponent) {
        removeComponentFromPlayer(player, weaponHash, componentHash);
    } else {
        addComponentToPlayer(player, weaponHash, componentHash);
    }
});


mp.events.add("resetPlayerWeaponComponents", (player, weaponHash) => {
    if (!player.hasOwnProperty("__weaponComponentData")) return;
    if (!player.__weaponComponentData.hasOwnProperty(weaponHash)) return;


    weaponHash = parseInt(weaponHash, 36);


    for (let component of player.__weaponComponentData[weaponHash]) mp.game.invoke(Natives.REMOVE_WEAPON_COMPONENT_FROM_PED, player.handle, weaponHash >> 0, componentHash >> 0);
    player.__weaponComponentData[weaponHash].clear();
});


mp.events.add("nukePlayerWeaponComponents", (player) => {
    if (!player.hasOwnProperty("__weaponComponentData")) return;


    for (let weapon in player.__weaponComponentData) {
        for (let component of player.__weaponComponentData[weapon]) mp.game.invoke(Natives.REMOVE_WEAPON_COMPONENT_FROM_PED, player.handle, weapon >> 0, component >> 0);
    }


    player.__weaponComponentData = {};
});


mp.events.add("entityStreamIn", (entity) => {
    if (entity.type === "player") {
        let data = entity.getVariable("currentWeaponComponents");


        if (data) {
            let [weaponHash, components] = data.split(".");
            weaponHash = parseInt(weaponHash, 36);
            let componentsArray = (components && components.length > 0) ? components.split('|').map(hash => parseInt(hash, 36)) : [];


            // don't touch this or you will have a bad time
            entity.giveWeapon(weaponHash, -1, true);
            for (let component of componentsArray) addComponentToPlayer(entity, weaponHash, component);
            mp.game.invoke(Natives.SET_CURRENT_PED_WEAPON, entity.handle, weaponHash >> 0, true);
        }
    }
});


mp.events.add("entityStreamOut", (entity) => {
    if (entity.type === "player" && entity.hasOwnProperty("__weaponComponentData")) entity.__weaponComponentData = {};
});


mp.events.addDataHandler("currentWeaponComponents", (entity, value) => {
    if (entity.type === "player" && entity.handle !== 0) {
        if (!entity.hasOwnProperty("__weaponComponentData")) entity.__weaponComponentData = {};


        let [weaponHash, components] = value.split(".");
        weaponHash = parseInt(weaponHash, 36);


        if (!entity.__weaponComponentData.hasOwnProperty(weaponHash)) entity.__weaponComponentData[weaponHash] = new Set();


        let currentComponents = entity.__weaponComponentData[weaponHash];
        let newComponents = (components && components.length > 0) ? components.split('|').map(hash => parseInt(hash, 36)) : [];


        for (let component of currentComponents) {
            if (!newComponents.includes(component)) removeComponentFromPlayer(entity, weaponHash, component);
        }


        for (let component of newComponents) addComponentToPlayer(entity, weaponHash, component);
        mp.game.invoke(Natives.SET_CURRENT_PED_WEAPON, entity.handle, weaponHash >> 0, true);


        entity.__weaponComponentData[weaponHash] = new Set(newComponents);
    }
});
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Server side :
Код:
// "Borrowed" from attachments resource, credits to ragempdev
function serializeComponentSet(dataSet) {
    return (Array.from(dataSet).map((hash) => (hash.toString(36)))).join("|");
}


/**
 * Adds the specified component to the player's specified weapon.
 * @param  {Number} weaponHash    The weapon's hash.
 * @param  {Number} componentHash The component's hash.
 * @throws {TypeError} If any of the arguments is not a number.
 */
mp.Player.prototype.giveWeaponComponent = function (weaponHash, componentHash) {
    if (!Number.isInteger(weaponHash) || !Number.isInteger(componentHash)) throw new TypeError("Non number argument(s) passed to giveWeaponComponent.");
    if (!this.__weaponComponents.hasOwnProperty(weaponHash)) this.__weaponComponents[weaponHash] = new Set();
    this.__weaponComponents[weaponHash].add(componentHash);


    if (this.weapon === weaponHash) {
        this.setVariable("currentWeaponComponents", weaponHash.toString(36) + "." + serializeComponentSet(this.__weaponComponents[weaponHash]));
    } else {
        mp.players.callInRange(this.position, mp.config["stream-distance"], "updatePlayerWeaponComponent", [this, weaponHash.toString(36), componentHash.toString(36), false]);
    }
};


/**
 * Returns whether the player's specified weapon has the specified component or not.
 * @param  {Number}  weaponHash    The weapon's hash.
 * @param  {Number}  componentHash The component's hash.
 * @returns {Boolean}
 * @throws {TypeError} If any of the arguments is not a number.
 */
mp.Player.prototype.hasWeaponComponent = function (weaponHash, componentHash) {
    if (!Number.isInteger(weaponHash) || !Number.isInteger(componentHash)) throw new TypeError("Non number argument(s) passed to hasWeaponComponent.");
    return this.__weaponComponents.hasOwnProperty(weaponHash) ? this.__weaponComponents[weaponHash].has(componentHash) : false;
};


/**
 * Returns the components of the player's specified weapon.
 * @param  {Number}  weaponHash    The weapon's hash.
 * @returns {Number[]} An array of component hashes.
 * @throws {TypeError} If weaponHash argument is not a number.
 */
mp.Player.prototype.getWeaponComponents = function (weaponHash) {
    if (!Number.isInteger(weaponHash)) throw new TypeError("Non number argument passed to getWeaponComponents.");
    return this.__weaponComponents.hasOwnProperty(weaponHash) ? Array.from(this.__weaponComponents[weaponHash]) : [];
};


/**
 * Removes the specified component from the player's specified weapon.
 * @param  {Number} weaponHash    The weapon's hash.
 * @param  {Number} componentHash The component's hash.
 * @throws {TypeError} If any of the arguments is not a number.
 */
mp.Player.prototype.removeWeaponComponent = function (weaponHash, componentHash) {
    if (!Number.isInteger(weaponHash) || !Number.isInteger(componentHash)) throw new TypeError("Non number argument(s) passed to removeWeaponComponent.");


    if (this.__weaponComponents.hasOwnProperty(weaponHash)) {
        this.__weaponComponents[weaponHash].delete(componentHash);


        if (this.weapon === weaponHash) {
            this.setVariable("currentWeaponComponents", weaponHash.toString(36) + "." + serializeComponentSet(this.__weaponComponents[weaponHash]));
        } else {
            mp.players.callInRange(this.position, mp.config["stream-distance"], "updatePlayerWeaponComponent", [this, weaponHash.toString(36), componentHash.toString(36), true]);
        }
    }
};


/**
 * Removes all components of the player's specified weapon.
 * @param  {Number}  weaponHash    The weapon's hash.
 * @throws {TypeError} If weaponHash argument is not a number.
 */
mp.Player.prototype.removeAllWeaponComponents = function (weaponHash) {
    if (!Number.isInteger(weaponHash)) throw new TypeError("Non number argument passed to removeAllWeaponComponents.");


    if (this.__weaponComponents.hasOwnProperty(weaponHash)) {
        if (this.weapon === weaponHash) {
            this.setVariable("currentWeaponComponents", weaponHash.toString(36) + ".");
        } else {
            mp.players.callInRange(this.position, mp.config["stream-distance"], "resetPlayerWeaponComponents", [this, weaponHash.toString(36)]);
        }


        delete this.__weaponComponents[weaponHash];
    }
};


/**
 * Resets all components of the player's all weapons.
 */
mp.Player.prototype.resetAllWeaponComponents = function () {
    if (this.__weaponComponents.hasOwnProperty(this.weapon)) this.setVariable("currentWeaponComponents", this.weapon.toString(36) + ".");
    mp.players.callInRange(this.position, mp.config["stream-distance"], "nukePlayerWeaponComponents", [this]);


    this.__weaponComponents = {};
};


// Events
mp.events.add("playerJoin", (player) => {
    player.__weaponComponents = {};
});


mp.events.add("playerWeaponChange", (player, oldWeapon, newWeapon) => {
    player.setVariable("currentWeaponComponents", newWeapon.toString(36) + "." + (player.__weaponComponents.hasOwnProperty(newWeapon) ? serializeComponentSet(player.__weaponComponents[newWeapon]) : ""));
});
 

Jerry (ChatGPT)

AI-powered language model
VIP
helper
17 Окт 2023
1,767
1,305
5
Проблема с отображением компонентов оружия между игроками на больших расстояниях может быть связана с потерей синхронизации. Попробуйте увеличить дальность вызова функции mp.players.callInRange или рассмотреть возможность использования других методов синхронизации данных между игроками на сервере.
 
Реакции: DeAAmoN

X-Clusiv

Модератор
Команда форума
high coder
4 Окт 2020
682
348
161
30
Евент entityStreamIn отрабатывает корректно?
Пробовали задержку ставить в нем(setTimeout)?
 
Реакции: Robert_Easter

DeAAmoN

Гуру
18 Мар 2022
509
169
114
mp.config stream-distance
У тебя все проходит в радиусе стрима, увеличь его
 

Robert_Easter

Активный участник
17 Июл 2024
103
13
28
mp.config stream-distance
У тебя все проходит в радиусе стрима, увеличь его
в conf.json файле в server-files папке увеличил stream-distance делал разные тесты увеличив stream-distance. Его дефаулт валю 500 там до 5000 поднял ничего не изменился. На самом деле когда например ты его на 10 поставишь(stream-distance) после 10 метров не будешь видеть других игроков. Это просто отоброжение другого игрока. Увеличив его ты просто будешь видеть других игроков вдали но компоненты не загружаются/не видно. только видно тогда когда вон рядом зашёл магазин купил итд... крч если компонент выдан рядом и когда игром прям впереди
 

Robert_Easter

Активный участник
17 Июл 2024
103
13
28
Спасибо вам еще раз за ответ; всё работает отлично. Если ставить 100мс задержку работать не будет. Надо 500мс поставить. Вот код клиент часть :
Код:
mp.events.add('entityStreamIn', (entity) => {
    if (entity.type === 'player') {
        setTimeout(() => {
            let data = entity.getVariable('currentWeaponComponents');
            if (data) {
                let [weaponHash, components] = data.split('.');
                weaponHash = parseInt(weaponHash, 36);
                let componentsArray = (components && components.length > 0) ? components.split('|').map(hash => parseInt(hash, 36)) : [];


                // don't touch this or you will have a bad time
                entity.giveWeapon(weaponHash, -1, true);
                for (let component of componentsArray) addComponentToPlayer(entity, weaponHash, component);
                mp.game.invoke(Natives.SET_CURRENT_PED_WEAPON, entity.handle, weaponHash >> 0, true);
            }
        }, 500);
    }
});

PS : Один маленький косяк еще есть) в машинах синхра не работает даже для у самого игрока у которого компоненты. Если есть идеи буду рад
Благодарю
 
Реакции: X-Clusiv

X-Clusiv

Модератор
Команда форума
high coder
4 Окт 2020
682
348
161
30
А можно визуализировать(скрин) как вообще это работает, чего вы хотите добиться. Глушители и прочие примочки синхронизировать?
По поводу машины есть предположение что оружие убирается автоматически при посадке в машину, возможно нужно вызывать функцию выдачи компонентов оружия когда персонаж садиться в авто или уже сел в авто.
 

Robert_Easter

Активный участник
17 Июл 2024
103
13
28
Да именно глушители и пропадают остальные почти все сохраняются. Вот как это выглядит : https://disk.yandex.com/d/N5jJB_Fcb8Npsw
 

X-Clusiv

Модератор
Команда форума
high coder
4 Окт 2020
682
348
161
30
а если прямо в машине ему выдать компонент глушитель?
 

X-Clusiv

Модератор
Команда форума
high coder
4 Окт 2020
682
348
161
30
Стоит изучить как в самой гта это работает, возможно там такое-же поведение, хотя очень сомневаюсь
 
Реакции: Robert_Easter

X-Clusiv

Модератор
Команда форума
high coder
4 Окт 2020
682
348
161
30
Можете еще посмотреть на код который был уже написан на эту тему.
Просто ищите в гитхабе через поиск.
Примерно вот ТАК
 

X-Clusiv

Модератор
Команда форума
high coder
4 Окт 2020
682
348
161
30
Ну и если у вас что-то годное получится, будем рады если вы напишите гайд на эту тему. Не припомню такого на нашем форуме.
Хорошего дня! И удачи в начинании.
 
Реакции: Robert_Easter

Robert_Easter

Активный участник
17 Июл 2024
103
13
28
На самом деле глушитель проподает за рулём даже на оригинальной ГТА по сети.
 
Реакции: X-Clusiv