-
Posts
81 -
Joined
-
Last visited
-
Feedback
0%
About Dex

Informations
-
Gender
Male
Recent Profile Visitors
2733 profile views
Dex's Achievements
-
Dex started following tree texture bug? and Fix Target Info System
-
Changelog 22.02.2026 - System theme added - Translations introduced for DE, FR, GR, IT, NL, PT, RO, RU, ES, CZ, TR, HU - Remote/Local FileBrowser introduced with autodiscover + autocomplete - SSH connections can now also be established using SSH keys with and without passphrase - Shortcut for saving introduced (CTRL + S / CMD + S) - Improved reading of npclist.txt to handle different cases for some models that do not have standard paths, as well as aliases for different naming conventions and cases where the same model has different textures - Shop module completely reworked: - Global / per-shop grid configuration - Grid configuration limited to a maximum of 15x15 - Maximum stack size is now configurable - Shop name can be changed - Shops can now be deleted - Tooltips now correctly load the item name instead of the VNUM - Item quantity automatically adjusts to the configured maximum amount - Adding new items automatically loads only items that are not already in the shop - The item list when inserting automatically adapts to the grid size, so only items that fit can be added - NPC can now be changed by clicking on the VNUM - Proto modules now retain their configuration when leaving the page - Theme switcher replaced with toggle buttons for selecting between the 3 modes Preview
-
Ahoi, there are some news! To achieve more compatibility and flexibility, the M2Manager has been fully refactored and migrated from the old tech stack PyQt6 to Tauri + React v18. The UI has been completely redesigned and the project restructured to make it easier to add new extensions or expand existing ones. All components of an extension are reusable. Setup Wizard The wizard is now more intuitive and offers the possibility to set preferences on first launch. All configurations are stored locally in a SQLite database and can be changed at any time. Currently, you only need to provide the extracted pack directory and the application performs an autodiscovery for all required files/paths. Individual paths can be specified manually as a fallback in case autodiscovery fails and to give you the option to enter them manually. Dashboard The dashboard provides various statistics, currently focused on players/characters. Data can be filtered and the charts are interactive. The Recharts library was used for this purpose. Item Module The Item Module allows you to switch between TXT and SQL. Here you can edit the items accordingly. Clicking on a row opens the Item Editor, where the item icon can generally be modified (currently not fully available yet). A search function is also available, including a shortcut to focus it. Mob Module This module is currently still a work in progress. At the moment, only the table and the search function are displayed — more coming later. Shop Module This module is used to manage NPC shops. Items can be added/removed, the item count can be adjusted, and the shop grid can be customized. Additionally, the Granny model of the NPC is visually displayed here. Shops can also be completely removed. Everything happens directly via queries. I plan to upload the repository to GitHub in the next few days and release a first version including the modules presented in the preview. What will the release include? - Edit item proto - Edit mob proto + model display - Edit item icons - Fully manage shops - Several filter functions for the tables - Load Granny models What is currently being actively worked on? Currently, only Granny models with a single texture can be loaded correctly. Models that have more than one texture do load, but they look accordingly broken. In addition, animation integration is planned to be introduced.
-
Its a long time gone, but this is probably one of the most used Systems, so I wanna contribute with something: Unused methods which can be removed: def SetVisible(self, is_show): if is_show: self.Show() else: self.Hide() def SetAttachParent(self, parent): wndMgr.SetAttachParent(self.hWnd, parent.hWnd) Reworking height calculation, for avoiding cutoffs of items: uitarget.py class ItemListBoxItem(ui.ListBoxExNew.Item): def __init__(self, width): ui.ListBoxExNew.Item.__init__(self) image = ui.ExpandedImageBox() image.SetParent(self) image.Show() self.image = image nameLine = ui.TextLine() nameLine.SetParent(self) nameLine.SetPosition(32 + 5, 0) nameLine.Show() self.nameLine = nameLine self.SetSize(width, 32 + 5) self.baseTextY = 0 def LoadImage(self, image, name = None): self.image.LoadImage(image) imgWidth = self.image.GetWidth() imgHeight = self.image.GetHeight() calculatedHeight = max(32, imgHeight) + 5 self.SetSize(self.GetWidth(), calculatedHeight) self.image.SetPosition(0, (calculatedHeight - imgHeight) / 2) self.baseTextY = (calculatedHeight - 15) / 2 if name != None: self.SetText(name) self.nameLine.SetPosition(imgWidth + 5, self.baseTextY) def SetText(self, text): self.nameLine.SetText(text) def RefreshHeight(self): ui.ListBoxExNew.Item.RefreshHeight(self) fullHeight = float(self.GetHeight()) if fullHeight == 0: return self.image.SetRenderingRect( 0.0, 0.0 - float(self.removeTop) / fullHeight, 0.0, 0.0 - float(self.removeBottom) / fullHeight ) self.image.SetPosition(0, -self.removeTop) if self.nameLine: imgWidth = self.image.GetWidth() currentTextY = self.baseTextY - self.removeTop self.nameLine.SetPosition(imgWidth + 5, currentTextY) currentVisibleHeight = fullHeight - self.removeTop - self.removeBottom textHeight = 15 if currentTextY < 0 or (currentTextY + textHeight) > currentVisibleHeight: self.nameLine.Hide() else: self.nameLine.Show() def __LoadInformation_Drops(self, race): self.AppendSeperator() if race in MONSTER_INFO_DATA: if len(MONSTER_INFO_DATA[race]["items"]) == 0: self.AppendTextLine(localeInfo.TARGET_INFO_NO_ITEM_TEXT) else: itemListBox = ui.ListBoxExNew(32 + 5, self.MAX_ITEM_COUNT) itemListBox.SetSize(self.GetWidth() - 15 * 2 - ui.ScrollBar.SCROLLBAR_WIDTH, (32 + 5) * self.MAX_ITEM_COUNT) height = 0 for curItem in MONSTER_INFO_DATA[race]["items"]: if curItem.has_key("vnum_list"): height += self.AppendItem(itemListBox, curItem["vnum_list"], curItem["count"]) else: height += self.AppendItem(itemListBox, curItem["vnum"], curItem["count"]) if height < itemListBox.GetHeight(): itemListBox.SetSize(itemListBox.GetWidth(), height) self.AppendWindow(itemListBox, 15) itemListBox.SetBasePos(0) if height > itemListBox.GetHeight(): itemScrollBar = ui.ScrollBar() itemScrollBar.SetParent(self) itemScrollBar.SetPosition(itemListBox.GetRight(), itemListBox.GetTop()) itemScrollBar.SetScrollBarSize(itemListBox.GetHeight()) itemScrollBar.SetMiddleBarSize(float(itemListBox.GetHeight()) / float(height)) itemScrollBar.Show() itemListBox.SetScrollBar(itemScrollBar) else: self.AppendTextLine(localeInfo.TARGET_INFO_NO_ITEM_TEXT) ui.py def __init__(self, stepSize, viewSteps): Window.__init__(self) self.viewItemCount=10 self.basePos=0 self.baseIndex=0 self.maxSteps=0 self.totalItemHeight = 0 self.viewSteps = viewSteps self.stepSize = stepSize self.itemList=[] self.scrollBar=None self.SetWindowName("NONAME_ListBoxEx") def SetBasePos(self, basePos, forceRefresh = TRUE): if forceRefresh == FALSE and self.basePos == basePos: return for oldItem in self.itemList[self.baseIndex:self.baseIndex+self.viewItemCount]: oldItem.ResetCurrentHeight() oldItem.Hide() self.basePos = basePos pixelOffset = basePos baseIndex = 0 accumulatedHeight = 0 while baseIndex < len(self.itemList): itemHeight = self.itemList[baseIndex].GetHeight() if accumulatedHeight + itemHeight > pixelOffset: topRemove = pixelOffset - accumulatedHeight self.itemList[baseIndex].SetRemoveTop(topRemove) break accumulatedHeight += itemHeight baseIndex += 1 self.baseIndex = baseIndex self.viewItemCount = 0 currentRenderY = 0 viewHeightPixels = self.GetHeight() while baseIndex < len(self.itemList): item = self.itemList[baseIndex] itemCurrentHeight = item.GetCurrentHeight() if currentRenderY + itemCurrentHeight > viewHeightPixels: visibleAmount = viewHeightPixels - currentRenderY removeBottom = itemCurrentHeight - visibleAmount item.SetRemoveBottom(removeBottom) itemCurrentHeight = visibleAmount item.SetPosition(0, currentRenderY) item.Show() currentRenderY += itemCurrentHeight self.viewItemCount += 1 baseIndex += 1 if currentRenderY >= viewHeightPixels: break def RemoveAllItems(self): self.itemList=[] self.maxSteps=0 self.totalItemHeight = 0 if self.scrollBar: self.scrollBar.SetPos(0) def RemoveAllItems(self): self.itemList=[] self.maxSteps=0 self.totalItemHeight = 0 if self.scrollBar: self.scrollBar.SetPos(0) def RemoveItem(self, delItem): self.totalItemHeight -= delItem.GetHeight() self.itemList.remove(delItem) if self.stepSize > 0: self.maxSteps = int((self.totalItemHeight + self.stepSize - 1) / self.stepSize) def AppendItem(self, newItem): newItem.SetParent(self) self.itemList.append(newItem) self.totalItemHeight += newItem.GetHeight() if self.stepSize > 0: self.maxSteps = int((self.totalItemHeight + self.stepSize - 1) / self.stepSize) def __GetScrollLen(self): scrollLen = self.totalItemHeight - self.GetHeight() if scrollLen < 0: return 0 return scrollLen
-
I know that is a little bit late for answering this question, but the core issue in here is on how textures are loaded for tree, look in your binary SpeedTreeLib/SpeedTreeWrapper.cpp and make sure depending on the c++ Version used, that this function looks kinda like that: bool CSpeedTreeWrapper::LoadTree(const char* pszSptFile, const BYTE* c_pbBlock, unsigned int uiBlockSize, UINT nSeed, float fSize, float fSizeVariance) { bool bSuccess = false; // directx, so allow for flipping of the texture coordinate #ifdef WRAPPER_FLIP_T_TEXCOORD m_pSpeedTree->SetTextureFlip(true); #endif // load the tree file if (!m_pSpeedTree->LoadTree(c_pbBlock, uiBlockSize)) { if (!m_pSpeedTree->LoadTree(pszSptFile)) { TraceError("SpeedTreeRT Error: %s", CSpeedTreeRT::GetCurrentError()); return false; } } // override the lighting method stored in the spt file #ifdef WRAPPER_USE_DYNAMIC_LIGHTING m_pSpeedTree->SetBranchLightingMethod(CSpeedTreeRT::LIGHT_DYNAMIC); m_pSpeedTree->SetLeafLightingMethod(CSpeedTreeRT::LIGHT_DYNAMIC); m_pSpeedTree->SetFrondLightingMethod(CSpeedTreeRT::LIGHT_DYNAMIC); #else m_pSpeedTree->SetBranchLightingMethod(CSpeedTreeRT::LIGHT_STATIC); m_pSpeedTree->SetLeafLightingMethod(CSpeedTreeRT::LIGHT_STATIC); m_pSpeedTree->SetFrondLightingMethod(CSpeedTreeRT::LIGHT_STATIC); #endif // set the wind method #ifdef WRAPPER_USE_GPU_WIND m_pSpeedTree->SetBranchWindMethod(CSpeedTreeRT::WIND_GPU); m_pSpeedTree->SetLeafWindMethod(CSpeedTreeRT::WIND_GPU); m_pSpeedTree->SetFrondWindMethod(CSpeedTreeRT::WIND_GPU); #endif #ifdef WRAPPER_USE_CPU_WIND m_pSpeedTree->SetBranchWindMethod(CSpeedTreeRT::WIND_CPU); m_pSpeedTree->SetLeafWindMethod(CSpeedTreeRT::WIND_CPU); m_pSpeedTree->SetFrondWindMethod(CSpeedTreeRT::WIND_CPU); #endif #ifdef WRAPPER_USE_NO_WIND m_pSpeedTree->SetBranchWindMethod(CSpeedTreeRT::WIND_NONE); m_pSpeedTree->SetLeafWindMethod(CSpeedTreeRT::WIND_NONE); m_pSpeedTree->SetFrondWindMethod(CSpeedTreeRT::WIND_NONE); #endif m_pSpeedTree->SetNumLeafRockingGroups(1); // override the size, if necessary if (fSize >= 0.0f && fSizeVariance >= 0.0f) m_pSpeedTree->SetTreeSize(fSize, fSizeVariance); // generate tree geometry if (m_pSpeedTree->Compute(NULL, nSeed)) { // get the dimensions m_pSpeedTree->GetBoundingBox(m_afBoundingBox); // make the leaves rock in the wind m_pSpeedTree->SetLeafRockingState(true); // billboard setup #ifdef WRAPPER_NO_BILLBOARD_MODE CSpeedTreeRT::SetDropToBillboard(false); #else CSpeedTreeRT::SetDropToBillboard(true); #endif // query & set materials m_cBranchMaterial.Set(m_pSpeedTree->GetBranchMaterial()); m_cFrondMaterial.Set(m_pSpeedTree->GetFrondMaterial()); m_cLeafMaterial.Set(m_pSpeedTree->GetLeafMaterial()); // adjust lod distances float fHeight = m_afBoundingBox[5] - m_afBoundingBox[2]; m_pSpeedTree->SetLodLimits(fHeight * c_fNearLodFactor, fHeight * c_fFarLodFactor); // query textures m_pTextureInfo = new CSpeedTreeRT::STextures; m_pSpeedTree->GetTextures(*m_pTextureInfo); // load branch textures auto vs1 = std::string(pszSptFile); auto vs2 = std::string(m_pTextureInfo->m_pBranchTextureFilename); LoadTexture((CFileNameHelper::GetPath(vs1) + CFileNameHelper::NoExtension(vs2) + ".dds").c_str(), m_BranchImageInstance); #ifdef WRAPPER_RENDER_SELF_SHADOWS if (m_pTextureInfo->m_pSelfShadowFilename != NULL) { auto vss = std::string(m_pTextureInfo->m_pSelfShadowFilename); LoadTexture((CFileNameHelper::GetPath(vs1) + CFileNameHelper::NoExtension(vss) + ".dds").c_str(), m_ShadowImageInstance); } #endif if (m_pTextureInfo->m_pCompositeFilename) { auto vss = std::string(m_pTextureInfo->m_pCompositeFilename); LoadTexture((CFileNameHelper::GetPath(vs1) + CFileNameHelper::NoExtension(vss) + ".dds").c_str(), m_CompositeImageInstance); } // setup the index and vertex buffers SetupBuffers(); // everything appeared to go well bSuccess = true; } else // tree failed to compute fprintf(stderr, "\nFatal Error, cannot compute tree [%s]\n\n", CSpeedTreeRT::GetCurrentError()); return bSuccess; }
-
Dex started following In-game VIP items (exp, drop, autoloot gold etc.) and [Preview]M2Manager
-
Ahoy! Since I’ve been asked several times about sales, features, and pricing, I wanted to give you all an update. The first release is planned for the end of July / beginning of August. The Community version will be released first and will serve as a beta release. About a week later, sales will start—provided everything is working as expected. The tool will be available in two versions: a Community and a Professional version. Both versions will receive patches and updates, and later on, additional extensions will be available for purchase. Feel free to leave feedback about what features you’d like to see in the tool. Community Dashboard Overview of items Overview of monsters Overview of characters Overview of accounts Filter data by time period Items Add new items Edit items Filter items by type/subtype Full-text search / exact search Alphanumeric sorting Item preview Color item icons Expandable types/subtypes Automatic saving Monster Add new monsters Edit monsters Filter monsters by type/rank Full-text search / exact search Alphanumeric sorting Automatic saving Shops Create new shops Edit shop items General shop editing Freely customizable shop grid Automatic saving General Translated into 3 languages (German, English, Romanian) Light and dark appearance Windows can be freely positioned Automatic path detection for necessary files in the unpacked client Professional Dashboard Overview of items Overview of monsters Overview of characters Overview of accounts Filter data by time period Items Add new items Edit items Filter items by type/subtype Full-text search / exact search Alphanumeric sorting Item preview Color item icons Expandable types/subtypes Automatic saving Automatically set entries depending on type (MSM, Icon, etc.) Automatically pack item_proto Automatic transfer of item_proto.txt/item_names.txt to the server Version management Monster Add new monsters Edit monsters Filter monsters by type/rank Full-text search / exact search Alphanumeric sorting Automatic saving Automatically pack mob_proto Automatic transfer of mob_proto.txt/mob_names.txt to the server Version Management Shops Create new shops Edit shop items General shop editing Freely customizable shop grid Automatic saving Drops Preview items with quantity and chance Edit drops Add new drops Set exact drop chances Automatic saving Version management General Translated into 3 languages (German, English, Romanian) Light and dark appearance Windows can be freely positioned Automatic path detection for necessary files in the unpacked client Automatic unpacking of the client from eix/epk
-
Update 16.06.2025: - Added fully translation - Added setup wizzard for initial start - Added ssh configuration - Added database configuration
-
Added some statistics to Dashboard:
-
M2Manager – Simple, Efficient Server & Client Data Management M2Manager is a simple tool designed to simplify working with server and client data. Currently, it is possible to add and edit Items and Monsters. All changes are saved immediately, with no need for manual post-processing. To use the tool, you must specify the unpacked client and connection to the server. M2Manager automatically reads all relevant data. UPDATE 20.02.2026 Version 1.0 Current Features Add and edit Items Filter Items Search Items Recolor Icons Add and edit Monsters Search Monsters Filter Monsters Direct saving of all changes Shop Manager Create Shops Delete Shops Add/Remove Items in Shops Edit Shops Customizable Grid Size (default 5x9) Realtime updates and responsive design Planned Features (Roadmap) Automatic packing of item_proto and mob_proto Monster model preview Item model preview Display and edit server drops The tool is under active development. The goal is to make common tasks easily accessible in one place to save time. Preview Stay tuned for more updates!
- 7 replies
-
- 11
-
-
-
-
-
-
In-game VIP items (exp, drop, autoloot gold etc.)
Dex replied to jking's topic in Features & Metin2 Systems
What is the diffrence between your system and the core one? -
A further nice completition will be an export to gtlf for web rendering.
-
Next: Dynamic weather through weather api over geolocation. Thx for rls mate!
-
Did you also managed to fix the locale.lua part for the npc chats? If I start the server and login with an german client after that starting a second client with romanian for example, both clients get the german language for the npc chats.
-
bump
-
bump
-
Hello fellas, I have some issues with the encoding of the hyperlinks when using special characters like umlate or diacritics, but can't figure out why is that happen. The database is storing the values right as far and the problem seems to be only on the SHOUT_CHAT. This is an example of data which is stored in log > shout_log: Dex : |cfff1e6c0|Hitem:115d8:0:6568feca:4:0|h[Schlachtenlöwen-Siegel]|h|r So how you can see everything seems to be fine, but the client is displaying a question mark instead of the right character as you can see here: Is it possible somehow that the server isn't returning it correctly so the client is rendering wrong? Kind regards, Dex
