Jump to content

Search the Community

Showing results for tags 'howto'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • M2Tec
    • M2Tec - News
    • M2Tec - Rules
    • Feedback
  • Metin2
    • Binaries & Clients/Serverfiles
    • Discussions & Opinions
    • Questions
    • Guides & Releases
    • 2D/3D Graphics
    • File requests
    • Private Servers
  • Metin2 Mobile
    • Metin2 Mobile Announcements
    • Discussions & Opinions
  • General
    • Programming / Scripts
    • Tools/Programs
    • Releases
  • Marketplace
    • Buy
    • Sell & Services
    • Freebies
  • Offtopic
    • Introductions
    • General Talk
    • Games Talk
    • Music/Videos/Art
    • M2tec Birthdays
  • Helfer's Themen
  • M2tec Files's Updates

Product Groups

  • Premium
  • Source
  • Advertisement
  • Donate

Categories

  • M2Tec Files
  • Kori Files
  • Starfoul - ServerFiles

Categories

  • Support
  • Sales
  • Administration
  • Other

Blogs

There are no results to display.

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


About Me

Found 63 results

  1. Hello, I want share a simple addon for more effective debugging crashes and exceptions on Windows. Technical details about mini dump: [Hidden Content] winminidump.c #define __LIBTHECORE__ #include "stdafx.h" #include "winminidump.h" #ifdef __WIN32__ #include <DbgHelp.h> #pragma comment(lib, "dbghelp.lib") // Custom minidump callback BOOL CALLBACK MiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, PMINIDUMP_CALLBACK_OUTPUT pOutput) { BOOL bRet = FALSE; if (!pInput || !pOutput) return FALSE; switch (pInput->CallbackType) { case IncludeModuleCallback: { bRet = TRUE; } break; case IncludeThreadCallback: { bRet = TRUE; } break; case ModuleCallback: { if (!(pOutput->ModuleWriteFlags & ModuleReferencedByMemory)) { pOutput->ModuleWriteFlags &= (~ModuleWriteModule); } bRet = TRUE; } break; case ThreadCallback: { bRet = TRUE; } break; case ThreadExCallback: { bRet = TRUE; } break; case MemoryCallback: { bRet = FALSE; } break; case CancelCallback: break; } return bRet; } bool CreateMiniDump(EXCEPTION_POINTERS* pExceptionInfo) { fprintf(stderr, "Exception handled: %p", pExceptionInfo); if (IsDebuggerPresent()) DebugBreak(); char szProcessName[MAX_PATH]; GetModuleFileNameA(NULL, szProcessName, MAX_PATH); std::string strFileName = std::string(szProcessName); if (strFileName.size() > 0) { size_t iLastSlash = strFileName.find_last_of("\\/"); strFileName = strFileName.substr(iLastSlash + 1, strFileName.length() - iLastSlash); } time_t t; time(&t); struct tm *tinfo; tinfo = localtime(&t); char szDumpName[128]; strftime(szDumpName, sizeof(szDumpName), "dump%Y%m%d_%H%M%S.dmp", tinfo); char szDumpPath[256]; sprintf(szDumpPath, "%s_%s", strFileName.c_str(), szDumpName); HANDLE hFile = CreateFileA(szDumpPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (!hFile || hFile == INVALID_HANDLE_VALUE) { fprintf(stderr, "Exception dump file is not created. Error code: %u Path: %s", GetLastError(), szDumpPath); return false; } // Create the minidump MINIDUMP_EXCEPTION_INFORMATION mdei; mdei.ThreadId = GetCurrentThreadId(); mdei.ExceptionPointers = pExceptionInfo; mdei.ClientPointers = FALSE; MINIDUMP_CALLBACK_INFORMATION mci; mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback; mci.CallbackParam = 0; MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory); BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, (pExceptionInfo != 0) ? &mdei : 0, 0, &mci); if (!rv) { fprintf(stderr, "Exception dump can not created. Error code: %u", GetLastError()); } else { fprintf(stderr, "Exception dump successfully created."); } // Close the file CloseHandle(hFile); return true; } LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS * pExceptionInfo) { if (pExceptionInfo && pExceptionInfo->ExceptionRecord) { if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CreateMiniDump, pExceptionInfo, 0, NULL); if (hThread && hThread != INVALID_HANDLE_VALUE) { WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); } } else { CreateMiniDump(pExceptionInfo); } } return EXCEPTION_EXECUTE_HANDLER; } bool setup_minidump_generator() { if (SetUnhandledExceptionFilter(ExceptionFilter)) { fprintf(stderr, "Mini dump generator succesfully created!"); return true; } fprintf(stderr, "Mini dump generator can NOT created! Error code: %u", GetLastError()); return false; } #else bool setup_minidump_generator() { return true; } #endif winminidump.h #ifndef __INC_LIBTHECORE_WINMINIDUMP_H__ #define __INC_LIBTHECORE_WINMINIDUMP_H__ #ifdef __cplusplus extern "C" { #endif extern bool setup_minidump_generator(); #ifdef __cplusplus }; #endif #endif Copy .c file to ServerSrc\libthecore\src and .h file to ServerSrc\libthecore\include. Define new files to your Makefile or CMakeLists.txt, and to libthecore project from your server's visual studio solution Open game\src\main.cpp and call new header file #include "../../libthecore/include/winminidump.h" Now search for your entrypoint int main(int argc, char **argv) Add new lines at the beginning of the function if (setup_minidump_generator() == false) return 1; Open your db\src\main.cpp and call new header file #include "../../libthecore/include/winminidump.h" Now search for your entrypoint int main() Add new lines at the beginning of the function if (setup_minidump_generator() == false) return 1; If you are using rubinum's auth core you can implement same routine to "int main(int argc, char** argv)" function from auth\src\main.cpp If you take any exceptions after making these edits, The core will create a memory dump with the file name like CORE_FILE_NAME_dump_DATE.dmp and you can easily analyze this file via visual studio just like freebsd ".core" files.
  2. Alle "Releases" in diesem Beitrag sind durch pub. "Systeme" oder Eigenarbeit in diesen Beitrag gelangt. Alles was hier Vorgestellt wird wurde von mir getestet auf denn "Fliege reworked V2 Files" 1. Source Compile Nachricht ändern. [C++] [✔] 2. Kamera Modus Fern* Hinzufügen. [Python][✔] 1. Source Compile Nachricht ändern. 2. Kamera Modus Fern* Hinzufügen.
  3. MEGA Die Spoiler verkackt.. Haha.. Peace! Ich sehe des Öfteren das viele User Probleme mit der Scale Funktion haben. Die Lösungen die Vorgeschlagen werden oder auch die Scale Funktionen aus denn einzelnen Files sind meistens Schrott. (Sorry dafür^^) Dann gibt es noch das Problem das die Zwei Funktionen sich beißen wenn man Sie nicht vernünftig voneinander trennt. Um Auf denn Punkt zu kommen Poste ich Heute denn Code aus meinem Source. Die Item Scale ist nur für das Schulterband System! Jedoch die Monster Scale kann für alles benutzt werden. (Monster/Pets/Npc usw) Have Fun. Alles Spielt sich im Client Source ab.. Für die Item Scale müsst ihr eines der Sash Systeme verbaut haben! schmeißt einfach die Scale Funktion sofern Sie bei euch nicht geht einfach raus. Wollt ihr nur die Monster Scale - Einfach die Augen auf machen und raus schnippeln. 1. Ordner -> EterGrnLib, Datei-> ThingInstance.cpp Die Include locale_inc.h setzen oder was ihr für eine Datei benutzt wo ihr eure ganzen #defines gesetzt habt. Danach Sucht ihr nach der Funktion void CGraphicThingInstance::DeformNoSkin() und void CGraphicThingInstance::OnDeform() und ersetzt diese mit dem Code im Spoiler. Man Sollte niemals einen Fremden Code einfach Copy & Pasten! Dadurch passieren die Meisten Fehler! Hier könnt ihr jedoch sicher sein das nichts passieren wird.
  4. Hi devs, I think a lot of you are not satisfied with an arrangement of client in default. Well, it is a long way to make it by your conception however I think this might help you a bit. There are a few hardcoded strings that could make a problem for you when creating a binary for more than one language. Here is a simple solution of how can you call those strings from a resource file. Go to the UserInterface > Resource Files and open UserInterface.rs. In Resource View unwrap String Table section and double click on String Table string node. Here you have a simple table with ID, value and caption. Lemme clarify this a bit. ID - An identifier you will use to call a required string. Value - A number that editor use for ordering the strings. Caption - Desired content of a string. To add a new string just click under the last string and fill all the columns. When you are done, save your new string by pressing an Enter key. To call our string use ApplicationStringTable_GetStringz(+two overloads) function. Here is a little example of usage: Old version: void __ErrorPythonLibraryIsNotExist() { LogBoxf("Oh crap! Python libraries are gone."); } New version: void __ErrorPythonLibraryIsNotExist() { LogBoxf(ApplicationStringTable_GetStringz(/*ID of your string.*/)); } Sources: [Hidden Content]
  5. Unser ziel ist es am Ende eine Compilebare ServerSource Maschine zu haben. in der Regel dauert dies so 1 Std dazu braucht Ihr: FreeBSD-9.3-RELEASE-i386-disc1.iso Virtual Box VM Ware Winscp Mindestens Zwei Hände und eine Menge Geduld. zunächst starten wir Virtual Box wir klicken auf Neu und erhalten dieses Fenster diese Maschine nennen wir wie man will in meinem Fall M2Compile nun vergeben wir dem noch ein Bisschen Ram. ich empfehle 4 GB Ram da verläuft das ganze am Reibungslosestem es geht alles ab 1 GB + empfehlenswert ist aber 4 GB nun erzeugen wir eine Virtuelle Festplatte dazu: Erzeugen -> VDI -> Dynamisch erzeugen wählt nun eure Speichergröße so 20 GB in meinem Fall dann wählen wir uns einen Pfad aus empfehlenswert wäre es dann 2 Thread einzustellen nun müssen wir die VDI einstellen unter Massenspeicher auf leer dort Sekundärer Master ausgewählt haben und die FreeBSD-9.3-RELEASE-i386-disc1.iso auswählen als nächstes noch die Netzwerk einstellungen nun sagen wir ihm er soll auf den selben Netzwerkcontroller zugreifen wie der Standartlich bei der Hardware vorhanden ist in meinem fall mein Ethernet Controller ungefähr so sehen dann eure einstellungen aus Nun starten wir die VM mithilfe des Grünen buttons namens Starten dieser bootet nun von alleine von der CD [ENTER] das wählen wir aus und drücken [ENTER] dann müsst ihr einen adminnamen eingeben in meinem fall dann mithilfe von Leertaste die * rausmachen nun bleiben mit mit der auswahl auf src und drücken [ENTER] dann bei Guided auf [ENTER] [Enter] bei Entire Disk einmal mit den pfeiltasten auf Delete und [Enter] dann geht ihr auf Create wir nennen das ganze freebsd-boot und geben ihm 512k und drücken dann auf Create mit [Enter] dann erstellen wir noch eine Festplatte die nennen wir freebsd-ufs und wir geben dem mal so 18 GB mountpoint / wir bestätigen das ganze mit [ENTER] nun erstellen wir noch eine partition wir nennen es swap so als zwischenspeicher falls wir mehrere Festplatten mounten wollen oder oder oder.... [ENTER] so nun gehen wir auf Finish [ENTER] Commit [ENTER] nach kurzem warten sind wir beim in meinem fall nehmen wir als Passwort 123 retypen dies nun tragen wir eine IP ein unter der wir den server erreichen können in meinem fall 192.168.178.13 ihr könnt die selbe nehmen da es eh lokal ist. dort müsst ihr bei 1&1 Nutzern Fritz.box eintragen oben als ipadresse eure ip normalerweise bei IVP4 DNS #1 192.168.178.1 danach Enter hier auf NO nun wählt ihr nochmal Europe aus hier nun durchentern ebenfalls enter da wir keine weiteren User brauchen nun kommen wir zu hier auf NO nun Rebooten wir das ganze aber unmounten gleich noch die CD da die maus gefangen ist STRG (Linke) mit einem Rechtsklick und die CD anklicken Auswurf erzwingen und am besten dann während der bildschirm der virtuellen maschine angezeigt wird. nun sollte er ohne CD einmal booten und wir befinden uns nach einigen sekunden nach dem einloggen mit root 123 nun mit clear machen wir alles weg was auf dem Bildschirm ist normalerweise müssten wir portsnap fetch extract ausführen aber wir sind hier im Jahre 2018 also nicht unbedingt nötig der rest geht von alleine pkg install python Y und [Enter] Ist dies nicht der fall und er kann nix Fetchen hier der Fix: bsdconfig ENTER runter mit pfeiltasten zu dort nun auf hier nun ENTER DHCP ist disabled geht auf DHCP und dann Enter danach sollte dies enable sein das wars. zurück zum python nach pkg install python Y Enter so nachdem wir alles bestätigt haben brauchen wir noch einige sachen. wir geben ein pkg install gmake und entern alles durch nun geben wir ein pkg install makedepend nun noch pkg install devil nun erstellen wir eine Winscp verbindung her nachdem wir diese winscp verbindung hergestellt haben: erstellen wir im ordner Root das verzeichnis metin2 und fügen dort eine beliebige src ein Bei mir im beispiel Fliegesrc also cd /root/metin2/BELIEBIGESOURCE/server/game/src gmake clean gmake -j4 das wars bei fragen einfach melden
  6. Hi everybody, I just share the results of my test after a few months. 1. Less unexplained disconnection related to the game. 2. No more errors related to the sequence in syserrs 3. Server Source & Clients Lightened As you can see, the removal of this system is entirely beneficial since it is an incomplete system causing disconnection in play for no reason. The system also generated this server-side error: On the other hand, if you have deactivated the encryption of the packets on your sources, it will require a lot of other important changes. If you want to do a series of tests you have the opportunity to act in 3 different ways: - #define SEQUENCE_SYSTEM_ENABLED - Comment the code - Delete the code Open input.cpp and search: if (bHeader == HEADER_CG_PONG) sys_log(0, "PONG! %u %u", m_pPacketInfo->IsSequence(bHeader), *(BYTE *) (c_pData + iPacketLen - sizeof(BYTE))); Here, the syslog linked to the Header of the key pong uses the function IsSequence, we will modify it by: if (bHeader == HEADER_CG_PONG) sys_log(0, "PONG! %u", *(BYTE *) (c_pData + iPacketLen - sizeof(BYTE))); Just down you have: if (m_pPacketInfo->IsSequence(bHeader)) { BYTE bSeq = lpDesc->GetSequence(); BYTE bSeqReceived = *(BYTE *) (c_pData + iPacketLen - sizeof(BYTE)); if (bSeq != bSeqReceived) { sys_err("SEQUENCE %x mismatch 0x%x != 0x%x header %u", get_pointer(lpDesc), bSeq, bSeqReceived, bHeader); LPCHARACTER ch = lpDesc->GetCharacter(); char buf[1024]; int offset, len; offset = snprintf(buf, sizeof(buf), "SEQUENCE_LOG [%s]-------------\n", ch ? ch->GetName() : "UNKNOWN"); if (offset < 0 || offset >= (int) sizeof(buf)) offset = sizeof(buf) - 1; for (size_t i = 0; i < lpDesc->m_seq_vector.size(); ++i) { len = snprintf(buf + offset, sizeof(buf) - offset, "\t[%03d : 0x%x]\n", lpDesc->m_seq_vector[i].hdr, lpDesc->m_seq_vector[i].seq); if (len < 0 || len >= (int) sizeof(buf) - offset) offset += (sizeof(buf) - offset) - 1; else offset += len; } snprintf(buf + offset, sizeof(buf) - offset, "\t[%03d : 0x%x]\n", bHeader, bSeq); sys_err("%s", buf); lpDesc->SetPhase(PHASE_CLOSE); return true; } else { lpDesc->push_seq(bHeader, bSeq); lpDesc->SetNextSequence(); //sys_err("SEQUENCE %x match %u next %u header %u", lpDesc, bSeq, lpDesc->GetSequence(), bHeader); } } Add the ifdef, comment or delete the entire code. Look for: CInputHandshake::CInputHandshake() { CPacketInfoCG * pkPacketInfo = M2_NEW CPacketInfoCG; pkPacketInfo->SetSequence(HEADER_CG_PONG, false); m_pMainPacketInfo = m_pPacketInfo; BindPacketInfo(pkPacketInfo); } We will delete the sending of the sequence of the key pong here like this: CInputHandshake::CInputHandshake() { CPacketInfoCG * pkPacketInfo = M2_NEW CPacketInfoCG; // pkPacketInfo->SetSequence(HEADER_CG_PONG, false); m_pMainPacketInfo = m_pPacketInfo; BindPacketInfo(pkPacketInfo); } That's it for the input.cpp, let's open the file desc.cpp: #include "sequence.h" Add a comment to the include. Search and comment the code: m_iCurrentSequence Search and comment the code: m_seq_vector.clear(); Add a comment here too Search again & comment the code: m_seq_vector.clear(); Search: BYTE DESC::GetSequence() { return gc_abSequence[m_iCurrentSequence]; } void DESC::SetNextSequence() { if (++m_iCurrentSequence == SEQUENCE_MAX_NUM) m_iCurrentSequence = 0; } Comment all. Look for: void DESC::push_seq(BYTE hdr, BYTE seq) { if (m_seq_vector.size()>=20) { m_seq_vector.erase(m_seq_vector.begin()); } seq_t info = { hdr, seq }; m_seq_vector.push_back(info); } Comment also the whole function. Let's open the desc.h for the statement. Look for: // sequence 버그 찾기용 데이타 struct seq_t { BYTE hdr; BYTE seq; }; typedef std::vector<seq_t> seq_vector_t; // sequence 버그 찾기용 데이타 Comment on everything. Look for: BYTE GetSequence(); void SetNextSequence(); Comment on the 2 functions. Look for: int m_iCurrentSequence; Comment on the function. Look for: public: seq_vector_t m_seq_vector; void push_seq (BYTE hdr, BYTE seq); Comment everything. Let's open the packet_info.cpp and look for: void CPacketInfo::Set(int header, int iSize, const char * c_pszName, bool bSeq) { if (m_pPacketMap.find(header) != m_pPacketMap.end()) return; TPacketElement * element = M2_NEW TPacketElement; element->iSize = iSize; element->stName.assign(c_pszName); element->iCalled = 0; element->dwLoad = 0; element->bSequencePacket = bSeq; if (element->bSequencePacket) element->iSize += sizeof(BYTE); m_pPacketMap.insert(std::map<int, TPacketElement *>::value_type(header, element)); } Edit by: void CPacketInfo::Set(int header, int iSize, const char * c_pszName) { if (m_pPacketMap.find(header) != m_pPacketMap.end()) return; TPacketElement * element = M2_NEW TPacketElement; element->iSize = iSize; element->stName.assign(c_pszName); element->iCalled = 0; element->dwLoad = 0; /* element->bSequencePacket = bSeq; if (element->bSequencePacket) element->iSize += sizeof(BYTE); */ m_pPacketMap.insert(std::map<int, TPacketElement *>::value_type(header, element)); } Search: bool CPacketInfo::IsSequence(int header) { TPacketElement * pkElement = GetElement(header); return pkElement ? pkElement->bSequencePacket : false; } void CPacketInfo::SetSequence(int header, bool bSeq) { TPacketElement * pkElem = GetElement(header); if (pkElem) { if (bSeq) { if (!pkElem->bSequencePacket) pkElem->iSize++; } else { if (pkElem->bSequencePacket) pkElem->iSize--; } pkElem->bSequencePacket = bSeq; } } Comment the whole function. Now, we will modify all the packages of the CPacketInfoCG :: CPacketInfoCG () function. Search: Set(HEADER_CG_GUILD_SYMBOL_UPLOAD, sizeof(TPacketCGGuildSymbolUpload), "SymbolUpload", false); Edit by: Set(HEADER_CG_GUILD_SYMBOL_UPLOAD, sizeof(TPacketCGGuildSymbolUpload), "SymbolUpload"); Do this for any header with a true or false. You should have something like this: Let's open the packet_info.h and look for: typedef struct SPacketElement { int iSize; std::string stName; int iCalled; DWORD dwLoad; bool bSequencePacket; } TPacketElement; Edit by: typedef struct SPacketElement { int iSize; std::string stName; int iCalled; DWORD dwLoad; //bool bSequencePacket; } TPacketElement; Search: void Set(int header, int size, const char * c_pszName, bool bSeq=false); Edit by: void Set(int header, int size, const char * c_pszName); Search and comment the code: bool IsSequence(int header); void SetSequence(int header, bool bSeq); To conclude the tutorial, open input udp.cpp and search for: Set(1, sizeof(ServerStateChecker_RequestPacket), "ServerStateRequest", false); Edit by: Set(1, sizeof(ServerStateChecker_RequestPacket), "ServerStateRequest"); Finally, remove the 2 sequence files from your source and do not forget to remove them from the makefile. 2) CLIENT PART I will not do any tutorial since this file is never modified so you can take mine (I made one for you as I have disabled the encryption of the packets on my side): Link: Click-here ! Source: Madara, please quote the source if you wish to share this tutorial elsewhere. Sorry for my english, i use google translate, if someone can edit my post for my mistakes
  7. Hello, today i release from my source, the fix for offline shop by great to work good with transmutation system. My source is kori source 1.4 but with fixed bugs. You dont have to replace the whole functions. You can compare with mine. If you install them correctly like i tell you, it should work. Its tested to my server, and it works 100%. Download link: [Hidden Content] I hope I helped, Yours sincerely, VoiD.
  8. serch /source /server /game /src ( questlua_pc.cpp) finde: ALUA(pc_get_informer_item) add under: int pc_give_and_equip_item(lua_State* L) { LPCHARACTER pkCharacter = CQuestManager::instance().GetCurrentCharacterPtr(); if (!pkCharacter || !lua_isnumber(L, 1)) { lua_pushboolean(L, false); return 1; } LPITEM pkItem = ITEM_MANAGER::instance().CreateItem(lua_tonumber(L, 1)); if (pkItem && pkCharacter->EquipItem(pkItem)) { lua_pushboolean(L, true); } else { M2_DESTROY_ITEM(pkItem); lua_pushboolean(L, false); } return 1; } search: { "get_informer_item", pc_get_informer_item }, Add under: { "give_and_equip_item", pc_give_and_equip_item }, on server go to quaest_functions and add a new function: pc.give_and_equip_item now on quests you can add: pc.give_and_equip_item for give and equipes itens.
  9. LIST OF ANTI-CHEATS ONE BIG LIST! YOU CAN FIND MORE AT [Hidden Content] BUT FEW OF THEM WORK ANYMORE 1.FIX ANTICMD FLOOD HACK ZONE PROTECT GM IP FIX SQL injection Messenger Block by LeNnT Anti Wait Hack(ProDamage and etc.) By Koray WALLHACK CLIENTSIDE Fix Moblock/bravery cape hack CHANGE TO SHA256 ENIGMA PROTECTION ANTI SQL INJECTION Anti Yang Bug OFFLINE SHOP SQL INJECTION Blocking P2P Input Link BLOCK API TOOLS FIX EXP EXPLOIT HIDE XTEA KEYS FIX PM KICK WAR EXPLOIT FIX WILL BE ADDED MORE SOON
  10. Hi folks! With this guide you will be able to combine textlines with images, like rubinum does. Usage is simple: emojiTextLine.SetText("|Eemoji/key_ctrl|e + |Eemoji/key_x|e + |Eemoji/key_rclick|e - Direct sell") The files are located in the icon pack, so basically the code will load from icon/{GIVEN_PATH}.tga - in the sample the path for the X is: icon/emoji/key_x.tga Here are the images from rubinum client: Howto: Have fun 😉 Sorry for arab players 😛 , for sure they have also developers, so let's go guys, finish it .
  11. Hello dear Players ! If you find a bug in the game, please report it here, so we can fix it. Atention ! 1. Before you report a bug, please check the list of well-known and fixed bugs. 2. All the bugs must be reported after this model. Bug report example Nickname: Arabu S. Razvan Place or Coordinates: Pyungmo - 369x892 Date & Hour : 1/4/2019 11:30 AM Description: I got stuck in a building ScreenShot: Bug List
  12. Hello, I come to share my knowledge on what I discovered recently on the packets encryption. Some might tell me, but that was already shared by MartySama. In fact, this one is not complete, it has forgotten a very important factor which I will present to you subsequently. But suddenly, you have to wonder what happens if we disable the encryption packets the way he shared it? Well, we risk having an overload in the buffer, which may lead to crash games without error or bugs quite strange. There are different strange bug that I could see, the most common was the fact that we can no longer perform an action that requires an agreement with the game. Example, after 15 minutes of play with some player connected, some will no longer click on an item, or else can not talk etc ... There was a lot of debate about that, I took advice left and right and I drew a problematic. I - Why these bugs where not present before the packet encryption? Simply because the structure has been edited. Indeed, we can see that in the protocol.h of the Game, the function buffer_adjust_size was commented. Also, in the desc.cpp, they completely removed the condition in the function: void DESC::Packet But why? Simply because it is no longer useful, the new system does not require a size adjuster for the buffer (it seems to me) Or, they coded something else that automatically adjusts the size of the buffers but I have not watched yet. II - How to remove the encryption packet system properly? In Common, open service.h and comment this: #define _IMPROVED_PACKET_ENCRYPTION_ In Game now, open protocol.h and search: //buffer_adjust_size(pbuf, length); Edit by this: buffer_adjust_size(pbuf, length); Game, open desc.cpp, and the search the function: void DESC::Packet(const void * c_pvData, int iSize) By this: void DESC::Packet(const void * c_pvData, int iSize) { assert(iSize > 0); if (m_iPhase == PHASE_CLOSE) // 끊는 상태면 보내지 않는다. return; if (m_stRelayName.length() != 0) { // Relay 패킷은 암호화하지 않는다. TPacketGGRelay p; p.bHeader = HEADER_GG_RELAY; strlcpy(p.szName, m_stRelayName.c_str(), sizeof(p.szName)); p.lSize = iSize; if (!packet_encode(m_lpOutputBuffer, &p, sizeof(p))) { m_iPhase = PHASE_CLOSE; return; } m_stRelayName.clear(); if (!packet_encode(m_lpOutputBuffer, c_pvData, iSize)) { m_iPhase = PHASE_CLOSE; return; } } else { if (m_lpBufferedOutputBuffer) { buffer_write(m_lpBufferedOutputBuffer, c_pvData, iSize); c_pvData = buffer_read_peek(m_lpBufferedOutputBuffer); iSize = buffer_size(m_lpBufferedOutputBuffer); } // TRAFFIC_PROFILE if (g_bTrafficProfileOn) TrafficProfiler::instance().Report(TrafficProfiler::IODIR_OUTPUT, *(BYTE *) c_pvData, iSize); // END_OF_TRAFFIC_PROFILER #ifdef _IMPROVED_PACKET_ENCRYPTION_ void* buf = buffer_write_peek(m_lpOutputBuffer); if (packet_encode(m_lpOutputBuffer, c_pvData, iSize)) { if (cipher_.activated()) { cipher_.Encrypt(buf, iSize); } } else { m_iPhase = PHASE_CLOSE; } #else if (!m_bEncrypted) { if (!packet_encode(m_lpOutputBuffer, c_pvData, iSize)) { m_iPhase = PHASE_CLOSE; } } else { if (buffer_has_space(m_lpOutputBuffer) < iSize + 8) { buffer_adjust_size(m_lpOutputBuffer, iSize); if (buffer_has_space(m_lpOutputBuffer) < iSize + 8) { sys_err( "desc buffer mem_size overflow : ", " memsize(%u) ", " write_pos(%u)", " iSize(%d)", m_lpOutputBuffer->mem_size, m_lpOutputBuffer->write_point_pos, iSize); m_iPhase = PHASE_CLOSE; } } else { // 암호화에 필요한 충분한 버퍼 크기를 확보한다. /* buffer_adjust_size(m_lpOutputBuffer, iSize + 8); */ DWORD * pdwWritePoint = (DWORD *) buffer_write_peek(m_lpOutputBuffer); if (packet_encode(m_lpOutputBuffer, c_pvData, iSize)) { int iSize2 = TEA_Encrypt(pdwWritePoint, pdwWritePoint, GetEncryptionKey(), iSize); if (iSize2 > iSize) buffer_write_proceed(m_lpOutputBuffer, iSize2 - iSize); } } } #endif // _IMPROVED_PACKET_ENCRYPTION_ SAFE_BUFFER_DELETE(m_lpBufferedOutputBuffer); } //sys_log(0, "%d bytes written (first byte %d)", iSize, *(BYTE *) c_pvData); if (m_iPhase != PHASE_CLOSE) fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_WRITE, true); } You can compile your game. Do not forget to compile a db also ! EterBase, open ServiceDefs.h and comment: #define _IMPROVED_PACKET_ENCRYPTION_ Userinterface, open Locale.cpp and edit: #define LSS_SECURITY_KEY "testtesttesttest" By this: #define LSS_SECURITY_KEY "1234abcd5678efgh" III - Why would I disable this system? - Connection time LARGEMENT decreased (unused cipher) - Loading time also decreased - Better fluidity (personal opinion) - Size of the game enormously decreased as well as that of the launcher Here is a small video: Hoping that it serves you well! Madara
  13. ITEM_WEAPON Sagt aus dass das Item eine Waffe ist WEAPON_SWORD Sagt aus dass das Item ein Schwert ist WEAPON_DAGGER Sagt aus dass das Item Dolche sind WEAPON_BOW Sagt aus dass das Item ein Bogen ist WEAPON_TWO_HANDED Sagt aus dass das Item eine Zweihandwaffe ist ITEM_TUNABLE Dieses Item kannst du mithilfe von Gegenstand Verzaubern/Verstärken bearbeiten ANTI_MUDANG Dieses Item soll nicht von Schamanen getragen werden WEAR_WEAPON Dieses Item soll im Waffenslot getragen werden LIMIT_NONE Dieses Item hat keine Limitierung ANTI_ASSASSIN Dieses Item kann nicht von einem Ninja getragen werden ANTI_MUSA Dieses Item kann nicht von einem Krieger getragen werden ANTI_SELL Dieses Item kann nicht verkauft werden ANTI_SURA Dieses Item kann nicht von einem Sura getragen werden ITEM_STACKABLE Dieses Item soll sich Stacken können ITEM_QUEST Dieses Item spricht auf Quests aus dem Questordner an ANTI_DROP Dieses Item kannst du nicht fallenlassen ANTI_GIVE Dieses Item kannst du nicht Handeln ANTI_MYSHOP Dieses Item kannst du nicht in einen Privatshop tun ANTI_WOLFMAN Dieses Item kann der Lykaner nicht tragen WEAPON_BELL Sagt aus dass das Item eine Glocke ist WEAPON_FAN Sagt aus dass das Item ein Fächer ist WEAPON_MOUNT_SPEAR Sagt aus dass das Item ein Besonderer Speer ist, (gibt ein Item mit dem Attribut das ist die Lanze) ITEM_ARMOR Sagt aus dass das Item eine Rüstungteil ist ARMOR_BODY Sagt aus dass das Item ein Brustschutz ist, bzw ein Panzer, eine Kleidung oder ein Anzug WEAR_BODY Dieses Item wird im Rüstungsslot getragen ARMOR_HEAD Dieses Item ist ein Helm WEAR_HEAD Dieses Item wird im Helmslot getragen ARMOR_WRIST Dieses Item ist ein Armband WEAR_WRIST Dieses Item wird im Armbandslot getragen ARMOR_EAR Dieses Item sind Ohrringe WEAR_EAR Dieses Item wird im Ohrringslot getragen ARMOR_SHIELD Dieses Item ist ein Schild WEAR_UNIQUE Dieses Item wird im Schildslot getragen ARMOR_NECK Dieses Item ist eine Halskette WEAR_NECK Dieses Item wird im Halskettenslot getragen ARMOR_FOOTS Dieses Item sind Schuhe WEAR_FOOTS Dieses Item wird im Schuhslot getragen ITEM_BELT Dieses Item ist ein Gürtel ITEM_USE Dieses Item kann man Benutzen und verschwindet danach USE_PUT_INTO_BELT_SOCKET Dieses Item benutzt man um Sockel in den Gürtel einzufügen USE_TALISMAN Dieses Item benutzt man als Talisman USE_DETACHMENT Dieses Item benutzt man um Geiststeine aus einem Item zu entfernen USE_POTION Dieses Item ist ein Trank ITEM_SLOW_QUERY Dieses Item wird in die Serverquery geloggt allerdings erst nach einiger Zeit USE_ABILITY_UP Dieses Item erhöht temporär oder Permanent die Angegebenen Stats ITEM_CAMPFIRE Dieses Item wird benutzt zum rufen einer Feuerstelle USE_SPECIAL Dieses Item wird durch Source oder sonstige aufforderungen eingestellt / Quests ITEM_RESOURCE Dieses Item ist ein Erzeugnis aus einem Anderem Item RESOURCE_FISHBONE Dieses Item kommt raus wenn man Fische tötet USE_BAIT Dieses Item kann man als Fischköder benutzen ITEM_FISH Dieses Item ist ein Fisch FISH_ALIVE Dieses Item ist ein Lebendiger Fisch FISH_DEAD Dieses Item ist ein Toter Fisch USE_POTION_NODELAY Dieses Item wirkt instant in kraft und kann pausenlos genutzt werden USE_CLEAR Dieses Item entfernt alle Temporären Boni“s USE_INVISIBILITY Dieses Item erzeugt den Unsichtbarkeits effekt für ein paar sekunden SPECIAL_MAP Dieses Item bekommt man nur auf bestimmten maps ITEM_SPECIAL Dieses Item wird durch die Source definiert für Map X oder System X RESOURCE_WATERSTONEPIECE Dieses Item ist ein Splitterstück eines Geiststeins RESOURCE_WATERSTONE Dieses Item ist ein Stein. Wortwörtlich. ITEM_RESOURCE Dieses Item ist ein Uppitem RESOURCE_WHITE_PEARL Dieses Item kann man aus Muscheln bekommen und gehört der Kategorie Weißer Perle RESOURCE_BLUE_PEARL Dieses Item kann man aus Muscheln bekommen und gehört der Kategorie Blauer Perle RESOURCE_BLOOD_PEARL Dieses Item kann man aus Muscheln bekommen und gehört der Kategorie Roter Perle ITEM_METIN Dieses Item ist ein Geiststein METIN_NORMAL Dieses Item ist ein Normaler Geiststein ohne besonderheiten ITEM_PICK Dieses Item ist eine Spitzhacke MATERIAL_LEATHER Dieses Item … eig. Gehört das zu Ledermaterialien aber es wird irgendwie für alle Questitems genutzt. ITEM_GIFTBOX Dieses Item ist eine Truhe USE_AFFECT Dieses Item setzt einen Effekt frei LOG Dieses Item wird geloggt und lässt sich in den Datenbanken auslesen USE_CLEAN_SOCKET Dieses Item entfernt Steinsplitter USE_CHANGE_ATTRIBUTE Dieses Item ändert attribute / Bonis USE_ADD_ATTRIBUTE Dieses Item fügt Bonis hinzu WEAR_SHIELD Dieses Item wird in den Zwei Special Slots getragen / Neben den Schuhen ITEM_COSTUME Dieses Item ist ein Kostüm COSTUME_BODY Dieses Item wird im Kostümslot für anzüge getragen ANTI_FEMALE Dieses Item kann nicht von Frauen getragen werden ANTI_MALE Dieses Item kann nicht von Männern getragen werden COSTUME_HAIR Dieses Item wird im Kopfschmuck / Haarslot getragen REAL_TIME Dieses Item läuft nach genereller Zeit ab (nicht nach eigener Onlinezeit sondern grundsätzlicher Zeit) ITEM_LOTTERY Dieses Item wird zur Lotterrie genutzt ITEM_TREASURE_BOX Dieses Item ist eine Schatzkiste ITEM_SKILLBOOK Dieses Item erhöht eine Fertigkeit ITEM_POLYMORPH Dieses Item nutzt man zur verwandlung USE_PUT_INTO_ACCESSORY_SOCKET Dieses Item nutzt man um es in eine Fassung einzufügen USE_ADD_ACCESSORY_SOCKET Dieses Item fügt eine Fassung ein ITEM_BLEND Dieses Item ist ein Tau ITEM_SKILLFORGET Dieses Item nutzt man um Skills oder Stats zu vergessen oder negative Punkte zu geben
  14. System ist getestet von dem Sender des Systems. [Hidden Content] Credit to @DarthNeno
  15. Hello community! I've found a small common bug in 3 systems wich I'm using. These Systems are the following: ~ Official Pet ~ Follow Mount ~ Great Offline Shop This bug appears for me two times. First case, when you want to use your "purge" command, with "all" or "map" argument, like "/purge all", or "/purge map" (if you have "map" argument type). In that case your new pets, mounts (if they are following right now), and offline shops are disappearing. Second Case if you use "npc.purge()" or "d.kill_all()" in your quest. When you use npc.purge(), your following mount, and your new pet disappear. When you use d.kill_all() function, your mount and new pet will die. Now I'll share the fix with you, so let's get started. All you need is your game source. BEFORE YOU START! "IsNewPet, IsMount and IsPrivateShop" maybe different in your source! 1. /** In char_manager.cpp **/ // In "void CHARACTER_MANAGER::DestroyCharacter(LPCHARACTER ch)" search this: if (ch->IsNPC() && !ch->IsPet() && ch->GetRider() == NULL) // I modified it like that: if (ch->IsNPC() && !ch->IsPet() && !ch->IsNewPet() && !ch->IsMount() && !ch->IsPrivShop() && ch->GetRider() == NULL) // In "void CHARACTER_MANAGER::DestroyCharacterInMap(long lMapIndex)" search this: if (pkChr && pkChr->GetMapIndex() == lMapIndex && pkChr->IsNPC() && !pkChr->IsPet() && pkChr->GetRider() == NULL) // I modified it like that: if (pkChr && pkChr->GetMapIndex() == lMapIndex && pkChr->IsNPC() && !pkChr->IsPet() && !pkChr->IsNewPet() && !pkChr->IsMount() && !pkChr->IsPrivShop() && pkChr->GetRider() == NULL) 2. /** In cmd_gm.cpp **/ // In "void operator () (LPENTITY ent)" search this: if (pkChr->IsNPC() && !pkChr->IsPet() && !pkChr->IsMount() && pkChr->GetRider() == NULL) // I modified it like that: if (pkChr->IsNPC() && !pkChr->IsPet() && !pkChr->IsNewPet() && !pkChr->IsMount() && pkChr->GetRider() == NULL) 3. /** In dungeon.cpp **/ // In "struct FKillSectree" search this: if(!ch->IsPC() && !ch->IsPet()) // I modified it like that: if(!ch->IsPC() && !ch->IsPet() && !ch->IsNewPet() && !ch->IsMount()) // In "struct FPurgeSectree" search this: if(!ch->IsPC() && !ch->IsPet()) // I modified it like that: if(!ch->IsPC() && !ch->IsPet() && !ch->IsNewPet() && !ch->IsMount()) 4. /** In questlua_dungeon.cpp **/ // In "struct FPurgeArea" search this: if (!pChar->IsPet() && (true == pChar->IsMonster() || true == pChar->IsStone())) // I modified it like that: if (!pChar->IsPet() && !pChar->IsNewPet() && !pChar->IsMount() && (true == pChar->IsMonster() || true == pChar->IsStone())) 5. /** In questlua_global.cpp **/ // In "struct FKillSectree2" search this: if (!ch->IsPC() && !ch->IsPet()) // I modified it like that: if (!ch->IsPC() && !ch->IsPet() && !ch->IsNewPet() && !ch->IsMount()) // In "struct FPurgeArea" search this: if (!pChar->IsPet() && (true == pChar->IsMonster() || true == pChar->IsStone())) // I modified it like that: if (!pChar->IsPet() && !pChar->IsNewPet() && !pChar->IsMount() && (true == pChar->IsMonster() || true == pChar->IsStone())) 6. /** In sectree_manager.cpp **/ // In "struct FPurgeMonsters" search this: if (lpChar->IsMonster() == true && !lpChar->IsPet()) // I modified it like that: if (lpChar->IsNPC() == true && !lpChar->IsPet() && !lpChar->IsNewPet() && !lpChar->IsMount() && !lpChar->IsPrivShop()) // In "struct FPurgeNPCs" search this: if (lpChar->IsNPC() == true && !lpChar->IsPet()) // I modified it like that: if (lpChar->IsNPC() == true && !lpChar->IsPet() && !lpChar->IsNewPet() && !lpChar->IsMount() && !lpChar->IsPrivShop()) Some parts of the fix contains the original descriptions of the mentioned systems above. Now compile and you're done. Not a large fix, but I think it's useful. Best regards!
  16. Hello, because i saw some people asking for that, there is: Replace the cmd_emotion.cpp With this file: Download: [Hidden Content] I couldn't find other way to do this, i just add the duration time in the file and i writed a code for hide & show with time event, everything working fine.
  17. Patcher by Hanashi Originalthread: [Hidden Content] Mir war mal langweilig und hab dazu mal n Video gemacht #outdate aber egal ^^ #reupload [Hidden Content]
  18. "Mensch mein World editor gibt ständig irgendwelche Fehlermeldungen raus und ich weiß nicht warum, ich hab ihn genauso kopiert wie er da zum DL steht trotzdem geht er nicht" So muss der Ordner vom World editor normalerweise aussehen natürlich könnt ihr nicht einfach die entpackten epk / eix ordner dort einfach reinziehen ihr müsst als aller erstes darauf achten und das ist ganz wichtig das der WE im verzeichnis :D/ymir work/ ist habt ihr keine zweite Festplatte nutzt ihr beispielsweise einen USB stick oder eine 2. Partition falls euer stick jetzt urplötzlich E I H oder sonstwas hat per Datenträgerverwaltung lässt sich sowas umstellen dann einfach rechtsklick auf das Laufwerk und den Kennbuchstaben auf D stellen fertig. haben wir nun den World Editor in den Pfad gesteckt kümmern wir uns mal um die Inhalte die er braucht. er wird womöglich nach dem background_stone.gr2 fragen. (klick mich falls ihr ihn braucht) dann müssen wir nun die einzelnen ordner durchgehen von eurem clienten solltet ihr erstmal den miles ordner komplett kopieren einfach direkt ins verzeichnis D/ymir work nun brauchen wir die inhalte von folgenden verzeichnissen wichtig ist hierbei dass nicht einfach der komplette Ordner kopiert werden soll SONDERN anstatt einfach nur den Zone Ordner den Inhalt der Zone d.h. der pfad darf dann nicht: d/ymir work/Zone/ymir work/ Objekte sein sondern muss d/ymir work/Zone/ Objekte das gilt für alle verzeichnisse zone tree textureset terrainmaps (terrain) special (etc) sound (für ambiente) property pc (eig nur so eine rüstung aber bin zu faul sie rauszusuchen) environment (etc) effect (etc) achtet darauf dass ihr die selbe granny version wie aus eurem clienten verwendet. im normal fall ist das granny 2.4 oder 2.9 😉 bei fragen einfach melden
  19. Hello m2tech, Today i will release the fix for invisibility effect bug and the AFFECT_EUNHYEONG = sealth ninja skill from 17.5 Official update. What has my hide system, it is imperative to apply this fix. Open instancebase.cpp and search for: BOOL CInstanceBase::IsInvisibility() { if (IsAffect(AFFECT_INVISIBILITY)) return true; return false; } Replace with: BOOL CInstanceBase::IsInvisibility() { if (IsAffect(AFFECT_INVISIBILITY) || IsAffect(AFFECT_EUNHYEONG)) return true; return false; } Search for: void CInstanceBase::Update() { Inside the function search for: if (IsMountingHorse()) { m_kHorse.m_pkActor->HORSE_MotionProcess(false); } } Add bellow: if (IsAffect(AFFECT_INVISIBILITY) || IsAffect(AFFECT_EUNHYEONG)) m_GraphicThingInstance.HideAllAttachingEffect(); Open InstanceBaseEffect.cpp and search for: void CInstanceBase::__SetAffect(UINT eAffect, bool isVisible) { Inside the function search: case AFFECT_INVISIBILITY: if (isVisible) { m_GraphicThingInstance.ClearAttachingEffect(); __EffectContainer_Destroy(); DetachTextTail(); } else { m_GraphicThingInstance.BlendAlphaValue(1.0f, 1.0f); AttachTextTail(); RefreshTextTail(); } return; break; } Replace with: case AFFECT_INVISIBILITY: if (isVisible) { // m_GraphicThingInstance.ClearAttachingEffect(); // __EffectContainer_Destroy(); // DetachTextTail(); m_GraphicThingInstance.HideAllAttachingEffect(); } else { m_GraphicThingInstance.BlendAlphaValue(1.0f, 1.0f); m_GraphicThingInstance.ShowAllAttachingEffect(); // AttachTextTail(); // RefreshTextTail(); } return; break; Thanks to legend for this sharing.
  20. So guys i've been messing around with Ore on items and i saw that despite an item has 3 bonus when you add an ore only two appear, but the character get all the bonuses. The fix for that is: Open root/uitooltip.py and then follow the instructions. Search for: affectList2=[0, max(1, affectValue2*10/100), max(2, affectValue2*20/100), max(3, affectValue2*40/100)] And add below: affectType3, affectValue3 = item.GetAffect(2) affectList3=[0, max(1, affectValue3*10/100), max(2, affectValue3*20/100), max(3, affectValue3*40/100)] Then Search for: affectString2 = self.__GetAffectString(affectType2, affectList2[mtrlPos+1]-affectList2[mtrlPos]) And add below: affectString3 = self.__GetAffectString(affectType3, affectList2[mtrlPos+1]-affectList3[mtrlPos]) Find: self.__AppendMetinSlotInfo_AppendMetinSocketData(mtrlPos, mtrl, affectString1, affectString2, leftTime) Replace with: self.__AppendMetinSlotInfo_AppendMetinSocketData(mtrlPos, mtrl, affectString1, affectString2, affectString3, leftTime) Find: def __AppendMetinSlotInfo_AppendMetinSocketData(self, index, metinSlotData, custumAffectString="", custumAffectString2="", leftTime=0): Replace with: def __AppendMetinSlotInfo_AppendMetinSocketData(self, index, metinSlotData, custumAffectString="", custumAffectString2="", custumAffectString3="", leftTime=0): Last find: if custumAffectString2: And add below: if custumAffectString3: affectTextLine = ui.TextLine() affectTextLine.SetParent(self) affectTextLine.SetFontName(self.defFontName) affectTextLine.SetPackedFontColor(self.POSITIVE_COLOR) affectTextLine.SetPosition(50, self.toolTipHeight + 16 + 2 + 16 + 2) affectTextLine.SetOutline() affectTextLine.SetFeather() affectTextLine.Show() affectTextLine.SetText(custumAffectString3) self.childrenList.append(affectTextLine) self.toolTipHeight += 16 + 2 I know thats something that some might never noticed and that's super easy to fix, but some people might do not know.
  21. After I released some Metin2-compatible Speedtree trees in another forum a few years ago, some people have also posted trees from other games which I downloaded from several forums. But the issue with those trees is always the same, they either do not work or they look strange, with noticeable dark areas. Metin2 uses the oldest existing version of Speedtree, in fact it uses a demo version of Speedtree from 2003 that was used to advertise the software to developers after it was created. It's not even a full version. Therefore some features that older versions use, even in games contemporary to Metin2, are not available. Fortunately there is a newer editor that is almost fully compatible with the version of SpeedTree included with Metin2, and this is version 3: [Hidden Content] Version 4 is partially compatible but I wouldn't recommend using it. Version 5 and newer of SpeedTree use a completely different file format and are not compatible. Let's say we have a speedtree (spt) file, with its matching dds texture, and now we try loading it into SpeedTree CAD 3: Here we encounter our first problem; while many games are using dds textures, Speedtree CAD only supports TGA files. In order to know what our tree looks like, we should convert the dds files to tga (although Metin2 will use dds regardless of what's set in the SPT file,you can try opening a spt file with a hex or text editor as the paths are there almost in plain text). A good tool for this is Irfanview, which also provides a batch conversion feature allowing us to convert dozens of files across subfolders in a single click: [Hidden Content] In this case, as I had to deal with subfolders, I used advanced options and checked "create subfolders in destination folder", as well as "Include subfolders for Add All button). After doing this, I had a tga version of all the dds textures used in this game, so now I can see the trees and work with them. Once we want to release our tree we can just keep the dds file. In this partcular case with Ragnarok, after converting all the textures, I found out the spt file itself was using dds as format (Metin2 rewrites the extension in the file), which meant there was only one way to see the trees within SpeedTree CAD and so I downloaded some hexadecimal editor to change these extensions from dds to tga: As I load the resulting file into Speedtree CAD 3 it seems Irfanview did not convert the alpha channel found in the original dds file to the tga one: That should be fine as we will use DDS ingame, not this TGA. So I decide this palm tree actually looks nice and I load the original file into World Editor which unsurprisingly results in a crash. This file is probably a SpeedTree 4 file. SpeedTree 4 was very popular in the 2000's and many games use it, but the file format is not compatible with Metin2 and will cause it to crash. Fortunately there is a workaround so I load the original unmodified SPT file into SpeedTree CAD 3 and save it back without changing anything, which allows it to be read by Metin2. FInally my tree is loading, unfortunately the size is wrong and it looks more like a banana: But this has an easy solution. I go back to Speedtree CAD, Global tab, and change the size field from 41.7 to 1000, then click Compute, and then save. PRT files have a Size field in them but it just doesn't work so we have to do it this way. Now going to the subject of lighting, this palm doesn't look too bad, but some trees will just look terrible in metin because of the lighting. Case in point: Half the leaves are dark which doesn't look too good. This is because those games have actual lighting for their trees which Metin2 doesn't, so we have to do it manually. We proceed to the Lighting tab in Speedtree CAD: What we are going to do here, to make the tree more fitting, is change all "Lighting Style" fields to Static and then play with the Dimming (set it around 10-20%) and optionally the Leaf Lighting Adjustment and "simulate shadows". Our goal is to show some slightly darker areas but not as exaggerated as in the picture before: I'm not happy with the result yet. There's another field which sometimes affects the leave color and it's under the "Leaves" tab. I reduced "Color variance" from 60 to 30 in both textures (click in "Texture #" to switch between textures) Here is the final result: Parameters changed: LIGHTING Branch lighting: Dynamic > Static Leave lighting: Dynamic > Static Static lighting style: Basic Leaf lighting adjustment: 0.1 > 0.8 Dimming: 90% > 10% Frond lighting: Dynamic > Static LEAVES Color variance: 60 > 90 (for both textures) These changes, with small variations, should work for pretty much every tree to look like a proper "Metin2 tree". Don't forget that you need to click "Compute" to see the changes, and before you save the file.
  22. Hi everyone. I would like to share with you a reversed small stuff from the official game. Any problem? Just write a comment below, even a feedback is also good for us to make sure I did not miss anything from the guide. 
  23. on char.cpp search : case POINT_MALL_GOLDBONUS: and to make any bonus cap you just need to do this(for any bonus you want a cap) case POINT_RESIST_SHAMAN: if (GetPoint(type) + amount > 80) { ChatPacket(CHAT_TYPE_INFO, "The percentage was higher than 80 percent. The Game will adjust your bonus."); //no need to include this, spams. amount = 80 - GetPoint(type); } Whats a cap? Basicly its the max value that a player will be able to reach even though he might have 100% on total. I was trying to find out whats wrong and how could i do that , so here's what i found, which perfectly works by the way. In my opinion do not use the chatpacket cause its spamming, and if you get on the horse you're gonna see more than one "calls" on that point so... yes it spams.
×