Jump to content

Search the Community

Showing results for tags 'fix'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Metin2 Dev
    • Announcements
  • Community
    • Member Representations
    • Off Topic
  • Miscellaneous
    • Metin2
    • Showcase
    • File Requests
    • Community Support - Questions & Answers
    • Paid Support / Searching / Recruiting
  • Metin2 Development
  • Metin2 Development
    • Basic Tutorials / Beginners
    • Guides & HowTo
    • Binaries
    • Programming & Development
    • Web Development & Scripts / Systems
    • Tools & Programs
    • Maps
    • Quests
    • 3D Models
    • 2D Graphics
    • Operating Systems
    • Miscellaneous
  • Private Servers
    • Private Servers
  • Uncategorized
    • Drafts
    • Trash
    • Archive
    • Temporary
    • Metin2 Download

Product Groups

  • Small Advertisement
  • Large Advertisement
  • Advertising

Categories

  • Third Party - Providers Directory

Categories

  • Overview
  • Pages
    • Overview
    • File Formats
    • Network
    • Extensions

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Pillory


Marketplace


Game Server


Country


Nationality


Github


Gitlab


Discord


Skype


Website

  1. This is a nasty bug where a boss can throw you inside a wall if he hits you with a skill that has SKILL_FLAG_CRUSH or SKILL_FLAG_CRUSH_LONG. // char_skill.cpp // Search: if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_CRUSH | SKILL_FLAG_CRUSH_LONG) && !IS_SET(pkChrVictim->GetAIFlag(), AIFLAG_NOMOVE)) { ... } // Replace the if with: if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_CRUSH | SKILL_FLAG_CRUSH_LONG) && !IS_SET(pkChrVictim->GetAIFlag(), AIFLAG_NOMOVE)) { float fCrushSlidingLength = 200; if (m_pkChr->IsNPC()) fCrushSlidingLength = 400; if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_CRUSH_LONG)) fCrushSlidingLength *= 2; float fx, fy; float degree = GetDegreeFromPositionXY(m_pkChr->GetX(), m_pkChr->GetY(), pkChrVictim->GetX(), pkChrVictim->GetY()); if (m_pkSk->dwVnum == SKILL_HORSE_WILDATTACK) { degree -= m_pkChr->GetRotation(); degree = fmod(degree, 360.0f) - 180.0f; if (degree > 0) degree = m_pkChr->GetRotation() + 90.0f; else degree = m_pkChr->GetRotation() - 90.0f; } GetDeltaByDegree(degree, fCrushSlidingLength, &fx, &fy); long startX = (long)(pkChrVictim->GetX()); long startY = (long)(pkChrVictim->GetY()); long endX = (long)(pkChrVictim->GetX() + fx); long endY = (long)(pkChrVictim->GetY() + fy); // We asume all positions between the start and end point are movable bool allPositionsMovable = true; // Calculate the distance between the start and end points double distance = std::sqrt((endX - startX) * (endX - startX) + (endY - startY) * (endY - startY)); // Calculate the step size for each coordinate double stepX = (endX - startX) / distance; double stepY = (endY - startY) / distance; // Check if all points on the trajectory between startX, startY and endX, endY are movable for (double i = 0; i <= distance; ++i) { double currentX = startX + i * stepX; double currentY = startY + i * stepY; long roundedX = static_cast<long>(std::round(currentX)); long roundedY = static_cast<long>(std::round(currentY)); if (!SECTREE_MANAGER::instance().IsMovablePosition(pkChrVictim->GetMapIndex(), roundedX, roundedY)) { allPositionsMovable = false; break; } } if (allPositionsMovable) { sys_log(0, "CRUSH SUCCESS! %s -> %s (%d %d) -> (%d %d)", m_pkChr->GetName(), pkChrVictim->GetName(), pkChrVictim->GetX(), pkChrVictim->GetY(), (long)(pkChrVictim->GetX()+fx), (long)(pkChrVictim->GetY()+fy)); pkChrVictim->Sync(endX, endY); pkChrVictim->Goto(endX, endY); pkChrVictim->CalculateMoveDuration(); } else { sys_log(0, "CRUSH FAIL! %s -> %s (%d %d) -> (%d %d)", m_pkChr->GetName(), pkChrVictim->GetName(), pkChrVictim->GetX(), pkChrVictim->GetY(), (long)(pkChrVictim->GetX()+fx), (long)(pkChrVictim->GetY()+fy)); } if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() == (DWORD) pkChrVictim->GetVID()) { SkillAttackAffect(pkChrVictim, 1000, IMMUNE_STUN, m_pkSk->dwVnum, POINT_NONE, 0, AFF_STUN, 4, m_pkSk->szName); } else { if (allPositionsMovable) pkChrVictim->SyncPacket(); } }
  2. Hello, pretty sure anyone of you knows about the Dispel and Heal Lag problem that has been around since always. This little modification will fix both these problems completely. (Thanks @Horinna for helping with the in-game tests) Problem: The RemoveAffect function calls ComputePoints() (Complete rearrange of all the player stats and equip parts, one of the heaviest checks). The correct function to use is RefreshAffect() which does its job pretty fine! But that's not the only problem: Based on the current code, that function would get called every single time an affect gets removed or added, while it should only get called once, at the end of the process. Solution: We could make new functions for those 2 special flags (REMOVE_BAD_AFFECT and REMOVE_GOOD_AFFECT), but in order to keep things simple for you guys, i'll simply "dynamicize" the RemoveAffect function. 1: navigate inside char_affect.cpp: 2: navigate inside char.h: This way, we applied a simple boolean value arg to the RemoveAffect function, which will get set to true by default. By setting it to false like this RemoveAffect(affectLUL, false); we are basically saying the game to not Rearrange the points when affectLUL gets removed. now we will use a cycle to do that for every affect like usual, and we will rearrange of the points just once, at the end of the process, like it should be. Done! Comparison:
  3. Hello, In this I fixed several problems Now with the new method the problems have all been solved [Please it has been tested before publishing] 1) OPEN char_affect.cpp search: void CHARACTER::RemoveBadAffect() { .......... } Change with: void CHARACTER::RemoveBadAffect() { for (auto it = 0; it < SKILL_MAX_NUM; it++) { const CAffect * pkAff = FindAffect(it); if (pkAff) { switch (it) { case AFFECT_FIRE: { RemoveAffect (AFFECT_FIRE); event_cancel(&m_pkFireEvent); break; } case AFFECT_POISON: { RemoveAffect (AFFECT_POISON); event_cancel(&m_pkPoisonEvent); break; } case AFFECT_STUN: case AFFECT_SLOW: case SKILL_TUSOK: { RemoveAffect (it); break; } } } } ComputePoints(); UpdatePacket(); } -------------------- ---------- 2. search: void CHARACTER::RemoveGoodAffect() { .......... } change with: void CHARACTER::RemoveGoodAffect() { for (auto it = 0; it < SKILL_MAX_NUM; it++) { const CAffect * pkAff = FindAffect(it); if (pkAff) { switch (it) { case AFFECT_MOV_SPEED: case AFFECT_ATT_SPEED: case AFFECT_STR: case AFFECT_DEX: case AFFECT_INT: case AFFECT_CON: case AFFECT_CHINA_FIREWORK: case SKILL_JEONGWI: case SKILL_GEOMKYUNG: case SKILL_CHUNKEON: case SKILL_EUNHYUNG: case SKILL_GYEONGGONG: case SKILL_GWIGEOM: case SKILL_TERROR: case SKILL_JUMAGAP: case SKILL_MANASHILED: case SKILL_HOSIN: case SKILL_REFLECT: case SKILL_GICHEON: case SKILL_KWAESOK: case SKILL_JEUNGRYEOK: { RemoveAffect (it); break; } } } } ComputePoints(); UpdatePacket(); } (If you haven't solved the UpdatePacket and ComputePoints issues please don't use this method) (90% people have martysama and owsap serverfiles there is no problem) I worked many hours to fix all the problems from the fix @ Syreldar it has been tested before I publish it (I Have test and in martysama serverfiles and in Owsap to be sure it will work properly) thanks you.
  4. Ayo, recently I've come across an issue with a customer who had item proto entries all over the place and when the database tried to sort that mess, it messed it up even more, eventually, it messed up this very Monday for me as I spent hours debugging this. Long story short: It first inserts key-value to map m_map_itemTableByVnum where the key was an integer (item vnum) and the value was a pointer that pointed to an item table object at position X in m_vec_itemTable but at the end, it sorted this very vector while values in map still pointed to the same positions in the vector. Guessed what happened? An item with vnum 19709 had an item table of the item with vnum 20009 because you donkey were too lazy to put new proto entries in the correct order. Go over to server source, database/ClientManagerBoot.cpp, at the end of the following function: bool CClientManager::InitializeItemTable() { [...] m_map_itemTableByVnum.clear(); auto it = m_vec_itemTable.begin(); while (it != m_vec_itemTable.end()) { TItemTable * item_table = &(*(it++)); sys_log(1, "ITEM: #%-5lu %-24s %-24s VAL: %ld %ld %ld %ld %ld %ld WEAR %lu ANTI %lu IMMUNE %lu REFINE %lu REFINE_SET %u MAGIC_PCT %u", item_table->dwVnum, item_table->szName, item_table->szLocaleName, item_table->alValues[0], item_table->alValues[1], item_table->alValues[2], item_table->alValues[3], item_table->alValues[4], item_table->alValues[5], item_table->dwWearFlags, item_table->dwAntiFlags, item_table->dwImmuneFlag, item_table->dwRefinedVnum, item_table->wRefineSet, item_table->bAlterToMagicItemPct); m_map_itemTableByVnum.insert(std::map<DWORD, TItemTable *>::value_type(item_table->dwVnum, item_table)); } sort(m_vec_itemTable.begin(), m_vec_itemTable.end(), FCompareVnum()); return true; Now we'll do some dark magic, we'll move the sort function at the beginning of previously shown code, like so: bool CClientManager::InitializeItemTable() { [...] m_map_itemTableByVnum.clear(); // -------------------------------------------------------------> Wohoo I am here now! sort(m_vec_itemTable.begin(), m_vec_itemTable.end(), FCompareVnum()); auto it = m_vec_itemTable.begin(); while (it != m_vec_itemTable.end()) { TItemTable * item_table = &(*(it++)); sys_log(1, "ITEM: #%-5lu %-24s %-24s VAL: %ld %ld %ld %ld %ld %ld WEAR %lu ANTI %lu IMMUNE %lu REFINE %lu REFINE_SET %u MAGIC_PCT %u", item_table->dwVnum, item_table->szName, item_table->szLocaleName, item_table->alValues[0], item_table->alValues[1], item_table->alValues[2], item_table->alValues[3], item_table->alValues[4], item_table->alValues[5], item_table->dwWearFlags, item_table->dwAntiFlags, item_table->dwImmuneFlag, item_table->dwRefinedVnum, item_table->wRefineSet, item_table->bAlterToMagicItemPct); m_map_itemTableByVnum.insert(std::map<DWORD, TItemTable *>::value_type(item_table->dwVnum, item_table)); } return true;
  5. When you set a text in a textline and then change font name, text disappear. Before fix: With fix: [Hidden Content]
  6. The client is freezing for a while(anywhere from a few ms to multiple seconds for slower PCs) when meeting a new NPC/enemy for the first time because that's when it registers, creates and loads the entity. Note: This is only a partial fix. Why is it partial? Because it only loads the static mobs and NPCs available in the map(npc, regen, boss, group and group_group), so it won't fix the problem for dynamic entities, like pets and mounts. It can be extended to load those as well, of course, but you'll have to take care of that on your own. Variant: A way of completely fixing this would be to create the instances and load their files after registering the path(in root->playerSettingModule->LoadGameNPC), BUT that would slow down the initial loading quite a bit, since it'll load ALL mobs/npcs/pets/mounts, even if most of them will never be used. There's advantages and drawbacks to both methods. Choose for yourself. Here's the link: [or] [Hidden Content] [or] [Hidden Content] Good luck! - Amun Edit: UPDATE 08/12/2022: 1. Refactored to use unordered_set from the beginning instead of creating a vector, then filtering unique entities by creating a set, and then moving them back to a vector. 2. Extended to load the full spectrum of entities(both static and dynamic), except for PC(which are loaded in loading phase), WARP, GOTO, and DOOR. They can be included by altering this block in char_manager.cpp: #ifdef ENABLE_ENTITY_PRELOADING //@Amun: or be specific, like if(ch->ispet, mount, whatever) if (!ch->IsPC() && !ch->IsGoto() && !ch->IsWarp() && !ch->IsDoor()) SECTREE_MANAGER::Instance().ExtendPreloadedEntitiesMap(lMapIndex, pkMob->m_table.dwVnum); #endif
  7. Download Alternative download links → Version1 or Version2 or Version3 Changelogs Version 3. Fix quest pick in quest Fix delayed desc kick Now it works stable without problems in version 3 Version 2. Now, the players cannot delete messange other people's In 4 failures the server kick you @ TMP4 @ Abel(Tiger) Version 1. Normal fix guild comment
  8. Download Click here to check the repository ↗ I think everyone already knows this problem, this happens because the client is just rendering the text pointer of the normal chat window, when opening the chat-log window, it just changes the position of the rendering text. Before After
  9. Hello, you probably have seen this "warning" in your syserr and probably ignored it: Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09204630>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09204650>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09204610>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09210B30>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x092109D0>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x092109F0>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09210A10>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09210A30>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09210A50>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09210A70>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x092104B0>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09210550>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x09210590>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x092106B0>> ignored Exception AttributeError: "'NoneType' object has no attribute '__del__'" in <bound method NumberLine.__del__ of <ui.NumberLine object at 0x092106F0>> ignored Exception TypeError: "'NoneType' object is not callable" in <bound method CursorImage.__del__ of <mouseModule.CursorImage object at 0x092045D0>> ignored This is caused by not deleting the CMouseController instance properly. To fix this we just need to delete the CMouseController instance when closing the client. Let's start: Open root/mouseModule.py and search for the constructor of CMouseController (CMouseController.__init__) and add this under 'self.callbackDict = {}': self.cursorDict = {} Now navigate towards the deconstructor of the same class (CMouseController.__del__) and add this under the 'self.callbackDict = {}': for k, v in self.cursorDict.items(): v.DeleteImage() And the final step is just to delete the instance of the CMouseController from de mouseModule; open prototype.py and add this under 'mainStream.Destroy()': del mouseModule.mouseController And that's all. If you have any problem related to the post just comment it. Note: I've started to see this when I compiled the python library as static.
  10. Reversed From 22.2.7.0 It's an old bug. You probably fixed it with another method, here is the reversed ver. [Hidden Content] [Hidden Content]
  11. When you are changing attributes in your item for every-single attribute server sends update packet to client, which is up to 4 unnecessary packets per one change. You must agree this is pointless. If you use bonus switcher and, let's say, with 500ms delay for 7 items it is 5 * 7 * 2 update packets per second. Going lower with delay you will get absurd amount of those packets. Another issue is you are not able to read attributes, I mean, avarage human cannot. After digging in code I got rid of redundant packets and received smoother in-game experience This how it looks for 150ms switch delay: gif With my fix: gif Download: link
  12. When cancelling server timers a core will crash as it is removing a timer from the map and increasing the iterator twice by calling erase() function and afterwards increasing it once again when entering a new cycle of loop. One way of solving this issue is to first collect the timers which must be removed and clean them up at the end. You can also add a simple counter which is increased at each end of the loop's cycle and remove the timer directly from the first loop by specifying the position with the counter itself. Note that this issue seems to appear after upgrading code to C++11 or higher. Replace the following function inside questmanager.cpp: void CQuestManager::CancelServerTimers(DWORD arg) { vector<pair<string, DWORD>> ServerTimersToDelete; for (const auto& kv : m_mapServerTimer) { if (kv.first.second == arg) { LPEVENT event = kv.second; event_cancel(&event); ServerTimersToDelete.push_back(kv.first); } } // Delete all the required server timers for (const auto &timer : ServerTimersToDelete) m_mapServerTimer.erase(timer); // Clean up ServerTimersToDelete.clear(); }
  13. I think some of you faced this bug when you had a monster with more then 21 million HP: the gauge showed 0% even when it was on full HP. It's because when the server calculates the HP percentage is like MINMAX(0, (m_pkChrTarget->GetHP() * 100) / m_pkChrTarget->GetMaxHP(), 100), so 21 million will overflow when it's multiplied by 100. The fix is really quick and easy: [Hidden Content]
  14. The funny thing about this tutorial/fix is that you have to rewrite it, it's beautiful isn't it? Good Saturday
  15. Hello community, I had a problem on my server that after 2 days of being turned on I would get the error "MySQL server has gone away". After 1 week of research and testing I came up with a solution. Step by Step [Hidden Content]
  16. Hey, so, basically I recently got into making environment effects and skyboxes, I'm pretty satisfied with the results so far, nevertheless, I had two issues: I was playing with the LensFlare on WorldEditor, that's how it should be, or at least, that's what the result the World Editor window showed me: When the camera is looking the MainFlare (the sun), the window should get blurrier and brighter, and it should also show the Flare effect you see. (the circles) But the problem was that, when I got in-game, it was like this: So the issues were 2: First problem: You see it only was getting brighter for only like half of the window, depending on my resolution (It was perfect on 800x600 and 1024x768, if I chose a resolution even just a little bit wider, a part of the screen bugged out, but it worked even on fullscreen as long as I used one of those 2 resolutions). Fix: 1. Open your ClientSide sources and then your LensFlare.cpp file. Search for: RenderBar2d(0.0f, 0.0f, 1024.0f, 1024.0f); Change it into: RenderBar2d(0.0f, 0.0f, 3840.0f, 2400.0f); ^ I overdid the fix so it supports even the most advanced gaming resolutions. Second problem: It didn't show the LensFlare effect ([Hidden Content]), no matter what I did. (Yes the binary loaded the 6 flare files from my client correctly). Fix: 1. Open your ClientSide sources and then your LensFlare.cpp file. Search for: static float g_afColors[][4] = {{1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f, 0.8f}, {0.3f, 0.5f, 1.0f, 0.9f}, {0.3f, 0.5f, 1.0f, 0.6f}, {1.0f, 0.6f, 0.9f, 0.4f}, {1.0f, 0.0f, 0.0f, 0.5f}, {1.0f, 0.6f, 0.3f, 0.4f}}; Each of these subarrays is a color, structure = R, G, B, A, the last argument, A, is the Alpha, by increasing it, it will eventually show them, make them as transparent as you like! My end result at max brightness: [Hidden Content] For the moderators: This thread was originally a help request, but since I managed to fix both of those issues, I think the thread should/could be moved to Guides/HowTo, I've already changed it so it fits for that section.
  17. Error: CRaceManager::RegisterRacePath : RACE[34080] LOAD MSMFILE[d:/ymir work/npc_pet/halloween_tar/halloween_tar.msm Metin2 not load 34080 from npc_pet why you add folder(halloween_tar) in npc_pet x2 load why ? Lets go to fix 1. OPEN GameLib folder 2. OPEN RaceManager.cpp 3. Search: if (race >= 30000) { if (race==34028 || race==34029) { vec_stPathes.push_back ("d:/ymir work/npc_pet/"); vec_stPathes.push_back ("d:/ymir work/npc2/"); } else { vec_stPathes.push_back ("d:/ymir work/npc2/"); vec_stPathes.push_back ("d:/ymir work/npc_pet/"); } vec_stPathes.push_back ("d:/ymir work/npc/"); vec_stPathes.push_back ("d:/ymir work/monster/"); vec_stPathes.push_back ("d:/ymir work/monster2/"); vec_stPathes.push_back ("d:/ymir work/guild/"); } 4. Change with: if (race >= 30000) { if (race==34028 || race==34029) { vec_stPathes.push_back ("d:/ymir work/npc_pet/"); vec_stPathes.push_back ("d:/ymir work/npc2/"); } else if (race==34080) // Load only from normal folder npc2 my halloween_tar :) and not load from npc_pet { vec_stPathes.push_back ("d:/ymir work/npc2/"); } else { vec_stPathes.push_back ("d:/ymir work/npc2/"); vec_stPathes.push_back ("d:/ymir work/npc_pet/"); } vec_stPathes.push_back ("d:/ymir work/npc/"); vec_stPathes.push_back ("d:/ymir work/monster/"); vec_stPathes.push_back ("d:/ymir work/monster2/"); vec_stPathes.push_back ("d:/ymir work/guild/"); } 34080 else { vec_stPathes.push_back ("d:/ymir work/npc2/"); vec_stPathes.push_back ("d:/ymir work/npc_pet/"); } i will add my number from pet if (race==34080) // Load only from normal folder npc2 my halloween_tar and not load from npc_pet { vec_stPathes.push_back ("d:/ymir work/npc2/"); } vec_stPathes.push_back ("d:/ymir work/npc2/"); pet this load from this npc2 If there are extra pets you can add example: if (race==34080 || race==34081 || race==34082 ) 34081 and 34082 = load npc2 if not load from npc2 and load from npc_pet add new code if (race==34080 || race==34081 || race==34082 ) // Load only from normal folder npc2 my halloween_tar and not load from npc_pet { vec_stPathes.push_back ("d:/ymir work/npc_pet/"); } Error fixed without hide error // TraceError("CRaceManager::RegisterRacePath : RACE[%u] LOAD MSMFILE[%s] ERROR. Will Find Another Path.", dwRaceIndex, stMSMFileName.c_str());
  18. Userinterface.cpp 1, put it to the beginning PVOID* find(const char *szFunc, HMODULE hModule) { if (!hModule) hModule = GetModuleHandle(0); PIMAGE_DOS_HEADER img_dos_headers = (PIMAGE_DOS_HEADER)hModule; PIMAGE_NT_HEADERS img_nt_headers = (PIMAGE_NT_HEADERS)((byte*)img_dos_headers + img_dos_headers->e_lfanew); PIMAGE_IMPORT_DESCRIPTOR img_import_desc = (PIMAGE_IMPORT_DESCRIPTOR)((byte*)img_dos_headers + img_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); if (img_dos_headers->e_magic != IMAGE_DOS_SIGNATURE) printf("e_magic dos sig\n"); for (IMAGE_IMPORT_DESCRIPTOR *iid = img_import_desc; iid->Name != 0; iid++) { for (int func_idx = 0; *(func_idx + (void**)(iid->FirstThunk + (size_t)hModule)) != nullptr; func_idx++) { char* mod_func_name = (char*)(*(func_idx + (size_t*)(iid->OriginalFirstThunk + (size_t)hModule)) + (size_t)hModule + 2); const intptr_t nmod_func_name = (intptr_t)mod_func_name; if (nmod_func_name >= 0) { if (!::strcmp(szFunc, mod_func_name)) return func_idx + (void**)(iid->FirstThunk + (size_t)hModule); } } } return 0; } std::uint32_t detour_ptr(const char *szFunc, PVOID newfunction, HMODULE module) { void **&&func_ptr = find(szFunc, module); if (*func_ptr == newfunction || *func_ptr == nullptr) return 0; DWORD old_rights; DWORD new_rights = PAGE_READWRITE; VirtualProtect(func_ptr, sizeof (uintptr_t), new_rights, &old_rights); uintptr_t ret = (uintptr_t)*func_ptr; *func_ptr = newfunction; VirtualProtect(func_ptr, sizeof (uintptr_t), old_rights, &new_rights); return ret; } 2, include #include <windows.h> #include <cstdint> 3, WriteProcessMemory prototype, hook using WriteProcessMemoryFn = BOOL(__stdcall*)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*); WriteProcessMemoryFn oWriteProcessMemory; BOOL __stdcall hkWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten) { return oWriteProcessMemory(nullptr, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten); } 4, search--> bool Main(HINSTANCE hInstance, LPSTR lpCmdLine) and put it to the beginning oWriteProcessMemory = (WriteProcessMemoryFn)detour_ptr("WriteProcessMemory", (PVOID)hkWriteProcessMemory, GetModuleHandleA("Kernel32.dll")); This not only protects the MemoryBreak, but also all the cheats that WriteProcessMemory changes the game. Now he's hooked, so if something invites WriteProcessMemory to get a nullpt to the handle. Original post
  19. First of all, thanks to @ Syreldar for bringing this matter to my attention and prompting me to examine this script more closely. As the title suggests, you may be curious about the specific improvements and fixes that were made, as well as the nature of this script. About the script and what it does. The pre_qc.py script serves as a pre-compiler, specifically designed for the quest language. In the quest language, only local variables are allowed, and it does not support the usage of global variables that extend across states, whens, or functions. The language's structure restricts the use of global "variables" in an efficient manner. Consequently, creating a function like "setting()" to emulate a global constant becomes inefficient. What was fixed? The main fix made in this script was about the incomplete group implementation which is defined as `define group` instead of `define`. With the fix, it is now possible not only to use `define group` correctly but also to index through these tables, similar to indexing a regular Lua table. However, dynamic indexing of the global table is not supported, meaning you cannot pass a local variable to index the table (e.g., table[i]). It is necessary to index by number. Another improvement made to the script pertains to strings. Previously, only contiguous strings without spaces were allowed. Now, it is possible to define strings that contain spaces. How to define global values? Defining them are very easy and simple, just put them at the top of your quest. They work very similar as C's preprocessor to allow the use of global constants. define MACRO_A 9009 define MACRO_B "Hello World" define group MACRO_C ["Hello", "World"] quest pre_qc_test begin state start begin when MACRO_A.chat.MACRO_B begin say_title(MACRO_B) -- "Hello World" say(string.format("%s %s", MACRO_C[1], MACRO_C[2])) -- "Hello World" local a = MACRO_C -- { "Hello", "World" } say_reward(string.format("%s %s!", a[1], a[2])) -- "Hello World!" --[[ for i = table.getn(MACRO_C), 1, -1 do print(MACRO_C[i]) -- UNSUPPORTED! end ]] end end end The Script The script itself remains largely unchanged in its original form. However, a few modifications have been made to enhance its functionality. Firstly, a main guard has been added to ensure proper execution. Additionally, the replace function has been edited to ensure the correct functioning of groups. Similarly, the my_split function has been modified to preserve strings accurately. Furthermore, the token list has been slightly adjusted to accommodate the specific "macros" that need to be replaced. However, it can be further extended if additional macros require replacement in the future. pre_qc.py # -*- coding: 949 -*- # 말 그대로 pre qc. # 우리 퀘스트 언어에는 지역 변수만이 있고, # state나, 심지어 when, function을 아우르는 전역 변수를 사용할 수 없다. # 전역 '변수'의 사용은 언어의 구조상 사용이 불가하고, 별 의미가 없다. # 하지만 전역 '상수'의 사용은 퀘스트 view 상으로 꼭 필요하기 때문에, # fuction setting () 과 같은 함수를 이용하여, # 매번 테이블을 생성하여 전역 상수를 흉내내어 사용하였다. # 이는 매우 비효율적이므로, # c의 preprocesser와 같이 pre qc를 만들어 전역 상수를 사용할 수 있도록 하였다. # 퀘스트를 qc로 컴파일 하기 전에 pre_qc.py를 통과하면, # pre_qc.py는 define 구문을 처리하고, 그 결과를 # pre_qc/filename에 저장한다. TOKEN_LIST = [ "-", "+", "*", "/", "<", ">", "!", "=", "~", "[", "]", "{", "}", "(", ")", "\t", "\n", "\r", " ", ",", ".", ] def split_by_quat(buf): p = False l = list(buf) l.reverse() s = "" res = [] while l: c = l.pop() if c == '"': if p == True: s += c res += [s] s = "" else: if len(s) != 0: res += [s] s = '"' p = not p elif c == "\\" and l[0] == '"': s += c s += l.pop() else: s += c if len(s) != 0: res += [s] return res def AddSepMiddleOfElement(l, sep): l.reverse() new_list = [l.pop()] while l: new_list.append(sep) new_list.append(l.pop()) return new_list def my_split_with_seps(s, seps): res = [s] for sep in seps: new_res = [] for r in res: sp = r.split(sep) sp = AddSepMiddleOfElement(sp, sep) new_res += sp res = new_res new_res = [] for r in res: if r != "": new_res.append(r) return new_res def my_split(s, seps): res = [] curr_token = "" is_quoted = False for c in s: if c == '"': if is_quoted: curr_token += c res.append(curr_token) curr_token = "" else: if curr_token != "": res.append(curr_token) curr_token = '"' is_quoted = not is_quoted elif c in seps and not is_quoted: if curr_token != "": res.append(curr_token) curr_token = "" else: curr_token += c if curr_token != "": res.append(curr_token) return res def MultiIndex(list, key): l = [] i = 0 for s in list: if s == key: l.append(i) i = i + 1 return l def Replace(lines, parameter_table, keys): r = [] for string in lines: l = split_by_quat(string) for s in l: if s[0] == '"': r += [s] else: tokens = my_split_with_seps(s, TOKEN_LIST) for key in keys: try: indices = MultiIndex(tokens, key) for i in indices: if len(parameter_table[key]) > 1: if tokens[i + 1] == "[" and tokens[i + 3] == "]": tokens[i] = parameter_table[key][int(tokens[i + 2]) - 1] tokens[i + 1:i + 4] = ["", "", ""] # [x] else: tokens[i] = "{ " + ", ".join(str(x) for x in parameter_table[key]) + " }" else: tokens[i] = parameter_table[key][0] except: pass r += tokens return r def MakeParameterTable(lines, parameter_table, keys): group_names = [] group_values = [] idx = 0 for line in lines: idx += 1 line = line.strip("\n") if (-1 != line.find("--")): line = line[0:line.find("--")] tokens = my_split(line, TOKEN_LIST) if len(tokens) == 0: continue if tokens[0] == "quest": start = idx break if tokens[0] == "define": if tokens[1] == "group": group_value = [] for value in tokens[3:]: if parameter_table.get(value, 0) != 0: value = parameter_table[value] group_value.append(value) parameter_table[tokens[2]] = group_value keys.append(tokens[2]) elif len(tokens) > 5: print("%d %s" % (idx, "Invalid syntax")) print("define <name> = <value>") print("define group <name> = [<val1>, <val2>, ...]") else: value = tokens[2] if parameter_table.get(value, 0) != 0: value = parameter_table[value] parameter_table[tokens[1]] = [value] keys.append(tokens[1]) parameter_table = dict(zip(group_names, group_values)) return start def run(path, file_name): parameter_table = dict() keys = [] path = path.strip("\n") if path == "": return lines = open(path).readlines() start = MakeParameterTable(lines, parameter_table, keys) if len(keys) == 0: return False lines = lines[start - 1:] r = Replace(lines, parameter_table, keys) f = open("pre_qc/" + file_name, "w") for s in r: f.write(s) return True if __name__ == "__main__": import sys if len(sys.argv) < 3: print("Usage: python pre_qc.py <input_file> <output_file>") else: run(sys.argv[1], sys.argv[2]) Input / Output Examples Input This is also an example of how you would use these global constants. Output This is the script file converted with the values of the global constants. Note that this will be the file that will be compiled.
  20. Hey m2dev You summon a lot of monsters, they attack your character and then you kill or purge monsters, but the damage still continues to be shown visually. Is this a familiar situation? In addition, the damage is shown visually even after the death of the character... I love this game. I haven't seen a fix for this problem, let's try to fix this sh.. [Hidden Content] I'm not saying that this is an ideal solution. If you have any ideas, please write comments. Best regards, Masha
  21. Hello fine people, A little bit of context, recently we have been talking with @ msnas about doing an action upon server closure. Which is what the db/game should be doing by default when it exits MainLoop. However, I noticed that because of the way I shutdown my core, I wasn't receiving the right signal and was exiting the server before I can do any other actions. He then told me that he noticed this issue a long time ago because it was also present for him, only on Windows. Well, after a little bit of digging, I noticed that the signal was simply not handled on a Windows server. So here is a rudimentary (but working) signal management for Windows. I guess you can still rewrite the whole thing using more modern stuff like boost signal. But so far so good. Please not that you should close your db / game using CTRL+C or CTRL+BREAK if you want to gracefully shutdown. As a forced closure (closing the window, shutdown or task manager) would still not allow for the server to properly close, notably because it doesn't give enough grace time. So, here is the fix: Have a nice day!
  22. You cannot drop items from equipped items. Why? Why there are bugs when throwing equipped items -------------------------------BUG 1-------------------------------------- If you have sura/warrior aura and throw 1 item the aura is still there if (iWearCell == WEAR_WEAPON) { if (IsAffectFlag(AFF_GWIGUM)) { RemoveAffect(SKILL_GWIGEOM); } if (IsAffectFlag(AFF_GEOMGYEONG)) { RemoveAffect(SKILL_GEOMKYUNG); } } Fix bypass for this code You have aura ? drop items and this aura is work -------------------------------END-------------------------------------- -------------------------------BUG 2-------------------------------------- If your serverfiles have a problem with HP/SP and drop object the HP stays In some server files there are even more problems -------------------------------END-------------------------------------- Tested and works perfectly, I have player block for exploiting quite a few bugs with items To fix this solves every problem!!!! thanks you 1) OPEN input_main.cpp search: void CInputMain::ItemDrop2(LPCHARACTER ch, const char * data) Change with: #ifdef FIX_DROP_ITEMSSS void CInputMain::ItemDrop2(LPCHARACTER ch, const char * data) { TPacketCGItemDrop2 * pinfo = (TPacketCGItemDrop2 *) data; LPITEM pkItem = ch->GetItem(pinfo->Cell); if (!pkItem || !ch) return; if (pkItem->IsEquipped() == true) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("bug fixes items IsEquipped not drop.")); return; } if (pinfo->gold > 0) ch->DropGold(pinfo->gold); else ch->DropItem(pinfo->Cell); } #else void CInputMain::ItemDrop2(LPCHARACTER ch, const char * data) { TPacketCGItemDrop2 * pinfo = (TPacketCGItemDrop2 *) data; if (!ch) return; if (pinfo->gold > 0) ch->DropGold(pinfo->gold); else ch->DropItem(pinfo->Cell); } #endif 2) OPEN service.h add #define FIX_DROP_ITEMSSS ------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------- OPEN CLIENT ROOT OPEN: game.py search: if player.SLOT_TYPE_INVENTORY == attachedType: dropItemIndex = player.GetItemIndex(attachedItemSlotPos) item.SelectItem(dropItemIndex) dropItemName = item.GetItemName() ## Question Text questionText = localeInfo.HOW_MANY_ITEM_DO_YOU_DROP(dropItemName, attachedItemCount) ## Dialog itemDropQuestionDialog = uiCommon.QuestionDialog() itemDropQuestionDialog.SetText(questionText) itemDropQuestionDialog.SetAcceptEvent(lambda arg=True: self.RequestDropItem(arg)) itemDropQuestionDialog.SetCancelEvent(lambda arg=False: self.RequestDropItem(arg)) itemDropQuestionDialog.Open() itemDropQuestionDialog.dropType = attachedType itemDropQuestionDialog.dropNumber = attachedItemSlotPos itemDropQuestionDialog.dropCount = attachedItemCount self.itemDropQuestionDialog = itemDropQuestionDialog constInfo.SET_ITEM_QUESTION_DIALOG_STATUS(1) change with: if player.SLOT_TYPE_INVENTORY == attachedType: if player.IsEquipmentSlot(attachedItemSlotPos): self.stream.popupWindow.Close() self.stream.popupWindow.Open(localeInfo.EXCHANGE_FAILURE_EQUIP_DROPPP, 0, localeInfo.UI_OK) else: dropItemIndex = player.GetItemIndex(attachedItemSlotPos) item.SelectItem(dropItemIndex) dropItemName = item.GetItemName() questionText = localeInfo.HOW_MANY_ITEM_DO_YOU_DROP(dropItemName, attachedItemCount) itemDropQuestionDialog = uiCommon.QuestionDialog() itemDropQuestionDialog.SetText(questionText) itemDropQuestionDialog.SetAcceptEvent(lambda arg=True: self.RequestDropItem(arg)) itemDropQuestionDialog.SetCancelEvent(lambda arg=False: self.RequestDropItem(arg)) itemDropQuestionDialog.Open() itemDropQuestionDialog.dropType = attachedType itemDropQuestionDialog.dropNumber = attachedItemSlotPos itemDropQuestionDialog.dropCount = attachedItemCount self.itemDropQuestionDialog = itemDropQuestionDialog constInfo.SET_ITEM_QUESTION_DIALOG_STATUS(1) OPEN LOCALE CLIENT: locale_game.txt add EXCHANGE_FAILURE_EQUIP_DROPPP Hello friends i am sorry this bug is closed :( . OPEN LOCALE SERVER: locale_string.txt add "bug fixes items IsEquipped not drop." "bug fixes items IsEquipped not drop." You can now take a test Put on a weapon or armor and try to throw them down.
  23. Hello, So I have shared this fix with someone a few days ago and saw this morning that martysama has published it on it's blog. I let you know before kids with "private" access to this start playing with it. (I do not have acces to martysama's blog member posts and do not know who does) The "pc_change_name" function has an exploitable item duplication bug. The fix is simple, in "pc_change_name" replace this code: db_clientdesc->DBPacketHeader(HEADER_GD_FLUSH_CACHE, 0, sizeof(DWORD)); db_clientdesc->Packet(&pid, sizeof(DWORD)); with this: if (!CHARACTER_MANAGER::instance().FlushDelayedSave(ch)) { ch->SaveReal(); } I will edit this post to add details on how and why later on to avoid kids playing with it before it's patched on majority of servers. Regards,
  24. I noticed a few days ago that the inventory class was not getting freed upon rewarp. Circular dependency was causing the garbage collector to fail. The fix was fairly simple, so I fixed it and decided to share it with you. So here it is:
  25. [Hidden Content] -Items Blood Pill- Fixed the Blood Pill item Use by right clicking the item When a Blood Pill is used you will notice a minus sign (-) to the left side of your character's screen . Clicking that takes one point from the stat you choose and you can add it to another stat later . #1 Bug If you have x94 stat and hit 4 pills and spend 4 stat at the end when you add another stat then the stat doubles from 90 to 160 #2 Bug In some serverfiles it stat can be as high as -90 -80 -70 -30 -10 1) OPEN: cmd_general.cpp 2) Search: ACMD(do_stat_minus) 3) Change with: ACMD(do_stat_minus) { char arg1[256]; one_argument(argument, arg1, sizeof(arg1)); if (!*arg1) return; if (ch->IsPolymorphed()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("둔갑 중에는 능력을 올릴 수 없습니다.")); return; } if (ch->GetPoint(POINT_STAT_RESET_COUNT) <= 0) return; if (!strcmp(arg1, "st")) { if (ch->GetRealPoint(POINT_ST) <= JobInitialPoints[ch->GetJob()].st) return; BYTE stpoints = 0; stpoints = POINT_ST; ch->SetRealPoint(stpoints, ch->GetRealPoint(stpoints) - 1); ch->SetPoint(stpoints, ch->GetPoint(stpoints) - 1); ch->ComputePoints(); ch->PointChange(stpoints, 0); } else if (!strcmp(arg1, "dx")) { if (ch->GetRealPoint(POINT_DX) <= JobInitialPoints[ch->GetJob()].dx) return; BYTE dxpoints = 0; dxpoints = POINT_DX; ch->SetRealPoint(dxpoints, ch->GetRealPoint(dxpoints) - 1); ch->SetPoint(dxpoints, ch->GetPoint(dxpoints) - 1); ch->ComputePoints(); ch->PointChange(dxpoints, 0); } else if (!strcmp(arg1, "ht")) { if (ch->GetRealPoint(POINT_HT) <= JobInitialPoints[ch->GetJob()].ht) return; BYTE htpoints = 0; htpoints = POINT_HT; ch->SetRealPoint(htpoints, ch->GetRealPoint(htpoints) - 1); ch->SetPoint(htpoints, ch->GetPoint(htpoints) - 1); ch->ComputePoints(); ch->PointChange(htpoints, 0); ch->PointChange(POINT_MAX_SP, 0); } else if (!strcmp(arg1, "iq")) { if (ch->GetRealPoint(POINT_IQ) <= JobInitialPoints[ch->GetJob()].iq) return; BYTE iqpoints = 0; iqpoints = POINT_IQ; ch->SetRealPoint(iqpoints, ch->GetRealPoint(iqpoints) - 1); ch->SetPoint(iqpoints, ch->GetPoint(iqpoints) - 1); ch->ComputePoints(); ch->PointChange(iqpoints, 0); ch->PointChange(POINT_MAX_HP, 0); } else return; ch->PointChange(POINT_STAT, + 1); ch->PointChange(POINT_STAT_RESET_COUNT, - 1); ch->ComputePoints(); }
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.