Jump to content
  • Create New...

Search the Community

Showing results for tags 'c++'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • Metin2 Dev
    • Announcements
    • Discord
    • Pillory
    • Top Metin2
    • Metin2 Dev Wiki
  • Community
    • Member Representations
    • Off Topic
  • Metin2
    • General
    • Private Servers
  • Help Center
    • Questions & Answers
    • File Requests
  • Releases
    • Basic Tutorials / Beginners
    • Guides & HowTo
    • Binaries
    • Programming & Scripts / Systems
    • Web Development & Scripts / Systems
    • Tools & Programs
    • Maps
    • Quests
    • 3D Models
    • 2D Graphics
    • Operating Systems
    • Others
  • Marketplace
    • Join the Marketplace - Sales & Services
    • Searching
  • Miscellaneous
    • Trash
    • Archive
    • Temporary
  • Forum Bureau of Investigation's Forum

Product Groups

  • Header & Footer
  • Topic & Forum
  • Pack


Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start



My Message









  1. Preview: [Hidden Content] The system is easy to implent. *For the affect icon to be seen in the affectshower you can add : Then extend it with the steps @ uiAffectShower.py. * If you have extended sockets before, You can make modifications to get rid of the value0 necessity. * You can skip (Optional) steps. Download: MEGA or M2DL
  2. Yo! If you have an item with a limit type LIMIT_REAL_TIME_START_FIRST_USE that has been used at one point and put it inside the safe-box, it will not be removed from the game until you pull it out of the safe-box and perform a teleport. item.h // Search: protected: friend class CInputDB; // Add below: friend class CHARACTER; char.cpp // Search: void CHARACTER::LoadSafebox(int iSize, DWORD dwGold, int iItemCount, TPlayerItem * pItems) { [...] if (!m_pkSafebox->Add(pItems->pos, item)) { M2_DESTROY_ITEM(item); } else item->SetSkipSave(false); // Modify to: if (!m_pkSafebox->Add(pItems->pos, item)) { M2_DESTROY_ITEM(item); } else { item->OnAfterCreatedItem(); item->SetSkipSave(false); }
  3. This vulnerability should affect every server. You can duplicate item rewards, and also crash the server through dangling pointers. The danger of this bug escalates to how many custom systems, and how many crafting quests (for example, the vitality ore quest, not the cube system) you have in your server. How to trigger it: Any quest that uses select & wait, and the item lua module after that is vulnerable. After the server uses select() or wait(), the player's quest state is suspended. After the player replies using the CG packet, the quest state is recovered. So what's wrong with it? It doesn't verify if the stored quest item ptr expired. You basically need to destroy the selected item ptr in order to dupe the rewards of the quest. After some tries, you may get a core crash in the game. (dangling pointers often cause crashes only after that memory sector has been rewritten) In my files, I've checked (since several years ago) if the quest state was suspended for the the default windows such as exchange, cube, shop. This bug can work very easily on offline shops or other new systems that don't check that. After the select() or wait() is called, you send the selected item to the (e.g.) offlineshop system window. It will delete the item ptr in the game. Now, you can press "Ok" on the quest, and the quest will proceed as if the item still existed. The item still exists in the offlineshop, but not the item ptr anymore. The item won't be deleted by the quest even after item.remove() is called. This is the fix: diff --git a/s3ll_server/Srcs/Server/game/src/char.cpp b/s3ll_server/Srcs/Server/game/src/char.cpp index 0ea307fa..65b1dd65 100644 --- a/s3ll_server/Srcs/Server/game/src/char.cpp +++ b/s3ll_server/Srcs/Server/game/src/char.cpp @@ -303,7 +303,10 @@ void CHARACTER::Initialize() m_dwQuestNPCVID = 0; m_dwQuestByVnum = 0; - m_pQuestItem = NULL; + m_dwQuestItemVID = 0; m_dwUnderGuildWarInfoMessageTime = get_dword_time()-60000; @@ -6123,33 +6126,37 @@ LPCHARACTER CHARACTER::GetQuestNPC() const void CHARACTER::SetQuestItemPtr(LPITEM item) { - m_pQuestItem = item; + m_dwQuestItemVID = (item) ? item->GetVID() : 0; } void CHARACTER::ClearQuestItemPtr() { - m_pQuestItem = NULL; + m_dwQuestItemVID = 0; } LPITEM CHARACTER::GetQuestItemPtr() const { - return m_pQuestItem; + if (!m_dwQuestItemVID) + return nullptr; + return ITEM_MANAGER::Instance().FindByVID(m_dwQuestItemVID); } diff --git a/s3ll_server/Srcs/Server/game/src/char.h b/s3ll_server/Srcs/Server/game/src/char.h index cc4da2bb..74b3470e 100644 --- a/s3ll_server/Srcs/Server/game/src/char.h +++ b/s3ll_server/Srcs/Server/game/src/char.h @@ -1674,9 +1674,9 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider private: DWORD m_dwQuestNPCVID; DWORD m_dwQuestByVnum; - LPITEM m_pQuestItem; + DWORD m_dwQuestItemVID{}; // @fixme304 (LPITEM -> DWORD) // Events To unlock the client in order to move your windows with a quest open, you edit this from interfacemodule.py: You can even Hide the TopBar and BottomBar from uiQuest.py for a better result. Important: after this fix, the item ptr may be nullptr after they press enter, so you need to check if the item ptr is still valid by using this function: ALUA(item_is_available) { auto item = CQuestManager::instance().GetCurrentItem(); lua_pushboolean(L, item != nullptr); return 1; } ... { "is_available", item_is_available }, // [return lua boolean] By simply doing: when 169.take begin local s1=select("Yes", "No") if s1==2 then return end if not item.is_available() then return end end If you want to tryhard, and be sure that the item ptr didn't get swapped, you can do as following via quest:
  4. Download Other Mirros Download Here (GitHub) Download Here (Mega) Ship Defense is a dungeon accessible only in groups (minimum 2 players, maximum 8) in which players set sail for the new continent defending the ship’s mast from increasingly stronger and more numerous monsters until they defeat all three heads of the Hydra boss. Once the mission is complete, the participants will receive some rewards (determined by chance). Information Demonstration
  5. Char.h Replace this: void ForgetMyAttacker(bool revive = true); Char_battle.cpp Replace this: void CHARACTER::ForgetMyAttacker(bool revive) { const LPSECTREE pSec = GetSectree(); if (pSec) { FuncForgetMyAttacker f(this); pSec->ForEachAround(f); } if (revive) ReviveInvisible(5); } Char_skill.cpp Search the function: CHARACTER::ComputeSkill( and ADD below // ADD_GRANDMASTER_SKILL ..... // END_OF_ADD_GRANDMASTER_SKILL This //Ninja Stealth improve if (IsPC() && pkSk->dwVnum == SKILL_EUNHYUNG) ForgetMyAttacker(false); Hope you like it
  6. M2 Download Center Download Here ( Internal ) Download Here ( GitHub ) [Hidden Content]
  7. Download Center Download Github Hello. So, i was bored and saw that nobody coded this (or someone did but never released) even though it was made like 3 years ago, so there you go.
  8. M2 Download Center Download Here ( Internal ) Hello, To extend NPC Shop to 80 Items follow these steps. ServerSide Open "common/length.h" and search: SHOP_HOST_ITEM_MAX_NUM = 40 Replace with: SHOP_HOST_ITEM_MAX_NUM = 80 In the same file search: SHOP_PRICELIST_MAX_NUM = 40 Replace with: SHOP_PRICELIST_MAX_NUM = 80 Now open "game/shop.cpp" and search: m_pGrid = M2_NEW CGrid(5, 9) Replace with: m_pGrid = M2_NEW CGrid(10, 9) Now open "game/shop_manager.cpp" and search: CGrid grid = CGrid(5, 9) Replace with: CGrid grid = CGrid(10, 9) Now compile Db File & Game File and ServerSide's steps complete. ClientSide NOTE: If you want Only NPC Shop's with 80 Items follow this guide, else if you want NPC Shop & Private Shop follow the Update Istruction. Extract "pack/uiscript" from your Client and open "shopdialog.py". Now reaplace all content with: Shopdialog.py ~ 80 Items Now create "shopdialog2.py" and insert this content: ShopDialog2 ~ 80 Items for Shop Ok, at this point you can compress your UiScript with the new file "shopdialog2.py". Extract "pack/root" from your Client and open "interfacemodule.py" Search this: self.dlgShop = uiShop.ShopDialog() self.dlgShop.LoadDialog() self.dlgShop.Hide() After add: self.dlgShop2 = uiShop.ShopDialog2() self.dlgShop2.LoadDialog() self.dlgShop2.Hide() Same file, search this: def OpenShopDialog(self, vid): self.wndInventory.Show() self.wndInventory.SetTop() self.dlgShop.Open(vid) self.dlgShop.SetTop() After add: def OpenShopDialog2(self, vid): self.wndInventory.Show() self.wndInventory.SetTop() self.dlgShop2.Open(vid) self.dlgShop2.SetTop() Now open "game.py" and Search: def StartShop(self, vid): self.interface.OpenShopDialog(vid) Replace with: def StartShop(self, vid): if chr.IsNPC(vid): self.interface.OpenShopDialog(vid) else: self.interface.OpenShopDialog2(vid) Now open "uishop.py" and Search: def Close(self): self.OnCloseQuestionDialog() shop.Close() net.SendShopEndPacket() self.CancelShopping() self.tooltipItem.HideToolTip() self.Hide() Replace with: def Close(self): self.OnCloseQuestionDialog() shop.Close() net.SendShopEndPacket() self.CancelShopping() self.Hide() Same file, search: def OnUpdate(self): USE_SHOP_LIMIT_RANGE = 1000 (x, y, z) = player.GetMainCharacterPosition() if abs(x - self.xShopStart) > USE_SHOP_LIMIT_RANGE or abs(y - self.yShopStart) > USE_SHOP_LIMIT_RANGE: self.Close() After add: UiShop.py ~ ShopDialog2 Now you can compress "root" file. #Update [24-02-15] Fixed Client Bug. Changes in "shop_manager.cpp" added. #Update [26-02-15] Added PrivateShop with 80 Items. NPC & PrivateShop with 80 Items ClientSide: Open "UserInterface/Packet.h" in you Binary Client Source and Search: SHOP_HOST_ITEM_MAX_NUM = 40 Replace with: SHOP_HOST_ITEM_MAX_NUM = 80 Now you can compile your Binary Source. Open your Client File and extract "pack/uiscript". Open "shopdialog.py" and replace all contentwith: Shopdialog.py ~ 80 Items Now open "privateshopbuilder.py" and replace all content with: PrivateShopBuilder ~ 80 Items Now you can compress your UiScript. Screen Private Shop: [Hidden Content] Et Voilà, we ended. [Hidden Content] Good work, Bye.
  9. Download Metin2 Download or Github Time of loading each fragment of the game before and after
  10. Hey guys, Today I was facing with a guild melting problem, the problem was that the stones which are in the special inventory is not shown in the SelectItemWindow. I managed to solve this by adding a new check for special inventory size && special inventory slot end. In this tutorial the codes may be different from yours, if you have Sanii Special Inventory you have to check your GameType.h how is page size calculated and your PythonPlayerModule.cpp to see how it's defined. For example: PythonPlayerModule.cpp-> PyModule_AddIntConstant(poModule, "SPECIAL_INVENTORY_PAGE_SIZE", SPECIAL_INVENTORY_PAGE_SIZE); PyModule_AddIntConstant(poModule, "SPECIAL_INVENTORY_SLOT_END", c_Special_Inventory_Slot_End); GameType.h-> SPECIAL_INVENTORY_WIDTH = 5, SPECIAL_INVENTORY_HEIGHT = 9, SPECIAL_INVENTORY_PAGE_SIZE = SPECIAL_INVENTORY_WIDTH * SPECIAL_INVENTORY_HEIGHT, const DWORD c_Special_Inventory_Slot_Start = c_Belt_Inventory_Slot_End; const DWORD c_Special_Inventory_Skillbook_Slot_Start = c_Special_Inventory_Slot_Start; const DWORD c_Special_Inventory_Skillbook_Slot_End = c_Special_Inventory_Skillbook_Slot_Start +SPECIAL_INVENTORY_PAGE_SIZE * c_Inventory_Page_Count; const DWORD c_Special_Inventory_Stone_Slot_Start = c_Special_Inventory_Skillbook_Slot_End; const DWORD c_Special_Inventory_Stone_Slot_End = c_Special_Inventory_Stone_Slot_Start + SPECIAL_INVENTORY_PAGE_SIZE * c_Inventory_Page_Count; const DWORD c_Special_Inventory_Material_Slot_Start = c_Special_Inventory_Stone_Slot_End; const DWORD c_Special_Inventory_Material_Slot_End = c_Special_Inventory_Material_Slot_Start + SPECIAL_INVENTORY_PAGE_SIZE * c_Inventory_Page_Count; const DWORD c_Special_Inventory_Slot_End = c_Special_Inventory_Material_Slot_End; const DWORD c_Inventory_Count = c_Special_Inventory_Slot_End; Solution: root/uiselect.py In def RefreshSlot(self): search for: for i in xrange(player.INVENTORY_PAGE_SIZE*player.INVENTORY_PAGE_COUNT): After for loop add a new for loop for the special inventory: for i in xrange(player.SPECIAL_INVENTORY_PAGE_SIZE*player.SPECIAL_INVENTORY_SLOT_END): slotNumber = i itemVNum = getItemVNum(slotNumber) if 0 == itemVNum: continue if not item.IsMetin(itemVNum): continue itemGrade = player.GetItemGrade(slotNumber) if itemGrade > 2: continue self.inventorySlotPosDict[slotPos] = i slotPos += 1 if slotPos > 54: break Another problem is that if you select 100 stack of stone in the SelectItemWindow, they all disappear from the inventory, so instead of one piece, all of them disappear. Solution: mining.cpp Search for: ITEM_MANAGER::instance().RemoveItem(metinstone_item, "REMOVE (MELT)"); Replace with: metinstone_item->SetCount(metinstone_item->GetCount() - 1); I hope it will be useful for you Author of special inventory: @Sanii. @LordZiege approved me to share this fix.
  11. M2 Download Center Download Here ( Internal ) [Hidden Content] I already created some of it for the transmutation system. It's best to separate it. Client part is from 2018 official root. You can set different colors: Spoiler You can enable flash effect: Spoiler Spoiler self.wndItem.SetSlotDiffuseColor(i, wndMgr.COLOR_TYPE_YELLOW) self.wndItem.SetSlotFlashEffect(i, True)
  12. The problem: Mobs are using CHARACTER_POINT_INSTANT struct, which contains fixed size arrays for dragon soul, items etc. For every mob these arrays are allocating memory, but mobs obviously don't use items... The solution: Replace fixed size arrays with std::map or other data type From my own testing i saw over 70% memory usage reduction with special inventory system and optimized variables listed below: bItemGrid pItems pDSItems wDSItemGrid Below i am sharing example implementation in clean source for bItemGrid variable
  13. Hello guys, I am once again coming with a really little fix that is related to rare attribute (6/7 bonuses). This bug is extra rare because to trigger it you must have a way to add 6 and 7 bonuses to an item and you must have an incorrect field or an error in your item_attr_rare table. So this is most likely a code sanitization but it's always good to avoid such errors as I encountered people having this bug. When you add a rare bonus, the game will fill a vector with the bonuses from the table and randomly pick one in the vector. However, if you have an error in the table, this vector will be empty and the randomization will result in doing "number(0, -1)", which is obviously incorrect and your core will crash. For searching purposes (if someone in the future is looking for a fix), the error is this one : The fix is really simple, we must check if the vector is empty and then exit at this moment. In item_attribute.cpp, in the following function: bool CItem::AddRareAttribute() Under this block of code: for (int i = 0; i < MAX_APPLY_NUM; ++i) { const TItemAttrTable& r = g_map_itemRare[i]; if (r.dwApplyIndex != 0 && r.bMaxLevelBySet[nAttrSet] > 0 && HasRareAttr(i) != true) { avail.push_back(i); } } Add the following check: [Hidden Content] And that's pretty much it, pretty straightforward, but instead of crashing, you will have a syserr and you will know what to check next!
  14. Hi all. I would like to share this little modification with this community. This idea came from a queastion what i saw today, u can see and read about it at dropitem effect. By this modification u can attach filtered effect to drop item on the ground. U can easy filter an item by item's vnum, item type and subtype then give different effect to the items. With this method for example you can seperate items by rarity, but the border is the starry sky. Let's see: Step I. I. Open the "UserInterface/PythonItem.h" and look for the following line: typedef struct SGroundItemInstance II. and before that line add the following lines: enum EDropItemEffects { DROP_ITEM_EFFECT_NORMAL, DROP_ITEM_EFFECT_RARE, DROP_ITEM_EFFECT_EPIC, DROP_ITEM_EFFECT_LEGENARY, DROP_ITEM_EFFECT_NUM, }; III. and now, you have to look for the folowing line: DWORD __Pick(const POINT& c_rkPtMouse); IV. and before that line add the following lines: void __RegisterEffect(int iIndex, const char* szFile); int __AttachEffect(DWORD dwVnum, BYTE byType, BYTE bySubType); V. last one in this step, look for the following line: DWORD m_dwDropItemEffectID; VI. and replace that line with the following line: DWORD m_dwDropItemEffectID[DROP_ITEM_EFFECT_NUM]; Step II. I. Open the "UserInterface/PythonItem.cpp" and look for the following lines: // attaching effect CEffectManager & rem =CEffectManager::Instance(); pGroundItemInstance->dwEffectInstanceIndex = rem.CreateEffect(m_dwDropItemEffectID, D3DXVECTOR3(x, -y, z), D3DXVECTOR3(0,0,0)); II. and replace those lines with the following lines: // attaching effect DWORD dwEffectIndex = __AttachEffect(dwVirtualNumber, pItemData->GetType(), pItemData->GetSubType()); if(dwEffectIndex < DROP_ITEM_EFFECT_NUM && dwEffectIndex >= 0) { dwEffectIndex = m_dwDropItemEffectID[dwEffectIndex]; if(dwEffectIndex != 0) { CEffectManager & rem =CEffectManager::Instance(); pGroundItemInstance->dwEffectInstanceIndex = rem.CreateEffect(dwEffectIndex, D3DXVECTOR3(x, -y, z), D3DXVECTOR3(0,0,0)); } } III. and now, you have to look for the folowing function: void CPythonItem::Create() IV. and replace that whole function with the following: void CPythonItem::Create() { //Default __RegisterEffect(DROP_ITEM_EFFECT_NORMAL, "d:/ymir work/effect/etc/dropitem/dropitem.mse"); //Rare __RegisterEffect(DROP_ITEM_EFFECT_RARE, "d:/ymir work/effect/etc/dropitem/dropitem_rare.mse"); //Epic __RegisterEffect(DROP_ITEM_EFFECT_EPIC, "d:/ymir work/effect/etc/dropitem/dropitem_epic.mse"); //Epic __RegisterEffect(DROP_ITEM_EFFECT_LEGENARY, "d:/ymir work/effect/etc/dropitem/dropitem_legendary.mse"); } V. and now, you have to look for the folowing line: m_dwPickedItemID = INVALID_ID; VI. and after that line add the following lines: memset(m_dwDropItemEffectID, 0, sizeof(m_dwDropItemEffectID)); VII. last one in this step, look for the following lines: CPythonItem::~CPythonItem() { assert(m_GroundItemInstanceMap.empty()); } VIII. and after that lines add the following lines: void CPythonItem::__RegisterEffect(int iIndex, const char* szFile) { if(iIndex >= DROP_ITEM_EFFECT_NUM || iIndex < 0) { TraceError("CPythonItem::__RegisterEffect - Invalid index: %d - %s", iIndex, szFile); return; } CEffectManager::Instance().RegisterEffect2(szFile, &m_dwDropItemEffectID[iIndex]); } int CPythonItem::__AttachEffect(DWORD dwVnum, BYTE byType, BYTE bySubType) { //Examples: //Determine the effect by item VNUM switch(dwVnum) { //Rare - These are the rare item vnums case 101: case 2001: return DROP_ITEM_EFFECT_RARE; //Epic - These are the epic item vnums case 3025: case 3229: return DROP_ITEM_EFFECT_EPIC; } //Determine the effect by item type/subtype switch(byType) { //Epic - This is the epic item type case CItemData::ITEM_TYPE_ARMOR: return DROP_ITEM_EFFECT_EPIC; //Filter by the material item type case CItemData::ITEM_TYPE_MATERIAL: { switch(bySubType) { //Epic - This is the epic item subtype case CItemData::MATERIAL_LEATHER: return DROP_ITEM_EFFECT_EPIC; //Legendary - This is the legendary item subtype case CItemData::MATERIAL_JEWEL: return DROP_ITEM_EFFECT_LEGENARY; } //Rare - All other ITEM_TYPE_MATERIAL type items return DROP_ITEM_EFFECT_RARE; //Default } } return DROP_ITEM_EFFECT_NORMAL; //Default } We are done now ! Important: In the "int CPythonItem::__AttachEffect" function you can see some example, that is not the final code, you have to config it like you want it to work! And you have to create those effect files what you register in the "void CPythonItem::Create()" function! You can add more effect separation by extending the "Step I. - II. - EDropItemEffects" enum. Preview:
  15. M2 Download Center Download Here ( Internal ) Hey guys, Today I'm releasing the tutorial for Boss Effect Over Head. Picture of system: Download link: Pastebin tutorial (only): Special thanks to: @Syreldar @M.Sorin for some functions which I used in the tutorial. I believe someone will use that Have a nice day/night! Sincerely, ReFresh
  16. M2 Download Center Download Here ( Internal ) char_skill.cpp search: if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY)) ComputeSkill(dwVnum, this); add before: //Party buff system if (GetParty() && (dwVnum == 94 || dwVnum == 95 || dwVnum == 96 || dwVnum == 110 || dwVnum == 111)) { if (pkVictim->GetParty()){ if (pkVictim->GetParty() == GetParty()){ ComputeSkillParty(dwVnum, this); } } }
  17. You can gain performance by turning off the spawn effects of monsters spawned in groups. Before: After: /**************************************************Game********************************************/ //Game/char.cpp //X2 Search: m_afAffectFlag.Set(AFF_SPAWN); //And Replace: // m_afAffectFlag.Set(AFF_SPAWN); /**************************************************Client*******************************************/ //UserInterFace/InstanceBase.cpp //Search: if (IsAffect(AFFECT_SPAWN)) __AttachEffect(EFFECT_SPAWN_APPEAR); //Replace: /*if (IsAffect(AFFECT_SPAWN)) __AttachEffect(EFFECT_SPAWN_APPEAR);*/ // UserInterFace/InstanceBaseBattle.cpp //Search: if (IsAffect(AFFECT_SPAWN)) __AttachEffect(EFFECT_SPAWN_DISAPPEAR); //Replace: /*if (IsAffect(AFFECT_SPAWN)) __AttachEffect(EFFECT_SPAWN_DISAPPEAR);*/
  18. Hello guys, Today I had the need to make a quest that had to trigger an action upon taking a goto. I didn't find any vanilla way to do it, so here we are, maybe it will be useful to someone. Please note that I did that on the fly, quickly and it's very rudimental, so if you have any comments about it, feel free to tell me or to contribute to this. I would be grateful as well. The tutorial is written for any vanilla 2014 files, so edit as you should for you. [Hidden Content] You can also refine it with other checks. But now you are able to check for example when someone is crossing a goto portal. Enjoy!
  19. M2 Download Center Download Here / Download Here / Download Here / Download Here / Download Here / Download Here Anti Wait Hack: Anti Safezone: Anti Ghostmode: Anti Wallhack: Anti Long name generator: #Update 1: -Clientside- -Serverside- Anti Mining Bot: Fishing without water fix Anti Colorful Shop Anti Drophack #Update 2: -Serverside- Anti Fish Bot Anti Guild Maker(low level) Activate Anti Teleport Hack -Clientside- Activate py inject protection Anti Anti Stun & Anti Visual GM Effect Anti Attackspeed & Anti Movespeed This thread subjects enough for general cheats For better bot and script cheat security change module or function names For this here basic tutorial for change net module name
  20. If anyone had bought the VegaS' client optimization, they know that the loading of the motion files, depending on the loading vector's size, can take a bit of time, especially if you have 3642 files to load (totally random number ) N.B. I won't display even a single byte of the VegaS system's code. I would be happy to assist you if you are a customer of his and have purchased his client optimization (I will confirm with him, but I won't offer support for leaked stuff). Alrright, so, at first I thought to simply create a new "HWND" and work on that one, but, since it would run on the same instance as the client, it wouldn't be just as smooth. So just initialize a different instance and load the window on that instance? Sure, but, also no, too much of an hassle. A simpler solution would be to start a new app with the client who would receive the progress of the loading and show a progress bar or something, just to inform the player that the client is actually opening. Technically the project can be used for just anything else, like a separate menu integrated into the client or something, although the framework I used is not intended to fully work with DX8, so there might be some glitches considering what you wanna do with it. Now, let's dive into it, because it's not just a plug-and-play thing. Let's start by saying the app is made using a framework called ImGui: [Hidden Content] What's need to be done? Let's start with the name and the size (in this case 1280x800) of the main Application. You can find it on LoadingWindowHandler.cpp: m_HWND = ::CreateWindow(m_WCEX.lpszClassName, _T("Dear ImGui DirectX8 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, m_WCEX.hInstance, NULL); If you've had any experience on Win32 APIs, do not do this: SetWindowLong(hWnd, GWL_STYLE, 0); It breaks the text. If there is a fix, I haven't found one, yet. Second thing, ImGui stores the position and the size of the child windows inside a .ini file, called imgui.ini For example, in my case, I have: [Window][MainWindow] Pos=98,165 Size=1266,750 Collapsed=0 (declared in imgui.cpp line 4556) and then: [Window][TopWindow] Pos=0,0 Size=1265,762 Collapsed=0 Which is the window where we're gonna render the background, text and progressbar. Obviously, depending on your image size, these settings should be changed. We can also edit the size of the "TopWindow" actually running the application and resize it there. To do that, we can just de-comment: #define TEST_PROGRESS_BAR in LoadingWindowHandler.h After that, we need to change the Configuration Type: then we can open the application and move the window: Or resize it: Once closed, the application will have changed the settings in the ini file: [Window][MainWindow] Pos=98,165 Size=1266,750 Collapsed=0 [Window][TopWindow] Pos=-78,-120 Size=967,524 Collapsed=0 This way you can resize/move the window according to your background image. It is also possible to change the name of the ini file in imgui.cpp IniFilename = "imgui.ini"; To change the background image you want to edit the directory and name here: std::string filepath = cwd.string() + "\\movie\\splash.bmp"; From Microsoft docs the formats supported are: .bmp, .dds, .dib, .hdr, .jpg, .pfm, .png, .ppm, and .tga. How are the positions of the ProgressBar, Text and background handled? Well, let's start from the background: ImGui::SetCursorPosY(0); auto size = ImGui::GetContentRegionAvail(); ImGui::Image((void*)SplashImage, ImVec2(size.x, size.y)); ImGui::SetCursorPosY(0); is like saying "go to the Y coord 0", then the rest is to "resize" the background image to the Area of the "TopWindow". The style of the ProgressBar is in LoadingWindowDesigner.cpp: #include "LoadingWindowDesigner.h" #include <ImGui/imgui.h> namespace LoadingWindowDesigner { void RenderUI(float progress, std::string loading_text) { auto window_size = ImGui::GetWindowSize(); ImGui::SetCursorPosY(window_size.y - 30); ImGui::Text(loading_text.c_str()); ImGui::ProgressBar(progress, ImVec2(window_size.x - 15.0f, 5.0f), ""); } } Again, with SetCursorPosY we are saying to go specific Y coords, in this case at the bottom of the window minus 30 pixels, that's where it's gonna write the text, then we draw the ProgressBar. The numbers inside ImVec2 are the dimensions of the ProgressBar. There's a third parameter where you could set an overlay text to the ProgressBar. If you wanna change the Font, well: [Hidden Content]/blob/master/docs/FAQ.md#q-how-can-i-load-a-different-font-than-the-default If you wanna change the color of the moving bar, you can go to imgui_widgets.cpp and change this line: RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_ButtonHovered), 0.0f, fraction, style.FrameRounding); The background instead is on this line: RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); The colors specified are the ones with the index: ImGuiCol_ButtonHovered and ImGuiCol_FrameBg. All this stuff can be seen by downloading the framework from the github repository and launching a project from the examples folder. The ImGui Demo window will show every possible option that you can then check on the source code (even the colors, that I found playing around with the demo window). One thing you'd notice from the window, is that there are some weird borders, and we can delete those (in my example, they actually fit pretty well with the background, so I left them. To do that just de-comment the other define: //#define LOADING_WINDOW_NOBORDERS P.S. There might be a few pixel modification on the ini file to do afterwards on the "TopWindow", noticeable when opening the client, because of the removal of the borders (if you did). Usually the correction is around 8px, which is the default padding of the framework, if I am not mistaken. You could also adjust the padding). So, we chose a background image, set the window size accordingly, positioned the text and rendered the progressbar as we wanted. And for now, we are done with the library (remember to change the configuration type to .lib and comment: #define TEST_PROGRESS_BAR Now compile the library both in Debug and Release mode, and add them to the lib folder of the client. After that open LinkerLibraries.h and add: #ifdef _DEBUG #pragma comment(lib, "LoadingWindowLib_d.lib") #else #pragma comment(lib, "LoadingWindowLib.lib") #endif then in StdAfx.h we add: #include "LoadingWindowMain.h" Then add on your include folder: LoadingWindowDesigner.h LoadingWindowHandler.h LoadingWindowMain.h You also need to add the ImGui folder (only the header files): Now if you have linking/compile errors, that's because your DirectX folder or your include directory, on the Project Settings, are different. To fix it you need to change the path in "Additional Include Properties" in the lib project so that your #include <directxheader> directive is the same as in the client. After confirming that everything works, how to use it: auto LoadingWindow = std::thread(LoadingWindow::InitializeLibrary); LoadingWindow.detach(); CPythonApplication *app = new CPythonApplication(); app->Initialize(hInstance); This will start a new thread running the library. How to change the progress percentage and the text? Let's say you have a number of executions: static auto EXECUTION_TIMES = 100000; float progress_adder = (1.0f - progress)/static_cast<float>(EXECUTION_TIMES); the "number" we are gonna add to the progress bar is gonna be his total (1.0f) minus the actual progress in that moment (if 0, you could just do 1.0f/static_cast<float>(EXECUTION_TIMES). Then on the loop of your loading stuff function you can change the text before the loop, or inside (if you wanna show something for every execution) and the actual progress: LoadingWindow::UpdateProgressText("Executing tasks..."); for (auto i = 0; i < EXECUTION_TIMES; ++i) { progress += progress_adder; // call a function here LoadingWindow::UpdateProgress(progress); } Always remember that the progress is a float and the "percentage" goes from 0.0f to 1.0f Now, in theory, the library should close itself when it gets to 1.0: if (m_Progress >= 1.0f) m_Done = true; but, at least in my case, it's also possible that it ends with a number such as 0.9999628 or something like that, so we can just call the CleanUpLibrary method to just close it when we want it. And that's it. Result: [Hidden Content] N.B. Despite working, if you intend to use this framework for other stuff, like some external menus to open from the client or w/e you have in mind, the DX8 version is super glitchy when there are two windows open: [Hidden Content]/issues/5379 and if you think you can use a different DirectX version, I am sorry to disappoint you: As you can see, when trying to load the texture, it's calling the "AddRef()" method: bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) { ImGuiIO& io = ImGui::GetIO(); IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!"); // Setup backend capabilities flags ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)(); io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_dx9"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. bd->pd3dDevice = device; bd->pd3dDevice->AddRef(); //<----------- return true; } but, the client calls the DX8 APIs, not DX9, ergo no DirectX different than 8.1 Can you use a different framework? Sure, you may always use a similar approach with another similar GUI App, like the CefWebBrowser, but on a different thread, because the webbrowser runs on the same instance of the client: int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { #ifdef _DEBUG _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_CRT_DF | _CRTDBG_LEAK_CHECK_DF ); //_CrtSetBreakAlloc( 110247 ); #endif LocaleService_LoadConfig("locale.cfg"); SetDefaultCodePage(LocaleService_GetCodePage()); CefWebBrowser_Startup(hInstance); //<------------- Credits: ocornuti, the owner of ImGui's repository KsaNL for providing a base for ImGui on DX8 Ikarus for dealing with my mental illness during this mini-project Project Download: Mega (or Metin2 Download)
  21. M2 Download Center Download Here ( Internal ) I know many people like me come here or try to find in another forums this select new character official.. and is just a part or is incomplete.. but i find a full version and i come here to reupload. so GL on servers. For make large description on characters / kingdoms: Check change BOX_VISIBLE_LINE_COUNT from 5 to 14 in PythonEventManager.h Thanks @Lajk Download: [Hidden Content]
  22. Hello everyone, I was optimizing the loading of maps for my server and I decided to share it with the public. With this modifications, only the objects and effects around the character will be loaded and it will handle their load and unload as you move around. Also effect updatings are optimized a way that closer effects are updated more frequently. Okay, so let's start the work [Hidden Content] Good luck!
  23. M2 Download Center Download Here ( Internal ) Download Here ( GitHub ) Hi guys, I leave the system of PENDANT, It's basically like the official system, If you see something is missing, you can tell me.
  24. Download Metin2 Download [Hidden Content] It's working without serverside.
  25. M2 Download Center Download Here ( Internal )

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.