diff --git a/.gitignore b/.gitignore index 64c56cce..3a0c8b0c 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,7 @@ sm64config.txt !/sound/**/*custom*/**/*.aiff !/assets/**/*custom*.bin !/assets/**/*custom*/**/*.bin +!/lib/discordsdk/*.* # visual studio build-windows-visual-studio/.vs diff --git a/Makefile b/Makefile index ffaf4cc8..e1edb219 100644 --- a/Makefile +++ b/Makefile @@ -54,8 +54,9 @@ DISCORDRPC ?= 0 DOCKERBUILD ?= 0 # Force various options due since coop assumes they are set this way -NODRAWINGDISTANCE = 1 -TEXTSAVES = 0 +NODRAWINGDISTANCE := 1 +TEXTSAVES := 0 +DISCORDRPC := 0 # Various workarounds for weird toolchains @@ -292,7 +293,8 @@ LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h))) # Directories containing source files # Hi, I'm a PC -SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes src/pc/network src/pc/network/packets src/pc/network/socket +SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes +SRC_DIRS += src/pc/network src/pc/network/packets src/pc/network/socket src/pc/network/discord ASM_DIRS := ifeq ($(DISCORDRPC),1) @@ -427,6 +429,16 @@ ifeq ($(DISCORDRPC),1) endif endif +DISCORD_SDK_LIBS := +ifeq ($(WINDOWS_BUILD),1) + DISCORD_SDK_LIBS := lib/discordsdk/discord_game_sdk.dll +else ifeq ($(OSX_BUILD),1) + # needs testing + DISCORD_SDK_LIBS := lib/discordsdk/discord_game_sdk.dylib +else + DISCORD_SDK_LIBS := lib/discordsdk/discord_game_sdk.so +endif + # Automatic dependency files DEP_FILES := $(O_FILES:.o=.d) $(ULTRA_O_FILES:.o=.d) $(GODDARD_O_FILES:.o=.d) $(BUILD_DIR)/$(LD_SCRIPT).d @@ -659,7 +671,7 @@ ifeq ($(TARGET_WEB),1) LDFLAGS := -lm -lGL -lSDL2 -no-pie -s TOTAL_MEMORY=20MB -g4 --source-map-base http://localhost:8080/ -s "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain']" else ifeq ($(WINDOWS_BUILD),1) - LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -Llib -L"ws2_32" -lwsock32 -lpthread $(BACKEND_LDFLAGS) -static + LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -Llib -lpthread $(BACKEND_LDFLAGS) -static ifeq ($(CROSS),) LDFLAGS += -no-pie endif @@ -679,7 +691,17 @@ else LDFLAGS += -ldl -Wl,-rpath . endif -endif # End of LDFLAGS +endif + +# coop specific libraries + +ifeq ($(WINDOWS_BUILD),1) + LDFLAGS += -L"ws2_32" -lwsock32 +endif + +LDFLAGS += -Wl,-Bdynamic -ldiscord_game_sdk + +# End of LDFLAGS # Prevent a crash with -sopt export LANG := C @@ -768,6 +790,9 @@ load: $(ROM) $(BUILD_DIR)/$(RPC_LIBS): @$(CP) -f $(RPC_LIBS) $(BUILD_DIR) +$(BUILD_DIR)/$(DISCORD_SDK_LIBS): + @$(CP) -f $(DISCORD_SDK_LIBS) $(BUILD_DIR) + libultra: $(BUILD_DIR)/libultra.a $(BUILD_DIR)/asm/boot.o: $(IPL3_RAW_FILES) @@ -1022,7 +1047,7 @@ $(BUILD_DIR)/%.o: %.s -$(EXE): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(SOUND_OBJ_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(BUILD_DIR)/$(RPC_LIBS) +$(EXE): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(SOUND_OBJ_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(BUILD_DIR)/$(RPC_LIBS) $(BUILD_DIR)/$(DISCORD_SDK_LIBS) $(LD) -L $(BUILD_DIR) -o $@ $(O_FILES) $(SOUND_OBJ_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(LDFLAGS) .PHONY: all clean distclean default diff test load libultra res diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index 56024294..eac557d5 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3949,6 +3949,11 @@ + + + + + @@ -4308,6 +4313,12 @@ + + + + + + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index 2579529d..5e56b6d8 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -3427,6 +3427,12 @@ {b1b4937e-775c-4a0c-92f5-48b010783e4d} + + {6d48a98e-e5ac-4409-a834-f2756dabfa4a} + + + {7fd7fed2-3f22-4bbf-a118-8ff54107c341} + @@ -15015,6 +15021,21 @@ Source Files\src\pc\controller + + Source Files\src\pc\network\discord + + + Source Files\src\pc\network\discord + + + Source Files\src\pc\network\discord + + + Source Files\src\pc\network\discord + + + Source Files\src\pc\network\discord + @@ -15937,5 +15958,23 @@ Source Files\src\pc\controller + + Header Files\src\pc\network\discord + + + Header Files\src\pc\network\discord + + + Header Files\src\pc\network\discord + + + Header Files\src\pc\network\discord + + + Header Files\src\pc\network\discord + + + Header Files\src\pc\network\discord + \ No newline at end of file diff --git a/lib/discordsdk/discord_game_sdk.bundle b/lib/discordsdk/discord_game_sdk.bundle new file mode 100644 index 00000000..24045f79 Binary files /dev/null and b/lib/discordsdk/discord_game_sdk.bundle differ diff --git a/lib/discordsdk/discord_game_sdk.dll b/lib/discordsdk/discord_game_sdk.dll new file mode 100644 index 00000000..10a8928f Binary files /dev/null and b/lib/discordsdk/discord_game_sdk.dll differ diff --git a/lib/discordsdk/discord_game_sdk.dll.lib b/lib/discordsdk/discord_game_sdk.dll.lib new file mode 100644 index 00000000..8ab3d4cb Binary files /dev/null and b/lib/discordsdk/discord_game_sdk.dll.lib differ diff --git a/lib/discordsdk/discord_game_sdk.dylib b/lib/discordsdk/discord_game_sdk.dylib new file mode 100644 index 00000000..24045f79 Binary files /dev/null and b/lib/discordsdk/discord_game_sdk.dylib differ diff --git a/lib/discordsdk/discord_game_sdk.so b/lib/discordsdk/discord_game_sdk.so new file mode 100644 index 00000000..e4657606 Binary files /dev/null and b/lib/discordsdk/discord_game_sdk.so differ diff --git a/network.sh b/network.sh index ec2677d1..7a5c0434 100755 --- a/network.sh +++ b/network.sh @@ -11,10 +11,16 @@ if [ ! -f "$FILE" ]; then FILE=./build/us_pc/sm64.us.f3dex2e fi -$FILE --server 27015 --configfile sm64config_server.txt & +#$FILE --discord 2 --configfile sm64config_server.txt & +#$FILE --discord 1 --configfile sm64config_client.txt & +#exit + +#$FILE --server 27015 --configfile sm64config_server.txt & #$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & #exit +$FILE --server 27015 --configfile sm64config_server.txt & + # debug if cgdb exists if ! [ -x "$(command -v cgdb)" ]; then $FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & diff --git a/src/menu/file_select.c b/src/menu/file_select.c index b3bddb90..719962b3 100644 --- a/src/menu/file_select.c +++ b/src/menu/file_select.c @@ -42,6 +42,8 @@ */ static u8 joinVersionMismatch = FALSE; +static char joinMenuCustomText[64] = { 0 }; +static u8 forceOpenJoinMenu = 0; #ifdef VERSION_US // The current sound mode is automatically centered on US due to @@ -385,6 +387,9 @@ void exit_join_to_network_menu(void) { // Begin exit if (sMainMenuButtons[MENU_BUTTON_JOIN]->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN && sCursorClickingTimer == 2) { + // clear custom text + joinMenuCustomText[0] = '\0'; + play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gDefaultSoundArgs); sMainMenuButtons[MENU_BUTTON_JOIN]->oMenuButtonState = MENU_BUTTON_STATE_SHRINKING; network_shutdown(); @@ -468,8 +473,37 @@ void render_network_mode_menu_buttons(struct Object* soundModeButton) { sMainMenuButtons[MENU_BUTTON_JOIN]->oFaceAngleRoll = 0; } +void open_join_menu(char* customText) { + if (sMainMenuButtons[MENU_BUTTON_JOIN] == NULL) { + forceOpenJoinMenu = (forceOpenJoinMenu == 0) ? 1 : forceOpenJoinMenu; + } else if (sMainMenuButtons[MENU_BUTTON_JOIN]->oMenuButtonState != MENU_BUTTON_STATE_FULLSCREEN) { + forceOpenJoinMenu = 0; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gDefaultSoundArgs); + sMainMenuButtons[MENU_BUTTON_JOIN]->oMenuButtonState = MENU_BUTTON_STATE_GROWING; + sSelectedButtonID = MENU_BUTTON_JOIN; + sCurrentMenuLevel = MENU_LAYER_SUBMENU; + } else { + forceOpenJoinMenu = 0; + } + + if (customText == joinMenuCustomText) { return; } + + if (customText != NULL) { + strncpy(joinMenuCustomText, customText, 63); + } else if (*gTextInput == '\0') { + joinMenuCustomText[0] = '\0'; + } +} + void check_network_mode_menu_clicked_buttons(struct Object* networkModeButton) { if (networkModeButton->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) { + + if (forceOpenJoinMenu && forceOpenJoinMenu++ > 3) { + forceOpenJoinMenu = 0; + open_join_menu(joinMenuCustomText); + return; + } + s32 buttonID; // Configure sound mode menu button group for (buttonID = MENU_BUTTON_NETWORK_MIN; buttonID < MENU_BUTTON_NETWORK_MAX; buttonID++) { @@ -486,9 +520,7 @@ void check_network_mode_menu_clicked_buttons(struct Object* networkModeButton) { } } else if (buttonID == MENU_BUTTON_JOIN) { - play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gDefaultSoundArgs); - sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_GROWING; - sSelectedButtonID = buttonID; + open_join_menu(NULL); // start input keyboard_start_text_input(TIM_IP, keyboard_exit_join_to_network_menu, join_server_as_client); @@ -565,16 +597,21 @@ void print_join_mode_menu_strings(void) { gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); // Print level name - print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 0), "Type or paste the host's IP."); - print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 2), gTextInput); + if (joinMenuCustomText[0] != '\0') { + print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (14 * 3), joinMenuCustomText); + } else { + print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (14 * 0), "Accept a Discord invite."); + print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (14 * 1), "Alternatively, type or paste the host's IP."); + print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (14 * 3), gTextInput); + } // Print status if (joinVersionMismatch) { - print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 14), "Error - versions don't match. Both should rebuild!"); + print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (13 * 14), "Error - versions don't match. Both should rebuild!"); } else if (gNetworkType == NT_CLIENT) { - print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 14), "Connecting..."); + print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (13 * 14), "Connecting..."); } else if (strlen(gTextInput) > 0) { - print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 14), "Press (ENTER) to join."); + print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (13 * 14), "Press (ENTER) to directly connect."); } gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_end); @@ -1619,6 +1656,7 @@ void check_main_menu_clicked_buttons(void) { button->oMenuButtonTimer = 0; sSelectedButtonID = MENU_BUTTON_NETWORK_MODE; + networkInit = TRUE; } diff --git a/src/menu/file_select.h b/src/menu/file_select.h index 1bf4b21e..63e74045 100644 --- a/src/menu/file_select.h +++ b/src/menu/file_select.h @@ -145,5 +145,6 @@ s32 lvl_init_menu_values_and_cursor_pos(UNUSED s32 arg, UNUSED s32 unused); s32 lvl_update_obj_and_load_file_selected(UNUSED s32 arg, UNUSED s32 unused); void joined_server_as_client(s16 fileIndex); void joined_server_version_mismatch(void); +void open_join_menu(char* customText); #endif // FILE_SELECT_H diff --git a/src/pc/cliopts.c b/src/pc/cliopts.c index 3f20f911..4643975c 100644 --- a/src/pc/cliopts.c +++ b/src/pc/cliopts.c @@ -79,6 +79,9 @@ void parse_cli_opts(int argc, char* argv[]) { else if (strcmp(argv[i], "--savepath") == 0 && (i + 1) < argc) arg_string("--savepath", argv[++i], gCLIOpts.SavePath, SYS_MAX_PATH); + else if (strcmp(argv[i], "--discord") == 0 && (i + 1) < argc) + arg_uint("--discord", argv[++i], &gCLIOpts.Discord); + // Print help else if (strcmp(argv[i], "--help") == 0) { print_help(); diff --git a/src/pc/cliopts.h b/src/pc/cliopts.h index 916e19b1..ea360450 100644 --- a/src/pc/cliopts.h +++ b/src/pc/cliopts.h @@ -22,6 +22,7 @@ struct PCCLIOptions { char ConfigFile[SYS_MAX_PATH]; char SavePath[SYS_MAX_PATH]; char GameDir[SYS_MAX_PATH]; + unsigned int Discord; }; extern struct PCCLIOptions gCLIOpts; diff --git a/src/pc/network/discord/activity.c b/src/pc/network/discord/activity.c new file mode 100644 index 00000000..7d3f1802 --- /dev/null +++ b/src/pc/network/discord/activity.c @@ -0,0 +1,73 @@ +#include "activity.h" +#include "lobby.h" +#include "discord_network.h" +#include "pc/debuglog.h" +#include "menu/file_select.h" + +#define HASH_LENGTH 8 +struct DiscordActivity gCurActivity = { 0 }; + +static void on_activity_update_callback(UNUSED void* data, enum EDiscordResult result) { + LOG_INFO("> on_activity_update_callback returned %d", result); + DISCORD_REQUIRE(result); +} + +static void on_activity_join_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordLobby* lobby) { + LOG_INFO("> on_activity_join_callback returned %d, lobby %lld", result, lobby->id); + DISCORD_REQUIRE(result); + network_init(NT_CLIENT); + + gCurActivity.type = DiscordActivityType_Playing; + snprintf(gCurActivity.party.id, 128, "%lld", lobby->id); + gCurActivity.party.size.current_size = 2; + gCurActivity.party.size.max_size = lobby->capacity; + + gCurLobbyId = lobby->id; + + discord_network_init(lobby->id); + discord_activity_update(false); + + network_on_joined(); +} + +static void on_activity_join(UNUSED void* data, const char* secret) { + LOG_INFO("> on_activity_join, secret: %s", secret); + open_join_menu("Joining Discord invite..."); + app.lobbies->connect_lobby_with_activity_secret(app.lobbies, (char*)secret, NULL, on_activity_join_callback); +} + +static void on_activity_join_request_callback(UNUSED void* data, enum EDiscordResult result) { + LOG_INFO("> on_activity_join_request_callback returned %d", (int)result); +} + +static void on_activity_join_request(UNUSED void* data, struct DiscordUser* user) { + LOG_INFO("> on_activity_join_request from %lld", user->id); + //app.activities->send_request_reply(app.activities, user->id, DiscordActivityJoinRequestReply_Yes, NULL, on_activity_join_request_callback); +} + +void discord_activity_update(bool hosting) { + gCurActivity.type = DiscordActivityType_Playing; + if (gCurActivity.party.size.current_size > 1) { + strcpy(gCurActivity.state, "Playing!"); + } else if (hosting) { + strcpy(gCurActivity.state, "Waiting for player..."); + } else { + strcpy(gCurActivity.state, "In-game."); + gCurActivity.party.size.current_size = 1; + gCurActivity.party.size.max_size = 1; + } + + char hash[HASH_LENGTH] = GIT_HASH; + strcpy(gCurActivity.details, "version "); + strncat(gCurActivity.details, GIT_HASH, 127); + + app.activities->update_activity(app.activities, &gCurActivity, NULL, on_activity_update_callback); + LOG_INFO("set activity"); +} + +struct IDiscordActivityEvents* discord_activity_initialize(void) { + static struct IDiscordActivityEvents events = { 0 }; + events.on_activity_join = on_activity_join; + events.on_activity_join_request = on_activity_join_request; + return &events; +} \ No newline at end of file diff --git a/src/pc/network/discord/activity.h b/src/pc/network/discord/activity.h new file mode 100644 index 00000000..2fced611 --- /dev/null +++ b/src/pc/network/discord/activity.h @@ -0,0 +1,10 @@ +#ifndef DISCORD_ACTIVITY_H +#define DISCORD_ACTIVITY_H +#include "discord.h" + +extern struct DiscordActivity gCurActivity; + +void discord_activity_update(bool hosting); +struct IDiscordActivityEvents* discord_activity_initialize(void); + +#endif \ No newline at end of file diff --git a/src/pc/network/discord/discord.c b/src/pc/network/discord/discord.c new file mode 100644 index 00000000..a82c8a54 --- /dev/null +++ b/src/pc/network/discord/discord.c @@ -0,0 +1,120 @@ +#include "discord.h" +#include "user.h" +#include "activity.h" +#include "lobby.h" +#include "discord_network.h" +#include "pc/debuglog.h" + +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#endif + +#define MAX_LAUNCH_CMD (MAX_PATH + 12) + +static int64_t applicationId = 752700005210390568; +struct DiscordApplication app = { 0 }; +bool gDiscordInitialized = false; + +static void set_instance_env_variable(void) { + // set local instance id + char environmentVariables[64] = { 0 }; + int instance = (gCLIOpts.Discord == 0) ? 0 : (gCLIOpts.Discord - 1); + sprintf(environmentVariables, "DISCORD_INSTANCE_ID=%d", instance); + putenv(environmentVariables); + LOG_INFO("set environment variables: %s", environmentVariables); +} + +static void get_oauth2_token_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordOAuth2Token* token) { + LOG_INFO("> get_oauth2_token_callback returned %d", result); + if (result != DiscordResult_Ok) { return; } + LOG_INFO("OAuth2 token: %s", token->access_token); +} + +static void register_launch_command(void) { + char cmd[MAX_LAUNCH_CMD]; +#if defined(_WIN32) || defined(_WIN64) + HMODULE hModule = GetModuleHandle(NULL); + if (hModule == NULL) { + LOG_ERROR("unable to retrieve absolute path!"); + return; + } + GetModuleFileName(hModule, cmd, sizeof(cmd)); +#else + int rc = readlink("/proc/self/exe", cmd, sizeof(MAX_LAUNCH_CMD) - 1); + if (rc) { + LOG_ERROR("unable to retrieve absolute path! rc = %d", rc); + return; + } +#endif + strncat(cmd, " --discord 1", MAX_LAUNCH_CMD - 1); + DISCORD_REQUIRE(app.activities->register_command(app.activities, cmd)); + LOG_INFO("cmd: %s", cmd); +} + +static void ns_discord_update(void) { + if (!gDiscordInitialized) { return; } + DISCORD_REQUIRE(app.core->run_callbacks(app.core)); + discord_network_flush(); +} + +static bool ns_discord_initialize(enum NetworkType networkType) { +#ifdef DEBUG + set_instance_env_variable(); +#endif + if (!gDiscordInitialized) { + // set up discord params + struct DiscordCreateParams params; + DiscordCreateParamsSetDefault(¶ms); + params.client_id = applicationId; + params.flags = DiscordCreateFlags_NoRequireDiscord; + params.event_data = &app; + params.user_events = discord_user_initialize(); + params.activity_events = discord_activity_initialize(); + params.lobby_events = discord_lobby_initialize(); + + int rc = DiscordCreate(DISCORD_VERSION, ¶ms, &app.core); + if (rc) { + LOG_ERROR("DiscordCreate failed: %d", rc); + return false; + } + + // set up manager pointers + app.users = app.core->get_user_manager(app.core); + app.achievements = app.core->get_achievement_manager(app.core); + app.activities = app.core->get_activity_manager(app.core); + app.application = app.core->get_application_manager(app.core); + app.lobbies = app.core->get_lobby_manager(app.core); + + // register launch params + register_launch_command(); + + // get oath2 token + app.application->get_oauth2_token(app.application, NULL, get_oauth2_token_callback); + + // set activity + discord_activity_update(false); + } + + // create lobby + if (networkType == NT_SERVER) { discord_lobby_create(); } + + gDiscordInitialized = true; + LOG_INFO("initialized"); + + return true; +} + +static void ns_discord_shutdown(void) { + if (!gDiscordInitialized) { return; } + discord_lobby_leave(); + LOG_INFO("shutdown"); +} + +struct NetworkSystem gNetworkSystemDiscord = { + .initialize = ns_discord_initialize, + .update = ns_discord_update, + .send = ns_discord_network_send, + .shutdown = ns_discord_shutdown, +}; diff --git a/src/pc/network/discord/discord.h b/src/pc/network/discord/discord.h new file mode 100644 index 00000000..76b0a708 --- /dev/null +++ b/src/pc/network/discord/discord.h @@ -0,0 +1,35 @@ +#ifndef DISCORD_H +#define DISCORD_H +#include +#include +#include +#pragma pack(push, 8) +#include "discord_game_sdk.h" +#pragma pack(pop) +#ifdef _WIN32 +#include +#else +#include +#include +#endif +#include "../network.h" + +#define DISCORD_REQUIRE(x) assert(x == DiscordResult_Ok) + +extern struct NetworkSystem gNetworkSystemDiscord; +extern bool gDiscordInitialized; + +struct DiscordApplication { + struct IDiscordCore* core; + struct IDiscordUserManager* users; + struct IDiscordAchievementManager* achievements; + struct IDiscordActivityManager* activities; + struct IDiscordRelationshipManager* relationships; + struct IDiscordApplicationManager* application; + struct IDiscordLobbyManager* lobbies; + DiscordUserId userId; +}; + +extern struct DiscordApplication app; + +#endif \ No newline at end of file diff --git a/src/pc/network/discord/discord_game_sdk.h b/src/pc/network/discord/discord_game_sdk.h new file mode 100644 index 00000000..81cc2bdb --- /dev/null +++ b/src/pc/network/discord/discord_game_sdk.h @@ -0,0 +1,646 @@ +#ifndef _DISCORD_GAME_SDK_H_ +#define _DISCORD_GAME_SDK_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#ifndef __cplusplus +#include +#endif + +#define DISCORD_VERSION 2 +#define DISCORD_APPLICATION_MANAGER_VERSION 1 +#define DISCORD_USER_MANAGER_VERSION 1 +#define DISCORD_IMAGE_MANAGER_VERSION 1 +#define DISCORD_ACTIVITY_MANAGER_VERSION 1 +#define DISCORD_RELATIONSHIP_MANAGER_VERSION 1 +#define DISCORD_LOBBY_MANAGER_VERSION 1 +#define DISCORD_NETWORK_MANAGER_VERSION 1 +#define DISCORD_OVERLAY_MANAGER_VERSION 1 +#define DISCORD_STORAGE_MANAGER_VERSION 1 +#define DISCORD_STORE_MANAGER_VERSION 1 +#define DISCORD_VOICE_MANAGER_VERSION 1 +#define DISCORD_ACHIEVEMENT_MANAGER_VERSION 1 + +enum EDiscordResult { + DiscordResult_Ok = 0, + DiscordResult_ServiceUnavailable = 1, + DiscordResult_InvalidVersion = 2, + DiscordResult_LockFailed = 3, + DiscordResult_InternalError = 4, + DiscordResult_InvalidPayload = 5, + DiscordResult_InvalidCommand = 6, + DiscordResult_InvalidPermissions = 7, + DiscordResult_NotFetched = 8, + DiscordResult_NotFound = 9, + DiscordResult_Conflict = 10, + DiscordResult_InvalidSecret = 11, + DiscordResult_InvalidJoinSecret = 12, + DiscordResult_NoEligibleActivity = 13, + DiscordResult_InvalidInvite = 14, + DiscordResult_NotAuthenticated = 15, + DiscordResult_InvalidAccessToken = 16, + DiscordResult_ApplicationMismatch = 17, + DiscordResult_InvalidDataUrl = 18, + DiscordResult_InvalidBase64 = 19, + DiscordResult_NotFiltered = 20, + DiscordResult_LobbyFull = 21, + DiscordResult_InvalidLobbySecret = 22, + DiscordResult_InvalidFilename = 23, + DiscordResult_InvalidFileSize = 24, + DiscordResult_InvalidEntitlement = 25, + DiscordResult_NotInstalled = 26, + DiscordResult_NotRunning = 27, + DiscordResult_InsufficientBuffer = 28, + DiscordResult_PurchaseCanceled = 29, + DiscordResult_InvalidGuild = 30, + DiscordResult_InvalidEvent = 31, + DiscordResult_InvalidChannel = 32, + DiscordResult_InvalidOrigin = 33, + DiscordResult_RateLimited = 34, + DiscordResult_OAuth2Error = 35, + DiscordResult_SelectChannelTimeout = 36, + DiscordResult_GetGuildTimeout = 37, + DiscordResult_SelectVoiceForceRequired = 38, + DiscordResult_CaptureShortcutAlreadyListening = 39, + DiscordResult_UnauthorizedForAchievement = 40, + DiscordResult_InvalidGiftCode = 41, + DiscordResult_PurchaseError = 42, + DiscordResult_TransactionAborted = 43, +}; + +enum EDiscordCreateFlags { + DiscordCreateFlags_Default = 0, + DiscordCreateFlags_NoRequireDiscord = 1, +}; + +enum EDiscordLogLevel { + DiscordLogLevel_Error = 1, + DiscordLogLevel_Warn, + DiscordLogLevel_Info, + DiscordLogLevel_Debug, +}; + +enum EDiscordUserFlag { + DiscordUserFlag_Partner = 2, + DiscordUserFlag_HypeSquadEvents = 4, + DiscordUserFlag_HypeSquadHouse1 = 64, + DiscordUserFlag_HypeSquadHouse2 = 128, + DiscordUserFlag_HypeSquadHouse3 = 256, +}; + +enum EDiscordPremiumType { + DiscordPremiumType_None = 0, + DiscordPremiumType_Tier1 = 1, + DiscordPremiumType_Tier2 = 2, +}; + +enum EDiscordImageType { + DiscordImageType_User, +}; + +enum EDiscordActivityType { + DiscordActivityType_Playing, + DiscordActivityType_Streaming, + DiscordActivityType_Listening, + DiscordActivityType_Watching, +}; + +enum EDiscordActivityActionType { + DiscordActivityActionType_Join = 1, + DiscordActivityActionType_Spectate, +}; + +enum EDiscordActivityJoinRequestReply { + DiscordActivityJoinRequestReply_No, + DiscordActivityJoinRequestReply_Yes, + DiscordActivityJoinRequestReply_Ignore, +}; + +enum EDiscordStatus { + DiscordStatus_Offline = 0, + DiscordStatus_Online = 1, + DiscordStatus_Idle = 2, + DiscordStatus_DoNotDisturb = 3, +}; + +enum EDiscordRelationshipType { + DiscordRelationshipType_None, + DiscordRelationshipType_Friend, + DiscordRelationshipType_Blocked, + DiscordRelationshipType_PendingIncoming, + DiscordRelationshipType_PendingOutgoing, + DiscordRelationshipType_Implicit, +}; + +enum EDiscordLobbyType { + DiscordLobbyType_Private = 1, + DiscordLobbyType_Public, +}; + +enum EDiscordLobbySearchComparison { + DiscordLobbySearchComparison_LessThanOrEqual = -2, + DiscordLobbySearchComparison_LessThan, + DiscordLobbySearchComparison_Equal, + DiscordLobbySearchComparison_GreaterThan, + DiscordLobbySearchComparison_GreaterThanOrEqual, + DiscordLobbySearchComparison_NotEqual, +}; + +enum EDiscordLobbySearchCast { + DiscordLobbySearchCast_String = 1, + DiscordLobbySearchCast_Number, +}; + +enum EDiscordLobbySearchDistance { + DiscordLobbySearchDistance_Local, + DiscordLobbySearchDistance_Default, + DiscordLobbySearchDistance_Extended, + DiscordLobbySearchDistance_Global, +}; + +enum EDiscordEntitlementType { + DiscordEntitlementType_Purchase = 1, + DiscordEntitlementType_PremiumSubscription, + DiscordEntitlementType_DeveloperGift, + DiscordEntitlementType_TestModePurchase, + DiscordEntitlementType_FreePurchase, + DiscordEntitlementType_UserGift, + DiscordEntitlementType_PremiumPurchase, +}; + +enum EDiscordSkuType { + DiscordSkuType_Application = 1, + DiscordSkuType_DLC, + DiscordSkuType_Consumable, + DiscordSkuType_Bundle, +}; + +enum EDiscordInputModeType { + DiscordInputModeType_VoiceActivity = 0, + DiscordInputModeType_PushToTalk, +}; + +typedef int64_t DiscordClientId; +typedef int32_t DiscordVersion; +typedef int64_t DiscordSnowflake; +typedef int64_t DiscordTimestamp; +typedef DiscordSnowflake DiscordUserId; +typedef char DiscordLocale[128]; +typedef char DiscordBranch[4096]; +typedef DiscordSnowflake DiscordLobbyId; +typedef char DiscordLobbySecret[128]; +typedef char DiscordMetadataKey[256]; +typedef char DiscordMetadataValue[4096]; +typedef uint64_t DiscordNetworkPeerId; +typedef uint8_t DiscordNetworkChannelId; +typedef char DiscordPath[4096]; +typedef char DiscordDateTime[64]; + +struct DiscordUser { + DiscordUserId id; + char username[256]; + char discriminator[8]; + char avatar[128]; + bool bot; +}; + +struct DiscordOAuth2Token { + char access_token[128]; + char scopes[1024]; + DiscordTimestamp expires; +}; + +struct DiscordImageHandle { + enum EDiscordImageType type; + int64_t id; + uint32_t size; +}; + +struct DiscordImageDimensions { + uint32_t width; + uint32_t height; +}; + +struct DiscordActivityTimestamps { + DiscordTimestamp start; + DiscordTimestamp end; +}; + +struct DiscordActivityAssets { + char large_image[128]; + char large_text[128]; + char small_image[128]; + char small_text[128]; +}; + +struct DiscordPartySize { + int32_t current_size; + int32_t max_size; +}; + +struct DiscordActivityParty { + char id[128]; + struct DiscordPartySize size; +}; + +struct DiscordActivitySecrets { + char match[128]; + char join[128]; + char spectate[128]; +}; + +struct DiscordActivity { + enum EDiscordActivityType type; + int64_t application_id; + char name[128]; + char state[128]; + char details[128]; + struct DiscordActivityTimestamps timestamps; + struct DiscordActivityAssets assets; + struct DiscordActivityParty party; + struct DiscordActivitySecrets secrets; + bool instance; +}; + +struct DiscordPresence { + enum EDiscordStatus status; + struct DiscordActivity activity; +}; + +struct DiscordRelationship { + enum EDiscordRelationshipType type; + struct DiscordUser user; + struct DiscordPresence presence; +}; + +struct DiscordLobby { + DiscordLobbyId id; + enum EDiscordLobbyType type; + DiscordUserId owner_id; + DiscordLobbySecret secret; + uint32_t capacity; + bool locked; +}; + +struct DiscordFileStat { + char filename[260]; + uint64_t size; + uint64_t last_modified; +}; + +struct DiscordEntitlement { + DiscordSnowflake id; + enum EDiscordEntitlementType type; + DiscordSnowflake sku_id; +}; + +struct DiscordSkuPrice { + uint32_t amount; + char currency[16]; +}; + +struct DiscordSku { + DiscordSnowflake id; + enum EDiscordSkuType type; + char name[256]; + struct DiscordSkuPrice price; +}; + +struct DiscordInputMode { + enum EDiscordInputModeType type; + char shortcut[256]; +}; + +struct DiscordUserAchievement { + DiscordSnowflake user_id; + DiscordSnowflake achievement_id; + uint8_t percent_complete; + DiscordDateTime unlocked_at; +}; + +struct IDiscordLobbyTransaction { + enum EDiscordResult (*set_type)(struct IDiscordLobbyTransaction* lobby_transaction, enum EDiscordLobbyType type); + enum EDiscordResult (*set_owner)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordUserId owner_id); + enum EDiscordResult (*set_capacity)(struct IDiscordLobbyTransaction* lobby_transaction, uint32_t capacity); + enum EDiscordResult (*set_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key, DiscordMetadataValue value); + enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key); + enum EDiscordResult (*set_locked)(struct IDiscordLobbyTransaction* lobby_transaction, bool locked); +}; + +struct IDiscordLobbyMemberTransaction { + enum EDiscordResult (*set_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key, DiscordMetadataValue value); + enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key); +}; + +struct IDiscordLobbySearchQuery { + enum EDiscordResult (*filter)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchComparison comparison, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value); + enum EDiscordResult (*sort)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value); + enum EDiscordResult (*limit)(struct IDiscordLobbySearchQuery* lobby_search_query, uint32_t limit); + enum EDiscordResult (*distance)(struct IDiscordLobbySearchQuery* lobby_search_query, enum EDiscordLobbySearchDistance distance); +}; + +typedef void* IDiscordApplicationEvents; + +struct IDiscordApplicationManager { + void (*validate_or_exit)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*get_current_locale)(struct IDiscordApplicationManager* manager, DiscordLocale* locale); + void (*get_current_branch)(struct IDiscordApplicationManager* manager, DiscordBranch* branch); + void (*get_oauth2_token)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordOAuth2Token* oauth2_token)); + void (*get_ticket)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, const char* data)); +}; + +struct IDiscordUserEvents { + void (*on_current_user_update)(void* event_data); +}; + +struct IDiscordUserManager { + enum EDiscordResult (*get_current_user)(struct IDiscordUserManager* manager, struct DiscordUser* current_user); + void (*get_user)(struct IDiscordUserManager* manager, DiscordUserId user_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordUser* user)); + enum EDiscordResult (*get_current_user_premium_type)(struct IDiscordUserManager* manager, enum EDiscordPremiumType* premium_type); + enum EDiscordResult (*current_user_has_flag)(struct IDiscordUserManager* manager, enum EDiscordUserFlag flag, bool* has_flag); +}; + +typedef void* IDiscordImageEvents; + +struct IDiscordImageManager { + void (*fetch)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, bool refresh, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordImageHandle handle_result)); + enum EDiscordResult (*get_dimensions)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, struct DiscordImageDimensions* dimensions); + enum EDiscordResult (*get_data)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, uint8_t* data, uint32_t data_length); +}; + +struct IDiscordActivityEvents { + void (*on_activity_join)(void* event_data, const char* secret); + void (*on_activity_spectate)(void* event_data, const char* secret); + void (*on_activity_join_request)(void* event_data, struct DiscordUser* user); + void (*on_activity_invite)(void* event_data, enum EDiscordActivityActionType type, struct DiscordUser* user, struct DiscordActivity* activity); +}; + +struct IDiscordActivityManager { + enum EDiscordResult (*register_command)(struct IDiscordActivityManager* manager, const char* command); + enum EDiscordResult (*register_steam)(struct IDiscordActivityManager* manager, uint32_t steam_id); + void (*update_activity)(struct IDiscordActivityManager* manager, struct DiscordActivity* activity, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*clear_activity)(struct IDiscordActivityManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*send_request_reply)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityJoinRequestReply reply, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*send_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityActionType type, const char* content, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*accept_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); +}; + +struct IDiscordRelationshipEvents { + void (*on_refresh)(void* event_data); + void (*on_relationship_update)(void* event_data, struct DiscordRelationship* relationship); +}; + +struct IDiscordRelationshipManager { + void (*filter)(struct IDiscordRelationshipManager* manager, void* filter_data, bool (*filter)(void* filter_data, struct DiscordRelationship* relationship)); + enum EDiscordResult (*count)(struct IDiscordRelationshipManager* manager, int32_t* count); + enum EDiscordResult (*get)(struct IDiscordRelationshipManager* manager, DiscordUserId user_id, struct DiscordRelationship* relationship); + enum EDiscordResult (*get_at)(struct IDiscordRelationshipManager* manager, uint32_t index, struct DiscordRelationship* relationship); +}; + +struct IDiscordLobbyEvents { + void (*on_lobby_update)(void* event_data, int64_t lobby_id); + void (*on_lobby_delete)(void* event_data, int64_t lobby_id, uint32_t reason); + void (*on_member_connect)(void* event_data, int64_t lobby_id, int64_t user_id); + void (*on_member_update)(void* event_data, int64_t lobby_id, int64_t user_id); + void (*on_member_disconnect)(void* event_data, int64_t lobby_id, int64_t user_id); + void (*on_lobby_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t* data, uint32_t data_length); + void (*on_speaking)(void* event_data, int64_t lobby_id, int64_t user_id, bool speaking); + void (*on_network_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length); +}; + +struct IDiscordLobbyManager { + enum EDiscordResult (*get_lobby_create_transaction)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult (*get_lobby_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult (*get_member_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction** transaction); + void (*create_lobby)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); + void (*update_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*delete_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*connect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret secret, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); + void (*connect_lobby_with_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbySecret activity_secret, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); + void (*disconnect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*get_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct DiscordLobby* lobby); + enum EDiscordResult (*get_lobby_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret* secret); + enum EDiscordResult (*get_lobby_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordMetadataKey key, DiscordMetadataValue* value); + enum EDiscordResult (*get_lobby_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordMetadataKey* key); + enum EDiscordResult (*lobby_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count); + enum EDiscordResult (*member_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count); + enum EDiscordResult (*get_member_user_id)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordUserId* user_id); + enum EDiscordResult (*get_member_user)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct DiscordUser* user); + enum EDiscordResult (*get_member_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, DiscordMetadataKey key, DiscordMetadataValue* value); + enum EDiscordResult (*get_member_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t index, DiscordMetadataKey* key); + enum EDiscordResult (*member_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t* count); + void (*update_member)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*send_lobby_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t* data, uint32_t data_length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*get_search_query)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery** query); + void (*search)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery* query, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*lobby_count)(struct IDiscordLobbyManager* manager, int32_t* count); + enum EDiscordResult (*get_lobby_id)(struct IDiscordLobbyManager* manager, int32_t index, DiscordLobbyId* lobby_id); + void (*connect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*disconnect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*connect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id); + enum EDiscordResult (*disconnect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id); + enum EDiscordResult (*flush_network)(struct IDiscordLobbyManager* manager); + enum EDiscordResult (*open_network_channel)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t channel_id, bool reliable); + enum EDiscordResult (*send_network_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length); +}; + +struct IDiscordNetworkEvents { + void (*on_message)(void* event_data, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length); + void (*on_route_update)(void* event_data, const char* route_data); +}; + +struct IDiscordNetworkManager { + /** + * Get the local peer ID for this process. + */ + void (*get_peer_id)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId* peer_id); + /** + * Send pending network messages. + */ + enum EDiscordResult (*flush)(struct IDiscordNetworkManager* manager); + /** + * Open a connection to a remote peer. + */ + enum EDiscordResult (*open_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data); + /** + * Update the route data for a connected peer. + */ + enum EDiscordResult (*update_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data); + /** + * Close the connection to a remote peer. + */ + enum EDiscordResult (*close_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id); + /** + * Open a message channel to a connected peer. + */ + enum EDiscordResult (*open_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, bool reliable); + /** + * Close a message channel to a connected peer. + */ + enum EDiscordResult (*close_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id); + /** + * Send a message to a connected peer over an opened message channel. + */ + enum EDiscordResult (*send_message)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length); +}; + +struct IDiscordOverlayEvents { + void (*on_toggle)(void* event_data, bool locked); +}; + +struct IDiscordOverlayManager { + void (*is_enabled)(struct IDiscordOverlayManager* manager, bool* enabled); + void (*is_locked)(struct IDiscordOverlayManager* manager, bool* locked); + void (*set_locked)(struct IDiscordOverlayManager* manager, bool locked, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*open_activity_invite)(struct IDiscordOverlayManager* manager, enum EDiscordActivityActionType type, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*open_guild_invite)(struct IDiscordOverlayManager* manager, const char* code, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*open_voice_settings)(struct IDiscordOverlayManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); +}; + +typedef void* IDiscordStorageEvents; + +struct IDiscordStorageManager { + enum EDiscordResult (*read)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, uint32_t* read); + void (*read_async)(struct IDiscordStorageManager* manager, const char* name, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length)); + void (*read_async_partial)(struct IDiscordStorageManager* manager, const char* name, uint64_t offset, uint64_t length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length)); + enum EDiscordResult (*write)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length); + void (*write_async)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*delete_)(struct IDiscordStorageManager* manager, const char* name); + enum EDiscordResult (*exists)(struct IDiscordStorageManager* manager, const char* name, bool* exists); + void (*count)(struct IDiscordStorageManager* manager, int32_t* count); + enum EDiscordResult (*stat)(struct IDiscordStorageManager* manager, const char* name, struct DiscordFileStat* stat); + enum EDiscordResult (*stat_at)(struct IDiscordStorageManager* manager, int32_t index, struct DiscordFileStat* stat); + enum EDiscordResult (*get_path)(struct IDiscordStorageManager* manager, DiscordPath* path); +}; + +struct IDiscordStoreEvents { + void (*on_entitlement_create)(void* event_data, struct DiscordEntitlement* entitlement); + void (*on_entitlement_delete)(void* event_data, struct DiscordEntitlement* entitlement); +}; + +struct IDiscordStoreManager { + void (*fetch_skus)(struct IDiscordStoreManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*count_skus)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult (*get_sku)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, struct DiscordSku* sku); + enum EDiscordResult (*get_sku_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordSku* sku); + void (*fetch_entitlements)(struct IDiscordStoreManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*count_entitlements)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult (*get_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake entitlement_id, struct DiscordEntitlement* entitlement); + enum EDiscordResult (*get_entitlement_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordEntitlement* entitlement); + enum EDiscordResult (*has_sku_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, bool* has_entitlement); + void (*start_purchase)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); +}; + +struct IDiscordVoiceEvents { + void (*on_settings_update)(void* event_data); +}; + +struct IDiscordVoiceManager { + enum EDiscordResult (*get_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode* input_mode); + void (*set_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode input_mode, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*is_self_mute)(struct IDiscordVoiceManager* manager, bool* mute); + enum EDiscordResult (*set_self_mute)(struct IDiscordVoiceManager* manager, bool mute); + enum EDiscordResult (*is_self_deaf)(struct IDiscordVoiceManager* manager, bool* deaf); + enum EDiscordResult (*set_self_deaf)(struct IDiscordVoiceManager* manager, bool deaf); + enum EDiscordResult (*is_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool* mute); + enum EDiscordResult (*set_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool mute); + enum EDiscordResult (*get_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t* volume); + enum EDiscordResult (*set_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t volume); +}; + +struct IDiscordAchievementEvents { + void (*on_user_achievement_update)(void* event_data, struct DiscordUserAchievement* user_achievement); +}; + +struct IDiscordAchievementManager { + void (*set_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake achievement_id, uint8_t percent_complete, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*fetch_user_achievements)(struct IDiscordAchievementManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*count_user_achievements)(struct IDiscordAchievementManager* manager, int32_t* count); + enum EDiscordResult (*get_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake user_achievement_id, struct DiscordUserAchievement* user_achievement); + enum EDiscordResult (*get_user_achievement_at)(struct IDiscordAchievementManager* manager, int32_t index, struct DiscordUserAchievement* user_achievement); +}; + +typedef void* IDiscordCoreEvents; + +struct IDiscordCore { + void (*destroy)(struct IDiscordCore* core); + enum EDiscordResult (*run_callbacks)(struct IDiscordCore* core); + void (*set_log_hook)(struct IDiscordCore* core, enum EDiscordLogLevel min_level, void* hook_data, void (*hook)(void* hook_data, enum EDiscordLogLevel level, const char* message)); + struct IDiscordApplicationManager* (*get_application_manager)(struct IDiscordCore* core); + struct IDiscordUserManager* (*get_user_manager)(struct IDiscordCore* core); + struct IDiscordImageManager* (*get_image_manager)(struct IDiscordCore* core); + struct IDiscordActivityManager* (*get_activity_manager)(struct IDiscordCore* core); + struct IDiscordRelationshipManager* (*get_relationship_manager)(struct IDiscordCore* core); + struct IDiscordLobbyManager* (*get_lobby_manager)(struct IDiscordCore* core); + struct IDiscordNetworkManager* (*get_network_manager)(struct IDiscordCore* core); + struct IDiscordOverlayManager* (*get_overlay_manager)(struct IDiscordCore* core); + struct IDiscordStorageManager* (*get_storage_manager)(struct IDiscordCore* core); + struct IDiscordStoreManager* (*get_store_manager)(struct IDiscordCore* core); + struct IDiscordVoiceManager* (*get_voice_manager)(struct IDiscordCore* core); + struct IDiscordAchievementManager* (*get_achievement_manager)(struct IDiscordCore* core); +}; + +struct DiscordCreateParams { + DiscordClientId client_id; + uint64_t flags; + IDiscordCoreEvents* events; + void* event_data; + IDiscordApplicationEvents* application_events; + DiscordVersion application_version; + struct IDiscordUserEvents* user_events; + DiscordVersion user_version; + IDiscordImageEvents* image_events; + DiscordVersion image_version; + struct IDiscordActivityEvents* activity_events; + DiscordVersion activity_version; + struct IDiscordRelationshipEvents* relationship_events; + DiscordVersion relationship_version; + struct IDiscordLobbyEvents* lobby_events; + DiscordVersion lobby_version; + struct IDiscordNetworkEvents* network_events; + DiscordVersion network_version; + struct IDiscordOverlayEvents* overlay_events; + DiscordVersion overlay_version; + IDiscordStorageEvents* storage_events; + DiscordVersion storage_version; + struct IDiscordStoreEvents* store_events; + DiscordVersion store_version; + struct IDiscordVoiceEvents* voice_events; + DiscordVersion voice_version; + struct IDiscordAchievementEvents* achievement_events; + DiscordVersion achievement_version; +}; + +#ifdef __cplusplus +inline +#else +static +#endif +void DiscordCreateParamsSetDefault(struct DiscordCreateParams* params) +{ + memset(params, 0, sizeof(struct DiscordCreateParams)); + params->application_version = DISCORD_APPLICATION_MANAGER_VERSION; + params->user_version = DISCORD_USER_MANAGER_VERSION; + params->image_version = DISCORD_IMAGE_MANAGER_VERSION; + params->activity_version = DISCORD_ACTIVITY_MANAGER_VERSION; + params->relationship_version = DISCORD_RELATIONSHIP_MANAGER_VERSION; + params->lobby_version = DISCORD_LOBBY_MANAGER_VERSION; + params->network_version = DISCORD_NETWORK_MANAGER_VERSION; + params->overlay_version = DISCORD_OVERLAY_MANAGER_VERSION; + params->storage_version = DISCORD_STORAGE_MANAGER_VERSION; + params->store_version = DISCORD_STORE_MANAGER_VERSION; + params->voice_version = DISCORD_VOICE_MANAGER_VERSION; + params->achievement_version = DISCORD_ACHIEVEMENT_MANAGER_VERSION; +} + +enum EDiscordResult DiscordCreate(DiscordVersion version, struct DiscordCreateParams* params, struct IDiscordCore** result); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/pc/network/discord/discord_network.c b/src/pc/network/discord/discord_network.c new file mode 100644 index 00000000..a2eead7f --- /dev/null +++ b/src/pc/network/discord/discord_network.c @@ -0,0 +1,39 @@ +#include "discord_network.h" +#include "lobby.h" +#include "pc/debuglog.h" + +int ns_discord_network_send(u8* data, u16 dataLength) { + if (!gDiscordInitialized) { return 1; } + if (gCurLobbyId == 0) { return 2; } + int32_t memberCount = 0; + DISCORD_REQUIRE(app.lobbies->member_count(app.lobbies, gCurLobbyId, &memberCount)); + if (memberCount <= 1) { return 3; } + + for (int i = 0; i < memberCount; i++) { + DiscordUserId userId; + DISCORD_REQUIRE(app.lobbies->get_member_user_id(app.lobbies, gCurLobbyId, i, &userId)); + if (userId == app.userId) { continue; } + DISCORD_REQUIRE(app.lobbies->send_network_message(app.lobbies, gCurLobbyId, userId, 0, data, dataLength)); + } + return 0; +} + +void discord_network_on_message(UNUSED void* eventData, int64_t lobbyId, int64_t userId, uint8_t channelId, uint8_t* data, uint32_t dataLength) { + network_receive((u8*)data, (u16)dataLength); +} + +void discord_network_flush(void) { + app.lobbies->flush_network(app.lobbies); +} + +void discord_network_init(int64_t lobbyId) { + DISCORD_REQUIRE(app.lobbies->connect_network(app.lobbies, lobbyId)); + DISCORD_REQUIRE(app.lobbies->open_network_channel(app.lobbies, lobbyId, 0, false)); +} + +void discord_network_shutdown(void) { + app.lobbies->flush_network(app.lobbies); + if (gCurLobbyId == 0) { return; } + app.lobbies->disconnect_network(app.lobbies, gCurLobbyId); + LOG_INFO("shutdown network, lobby = %lld", gCurLobbyId); +} \ No newline at end of file diff --git a/src/pc/network/discord/discord_network.h b/src/pc/network/discord/discord_network.h new file mode 100644 index 00000000..582e1195 --- /dev/null +++ b/src/pc/network/discord/discord_network.h @@ -0,0 +1,11 @@ +#ifndef DISCORD_NETWORK_H +#define DISCORD_NETWORK_H +#include "discord.h" + +int ns_discord_network_send(u8* data, u16 dataLength); +void discord_network_on_message(UNUSED void* eventData, int64_t lobbyId, int64_t userId, uint8_t channelId, uint8_t* data, uint32_t dataLength); +void discord_network_flush(void); +void discord_network_init(int64_t lobbyId); +void discord_network_shutdown(void); + +#endif \ No newline at end of file diff --git a/src/pc/network/discord/lobby.c b/src/pc/network/discord/lobby.c new file mode 100644 index 00000000..e2949a11 --- /dev/null +++ b/src/pc/network/discord/lobby.c @@ -0,0 +1,93 @@ +#include "lobby.h" +#include "activity.h" +#include "discord_network.h" +#include "pc/debuglog.h" + +static bool isHosting = false; +DiscordLobbyId gCurLobbyId = 0; + +static void on_lobby_create_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordLobby* lobby) { + LOG_INFO("> on_lobby_update returned %d\n", (int)result); + LOG_INFO("Lobby id: %lld\n", lobby->id); + LOG_INFO("Lobby type: %u\n", lobby->type); + LOG_INFO("Lobby owner id: %lld\n", lobby->owner_id); + LOG_INFO("Lobby secret: %s\n", lobby->secret); + LOG_INFO("Lobby capacity: %u\n", lobby->capacity); + LOG_INFO("Lobby locked: %d\n", lobby->locked); + + gCurActivity.type = DiscordActivityType_Playing; + snprintf(gCurActivity.party.id, 128, "%lld", lobby->id); + gCurActivity.party.size.current_size = 1; + gCurActivity.party.size.max_size = 2; + + char secretJoin[128] = ""; + snprintf(secretJoin, 128, "%lld:%s", lobby->id, lobby->secret); + strcpy(gCurActivity.secrets.join, secretJoin); + + isHosting = true; + gCurLobbyId = lobby->id; + + discord_network_init(lobby->id); + discord_activity_update(true); +} + +static void on_lobby_update(UNUSED void* data, int64_t lobbyId) { + LOG_INFO("> on_lobby_update id: %lld", lobbyId); +} + +static void on_member_connect(UNUSED void* data, int64_t lobbyId, int64_t userId) { + LOG_INFO("> on_member_connect lobby: %lld, user: %lld", lobbyId, userId); + gCurActivity.party.size.current_size++; + discord_activity_update(true); +} + +static void on_member_update(UNUSED void* data, int64_t lobbyId, int64_t userId) { + LOG_INFO("> on_member_update lobby: %lld, user: %lld", lobbyId, userId); +} + +static void on_member_disconnect(UNUSED void* data, int64_t lobbyId, int64_t userId) { + LOG_INFO("> on_member_disconnect lobby: %lld, user: %lld", lobbyId, userId); + gCurActivity.party.size.current_size--; + discord_activity_update(isHosting); +} + +void discord_lobby_create(void) { + struct IDiscordLobbyTransaction* txn = { 0 }; + + DISCORD_REQUIRE(app.lobbies->get_lobby_create_transaction(app.lobbies, &txn)); + txn->set_capacity(txn, 2); + txn->set_type(txn, DiscordLobbyType_Public); + //txn->set_metadata(txn, "a", "123"); + + app.lobbies->create_lobby(app.lobbies, txn, NULL, on_lobby_create_callback); +} + +static void on_lobby_leave_callback(UNUSED void* data, enum EDiscordResult result) { + LOG_INFO("> on_lobby_leave returned %d", result); +} + +void discord_lobby_leave(void) { + if (gCurLobbyId == 0) { return; } + + discord_network_shutdown(); + if (isHosting) { + app.lobbies->delete_lobby(app.lobbies, gCurLobbyId, NULL, on_lobby_leave_callback); + } else { + app.lobbies->disconnect_lobby(app.lobbies, gCurLobbyId, NULL, on_lobby_leave_callback); + } + + LOG_INFO("left lobby %lld", gCurLobbyId); + + isHosting = false; + gCurLobbyId = 0; +} + +struct IDiscordLobbyEvents* discord_lobby_initialize(void) { + static struct IDiscordLobbyEvents events = { 0 }; + events.on_lobby_update = on_lobby_update; + events.on_member_connect = on_member_connect; + events.on_member_update = on_member_update; + events.on_member_disconnect = on_member_disconnect; + events.on_network_message = discord_network_on_message; + return &events; +} \ No newline at end of file diff --git a/src/pc/network/discord/lobby.h b/src/pc/network/discord/lobby.h new file mode 100644 index 00000000..3dec9a3d --- /dev/null +++ b/src/pc/network/discord/lobby.h @@ -0,0 +1,11 @@ +#ifndef DISCORD_LOBBY_H +#define DISCORD_LOBBY_H +#include "discord.h" + +extern DiscordLobbyId gCurLobbyId; + +void discord_lobby_create(void); +void discord_lobby_leave(void); +struct IDiscordLobbyEvents* discord_lobby_initialize(void); + +#endif \ No newline at end of file diff --git a/src/pc/network/discord/user.c b/src/pc/network/discord/user.c new file mode 100644 index 00000000..f06cf3b2 --- /dev/null +++ b/src/pc/network/discord/user.c @@ -0,0 +1,15 @@ +#include "user.h" +#include "pc/debuglog.h" + +static void on_current_user_update(UNUSED void* data) { + LOG_INFO("> on_current_user_update"); + struct DiscordUser user; + app.users->get_current_user(app.users, &user); + app.userId = user.id; +} + +struct IDiscordUserEvents* discord_user_initialize(void) { + static struct IDiscordUserEvents events = { 0 }; + events.on_current_user_update = on_current_user_update; + return &events; +} \ No newline at end of file diff --git a/src/pc/network/discord/user.h b/src/pc/network/discord/user.h new file mode 100644 index 00000000..a3089192 --- /dev/null +++ b/src/pc/network/discord/user.h @@ -0,0 +1,7 @@ +#ifndef DISCORD_USER_H +#define DISCORD_USER_H +#include "discord.h" + +struct IDiscordUserEvents* discord_user_initialize(void); + +#endif \ No newline at end of file diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 5a0da0d0..6f5fbad8 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -3,6 +3,7 @@ #include "object_fields.h" #include "object_constants.h" #include "socket/socket.h" +#include "discord/discord.h" #include "pc/configfile.h" #include "pc/debuglog.h" @@ -10,7 +11,7 @@ extern s16 sCurrPlayMode; enum NetworkType gNetworkType = NT_NONE; -struct NetworkSystem* gNetworkSystem = &gNetworkSystemSocket; +struct NetworkSystem* gNetworkSystem = &gNetworkSystemDiscord; #define LOADING_LEVEL_THRESHOLD 10 u8 networkLoadingLevel = 0; @@ -21,6 +22,15 @@ struct ServerSettings gServerSettings = { .playerKnockbackStrength = 25, }; + +void network_set_system(enum NetworkSystemType nsType) { + switch (nsType) { + case NS_SOCKET: gNetworkSystem = &gNetworkSystemSocket; break; + case NS_DISCORD: gNetworkSystem = &gNetworkSystemDiscord; break; + default: LOG_ERROR("Unknown network system: %d", nsType); + } +} + bool network_init(enum NetworkType inNetworkType) { // sanity check network system if (gNetworkSystem == NULL) { @@ -28,6 +38,11 @@ bool network_init(enum NetworkType inNetworkType) { return false; } + // set server settings + gServerSettings.playerInteractions = configPlayerInteraction; + gServerSettings.playerKnockbackStrength = configPlayerKnockbackStrength; + gServerSettings.stayInLevelAfterStar = configStayInLevelAfterStar; + // initialize the network system int rc = gNetworkSystem->initialize(inNetworkType); if (!rc) { @@ -38,26 +53,15 @@ bool network_init(enum NetworkType inNetworkType) { // set network type gNetworkType = inNetworkType; - // set server settings - if (gNetworkType == NT_SERVER) { - gServerSettings.playerInteractions = configPlayerInteraction; - gServerSettings.playerKnockbackStrength = configPlayerKnockbackStrength; - gServerSettings.stayInLevelAfterStar = configStayInLevelAfterStar; - } - - // exit early if we're not really initializing the network - if (gNetworkType == NT_NONE) { - return true; - } - - // send connection request - if (gNetworkType == NT_CLIENT) { - network_send_save_file_request(); - } + LOG_INFO("initialized"); return true; } +void network_on_joined(void) { + network_send_save_file_request(); +} + void network_on_init_level(void) { // reset loading timer networkLoadingLevel = 0; @@ -131,7 +135,6 @@ void network_receive(u8* data, u16 dataLength) { } void network_update(void) { - if (gNetworkType == NT_NONE) { return; } // check for level loaded event if (!gNetworkLevelLoaded) { @@ -141,10 +144,12 @@ void network_update(void) { } } - // figure out which update loop to run - if (sCurrPlayMode == PLAY_MODE_NORMAL || sCurrPlayMode == PLAY_MODE_PAUSED) { - network_update_player(); - network_update_objects(); + // send out update packets + if (gNetworkType != NT_NONE) { + if (sCurrPlayMode == PLAY_MODE_NORMAL || sCurrPlayMode == PLAY_MODE_PAUSED) { + network_update_player(); + network_update_objects(); + } } // receive packets @@ -153,13 +158,16 @@ void network_update(void) { } // update reliable packets - network_update_reliable(); + if (gNetworkType != NT_NONE) { + network_update_reliable(); + } } void network_shutdown(void) { if (gNetworkType == NT_NONE) { return; } - gNetworkType = NT_NONE; if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); return; } gNetworkSystem->shutdown(); + + gNetworkType = NT_NONE; } diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 16972fee..2fc84107 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -16,7 +16,14 @@ extern struct MarioState gMarioStates[]; #define MAX_SYNC_OBJECTS 256 // note: increasing this requires code to be rewritten #define MAX_SYNC_OBJECT_FIELDS 64 #define PACKET_LENGTH 1024 -#define NETWORKTYPESTR (gNetworkType == NT_CLIENT ? "Client" : "Server") +#define NETWORKTYPESTR (gNetworkType == NT_CLIENT \ + ? "Client" \ + : (gNetworkType == NT_SERVER ? "Server" : " None ")) \ + +enum NetworkSystemType { + NS_SOCKET, + NS_DISCORD, +}; struct NetworkSystem { bool (*initialize)(enum NetworkType); @@ -92,11 +99,13 @@ extern struct SyncObject gSyncObjects[]; extern struct ServerSettings gServerSettings; // network.c +void network_set_system(enum NetworkSystemType nsType); bool network_init(enum NetworkType inNetworkType); void network_on_init_level(void); void network_on_loaded_level(void); void network_send(struct Packet* p); void network_receive(u8* data, u16 dataLength); +void network_on_joined(void); void network_update(void); void network_shutdown(void); diff --git a/src/pc/network/socket/socket.c b/src/pc/network/socket/socket.c index d3382772..5421096e 100644 --- a/src/pc/network/socket/socket.c +++ b/src/pc/network/socket/socket.c @@ -2,6 +2,7 @@ #include "socket.h" #include "pc/configfile.h" #include "pc/debuglog.h" +#include "menu/file_select.h" static SOCKET curSocket = INVALID_SOCKET; struct sockaddr_in txAddr = { 0 }; @@ -70,6 +71,16 @@ static bool ns_socket_initialize(enum NetworkType networkType) { LOG_INFO("connecting to %s %u", configJoinIp, port); } + // kick off first packet + if (networkType == NT_CLIENT) { + char joinText[128] = { 0 }; + snprintf(joinText, 63, "%s %d", configJoinIp, configJoinPort); + open_join_menu(joinText); + + gNetworkType = NT_CLIENT; + network_on_joined(); + } + LOG_INFO("initialized"); // success diff --git a/src/pc/network/socket/socket_windows.h b/src/pc/network/socket/socket_windows.h index 4fd8f4a1..50dad0cf 100644 --- a/src/pc/network/socket/socket_windows.h +++ b/src/pc/network/socket/socket_windows.h @@ -3,7 +3,6 @@ #include #include -#include "socket.h" #define SOCKET_LAST_ERROR WSAGetLastError() #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index fc99f4f5..c5a252ba 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -262,12 +262,16 @@ void main_func(void) { } if (gCLIOpts.Network == NT_CLIENT) { + network_set_system(NS_SOCKET); strncpy(configJoinIp, gCLIOpts.JoinIp, IP_MAX_LEN); configJoinPort = gCLIOpts.NetworkPort; network_init(NT_CLIENT); } else if (gCLIOpts.Network == NT_SERVER) { + network_set_system(NS_SOCKET); configHostPort = gCLIOpts.NetworkPort; network_init(NT_SERVER); + } else { + network_init(NT_NONE); } audio_init();