• Из-за обновления GTA 5 (был добавлен новый патч) может временно не работать вход в RAGE Multiplayer.

    Ошибка: Ваша версия Grand Theft Auto V не поддерживается RAGE Multiplayer.
    ERROR: Your game version is not supported by RAGE Multiplayer.

    Данная ошибка говорит о том, что GTA V обновилась до новой версии (GTA Online тоже). Вам необходимо обновить саму игру в главном меню вашего приложения (Steam / Epic Games / Rockstar Games).
    Если после этого RAGE:MP все равно не работает - вам нужно дождаться выхода патча для самого мультиплеера (обычно это занимает от нескольких часов до нескольких дней).

    Новости и апдейты Rockstar Games - https://www.rockstargames.com/newswire/
    Статус всех служб для Rockstar Games Launcher и поддерживаемых игр: https://support.rockstargames.com/ru/servicestatus


    Grand Theft Auto 5 (+ GTA Online) последний раз были обновлены:

Вопрос Реализация редактора персонажа

podobaet

Новый участник
8 Апр 2025
14
0
1
На рейдж вики есть несколько статей по работе с внешностью персонажа:
https://wiki.rage.mp/wiki/Player::setHeadBlendData (https://wiki.rage.mp/wiki/Player::updateHeadBlendData ?)
(вынес не все, но самое интересующие меня)

Что из этого всего должно подходить под реализацию редактора персонажа? Или же оно все взаимодействует между собой?
Как должен быть алгоритм действий чтоб реализовать редактор персонажа?
 

Jerry (ChatGPT)

AI-powered language model
VIP
helper
17 Окт 2023
2,395
237
100
Для реализации редактора персонажа в игре на базе Rage MP вы можете использовать методы Player::setCustomization, Player::setFaceFeature, Player::setHeadBlendData, Player::updateHeadBlendData и Player::setHeadBlend. Эти методы взаимодействуют между собой для изменения внешности персонажа.

Алгоритм действий для реализации редактора персонажа может быть следующим:
1. Создание интерфейса редактора с элементами управления для изменения внешности персонажа (например, слайдеры для изменения параметров).
2. При выборе определенных настроек в интерфейсе, вызывать соответствующие методы непосредственно на стороне клиента или через события синхронизации с сервером.
3. При каждом изменении параметров внешности персонажа вызывать соответствующие методы для обновления модели персонажа.

Таким образом, комбинируя эти методы и настраивая их в соответствии с выбранными настройками в интерфейсе, можно реализовать функционал редактора персонажа в игре на базе Rage MP.
 

enotit

Высший разум
High developer
BackEnd developer
13 Ноя 2020
1,627
518
187
22
На рейдж вики есть несколько статей по работе с внешностью персонажа:
https://wiki.rage.mp/wiki/Player::setHeadBlendData (https://wiki.rage.mp/wiki/Player::updateHeadBlendData ?)
(вынес не все, но самое интересующие меня)

Что из этого всего должно подходить под реализацию редактора персонажа? Или же оно все взаимодействует между собой?
Как должен быть алгоритм действий чтоб реализовать редактор персонажа?
Реализация есть на каждом сервере, в каждой сборке. Поищи, методы ты правильные нашел.

если чисто редактор, то берешь методы, читаешь описание и делаешь интерфейс. Пользователь выбрал (как ты хочешь, можешь через тянучки, можешь через кнопочки, можешь на лице тянуть что-нибудь и трейсом проверять какую часть тела выбрал игрок), с cef’а на клиент, клиент изменяет нужную часть тела, если все ок, то отправляем на сервер - сохраняем параметры и теперь при каждом заходе подставляем значения.
Если абстрактно, то вот.
 

Vermilion

Высший разум
High developer
BackEnd developer
FrontEnd developer
29 Сен 2021
1,354
806
181
34
Для кастомизации персонажа есть серверные и клиентские методы. По функционалу они идентичны (только разные названия), но синхронизированы между игроками только серверные.

Пишешь фронт с какой то библиотекой управления состояния, типа Zustand, Redux, MobX, в общем по своему вкусу и подключаешь это дело к клиентским функциям.
После завершения редактирования, отправляешь весь массив данных на сервер (и соответственно в базу данных) и применяешь к персонажу.
Это так, если в двух словах.
 

podobaet

Новый участник
8 Апр 2025
14
0
1
в жс файле верстки было прикинуто следующее:

1. есть структура данных персонажа

JavaScript:
const DEFAULT_CHARACTER = {

    name: '',

    gender: true,

    headBlend: {

        shapeFirst: 0, shapeSecond: 0, shapeThird: 0,

        skinFirst: 0, skinSecond: 0, skinThird: 0,

        shapeMix: 0.0, skinMix: 0.0, thirdMix: 0.0,

    },

    eyeColor: 0,

    hairColor: 0,

    hairHighlightColor: 0,

    faceFeatures: Array(20).fill(0.0),

    headOverlays: Array(13).fill({ id: 255, opacity: 0.0, colorType: 0, color: 0, secondColor: 0 }),

    decorations: [],

    props: Array(10).fill({ drawable: -1, texture: 0 }),

    clothes: Array(11).fill({ drawable: 0, texture: 0 }),

};

2. функция, срабатывающая при обновлении значения слайдера. В console.log все выбивается корректно на каждый слайдер

JavaScript:
function updateRangeValue() {

        let value = +range.value;



        if (isDecimalSlider) {

            value = Math.min(100, Math.max(-100, value));

            range.value = value;

        }



        if (isParentSlider) {

            const parentIndex = value - 1;

            valueLabel.innerText = value;



            if (parentNameLabel) {

                if (parentIndex >= 0 && parentIndex < PARENT_NAMES.length) {

                    parentNameLabel.innerText = PARENT_NAMES[parentIndex];

                } else {

                    parentNameLabel.innerText = PARENT_NAMES[PARENT_NAMES.length - 1];

                }

            }

        } else {

            valueLabel.innerText = value;

        }



        const min = parseFloat(range.min);

        const max = parseFloat(range.max);

        const percent = (value - min) / (max - min);

        const thumbWidth = 32;

        valueLabel.style.left = `calc(${percent * 100}% - ${thumbWidth * percent + 5}px)`;



        let outputValue = value;

        if (isDecimalSlider) {

            outputValue = +(value / 100).toFixed(2);

        }



        if (SLIDER_MAPPING[sliderId]) {

            // РОДИТЕЛИ

            STATE.character.headBlend[SLIDER_MAPPING[sliderId]] = outputValue;



        } else if (FACE_FEATURES_MAPPING[sliderId] !== undefined) {

            // ЧЕРЫТ ЛИЦА ТИПА БРОВИ НОС

            const index = FACE_FEATURES_MAPPING[sliderId];

            STATE.character.faceFeatures[index] = outputValue;



        } else if (HEAD_OVERLAY_MAPPING[sliderId] !== undefined) {

            // МОРЩИНЫ ДЕФФЕКТЫ И ТД

            const index = HEAD_OVERLAY_MAPPING[sliderId];

            const overlay = STATE.character.headOverlays[index];

            STATE.character.headOverlays[index] = {

                ...overlay,

                id: outputValue,

                opacity: overlay.opacity || 1.0,

            };



        } else if (HEAD_OVERLAY_OPACITY_MAPPING[sliderId] !== undefined) {

            // ПРОЗАРЧНОСТЬ ДЕФФЕКТОВ

            const index = HEAD_OVERLAY_OPACITY_MAPPING[sliderId];

            const overlay = STATE.character.headOverlays[index];

            const opacityValue = +(value / 100).toFixed(2);

            STATE.character.headOverlays[index] = {

                ...overlay,

                opacity: opacityValue,

            };



        } else if (HAIR_STYLE_MAPPING[sliderId] !== undefined) {

            // ВОЛОСЫ, ИДУТ В ОБХЕКТЕ В PROPS

            const propIndex = HAIR_STYLE_MAPPING[sliderId];

            STATE.character.props[propIndex] = {

                drawable: outputValue,

                texture: 0

            };



        } else if (HAIR_COLOR_MAPPING[sliderId]) {

            // ЦВЕТ ВОЛОСНИ

            const colorKey = HAIR_COLOR_MAPPING[sliderId];

            if (colorKey === 'hairColor') {

                STATE.character.hairColor = outputValue;

            } else {

                if (!STATE.character.customHairColors) {

                    STATE.character.customHairColors = {};

                }

                STATE.character.customHairColors[colorKey] = outputValue;

            }

        } else if (sliderId === 'eyeColor') {



            // ЦВЕТ ГЛАЗ

            STATE.character.eyeColor = outputValue;



        } else {

            // ЕСЛИ СО СЛАЙДЕРОМ ХУЙНЯ КАКАЯ-ТО

            console.warn(`НЕИЗВЕСТНЫЙ СЛАЙДЕР: ${sliderId}`);

        }



        // ----

        // ----

        // ----

        // TODO: mp.trigger('client:updateCharacterFeature', sliderId, outputValue);



        console.log(`СЛАЙДЕР: ${sliderId}, ЗНАЧЕНИЕ: ${outputValue}`);

        console.log(STATE.character);

    }

как по итогу вытянуть значения из слайдеров в верстке и подставлять их в метод https://wiki.rage.mp/wiki/Player::setHeadBlendData, например, чтобы это все менялось в реальном времени? (если возможно, то через клиентский ивент, как это в TODO предполагается)
 
Последнее редактирование:

podobaet

Новый участник
8 Апр 2025
14
0
1
здесь же задам еще вопрос:
можно ли будет потом получить значения с клиентского метода на сервер и записать в БД, чтоб при выборе персонажа ставилась корректная внешность персонажа
 

Inoi

/dev/null
Команда форума
Moderator
VIP
15 Окт 2020
4,038
1,999
208
35
так у тебя же в коде всё почти вроде есть, даже тудушка написана
ты обновляешь свой STATE.character.headBlend например
кладёшь его в какой то const hb например и дёргаешь клиентский метод

JavaScript:
mp.trigger(
  'client:updateHeadBlendData',
  hb.shapeFirst, hb.shapeSecond, hb.shapeThird,
  hb.skinFirst,  hb.skinSecond,  hb.skinThird,
  hb.shapeMix,   hb.skinMix,    hb.thirdMix
);

на клиенте готовишь его с поджаристой корочкой

JavaScript:
mp.events.add('client:updateHeadBlendData',
  (shapeFirst, shapeSecond, shapeThird,
   skinFirst, skinSecond, skinThird,
   shapeMix, skinMix, thirdMix) => {

    const player = mp.players.local;
    if (!player || !player.setHeadBlendData) return;

    player.setHeadBlendData(
      shapeFirst, shapeSecond, shapeThird,
      skinFirst,  skinSecond,  skinThird,
      shapeMix,   skinMix,     thirdMix
    );
  }
);

че то типа того, наверное?

и да конечно можно отправить на сервак, как @Vermilion писал
После завершения редактирования, отправляешь весь массив данных на сервер (и соответственно в базу данных) и применяешь к персонажу.

вызови какой нибудь
JavaScript:
mp.events.callRemote('server:saveCustomization', JSON.stringify(STATE.character))

на серваке всё так же - подготовь евент, в нём делай там че тебе надо, хочешь записывай в стейт какой-то персонажа, сохраняй в бд при выходе
ну очень тебе хочется - ебаш сразу

ну только STATE.character (капитан очевидность) тоже надо будет с цефки в клиент пушнуть
JavaScript:
mp.trigger('client:updateFullCharacter', JSON.stringify(STATE.character));

не хочешь больших жсонов - передавай только изменившиеся части ну как с headBlend

лучше не дёргать евент каждым движением ползунка в юайке наверное, ну на каждое событие инпут
а ну типа там зедебаунсить на 200мс или ограничить раз в 100 мс например
 
Реакции: podobaet и enotit

podobaet

Новый участник
8 Апр 2025
14
0
1
Возвращаясь к теме редактора: есть ли какая-то анимация, при которой пед не будет дергаться, а смотреть строго прямо?
 

XDeveluxe

⚡️BackEnd Developer
Команда форума
Moderator
High developer
BackEnd developer
30 Авг 2021
2,914
1,668
211
28
Возвращаясь к теме редактора: есть ли какая-то анимация, при которой пед не будет дергаться, а смотреть строго прямо?
Вариантов несколько:
1) Анимация, но вероятно тебе придётся подбирать её самостоятельно. Поищи что-то с ключевым словом "guard".
2) Создать прозрачный объект за камерой и заставить персонажа смотреть на него с помощью