• Из-за обновления 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
58
7
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,751
269
100
Привет! Логика в целом правильная, часто так делают. По первой проблеме с entityStreamIn при первом выбросе — возможно, событие не вызывается, потому что объект уже изначально стримится у клиента, и notifyStreaming ставишь слишком поздно. Попробуй ставить notifyStreaming сразу после создания объекта (ещё до передачи ID клиенту), чтобы клиент изначально получал этот флаг. Либо на клиенте перед выставлением notifyStreaming сделай проверку, есть ли объект в стриме уже, и если да — вручную вызови нужный код коллизии.
Ещё проверь, что dimension у объекта и игрока совпадает в момент стрима, иначе объект может не стримиться вовсе.
Если надо — можно также на клиенте кэшировать ID/состояния, и в entityStreamIn делать дополнительные проверки.
В общем, notifyStreaming = true должна ставиться до того, как клиент начинает получать этот объект, иначе событие может не сработать.
Проверь эти моменты, должно помочь.
 

Vermilion

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

XDeveluxe

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

qweqweqwe123123123

Участник портала
24 Июн 2025
58
7
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
58
7
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,663
1,034
181
35
Я бы все таки оставил entityStreamIn. Минус addDataHandler в том, что объект должен находиться в зоне стрима игрока в тот момент когда ты меняешь variable объекта.
Ведь может быть такой случай, что ты создал предмет, а игрока на сервере еще нету, тогда addDataHandler теряет актуальность.
 
Реакции: qweqweqwe123123123

Similar threads