Объявления
Поздравляем
VDV_forever


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

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

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

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

Сообщение as239 » 21 мар 2019, 15:44

Сделал сдвиг блоков, через перестановку объектов.
Код: Выделить всё
bool IsReplaceable( int ObjType )
{
//   bool IsArt = ( ObjType == 65 || ObjType == 66 || ObjType == 67 || ObjType == 68 || ObjType == 69 || ObjType == 5 );
   bool IsArt = ( ObjType == 5 );
   bool IsRes = ( ObjType == 79 );
   bool IsShc = ( ObjType == 81 );
   bool IsScr = ( ObjType == 93 );
   bool IsChe = ( ObjType == 101 );
   bool IsPan = ( ObjType == 6 );
   bool IsOrh = ( ObjType == 12 ); //Костер

   return ( IsArt || IsRes || IsShc || IsScr || IsChe || IsPan );
}

void ReplaceObject( _Object_ *obj, int addX, int addY, int CurObjSubtype ){

   _GameMap_ *map = &o_GameMgr->Map;
   int mapSize = o_GameMgr->GetMapWidth();
   int CurX = obj->x;
   int CurY = obj->y;
   int ofsetX = CurX+addX;
   int ofsetY = CurY+addY;
   if ( CurX >= mapSize-1 || CurY >= mapSize-1 ) return;

   _List_<_Object_> *objects = &map->Objects;
   _List_<_Template_> *templates = &map->Templates;

   for (_Object_ *objReplace = objects->Data; objReplace < objects->EndData; objReplace++)
   {
      if ( objReplace->x >= mapSize-1 || objReplace->y >= mapSize-1 ) continue;
      if ( objReplace->x <= 0 || objReplace->y <= 0 ) continue;
   
      _Template_ *tempR = &templates->Data[objReplace->template_id];
      bool IsX = false, IsY = false;
      if ( addX != 0 ) {
         IsY = ( objReplace->y == CurY-1 || objReplace->y == CurY || objReplace->y == CurY+1 );
         IsX = ( objReplace->x == ofsetX );
      }
      else if ( addY != 0 ) {
         IsX = ( objReplace->x == CurX-1 || objReplace->x == CurX || objReplace->x == CurX+1 );
         IsY = ( objReplace->y == ofsetY );
      }
      if ( IsX && IsY && IsReplaceable( tempR->ObjType ) ) {
         obj->x = objReplace->x;
         obj->y = objReplace->y;
         //continue;
         objReplace->x = CurX;
         objReplace->y = CurY;         
         return;
      }
   }
}


int __stdcall shiftBlocks(LoHook* h, HookContext* c)
{
   _GameMap_ *map = &o_GameMgr->Map;
   _List_<_Template_> *templates = &map->Templates;
   _List_<_Object_> *objects = &map->Objects;
   _MapItem_ *MapItemLeft, *MapItemRight, *MapItemUp, *MapItemDown, *MapItemCur;


   for (_Object_ *obj = objects->Data; obj < objects->EndData; obj++) {
      _Template_ *temp = &templates->Data[obj->template_id];
      MapItemCur = map->GetItem( obj->x, obj->y, obj->z );
      if (temp->ObjType != 54) continue;

      MapItemRight = map->GetItem( obj->x+1, obj->y, obj->z);
      MapItemLeft = map->GetItem( obj->x-1, obj->y, obj->z);
      MapItemUp = map->GetItem( obj->x, obj->y-1, obj->z);
      MapItemDown = map->GetItem( obj->x, obj->y+1, obj->z);

      if ( MapItemRight->road )  {
         ReplaceObject( obj, -1, 0, temp->ObjSubtype );
      }
      else if ( MapItemLeft->road )  {
         ReplaceObject( obj, +1, 0, temp->ObjSubtype );
      }
      else if ( MapItemUp->road )  {
         ReplaceObject( obj, 0, +1, temp->ObjSubtype);
      }
      else if (MapItemDown->road )  {
         ReplaceObject( obj, 0, -1, temp->ObjSubtype);
      }
   }
   return EXEC_DEFAULT;
}

_PI->WriteLoHook(0x4FDF64, shiftBlocks);

Все работает как задумано.
Вот только иногда вылетает создание карты на этих строчках
Код: Выделить всё
         obj->x = objReplace->x;
         obj->y = objReplace->y;

Никак не могу понять в чем проблема.
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

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

Сообщение RoseKavalier » 22 мар 2019, 02:37

Ben80 писал(а):

Кто-нибудь знает, как можно для любой выбранной кампании сделать доступным изменение уровня сложности ?
Без редактирования файла кампании, естественно.

Код: Выделить всё
pi->WriteWord(0x458D46, 0x9090);
pi->WriteWord(0x458D50, 0x9090);
pi->WriteWord(0x458D78, 0x9090);

EDIT: see corrrection.

@as239
Are you checking for out-of-map-bounds x and y ? Should be positive and smaller than map size.

Yellow/red tiles are bitfields, from bottom right if memory serves. See description here. It's for h3m format but I can't remember if they do the same for H3 of if reversed like DEF drawing.
Последний раз редактировалось RoseKavalier 24 мар 2019, 13:45, всего редактировалось 1 раз.
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 22 мар 2019, 13:42

RoseKavalier писал(а):

Код: Выделить всё
pi->WriteWord(0x458D46, 0x9090);
pi->WriteWord(0x458D50, 0x9090);
pi->WriteWord(0x458D78, 0x9090);



Спасибо. Я пробовал найти сам, но не смог. Я даже не знаю, как с помощью OllyDbg делать что-то в приложении, и узнавать, какой код при этом выполняется. То есть исследования в Olly у меня только на breakpoint'ах работают.
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

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

Сообщение RoseKavalier » 22 мар 2019, 15:00

Research steps were:
1 - breakpoint at Load Def ~ looking for gspbut3~7.def.
2 - breakpoint on resulting dlgdef's state (offset +16h) to find what hides it
3 - backtrace to function ( 0x458CF0 ) calling hide item ( 0x5FED80(6,6) )
4 - patch
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 22 мар 2019, 21:57

RoseKavalier писал(а):

Код: Выделить всё
pi->WriteWord(0x458D46, 0x9090);
pi->WriteWord(0x458D50, 0x9090);
pi->WriteWord(0x458D78, 0x9090);



It seems code below works more correct.
Код: Выделить всё
_PI->WriteWord(0x458D50, 0x9090);
_PI->WriteWord(0x458D78, 0x9090);
Вернуться к началу

offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

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

Сообщение as239 » 24 мар 2019, 07:16

Цитата:
Are you checking for out-of-map-bounds x and y ? Should be positive and smaller than map size.

Yes it is:
Код: Выделить всё
     if ( objReplace->x >= mapSize-1 || objReplace->y >= mapSize-1 ) continue;
      if ( objReplace->x <= 0 || objReplace->y <= 0 ) continue;
Вернуться к началу

offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

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

Сообщение as239 » 24 мар 2019, 07:24

Очень обидно - все работает как нужно, количество блоков заметно уменьшается.
Но пользоваться нельзя из-за периодических вылетов.
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 24 мар 2019, 11:21

as239 писал(а):

Очень обидно - все работает как нужно, количество блоков заметно уменьшается.
Но пользоваться нельзя из-за периодических вылетов.


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

Я при отладке люблю использовать запись информации в файл:
Код: Выделить всё
#include <iostream>
#include <fstream>
...
std::ofstream file;
file.open("test1.txt",std::ios::app);
file << "Debug info\n";

file.close();


Последнее время также пытаюсь использовать OllyDbg более активно.
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

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

Сообщение RoseKavalier » 24 мар 2019, 14:30

@as
I copied your code and compiled it, added plugin to my list and started game.
Crash first time, no surprise...

So then I attach debugger to Heroes3 process and run it again.
 
Another option is to attach Visual Studio itself to process and use its debugger. The only issue is it does not read local variables from pointers so you have to modify your code with static variables and static copies of objects. It's temporary fix but it can help.


It again crashes but debugger stops at error, which pinpoints the memory access error as MapItemUp->road which is unallocated memory.

My suspicion was still on out-of-bounds x & y and ... lo-and-behold :smile6:
Код: Выделить всё
MapItemRight = map->GetItem( obj->x+1, obj->y, obj->z);
MapItemLeft = map->GetItem( obj->x-1, obj->y, obj->z);
MapItemUp = map->GetItem( obj->x, obj->y-1, obj->z);
MapItemDown = map->GetItem( obj->x, obj->y+1, obj->z);


No bounds check in shiftBlocks :(
Due to GetItem function arithmetic, it will not crash but return reference to out-of-bounds mapitems.

I fixed it by adding check in the LoHook function and no crash since generating 10 maps so I guess that was it.

I would propose a few code optimizations:

This eliminates unecessary calls to GetMapItem. 100+ instructions of assembly down to < 10
Код: Выделить всё
MapItemRight = MapItemCur + 1;
MapItemLeft = MapItemCur - 1;
MapItemUp = MapItemCur - mapsize;
MapItemDown = MapItemCur + mapsize;


Probably more efficient but also easier to read to my preference)
Код: Выделить всё
bool IsReplaceable(int ObjType)
{
   switch (ObjType)
   {
   case 5:
   case 6:
   case 12:
   case 79:
   case 81:
   case 89:
   case 101:
      return true;
   }
   return false;
}


It will be nice when this type of situation is only in the past!
Изображение
Вернуться к началу

offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

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

Сообщение as239 » 24 мар 2019, 17:25

@RoseKavalier
Thank you so much!
Added this:
Код: Выделить всё
if ( obj->x+1 > mapSize || obj->y+1 > mapSize ) continue;

And there are no crashes.
But now some objects which definitely should be replaced, are not replaced.
That task is too complicated for me. Nothing a can do with it, blocks wins :)
Here is the code I left off:
Код: Выделить всё
   bool IsReplaceable( int ObjType )
{
   return ( ObjType == 5 || ObjType == 79 || ObjType == 81 || ObjType == 93 || ObjType == 101 || ObjType == 6 || ObjType == 12);
}

int __stdcall shiftBlocks(LoHook* h, HookContext* c)
{
   _GameMap_ *map = &o_GameMgr->Map;
   int mapSize = map->size-1;

   _List_<_Template_> *templates = &map->Templates;
   _List_<_Object_> *objects = &map->Objects;
   _MapItem_ *MapItemLeft, *MapItemRight, *MapItemUp, *MapItemDown, *MapItemCur;
 
   int addX=0, addY=0, ofsetX = 0, ofsetY = 0, CurX=0, CurY =0;
   bool IsX = false, IsY = false;

   for (_Object_ *obj = objects->Data; obj < objects->EndData; obj++) {
      _Template_ *temp = &templates->Data[obj->template_id];
      if ( temp->ObjType != 54) continue;
      if ( obj->x+1 > mapSize || obj->y+1 > mapSize ) continue;//|| obj->x <= 0 || obj->y <= 0

      MapItemCur = map->GetItem( obj->x, obj->y, obj->z );
      MapItemRight = map->GetItem( obj->x+1, obj->y, obj->z);
      MapItemLeft = map->GetItem( obj->x-1, obj->y, obj->z);
      MapItemUp = map->GetItem( obj->x, obj->y-1, obj->z);
      MapItemDown = map->GetItem( obj->x, obj->y+1, obj->z);

      addX=0; addY=0;
      if ( MapItemRight->road )  {
         addX = -1;
         addY =   0;
      }
      else if ( MapItemLeft->road )  {
         addX =  1;
         addY =   0;
      }
      else if ( MapItemUp->road )  {
         addX =  0;
         addY =   1;
      }
      else if ( MapItemDown->road )  {
         addX =  0;
         addY =   -1;
      }
      if ( addX==0 && addY==0 ) continue;

      CurX = obj->x;
      CurY = obj->y;
      ofsetX = CurX+addX;
      ofsetY = CurY+addY;
      for (_Object_ *objReplace = objects->Data; objReplace < objects->EndData; objReplace++) {
         _Template_ *tempR = &templates->Data[objReplace->template_id];

         if ( objReplace->x >= mapSize || objReplace->y >= mapSize   ) continue;//|| objReplace->x <= 0 || objReplace->y <= 0
         if ( IsReplaceable( tempR->ObjType )==false ) continue;

         IsX = false;
         IsY = false;
         if ( addX != 0 ) {
            IsY = ( objReplace->y == CurY-1 || objReplace->y == CurY || objReplace->y == CurY+1 );
            IsX = ( objReplace->x == ofsetX );
         }
         else if ( addY != 0 ) {
            IsX = ( objReplace->x ==  CurX-1 || objReplace->x == CurX || objReplace->x == CurX+1 );
            IsY = ( objReplace->y == ofsetY );
         }
         if ( !IsX || !IsY ) continue;

         obj->x = objReplace->x;
         obj->y = objReplace->y;
         objReplace->x = CurX;
         objReplace->y = CurY;
         break;
      }
   }

   return EXEC_DEFAULT;
}
....._PI->WriteLoHook(0x4FDF64, shiftBlocks);
Вернуться к началу

Пред.След.

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

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

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