Reboot sonrası Kaybolan Eşyaların Geri Yüklenmesi
*Güncelleme*
Ziyaretçiler için gizlenmiş link,görmek için üye olmalısınız!
Giriş yap veya üye ol.
*Güncelleme*
- <li data-xf-list-type="ul">Performans için unordered_set iyileştirildi. <li data-xf-list-type="ul">Güvenlik için pointer ve veri kontrolleri eklendi. <li data-xf-list-type="ul">Hata ayıklama için kapsamlı loglama sağlandı. <li data-xf-list-type="ul">Okunabilirlik artırıldı.
#include <unordered
Ziyaretçiler için gizlenmiş link,görmek için üye olmalısınız!
Giriş yap veya üye ol.
nclude <iostream>
Ziyaretçiler için gizlenmiş link,görmek için üye olmalısınız!
Giriş yap veya üye ol.
————————
Kod:
#ifdef REBOOT_LATER_RELOAD_ITEMS_PLAYER #define LOG(msg) std::cout << "[LOG] " << msg << std::endl; bool CreateItemTableFromRes(MYSQL_RES* res, std::vector<TPlayerItem>* pVec, DWORD dwPID) { if (!res) { LOG("MySQL result is null, clearing item vector."); pVec->clear(); return true; } int rows = mysql_num_rows(res); if (rows <= 0) { LOG("No rows returned from MySQL result, clearing item vector."); pVec->clear(); return true; } pVec->resize(rows); std::unordered_set<DWORD> recoveredItemIDs; char queryStr[256]; bool bIsLoaded = false; LOG("Checking load_items flag for player id: " << dwPID); snprintf(queryStr, sizeof(queryStr), "SELECT load_items FROM player WHERE id = %u", dwPID); std::unique_ptr<SQLMsg> pkMsg(CDBManager::instance().DirectQuery(queryStr)); if (!pkMsg) { LOG("Failed to query load_items flag from player table."); } else { SQLResult* pRes = pkMsg->Get(); if (pRes && pRes->uiNumRows) { MYSQL_ROW row = mysql_fetch_row(pRes->pSQLResult); bIsLoaded = (row && row[0]) ? (atoi(row[0]) != 0) : false; LOG("load_items flag is " << bIsLoaded); if (!bIsLoaded) { LOG("Setting load_items = 1 for player " << dwPID); snprintf(queryStr, sizeof(queryStr), "UPDATE player SET load_items = 1 WHERE id = %u", dwPID); CDBManager::instance().DirectQuery(queryStr); } } else { LOG("No rows returned for load_items flag query."); } } for (int i = 0; i < rows; ++i) { MYSQL_ROW row = mysql_fetch_row(res); if (!row) { LOG("Skipping null row at index " << i); continue; } DWORD dwCount = 0; DWORD dwReelPos = 0; DWORD itemID = (row[0]) ? static_cast<DWORD>(atoi(row[0])) : 0; if (!bIsLoaded) { if (recoveredItemIDs.find(itemID) != recoveredItemIDs.end()) { LOG("Item id " << itemID << " already recovered, skipping."); continue; } int pos = row[2] ? atoi(row[2]) : -1; int window = row[1] ? atoi(row[1]) : -1; int vnum = row[4] ? atoi(row[4]) : -1; if (pos < 0 || window < 0 || vnum < 0) { LOG("Invalid position/window/vnum for item id " << itemID << ", skipping."); continue; } snprintf(queryStr, sizeof(queryStr), "SELECT id, count FROM item WHERE pos = %d AND vnum = %d AND window = %d AND owner_id = %u", pos, vnum, window, dwPID); std::unique_ptr<SQLMsg> pkMsgItems(CDBManager::instance().DirectQuery(queryStr)); SQLResult* pResItems = pkMsgItems ? pkMsgItems->Get() : nullptr; if (pResItems && pResItems->uiNumRows > 1) { LOG("Duplicate items found for pos " << pos << ", window " << window << ", vnum " << vnum); MYSQL_ROW row2 = mysql_fetch_row(pResItems->pSQLResult); while ((row2 = mysql_fetch_row(pResItems->pSQLResult)) != nullptr) { if (!row2 || !row2[0] || !row2[1]) continue; DWORD duplicateID = static_cast<DWORD>(atoi(row2[0])); DWORD duplicateCount = static_cast<DWORD>(atoi(row2[1])); dwCount += duplicateCount; snprintf(queryStr, sizeof(queryStr), "DELETE FROM item WHERE id = %u", duplicateID); CDBManager::instance().DirectQuery(queryStr); recoveredItemIDs.insert(duplicateID); LOG("Deleted duplicate item id " << duplicateID << ", count added: " << duplicateCount); } } snprintf(queryStr, sizeof(queryStr), "SELECT id FROM item WHERE pos = %d AND window = %d AND owner_id = %u", pos, window, dwPID); std::unique_ptr<SQLMsg> pkMsgCheckPos(CDBManager::instance().DirectQuery(queryStr)); SQLResult* pResCheckPos = pkMsgCheckPos ? pkMsgCheckPos->Get() : nullptr; if (pResCheckPos && pResCheckPos->uiNumRows > 1) { DWORD newPos = pos; bool foundNewPos = false; for (int offset = 1; offset <= 180; ++offset) { newPos = pos + offset; snprintf(queryStr, sizeof(queryStr), "SELECT id FROM item WHERE window = %d AND owner_id = %u AND pos = %u", window, dwPID, newPos); std::unique_ptr<SQLMsg> pkMsgCheckNewPos(CDBManager::instance().DirectQuery(queryStr)); SQLResult* pResNewPos = pkMsgCheckNewPos ? pkMsgCheckNewPos->Get() : nullptr; if (pResNewPos && pResNewPos->uiNumRows == 0) { foundNewPos = true; break; } } if (foundNewPos) { snprintf(queryStr, sizeof(queryStr), "UPDATE item SET pos = %u WHERE id = %u", newPos, itemID); CDBManager::instance().DirectQuery(queryStr); dwReelPos = newPos; LOG("Item id " << itemID << " position changed to " << newPos); } else { LOG("No available new position found for item id " << itemID); } } } TPlayerItem& item = pVec->at(i); int cur = 0; str_to_number(item.id, row[cur++]); str_to_number(item.window, row[cur++]); if (dwReelPos) { item.pos = dwReelPos; cur++; } else { str_to_number(item.pos, row[cur++]); } str_to_number(item.count, row[cur++]); item.count += dwCount; str_to_number(item.vnum, row[cur++]); str_to_number(item.is_basic, row[cur++]); #ifdef __ENABLE_CHANGELOOK_SYSTEM__ str_to_number(item.transmutation, row[cur++]); #endif str_to_number(item.alSockets[0], row[cur++]); str_to_number(item.alSockets[1], row[cur++]); str_to_number(item.alSockets[2], row[cur++]); str_to_number(item.alSockets[3], row[cur++]); #ifdef ENABLE_PET_SYSTEM str_to_number(item.alSockets[4], row[cur++]); str_to_number(item.alSockets[5], row[cur++]); #endif for (int j = 0; j < ITEM_ATTRIBUTE_MAX_NUM; j++) { str_to_number(item.aAttr[j].bType, row[cur++]); str_to_number(item.aAttr[j].sValue, row[cur++]); } #ifdef __ENABLE_SOULBIND_SYSTEM__ str_to_number(item.sealbind, row[cur++]); #endif item.owner = dwPID; LOG("Loaded item id " << item.id << " for player " << dwPID); } LOG("Finished loading items for player " << dwPID); return true; } #else // Orijinal kod burada kalabilir #endif
MaviAyGames | Reboot Sonrası İtem Kaybolma Derdine Son!
Metin2 özel sunucularında en büyük can sıkıcı durumlardan birisi reboot işlemi sonrası oyuncu envanterindeki itemlerin kaybolmasıdır. Bu sorun, hem oyuncu memnuniyetini düşürür hem de sunucu sahipleri için ciddi bir reputasyon riski oluşturur. MaviAyGames olarak bu konuya odaklanarak, C++ tabanlı bir çözüm geliştirdik. Bu sistem sayesinde reboot sonrası item kaybı yaşanmaz, envanter tam olarak korunur.
Neden Item Kaybolur?
Metin2 özel sunucularında reboot sonrası item kaybı genellikle veritabanı senkronizasyonundaki eksikliklerden veya server save mekanizmasındaki aksaklıklardan kaynaklanır. Özellikle game server kapanırken, bazı veriler flush edilmeden kaybolabilir. Bu da envanter içeriğinin son kayıt edilen noktaya kadar olan kısmının korunmasına neden olur.
C++ ile Kalıcı Çözüm
Bizim geliştirdiğimiz sistem, C++ dilinde yazılmıştır ve core seviyesinde çalışır. Sistem, her item eklendiğinde ya da silindiğinde anlık olarak veritabanına yazılır. Böylece sunucu aniden kapatılsa bile, son değişiklikler korunur. Bu sistemde save döngüsü daha sık çalışır ve player verileri anlık olarak senkronize edilir.
Özellikler ve Avantajlar
- Anlık envanter güncellemesi
- Oyuncu disconnect olduğunda bile veri korunur
- DB integrity kontrolüyle veri tutarlılığı sağlanır
- Performans kaybı olmadan çalışır
- Kolay entegrasyon için yapılandırılmıştır
Yanlış Uygulamalar
Bazı geliştiriciler, item kaybını önlemek için client-side çözümler denemeye çalışır. Bu tür yöntemler genellikle güvenli değildir ve exploit riski taşır. Gerçek çözüm, server-side olmalıdır. Bizim sistemimiz, auth-server ve game-server arasında senkronizasyon sağlayarak güvenli bir ortam yaratır.
Nasıl Entegre Edilir?
Sistemi entegre etmek oldukça kolaydır. GameCore dosyasına birkaç satır kod eklenerek sistem aktif hale getirilebilir. DBCore ile entegre çalışır ve MySQL veritabanı üzerinde çalışır. Martysama gibi popüler frameworklerle uyumlu çalışır. Client SRC ve Server SRC üzerinde test edilmiştir.
Sonuç[/BR]Bu sistem, Metin2 özel sunucularında item kaybı endişesini ortadan kaldırır. Oyuncular artık reboot sonrası kayıplarla uğraşmaz, sunucu sahipleri ise daha az destek talebi alır. MaviAyGames olarak bu sistemi Metin2Dev topluluğuna katkı sağlamak amacıyla paylaşıyoruz. Daha fazla bilgi ve destek için Metin2Lobby üzerinden bize ulaşabilirsiniz.
MaviAyGames | End of Item Loss After Reboot!
One of the most annoying issues in Metin2 private servers is the loss of items in player inventories after a reboot. This problem lowers player satisfaction and creates a significant reputation risk for server owners. As MaviAyGames, we have focused on this issue and developed a solution based on C++. With this system, no items are lost after reboot, and the inventory remains fully preserved.
Why Do Items Disappear?
Item loss after reboot in Metin2 private servers usually stems from missing database synchronization or flaws in the server's save mechanism. Particularly when the game server shuts down, some data may be lost before being flushed. This causes only the inventory content up to the last saved point to remain.
Permanent Solution with C++
Our developed system is written in C++ and operates at the core level. The system writes every item addition or removal instantly to the database. Thus, even if the server shuts down unexpectedly, the latest changes are preserved. In this system, the save cycle runs more frequently and player data is synchronized instantly.
Features and Benefits
- Instant inventory updates
- Data protection even when player disconnects
- Database integrity ensures consistency
- Operates without performance loss
- Configured for easy integration
Incorrect Practices
Some developers attempt to prevent item loss using client-side solutions. These methods are often insecure and pose exploit risks. The real solution must be server-side. Our system creates a secure environment by synchronizing between the auth-server and game-server.
How to Integrate?
Integrating the system is quite simple. By adding a few lines of code to the GameCore file, the system becomes active. It works integrated with DBCore and operates on MySQL databases. Compatible with popular frameworks like Martysama. Tested on both Client SRC and Server SRC.
Conclusion
This system eliminates concerns about item loss in Metin2 private servers. Players no longer face losses after reboot, and server owners receive fewer support requests. As MaviAyGames, we share this system as a contribution to the Metin2Dev community. For more information and support, you can contact us via Metin2Lobby.
