#include "storm/storm_net.hpp" #include #include #include #ifndef NONET #include #include #include #include "utils/sdl_mutex.h" #endif #include "dvlnet/abstract_net.h" #include "engine/demomode.h" #include "headless_mode.hpp" #include "menu.h" #include "multi.h" #include "options.h" #include "utils/log.hpp" #include "utils/stubs.h" #include "utils/utf8.hpp" namespace devilution { namespace { std::unique_ptr dvlnet_inst; bool GameIsPublic = {}; #ifndef NONET SdlMutex storm_net_mutex; #endif } // namespace bool SNetReceiveMessage(uint8_t *senderplayerid, void **data, size_t *databytes) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif return dvlnet_inst->SNetReceiveMessage(senderplayerid, data, databytes); } bool SNetSendMessage(uint8_t playerID, void *data, size_t databytes) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif return dvlnet_inst->SNetSendMessage(playerID, data, databytes); } bool SNetReceiveTurns(int arraysize, char **arraydata, size_t *arraydatabytes, uint32_t *arrayplayerstatus) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif if (arraysize != MAX_PLRS) UNIMPLEMENTED(); return dvlnet_inst->SNetReceiveTurns(arraydata, arraydatabytes, arrayplayerstatus); } bool SNetSendTurn(char *data, size_t databytes) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif return dvlnet_inst->SNetSendTurn(data, databytes); } void SNetGetProviderCaps(struct _SNETCAPS *caps) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif dvlnet_inst->SNetGetProviderCaps(caps); } bool SNetUnregisterEventHandler(event_type evtype) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif if (dvlnet_inst == nullptr) return true; return dvlnet_inst->SNetUnregisterEventHandler(evtype); } bool SNetRegisterEventHandler(event_type evtype, SEVTHANDLER func) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif return dvlnet_inst->SNetRegisterEventHandler(evtype, func); } bool SNetDestroy() { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif dvlnet_inst = nullptr; return true; } bool SNetDropPlayer(uint8_t playerid, leaveinfo_t flags) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif return dvlnet_inst->SNetDropPlayer(playerid, flags); } bool SNetLeaveGame(leaveinfo_t type) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif if (dvlnet_inst == nullptr) return true; if (!IsLoopback) { std::string upperGameName = GameName; std::transform(upperGameName.begin(), upperGameName.end(), upperGameName.begin(), ::toupper); const std::string reasonDescription = DescribeLeaveReason(type); LogInfo("Leaving {} multiplayer game '{}' (reason: {})", ConnectionNames[provider], upperGameName, reasonDescription); } return dvlnet_inst->SNetLeaveGame(type); } /** * @brief Called by engine for single, called by ui for multi * @param provider BNET, IPXN, MODM, SCBL or UDPN * @param gameData The game data */ bool SNetInitializeProvider(uint32_t provider, struct GameData *gameData) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif dvlnet_inst = net::abstract_net::MakeNet(provider); return (HeadlessMode && !demo::IsRunning()) || mainmenu_select_hero_dialog(gameData); } /** * @brief Called by engine for single, called by ui for multi */ bool SNetCreateGame(const char *pszGameName, const char *pszGamePassword, char *gameTemplateData, int gameTemplateSize, int *playerID) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif if (gameTemplateSize != sizeof(GameData)) ABORT(); net::buffer_t gameInitInfo(gameTemplateData, gameTemplateData + gameTemplateSize); dvlnet_inst->setup_gameinfo(std::move(gameInitInfo)); std::string defaultName; if (pszGameName == nullptr) { defaultName = dvlnet_inst->make_default_gamename(); pszGameName = defaultName.c_str(); } GameName = pszGameName; if (pszGamePassword != nullptr) DvlNet_SetPassword(pszGamePassword); else DvlNet_ClearPassword(); const int createdPlayerId = dvlnet_inst->create(pszGameName); if (createdPlayerId == -1) return false; *playerID = createdPlayerId; if (!IsLoopback) { std::string upperGameName = GameName; std::transform(upperGameName.begin(), upperGameName.end(), upperGameName.begin(), ::toupper); const char *privacy = GameIsPublic ? "public" : "private"; if (gameTemplateData != nullptr && gameTemplateSize >= static_cast(sizeof(GameData))) { const GameData *gameData = reinterpret_cast(gameTemplateData); LogInfo("Created {} {} multiplayer game '{}' (player id: {}, seed: {})", privacy, ConnectionNames[provider], upperGameName, createdPlayerId, FormatGameSeed(gameData->gameSeed)); } else { LogInfo("Created {} {} multiplayer game '{}' (player id: {}, seed unavailable)", privacy, ConnectionNames[provider], upperGameName, createdPlayerId); } } return true; } bool SNetJoinGame(char *pszGameName, char *pszGamePassword, int *playerID) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif if (pszGameName != nullptr) GameName = pszGameName; if (pszGamePassword != nullptr) DvlNet_SetPassword(pszGamePassword); else DvlNet_ClearPassword(); const int joinedPlayerId = dvlnet_inst->join(pszGameName); if (joinedPlayerId == -1) return false; *playerID = joinedPlayerId; // Join message with seed will be logged in NetInit after game data is synchronized return true; } /** * @brief Is this the mirror image of SNetGetTurnsInTransit? */ bool SNetGetOwnerTurnsWaiting(uint32_t *turns) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif return dvlnet_inst->SNetGetOwnerTurnsWaiting(turns); } bool SNetGetTurnsInTransit(uint32_t *turns) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif return dvlnet_inst->SNetGetTurnsInTransit(turns); } /** * @brief engine calls this only once with argument 1 */ bool SNetSetBasePlayer(int /*unused*/) { #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif return true; } void DvlNet_ProcessNetworkPackets() { return dvlnet_inst->process_network_packets(); } bool DvlNet_SendInfoRequest() { return dvlnet_inst->send_info_request(); } void DvlNet_ClearGamelist() { return dvlnet_inst->clear_gamelist(); } std::vector DvlNet_GetGamelist() { return dvlnet_inst->get_gamelist(); } void DvlNet_SetPassword(std::string pw) { GameIsPublic = false; GamePassword = pw; dvlnet_inst->setup_password(std::move(pw)); } void DvlNet_ClearPassword() { GameIsPublic = true; GamePassword.clear(); dvlnet_inst->clear_password(); } bool DvlNet_IsPublicGame() { return GameIsPublic; } DvlNetLatencies DvlNet_GetLatencies(uint8_t playerId) { return dvlnet_inst->get_latencies(playerId); } } // namespace devilution