• Из-за обновления 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) последний раз были обновлены:

Проблема object и notifyStreaming

qweqweqwe123123123

Участник портала
24 Июн 2025
70
10
18
Ребят, привет. Немного запутался, подскажите пожалуйста :)
Эта система инвентаря. Если точнее, игрок выбрасывает предмет на землю.

Логика:

1) СЕРВЕР. Я создаю объект на сервере

Код:
const newDropItem = mp.objects.new(
    mp.joaat(itemData.joaatName),
    new mp.Vector3(p.x, p.y, p.z - Z_OBJECT),
    {
      rotation: ZERO_VECTOR,
      alpha: 255,
      dimension: player.dimension,
    },
  );

2) Прямо объекту присваиваю variable

Код:
newDropItem.setVariable("inv:drop-item:collision", false);

3) Далее ВСЕМ игрокам на карте отправляю событие на клиент, передав туда IDшник созданного объекта на сервере

Код:
mp.players.forEach((user: PlayerMp) => {
    user.call(Inventory["SRV-CLI:enable-stream-in:drop-item"], [
      newDropItem.id,
    ]);
  });

4) КЛИЕНТ. Далее я на клиенте включаю object.notifyStreaming = true; (это нужно для того, чтобы созданный объект на серверной части мог отображаться в ивенте entityStreamIn на клиетнской части).

Код:
addServer(
  Inventory["SRV-CLI:enable-stream-in:drop-item"],
  (remoteObjId: number) => {
    const object = mp.objects.atRemoteId(remoteObjId);
    if (!object) return;
    object.notifyStreaming = true;
  },
);

5) Финал. Также на клиенте я ожидал , что ивент entityStreamIn вызовется и коллизия выключиться.

Код:
mp.events.add("entityStreamIn", (entity: EntityMp) => {
  if (!entity || entity.type !== "object" || entity.handle === 0) {
    return;
  }
  const value = entity.getVariable("inv:drop-item:collision");
  if (typeof value === "boolean") {
    entity.setCollision(value, value);
  }
});

Суть проблемы: когда только сервер запускаю и выбрасываю первый предмет на землю , то пункт 5 (ивент entityStreamIn) - не вызывается (хотя по идеи, если ты делаешь object.notifyStreaming = true, то вызваться должен , я это делаю в пункте 4). Потом еще раз что то выбрасываю из инвентаря - и все работает. Последующие выброшенные вещи дальше -тоже работают. Я также делал задержку до появления handle в пункте 4 (await isLoadedEntity handle), но это не помогло.

В целом логика правильная ? правильно ли я создаю объект, даю ему setVariable, передаю данные, через forEach оповещаю игроков, правильно ли делаю синхронизацию и тд тд ? Как вы это делаете, какие варианты у вас ?
Ну и главный вопрос, почему ивент entityStreamIn не вызывается (при первом выбрасывании) после object.notifyStreaming = true ?


UPDATE:
Вот наглядный пример. Выкинул первый предмет, entityStreamIn не вызвался (после object.notifyStreaming = true) и игрок одной ногой стоит на нем.
Выкинул еще, всё отработало прекрасно и коллизия выключилась.

1766947998373.png
 
Последнее редактирование:

Jerry (ChatGPT)

AI-powered language model
VIP
helper
17 Окт 2023
2,863
290
100
Привет! Логика в целом правильная, часто так делают. По первой проблеме с entityStreamIn при первом выбросе — возможно, событие не вызывается, потому что объект уже изначально стримится у клиента, и notifyStreaming ставишь слишком поздно. Попробуй ставить notifyStreaming сразу после создания объекта (ещё до передачи ID клиенту), чтобы клиент изначально получал этот флаг. Либо на клиенте перед выставлением notifyStreaming сделай проверку, есть ли объект в стриме уже, и если да — вручную вызови нужный код коллизии.
Ещё проверь, что dimension у объекта и игрока совпадает в момент стрима, иначе объект может не стримиться вовсе.
Если надо — можно также на клиенте кэшировать ID/состояния, и в entityStreamIn делать дополнительные проверки.
В общем, notifyStreaming = true должна ставиться до того, как клиент начинает получать этот объект, иначе событие может не сработать.
Проверь эти моменты, должно помочь.
 

Vermilion

Искусственный Интеллект
High developer
BackEnd developer
FrontEnd developer
29 Сен 2021
1,724
1,077
181
35
В ивенте entityStreamIn поставь не большой тайм аут, перед тем как проверяешь у сущности variable. Она может не прогрузится.
 

XDeveluxe

⚡️BackEnd Developer
Команда форума
Moderator
High developer
BackEnd developer
30 Авг 2021
3,225
1,936
216
29
В ивенте entityStreamIn поставь не большой тайм аут, перед тем как проверяешь у сущности variable. Она может не прогрузится.
Либо так, либо добавить mp.events.addDataHandler, в котором проверка по ключу и когда приходит ключ с новым значением переменной - менять коллизию.
 

qweqweqwe123123123

Участник портала
24 Июн 2025
70
10
18
В ивенте entityStreamIn поставь не большой тайм аут, перед тем как проверяешь у сущности variable. Она может не прогрузится.
Точно! Забыл блин об этом. Просто это странно :) у тебя есть уже object, есть у тебя handle у object, и все равно ты не можешь без setTimeout вызывать метод у этого object в entitytStreamIn... Типа все данные есть, handle есть, а методы не работают.
Было ло бы классно не хардкодить 200-350мс, а как то вычислять это динамически... Есть у кого варианты на что завязаться можно в условии ? Вдруг понадобиться в одном случае 50мс, а в другом 150мс или 250мс...


Либо так, либо добавить mp.events.addDataHandler, в котором проверка по ключу и когда приходит ключ с новым значением переменной - менять коллизию.
Ого, это интересно.На коленке накидал такой код, но что то не работает,коллизия не выключается
Код:
mp.events.addDataHandler(
  "inv:drop-item:collision",
  function (entity, value, oldValue) {
    if (entity.type === "object") {
      entity.setCollision(value, value);
      (entity as ObjectMp).notifyStreaming = true;
    }
  },
);

UPDATE: повесил await loadEntity(entity) в ивент addDataHandler и вроде завелось... сейчас еще пару тестов сделаю... 10 мин
UPDATE2: да, просто дожидаемся handle у объекта и все работает, который раз уже выручаешь... :)


И спасибо всем за ответы :)
 
Последнее редактирование:

qweqweqwe123123123

Участник портала
24 Июн 2025
70
10
18
Ну что ж... не все так просто... если ошибаюсь , поправьте меня. Но я сделал много тестов и куча часов работы...

Итоговый код на основании mp.events.addDataHandler

1) server side теперь выглядит так

Создаю объект на сервере
Код:
const newDropItem = mp.objects.new(
    mp.joaat(itemData.joaatName),
    new mp.Vector3(p.x, p.y, p.z - Z_OBJECT),
    {
      rotation: ZERO_VECTOR,
      alpha: 255,
      dimension: player.dimension,
    },
  );

2) И теперь только ОДИН такой вызов на клиент. Больше ничего. Ни какого forEach итд тд

Код:
newDropItem.setVariable("inv:drop-item:collision", false);

3) Клиент. Как мы знаем, при вызове метода .setVariable на сервере, будет вызван на клиент addDataHandler


Код:
mp.events.addDataHandler(
  "inv:drop-item:collision",
  async function (entity, value, oldValue) {
    if (!entity || entity.type !== "object") return;
    const object = entity as ObjectMp;
    object.notifyStreaming = true;
    const objectReady = await waitForEntity(object);
    if (!objectReady) return;
    object.setCollision(value, value);
  },
);

А тут более подробно надо остановиться. Вот эту строчку -> object.notifyStreaming = true -> Мы вызываем ДО const objectReady = await waitForEntity(object),
*(1) - если мы напишем строчку (object.notifyStreaming = true) ДО (как сейчас в коде): то СРАЗУ вызовется mp.events.add("entityStreamIn") , полностью выполнится ивент entityStreamIn и только ПОСЛЕ выполнения ивента entitytStreamIn ПРОДЛОЖИТ выполнятся дальше ивент addDataHandler.

*(2) - если мы напишем строчку (object.notifyStreaming = true) ПОСЛЕ await waitForEntity(object), то у игроков, которые НЕ в зоне стрима объекта просто не отработает эта строчка (object.notifyStreaming = true) (ну тупо не создаться entity, так как объект не в зоне их стрима) и у тем самым игроков, которые уже после войдут в зону стрима этого объекта, у них не отработает ивент entityStreamIn и синхронизации не будет (в нашем случае отключение коллизии).

Поэтому остается только 1 вариант.
Итоговая логика такая. В ивента addDataHandler вызвать сразу object.notifyStreaming = true , тут же вызывается ивент entityStreamIn, он отрабатывает , и потом продолжает работу ивент addDataHandler. По итогу происходит дублирование логики.

вот так выглядит ивент entityStreamIn

Код:
mp.events.add("entityStreamIn", (entity: EntityMp) => {
  if (!entity || entity.type !== "object" || entity.handle === 0) {
    return;
  }
  const value = entity.getVariable("inv:drop-item:collision");
  if (typeof value === "boolean") {
    entity.setCollision(value, value);
  }
});

Суть проблемы: дублирование логики. Для игроков, которые в зоне стрима, у них логика дважды отработает (в ивенте entityStreamIn и в addDataHandler. Возможно , логика в ивенте entityStreamIn не сработает, потому что там нет ожидания (await) сущности ХОТЬ И ЕСТЬ ТАМ ПРОВЕРКА НА handle, мы знаем этот баг, что ему плевать , даже если есть handle , методы на сущность могут не работать (в нашем случае entity.setCollision(value,value)

В идеале убрать заход кода в ивент entityStreamIn для игроков, которые в зоне в стрима. Есть варианты ? Я понимаю, что наверное, это не сильно влияет на производительность , но все же. Тоже мыслил по этому поводу, но нету значений, на которые можно завязаться, создать new Map() какой нибудь на клиенте...

ps. ну или использовать внутри entityStreamIn -> использовать setTImeout , только вот какое значение хардкодить ? 250мс? 300 мс? а если выполнение по факту будет 20мс? 50мс? а мы хардкоднули 300 мс ? никто не знает это время... этот вариант меня не сильно радует
 
Последнее редактирование:

Vermilion

Искусственный Интеллект
High developer
BackEnd developer
FrontEnd developer
29 Сен 2021
1,724
1,077
181
35
Я бы все таки оставил entityStreamIn. Минус addDataHandler в том, что объект должен находиться в зоне стрима игрока в тот момент когда ты меняешь variable объекта.
Ведь может быть такой случай, что ты создал предмет, а игрока на сервере еще нету, тогда addDataHandler теряет актуальность.
 
Реакции: qweqweqwe123123123

XDeveluxe

⚡️BackEnd Developer
Команда форума
Moderator
High developer
BackEnd developer
30 Авг 2021
3,225
1,936
216
29
Я бы все таки оставил entityStreamIn. Минус addDataHandler в том, что объект должен находиться в зоне стрима игрока в тот момент когда ты меняешь variable объекта.
Ведь может быть такой случай, что ты создал предмет, а игрока на сервере еще нету, тогда addDataHandler теряет актуальность.
Они не заменяют друг-друга, а дополняют.
Так же как и entityStreamIn не сработает, если коллизия изменится в моменте, когда объект уже прорисован.
Эти два ивента для такой системы лучше держать рядом и позволить им дополнять друг-друга.
 

qweqweqwe123123123

Участник портала
24 Июн 2025
70
10
18
Я бы все таки оставил entityStreamIn. Минус addDataHandler в том, что объект должен находиться в зоне стрима игрока в тот момент когда ты меняешь variable объекта.
Ведь может быть такой случай, что ты создал предмет, а игрока на сервере еще нету, тогда addDataHandler теряет актуальность.
Я немного другое имел ввиду моего последнего большого ответа.

Как ниже ответил XDeveluxe -> addDataHandler и entityStreamIn работают вместе.

Давай еще раз. Нам надо сделать синхронизацию : 1) для тех, кто уже в стриме 2) кто зайдет в стрим 3) и вот еще вариант появился. Это когда игрока вообще нету на сервере, и игрок он подключается.

Теперь объясню, почему нельзя что-то одно убрать из этих двух (addDataHandler / entityStreamIn)

Вариант №1 (кастомное событие через forEach ) (без addDataHandle)
Тогда серверная сторона будет такой:
Мы сообщаем игрокам на всей карте, что появился новый объект и ему(объекту) надо установить значение на клиенте (object.notifyStreaming = true, чтобы он ловился в entitytStreamIn + await waitForEntity и getVariable collision)
Код:
newDropItem.setVariable("inv:drop-item:collision", false);

mp.players.forEach((user: PlayerMp) => {
    user.call(Inventory["SRV-CLI:enable-stream-in:drop-item"], [
      newDropItem.id,
    ]);
  });

Вариант №2 (используем addDataHandle)
Делаем все 1 в 1 , просто АПИ удобнее у addDataHandler, не более, логика одинаковая. Ты на клиенте сразу получаешься сущность и из getVariable не достаешь параметр (удобнее АПИ).
вот так код выглядит для этого варианта, чисто setVariable
Код:
newDropItem.setVariable("inv:drop-item:collision", false);

Эти два варианта одинаковые, для второго варианта чуть меньше кода

Я в своем прошлом сообщение все таки хотел узнать, решил ли кто проблему, чтобы для игроков, кто в зоне стрима entity(объект в нашем случае) не заходило в ивент entityStreamIn , но в такие тонкости,наверное, только я залез, либо не признаются :)):)

XDeveluxe, поправь меня пожалуйста если ошибаюсь :):)

Ну и сейчас буду писать функцию, которая будет вызываться для игроков, которые только только зашли на сервер, а предмет уже выбросили . На клиенте через mp.objects.forEach буду пробегаться по объектам и присваивать значение object.notifyStreaming = true, чтобы для новых игроков выключилась коллизия уже выброшенных предметов
 
Последнее редактирование:

qweqweqwe123123123

Участник портала
24 Июн 2025
70
10
18
Похоже никак не уйти от setTimeout :)
Подскажите кто шарит) Пишу клиентскую анимацию, и когда игрок заходит в стрим другого игрока и у этого игрока должна анимация отработать, то ничего не срабатывает. Помогает добавить setTimeout... Но так себе решение. Есть другие варианты ? ps. в Ивенте entityStreamIn нет смысла дожидаться handle, он и так там есть!

Код:
mp.events.add("entityStreamIn", (entity: EntityMp) => {
  if (!entity || entity.type !== "player" || entity.handle === 0) {
    return;
  }


  const player = entity as PlayerMp;


  if (player.getVariable("player:is-cuff")) {
    syncHandcuffs(player);
  }
});




Код:
async function syncHandcuffs(player: PlayerMp) {
  // setTimeout(() => {  if I add this, it will work
  loadAnimationDictionary("mp_arresting").then(() => {
    player.taskPlayAnim(
      "mp_arresting",
      "idle",
      1,
      -8,
      -1,
      49,
      0.0,
      false,
      false,
      false,
    );
  });
  // }, 300); if I add this, it will work.
}
 

PercyBerkeley

Новый участник
16 Ноя 2024
210
4
62
When you set object.notifyStreaming = true, you are enabling streaming notifications, but if the object is already in the player's streaming range, the entityStreamIn event will not fire because technically the object already "entered" the stream before you enabled notifications.
 

PercyBerkeley

Новый участник
16 Ноя 2024
210
4
62
One more thing, you're using 'mp.players.forEach', but I recommend using 'mp.players.forEachInRange' so you only notify nearby players. Then, with entityStreaming, the object is loaded for each person who enters the range.
 

qweqweqwe123123123

Участник портала
24 Июн 2025
70
10
18
Thank you so much for the feedback! Unfortunately, I didn't see the notification about your response for some reason. I've investigated these situations, let me explain now.

When you set object.notifyStreaming = true, you are enabling streaming notifications, but if the object is already in the player's streaming range, the entityStreamIn event will not fire because technically the object already "entered" the stream before you enabled notifications.
When I set object.notifyStreaming = true, this line immediately triggers entityStreamIn. In my case, it works like this: a player drops an item from inventory, I create an object on the server side, trigger an event to the client, on the client I assign the value object.notifyStreaming = true, and the entityStreamIn event is called immediately (for players who are in the stream area). So the conclusion is: I don't agree with your opinion. The entityStreamIn event is triggered immediately (for players who are in the stream area), or maybe I misunderstood something

Always check the initial state when you enable notifyStreaming, don't rely solely on the event.
Why check the value? If I assign true to the object.notifyStreaming field again, nothing will happen, there won't be any duplication.

One more thing, you're using 'mp.players.forEach', but I recommend using 'mp.players.forEachInRange' so you only notify nearby players. Then, with entityStreaming, the object is loaded for each person who enters the range.
I need to set object.notifyStreaming = true for every player on the server. That means I should use forEach instead of forEachInRange. But that's how it was before. Now I'm doing it differently: I call setVariable on the server, and on the client I catch this in addDataHandler and set object.notifyStreaming = true.
 
Последнее редактирование:

qweqweqwe123123123

Участник портала
24 Июн 2025
70
10
18
Похоже никак не уйти от setTimeout :)
Подскажите кто шарит) Пишу клиентскую анимацию, и когда игрок заходит в стрим другого игрока и у этого игрока должна анимация отработать, то ничего не срабатывает. Помогает добавить setTimeout... Но так себе решение. Есть другие варианты ? ps. в Ивенте entityStreamIn нет смысла дожидаться handle, он и так там есть!

Код:
mp.events.add("entityStreamIn", (entity: EntityMp) => {
  if (!entity || entity.type !== "player" || entity.handle === 0) {
    return;
  }


  const player = entity as PlayerMp;


  if (player.getVariable("player:is-cuff")) {
    syncHandcuffs(player);
  }
});




Код:
async function syncHandcuffs(player: PlayerMp) {
  // setTimeout(() => {  if I add this, it will work
  loadAnimationDictionary("mp_arresting").then(() => {
    player.taskPlayAnim(
      "mp_arresting",
      "idle",
      1,
      -8,
      -1,
      49,
      0.0,
      false,
      false,
      false,
    );
  });
  // }, 300); if I add this, it will work.
}
Ребят, это другая проблема, я решил не создавать отдельную тему на форуме, они почти похожи...

Есть вариант, как это исправить без setTimeout ? (не загружается анимация у player(не PED), когда ты входишь в стрим игрока).
 

Inoi

/dev/null
Команда форума
Moderator
VIP
15 Окт 2020
4,784
2,386
208
36
Ребят, это другая проблема, я решил не создавать отдельную тему на форуме, они почти похожи...

Есть вариант, как это исправить без setTimeout ? (не загружается анимация у player(не PED), когда ты входишь в стрим игрока).

не же, тебе всегда надо подождать пока и она и пед загрузятся
можно авейт mp.game.waitAsync(0) делать, while !hasAnimDictLoaded

но подождать надо
 
Реакции: qweqweqwe123123123

qweqweqwe123123123

Участник портала
24 Июн 2025
70
10
18
не же, тебе всегда надо подождать пока она загрузится
можно авейт mp.game.waitAsync(0) делать, while !hasAnimDictLoaded

но подождать надо
Не совсем так... сейчас объясню

Код:
export const loadAnimationDictionary = async (
  dict: string,
): Promise<boolean> => {
  if (mp.game.streaming.hasAnimDictLoaded(dict)) {
    return true;
  }
  mp.game.streaming.requestAnimDict(dict);
  for (let i = 0; !mp.game.streaming.hasAnimDictLoaded(dict) && i < 350; i++) {
    await mp.game.waitAsync(10);
  }
  return mp.game.streaming.hasAnimDictLoaded(dict);
};

1) я дожидаюсь загрузки анимации в любом случае (есть или нет setTimeout)
2) В методе loadAnimationDictionary есть ожидание и есть загрузка
3) setTimeout оборачивает метод loadAnimationDictionary
4) есть решение - добавить setTimeout, но есть другие ? это хочу узнать
 
Реакции: Harland David Sanders

PercyBerkeley

Новый участник
16 Ноя 2024
210
4
62

Inoi

/dev/null
Команда форума
Moderator
VIP
15 Окт 2020
4,784
2,386
208
36
Не совсем так... сейчас объясню

Код:
export const loadAnimationDictionary = async (
  dict: string,
): Promise<boolean> => {
  if (mp.game.streaming.hasAnimDictLoaded(dict)) {
    return true;
  }
  mp.game.streaming.requestAnimDict(dict);
  for (let i = 0; !mp.game.streaming.hasAnimDictLoaded(dict) && i < 350; i++) {
    await mp.game.waitAsync(10);
  }
  return mp.game.streaming.hasAnimDictLoaded(dict);
};

1) я дожидаюсь загрузки анимации в любом случае (есть или нет setTimeout)
2) В методе loadAnimationDictionary есть ожидание и есть загрузка
3) setTimeout оборачивает метод loadAnimationDictionary
4) есть решение - добавить setTimeout, но есть другие ? это хочу узнать
а, это видимо потому что педа нет
ну подгруженного с handle уже валидным

можно в тике проверять, await mp.game.waitAsync(0); вставить, наверное
 
Реакции: qweqweqwe123123123

qweqweqwe123123123

Участник портала
24 Июн 2025
70
10
18
But if someone in Los Santos drops an item, why should someone in Paleto get a notification? The only reason to use forEach would be if you needed players 10km away to know about the item BEFORE it enters their range, but that doesn't make sense for a ground item system. It only works with addDataHandler.
I need to assign the value object.notifyStreaming = true on the client side for an item created on the server. For all players, across the entire map. This is necessary so that the item is tracked. This is needed so that when a player enters the zone of this object, the properties for this object are applied. This is required for the item to appear in the entityStreamIn event. Therefore, I either use forEach across the entire map, or use addDataHandler, which also works across the entire map.