Итак касаемо отрисовки предметов. Я наконец-то победил эту суку. Не знаю, насколько мой способ оптимальный и вообще стабильный. Но другого я пока не знаю
Что нужно чтобы отрисовать Texture2D на экране в
SCP:SL
Шаг 1 Ищем s_GUIManager. Текущий его оффсет
0x1f03188 Найти его изи через PDBшку от нужной версии
юнити
Шаг 2 Основа для этого шага взята из функции
GUIManager::DoGUIEvent
if (*(GUIManager **)(this + 8) == this) {
this[0x10] = (GUIManager)0x0;
goto LAB_180db5dc7;
}Как видно тут идёт проверка по оффсету 0x8 от
GUIManager. Что же у нас там? Если поискать использования
GUIManager, то можно найти
IMGUIModule::AddGUIScript Там можно увидеть, что при
передаче списка (List) экземпляров MonoBehaviour, они
“сцепливаются” как раз с инстансом GUIManager
Мне было лень именно полноценно список реализовывать, поэтому я в лоб скопировал декомпилированную хуйню
lVar1 = *(longlong *)guiManager;
*(longlong *)param_1 = lVar1;
*(GUIManager **)(param_1 + 8) = guiManager;
*(ListNode<> **)(lVar1 + 8) = param_1;
**(ListNode<> ***)(param_1 + 8) = param_1;Таким образом, если мы “прицепим” к GUIManager любой
MonoBehaviour, то методы, связанные с движковой отрисовкой
будут вызываться
Шаг 3 Идём опять в GUIManager::DoGUIEvent и смотрим туда
У нас тут разные методы типа
IMGUI::BeginWindows()
GUIObjectWrapper::DoGUI()
IMGUI::EndWindows()
и т.д.
Нас интересует GUIClipState::BeginOnGUI. Мы его хукаем.
Почему именно он? Дело в том что в него вторым параметром передаётся
InputEvent, который мы должны проверить на то, что он
RepaintEvent. Иначе получим артефакты (не из сталкера) при
отрисовке. Проверка делается так
void HookedBeginOnGUI(void *self, void *inputEvent) {
originalInputEvent(self, inputEvent);
// 7 - Repaint Event
// 8 - Какой-то другой
if(!inputEvent || ((uint8_t) ((uint8_t*) inputEvent)[0]) != 7) return;
// TODO : Ваша отрисовка
}
Шаг 4 Реализуем отрисовку. Я для этого брал
DrawClippedTexture, потому что там малое количество
очевидных параметров
struct Rect {
float x;
float y;
float width;
float height;
};
using DrawClippedTexture_t = void(
__cdecl*)(Rect*, InternalTexture*, float, float, float, float, float*);Стуктура Rect очевидна. Текстура - это текстура. Дальше
идут 4 float’а, которые нам не интересны Вероятно это
leftBorder,rightBorder и т.д. И последняя - это цвет в формате
[0.0:1.0]
Вот и всё. Вызывать его, понятное дело, нужно в хуке
BeginOnGui