mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-05 03:43:40 +00:00
345 lines
10 KiB
C++
345 lines
10 KiB
C++
#include "liteloader/LiteLoader.h"
|
|
#include "llapi/EventAPI.h"
|
|
#include "llapi/Global.h"
|
|
#include "llapi/ScheduleAPI.h"
|
|
#include "llapi/ServerAPI.h"
|
|
#include <llapi/utils/WinHelper.h>
|
|
#include <llapi/utils/StringHelper.h>
|
|
#include <llapi/utils/NetworkHelper.h>
|
|
#include <llapi/mc/Level.hpp>
|
|
#include <llapi/mc/PropertiesSettings.hpp>
|
|
#include <llapi/mc/ServerNetworkHandler.hpp>
|
|
#include <llapi/mc/ServerPlayer.hpp>
|
|
#include <Nlohmann/json.hpp>
|
|
|
|
#define BSTATS_JSON(key, val) \
|
|
if (json.find(key) != json.end()) { \
|
|
const nlohmann::json& out = json.at(key); \
|
|
out.get_to(val); \
|
|
}
|
|
|
|
using namespace std;
|
|
|
|
namespace regEdit {
|
|
|
|
bool create(const string& UUID) {
|
|
HKEY hRoot = HKEY_CURRENT_USER;
|
|
HKEY hKey;
|
|
DWORD dwDisposition = REG_OPENED_EXISTING_KEY;
|
|
LONG lRet = ::RegCreateKeyEx(hRoot, L"SOFTWARE\\LiteLoaderBDS", 0, nullptr,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition);
|
|
if (lRet != ERROR_SUCCESS)
|
|
return false;
|
|
auto uuid = str2wstr(UUID);
|
|
lRet = ::RegSetValueEx(hKey, uuid.c_str(), 0, REG_SZ, nullptr, 0);
|
|
if (lRet == ERROR_SUCCESS) {
|
|
}
|
|
::RegCloseKey(hKey);
|
|
return true;
|
|
}
|
|
|
|
unordered_set<string> getAllValue() {
|
|
unordered_set<string> result;
|
|
HKEY hRoot = HKEY_CURRENT_USER;
|
|
HKEY hKey;
|
|
DWORD dwDisposition = REG_OPENED_EXISTING_KEY;
|
|
LONG lRet = ::RegCreateKeyEx(hRoot, L"SOFTWARE\\LiteLoaderBDS", 0, nullptr,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition);
|
|
if (lRet != ERROR_SUCCESS)
|
|
return result;
|
|
|
|
// enum value from registry
|
|
DWORD dwIndex = 0;
|
|
DWORD dwValueNameSize = MAX_PATH;
|
|
DWORD dwValueSize = MAX_PATH;
|
|
auto* lpValueName = new wchar_t[dwValueNameSize];
|
|
auto* lpValue = new wchar_t[dwValueSize];
|
|
while (::RegEnumValue(hKey, dwIndex, lpValueName, &dwValueNameSize, nullptr, nullptr, (LPBYTE)lpValue, &dwValueSize) == ERROR_SUCCESS) {
|
|
result.insert(wstr2str(lpValueName));
|
|
dwValueNameSize = MAX_PATH;
|
|
dwValueSize = MAX_PATH;
|
|
dwIndex++;
|
|
}
|
|
delete[] lpValueName;
|
|
delete[] lpValue;
|
|
::RegCloseKey(hKey);
|
|
return result;
|
|
}
|
|
} // namespace regEdit
|
|
|
|
|
|
namespace bstatsSettings {
|
|
|
|
namespace uuid {
|
|
|
|
std::string generateUuidV4() {
|
|
static std::random_device rd;
|
|
static std::mt19937 gen(rd());
|
|
static std::uniform_int_distribution<> dis(0, 15);
|
|
static std::uniform_int_distribution<> dis2(8, 11);
|
|
|
|
std::stringstream ss;
|
|
int i;
|
|
ss << std::hex;
|
|
for (i = 0; i < 8; i++) {
|
|
ss << dis(gen);
|
|
}
|
|
ss << "-";
|
|
for (i = 0; i < 4; i++) {
|
|
ss << dis(gen);
|
|
}
|
|
ss << "-4";
|
|
for (i = 0; i < 3; i++) {
|
|
ss << dis(gen);
|
|
}
|
|
ss << "-";
|
|
ss << dis2(gen);
|
|
for (i = 0; i < 3; i++) {
|
|
ss << dis(gen);
|
|
}
|
|
ss << "-";
|
|
for (i = 0; i < 12; i++) {
|
|
ss << dis(gen);
|
|
}
|
|
return ss.str();
|
|
}
|
|
} // namespace uuid
|
|
|
|
bool enable = true;
|
|
std::string serverUuid = uuid::generateUuidV4(); // NOLINT(cert-err58-cpp)
|
|
|
|
nlohmann::json globalJson() {
|
|
nlohmann::json json;
|
|
json["enabled"] = enable;
|
|
json["serverUuid"] = serverUuid;
|
|
return json;
|
|
}
|
|
|
|
void initJson(nlohmann::json json) {
|
|
BSTATS_JSON("enabled", enable)
|
|
BSTATS_JSON("serverUuid", serverUuid)
|
|
}
|
|
|
|
void writeDefaultConfig(const std::string& fileName) {
|
|
std::ofstream file(fileName);
|
|
if (!file.is_open()) {
|
|
logger.error("Can't open file {}", fileName);
|
|
return;
|
|
}
|
|
auto json = globalJson();
|
|
regEdit::create(serverUuid);
|
|
file << "//bStats collects some data for plugin authors like how many servers are using their plugins.\n";
|
|
file << "//To honor their work, you should not disable it.\n";
|
|
file << "//This has nearly no effect on the server performance!Check out https://bStats.org/ to learn more\n";
|
|
file << json.dump(4);
|
|
file.close();
|
|
}
|
|
|
|
void writeConfig(const std::string& fileName) {
|
|
std::ofstream file(fileName);
|
|
if (!file.is_open()) {
|
|
logger.error("Can't open file {}", fileName);
|
|
return;
|
|
}
|
|
auto json = globalJson();
|
|
file << "//bStats collects some data for plugin authors like how many servers are using their plugins.\n";
|
|
file << "//To honor their work, you should not disable it.\n";
|
|
file << "//This has nearly no effect on the server performance!Check out https://bStats.org/ to learn more\n";
|
|
file << json.dump(4);
|
|
file.close();
|
|
}
|
|
|
|
void loadConfigFromJson(const std::string& fileName) {
|
|
std::ifstream file(fileName);
|
|
if (!file.is_open()) {
|
|
logger.error("Can't open file {}", fileName);
|
|
return;
|
|
}
|
|
auto json = nlohmann::json::parse(file, nullptr, true, true);
|
|
// file >> json;
|
|
// file.close();
|
|
initJson(json);
|
|
writeConfig(fileName);
|
|
}
|
|
|
|
void reloadJson(const std::string& fileName) {
|
|
std::ofstream file(fileName);
|
|
if (file) {
|
|
file << "//bStats collects some data for plugin authors like how many servers are using their plugins.\n";
|
|
file << "//To honor their work, you should not disable it.\n";
|
|
file << "//This has nearly no effect on the server performance!Check out https://bStats.org/ to learn more\n";
|
|
file << globalJson().dump(4);
|
|
} else {
|
|
logger.error("Configuration File Creation failed!");
|
|
}
|
|
file.close();
|
|
}
|
|
} // namespace bstatsSettings
|
|
|
|
namespace bstats {
|
|
|
|
static bool isOnlineAuth;
|
|
static int playerAmount;
|
|
static unordered_map<string, int> playerPlatList; // NOLINT(cert-err58-cpp)
|
|
|
|
DWORD getCpuCoreCount() {
|
|
SYSTEM_INFO systemInfo;
|
|
GetSystemInfo(&systemInfo);
|
|
return systemInfo.dwNumberOfProcessors;
|
|
}
|
|
|
|
string getOsArch() {
|
|
SYSTEM_INFO systemInfo;
|
|
GetSystemInfo(&systemInfo);
|
|
return systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? "x64" : "x86";
|
|
}
|
|
|
|
|
|
string getOsName() {
|
|
return IsWineEnvironment() ? "Linux" : "Windows";
|
|
}
|
|
|
|
|
|
nlohmann::json addSimplePie(const string& key, const string& val) {
|
|
nlohmann::json json;
|
|
json["chartId"] = key;
|
|
nlohmann::json json2;
|
|
json2["value"] = val;
|
|
json["data"] = json2;
|
|
return json;
|
|
}
|
|
|
|
nlohmann::json addAdvancedPie(const string& key, const unordered_map<string, int>& val) {
|
|
nlohmann::json json;
|
|
json["chartId"] = key;
|
|
nlohmann::json json2;
|
|
nlohmann::json valuesBuilder;
|
|
for (auto [String, Integer] : val) {
|
|
valuesBuilder[String] = Integer;
|
|
}
|
|
json2["values"] = valuesBuilder;
|
|
json["data"] = json2;
|
|
return json;
|
|
}
|
|
|
|
nlohmann::json getCustomCharts() {
|
|
nlohmann::json pluginsJson;
|
|
|
|
pluginsJson.emplace_back(addSimplePie("liteloaderbds_version", ll::getLoaderVersion().toString(false)));
|
|
pluginsJson.emplace_back(addSimplePie("bds_version", ll::getBdsVersion().substr(1)));
|
|
pluginsJson.emplace_back(addSimplePie("xbox_auth", isOnlineAuth ? "Required" : "Not required"));
|
|
pluginsJson.emplace_back(addAdvancedPie("player_platform", playerPlatList));
|
|
|
|
return pluginsJson;
|
|
}
|
|
|
|
string createJson() {
|
|
nlohmann::json json;
|
|
// service
|
|
json["service"]["id"] = 15847;
|
|
json["service"]["customCharts"] = getCustomCharts();
|
|
json["serverUUID"] = bstatsSettings::serverUuid;
|
|
json["playerAmount"] = playerAmount;
|
|
json["osName"] = getOsName();
|
|
json["osArch"] = getOsArch();
|
|
json["osVersion"] = getOsArch();
|
|
json["coreCount"] = getCpuCoreCount();
|
|
return json.dump();
|
|
}
|
|
|
|
void submitTask() {
|
|
playerAmount = Global<ServerNetworkHandler>->_getActiveAndInProgressPlayerCount(mce::UUID::EMPTY);
|
|
playerPlatList.clear();
|
|
for (auto sp : Level::getAllPlayers()) {
|
|
auto OS = sp->getDeviceName();
|
|
if (playerPlatList.find(OS) == playerPlatList.end()) {
|
|
playerPlatList.emplace(OS, 1);
|
|
} else {
|
|
playerPlatList[OS] = playerPlatList[OS] + 1;
|
|
}
|
|
}
|
|
|
|
std::thread a([] {
|
|
auto json = createJson();
|
|
httplib::Headers headers = {
|
|
{"Accept-Encoding", "gzip"},
|
|
{"Accept", "application/json"},
|
|
{"Connection", "close"},
|
|
{"Content-Length", std::to_string(json.size())},
|
|
{"Content-Type", "application/json"},
|
|
{"User-Agent", "Metrics-Service/1"}};
|
|
HttpPost(
|
|
"https://bstats.org/api/v2/data/bukkit", headers, json, "", [](int a1, const string& a2) {}, 10);
|
|
});
|
|
|
|
a.detach();
|
|
}
|
|
|
|
void createJsonConfig() {
|
|
if (!std::filesystem::exists("plugins/bStats"))
|
|
std::filesystem::create_directories("plugins/bStats");
|
|
if (std::filesystem::exists("plugins/bStats/config.json")) {
|
|
try {
|
|
bstatsSettings::loadConfigFromJson("plugins/bStats/config.json");
|
|
} catch (std::exception& e) {
|
|
logger.error("Config File isInvalid, Err {}", e.what());
|
|
} catch (...) {
|
|
logger.error("Config File isInvalid");
|
|
}
|
|
} else {
|
|
logger.info("Config with default values created");
|
|
bstatsSettings::writeDefaultConfig("plugins/bStats/config.json");
|
|
}
|
|
}
|
|
|
|
void configInit() {
|
|
createJsonConfig();
|
|
auto serverUuidList = regEdit::getAllValue();
|
|
if (!serverUuidList.count(bstatsSettings::serverUuid)) {
|
|
auto newUUID = bstatsSettings::uuid::generateUuidV4();
|
|
regEdit::create(newUUID);
|
|
bstatsSettings::serverUuid = newUUID;
|
|
bstatsSettings::reloadJson("plugins/bStats/config.json");
|
|
}
|
|
}
|
|
|
|
// generate random float between 0.0 and 1.0
|
|
float randomFloat() {
|
|
std::random_device rd;
|
|
std::mt19937 gen(rd());
|
|
std::uniform_real_distribution<float> dis(0.0, 1.0);
|
|
return dis(gen);
|
|
}
|
|
|
|
const unsigned long long period = 1000 * 60 * 30;
|
|
|
|
void scheduleThread() {
|
|
std::thread schedule([]() {
|
|
auto initialDelay = (unsigned long long)(1000 * 60 * (3 + randomFloat() * 3));
|
|
auto secondDelay = (unsigned long long)(1000 * 60 * (randomFloat() * 30));
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(initialDelay));
|
|
Schedule::nextTick(submitTask);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(secondDelay));
|
|
while (!ll::isServerStopping()) {
|
|
Schedule::nextTick(submitTask);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(period));
|
|
}
|
|
|
|
});
|
|
schedule.detach();
|
|
}
|
|
|
|
void registerBStats() {
|
|
configInit();
|
|
if (bstatsSettings::enable) {
|
|
Event::ServerStartedEvent::subscribe([](const Event::ServerStartedEvent& ev) {
|
|
isOnlineAuth = Global<PropertiesSettings>->useOnlineAuthentication();
|
|
scheduleThread();
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
|
|
} // namespace bstats
|