Jump to content

z3r002557

Member
  • Posts

    13
  • Joined

  • Last visited

  • Feedback

    0%

About z3r002557

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

z3r002557's Achievements

Enthusiast

Enthusiast (6/16)

  • Collaborator Rare
  • Conversation Starter
  • One Year In
  • First Post
  • Dedicated

Recent Badges

4

Reputation

  1. I'm logging into the game with the wing/sash equipped. I set up a hotkey for the skill "Arahan Warrior's Fury". I press the hotkey several times and click on the ground to make the character walk... That's when the bug happened: the visual effect of the spell was triggered, but the character's animation was canceled and he went running full of effects. This was with the sash equipped. Then I minimized the game, waited 5 minutes, and went back to try again. After maximizing the window, I did the same procedure: I clicked the skill hotkey several times and clicked on the map ground to walk at the same time. The result? The player got stuck in the same spot and executed the skill animation correctly. Now I unequipped the sash and tried to reproduce the bug again. With the game still open, I tried to trigger the bug by pressing the skill hotkey several times and clicking to walk. (Detail: when the bug happens, you don't need to press the hotkey several times. Just pressing it once already starts the animation, but it seems to choke on the first frame, repeats as if it choked twice, and cancels the animation on its own.) Still without the sash, I kept trying to trigger the bug: several clicks on the hotkey and on the ground, but nothing happens. I used the /go c1 command to return to town and tried again, because after a loading screen (teleport, map change, etc.) it's usually prone to triggering the bug. But nothing. (Detail: still without the sash equipped.) I tried several times to trigger the bug without the sash equipped, but it simply doesn't happen. The player locks in place, executes the animation normally, and only releases movement after the animation finishes. Now I exited the game and logged back in without the sash to try to trigger the bug right after login, just like I did with the sash equipped before. I logged in, tried, but... without the sash equipped, the bug doesn't happen. Conclusion: I strongly believe the bug is being caused by having the wing/sash equipped. The bug only happens when it's equipped, and even then, it's not every time. Another detail: when the bug does occur, it's not necessary to keep clicking on the map to walk — just one click on the skill hotkey already cancels the animation on its own. It's also worth noting that the issue doesn't happen with all skills. It seems to mainly affect buff skills that force the player to lock in place to play the animation. The hotkey used is irrelevant (it can be any configured key), so mentioning the specific key is not relevant.
  2. Someone discovered the solution to this behavior?
  3. Someone discovered the solution to this behavior?
  4. Can anyone help me fix this visual problem with the gold in the inventory?
  5. #include <memory> // Para std::unique_ptr int db_query(lua_State* L) { if (!lua_isstring(L, 1)) { lua_pushnumber(L, 0); lua_newtable(L); return 2; } const char* szQuery = lua_tostring(L, 1); // Executa a query usando std::unique_ptr para evitar Memory Leak (substitui o auto_ptr antigo) std::unique_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery(szQuery)); if (!pMsg || !pMsg->Get()) { lua_pushnumber(L, 0); lua_newtable(L); return 2; } // Retorno 1: Número de linhas afetadas ou encontradas lua_pushnumber(L, (double)pMsg->Get()->uiAffectedRows); // Retorno 2: Tabela de resultados lua_newtable(L); MYSQL_RES* result = pMsg->Get()->pSQLResult; if (result && pMsg->Get()->uiAffectedRows > 0) { MYSQL_ROW row; MYSQL_FIELD* fields = mysql_fetch_fields(result); int num_fields = mysql_num_fields(result); int m = 1; while ((row = mysql_fetch_row(result))) { lua_pushnumber(L, m); lua_newtable(L); // Tabela da linha for (int i = 0; i < num_fields; ++i) { // Usa o nome da coluna como CHAVE da tabela (Ex: row.name) lua_pushstring(L, fields[i].name); if (row[i] == nullptr) { lua_pushnil(L); } else if (IS_NUM(fields[i].type)) { // Auto-detecta número e envia como número para o Lua lua_pushnumber(L, atof(row[i])); } else { // Envia como string lua_pushstring(L, row[i]); } lua_rawset(L, -3); } lua_rawset(L, -3); m++; } } return 2; // Retorna a contagem e a tabela } int db_escape(lua_State* L) { if (!lua_isstring(L, 1)) { lua_pushstring(L, ""); return 1; } const char* szSource = lua_tostring(L, 1); // Buffer dinâmico baseado no tamanho da string de entrada (mais seguro) std::vector<char> szDest(strlen(szSource) * 2 + 1); DBManager::instance().EscapeString(szDest.data(), szDest.size(), szSource, strlen(szSource)); lua_pushstring(L, szDest.data()); return 1; } void RegisterDBFunctionTable() { luaL_reg db_functions[] = { { "query", db_query }, { "escape", db_escape }, { NULL, NULL } }; CQuestManager::instance().AddLuaFunctionTable("db", db_functions); } Fix Version Go to your quests folder (e.g., share/locale/english/quest), open the quest_functions file, and add the following line: db.query and db.escape
  6. Hey everyone, I decided to share a simple, native C++ implementation for database queries. I've noticed that some bases out there still rely on the old mysql_query Lua function (the one that uses os.execute to open the terminal, run the query, and generate a temporary text file in /tmp). The main issue with that legacy method is that it halts the main game thread. During peak moments, such as guild wars, this causes the notorious "step lag" / "core lag". The code below creates a native db.query function utilizing the direct connection from the DBManager, making the execution instantaneous and completely lag-free. ## Source Implementation (Game) Step 1: questlua.cpp Open the file game/src/questlua.cpp and search for the ScriptToString function. Right after its closing bracket (the last }), skip a line and paste the new code. Example of how it should look: lua_settop(L,x); return retstr; } // <-- End of ScriptToString // --- START NATIVE DB.QUERY --- int db_query(lua_State* L) { if (!lua_isstring(L, 1)) return 0; const char* szQuery = lua_tostring(L, 1); if (!szQuery || strlen(szQuery) == 0) return 0; SQLMsg* pMsg = DBManager::instance().DirectQuery(szQuery); if (pMsg) { delete pMsg; } return 0; } void RegisterDBFunctionTable() { luaL_reg db_functions[] = { { "query", db_query }, { NULL, NULL } }; CQuestManager::instance().AddLuaFunctionTable("db", db_functions); } // --- END NATIVE DB.QUERY --- Step 2: Still in questlua.cpp In the exact same file, search for RegisterHorseFunctionTable();. Skip a line below it and register our new function. Example of how it should look: RegisterHorseFunctionTable(); RegisterDBFunctionTable(); Step 3: questlua.h Open game/src/questlua.h, look for the registry list (where the extern void Register... declarations are located), and add the following line: extern void RegisterDBFunctionTable(); ## Final Steps Now simply compile your source and replace the game executable in your server. Go to your quests folder (e.g., share/locale/english/quest), open the quest_functions file, and add the following line: db.query ## Quest Usage Example You can use string.format to build your queries in a clean and safe way. Here is an example of a kill counter updating the kill column inside the player table: quest ranking_kills begin state start begin when kill with npc.is_pc() begin local pid = pc.get_player_id() -- Direct, fast query with no core lag local query = string.format("UPDATE player.player SET kill = kill + 1 WHERE id = %d", pid) db.query(query) end end end ## Caveats and Limitations Before applying this to all your systems, please keep two things in mind: Execution Only (Does not read SELECTs): This function was built specifically for write performance (UPDATE, INSERT, DELETE, REPLACE). Due to the delete pMsg; command in the C++ code, it does not return SELECT rows into Lua tables. If you try to fetch data, it will return 0 or nil. Beware of SQL Injection: Never place an input() command directly inside db.query without strictly sanitizing it first. If you ask a player to type a string and feed it directly into the query, a malicious user could run commands to drop your tables. Always use safe, native source functions like pc.get_player_id(), pc.get_name(), etc., or heavily restrict the allowed input characters.
  7. [Tutorial] Acce/Sash System: Window Centering & ESC/Z-Order Fix Description: Many Acce (Sash) systems have two common UI issues: Initial Position: The window opens at the top-left corner (0,0) the first time it's opened. Focus/Z-Order: When the window is open along with the inventory, pressing the ESC key closes the inventory first instead of the Acce window, even if the Acce window is visually on top. This guide will show you how to fix both in your uiacce.py. 1. Fixing the Initial Window Position (Auto-Centering) We want the window to start at the center of the screen upon the first execution, but still allow the game to remember if the player drags it to a new position. File: root/uiacce.py Search for: def LoadWindow(self): inside both class CombineWindow and class AbsorbWindow. Action: Go to the end of the LoadWindow function and add self.SetCenterPosition() before the end of the block. Example for CombineWindow: Python def LoadWindow(self): # ... (existing code) self.btnAccept.SetEvent(ui.__mem_func__(self.OnAccept)) self.tooltipItem = None self.SetCenterPosition() # Add this line here Example for AbsorbWindow: Python def LoadWindow(self): # ... (existing code) self.btnAccept.SetEvent(ui.__mem_func__(self.OnAccept)) self.tooltipItem = None self.SetCenterPosition() # Add this line here 2. Fixing the Z-Order and ESC Key Hierarchy This ensures that the Acce window becomes the "Active" window when opened, so the first ESC press closes it instead of background windows (like the inventory). File: root/uiacce.py Search for: def Open(self): inside both class CombineWindow and class AbsorbWindow. Action: Add self.SetTop() at the very end of the Open function. Example: Python def Open(self): # ... (existing code) self.Show() self.SetTop() # Add this to bring the window to the front (Repeat this for both classes: CombineWindow and AbsorbWindow). Why this works: SetCenterPosition in LoadWindow: By placing it in LoadWindow, it only triggers once when the UI is first created. If the player moves the window, the game's internal movable style will preserve the new coordinates for the rest of the session. SetTop in Open: This tells the game engine that this window now has the focus. The UI stack will recognize it as the top-most layer, redirecting the ESC key input to it immediately. Note: Always make sure your indentation (tabs) is correct, as Python is sensitive to it!
  8. Hello Metin2 Dev community, I hope you are all doing well. I am seeking guidance from anyone with experience in upgrading Metin2 servers from MySQL 5.x to MySQL 8.x. In particular, I would like to better understand how to handle the mysql_native_password issue to ensure that the server core continues to function correctly. If anyone has knowledge of this process, I would be extremely grateful if you could share a tutorial or a detailed step-by-step guide, so that other community members can also benefit from this experience. Any practical examples, configurations, or commands that can be shared would be very helpful. Thank you in advance for your time and generosity. Best regards, [Z3R0]
      • 2
      • Good
×
×
  • 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.