#include #include #include #include #include #include #include #define CPPHTTPLIB_OPENSSL_SUPPORT #include extern Console::Setting uMaxPlayerCount; static constexpr char kMasterServerEndpoint[] = //"http://127.0.0.1:8000"; "https://skyrim-reborn-list.skyrim-together.com"; static Console::Setting bAnnounceServer{"LiveServices:bAnnounceServer", "Whether to list the server on the public server list", false}; ServerListService::ServerListService(World& aWorld, entt::dispatcher& aDispatcher) noexcept : m_world(aWorld) , m_updateConnection(aDispatcher.sink().connect<&ServerListService::OnUpdate>(this)) , m_nextAnnounce(std::chrono::seconds(0)) { if (!bAnnounceServer) spdlog::warn("bAnnounceServer is set to false. The server will not show up as a public server. " "If you are just playing with friends, this is probably what you want."); } void ServerListService::OnUpdate(const UpdateEvent& acEvent) noexcept { if (m_nextAnnounce < std::chrono::steady_clock::now()) { Announce(); m_nextAnnounce = (std::chrono::steady_clock::now() + std::chrono::minutes(1)); } } void ServerListService::OnPlayerJoin(const PlayerJoinEvent& acEvent) noexcept { Announce(); m_nextAnnounce = (std::chrono::steady_clock::now() + std::chrono::minutes(1)); } void ServerListService::OnPlayerLeave(const PlayerLeaveEvent& acEvent) noexcept { Announce(); m_nextAnnounce = (std::chrono::steady_clock::now() + std::chrono::minutes(1)); } void ServerListService::Announce() noexcept { std::thread([&]() { auto* pServer = GameServer::Get(); auto pc = static_cast(m_world.GetPlayerManager().Count()); if (bAnnounceServer) m_flags |= kIsPublic; if (pServer->IsPasswordProtected()) m_flags |= kHasPassword; const auto& cInfo = pServer->GetInfo(); PostAnnouncement(cInfo.name, cInfo.desc, cInfo.icon_url, pServer->GetPort(), cInfo.tick_rate, pc, uMaxPlayerCount.value_as(), cInfo.tagList, bAnnounceServer, pServer->IsPasswordProtected(), m_flags); }).detach(); } void ServerListService::PostAnnouncement(String acName, String acDesc, String acIconUrl, uint16_t aPort, uint16_t aTick, uint16_t aPlayerCount, uint16_t aPlayerMaxCount, String acTagList, bool aPublic, bool aPassword, int32 aFlags) noexcept { const std::string kVersion{BUILD_COMMIT}; const httplib::Params params{ {"name", std::string(acName.c_str(), acName.size())}, {"desc", std::string(acDesc.c_str(), acDesc.size())}, {"icon_url", std::string(acIconUrl.c_str(), acIconUrl.size())}, {"version", std::string(kVersion.c_str(), kVersion.size())}, {"port", std::to_string(aPort)}, {"tick", std::to_string(aTick)}, {"player_count", std::to_string(aPlayerCount)}, {"max_player_count", std::to_string(aPlayerMaxCount)}, {"tags", std::string(acTagList.c_str(), acTagList.size())}, {"public", aPublic ? "true" : "false"}, {"pass", aPassword ? "true" : "false"}, {"flags", std::to_string(aFlags)}, }; httplib::Client client(kMasterServerEndpoint); client.enable_server_certificate_verification(false); client.set_read_timeout(std::chrono::milliseconds(30000)); const auto response = client.Post("/announce", params); // If we send a 403 it means we banned this server if (response) { if (response->status == 403) GameServer::Get()->Kill(); else if (response->status != 200) spdlog::error("Server list error! {}", response->body); } else { spdlog::error("Server could not reach the server list! {}", to_string(response.error())); } }