Reklam
teşekkürler? Hyper Payment Bridge - Knight Online İçin Oyun İçi Ödeme Sistemi
Knight Online serverinize modern ve güvenli bir ödeme sistemi entegre etmek için bir çok Metin2 ve bir kaç knight online serverı tarafından kullanılan hyper ödeme köprüsünün ürün bilgisi, ödeme siparişi ve ödeme bildirimlerini işleme işlerini yapacak node.js projesini paylaşıyorum.
? Nedir?
HPB, Knight Online gibi oyunlarda oyuncuların güvenli bir şekilde oyun içi satın alımlar yapabilmesini sağlayan bir köprü (bridge) uygulamasıdır. HyperPay API'si ile entegre çalışarak,
oyuncularınızın kredi kartı/banka kartı ile Cash, Premium gibi oyun içi değerleri satın alabilmesini sağlar.
Özellikler
-Çift Veritabanı Desteği: MySQL ve MSSQL'i destekler (KO için ideal)
-HyperPay Entegrasyonu: Türkiye'nin en yaygın ödeme altyapılarından biri
-Otomatik Callback: Ödeme sonrası otomatik işlem kuyruğu
? Nasıl Çalışır?
1. Oyuncu oyun içi açılan web arayüzünden bir paket seçer oyun node.js sunucusuna oyuncunun bilgileriyle ödeme talebi gönderir (örn: 1000 Cash)
2. Sistem HyperPay'e ödeme talebi gönderir
3. Oyuncu güvenli ödeme sayfasında kartı ile ödeme yapar
4. Ödeme onaylandığında Hyper tarafından node.js sunucusuna bildirim gönderilir ve ödeme otomatik olarak işlem kuyruğuna düşer
5. Kuyruğu işleyen sistemleriniz (daemon/service) oyuncuya ödülü verir
Minimum Gereksinimler:
- Node.js 16+
- MySQL 5.7+ veya MSSQL Server 2016+
- HyperPay API Key
Kurulum talimatları githubda mevcut.
?️ Veritabanı Yapısı
Projeyle birlikte 3 basit tablo gerekiyor:
- pb_products: Satışa sunulan paketler (örn: 1000 Cash - 50 TL)
- pb_payments: Ödeme kayıtları
- pb_process_queue: İşlenmeyi bekleyen ödemeler
Ödeme tamamlandığında pb_process_queue tablosuna otomatik kayıt düşer. Siz sadece bu kuyruğu kontrol edip Cash/Premium dağıtımını yaparsınız.
pb_process_queue tablosuna oyuncu bilgisiyle ödenen miktar is_processed değeri 0 olarak ekleniyor. Oyun sunucusu tarafında bu tabloda 0 olan işlemleri alıp oyuncuya eşyaları teslim edip is_processed değerini 1 e çekmeniz gerekiyor.
? Avantajları
1. Hazır Çözüm: Sıfırdan ödeme sistemi geliştirmeye gerek yok, sanal pos almaya gerek yok
2. Esnek Yapı: Hem MySQL hem MSSQL destekler
4. Ölçeklenebilir: Node.js sayesinde yüksek trafiğe hazır
5. Kolay Entegrasyon: Basit REST API ile her platforma entegre olur
GitHub:Ziyaretçiler için gizlenmiş link,görmek için Giriş yap veya üye ol.
Lisans: MIT (Ticari kullanım dahil serbest)
? Notlar
- HyperPay API key almak için bursagbZiyaretçiler için gizlenmiş link,görmek için Giriş yap veya üye ol.veya ödeme köprüsü veren bir hyper altyapısı ile iletişime geçmeniz gerekiyor
- Kurulum veya kullanım konusunda sorularınız varsa GitHub Issues'dan ulaşabilirsiniz
Ek Bilgi:
Topluluğa faydalı olması için açık kaynak olarak paylaşıyorum. Sorularınız için bu konuya yazabilirsiniz.
Sexyko örnek ödeme entegrasyonu
Serverdan ürün listesini gönderebilirsiniz
Sexykoda kullanılan web arayüzü github projesinde game_frontend klasöründe yer almaktadır.
Kod:const uint16_t count = pkt.read<uint16_t>(); json& webItems = Engine->m_WebItemData["items"]; webItems.clear(); // döngü auto productName = std::string(""); if (it.dc > it.price) productName = std::format("{} TL + {} TL Super Bonus", it.price, it.dc - it.price); else productName = std::format("{} TL", it.price); webItems.push_back({ {"ProductID", it.itemID}, {"ProductName", productName}, {"Cost", it.price}, {"NPoints", it.dc}, {"ProductImage", std::format("assets/images/{}.webp", it.price)} });
Ödeme için arayüzü açma
C++:auto localPlayer = StoneSoft::GetLocalPlayer(); if (!localPlayer) return false; Engine->m_WebItemData["account_id"] = localPlayer->GetAccountName(); char buffer[MAX_PATH]; GetModuleFileNameA(NULL, buffer, MAX_PATH); std::string exePath = std::string(buffer); std::string basePath = exePath.substr(0, exePath.find_last_of("\\/")); try { std::ofstream file(std::format("{}\\StoneSoft\\Shopping\\data.js", basePath)); if (file.is_open()) { file << "window.data = " << Engine->m_WebItemData.dump(2) << ";"; file.close(); } } catch (const std::exception& e) { std::cerr << "Error saving data: " << e.what() << std::endl; } OpenWebWrapper openWeb; std::string urlPath = basePath; std::replace(urlPath.begin(), urlPath.end(), '\\', '/'); openWeb.OpenPage(std::format("file:///{}/StoneSoft/Shopping/index.html", urlPath));
Client içerisinde web sayfası açma kodları
C++:#pragma once const DWORD KO_SHOPPINGMALL_WEBPAGE = 0x00D92EE0; // 2583 const DWORD KO_SHOPPINGMALL_WEBPAGE_GO = 0x00D930FC; // 2583 // const DWORD KO_SHOPPINGMALL_WEBPAGE = 0x00D5B700; // 2517 // const DWORD KO_SHOPPINGMALL_WEBPAGE_GO = 0x00D5B8F8; // 2517 extern std::string g_url; static void* g_originalReturn = nullptr; static void __declspec(naked) URLPushHook() { __asm { mov eax, offset g_url jmp[g_originalReturn] } } class OpenWebWrapper { private: PBYTE originalFunc = reinterpret_cast<PBYTE>(KO_SHOPPINGMALL_WEBPAGE_GO); PBYTE hookFunc = reinterpret_cast<PBYTE>(URLPushHook); public: static void OpenPage(const std::string& url); OpenWebWrapper() { g_originalReturn = reinterpret_cast<void*>(DetourFunction(originalFunc, hookFunc)); } ~OpenWebWrapper() { DetourRemove(reinterpret_cast<BYTE*>(g_originalReturn), reinterpret_cast<BYTE*>(hookFunc)); g_originalReturn = nullptr; } };
C++:#include "../stdafx.h" #include "OpenWebWrapper.h" std::string g_url; // pShoppingMall->dwTable = co_shoppingmall.uif arayüzünün memory adresidir. void OpenWebWrapper::OpenPage(const std::string& url) { if (!pShoppingMall || pShoppingMall->dwTable == 0) return; g_url = url; using tOpenWeb = void(__thiscall*)(DWORD, bool); reinterpret_cast<tOpenWeb>(KO_SHOPPINGMALL_WEBPAGE)(pShoppingMall->dwTable, 1); }
Fonksiyon adresi farklı exelerde bulmak için 2517 örneği gösterilmiştir
Ekli dosyayı görüntüle 10962
Ekli dosyayı görüntüle 10963Ekli dosyayı görüntüle 10964
teşekkürler!