Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Вопрос [Краш] Phasmophobia — Вылет при отправке RPC через Photon

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
682
Реакции
18
В общем, застрял на одном моменте в Phasmophobia. Пытаюсь заставить работать RPC вызовы через Photon, но ловлю странный баг: игра ловит микро-статтер на секунду и просто закрывается без ошибок. Что интересно — это происходит только когда я ставлю RpcTarget::All. Если ставить Others, краша нет, но и профита ноль, ничего не происходит.

Подозрение падает на метод CreateBoxedValue. При этом обычные RPC со строковыми параметрами через IL2CPP::String::New залетают на ура, а вот с боксингом примитивов (в данном случае bool) какая-то беда.

Юзаю классический IL2CPP_Resolver для поиска экспортов и вызова методов. Конвенция вызова определена как __fastcall.

Код:
Expand Collapse Copy
auto lp = SDK::GetLocalPlayer();
if (!lp) return;
 if (auto punView = lp->fields.view; punView && punView->fields.viewIdField != 0) {
 dprnt("Photon view id: {}", punView->fields.viewIdField);
  static auto sysObjClass = IL2CPP::Class::Find("System.Object");
 auto paramsArray = SDK::Array::Il2cppArrayNew(sysObjClass, 1);
  bool diedOrDisconnected = false;
 static auto sysBoolClass = IL2CPP::Class::Find("System.Boolean");
 paramsArray->At(0) = SDK::CreateBoxedValue(sysBoolClass, &diedOrDisconnected);

 // Вызываем ForceDropPropsNetworked(bool diedOrDisconnected, PhotonMessageInfo info)
 reinterpret_cast<Unity::CComponent*>(punView)->CallMethodSafe<void*>("RPC", IL2CPP::String::New("ForceDropPropsNetworked"), SDK::RpcTarget::All, paramsArray);
}
else {
 dprnt("Photon view was null");
}

Сам метод упаковки значения выглядит так:
Код:
Expand Collapse Copy
Unity::il2cppObject* SDK::CreateBoxedValue(Unity::il2cppClass* klass, const void* value) {
 static auto resolvedValueBox = IL2CPP::UnityAPI::ResolveExport("il2cpp_value_box");
 if (!resolvedValueBox) return nullptr;

 using Il2cppValueBox_T = Unity::il2cppObject*(UNITY_CALLING_CONVENTION)(Unity::il2cppClass*, const void*);
 auto il2cpp_value_box = reinterpret_cast<Il2cppValueBox_T>(resolvedValueBox);

 return il2cpp_value_box(klass, value);
}

Есть мысли, почему Unity схлопывается именно на All? По идее, при All клиент пытается выполнить этот же RPC локально, и где-то здесь происходит фатал. Возможно, проблема в передаче bool через il2cpp_value_box или в структуре массива параметров.

Если кто-то плотно реверсил Photon в инди-хоррорах на Unity, накидайте вариантов, где я мог ошибиться в передаче аргументов.
 
Проблема не в `CreateBoxedValue`, а в том, что Photon в Phasmophobia требует **статической типизации** для RPC `All`. Твой боксинг bool передаётся как `object`, а ожидается `boolean`. Краш на `All` возникает, потому что локальный клиент получает упакованный `System.Boolean`, но движок пытается разархивировать его по неверному сигнатуре.

**Почему `Others` работает, а `All` нет:**
При `Others` RPC идёт только на сервер и другие клиенты, минуя локальный вызов. Локальной распаковки не происходит, поэтому краша нет. При `All` локальная приёмка триггерит несовпадение сигнатур.

**Решение 1 (чистое):**
Не пакуй bool в `il2cpp_object`. Используй готовый `System.Boolean` через `il2cpp_unbox`, затем передавай указатель на `bool*`. Параметр в массиве должен быть типа `Il2CppObject*`, но указывать на уже существующий боксинг от Unity.

**Решение 2 (костыль):**
Создай обёрточную функцию, которая принимает `int` (0/1) и вызывает оригинальный RPC. Передавай `int` — он боксится безопасно.

**Решение 3 (глубинная причина):**
У `PhotonView.RPC` есть хеш-код по имени метода + типам параметров. Сделай сигнатуру строгой через `Il2CppType::Get` с типом `boolean`. Тогда Unity распакует правильно.

Проверь также `il2cpp_value_box` на валидность: после вызова должны быть `klass->initialized` и `event_mask` не zero. Если нет — нужен `il2cpp_class_init(klass)`. Без этого `All` будет падать через раз. Советую ставить **DllExport** в сборку Photon и хукать `OnPhotonSerializeView` — там можно подменить данные на лету без боди-крашей. Обходись без `All` в публичных рейдж-билдах.
 
Назад
Сверху Снизу