Объявления

Друзья, если не получается зарегистрироваться, напишите на почту vdv_forever@bk.ru.
Я оторву свою задницу от всех дел и обязательно Вас активирую! :smile10:
Добро пожаловать на геройский форум! :smile25:

Как создать плагин для HD мода

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 23 дек 2021, 09:45

Цитата:
Никаких трудностей при взаимодействии с Хайрезом я не встретил. Единственное с чем я вижу трудность взаимодействия - так это с очередью хода. И только.

С большинством диалогов HD не должно возникать трудностей. Но всё-таки хотелось бы уметь получать VMT для конструкторов/деструкторов. Например, как грамотно и без костылей получить получить адрес конструктора TDimensionDoorWindow::TDimensionDoorWindow(void) в HD моде? У меня пока только косвенно выходит выковыривать из ассемблерной инструкции. Вдруг есть прямые методы?

С очередью ситуация другая. Там реализован механизм предсказания ходов и их просчёт опирается на стандартную механику, а вклиниться в эту механику без патча dll невозможно (по крайней мере, мне об этом неизвестно). Так понимаю, с миникартой та же ситуация, но это я по словам выше (самому не требовалось работать с миникартой в HD). Если вдруг кто-то захочет видеть свой уникальный объект на миникарте или даже по-другому рисовать города и замки на миникарте, то вряд ли это получится сделать без танцев с бубном. Миникарта меня, конечно, не волнует. А вот доступ к базовым функциям очереди ходов хотелось бы иметь. Её можно усовершенствовать для предсказания скорости (не говоря уже о предсказании других параметров). Сейчас, если у отряда снимается Slow в начале следующего раунда, а игрок видит как текущий ход, так и следующий, то параметр скорости по ПКМ будет показан так, как будто Slow в следующем раунде ещё действует, хотя порядок ходов и будет правильным. Некритично, но можно было бы допилить.
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

Re: Как создать плагин для HD мода

Сообщение Rolex » 23 дек 2021, 11:26

AlexSpl писал(а):

А вот доступ к базовым функциям очереди ходов хотелось бы иметь. Её можно усовершенствовать для предсказания скорости (не говоря уже о предсказании других параметров). Сейчас, если у отряда снимается Slow в начале следующего раунда, а игрок видит как текущий ход, так и следующий, то параметр скорости по ПКМ будет показан так, как будто Slow в следующем раунде ещё действует, хотя порядок ходов и будет правильным. Некритично, но можно было бы допилить.

А ни этот ли баг исправляет фикс <QueueFix>, который Вы недавно добавили в NewSpells? Или там что-то другое?
Вернуться к началу

offlineigrik  
Подмастерье
Подмастерье
 
Сообщения: 108
Зарегистрирован: 14 сен 2017, 12:35
Пол: Не указан
Поблагодарили: 84 раз.

Re: Как создать плагин для HD мода

Сообщение igrik » 23 дек 2021, 12:08

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

Код: Выделить всё
#pragma pack(push, 1)
struct _DlgVTable_
{
  funk_thiscall Destruct;
  funk_thiscall Show;
  funk_thiscall Hide;
  funk_thiscall CallProcessAction;
  funk_thiscall nullsub_4;
  funk_thiscall Redraw;
  funk_thiscall Run;
  funk_thiscall InitItems;
  funk_thiscall Activate;
  funk_thiscall ProcessAction;
  funk_thiscall OnMouseMove_SetHintItem;
  funk_thiscall OnRightClick_ShowMsgItem;
  funk_thiscall nullsub_12;
  funk_thiscall nullsub_13;
  funk_thiscall Close;
};
#pragma pack(pop)


Сам же конструктор большинства диалогов в игре (базовый класс _Dlg_) это 0x41AFA0. Как раз по смещению 0 и пишется указатель на виртуальную таблицу.

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

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 23 дек 2021, 22:22

Обновил плагин NewSpells, чтобы можно было потестить новые фичи заклинаний Explosion и Incineration.

Для Explosion - это уменьшение скорости на 1 ед. до конца раунда, а для Incineration - невозможность вернуть обратно отряды, которые погибли от каста этого заклинания. Кроме того, переписана значительная часть AI в плане кода.
Вернуться к началу

offlineХеромант  
имя: OL
Новичок
Новичок
 
Сообщения: 15
Зарегистрирован: 21 ноя 2021, 19:42
Пол: Мужчина
Поблагодарили: 2 раз.

Re: Как создать плагин для HD мода

Сообщение Херомант » 24 дек 2021, 06:54

igrik писал(а):

Любыми элементами диалогов можно управлять, перемещать, скрывать, показывать и т.п. Даже HD-шные элементы подчиняются этим правилам.


Ну к примеру как перехватить отрисовку рамок и фона главного меню, которую производит HD-мод поверх содовского? Пример: вставка титульника главного меню повышенного разрешения (мне год назад пришлось вручную править _HD3_.dll чтобы увеличить картинку фона с 800х600 до 1024х768, естественно, что это сработало, но патчить _HD3_.dll после каждого обновления HD-мода - плохое решение). Там даже новые индексы элементов диалога Бараторч знает какие....

igrik писал(а):

Чисто для информации: у меня большие трудности вызывает взаимодействие с кодом Вога (даже при наличии исходников), чем с HD.


Да, СИ-шные исходники ВоГа читать тяжело (повезло, что там тонна ассемблерных вставок, по которым лично я и ориентируюсь в коде ВоГа). Но использовать функционал HD-мода так же не просто (например, в Тифоне 3 у меня получилось только вызывать HD-функции отрисовки кастомных данных в окне состояния диалога Окна Карты Приключений, и то, адрес я вычисляю "по чёрному", а не спрашиваю у dll Бараторча с помощью легальных методов (т.к. Бараторч подобный функционал предоставляет только в хотовской dll, а оно, понятное дело, работает только с HoA). Поэтому частенько приходится некоторые патчи HD-мода убирать.

А каких трудов мне стоило добавить отрисовку спрайтов новых героев на карте под HD-мод - это был лютый трэш, так как мне всё же удалось найти в коде HD-мода вызов одной содовской функции, в которой удалось "пропихать" в стек данные для функции HD-мода, рисующей спрайты на карте приключений, чтобы HD-мод рисовал нужный мне спрайт, а не дефолтный. Увы, Бараторч очень любит перехватывать функции целиком, часто для взаимодействия с HD-модом приходится использовать различные костыли, чтобы работало так как нужно моддеру. :smile26:

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

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

Re: Как создать плагин для HD мода

Сообщение Rolex » 24 дек 2021, 08:53

AlexSpl писал(а):

Обновил плагин NewSpells, чтобы можно было потестить новые фичи заклинаний Explosion и Incineration.

Я так понял в это обновление не вошла новая функция взвешивания для Drain Life, верно? То есть вы еще над ней работаете.

Получается осталось доделать функцию взвешивания для Drain Life + разобрать Adventure AI и прикрутить каст Mobility для AI.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 24 дек 2021, 09:12

Замечали, как AI частенько кастует Anti-Magic на отряды с отрицательными эффектами, даже если навыка Земли кастующего героя недостаточно для снятия этих эффектов?

Код: Выделить всё
int __thiscall type_AI_spellcaster::get_antimagic_value(
        type_AI_spellcaster *const this,
        army *const army,
        type_enchant_data enchantData)
{
  int cancelValue; // edi
  int result; // edi
  army armyCopy; // [esp+Ch] [ebp-554h] BYREF
  int tryNestedLevel; // [esp+55Ch] [ebp-4h]

  army::army(&armyCopy, army);
  tryNestedLevel = 0;
  cancelValue = type_AI_spellcaster::get_cancel_value(this, &armyCopy, 0);
  result = type_AI_spellcaster::get_protection_value(
             this,
             army,
             EARTH_SCHOOL|WATER_SCHOOL|FIRE_SCHOOL|AIR_SCHOOL,
             akSpelltraits[SPL_ANTI_MAGIC].effect[enchantData.skillMastery],
             enchantData.spellDuration,
             0)
         + cancelValue;
  tryNestedLevel = -1;
  army::~army(&armyCopy);
  return result;
}

Оценка заклинания Anti-Magic есть сумма двух составляющих: оценки защиты от магии (от всех четырёх стихий)* и оценки снятия всех эффектов с отряда. Первым значением практически всегда можно пренебречь, а вот второе может быть огромным, т.к. есть сумма оценок висящих на отряде заклинаний (оценка снятия положительных эффектов, естественно, идёт со знаком минус). И всё было бы здорово, если бы не тот факт, что AI не учитывает уровень развития Earth Magic при оценке снятия эффектов, и поэтому мы получаем очень странные касты Anti-Magic, не снимающие негативные эффекты высокого уровня. Да, в этом есть какой-то смысл (AI делает профилактику негативных кастов), но по алгоритму видно, что оценка второй составляющей (составляющей снятия эффектов) должна плюсоваться только тогда, когда Anti-Magic реально снимает эффекты.

В следующей версии плагина этот момент будет учтён, и AI станет чуточку умнее. Также будут закрыты неоднозначные касты AI заклинаний на отряды под Fear. С одной стороны, Fire Shield на беззащитный отряд - хорошая идея, с другой, классический AI не рассматривает отряды под Blind, Stone Gaze и Paralyze в качестве целей для бафов. Думаю, я добавлю Fear в эту категорию, заодно понизив вес самого Fear, что даст более интересные и "красочные" бои с AI. Далее, будет пересмотрен массовый Dispel, чтобы приоритет получал массовый Cure при его наличии. Да, иногда выгодно снять со своих отрядов негативные эффекты даже ценой снятия негативных эффектов с вражеских отрядов, но приоритет всё же должен быть у массового Cure, который снимет негативные эффекты только с союзных отрядов.

Тема AI, конечно, большая. Здесь целое непаханное поле для плагинов, улучшающих AI. И нет предела совершенству, но закрыть все косяки AI, которые дожили до 2021-го года, трудоёмкая, а - главное - мало кому нужная задача. Однако поправить самые вопиющие моменты следует.

* Кстати, эту составляющую можно смело умножать на 2, т.к. Protection from Element дают только 50% защиту, тогда как Anti-Magic даёт 100%.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 24 дек 2021, 19:22

Сделал класс по фэншую почти:

Код: Выделить всё
class type_AI_spellcaster
{
public:
   type_AI_spellcaster* (__thiscall** VMT)(void*, char); // 0x000
   Hero* current_hero;                                   // 0x004
   Hero* enemy_hero;                                     // 0x008
   long our_group;                                       // 0x00C
   long enemy_group;                                     // 0x010
   long enemy_can_attack;                                // 0x014
   long can_be_attacked;                                 // 0x018
   bool win_likely;                                      // 0x01C
   bool is_creature_spell;                               // 0x01D
   type_AI_combat_parameters estimate;                   // 0x020
   type_AI_spellcaster *enemy_caster;                    // 0x048
   bool owns_enemy_caster;                               // 0x04C
   type_AI_enemy_data melee_enemies[20];                 // 0x050
   type_AI_enemy_data ranged_enemies[20];                // 0x190
   type_AI_enemy_data worst_enemies[20];                 // 0x2D0
                                                         // 0x410
   inline int get_attack_skill_value(Army* const army, Army* const enemyArmy, int spellDuration, int effect) const {
      return CALL_5(int, __thiscall, 0x437450, this, army, enemyArmy, spellDuration, effect);
   }
   inline int get_defense_skill_value(Army* const army, int spellDuration, int effect) const {
      return CALL_4(int, __thiscall, 0x438560, this, army, spellDuration, effect);
   }

   int (type_AI_spellcaster::*type_AI_spellcaster::get_enchantment_function(SpellID spell) const)(Army* const, type_enchant_data) const;
   int get_poison_value(Army* const army, type_enchant_data data) const;
   int get_disease_value(Army* const army, type_enchant_data data) const;
   int get_age_value(Army* const army, type_enchant_data data) const;
   int get_fear_value(Army* const army, type_enchant_data data) const;
   int get_death_blow_value(Army* const army, type_enchant_data data) const;
   int get_drain_life_value(Army* const army, type_enchant_data data) const;
   int get_toughness_value(Army* const army, type_enchant_data data) const;
   int get_behemoths_claws_value(Army* const army, type_enchant_data data) const;
   int unimplemented(Army* const army, type_enchant_data data) const;
};

А вот, как нужно получать адрес метода (еле нашёл в сети, как это сделать, столько мусора по теме):

Код: Выделить всё
int __stdcall get_enchantment_function(HiHook* h, type_AI_spellcaster* caster, SpellID spell)
{
   int (__thiscall type_AI_spellcaster::*value_func)(Army* const, type_enchant_data) const = caster->get_enchantment_function(spell);

   switch (spell)
   {
   case SPELL_POISON:
   case SPELL_DISEASE:
   case SPELL_AGE:
   case SPELL_FEAR:
   case SPELL_DEATH_BLOW:
   case SPELL_DRAIN_LIFE:
   case SPELL_TOUGHNESS:
   case SPELL_BEHEMOTHS_CLAWS:
     return (int&)value_func;
   case SPELL_EXPLOSION:
     // get_damage_spell_value
     return 0x436BB0;
   default:
     return CALL_2(int, __thiscall, h->GetDefaultFunc(), caster, spell);
   }
}

Код выходит на новый уровень :smile16: Вот с таким уже можно менять любую функцию взвешивания. По сути, у нас оригинальный класс (за исключением неиспользуемых в плагине методов) и работаем мы с ним в точности так, как это делает оригинальный код. Нет больше никаких __fastcall и unused_edx, только родной __thiscall :smile20:

* * *
Глядя на функции взвешивания хочется плакать. Это такая аппроксимация. Единственное оправдание этому то, что в 1999-м году очень важно было экономить время CPU. Если кто помнит, Герои 3 были довольно требовательной игрой и много кого разочаровали потому, что не хотели нормально работать на машинах, которые тянули Героев 2. Я думаю, именно поэтому такие упрощения. Много упрощений и есть косяки (отсутствуют банальные проверки, симуляция идёт против какого-то идеального отряда, который юнит даже атаковать не собирается и т.п.). Поэтому чуток поправить не повредит. Понимаю, смысла нет особого, все давно привыкли нагибать AI и считать его баги фичами, но посмотреть всё равно хочется, на что он способен с минимальными правками.

И это только начало. Наверняка есть новое поколение геройщиков-моддеров (пусть и не такое многочисленное), которое не знает, как сделать что-то, что бы превзошло все достижения прошлого :smile2: Казалось бы, всё давно разобрано на винтики и гаечки (хотя бы той же HotA Crew), а я скажу, что к AI даже и не прикасались, в том числе и HotA Crew. Так что, дерзайте. Впереди ещё один дивный мир под названием AI.

* * *
Можно ли считать программистов Героев 3 гениями из-за того, что мы копаемся в их коде спустя 20 лет? Можно, но не поэтому и не их :smile2: Квадратный корень всегда более сложная процедура, чем возведение в квадрат. Программисты NWC просто реализовывали идеи на С++: нужен метод - пишем метод :smile1: По сути реверсеры начинают с минимальной информацией о коде и далеко бы не продвинулись, если бы не дизассемблеры, а декомпиляторы - это и вовсе подарок. А теперь у нас есть исходный код RoE (ок, почти, но разница очень маленькая). Гении - реверсеры. Которые смогли создать WoG (пусть я и недолюбливаю WoG, но я играл в WoG, там просто людей накрыло от возможностей и они начали добавлять всё, что можно добавить), Era и HotA. ОК, добавлю MoP (тоже примечальный мод). Спасибо Вам за это :smile29: Реально, пройденный путь - это :smile11: и :smile16: Но теперь стоит всё-таки изучить дампы void_17 и придать хаосу некое подобие порядка.

Я допускаю, что у HotA Crew такой дамп уже был (всё-таки неглупые люди в команде), но для всех остальных моддеров, эти дампы - бесценный дар. Да, есть отличия кое-где, другой UI и нет RMG, но ядро оригинальное, а это уже больше, чем можно хотеть в отсутствие исходного кода. Я думаю, что моддеры после НГ чуток поправят здоровье и перепишут свой код с "догадками", чтобы он обрёл наконец настоящий смысл. Я никогда не увлекался Героями так сильно, чтобы пробовать писать что-то вроде Era, но я уже вижу, как Эру бустят эти дампы.

* * *
Добавлю про void_17. Мне всегда его вопросы казались странными и оторванными от темы. Если честно, я думал, что человек вообще далёк от темы и только учится :smile1: А оказывается, он делал то, что я считаю революцией 2021-го в моддинге Героев 3. Что ж, хочется и себя похвалить ленивого: я смог убедить, что код RoE стоит внимания и усилий. Но если копнуть глубже, то оригинальные посты о базе Dreamcast принадлежат Херомант'у. Просто никто из нас не понимал/ленился разбираться в том, что может дать дебажная инфа в Dreamcast для моддинга в целом (которая не лежала на поверхности, между прочим). А void_17 взял и разобрал, так что и мне стало стыдно :smile14:

Теперь, конечно, моддинг сильно упрощается. Я могу посмотреть любое поле/метод класса, параметры методов и т.п. и восстановить сигнатуры со 100% точностью такими, какими они были в RoE. Ну, а допилить до SoD, я думаю, не проблема. Всё-таки реверсеры мы, чи не? :smile10:
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: Как создать плагин для HD мода

Сообщение void_17 » 25 дек 2021, 07:36

Цитата:
Можно ли считать программистов Героев 3 гениями из-за того, что мы копаемся в их коде спустя 20 лет?


Не очень понимаю в чем гениальность. Код не такой качественный, как у четверки например. Явно видно, что и кто писал
 
(у разных программистов NWC разный стиль, например у Джефа Леджета был мой любимый, CamelCase и венгерская нотация, у Газа Смедстада был snake_case, он же писал 99% ИИ)
. В 4-ке такого нет, там абсолютно все строго стандартизировано и вид там АБСОЛЮТНО ВСЕХ ТИПОВ t_some_class. (имхо, CamelCase в разы читабельнее, хотя программисты профессия такая что, переключить регистр постоянно надоедает и съедает казалось бы копеечное время не более секунды, но копейка рубль бережет, как известно, поэтому snake_case быстрее для написания).

А реверсить древний код - занятие не такое уж и пошлое, как вам кажется. И реверсят нетолько код, почитайте например про Юрия Кнорозова или посмотрите документашку (недавно фильм Пивоварова про него вышел). Или например взгляните на СССР XX века или современный Китай, огромный кусок их техники - реверс чужой. Именно поэтому советских инженеров считали одними из крутейших в мире. И это очень полезный навык, развивает мышление и к тому же лучше понимаешь как работают вещи. Тем более тут такое благое дело, как шедевр игростроения - Герои 3.

Цитата:
Я допускаю, что у HotA Crew такой дамп уже был (всё-таки неглупые люди в команде)


Задал этот вопрос sav-y в личку. Как ответит - отпишусь.
upd.: пикрилейтед.
Изображение
Цитата:
Сразу отвечу на вопрос — нет, этот дамп не был мне известен, и у нас не было чего-либо подобного. Я составлял свою базу с нуля, используя только знания номеров элементов и некоторых смещений в структуре отряда в бою, которые у меня были ещё по опыту ERM-скриптинга. Также, уже на более позднем этапе, я взял кое-какую информацию из исходников HD (вероятно, в определённой части это переработанная информация из исходников WoG). Но всё это тоже было многократно переработано. -- Sav


Цитата:
Да, есть отличия кое-где, другой UI и нет RMG, но ядро оригинальное, а это уже больше, чем можно хотеть в отсутствие исходного кода. Я думаю, что моддеры после НГ чуток поправят здоровье и перепишут свой код с "догадками", чтобы он обрёл наконец настоящий смысл. Я никогда не увлекался Героями так сильно, чтобы пробовать писать что-то вроде Era, но я уже вижу, как Эру бустят эти дампы.

Да черт с ним, с RMG, тем более as239 его нехило и так подкрутил. Да и судя по хаосу в декомпиляте, там огромное количество встроенных функций и прочего д2,718рьма, так что оригинальные названия особо ничего не дали. А типы впринципе и так разобрали..

UI не особо сильно отличается, по крайней мере с точки зрения локальных переменных структур и классов. Разве что где-то он просто менялся по принципу: целый тип -> указатель на этот тип, или наоборот. Могу сказать так, типы UI дримкаста совпадают с RoE-ПК-шными на ~95%, с SoD на 75-85%.

Цитата:
А теперь у нас есть исходный код RoE (ок, почти, но разница очень маленькая).


Неа, вообще не так. Декомпилят гидры очень кривой. Начиная от маразма в стиле разбития указателей на 4 байта по-отдельности, заканчивая кривыми локальными переменными, параметрами и отсутствием казалось бы такой просто фичи как деманглера (он там есть, да, но он сломан, я писал даже на гитхабе, меня проигнорили, лишь кто-то пукнул в стиле ну ты вручную демангли и переименовывай). Ругать гидру можно хоть сколько, но альтернатив нет, к сожалению.
 
Вообще гидра в разы неудобнее и медленнее иды. В IDA мне практически все нравится. Пожалуй кроме usercall ака userpurge и прочего мусора с функциями. А так, от IDA веет уютом, с ней работать удобно и приятно, а еще быстро и эффективно.


Приведу пример:
Метод void TPalette16::Convert24to16. Я 5 разных баз героев смотрел(Ghidra Dreamcast, RoE-ПК, SoD, HD Edition Android, Armageddon's blade).
Вот что выдает Ghidra:
 
Код: Выделить всё
void __thiscall
TPalette16::Convert24to16
          (TPalette16 *this,void *p24,int rbits,int rshift,int gbits,uint gshift,int bbits,
          int bshift)

{
  ushort uVar1;
  ushort uVar2;
  int iVar3;
  int iVar4;
  ushort uVar5;
  int iVar6;
  uint uVar7;
  uint uVar8;
  ushort *palptr;
  int i;
  int in_stack_00000010;
  uint in_stack_00000014;
  int in_stack_00000018;
  uint in_stack_0000001c;
 
  palptr = this->Palette;
  for (i = 0; i < 256; i = i + 1) {
    iVar4 = i * 3;
    uVar7 = -(8 - rbits);
    if (8 - rbits < 1) {
      iVar6 = (uint)*(byte *)(iVar4 + (int)p24) << (uVar7 & 31);
    }
    else {
      iVar6 = (int)(uint)*(byte *)(iVar4 + (int)p24) >> (~uVar7 & 31) + 1;
    }
    uVar7 = (uint)*(byte *)((int)p24 + iVar4 + 1);
    uVar8 = -(8 - in_stack_00000010);
    if (8 - in_stack_00000010 < 1) {
      iVar3 = uVar7 << (uVar8 & 31);
    }
    else {
      iVar3 = (int)uVar7 >> (~uVar8 & 31) + 1;
    }
    if ((int)in_stack_00000014 < 0) {
      uVar1 = (ushort)(iVar3 >> (~in_stack_00000014 & 31) + 1);
    }
    else {
      uVar1 = (ushort)(iVar3 << (in_stack_00000014 & 31));
    }
    uVar7 = (uint)*(byte *)(iVar4 + 2 + (int)p24);
    uVar8 = -(8 - in_stack_00000018);
    if (8 - in_stack_00000018 < 1) {
      iVar4 = uVar7 << (uVar8 & 31);
    }
    else {
      iVar4 = (int)uVar7 >> (~uVar8 & 31) + 1;
    }
    if (rshift < 0) {
      uVar5 = (ushort)(iVar6 >> (~rshift & 31U) + 1);
    }
    else {
      uVar5 = (ushort)(iVar6 << (rshift & 31U));
    }
    if ((int)in_stack_0000001c < 0) {
      uVar2 = (ushort)(iVar4 >> (~in_stack_0000001c & 31) + 1);
    }
    else {
      uVar2 = (ushort)(iVar4 << (in_stack_0000001c & 31));
    }
    *palptr = uVar5 | uVar1 | uVar2;
    palptr = palptr + 1;
  }
  return;
}


В других базах эта функция inline, находится внутри конструкторов.
TPalette16::TPalette16(class TPalette24 const & p24, int rbits, int rshift, int gbits, int gshift, int bbits, int bshift);
TPalette16::TPalette16(char const * name,TPalette24 const & p24, int rbits, int rshift, int gbits, int gshift, int bbits, int bshift);
В SoD выглядит так:
 
Код: Выделить всё
TPalette16 *__thiscall TPalette16::TPalette16(
        TPalette16 *this,
        const TPalette24 *p24,
        int rbits,
        int rshift,
        int gbits,
        int gshift,
        int bbits,
        int bshift)
{
  int v8; // ebx
  int v9; // edi
  char v11; // cl
  __int16 *Palette; // esi
  __int16 *v13; // eax
  int v14; // ebx
  int v15; // edi
  bool v16; // zf
  char gbits_3; // [esp+27h] [ebp+17h]
  int bbitsa; // [esp+2Ch] [ebp+1Ch]

  resource::resource(this, 0, RType_misc);
  v11 = 8 - gbits;
  this->resource::resource::vftable = (resource::vftable *)&TPalette16::`vftable';
  gbits_3 = 8 - bbits;
  Palette = this->Palette;
  v13 = &p24->Palette[1];
  bbitsa = 256;
  while ( 1 )
  {
    ++Palette;
    LOBYTE(v8) = *((_BYTE *)v13 - 1) >> v11;
    v13 = (__int16 *)((char *)v13 + 3);
    LOWORD(v9) = (unsigned __int8)v8;
    LOWORD(v8) = (unsigned __int8)(*((_BYTE *)v13 - 5) >> (8 - rbits));
    v14 = v8 << rshift;
    v15 = v14 | (v9 << gshift);
    LOWORD(v14) = (unsigned __int8)(*((_BYTE *)v13 - 3) >> gbits_3);
    v8 = v14 << bshift;
    v9 = v8 | v15;
    v16 = bbitsa == 1;
    *(Palette - 1) = v9;
    --bbitsa;
    if ( v16 )
      break;
    v11 = 8 - gbits;
  }
  return this;
}


Я еще не до конца понял, как работают TPalette16 и TPalette24, т.к. особо не вникал, но впринципе можно с нуля алгоритмы все эти переписать.
Вид TPalette16 в SoD:
Код: Выделить всё
class TPalette16 : public resource
{
short Palette[256];
}


TPalette24 в SoD:
Код: Выделить всё
class TPalette16 : public resource
{
short Palette[384];
}


Самые сложные функции - с игровой графикой, с точки зрения декомпилирования. Только начал работать с этим, а разобрал пока что только TPalette16::Gray(), одновременно смотря в 3 базы, соединяя воедино всю информацию.
Код: Выделить всё
void TPalette16::Gray()
{

    ushort * pal_ptr = this->Palette;
    ushort const rdiv = std::numeric_limits<int>::max() / TPalette16::red_mask;
    ushort const gdiv = std::numeric_limits<int>::max() / TPalette16::green_mask;
    ushort const bdiv = std::numeric_limits<int>::max() / TPalette16::blue_mask;

    for (uchar i = 10; i < 256; ++i )
    {
      pal_ptr[i] = rdiv & (TPalette16::red_mask)
      | gdiv & (TPalette16::green_mask)
      | bdiv & (TPalette16::blue_mask);
    }

}
Последний раз редактировалось void_17 25 дек 2021, 08:07, всего редактировалось 2 раз(а).
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: Как создать плагин для HD мода

Сообщение void_17 » 25 дек 2021, 07:56

Цитата:
Добавлю про void_17. Мне всегда его вопросы казались странными и оторванными от темы. Если честно, я думал, что человек вообще далёк от темы и только учится


Ну кстати, весной этого года я действительно учился не то что хуки писать, а вообще программировать, т.к. я не знал, что такое класс или функция...
Поэтому прогресс на лицо.
 
Думаю на джуна вполне потяну, еще бы фичи С++17/20 глянуть и можно подаваться на джуна 300кк/наносек.


Цитата:
А оказывается, он делал то, что я считаю революцией 2021-го в моддинге Героев 3. Что ж, хочется и себя похвалить ленивого: я смог убедить, что код RoE стоит внимания и усилий. Но если копнуть глубже, то оригинальные посты о базе Dreamcast принадлежат Херомант'у. Просто никто из нас не понимал/ленился разбираться в том, что может дать дебажная инфа в Dreamcast для моддинга в целом.


А это зря. Я действительно не понимал, почему вы все эту самую базу просто напросто в лоб игнорировали. Это же халява прямо перед носом. Даже без дампа здесь уже огромное количество информации, моя база доказала это. Может кому-то лень было переносить сигнатуры, но это все же нужно было сделать, это однозначно стоило того.

А Херомант открыл лишь верхушку айсберга. Да и объективно, тогда в 2020, ему эта инфа напрочь не сдалась. Он выдрал лежащие на поверхности названия исполняемых файлов и с этим конец, мол, просто как интересный факт, гляньте, ребята, больше ничего сказать не могу. И на этом остановился. А зряяя...

Да и впринципе, Херомант, как и многие другие воговцы, очень консервативные ребята, прям до невозможного. Дальше ERM-а и древней воговской базы из нулевых им особо ничего не интересно, кстати до сих пор, когда уже у нас есть такая база и дамп.. Я же продвигаю более современный подход к реверсингу, более эффективный и стандартизированный, полагаю, что AlexSpl и тем более RoseKavalier ценят такой подход.

Цитата:
которая не лежала на поверхности, между прочим

Совет на будущее можно сформировать: видите экзешник с сигнатурами -- смело пробуйте дампать, вдруг вам повезет... Жаль, что в Героях 2, несмотря на сигнатуры, нет информации о типах и прочего.. А ведь там код гораздо проще и нет STL функций и типов вообще, по-сути, у нас был бы готовый код героев 2.
Вернуться к началу

Пред.След.

Вернуться в Общий раздел

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4