Wake of Gods Forum | Форум Во Имя Богов

Full Version: Вопросы по моддингу
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
(20.04.2020 18:10)XEPOMAHT Wrote: [ -> ]Плохо тем, что нужен хотя бы 1 человек, который будет заниматься систематизацией, обновлением и добавлением новых erm-функций. Который послезавтра не положит болт с резьбой на это дело.
Git с доступом для нескольких проверенных модеров. + Тема с предложением/обсуждением нововведений или корректировок.
Quote:Прямая адресация - зло. Для совместимости с данными, которые могут быть перенесены другими моддерами, лучше считывать адреса с железобетонных функций, которые их используют.
В ERA Plus нужно просто вызывать RedirectMemoryBlock, как я делаю в нескольких местах Typhon 2.72. В результате !!UN:C будет работать с адресами перенесённых структур. Там таблица поиска в памяти вида [старый адрес, новый адрес, размер старой структуры].

Во всём остальном Zur13 прав. Библиотеки решают массу проблем, обеспечивают совместимость через сокрытие деталей реализации и разгружают «базу». Например, в языке СИ почти всё, что можно, вынесено на уровень библиотек, а не средств языка.
(21.04.2020 06:02)Berserker Wrote: [ -> ]В ERA Plus нужно просто вызывать RedirectMemoryBlock, как я делаю в нескольких местах Typhon 2.72. В результате !!UN:C будет работать с адресами перенесённых структур. Там таблица поиска в памяти вида [старый адрес, новый адрес, размер старой структуры].

Пока что страшусь использовать RedirectMemoryBlock, т.к. она довольно не простая (с тем, чтобы просто указать ЭРЕ на расширенную таблицу монстров, мне пришлось дожидаться твоей версии Typhon и потом ещё искать место в коде, из которого RedirectMemoryBlock срабатывала корректно). И в ERA Plus RedirectMemoryBlock можно использовать только для структуры монстров, к которой часто обращаются через ERM и плагинами, остальные структуры, которые были перенесены, моддерами почти не используются (попадаются такие ERMэшники-экстрималы, но они обычно за километр обходят ERA Plus 148 ), поэтому жду того времени, когда ERM в era.dll больше не будет изменяться и тогда можно будет менять ERM уже в ERA Plus с поддержкой всех перенесённых структур.
XEPOMAHT, функция элементарная. Приведи пример старого адреса, названия переменной с новым и размера старой области. Я напишу код вызова (там одна строка). Через UN:C сам увидишь, что всё верно работает.
Пример: таблица запрета артефактов (та самая, из-за которой до сих пор ругается ERM при загрузке карты в ERA PLUS)

Старый адрес: [699538h]+4E2B4h
Название переменной: Таблица_запрета_артефактов
Новый адрес: [699538h]+4E2B4h+321488
Размер старой области: 90h
XEPOMAHT, сразу после патча на подмену адреса.
Code:
mov eax, [699538h]
add eax, 4E2B4h; eax - старый адрес
lea ecx, [eax + 321488]; ecx - новый адрес
stdcall [RedirectMemoryBlock], eax, 90h, ecx

В ЕРМ
(21.04.2020 17:57)Berserker Wrote: [ -> ]В ЕРМ

Теоретически, должно быть так:


К у2 точно прибавится 321488, чтобы получить новый адрес??? 148 Ведь на твой RedirectMemoryBlock посылаются реальные адреса памяти, а скрипт оперирует сложением с базовым.

И что будет, если где-нибудь в другом месте встретится число 3282056 (или случайно произойдёт совпадение реального адреса с каким-нибудь числом в скрипте, мне не известно, как срабатывают проверки при обработке данных из RedirectMemoryBlock), не имеющее никакое отношение к таблице запрета артефактов??? 148
Точно, неверно смещение скопировал. У тебя верный код.
Ничего нигде не совпадёт. Игра запускается, адрес [699538h]+4E2B4h становится фиксированным и известным. Назовём его X.
Тогда таблица занимает память [X..X + 0x90 - 1].
Новая таблица у тебя перенесена в память [Y..Y + очень много - 1]
У Эры есть запись, что [X..X + 0x90 - 1] нужно транслировать в [Y..Y + 0x90 - 1]

Мы в ЕРМ в любом месте получаем старый адрес X
Затем находим его новый адрес:
После чего имеем "Y". Можно смело прибавлять индекс артефакта * размер записи для артефакта, чтобы сослаться на запрет конкретного артефакта. Всё. Никаких багов, ошибок, двусмысленностей.

Пример, перенос с адреса 1000 структуры на 200 байт на адрес 2000.
Было 1000..1199, стало 2000..2499 (структура расширена).

Для безопасной работы с расширенными структурами нужно не по 1000 + номер арта * 4 проводить работу, а сперва получить реальный базовый адрес структуры.
GetRealAddr(1000) = 2000.
Всё, теперь прибавляй, что хочешь.

В Era 2.9.13 есть команда !!UN:C[базовый адрес]/[смещение]/[размер]/[значение].
Вот она работает в точности так, как описано выше. Сперва получает реальный адрес для базового, только потом прибавляет смещение.


Чёрт. Понял, что написал полный бред. Херомант, ну ты и затейник. Если ты расширил таблицу путём изменения указателя в структуре данных, то не нужны RedirectMemoryBlock и GetRealAddr вообще. У тебя по

!!UN:C6919480/4/?y1;
!!VRy1:+320180; y1 - всегда актуальный адрес

Вот если ты расширяешь статичную область памяти (например, строго по 0x500000 размером 1000 байт), на которую нет единого указателя, вот тогда и нужен RedirectMemoryBlock.
(21.04.2020 18:56)Berserker Wrote: [ -> ]У тебя по

!!UN:C6919480/4/?y1;
!!VRy1:+320180; y1 - всегда актуальный адрес
Ага, если конечно ХЕРОМАНТ будет в 6919480 заносить адрес смещенной таблицы))
igrik, если не будет, то это ахтунг )))
(21.04.2020 19:18)igrik Wrote: [ -> ]если конечно ХЕРОМАНТ будет в 6919480 заносить адрес смещенной таблицы))

Не, точно не будет, т.к. расширению базовой структуры ничего не мешает (в чём её огромный плюс). Главное, чтобы этим занимался только 1 плагин в ERA, иначе будет истинный ахтунг.
XEPOMAHT, вот как это понимать? Весь геройский код работает со старой таблицей? Если с новой и ты патчишь код для новых смещений, то это в корне неверно. Нужно просто подменить адрес.
(21.04.2020 22:32)Berserker Wrote: [ -> ]Весь геройский код работает со старой таблицей?

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

(21.04.2020 22:32)Berserker Wrote: [ -> ]Если с новой и ты патчишь код для новых смещений, то это в корне неверно. Нужно просто подменить адрес.

Если бы было всё так просто, новые города в WoG появились бы ещё в 2005 году. Замена адреса на всю таблицу работает только для небольших и простых изолированных таблиц, типа таблицы монстров (что в WoG было реализовано ещё в 2001 году). Крупные массивы данных типа базовой структуры - только через непосредственное перераспределение данных в памяти бинарным патчем. А вот данные стека уже переносятся только заменой кода (т.к. менять адресацию в стеке так, чтобы работа функций при этом не нарушилась - полный хардкор).
Не соглашусь. Пусть есть большая структура, которая состоит из трёх других структур, разделённых мусором.
Пусть есть указатель на эту большую структуру, например [699538h].

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

В результате получаем совместимость с плагинами и lua/erm-скриптами, который будут использовать UN:C или GetRealAddr.

!!UN:C6919480/4/?y1;
!!VRy1:+320180; y1 - адрес старой подструктуры запрещённых артефактов

!!UN:Cy1/смещение/4/?y2; прочли данные уже из новой

mov eax, [699538h]
add eax, 4E2B4h; eax - старый адрес
lea ecx, [eax + 641668]; ecx - новый адрес. Смещение вроде бы верно расчитал
stdcall [RedirectMemoryBlock], eax, 90h, ecx
(22.04.2020 04:48)Berserker Wrote: [ -> ]Тогда патчим все смещения от этой большой структуры до трёх подструктур так, чтобы итогово смещение = новый адрес подструктуры - адрес начала большой старой структуры.
Вызываем RedirectMemoryBlock, как в зачёркнутом посте выше для каждой подструктуры.

Хорошо, к примеру была таблица по адресу 6666, с помощью RedirectMemoryBlock указываем, что она переместилась на 6667. Какой-нибудь левый скрипт использует следующий код:

!!VRy1:S1;
!!VRy1:+6665;

Что получится в итоге? 6666 или 6667?

И если честно, мне плохо понятен принцип работы RedirectMemoryBlock. Она проверяет значения при каждой математической операции? Смещения могут быть очень маленькими, что в итоге может превратить любой ERM-код в тыкву. Технического описания по RedirectMemoryBlock по-прежнему нету (соответственно, когда не знаешь последствий от использования данного вызова, сложно с ней работать, принцип чёрного ящика здесь не работает).

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

Так же может использоваться прямая адресация от базового значения, без использования адреса субтаблиц (т.к. адрес сразу вычисляется для определённой ячейки первой строки таблицы, а не её начала, чтобы использовать, например, в цикле).
Reference URL's