Current time: 30.11.2024, 10:30 Hello There, Guest! (LoginRegister)
Language: english | russian  

Post Reply 
Threaded Mode | Linear Mode
Авторам плагинов
» Заметки по ERA API
Author Message
Berserker Offline
Administrators

Posts: 16657
Post: #1
Восклицание 
Работа с перенесёнными структурами данных
Если Вы используете структуры данных, которые имеют вероятность быть расширенными Эрой или другими плагинами, то для сохранения совместимости и предотвращения вылетов следует поступать следующим образом:

1) Плагинам, которые расширяют структуры, следует в событиях "OnBeforeWoG" или "OnAfterWoG" вызвать функцию
void __stdcall RedirectMemoryBlock (void* OldAddr, int BlockSize, void* NewAddr);

Укажите старый адрес структуры, старый размер структуры и новый адрес структуры.

2) Плагинам, что используют потенциально расширяемые структуры нужно в событии "OnAfterStructRelocations" сохранить себе новые адреса структур через вызов GetRealAddr:
void* __stdcall *GetRealAddr (void* Addr);

Для подписки на события Эры используйте
void (__stdcall *RegisterHandler (TEventHandler Handler, const char* EventName);

Code:
struct TEvent
  {
    char* Name;
    void* Data;
    int   DataSize;
  };
typedef void (__stdcall *TEventHandler) (TEvent* Event);

Таким образом Вы обеспечите корректную работу всех других плагинов и новых версий Эры.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
19.11.2020 17:39
Find all posts by this user Quote this message in a reply
XEPOMAHT Offline
Moderators

Posts: 2356
Post: #2

(19.11.2020 17:39)Berserker Wrote:  Если Вы используете структуры данных, которые имеют вероятность быть расширенными Эрой или другими плагинами, то для сохранения совместимости и предотвращения вылетов следует поступать следующим образом

На практике это было использовано 1 раз в Тифоне для структуры монстров (и то только после того, как Берсеркер это сделал сам, у меня так и не вышло такое добавить в код плагина), больше нигде "вероятность быть расширенными Эрой" слава богу не встретилась. И вообще, тут понятнее термин "перенесёнными в памяти", а не "расширенными": например Тифон 3.2 расширяет структуру героев, но не переносит её в памяти (сделано для совместимости с HD-модом и прочими модами, в которых RedirectMemoryBlock никогда не будет в силу отсутствия исходных кодов или возможности перекомпиляции или просто автору плагина наплевать на совместимость).

(19.11.2020 17:39)Berserker Wrote:  Таким образом Вы обеспечите корректную работу всех других плагинов и новых версий Эры.

Чтобы это работало на практике, нужно, чтобы это применялось в двухстороннем порядке. Например, тот же Тифон 3.2 переносит кучу всяких данных, но RedirectMemoryBlock применяется только для структуры монстров для совместимости с era.dll, но абсолютно не известно, какие перенесённые структуры потребуются ЭРЕ в будущем 105 (а Тифон переносит ещё много что... 148 ).

В подавляющем большинстве случаев для чтения перенесённых структур лучше использовать базовые адреса структур (любая прямая адресация в коде может быть принята за базовый адрес) - это позволяет не договариваться с автором плагина, в котором перенесена структура, о добавлении RedirectMemoryBlock. Тем более, одна структура может быть перенесена только одним плагином (например Тифон никогда не заработает вместе с Аметистом так же как ERA+ будет всегда конфликтовать с вражеским Knightmare Kingdoms), а самих плагинов, меняющих структуры, существует не так много.

Для совместимости плагинов как раз и созданы сборники плагинов - никому не нужный отечественный ERA+ и никому не нужный его зарубежный аналог Knightmare Kingdoms. Т.е. для создания какого-то по-настоящему глобального мода для ERA, типа Horn of the Abyss, выбираются сборники плагинов, которые имеют проверенную совместимость (но, как понимаете, до этого ещё дело не дошло, ВСЕ современные моддеры на ERA ограничиваются созданием небольших модов), а не подбираются отдельные плагины (которые всё равно будут частью подплатформ ERA).
(This post was last modified: 19.11.2020 19:01 by XEPOMAHT.)
19.11.2020 18:40
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #3

XEPOMAHT, я не занимаюсь поддержкой плагинов, которые пишутся криво в расчёте, что других плагинов не существует. Предложенный механизм из Эры 2.0 (!) решает большинство проблем. Так, если в 10 плагинах нужен массив монстров, а 1-му плагину нужно его расширить (Typhon или Аместист), то все они будут работать. Исходники TyphonZ опубликованы. Как написать две команды на ассемблере можно и подглядеть.

TyphonZ с нуля писал МоР. За консультациями никто не обращался. Я лишь исправил несколько самых очевидных проблем: убрал хуки на события, заменив их подпиской на события Эры, и добавил те самые RedirectMemoryBlock.

Более того, UN:C в Эре тоже всегда использует GetRealAddr на базовый адрес (если в параметрах отдельно указывается и смещение). То есть всё работает прозрачно и надёжно.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
19.11.2020 19:12
Find all posts by this user Quote this message in a reply
XEPOMAHT Offline
Moderators

Posts: 2356
Post: #4

(19.11.2020 19:12)Berserker Wrote:  Так, если в 10 плагинах нужен массив монстров, а 1-му плагину нужно его расширить (Typhon или Аместист), то все они будут работать.

К примеру, HD-мод как-то работает с перемещённым массивом монстров вместе с Тифоном или Аметистом. HD-моду не потребовалось использование GetRealAddr. А вот в ERA почему-то потребовалось. Где искать истину? Мы в плену HD-мода по-сути, совместимость с которым на 1-м месте. Если era.dll будет использовать перемещённые структуры, кроме структуры монстров, то добавить RedirectMemoryBlock в код Тифона - без проблем, нужно будет только сообщить для каких конкретно. Ну а для всех перемещаемых структур делать это боюсь - сказывается негативный опыт со структурой монстров (там помог только метод научного тыка).
(This post was last modified: 19.11.2020 20:39 by XEPOMAHT.)
19.11.2020 20:38
Find all posts by this user Quote this message in a reply
feanor Offline

Posts: 624
Post: #5

Известить эру о том, что мы переносим структуру, не западло, конечно. (хотя и в ряде случаев бессмысленно, если изменяется и способ работы со структурой, например, в случае реализации альтерветок/третьих грейдов)

а вот самому использовать GetRealAddr() - фигня какая-то.
Во-первых, совершенно неясно, куда его в существующей парадигме совать. Ну вот есть у нас есть тупо определенный дефайном указатель на игровые структуры, с нулевыми накладными расходами; их библиотека подключается как обычный заголовочник, и не нужно возиться ни с каким разрешением зависимостей и экспортами функций.

Вот оч правильный вопрос
Quote: HD-моду не потребовалось использование GetRealAddr. А вот в ERA почему-то потребовалось. Где искать истину
Потому что в НD используется двойной указатель на структуру монстров, указатель из кода на указатель на массив структур
как-то так:
было
Code:
//#define o_CreatureInfo ((_CreatureInfo_*)0x6703B8)
стало
Code:
#define CREATURE_INFO_OFFSET (*(_ptr_*)0x6747B0)
#define o_CreatureInfo ((_CreatureInfo_*)CREATURE_INFO_OFFSET)

И именно так и надо делать, просто потому что расширялки мимо этих указателей в любом случае не пройдут, а выбор между предлагаемым методом, который требует от всех участников соблюдения конвенций (учитывая, что соблюдение конвенций и эра - кхмкхм такое себе сочетание) и методом, который не требует этого, ну, очевиден.
19.11.2020 22:58
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #6

Quote:К примеру, HD-мод как-то работает с перемещённым массивом монстров вместе с Тифоном или Аметистом.
То, как работает HD (через двойной указатель) — гораздо безопаснее. И HD-мод не расширяет структуру. Ему не нужен RedirectMemoryBlock.

Quote:Если era.dll будет использовать перемещённые структуры, кроме структуры монстров, то добавить RedirectMemoryBlock в код Тифона - без проблем
Не нужно ждать. Вызов RedirectMemoryBlock → это просто извещение, которое сразу даёт кислород всем плагинам на ERM/Lua/C++/Pascal/Brainfuck.

Quote:а вот самому использовать GetRealAddr() - фигня какая-то.
Во-первых, совершенно неясно, куда его в существующей парадигме совать.
Тут два момента:
1) В вопросах скорости — экономия на спичках, даже не серьёзно.
2) Работать классически не через define, а через объявление указателя.
_CreatureInfo_ *monsterAttrs = 0xAAAAAA;

=> OnAfterStructRelocations
monsterAttrs = GetRealAddr(monsterAttrs); преобразовали адрес с оригинального в конечный.

У меня так в одном из модулей:

Code:
procedure OnAfterStructRelocations (Event: GameExt.PEvent); stdcall;
begin
  ZvsIsGameLoading           := GameExt.GetRealAddr(ZvsIsGameLoading);
  ZvsTriggerIfs              := GameExt.GetRealAddr(ZvsTriggerIfs);
  ZvsTriggerIfsDepth         := GameExt.GetRealAddr(ZvsTriggerIfsDepth);
  ZvsChestsEnabled           := GameExt.GetRealAddr(ZvsChestsEnabled);
  ZvsGmAiFlags               := GameExt.GetRealAddr(ZvsGmAiFlags);
  IsWoG                      := GameExt.GetRealAddr(IsWoG);
  WoGOptions                 := GameExt.GetRealAddr(WoGOptions);
  ErmEnabled                 := GameExt.GetRealAddr(ErmEnabled);
  ErmErrCmdPtr               := GameExt.GetRealAddr(ErmErrCmdPtr);
  ErmDlgCmd                  := GameExt.GetRealAddr(ErmDlgCmd);
  MrMonPtr                   := GameExt.GetRealAddr(MrMonPtr);
  HeroSpecsTable             := GameExt.GetRealAddr(HeroSpecsTable);
  HeroSpecsTableBack         := GameExt.GetRealAddr(HeroSpecsTableBack);
  HeroSpecSettingsTable      := GameExt.GetRealAddr(HeroSpecSettingsTable);
  SecSkillSettingsTable      := GameExt.GetRealAddr(SecSkillSettingsTable);
  SecSkillNamesBack          := GameExt.GetRealAddr(SecSkillNamesBack);
  SecSkillDescsBack          := GameExt.GetRealAddr(SecSkillDescsBack);
  SecSkillTextsBack          := GameExt.GetRealAddr(SecSkillTextsBack);
  MonNamesSettingsTable      := GameExt.GetRealAddr(MonNamesSettingsTable);
  MonNamesSingularTable      := GameExt.GetRealAddr(MonNamesSingularTable);
  MonNamesPluralTable        := GameExt.GetRealAddr(MonNamesPluralTable);
  MonNamesSpecialtyTable     := GameExt.GetRealAddr(MonNamesSpecialtyTable);
  MonNamesSingularTableBack  := GameExt.GetRealAddr(MonNamesSingularTableBack);
  MonNamesPluralTableBack    := GameExt.GetRealAddr(MonNamesPluralTableBack);
  MonNamesSpecialtyTableBack := GameExt.GetRealAddr(MonNamesSpecialtyTableBack);
  ArtNamesSettingsTable      := GameExt.GetRealAddr(ArtNamesSettingsTable);
  ArtInfosBack               := GameExt.GetRealAddr(ArtInfosBack);
  MonNamesTables[0]          := MonNamesSingularTable;
  MonNamesTables[1]          := MonNamesPluralTable;
  MonNamesTables[2]          := MonNamesSpecialtyTable;
  MonNamesTablesBack[0]      := MonNamesSingularTableBack;
  MonNamesTablesBack[1]      := MonNamesPluralTableBack;
  MonNamesTablesBack[2]      := MonNamesSpecialtyTableBack;
end; // .procedure OnAfterStructRelocations

procedure OnAfterStructRelocations (Event: GameExt.PEvent); stdcall;
begin
  SecSkillNames := GameExt.GetRealAddr(SecSkillNames);
  SecSkillDescs := GameExt.GetRealAddr(SecSkillDescs);
  SecSkillTexts := GameExt.GetRealAddr(SecSkillTexts);
  MonInfos      := GameExt.GetRealAddr(MonInfos);
  ArtInfos      := ppointer(ArtInfos)^;
end;

А там, где прямой адрес был, заменил на:
Code:
NextRecruitMonsDlgOpenEventDwellingId := pbyte(Heroes.GetTownManager.Town.TownType * 2 + Context.EDI + integer(GameExt.GetRealAddr(Ptr($68A3A2))))^;

Если я берусь использовать в коде таблицу, то считаю, что навыки/монстров/тексты/героев кто-то наверняка можешь расширить. Или правильнее было бы использовать фиксированные адреса и писать, что у людей просто нерабочие плагины? Spiteful


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
19.11.2020 23:20
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #7

А теперь представьте, что вы написали 10 плагинов и ушли на пенсию. Чтобы сделать с ними совместимость, мне достаточно в пару мест добавить GetRealAddr в ранее неучтённых указателях. Как и в любом актуальном коде. Но если ваши плагины сами никогда не уведомляют о расширенных структурах и не пользуются GetRealAddr, то беда.

Quote:#define o_CreatureInfo ((_CreatureInfo_*)CREATURE_INFO_OFFSET)
Такой подход я применяю пока для определения лимита существ, но стоит какому-нибудь majaczek пропатчить код по данному адресу…Вы поняли. То, о чём извещено явно, можно явно же и узнать. Вариант HD-мода тоже неплох, но требует искать всегда такие неизменные участки кода (которые часто не выравнены) и надеяться, что там никто команду не пропатчил с полной заменой логики. У каждого разработчика будет свой участок кода, из которого он будет считывать указатель, что повышает хрупкость всей системы. Хотя в целом решение лежит на поверхности, его даже в patcher нужно было вводить: Redirect + GetAddress пара позволила бы всем договориться и не ссылаться на код.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
19.11.2020 23:29
Find all posts by this user Quote this message in a reply
XEPOMAHT Offline
Moderators

Posts: 2356
Post: #8

(19.11.2020 23:20)Berserker Wrote:  То, как работает HD (через двойной указатель) — гораздо безопаснее. И HD-мод не расширяет структуру. Ему не нужен RedirectMemoryBlock.

Ну HD-мод видит перемещённые структуры от hota.dll, где много чего наменяли, и перемещённые данные воговского кода независимо от версии вога, в общем это вполне универсальное решение. Ну а мне откуда знать, что автор плагина сделал RedirectMemoryBlock? Авторов ведь палкой не заставишь делать в коде RedirectMemoryBlock (программисты в основном одни лентяи).



(19.11.2020 23:20)Berserker Wrote:  Если я берусь использовать в коде таблицу, то считаю, что навыки/монстров/тексты/героев кто-то наверняка можешь расширить. Или правильнее было бы использовать фиксированные адреса и писать, что у людей просто нерабочие плагины? Spiteful

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


(19.11.2020 23:29)Berserker Wrote:  А теперь представьте, что вы написали 10 плагинов и ушли на пенсию. Чтобы сделать с ними совместимость, мне достаточно в пару мест добавить GetRealAddr в ранее неучтённых указателях. Как и в любом актуальном коде. Но если ваши плагины сами никогда не уведомляют о расширенных структурах и не пользуются GetRealAddr, то беда.

Если так сильно нужен GetRealAddr в UN:C например, то определение адресов структур можно добавить в саму ЭРУ, не перекладывая это на плечи плагинописцев. Можно даже сделать отдельным плагином, который укажет ЭРЕ о всех перемещённых структурах.

(19.11.2020 23:29)Berserker Wrote:  Такой подход я применяю пока для определения лимита существ, но стоит какому-нибудь majaczek пропатчить код по данному адресу…Вы поняли. То, о чём извещено явно, можно явно же и узнать.

Бинарные патчи хороши для одного глобального мода типа MoP и являются абсолютным злом на платформе ERA (Тифон 3.хх тоже грешен небольшим количеством бинарных патчей, скопированных с MoP, которые было просто лень преобразовывать в отдельные функции). Никто не застрахован и от перекрывающих друг друга хуков, а если их накапливается 100500 штук на era.exe, то любой программист в них утонет и никакая база уже не поможет.

(19.11.2020 23:29)Berserker Wrote:  Вариант HD-мода тоже неплох, но требует искать всегда такие неизменные участки кода (которые часто не выравнены) и надеяться, что там никто команду не пропатчил с полной заменой логики. У каждого разработчика будет свой участок кода, из которого он будет считывать указатель, что повышает хрупкость всей системы.

Да, только так. Это в MoP сильно изменён код игры, что ни HD-мод, ни ERA никогда там не смогут запуститься (и с каждой новой версией MoP тамошний код мутирует ещё сильнее). В ERA ж - только отслеживать чужой код и делать соответствующие правки у себя в плагине. И больше использовать события эры, где это возможно.

Да и самих плагинов, расширяющих структуры, очень мало. У меня специально скомпилировано всё в одной dll, чтобы не мучится с адресацией перенесённых структур на разных dll. Для поддержки новых героев, например, придётся поглотить плагин Dwellings.dll, как раз из-за проблемы с адресацией. И т.д.
20.11.2020 00:58
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #9

В любом случае, это информация для igrik-а, раз ему пришлось снова решить вылет, связанный с конфликтом доработанного аметиста от majaczek. Самому majaczek-у я пост перекинул, благо Яндекс прекрасно перевёл. Рекомендую всем новый код писать именно в таком варианте, как минимум используя GetRealAddr или на худой конец двойной указатель, а также вызывая RedirectMemoryBlock для работы Эры и плагинов, что будут следовать соглашению и UN:C.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
20.11.2020 01:15
Find all posts by this user Quote this message in a reply
feanor Offline

Posts: 624
Post: #10

Quote:1) В вопросах скорости — экономия на спичках, даже не серьёзно.
Минимум один раз я впилился в ситуацию, когда мне даже накладные расходы на патчеровский переходник для хука оказались велики. Так что я бы не стал говорить за спички.
   
Quote:У меня так в одном из модулей:
Тут пять объявлений. В оч базовой библиотеке типа старохотовского/третьехдшного Homm3.h их семьдесят, и это потому что я очень ленивый и не добавлял туда еще несколько десятков локально разбросанного по исходникам.
Все переписывать, все в глобальные переменные ><
Еще и возможность сравнительно быстро адаптировать несложные плагины под сод уйдет.

Quote:А теперь представьте, что вы написали 10 плагинов и ушли на пенсию. Чтобы сделать с ними совместимость, мне достаточно в пару мест добавить GetRealAddr в ранее неучтённых указателях. Как и в любом актуальном коде. Но если ваши плагины сами никогда не уведомляют о расширенных структурах и не пользуются GetRealAddr, то беда.
Седьмой плагин сломался, когда Эра 4.0.74 поставила свой хук в то же место, третий не актуален, потому что его функционал все равно ломает пару других популярных плагинов, восьмой отвалился при очередном обновлении HD-мода, еще четыре сдохли, когда Эра 5.70.05 в очередной раз вышла под девизом "Сбросим Пушкина с парохода современности", грохнув какое-то старое легаси.
Общая хрупкость системы? Она у нас давно в отрицательных величинах.
Более того, тут сама пресуппозиция неверна, прям обязательное использование GetRealAddr имеет смысл только если у нас _уже_ нету десятка плагинов от ушедших на покой авторов и кучи разбросанных по сети устаревших примеров, по которым учатся новички.
А если мы вынуждены о них думать..только цепочки косвенных адресаций, только хардкор.

Quote:Вариант HD-мода тоже неплох, но требует искать всегда такие неизменные участки кода (которые часто не выравнены) и надеяться, что там никто команду не пропатчил с полной заменой логики.
а если у нас команда пропатчена с полной заменой логики, то, скорее всего, нам и GetRealAddr не поможет.
Т.е. не искусственный пример для этого - тифон или что-то тифоноподобное (реализующее и альтерветки/апгрейды), что для работы с таблицей монстров заменяет почти все обращения к ней. Казалось бы, указателей нету, но ведь у нас теперь нету и таблицы, на которую можно было бы кидать редирект!
Причем в подавляющем большинстве ненадуманных примеров так и будет по определению - если мы патчим обработчик таблицы, то, скорее всего, нас не устраивает таблица целиком.

Кстати, а что мы делаем с тем фактом, что GetRealAddress не даст нам информации ни о дополнительной части таблицы, ни о её пределах? Как ни крути, нам все равно нужно изворачиваться, это ни разу не серебряная пуля.
Для UN:C это отличный механизм, я не спорю, и плагинам он хотя бы не создает проблем (в отличие от), но я не считаю, что он реально необходим и обязателен.

Quote:Хотя в целом решение лежит на поверхности, его даже в patcher нужно было вводить: Redirect + GetAddress пара позволила бы всем договориться и не ссылаться на код.
Эм, нет, это не сработает. Потому что читаем данные мы не через патчер, а через *(_type_*).
(This post was last modified: 20.11.2020 01:57 by feanor.)
20.11.2020 01:54
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #11

feanor, ты прав насчёт конечных размеров структур. У меня вертится идея добавить аналог RedirectMemoryBlock, но с NewSize последним параметром. Сейчас лимиты монстров/героев я получаю по способу HD-мода: считываю значение из какого-нибудь воговского цикла. Если бы был четвёртый параметр, можно было бы писать функции а-ля GetTownLimit => GetStructSize(addr) / SINGLE_ITEM_SIZE.

Итого, что мы имеем. На текущий момент у нас есть компромиссно-альтернативный вариант:
1) Плагины читают указатель на таблицы/структуры, не используя прямые адреса.
2) Плагины вызывают GetRealAddr в событии OnAfterStructRelocations.

При этом в любом случае о перенесённых структурах сообщают через RedirectMemoryBlock, чтобы Era/ERM UN:C/Lua/православные плагины были счастливы.

Возможно, найдутся предложения получше.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
20.11.2020 02:41
Find all posts by this user Quote this message in a reply
feanor Offline

Posts: 624
Post: #12

Quote:feanor, ты прав насчёт конечных размеров структур. У меня вертится идея добавить аналог RedirectMemoryBlock, но с NewSize последним параметром. Сейчас лимиты монстров/героев я получаю по способу HD-мода: считываю значение из какого-нибудь воговского цикла. Если бы был четвёртый параметр, можно было бы писать функции а-ля GetTownLimit => GetStructSize(addr) / SINGLE_ITEM_SIZE.
Не решает проблему с новой частью таблицы.

Какой бы не очень надуманный пример придумать..
Вот у нас есть, допустим, код для изменения стрелков в башнях. Там как раз таблица, 36 двордов на девять городов.
Есть использующий его скрипт, который в начале боя берет номер осаждаемого города, и допустим, берет-изменяет какие-то данные в этой таблице. Например, заменяет стрелков в зависимости от его отстройки.
Все довольны, все работает, Солмир строит Капитолий и получает косметических титанов в башнях.

Потом появляется плагин на расширение городов. Он эту таблицу переносит, регистирует редирект блока, заполняет данные десятого города..
И на десятом городе скрипт начинает в лучшем случае не работать (если он правит данные где-то за верхней границей массива, но там ничего важного нет), в обычном - ронять игру (если правит данные за верхней границей массива, но там критичное), в худшем - работать неправильно (если он пытатся брать данные из мусора за верхней границей).

Теоретически мы можем зарегистрировать редирект с избытком, захватив область памяти за верхним краем. Тогда UN:C по таблице стрелков десятого города будет отрабатывать правильно.
Но это концептуально неправильно, и, что важнее, как минимум (тут уже пошли теоретические вымышленные примеры, надо смотреть) способно грозить проблемами. Не дай бог у нас таблица стрелков упирается во что-то нужное другому скрипту, например, там какая-то другая таблица, или просто какие-то системные данные. Тогда у нас уже другой скрипт будет сходить с ума, причем, в отличие от чистого случая, на отладке вполне можно будет свихнуться.
20.11.2020 13:04
Find all posts by this user Quote this message in a reply
XEPOMAHT Offline
Moderators

Posts: 2356
Post: #13

(20.11.2020 13:04)feanor Wrote:  Не решает проблему с новой частью таблицы.

Резать таблицы в памяти на части - плохая идея. Сразу и оригинальный код слетит к майкрософту, а не только UN:C. Да и любые обращения к таким вещам как к единой таблице будут приводить к ошибкам. Поэтому такие варварские воговско-хотовские методы фрагментации таблиц - зло, которого необходимо избегать на ERA. На MoP например такие вещи вырезаны нафиг.

(20.11.2020 13:04)feanor Wrote:  Потом появляется плагин на расширение городов. Он эту таблицу переносит, регистирует редирект блока, заполняет данные десятого города..
И на десятом городе скрипт начинает в лучшем случае не работать (если он правит данные где-то за верхней границей массива, но там ничего важного нет), в обычном - ронять игру (если правит данные за верхней границей массива, но там критичное), в худшем - работать неправильно (если он пытатся брать данные из мусора за верхней границей).

Отчего ж будет работать не правильно? Редитект блок укажет новый адрес начала этой таблицы. Таблица уже заполнена готовыми данными непосредственно в самой dll и имеет в памяти следующий вид:

Code:
Town_SiegeTowersArmy = $
;<<<ЗАМОК>>>
dd CR_Арбалетчик,    780, 238, 648, 566, 596, 80, 6609B0h
;<<<ОПЛОТ>>>
dd CR_Эльф,        786, 240, 625, 563, 595, 81, 660998h
;<<<БАШНЯ>>>
dd CR_Маг,        753, 251, 609, 578, 600, 92, 660914h
;<<<ИНФЕРНО>>>
dd CR_Гог,        765, 230, 623, 565, 595, 80, 660974h
;<<<НЕКРОПОЛИС>>>
dd CR_Лич,        755, 365, 625, 570, 593, 90, 660968h
;<<<ТЕМНИЦА>>>
dd CR_Созерцатель,    785, 217, 625, 560, 596, 80, 66095Ch
;<<<ЦИТАДЕЛЬ>>>
dd CR_Орк,        785, 222, 615, 557, 596, 80, 660950h
;<<<КРЕПОСТЬ>>>
dd CR_Ящер,        795, 230, 626, 575, 580, 85, 660938h
;<<<СОПРЯЖЕНИЕ>>>
dd CR_Элементаль_Шторма,783, 225, 636, 575, 595, 105, 6608FCh
;<<<ПРИЧАЛ>>>
dd CR_Пират,        780, 238, 648, 566, 596, 80, ZShot194

Хотим заменить Пиратов на Жриц любви Моря? Получаем новый адрес + размер строки * номер города. Скрипт на UN:C теоретически должен сработать без глюков.
(This post was last modified: 20.11.2020 14:38 by XEPOMAHT.)
20.11.2020 13:21
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #14

feanor, проблема уже решена новым подходом.
1) В Эру добавлена UN:C с четырьмя параметрами, поддерживающая Базовый адрес + Смещение. GetRealAddr вызывается только для базового адреса, затем прибавляется смещение.
2) В коде стоит вызывать GetRealAddr только для базового адреса.

Таким образом даже если за таблицей для 9 городов следует другая таблица для 9 городов проблемы не будет.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
20.11.2020 17:39
Find all posts by this user Quote this message in a reply
« Next Oldest | Next Newest »
Post Reply 


Forum Jump:

Powered by MyBB Copyright © 2002-2024 MyBB Group