avatar_SmallHabit

Как загрузить модели и создать модельку в клиенте MU Online в 2021 году

Автор SmallHabit, 2010 Апр. 04, 13:11

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

Ключевые слова [SEO] клиент muмодели mu online*.smd форматсоздание моделей в mu online

SmallHabit

И так, вчера я выкладывал програмку MilkShape 3D для редактирования *.smd файлов, сегодня же я хотел с вами поделится способом загрузки этих файлов в клиент. Т.е - Мы создаём модельку в программе, сохраняем её как *.smd и можем смело заходить в игру не опасаясь того-что мы не у видим свою модель.

Для начала создадим проект в студии, это будет динамичная библиотека(DLL). Далее создаём файл исходного кода(CPP) и копируем туда этот код :

//=================================
// LCTeam 1.00L Main Project v0.1b
// Started : 30.01.2010
// Coder : SmallHabit
//=================================

#include <windows.h>
#include "Models.h"
//#include "Utils.h"

//Structure
ItemStruct Items[512];

// SMD Items Loader
int InitItems()
{
//Jewel Of Luck (S:14, I:140)
strcpy( Items[0].ModelName,"Jewel23.smd");
strcpy(Items[0].ModelPath,"Data\Item\");
strcpy(Items[0].TextureDir,"Item\");
Items[0].Section = MISC3;
Items[0].Id = 140;

return 1;
}

// Load SMD Model to Memory
int LoadModel(char dir[128],char model[64],char texdir[128],int section,int id)
{
// If there is model name
if(model[0] != 0)
{
LoadSMD(section+id,dir,model,"end");
}

// If our model have a Texture then we must load it.
if(texdir[0] != 0)
{
// This function loads OZT and OZJ images directly to our loaded model.
LoadTEX(section+id,texdir,0x2901,0x2600,1);
}
return 1;
}

// Load Model Wrapper for Animated models like Wings or Bows
void LoadDMD()
{
for ( int a = 0; a < 64; a++ )
{
LoadModel ( Items[a].ModelPath , Items[a].ModelName , Items[a].TextureDir , Items[a].Section , Items[a].Id);
}

//Load Models with Animations

//LoadSMD( MISC1 + 100 , "Data\Item\" , "wings_demonic.smd" , "wings_demonic_fly.smd" , "wings_demonic_fly.smd" ,  "end" );
//LoadTEX( MISC1 + 100  , "Item\" , 0x2901 , 0x2600 , 1);

//LoadSMD( BOW + 30 , "Data\Item\" , "dge_bow_1.smd" , "dge_bow_1_shot.smd" ,  "end" );
//LoadTEX( BOW + 30  , "Item\" , 0x2901 , 0x2600 , 1);
}

Чуть ниже я обьясню как именно загружать новые модельки. Далее создаём файл заголовков(H), и копируем в него следующий код :

//=================================
// LCTeam 1.00L Main Project v0.1b
// Started : 30.01.2010
// Coder : SmallHabit
//=================================

//Item Structure
typedef struct Item
{
char ModelName[64];
char ModelPath[128];
char TextureDir[128];
int Section;
int Id;
}ItemStruct;

extern ItemStruct Items[512];

// Function Types
typedef int(*TLoadSMD) ( ... );

// Main Functions
TLoadSMD LoadSMD = (TLoadSMD) 0x005F204E; //1.00L Blue
TLoadSMD LoadTEX = (TLoadSMD) 0x005F1B90; //1.00L Blue

// Items Declarations
#define SKILL  0xC2 //1.00L Blue
#define SWORD  0x365 //1.00L Blue
#define AXE    0x565 //1.00L Blue
#define MACE  0x765 //1.00L Blue
#define SPEAR  0x965 //1.00L Blue
#define BOW    0xB65 //1.00L Blue
#define STAFF  0xD65 //1.00L Blue
#define SHIELD 0xF65 //1.00L Blue
#define HELM  0x1165 //1.00L Blue
#define ARMOR  0x1365 //1.00L Blue
#define PANTS  0x1565 //1.00L Blue
#define GLOVES 0x1765 //1.00L Blue
#define BOOTS  0x1965 //1.00L Blue
#define MISC1  0x1B75 //1.00L Blue
#define MISC2  0x1D65 //1.00L Blue
#define MISC3  0x1F65 //1.00L Blue
#define SCROLL 0x2165 //1.00L Blue

Далее делаем так чтобы при запуске нашей библиотеки вызывалась функция LoadDMD(). И загружаем нашу библиотеку маином. Хотелось бы заметить что библиотеку надо грузить не сразу после запуска Маин, а через 2-3 секунды после.

Теперь о том, как же задать имя файла нашей модели и на какую вещь мы будем её грузить.

Находим в коде следующее :
//Jewel Of Luck (S:14, I:140)
strcpy( Items[0].ModelName,"Jewel23.smd");
strcpy(Items[0].ModelPath,"Data\Item\");
strcpy(Items[0].TextureDir,"Item\");
Items[0].Section = MISC3;
Items[0].Id = 140;

ModelName - имя нашей модели(грузится только *.smd формат)
ModelPath - Путь где моделька лежит
TextureDir - Папка где лежат текстуры(стоит заметить что грузит он только текстуры которые используются маином, т.е. свои использовать нельзя)
Section - Секция вещи, например MISC3 = 14 секции, это та где находится Jewel of Soul, Jewel of Bless и т.д.
ItemId - номер вещи в игре, важно выбирать такой номер который не занят уже существующей вещью( открываем item.txt на сервере чотбы узнать свободный ID). Макс. значение 512.

Т.е если хотим чтобы вещь в игре создавалась при помощи команды - /item 14 142 0 0 0 0 0

То добавляем после строчки Items
  • .Id = 140
  • следующее :
//Ваша вешь (S:14, I:142)
strcpy( Items[1].ModelName,"ИмяФайла.smd");
strcpy(Items[1].ModelPath,"Data\Item\");
strcpy(Items[1].TextureDir,"Item\");
Items[1].Section = MISC3;
Items[1].Id = 142;
Ну и далее по аналогии. Макс. кол-во новых вещей - 512 штук)

Так-же хочу заметить что после редактирования модельки в Милке, формат текстур ставится bmp, а нам нужен jpg или tga зависит от того какой формат тектсуры используется. Открываем наш smd файл hex эдитором, и заменяем все .bmp на .jpg, и сохраняем файл. Всё, теперь наша моделька грузится.



Так-же для каждого клиента оффсеты функций загрузки моделей будут разными - я использовал оффсеты для клиента Mu Blue 1.00L версии. И также использовал - Items Declarations для Mu Blue 1.00L, если вы хотите зделать тоже самое для вашего клиента вам прийдётся найти эти значения.

Этот способ должен работать на всех версиях клиента от старых и до самых новых!!!

**Если кто-то знает как подгружать новые текстуры в клиент, буду очень благодарен за помощь.

З.Ы. Не забываем говорить Спасибо.


Profesor08

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

ACGLeGrand

#2
А теперь я выложу свой способ загрузки модельки и текстуры, дабы особо умные не тыкали мне, что мой клиент сделан Хоббитом.

Функция грузит BMD-модель(SMD как таковая была не нужна, у меня P.Tools), а также подгружает для нее текстуру(привет Хоббит)
void LoadThisFuckingModelByITEMID(int ItemID,char* ModelName,char* FolderFrom,char* WayFrom)
{
_asm
{
PUSH -1
PUSH ModelName
PUSH WayFrom
PUSH ItemID
mov eax,BMDModelLoad
CALL eax

PUSH 1
PUSH 0x2600
PUSH 0x2901
PUSH FolderFrom                   ; |Arg2 = 0090175C ASCII "Item"
PUSH ItemID                                 ; |Arg1 = 00001FF1
mov eax,OpenTexture
CALL eax
}
}

Подстановочная функция которая грузит камушки и грузит вырезанную модельку Jof Guardian.
__declspec(naked) void PatchMainForLoadModels()
{
LoadThisFuckingModelByITEMID(ITEM_IN_MAIN(14,181),"BlueJewel",CustomzFolder,WaytoCustomz);
LoadThisFuckingModelByITEMID(ITEM_IN_MAIN(14,182),"BlackJewel",CustomzFolder,WaytoCustomz);
LoadThisFuckingModelByITEMID(ITEM_IN_MAIN(14,183),"RedJewel",CustomzFolder,WaytoCustomz);
LoadThisFuckingModelByITEMID(ITEM_IN_MAIN(14,184),"GreenJewel",CustomzFolder,WaytoCustomz);

_asm
{
PUSH -1                           ; /Arg4 = FFFFFFFF
PUSH 0x0090C118                   ; |Arg3 = 00900014 ASCII "suho"
PUSH 0x0090C120                  ; |Arg2 = 0090001C ASCII "DataItem"
PUSH 0x1F91                       ; |Arg1 = 00001F84
mov eax,BMDModelLoad
CALL eax                    ; Main_Ins.005F1BC3
ADD ESP,0x10
mov eax,ReturnOffset
JMP eax
}
}


char* WaytoCustomz = "Data\LeGrandCustom\";
char* CustomzFolder = "LeGrandCustom\";

#define FuckAdder 882
#define ITEM_IN_MAIN(x,y) ((x)*512+(y)+FuckAdder)
FuckAdder - это число, которое вебзен увеличивает с каждым клиентом. Является добавочным числом к модельке, для чего? Я не знаю.
Чтобы найти факаддер, вам нужно:
Открыть свой майн в дебаггере
Найти слово "suho"
Цитировать005F91C2  |. 6A FF          PUSH -1                                  ; /Arg4 = FFFFFFFF
005F91C4  |. 68 18C19000    PUSH MAIN.0090C118                       ; |Arg3 = 0090C118 ASCII "suho"
005F91C9  |. 68 20C19000    PUSH MAIN.0090C120                       ; |Arg2 = 0090C120 ASCII "DataItem"
005F91CE  |. 68 911F0000    PUSH 1F91                               ; |Arg1 = 00001F91
005F91D3  |. E8 2BC9FFFF    CALL MAIN.005F5B03                       ; MAIN.005F5B03
005F91D8  |. 83C4 10        ADD ESP,10
Открыть калькулятор
Ввести туда 1F91 и вычесть из него 1C1F
Полученную разницу их HEX перевести в DEC и заменить в FuckAdder.


#define LoadModel_Offset 0x05F91C2
#define BMDModelLoad 0x005F5B03
#define ReturnOffset 0x005F91DB
#define OpenTexture 0x005F5450

struct DataJMP
{
BYTE Command;
DWORD PointerToFunc;
};


//Patch Loadmodel
DataJMP ModelJMP;
SetNop(LoadModel_Offset,25);
ModelJMP.Command=0xE9;
ModelJMP.PointerToFunc=(DWORD)&PatchMainForLoadModels;
memcpy((int*)LoadModel_Offset,&ModelJMP,sizeof(ModelJMP));
HookThis((DWORD)&PatchMainForLoadModels,LoadModel_Offset); // no needed, just patching...
Хукаем функцию загрузки моделек, и грузим нашу модель и текстуру к ней.

Совет тем кто хочет рыть клиент:
Если вы слабак в с++ и полный нулина в disASM, не беритесь, только время потратите.

Средний майн, требует примерно 20 оффсетов.

моя инсоминовская дллка содержит около 50 оффсетов... Ужось..  ^_^

Blue 1.00o майн...

SmallHabit

ACGLeGrand ну так, у тебя грузит bmd, а у меня smd =) и никакой P. Tools не нужен. За то есть выбор - грузить bmd или smd =)

Hose


Ember

отличный гайд
автору спасибо большое, пригодилось и еще не раз пригодится

8BitCore

Как задать чтоб подгрузка шла через время, а не при запуске майна?

Enget

Извините что прошу,но можете пожалуйста сделать  гайд для "чайников"?

Simp1e


7mm

Интересно, спасибо.

Кстати, парни, откройте для себя макросы :)

#define API_CALL(F,...) (API_TYPE_##F API_ADDR_##F)(__VA_ARGS__)

#define API_ADDR_LoadBmdFile 0x005FD723
#define API_TYPE_LoadBmdFile (int (__cdecl *)(int, char *, char *, int))

#define API_ADDR_LoadTxtFile 0x005FD070
#define API_TYPE_LoadTxtFile (int (__cdecl *)(int, char *, int, int, int))

... кде-то в коде:

API_CALL(LoadBmdFile, ITEM_ID(12, 240), "Data\Custom\Item\", "WingN", 1);
API_CALL(LoadTxtFile, ITEM_ID(12, 240), "Custom\Item\", 0x2901, 0x2600, 1);


Цитата: 8BitCore от 2011 Янв. 22, 21:03  Как задать чтоб подгрузка шла через время, а не при запуске майна?

В main.exe есть оффсет, содержащий переменную -- состояние игры. Значение, равное 5 соответствует началу игры (2 - выбор сервера, 4 - выбор персонажа, 5 - в игре). Можно отслеживать это значение с небольшим периодом. Для main версии 1.03A+ оффсет будет такой:

#define PTR_CLIENT_STATE         0x0092B0A4

Соответственно проверка:

while (REF_32(PTR_CLIENT_STATE) != 5) {
Sleep(10);
}

Похожие темы (5)