Ripped out discord network system, started re-adding invites

This commit is contained in:
MysterD 2023-04-15 19:53:34 -07:00
parent 8e2cd25617
commit 4566b7ee14
49 changed files with 525 additions and 1248 deletions

View file

@ -48,9 +48,7 @@ EXT_OPTIONS_MENU ?= 1
TEXTSAVES ?= 0
# Load resources from external files
EXTERNAL_DATA ?= 0
# Enable Discord Rich Presence (outdated, no longer supported)
DISCORDRPC ?= 0
# Enable Discord Game SDK (used for Discord server hosting)
# Enable Discord Game SDK (used for Discord invites)
DISCORD_SDK ?= 1
# Enable CoopNet SDK (used for CoopNet server hosting)
COOPNET ?= 1
@ -530,12 +528,8 @@ BIN_DIRS := bin bin/$(VERSION)
# PC files
SRC_DIRS += src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes src/pc/mods src/pc/network src/pc/network/packets src/pc/network/socket src/pc/network/coopnet src/pc/utils src/pc/utils/miniz src/pc/djui src/pc/lua src/pc/lua/utils
#ifeq ($(DISCORDRPC),1)
# SRC_DIRS += src/pc/discord
#endif
ifeq ($(DISCORD_SDK),1)
SRC_DIRS += src/pc/network/discord
SRC_DIRS += src/pc/discord
endif
ULTRA_SRC_DIRS := lib/src lib/src/math lib/asm lib/data
@ -607,18 +601,8 @@ ULTRA_O_FILES := $(foreach file,$(ULTRA_S_FILES),$(BUILD_DIR)/$(file:.s=.o)) \
GODDARD_O_FILES := $(foreach file,$(GODDARD_C_FILES),$(BUILD_DIR)/$(file:.c=.o))
RPC_LIBS :=
#ifeq ($(DISCORDRPC),1)
# ifeq ($(WINDOWS_BUILD),1)
# RPC_LIBS := lib/discord/libdiscord-rpc.dll
# else ifeq ($(OSX_BUILD),1)
# # needs testing
# RPC_LIBS := lib/discord/libdiscord-rpc.dylib
# else
# RPC_LIBS := lib/discord/libdiscord-rpc.so
# endif
#endif
DISCORD_SDK_LIBS :=
ifeq ($(DISCORD_SDK), 1)
ifeq ($(WINDOWS_BUILD),1)
ifeq ($(TARGET_BITS), 32)
@ -758,7 +742,6 @@ else
CP := cp
endif
#ifeq ($(DISCORDRPC),1)
ifeq ($(DISCORD_SDK),1)
LD := $(CXX)
else ifeq ($(WINDOWS_BUILD),1)
@ -923,9 +906,6 @@ else ifeq ($(OSX_BUILD),1)
LDFLAGS := -lm $(BACKEND_LDFLAGS) -lpthread
else
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -no-pie -lpthread
# ifeq ($(DISCORDRPC),1)
# LDFLAGS += -ldl -Wl,-rpath .
# endif
endif
# icon
@ -1080,12 +1060,6 @@ endif
CFLAGS += -DNODRAWINGDISTANCE
#endif
# Check for Discord Rich Presence option
#ifeq ($(DISCORDRPC),1)
# CC_CHECK_CFLAGS += -DDISCORDRPC
# CFLAGS += -DDISCORDRPC
#endif
# Check for Discord SDK option
ifeq ($(DISCORD_SDK),1)
CC_CHECK_CFLAGS += -DDISCORD_SDK

View file

@ -47,6 +47,7 @@ in_files = [
"src/pc/lua/utils/smlua_text_utils.h",
"src/pc/lua/utils/smlua_audio_utils.h",
"src/pc/lua/utils/smlua_level_utils.h",
"src/pc/lua/utils/smlua_deprecated.h",
"src/game/object_helpers.c",
"src/game/obj_behaviors.c",
"src/game/obj_behaviors_2.c",
@ -106,6 +107,10 @@ override_disallowed_functions = {
"src/pc/network/lag_compensation.h": [ "lag_compensation_clear", "lag_compensation_store" ],
}
override_hide_functions = {
"smlua_deprecated.h" : [ ".*" ],
}
lua_function_params = {
"src/pc/lua/utils/smlua_obj_utils.h::spawn_object_sync::objSetupFunction": [ "struct Object*" ]
}
@ -763,6 +768,16 @@ def process_files():
############################################################################
def doc_should_document(fname, identifier):
if fname in override_hide_functions:
found_match = False
for pattern in override_hide_functions[fname]:
if re.search(pattern, identifier) != None:
found_match = True
break
return not found_match
return True
def doc_page_link(page_num):
if page_num == 1:
return 'functions.md'
@ -779,6 +794,9 @@ def doc_function_index(processed_files):
for function in processed_file['functions']:
if not function['implemented']:
continue
if not doc_should_document(processed_file['filename'], function['identifier']):
continue
s += ' - [%s](%s#%s)\n' % (function['identifier'], doc_page_link(page_num), function['identifier'])
s += '\n<br />\n\n'
@ -805,10 +823,13 @@ def doc_lua_func_param(param):
s += ')'
return s
def doc_function(function):
def doc_function(fname, function):
if not function['implemented']:
return ''
if not doc_should_document(fname, function['identifier']):
return ''
fid = function['identifier']
s = '\n## [%s](#%s)\n' % (fid, fid)
@ -860,10 +881,10 @@ def doc_function(function):
return s
def doc_functions(functions):
def doc_functions(fname, functions):
s = ''
for function in functions:
s += doc_function(function)
s += doc_function(fname, function)
return s
def doc_files(processed_files):
@ -879,7 +900,7 @@ def doc_files(processed_files):
for processed_file in processed_files:
s_file = '\n---'
s_file += '\n# functions from %s\n\n<br />\n\n' % processed_file['filename']
s_file += doc_functions(processed_file['functions'])
s_file += doc_functions(processed_file['filename'], processed_file['functions'])
if len(s) + len(s_file) + extra_space > page_len_limit:
s += '---\n\n$[FUNCTION_NAV_HERE]\n\n'

View file

@ -4727,7 +4727,10 @@ SYNC_DISTANCE_INFINITE = 0
NS_SOCKET = 0
--- @type NetworkSystemType
NS_DISCORD = 1
NS_COOPNET = 1
--- @type NetworkSystemType
NS_MAX = 2
--- @class PlayerInteractions
@ -11522,13 +11525,13 @@ MAX_LOCAL_VERSION_LENGTH = 12
MAX_VERSION_LENGTH = 10
--- @type integer
MINOR_VERSION_NUMBER = 1
MINOR_VERSION_NUMBER = 0
--- @type integer
PATCH_VERSION_NUMBER = 0
--- @type integer
VERSION_NUMBER = 33
VERSION_NUMBER = 34
--- @type string
VERSION_TEXT = "beta"

View file

@ -5639,12 +5639,6 @@ function network_player_set_description(np, description, r, g, b, a)
-- ...
end
--- @param localIndex integer
--- @return string
function network_discord_id_from_local_index(localIndex)
-- ...
end
--- @param localIndex integer
--- @return string
function network_get_player_text_color_string(localIndex)
@ -8015,6 +8009,12 @@ function smlua_collision_util_get(name)
-- ...
end
--- @param localIndex integer
--- @return string
function network_discord_id_from_local_index(localIndex)
-- ...
end
--- @param scriptEntryName string
--- @param courseNum integer
--- @param fullName string

View file

@ -1721,6 +1721,7 @@
--- @field public enablePlayerList integer
--- @field public enablePlayersInLevelDisplay integer
--- @field public headlessServer integer
--- @field public maxPlayers integer
--- @field public playerInteractions PlayerInteractions
--- @field public playerKnockbackStrength integer
--- @field public shareLives integer

View file

@ -1690,7 +1690,8 @@
| Identifier | Value |
| :--------- | :---- |
| NS_SOCKET | 0 |
| NS_DISCORD | 1 |
| NS_COOPNET | 1 |
| NS_MAX | 2 |
### [enum PlayerInteractions](#PlayerInteractions)
| Identifier | Value |

View file

@ -8265,26 +8265,6 @@
<br />
## [network_discord_id_from_local_index](#network_discord_id_from_local_index)
### Lua Example
`local stringValue = network_discord_id_from_local_index(localIndex)`
### Parameters
| Field | Type |
| ----- | ---- |
| localIndex | `integer` |
### Returns
- `string`
### C Prototype
`char* network_discord_id_from_local_index(u8 localIndex);`
[:arrow_up_small:](#)
<br />
## [network_get_player_text_color_string](#network_get_player_text_color_string)
### Lua Example

View file

@ -7251,6 +7251,12 @@
<br />
---
# functions from smlua_deprecated.h
<br />
---
# functions from smlua_level_utils.h

View file

@ -1096,7 +1096,6 @@
<br />
- network_utils.h
- [network_discord_id_from_local_index](functions-3.md#network_discord_id_from_local_index)
- [network_get_player_text_color_string](functions-3.md#network_get_player_text_color_string)
- [network_global_index_from_local](functions-3.md#network_global_index_from_local)
- [network_is_moderator](functions-3.md#network_is_moderator)
@ -1490,6 +1489,10 @@
<br />
- smlua_deprecated.h
<br />
- smlua_level_utils.h
- [level_register](functions-4.md#level_register)
- [smlua_level_util_get_info](functions-4.md#smlua_level_util_get_info)

View file

@ -2181,6 +2181,7 @@
| enablePlayerList | `integer` | |
| enablePlayersInLevelDisplay | `integer` | |
| headlessServer | `integer` | |
| maxPlayers | `integer` | |
| playerInteractions | [enum PlayerInteractions](constants.md#enum-PlayerInteractions) | |
| playerKnockbackStrength | `integer` | |
| shareLives | `integer` | |

View file

@ -85,9 +85,6 @@ 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();

View file

@ -22,7 +22,6 @@ struct PCCLIOptions {
char ConfigFile[SYS_MAX_PATH];
char SavePath[SYS_MAX_PATH];
char GameDir[SYS_MAX_PATH];
unsigned int Discord;
};
extern struct PCCLIOptions gCLIOpts;

View file

@ -120,9 +120,6 @@ bool configEnableCheats = 0;
bool configBubbleDeath = true;
unsigned int configAmountofPlayers = 16;
bool configHUD = true;
#ifdef DISCORDRPC
bool configDiscordRPC = true;
#endif
// coop-specific
char configJoinIp[MAX_CONFIG_STRING] = "";
unsigned int configJoinPort = DEFAULT_PORT;
@ -213,9 +210,6 @@ static const struct ConfigOption options[] = {
#endif
{.name = "skip_intro", .type = CONFIG_TYPE_BOOL, .boolValue = &configSkipIntro},
{.name = "enable_cheats", .type = CONFIG_TYPE_BOOL, .boolValue = &configEnableCheats},
#ifdef DISCORDRPC
{.name = "discordrpc_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configDiscordRPC},
#endif
// debug
{.name = "debug_offset", .type = CONFIG_TYPE_U64 , .u64Value = &gPcDebug.bhvOffset},
{.name = "debug_tags", .type = CONFIG_TYPE_U64 , .u64Value = gPcDebug.tags},

View file

@ -80,9 +80,6 @@ extern bool configShareLives;
extern bool configEnableCheats;
extern bool configBubbleDeath;
extern unsigned int configAmountofPlayers;
#ifdef DISCORDRPC
extern bool configDiscordRPC;
#endif
extern char configJoinIp[];
extern unsigned int configJoinPort;
extern unsigned int configHostPort;

159
src/pc/discord/discord.c Normal file
View file

@ -0,0 +1,159 @@
#include "discord.h"
#include "pc/djui/djui.h"
#include "pc/debuglog.h"
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <winuser.h>
#else
#include <unistd.h>
#define MAX_PATH 1024
#endif
#define MAX_LAUNCH_CMD (MAX_PATH + 12)
static int64_t applicationId = 752700005210390568;
struct DiscordApplication app = { 0 };
static bool sFatalShown = false;
static bool sDiscordInitialized = false;
static void discord_sdk_log_callback(UNUSED void* hook_data, enum EDiscordLogLevel level, const char* message) {
LOG_INFO("callback (%d): %s", level, message);
}
void discord_fatal_message(int rc) { // Discord usually does this because of loss of connection to Discord
char errorMessage[132] = { 0 };
snprintf(errorMessage, 132, "%s\nRC: %d", DLANG(NOTIF, DISCORD_ERROR), rc);
djui_popup_create(errorMessage, 6);
}
void discord_fatal(int rc) {
if (!sFatalShown) {
discord_fatal_message(rc);
sFatalShown = true;
}
if (rc != DiscordResult_Ok) {
LOG_ERROR("Discord threw an error. RC: %d", rc);
}
}
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] = { 0 };
int rc;
#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
char path[MAX_LAUNCH_CMD] = { 0 };
snprintf(path, MAX_LAUNCH_CMD - 1, "/proc/%d/exe", getpid());
rc = readlink(path, cmd, MAX_LAUNCH_CMD - 1);
if (rc <= 0) {
LOG_ERROR("unable to retrieve absolute path! rc = %d", rc);
return;
}
#endif
strncat(cmd, " --discord 1", MAX_LAUNCH_CMD - 1);
rc = app.activities->register_command(app.activities, cmd);
if (rc != DiscordResult_Ok) {
LOG_ERROR("register command failed %d", rc);
return;
}
LOG_INFO("cmd: %s", cmd);
}
static void on_current_user_update(UNUSED void* data) {
LOG_INFO("> on_current_user_update");
struct DiscordUser user = { 0 };
app.users->get_current_user(app.users, &user);
// remember user id
app.userId = user.id;
// copy over discord username if we haven't set one yet
if (configPlayerName[0] == '\0' && strlen(user.username) > 0) {
char* cname = configPlayerName;
char* dname = user.username;
for (int i = 0; i < MAX_PLAYER_STRING - 1; i++) {
if (*dname >= '!' && *dname <= '~') {
*cname = *dname;
cname++;
}
dname++;
}
}
}
struct IDiscordUserEvents* discord_user_initialize(void) {
LOG_INFO("> discord_user_intitialize");
static struct IDiscordUserEvents events = { 0 };
events.on_current_user_update = on_current_user_update;
return &events;
}
static void discord_initialize(void) {
if (sDiscordInitialized) { return; }
sDiscordInitialized = true;
if (app.core != NULL) {
app.core->set_log_hook(app.core, DiscordLogLevel_Debug, NULL, discord_sdk_log_callback);
}
// set up discord params
struct DiscordCreateParams params = { 0 };
DiscordCreateParamsSetDefault(&params);
params.client_id = applicationId;
params.flags = DiscordCreateFlags_NoRequireDiscord;
params.event_data = &app;
params.user_events = discord_user_initialize();
params.activity_events = discord_activity_initialize();
int rc = DiscordCreate(DISCORD_VERSION, &params, &app.core);
if (app.core != NULL) {
app.core->set_log_hook(app.core, DiscordLogLevel_Debug, NULL, discord_sdk_log_callback);
}
if (rc) {
LOG_ERROR("DiscordCreate failed: %d", rc);
djui_popup_create(DLANG(NOTIF, DISCORD_DETECT), 3);
return;
}
// set up manager pointers
if (app.core != NULL) {
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);
}
// 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();
LOG_INFO("initialized");
}
void discord_update(void) {
if (!sDiscordInitialized) {
discord_initialize();
}
discord_activity_update_check();
DISCORD_REQUIRE(app.core->run_callbacks(app.core));
}

View file

@ -1,22 +1,14 @@
#ifndef DISCORD_H
#define DISCORD_H
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#pragma pack(push, 8)
#pragma once
#include "PR/ultratypes.h"
#include "discord_game_sdk.h"
#pragma pack(pop)
#ifdef _WIN32
#define DISCORD_ID_FORMAT "%lld"
#include <Windows.h>
#else
#define DISCORD_ID_FORMAT "%ld"
#include <unistd.h>
#include <string.h>
#endif
#include "../network.h"
void discord_fatal(int rc);
// disgusting but descriptive
#define DISCORD_REQUIRE(x) { \
@ -26,10 +18,6 @@ void discord_fatal(int rc);
} \
}
extern struct NetworkSystem gNetworkSystemDiscord;
extern bool gDiscordInitialized;
extern bool gDiscordFailed;
struct DiscordApplication {
struct IDiscordCore* core;
struct IDiscordUserManager* users;
@ -41,6 +29,8 @@ struct DiscordApplication {
DiscordUserId userId;
};
extern struct DiscordApplication app;
#endif
void discord_update(void);
void discord_fatal(int rc);
void discord_activity_update_check(void);
void discord_activity_update(void);
struct IDiscordActivityEvents* discord_activity_initialize(void);

View file

@ -0,0 +1,152 @@
#include "discord.h"
#include "pc/djui/djui.h"
#include "pc/mods/mods.h"
#include "pc/debuglog.h"
extern struct DiscordApplication app;
struct DiscordActivity sCurActivity = { 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", result);
DISCORD_REQUIRE(result);
LOG_INFO("Discord join callback: %u, %lu, %d, %lu %s, %d",
lobby->capacity,
lobby->id,
lobby->locked,
lobby->owner_id,
lobby->secret,
lobby->type
);
/*sCurActivity.type = DiscordActivityType_Playing;
sCurActivity.party.size.current_size = 2;
sCurActivity.party.size.max_size = 16; // TODO: wrong
*/
discord_activity_update();
}
static void on_activity_join(UNUSED void* data, const char* secret) {
LOG_INFO("> on_activity_join, secret: %s", secret);
//djui_connect_menu_open();
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);
DISCORD_REQUIRE(result);
}
static void on_activity_join_request(UNUSED void* data, struct DiscordUser* user) {
LOG_INFO("> on_activity_join_request from " DISCORD_ID_FORMAT, user->id);
}
static void strncat_len(char* destination, char* source, size_t destinationLength, size_t sourceLength) {
char altered[128] = { 0 };
snprintf(altered, (sourceLength < 127) ? sourceLength : 127, "%s", source);
strncat(destination, altered, destinationLength);
}
static bool discord_populate_details(char* details, bool shorten) {
snprintf(details, 127, "%s", get_version());
bool displayDash = true;
bool displayComma = false;
size_t catLength = shorten ? 14 : 64;
// add mods to activity
if (gActiveMods.entryCount > 0) {
for (int i = 0; i < gActiveMods.entryCount; i++) {
struct Mod* mod = gActiveMods.entries[i];
if (displayDash) { strncat_len(details, " - ", 127, catLength); }
if (displayComma) { strncat_len(details, ", ", 127, catLength); }
strncat_len(details, mod->name, 127, catLength);
displayDash = false;
displayComma = true;
}
}
return (strlen(details) >= 125);
}
void discord_activity_update(void) {
sCurActivity.type = DiscordActivityType_Playing;
if (gNetworkType != NT_NONE && gNetworkSystem) {
gNetworkSystem->get_lobby_id(sCurActivity.party.id, 128);
gNetworkSystem->get_lobby_secret(sCurActivity.secrets.join, 128);
sCurActivity.party.size.current_size = network_player_connected_count();
sCurActivity.party.size.max_size = gServerSettings.maxPlayers;
} else {
sCurActivity.party.size.current_size = 1;
sCurActivity.party.size.max_size = 1;
}
if (sCurActivity.party.size.current_size > 1) {
strcpy(sCurActivity.state, "Playing!");
} else if (gNetworkType == NT_SERVER) {
strcpy(sCurActivity.state, "Waiting for players...");
} else {
strcpy(sCurActivity.state, "In-game.");
sCurActivity.party.size.current_size = 1;
if (sCurActivity.party.size.max_size < 1) { sCurActivity.party.size.max_size = 1; }
}
char details[256] = { 0 };
bool overrun = discord_populate_details(details, false);
if (overrun) {
discord_populate_details(details, true);
}
if (snprintf(sCurActivity.details, 125, "%s", details) < 0) {
LOG_INFO("truncating details");
}
if (!app.activities) {
LOG_INFO("no activities");
return;
}
if (!app.activities->update_activity) {
LOG_INFO("no update_activity");
return;
}
app.activities->update_activity(app.activities, &sCurActivity, NULL, on_activity_update_callback);
LOG_INFO("set activity");
}
void discord_activity_update_check(void) {
if (gNetworkType == NT_NONE) { return; }
bool shouldUpdate = false;
u8 connectedCount = network_player_connected_count();
if (connectedCount > 0) {
if (connectedCount != sCurActivity.party.size.current_size) {
shouldUpdate = true;
}
}
static int updateTimer = 30 * 60;
if (--updateTimer <= 0) {
updateTimer = 30 * 60;
shouldUpdate = true;
}
if (shouldUpdate) {
discord_activity_update();
}
}
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;
}

View file

@ -1,291 +0,0 @@
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "macros.h"
#include "PR/ultratypes.h"
#include "game/memory.h"
#include "game/save_file.h"
#include "pc/configfile.h"
#include "discordrpc.h"
#define DISCORDLIBFILE "libdiscord-rpc"
// Thanks Microsoft for being non posix compliant
#if defined(_WIN32)
# include <windows.h>
# define DISCORDLIBEXT ".dll"
# define dlopen(lib, flag) LoadLibrary(TEXT(lib))
# define dlerror() ""
# define dlsym(handle, func) (void *)GetProcAddress(handle, func)
# define dlclose(handle) FreeLibrary(handle)
#elif defined(__APPLE__)
# include <dlfcn.h>
# define DISCORDLIBEXT ".dylib"
#elif defined(__linux__) || defined(__FreeBSD__) // lets make the bold assumption for FreeBSD
# include <dlfcn.h>
# define DISCORDLIBEXT ".so"
#else
# error Unknown System
#endif
#define DISCORDLIB DISCORDLIBFILE DISCORDLIBEXT
#define DISCORD_APP_ID "709083908708237342"
#define DISCORD_UPDATE_RATE 5
extern s16 gCurrCourseNum;
extern s16 gCurrActNum;
extern u8* seg2_course_name_table[];
extern u8* seg2_act_name_table[];
static time_t lastUpdatedTime;
static DiscordRichPresence discordRichPresence;
static bool initd = false;
static void* handle;
void (*Discord_Initialize)(const char *, DiscordEventHandlers *, int, const char *);
void (*Discord_Shutdown)(void);
void (*Discord_ClearPresence)(void);
void (*Discord_UpdatePresence)(DiscordRichPresence *);
static s16 lastCourseNum = -1;
static s16 lastActNum = -1;
#ifdef VERSION_EU
#include "eu_translation.h"
extern s32 gInGameLanguage;
#endif
static char stage[188];
static char act[188];
static char smallImageKey[5];
static char largeImageKey[5];
static const char charset[0xFF+1] = {
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 7
' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f', // 15
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 23
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 31
'w', 'x', 'y', 'z', ' ', ' ', ' ', ' ', // 39
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 49
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 55
' ', ' ', ' ', ' ', ' ', ' ', '\'', ' ', // 63
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 71
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 79
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 87
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 95
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 103
' ', ' ', ' ', ' ', ' ', ' ', ' ', ',', // 111
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 119
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 127
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 135
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 143
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 151
' ', ' ', ' ', ' ', ' ', ' ', ' ', '-', // 159
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 167
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 175
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 183
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 192
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 199
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 207
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 215
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 223
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 231
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 239
' ', ' ', '!', ' ', ' ', ' ', ' ', ' ', // 247
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' // 255
};
static void convertstring(const u8 *str, char* output) {
s32 strPos = 0;
bool capitalizeChar = true;
while (str[strPos] != 0xFF) {
if (str[strPos] < 0xFF) {
output[strPos] = charset[str[strPos]];
// if the char is a letter we can capatalize it
if (capitalizeChar && 0x0A <= str[strPos] && str[strPos] <= 0x23) {
output[strPos] -= ('a' - 'A');
capitalizeChar = false;
}
} else {
output[strPos] = ' ';
}
// decide if the next character should be capitalized
switch (output[strPos]) {
case ' ':
if (str[strPos] != 158)
fprintf(stdout, "Unknown Character (%i)\n", str[strPos]); // inform that an unknown char was found
case '-':
capitalizeChar = true;
break;
default:
capitalizeChar = false;
break;
}
strPos++;
}
output[strPos] = '\0';
}
static void on_ready(UNUSED const DiscordUser* user) {
discord_reset();
}
static void init_discord(void) {
DiscordEventHandlers handlers;
memset(&handlers, 0, sizeof(handlers));
handlers.ready = on_ready;
Discord_Initialize(DISCORD_APP_ID, &handlers, false, "");
initd = true;
}
static void set_details(void) {
if (lastCourseNum != gCurrCourseNum) {
// If we are in in Course 0 we are in the castle which doesn't have a string
if (gCurrCourseNum) {
void **courseNameTbl;
#ifndef VERSION_EU
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#else
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
#endif
u8 *courseName = segmented_to_virtual(courseNameTbl[gCurrCourseNum - 1]);
convertstring(&courseName[3], stage);
} else {
strcpy(stage, "Peach's Castle");
}
lastCourseNum = gCurrCourseNum;
}
}
static void set_state(void) {
if (lastActNum != gCurrActNum || lastCourseNum != gCurrCourseNum) {
// when exiting a stage the act doesn't get reset
if (gCurrActNum && gCurrCourseNum) {
// any stage over 19 is a special stage without acts
if (gCurrCourseNum < 19) {
void **actNameTbl;
#ifndef VERSION_EU
actNameTbl = segmented_to_virtual(seg2_act_name_table);
#else
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
break;
}
#endif
u8 *actName = actName = segmented_to_virtual(actNameTbl[(gCurrCourseNum - 1) * 6 + gCurrActNum - 1]);
convertstring(actName, act);
} else {
act[0] = '\0';
gCurrActNum = 0;
}
} else {
act[0] = '\0';
}
lastActNum = gCurrActNum;
}
}
void set_logo(void) {
if (lastCourseNum)
snprintf(largeImageKey, sizeof(largeImageKey), "%d", lastCourseNum);
else
strcpy(largeImageKey, "0");
/*
if (lastActNum)
snprintf(smallImageKey, sizeof(largeImageKey), "%d", lastActNum);
else
smallImageKey[0] = '\0';
*/
discordRichPresence.largeImageKey = largeImageKey;
//discordRichPresence.largeImageText = "";
//discordRichPresence.smallImageKey = smallImageKey;
//discordRichPresence.smallImageText = "";
}
void discord_update_rich_presence(void) {
if (!configDiscordRPC || !initd) return;
if (time(NULL) < lastUpdatedTime + DISCORD_UPDATE_RATE) return;
lastUpdatedTime = time(NULL);
set_state();
set_details();
set_logo();
Discord_UpdatePresence(&discordRichPresence);
}
void discord_shutdown(void) {
if (handle) {
Discord_ClearPresence();
Discord_Shutdown();
dlclose(handle);
}
}
void discord_init(void) {
if (configDiscordRPC) {
handle = dlopen(DISCORDLIB, RTLD_LAZY);
if (!handle) {
fprintf(stderr, "Unable to load Discord\n%s\n", dlerror());
return;
}
Discord_Initialize = dlsym(handle, "Discord_Initialize");
Discord_Shutdown = dlsym(handle, "Discord_Shutdown");
Discord_ClearPresence = dlsym(handle, "Discord_ClearPresence");
Discord_UpdatePresence = dlsym(handle, "Discord_UpdatePresence");
init_discord();
discordRichPresence.details = stage;
discordRichPresence.state = act;
lastUpdatedTime = 0;
}
}
void discord_reset(void) {
memset( &discordRichPresence, 0, sizeof( discordRichPresence ) );
set_state();
set_details();
set_logo();
Discord_UpdatePresence(&discordRichPresence);
}

View file

@ -1,49 +0,0 @@
#ifndef DISCORDRPC_H
#define DISCORDRPC_H
#include <stdint.h>
typedef struct DiscordRichPresence {
const char* state; /* max 128 bytes */
const char* details; /* max 128 bytes */
int64_t startTimestamp;
int64_t endTimestamp;
const char* largeImageKey; /* max 32 bytes */
const char* largeImageText; /* max 128 bytes */
const char* smallImageKey; /* max 32 bytes */
const char* smallImageText; /* max 128 bytes */
const char* partyId; /* max 128 bytes */
int partySize;
int partyMax;
const char* matchSecret; /* max 128 bytes */
const char* joinSecret; /* max 128 bytes */
const char* spectateSecret; /* max 128 bytes */
int8_t instance;
} DiscordRichPresence;
typedef struct DiscordUser {
const char* userId;
const char* username;
const char* discriminator;
const char* avatar;
} DiscordUser;
typedef struct DiscordEventHandlers {
void (*ready)(const DiscordUser* request);
void (*disconnected)(int errorCode, const char* message);
void (*errored)(int errorCode, const char* message);
void (*joinGame)(const char* joinSecret);
void (*spectateGame)(const char* spectateSecret);
void (*joinRequest)(const DiscordUser* request);
} DiscordEventHandlers;
#define DISCORD_REPLY_NO 0
#define DISCORD_REPLY_YES 1
#define DISCORD_REPLY_IGNORE 2
void discord_update_rich_presence(void);
void discord_shutdown(void);
void discord_init(void);
void discord_reset(void);
#endif // DISCORDRPC_H

View file

@ -18,14 +18,6 @@ struct DjuiInputbox* sInputboxPort = NULL;
struct DjuiInputbox* sInputboxPassword = NULL;
static void djui_panel_host_network_system_change(UNUSED struct DjuiBase* base) {
#ifndef DISCORD_SDK
{
struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*) base;
if (*selectionbox->value == NS_DISCORD) {
selectionbox->value = NS_SOCKET;
}
}
#endif
#ifndef COOPNET
{
struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*) base;
@ -101,8 +93,8 @@ void djui_panel_host_create(struct DjuiBase* caller) {
: DLANG(HOST, HOST_TITLE));
struct DjuiBase* body = djui_three_panel_get_body(panel);
{
char* nChoices[] = { DLANG(HOST, DIRECT_CONNECTION), DLANG(HOST, DISCORD), DLANG(HOST, COOPNET) };
struct DjuiSelectionbox* selectionbox1 = djui_selectionbox_create(body, DLANG(HOST, NETWORK_SYSTEM), nChoices, 3, &configNetworkSystem, djui_panel_host_network_system_change);
char* nChoices[] = { DLANG(HOST, DIRECT_CONNECTION), DLANG(HOST, COOPNET) };
struct DjuiSelectionbox* selectionbox1 = djui_selectionbox_create(body, DLANG(HOST, NETWORK_SYSTEM), nChoices, 2, &configNetworkSystem, djui_panel_host_network_system_change);
if (gNetworkType == NT_SERVER) {
djui_base_set_enabled(&selectionbox1->base, false);
}

View file

@ -4,7 +4,6 @@
#include "djui_panel_menu.h"
#include "djui_panel_modlist.h"
#include "src/pc/network/network.h"
#include "src/pc/network/discord/discord.h"
#include "src/pc/utils/misc.h"
#include "src/pc/configfile.h"
#include "pc/utils/misc.h"
@ -21,9 +20,6 @@ void djui_panel_do_host(bool reconnecting) {
gCurrSaveFileNum = configHostSaveSlot;
update_all_mario_stars();
#ifndef DISCORD_SDK
if (configNetworkSystem == NS_DISCORD) { configNetworkSystem = NS_COOPNET; }
#endif
#ifndef COOPNET
if (configNetworkSystem == NS_COOPNET) { configNetworkSystem = NS_SOCKET; }
#endif
@ -54,15 +50,9 @@ void djui_panel_host_message_create(struct DjuiBase* caller) {
char* warningMessage = NULL;
bool hideHostButton = false;
if (configNetworkSystem == NS_DISCORD) {
warningLines = gDiscordFailed ? 5 : 13;
warningMessage = gDiscordFailed ? DLANG(HOST_MESSAGE, WARN_DISCORD2) : DLANG(HOST_MESSAGE, WARN_DISCORD);
hideHostButton = gDiscordFailed;
} else {
warningLines = 5;
warningMessage = calloc(256, sizeof(char));
sprintf(warningMessage, DLANG(HOST_MESSAGE, WARN_SOCKET), configHostPort);
}
warningLines = 5;
warningMessage = calloc(256, sizeof(char));
snprintf(warningMessage, 256, DLANG(HOST_MESSAGE, WARN_SOCKET), configHostPort);
f32 textHeight = 32 * 0.8125f * warningLines + 8;
@ -88,7 +78,5 @@ void djui_panel_host_message_create(struct DjuiBase* caller) {
}
djui_panel_add(caller, panel, NULL);
if (configNetworkSystem != NS_DISCORD) {
free(warningMessage);
}
free(warningMessage);
}

View file

@ -7,7 +7,6 @@
#include "pc/utils/misc.h"
#include "pc/configfile.h"
#include "pc/cheats.h"
#include "pc/network/discord/lobby.h"
#include "djui_inputbox.h"
static unsigned int sKnockbackIndex = 0;

View file

@ -20,6 +20,7 @@ static char* sPassword = NULL;
void djui_panel_join_lobby(struct DjuiBase* caller) {
gCoopNetDesiredLobby = (uint64_t)caller->tag;
snprintf(gCoopNetPassword, 64, "%s", sPassword);
network_reset_reconnect_and_rehost();
network_set_system(NS_COOPNET);
network_init(NT_CLIENT, false);

View file

@ -1887,13 +1887,14 @@ static struct LuaObjectField sRayIntersectionInfoFields[LUA_RAY_INTERSECTION_INF
{ "surface", LVT_COBJECT_P, offsetof(struct RayIntersectionInfo, surface), false, LOT_SURFACE },
};
#define LUA_SERVER_SETTINGS_FIELD_COUNT 10
#define LUA_SERVER_SETTINGS_FIELD_COUNT 11
static struct LuaObjectField sServerSettingsFields[LUA_SERVER_SETTINGS_FIELD_COUNT] = {
{ "bubbleDeath", LVT_U8, offsetof(struct ServerSettings, bubbleDeath), false, LOT_NONE },
{ "enableCheats", LVT_U8, offsetof(struct ServerSettings, enableCheats), false, LOT_NONE },
{ "enablePlayerList", LVT_U8, offsetof(struct ServerSettings, enablePlayerList), false, LOT_NONE },
{ "enablePlayersInLevelDisplay", LVT_U8, offsetof(struct ServerSettings, enablePlayersInLevelDisplay), false, LOT_NONE },
{ "headlessServer", LVT_U8, offsetof(struct ServerSettings, headlessServer), false, LOT_NONE },
{ "maxPlayers", LVT_U8, offsetof(struct ServerSettings, maxPlayers), false, LOT_NONE },
{ "playerInteractions", LVT_S32, offsetof(struct ServerSettings, playerInteractions), false, LOT_NONE },
{ "playerKnockbackStrength", LVT_U8, offsetof(struct ServerSettings, playerKnockbackStrength), false, LOT_NONE },
{ "shareLives", LVT_U8, offsetof(struct ServerSettings, shareLives), false, LOT_NONE },

View file

@ -1759,7 +1759,8 @@ char gSmluaConstants[] = ""
"SYNC_DISTANCE_INFINITE = 0\n"
"PACKET_LENGTH = 3000\n"
"NS_SOCKET = 0\n"
"NS_DISCORD = 1\n"
"NS_COOPNET = 1\n"
"NS_MAX = 2\n"
"PLAYER_INTERACTIONS_NONE = 0\n"
"PLAYER_INTERACTIONS_SOLID = 1\n"
"PLAYER_INTERACTIONS_PVP = 2\n"
@ -4015,8 +4016,8 @@ char gSmluaConstants[] = ""
"COOP_OBJ_FLAG_NON_SYNC = (1 << 2)\n"
"COOP_OBJ_FLAG_INITIALIZED = (1 << 3)\n"
"VERSION_TEXT = 'beta'\n"
"VERSION_NUMBER = 33\n"
"MINOR_VERSION_NUMBER = 1\n"
"VERSION_NUMBER = 34\n"
"MINOR_VERSION_NUMBER = 0\n"
"PATCH_VERSION_NUMBER = 0\n"
"MAX_VERSION_LENGTH = 10\n"
"MAX_LOCAL_VERSION_LENGTH = 12\n"

View file

@ -30,6 +30,7 @@
#include "src/pc/lua/utils/smlua_text_utils.h"
#include "src/pc/lua/utils/smlua_audio_utils.h"
#include "src/pc/lua/utils/smlua_level_utils.h"
#include "src/pc/lua/utils/smlua_deprecated.h"
#include "src/game/object_list_processor.h"
#include "src/game/behavior_actions.h"
#include "src/game/mario_misc.h"
@ -18741,23 +18742,6 @@ int smlua_func_network_player_set_description(lua_State* L) {
// network_utils.h //
/////////////////////
int smlua_func_network_discord_id_from_local_index(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_discord_id_from_local_index", 1, top);
return 0;
}
u8 localIndex = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "network_discord_id_from_local_index"); return 0; }
lua_pushstring(L, network_discord_id_from_local_index(localIndex));
return 1;
}
int smlua_func_network_get_player_text_color_string(lua_State* L) {
if (L == NULL) { return 0; }
@ -26273,6 +26257,27 @@ int smlua_func_smlua_collision_util_get(lua_State* L) {
return 1;
}
////////////////////////
// smlua_deprecated.h //
////////////////////////
int smlua_func_network_discord_id_from_local_index(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_discord_id_from_local_index", 1, top);
return 0;
}
u8 localIndex = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "network_discord_id_from_local_index"); return 0; }
lua_pushstring(L, network_discord_id_from_local_index(localIndex));
return 1;
}
/////////////////////////
// smlua_level_utils.h //
/////////////////////////
@ -30186,7 +30191,6 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "network_player_set_description", smlua_func_network_player_set_description);
// network_utils.h
smlua_bind_function(L, "network_discord_id_from_local_index", smlua_func_network_discord_id_from_local_index);
smlua_bind_function(L, "network_get_player_text_color_string", smlua_func_network_get_player_text_color_string);
smlua_bind_function(L, "network_global_index_from_local", smlua_func_network_global_index_from_local);
smlua_bind_function(L, "network_is_moderator", smlua_func_network_is_moderator);
@ -30571,6 +30575,9 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "get_water_surface_pseudo_floor", smlua_func_get_water_surface_pseudo_floor);
smlua_bind_function(L, "smlua_collision_util_get", smlua_func_smlua_collision_util_get);
// smlua_deprecated.h
smlua_bind_function(L, "network_discord_id_from_local_index", smlua_func_network_discord_id_from_local_index);
// smlua_level_utils.h
smlua_bind_function(L, "level_register", smlua_func_level_register);
smlua_bind_function(L, "smlua_level_util_get_info", smlua_func_smlua_level_util_get_info);

View file

@ -0,0 +1,5 @@
#include "types.h"
char* network_discord_id_from_local_index(UNUSED u8 localIndex) {
return NULL;
}

View file

@ -0,0 +1,3 @@
#pragma once
char* network_discord_id_from_local_index(u8 localIndex);

View file

@ -7,17 +7,21 @@
#include "pc/djui/djui_popup.h"
#include "pc/mods/mods.h"
#include "pc/debuglog.h"
#ifdef DISCORD_SDK
#include "pc/discord/discord.h"
#endif
#ifdef COOPNET
#define CN_GAME_STR "sm64ex-coop"
uint64_t gCoopNetDesiredLobby = 0;
char gCoopNetPassword[64] = "";
static uint64_t sLocalLobbyId = 0;
static uint64_t sLocalLobbyOwnerId = 0;
static enum NetworkType sNetworkType;
static bool sReconecting = false;
static bool sReconnecting = false;
static CoopNetRc coopnet_initialize(void);
@ -69,6 +73,9 @@ static void coopnet_on_lobby_joined(uint64_t lobbyId, uint64_t userId, uint64_t
if (userId == coopnet_get_local_user_id() && gNetworkType == NT_CLIENT) {
network_send_mod_list_request();
}
#ifdef DISCORD_SDK
discord_activity_update();
#endif
}
static void coopnet_on_lobby_left(uint64_t lobbyId, uint64_t userId) {
@ -81,7 +88,7 @@ static void coopnet_on_lobby_left(uint64_t lobbyId, uint64_t userId) {
static bool ns_coopnet_initialize(enum NetworkType networkType, bool reconnecting) {
sNetworkType = networkType;
sReconecting = reconnecting;
sReconnecting = reconnecting;
if (reconnecting) { return true; }
return coopnet_is_connected()
? true
@ -114,8 +121,8 @@ void ns_coopnet_update(void) {
coopnet_update();
if (gNetworkType != NT_NONE && sNetworkType != NT_NONE) {
if (sNetworkType == NT_SERVER) {
if (sReconecting) {
if (sReconnecting) {
// TODO: send lobby update packet
} else {
LOG_INFO("Create lobby");
char mode[64] = "";
@ -124,7 +131,7 @@ void ns_coopnet_update(void) {
}
} else if (sNetworkType == NT_CLIENT) {
LOG_INFO("Join lobby");
coopnet_lobby_join(gCoopNetDesiredLobby, "");
coopnet_lobby_join(gCoopNetDesiredLobby, gCoopNetPassword);
}
sNetworkType = NT_NONE;
}
@ -140,12 +147,31 @@ static int ns_coopnet_network_send(u8 localIndex, void* address, u8* data, u16 d
return 0;
}
static void ns_coopnet_get_lobby_id(UNUSED char* destination, UNUSED u32 destLength) {
if (sLocalLobbyId == 0) {
snprintf(destination, destLength, "%s", "");
} else {
snprintf(destination, destLength, "coopnet-id:%" PRIu64 "", sLocalLobbyId);
}
}
static void ns_coopnet_get_lobby_secret(UNUSED char* destination, UNUSED u32 destLength) {
if (sLocalLobbyId == 0) {
snprintf(destination, destLength, "%s", "");
} else {
snprintf(destination, destLength, "coopnet-pw:%s", gCoopNetPassword);
}
}
static void ns_coopnet_shutdown(bool reconnecting) {
if (reconnecting) { return; }
LOG_INFO("Coopnet shutdown!");
coopnet_shutdown();
gCoopNetCallbacks.OnLobbyListGot = NULL;
gCoopNetCallbacks.OnLobbyListFinish = NULL;
sLocalLobbyId = 0;
sLocalLobbyOwnerId = 0;
}
static CoopNetRc coopnet_initialize(void) {
@ -167,18 +193,20 @@ static CoopNetRc coopnet_initialize(void) {
}
struct NetworkSystem gNetworkSystemCoopNet = {
.initialize = ns_coopnet_initialize,
.get_id = ns_coopnet_get_id,
.get_id_str = ns_coopnet_get_id_str,
.save_id = ns_coopnet_save_id,
.clear_id = ns_coopnet_clear_id,
.dup_addr = ns_coopnet_dup_addr,
.match_addr = ns_coopnet_match_addr,
.update = ns_coopnet_update,
.send = ns_coopnet_network_send,
.shutdown = ns_coopnet_shutdown,
.initialize = ns_coopnet_initialize,
.get_id = ns_coopnet_get_id,
.get_id_str = ns_coopnet_get_id_str,
.save_id = ns_coopnet_save_id,
.clear_id = ns_coopnet_clear_id,
.dup_addr = ns_coopnet_dup_addr,
.match_addr = ns_coopnet_match_addr,
.update = ns_coopnet_update,
.send = ns_coopnet_network_send,
.get_lobby_id = ns_coopnet_get_lobby_id,
.get_lobby_secret = ns_coopnet_get_lobby_secret,
.shutdown = ns_coopnet_shutdown,
.requireServerBroadcast = false,
.name = "CoopNet",
.name = "CoopNet",
};
#endif

View file

@ -7,6 +7,7 @@ typedef void (*QueryFinishCallbackPtr)(void);
extern struct NetworkSystem gNetworkSystemCoopNet;
extern uint64_t gCoopNetDesiredLobby;
extern char gCoopNetPassword[];
bool ns_coopnet_query(QueryCallbackPtr callback, QueryFinishCallbackPtr finishCallback, const char* password);
bool ns_coopnet_is_connected(void);

View file

@ -1,171 +0,0 @@
#include "activity.h"
#include "lobby.h"
#include "discord_network.h"
#include "pc/network/network.h"
#include "pc/network/version.h"
#include "pc/djui/djui.h"
#include "pc/mods/mods.h"
#include "pc/logfile.h"
#define HASH_LENGTH 8
struct DiscordActivity gCurActivity = { 0 };
bool gActivityLock = false;
static void on_activity_update_callback(UNUSED void* data, enum EDiscordResult result) {
LOGFILE_INFO(LFT_DISCORD, "> 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) {
gActivityLock = false;
LOGFILE_INFO(LFT_DISCORD, "> on_activity_join_callback returned %d, lobby " DISCORD_ID_FORMAT ", owner " DISCORD_ID_FORMAT, result, lobby->id, lobby->owner_id);
DISCORD_REQUIRE(result);
if (gNetworkType != NT_NONE) {
LOGFILE_ERROR(LFT_DISCORD, "Joined lobby when already connected somewhere!");
return;
}
network_reset_reconnect_and_rehost();
network_init(NT_CLIENT, false);
gCurActivity.type = DiscordActivityType_Playing;
if (snprintf(gCurActivity.party.id, 128, DISCORD_ID_FORMAT, lobby->id) < 0) {
LOGFILE_ERROR(LFT_DISCORD, "Truncating party 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);
if (gNetworkPlayerServer == NULL) {
network_player_connected(NPT_SERVER, 0, 0, &DEFAULT_MARIO_PALETTE, "Player");
}
ns_discord_save_id(gNetworkPlayerServer->localIndex, lobby->owner_id);
network_send_mod_list_request();
gNetworkUserIds[0] = lobby->owner_id;
}
static void on_activity_join(UNUSED void* data, const char* secret) {
LOGFILE_INFO(LFT_DISCORD, "> on_activity_join, secret: %s", secret);
if (gActivityLock) { return; }
gActivityLock = true;
djui_connect_menu_open();
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) {
LOGFILE_INFO(LFT_DISCORD, "> on_activity_join_request_callback returned %d", (int)result);
DISCORD_REQUIRE(result);
}
static void on_activity_join_request(UNUSED void* data, struct DiscordUser* user) {
LOGFILE_INFO(LFT_DISCORD, "> on_activity_join_request from " DISCORD_ID_FORMAT, user->id);
//app.activities->send_request_reply(app.activities, user->id, DiscordActivityJoinRequestReply_Yes, NULL, on_activity_join_request_callback);
}
static void strncat_len(char* destination, char* source, size_t destinationLength, size_t sourceLength) {
char altered[128] = { 0 };
snprintf(altered, (sourceLength < 127) ? sourceLength : 127, "%s", source);
strncat(destination, altered, destinationLength);
}
static bool discord_populate_details(char* details, bool shorten) {
snprintf(details, 127, "%s", get_version());
bool displayDash = true;
bool displayComma = false;
size_t catLength = shorten ? 14 : 64;
if (gRegisteredMods.string != NULL) {
strncat_len(details, " - ", 127, catLength);
displayDash = false;
// add patches to activity
struct StringLinkedList* node = &gRegisteredMods;
while (node != NULL && node->string != NULL) {
if (displayComma) { strncat_len(details, ", ", 127, catLength); }
strncat_len(details, node->string, 127, catLength);
displayComma = true;
node = node->next;
}
}
if (gActiveMods.entryCount > 0) {
// add mods to activity
for (int i = 0; i < gActiveMods.entryCount; i++) {
struct Mod* mod = gActiveMods.entries[i];
if (displayDash) { strncat_len(details, " - ", 127, catLength); }
if (displayComma) { strncat_len(details, ", ", 127, catLength); }
strncat_len(details, mod->name, 127, catLength);
displayDash = false;
displayComma = true;
}
}
return (strlen(details) >= 125);
}
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 players...");
} else {
strcpy(gCurActivity.state, "In-game.");
gCurActivity.party.size.current_size = 1;
if (gCurActivity.party.size.max_size < 1) { gCurActivity.party.size.max_size = 1; }
}
char details[256] = { 0 };
bool overrun = discord_populate_details(details, false);
if (overrun) {
discord_populate_details(details, true);
}
if (snprintf(gCurActivity.details, 125, "%s", details) < 0) {
LOGFILE_INFO(LFT_DISCORD, "truncating details");
}
if (!app.activities) {
LOGFILE_INFO(LFT_DISCORD, "no activities");
return;
}
if (!app.activities->update_activity) {
LOGFILE_INFO(LFT_DISCORD, "no update_activity");
return;
}
app.activities->update_activity(app.activities, &gCurActivity, NULL, on_activity_update_callback);
LOGFILE_INFO(LFT_DISCORD, "set activity");
}
void discord_activity_update_check(void) {
if (gNetworkType == NT_NONE) { return; }
bool shouldUpdate = false;
u8 connectedCount = network_player_connected_count();
if (connectedCount > 0) {
if (connectedCount != gCurActivity.party.size.current_size) {
gCurActivity.party.size.current_size = connectedCount;
shouldUpdate = true;
}
}
if (shouldUpdate) {
discord_activity_update(gNetworkType == NT_SERVER);
}
}
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;
}

View file

@ -1,12 +0,0 @@
#ifndef DISCORD_ACTIVITY_H
#define DISCORD_ACTIVITY_H
#include "discord.h"
extern struct DiscordActivity gCurActivity;
void discord_activity_update(bool hosting);
void discord_activity_update_check(void);
struct IDiscordActivityEvents* discord_activity_initialize(void);
extern bool gActivityLock;
#endif

View file

@ -1,203 +0,0 @@
#include "discord.h"
#include "user.h"
#include "activity.h"
#include "lobby.h"
#include "discord_network.h"
#include "pc/network/version.h"
#include "pc/djui/djui.h"
#include "pc/logfile.h"
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <winuser.h>
#else
#include <unistd.h>
#define MAX_PATH 1024
#endif
#define MAX_LAUNCH_CMD (MAX_PATH + 12)
static int64_t applicationId = 752700005210390568;
struct DiscordApplication app = { 0 };
bool gDiscordInitialized = false;
bool gDiscordFailed = false;
bool alreadyRun = false;
static void discord_sdk_log_callback(UNUSED void* hook_data, enum EDiscordLogLevel level, const char* message) {
LOGFILE_INFO(LFT_DISCORD, "callback (%d): %s", level, message);
}
void discord_fatal_message(int rc) { // Discord usually does this because of loss of connection to Discord
char errorMessage[132] = { 0 };
snprintf(errorMessage, 132, "%s\nRC: %d", DLANG(NOTIF, DISCORD_ERROR), rc);
djui_popup_create(errorMessage, 6);
}
void discord_fatal(int rc) {
if (!alreadyRun) {
discord_fatal_message(rc);
alreadyRun = true;
}
if (rc != DiscordResult_Ok) {
LOG_ERROR("Discord threw an error. RC: %d", rc);
}
}
static void set_instance_env_variable(void) {
// set local instance id
char environmentVariables[128] = { 0 };
int instance = (gCLIOpts.Discord == 0) ? 0 : (gCLIOpts.Discord - 1);
snprintf(environmentVariables, 128, "DISCORD_INSTANCE_ID=%d", instance);
putenv(environmentVariables);
LOGFILE_INFO(LFT_DISCORD, "set environment variables: %s", environmentVariables);
}
static void get_oauth2_token_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordOAuth2Token* token) {
LOGFILE_INFO(LFT_DISCORD, "> get_oauth2_token_callback returned %d", result);
if (result != DiscordResult_Ok) { return; }
LOGFILE_INFO(LFT_DISCORD, "OAuth2 token: %s", token->access_token);
}
static void register_launch_command(void) {
char cmd[MAX_LAUNCH_CMD] = { 0 };
int rc;
#if defined(_WIN32) || defined(_WIN64)
HMODULE hModule = GetModuleHandle(NULL);
if (hModule == NULL) {
LOGFILE_ERROR(LFT_DISCORD, "unable to retrieve absolute path!");
return;
}
GetModuleFileName(hModule, cmd, sizeof(cmd));
#else
char path[MAX_LAUNCH_CMD] = { 0 };
snprintf(path, MAX_LAUNCH_CMD - 1, "/proc/%d/exe", getpid());
rc = readlink(path, cmd, MAX_LAUNCH_CMD - 1);
if (rc <= 0) {
LOGFILE_ERROR(LFT_DISCORD, "unable to retrieve absolute path! rc = %d", rc);
return;
}
#endif
strncat(cmd, " --discord 1", MAX_LAUNCH_CMD - 1);
rc = app.activities->register_command(app.activities, cmd);
if (rc != DiscordResult_Ok) {
LOGFILE_ERROR(LFT_DISCORD, "register command failed %d", rc);
return;
}
LOGFILE_INFO(LFT_DISCORD, "cmd: %s", cmd);
}
static void* ns_discord_dup_addr(u8 localIndex) {
void* address = malloc(sizeof(DiscordUserId));
memcpy(address, &gNetworkUserIds[localIndex], sizeof(DiscordUserId));
return address;
}
static bool ns_discord_match_addr(void* addr1, void* addr2) {
return !memcmp(addr1, addr2, sizeof(u64));
}
static void ns_discord_update(void) {
if (!gDiscordInitialized) { return; }
discord_activity_update_check();
discord_lobby_update();
DISCORD_REQUIRE(app.core->run_callbacks(app.core));
discord_network_flush();
}
static bool ns_discord_initialize(enum NetworkType networkType, bool reconnecting) {
if (reconnecting) { return true; }
#ifdef DEBUG
set_instance_env_variable();
#endif
if (app.core != NULL) {
app.core->set_log_hook(app.core, DiscordLogLevel_Debug, NULL, discord_sdk_log_callback);
}
if (!gDiscordInitialized) {
// set up discord params
struct DiscordCreateParams params = { 0 };
DiscordCreateParamsSetDefault(&params);
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();
gCurLobbyId = 0;
gLobbyCreateRetry = false;
gLobbyCreateAttempts = 0;
gLobbyCreateAttemptElapsed = 0;
int rc = DiscordCreate(DISCORD_VERSION, &params, &app.core);
if (app.core != NULL) {
app.core->set_log_hook(app.core, DiscordLogLevel_Debug, NULL, discord_sdk_log_callback);
}
gDiscordFailed = false;
if (networkType != NT_NONE) {
DISCORD_REQUIRE(rc);
} else if (rc) {
LOGFILE_ERROR(LFT_DISCORD, "DiscordCreate failed: %d", rc);
djui_popup_create(DLANG(NOTIF, DISCORD_DETECT), 3);
gDiscordFailed = true;
return false;
}
// set up manager pointers
if (app.core != NULL) {
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();
gActivityLock = true;
} else {
gActivityLock = false;
}
gDiscordInitialized = true;
LOGFILE_INFO(LFT_DISCORD, "initialized");
return true;
}
static void ns_discord_shutdown(bool reconnecting) {
if (reconnecting) { return; }
if (!gDiscordInitialized) { return; }
discord_lobby_leave();
gActivityLock = false;
LOGFILE_INFO(LFT_DISCORD, "shutdown");
}
struct NetworkSystem gNetworkSystemDiscord = {
.initialize = ns_discord_initialize,
.get_id = ns_discord_get_id,
.get_id_str = ns_discord_get_id_str,
.save_id = ns_discord_save_id,
.clear_id = ns_discord_clear_id,
.dup_addr = ns_discord_dup_addr,
.match_addr = ns_discord_match_addr,
.update = ns_discord_update,
.send = ns_discord_network_send,
.shutdown = ns_discord_shutdown,
.requireServerBroadcast = false,
.name = "Discord",
};

View file

@ -1,84 +0,0 @@
#include "discord_network.h"
#include "lobby.h"
#include "pc/logfile.h"
int64_t gNetworkUserIds[MAX_PLAYERS] = { 0 };
u8 discord_user_id_to_local_index(int64_t userId) {
for (int i = 1; i < MAX_PLAYERS; i++) {
if (gNetworkPlayers[i].connected && gNetworkUserIds[i] == userId) {
return i;
}
}
return UNKNOWN_LOCAL_INDEX;
}
int ns_discord_network_send(u8 localIndex, void* address, u8* data, u16 dataLength) {
if (!gDiscordInitialized) { return 1; }
if (gCurLobbyId == 0) { return 2; }
DiscordUserId userId = gNetworkUserIds[localIndex];
if (localIndex == 0 && address != NULL) { userId = *(DiscordUserId*)address; }
DISCORD_REQUIRE(app.lobbies->send_network_message(app.lobbies, gCurLobbyId, userId, 0, data, dataLength));
return 0;
}
void discord_network_on_message(UNUSED void* eventData, UNUSED int64_t lobbyId, int64_t userId, UNUSED uint8_t channelId, uint8_t* data, uint32_t dataLength) {
gNetworkUserIds[0] = userId;
u8 localIndex = UNKNOWN_LOCAL_INDEX;
for (int i = 1; i < MAX_PLAYERS; i++) {
if (gNetworkUserIds[i] == userId) {
localIndex = i;
break;
}
}
network_receive(localIndex, &userId, (u8*)data, (u16)dataLength);
}
void discord_network_flush(void) {
app.lobbies->flush_network(app.lobbies);
}
s64 ns_discord_get_id(u8 localId) {
if (localId == 0) { return app.userId; }
return gNetworkUserIds[localId];
}
char* ns_discord_get_id_str(u8 localId) {
static char id_str[22] = { 0 };
if (localId == UNKNOWN_LOCAL_INDEX) {
snprintf(id_str, 22, "???");
} else {
snprintf(id_str, 22, "%lld", (long long int)ns_discord_get_id(localId));
}
return id_str;
}
void ns_discord_save_id(u8 localId, s64 networkId) {
SOFT_ASSERT(localId > 0);
SOFT_ASSERT(localId < MAX_PLAYERS);
gNetworkUserIds[localId] = (networkId == 0) ? gNetworkUserIds[0] : networkId;
LOGFILE_INFO(LFT_DISCORD, "saved user id %d == " DISCORD_ID_FORMAT, localId, gNetworkUserIds[localId]);
}
void ns_discord_clear_id(u8 localId) {
if (localId == 0) { return; }
SOFT_ASSERT(localId < MAX_PLAYERS);
gNetworkUserIds[localId] = 0;
LOGFILE_INFO(LFT_DISCORD, "cleared user id %d == " DISCORD_ID_FORMAT, localId, gNetworkUserIds[localId]);
}
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));
LOGFILE_INFO(LFT_DISCORD, "network initialized");
}
void discord_network_shutdown(void) {
if (gCurLobbyId == 0) { return; }
app.lobbies->flush_network(app.lobbies);
app.lobbies->disconnect_network(app.lobbies, gCurLobbyId);
app.lobbies->flush_network(app.lobbies);
LOGFILE_INFO(LFT_DISCORD, "shutdown network, lobby = " DISCORD_ID_FORMAT, gCurLobbyId);
}

View file

@ -1,18 +0,0 @@
#ifndef DISCORD_NETWORK_H
#define DISCORD_NETWORK_H
#include "discord.h"
extern int64_t gNetworkUserIds[MAX_PLAYERS];
u8 discord_user_id_to_local_index(int64_t userId);
int ns_discord_network_send(u8 localIndex, void* addr, 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);
s64 ns_discord_get_id(u8 localId);
char* ns_discord_get_id_str(u8 localId);
void ns_discord_save_id(u8 localId, s64 networkId);
void ns_discord_clear_id(u8 localId);
void discord_network_init(int64_t lobbyId);
void discord_network_shutdown(void);
#endif

View file

@ -1,137 +0,0 @@
#include "lobby.h"
#include "activity.h"
#include "discord_network.h"
#include "pc/logfile.h"
#include "pc/utils/misc.h"
#include "pc/configfile.h"
#define MAX_LOBBY_RETRY 5
#define MAX_LOBBY_RETRY_WAIT_TIME 6
static bool isHosting = false;
DiscordLobbyId gCurLobbyId = 0;
bool gLobbyCreateRetry = false;
u8 gLobbyCreateAttempts = 0;
f32 gLobbyCreateAttemptElapsed = 0;
void discord_lobby_update(void) {
if (gCurLobbyId != 0) { return; }
if (!gLobbyCreateRetry) { return; }
f32 timeUntilRetry = (clock_elapsed() - gLobbyCreateAttemptElapsed);
if (timeUntilRetry < MAX_LOBBY_RETRY_WAIT_TIME) { return; }
gLobbyCreateRetry = false;
discord_lobby_create();
}
static void on_lobby_create_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordLobby* lobby) {
LOGFILE_INFO(LFT_DISCORD, "> on_lobby_create returned %d", (int)result);
if (result != DiscordResult_Ok && gLobbyCreateAttempts < MAX_LOBBY_RETRY) {
LOGFILE_INFO(LFT_DISCORD, "rescheduling lobby creation");
gLobbyCreateRetry = true;
gLobbyCreateAttempts++;
gLobbyCreateAttemptElapsed = clock_elapsed();
return;
}
DISCORD_REQUIRE(result);
LOGFILE_INFO(LFT_DISCORD, "Lobby id: " DISCORD_ID_FORMAT, lobby->id);
LOGFILE_INFO(LFT_DISCORD, "Lobby type: %u", lobby->type);
LOGFILE_INFO(LFT_DISCORD, "Lobby owner id: " DISCORD_ID_FORMAT, lobby->owner_id);
LOGFILE_INFO(LFT_DISCORD, "Lobby secret: %s", lobby->secret);
LOGFILE_INFO(LFT_DISCORD, "Lobby capacity: %u", lobby->capacity);
LOGFILE_INFO(LFT_DISCORD, "Lobby locked: %d", lobby->locked);
gCurActivity.type = DiscordActivityType_Playing;
if (snprintf(gCurActivity.party.id, 128, DISCORD_ID_FORMAT, lobby->id) < 0) {
LOGFILE_ERROR(LFT_DISCORD, "truncating party id");
}
gCurActivity.party.size.current_size = 1;
gCurActivity.party.size.max_size = configAmountofPlayers;
char secretJoin[128] = "";
if (snprintf(secretJoin, 128, DISCORD_ID_FORMAT ":%s", lobby->id, lobby->secret) < 0) {
LOGFILE_ERROR(LFT_DISCORD, "truncating 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) {
LOGFILE_INFO(LFT_DISCORD, "> on_lobby_update id: " DISCORD_ID_FORMAT, lobbyId);
}
static void on_member_connect(UNUSED void* data, int64_t lobbyId, int64_t userId) {
LOGFILE_INFO(LFT_DISCORD, "> on_member_connect lobby: " DISCORD_ID_FORMAT ", user: " DISCORD_ID_FORMAT, 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) {
LOGFILE_INFO(LFT_DISCORD, "> on_member_update lobby: " DISCORD_ID_FORMAT ", user: " DISCORD_ID_FORMAT, lobbyId, userId);
}
static void on_member_disconnect(UNUSED void* data, int64_t lobbyId, int64_t userId) {
LOGFILE_INFO(LFT_DISCORD, "> on_member_disconnect lobby: " DISCORD_ID_FORMAT ", user: " DISCORD_ID_FORMAT, lobbyId, userId);
u8 localIndex = discord_user_id_to_local_index(userId);
if (localIndex != UNKNOWN_LOCAL_INDEX && gNetworkPlayers[localIndex].connected) {
network_player_disconnected(gNetworkPlayers[localIndex].globalIndex);
}
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, MAX_PLAYERS);
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) {
LOGFILE_INFO(LFT_DISCORD, "> on_lobby_leave returned %d", result);
DISCORD_REQUIRE(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);
}
LOGFILE_INFO(LFT_DISCORD, "left lobby " DISCORD_ID_FORMAT, gCurLobbyId);
if (snprintf(gCurActivity.party.id, 128, "%s", "none") < 0) {
LOGFILE_ERROR(LFT_DISCORD, "Truncating party id");
}
gCurActivity.party.size.current_size = 1;
gCurActivity.party.size.max_size = 1;
discord_activity_update(gNetworkType == NT_SERVER);
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;
}

View file

@ -1,16 +0,0 @@
#ifndef DISCORD_LOBBY_H
#define DISCORD_LOBBY_H
#include "discord.h"
extern DiscordLobbyId gCurLobbyId;
extern bool gLobbyCreateRetry;
extern u8 gLobbyCreateAttempts;
extern f32 gLobbyCreateAttemptElapsed;
void discord_lobby_update(void);
void discord_lobby_create(void);
void discord_lobby_leave(void);
struct IDiscordLobbyEvents* discord_lobby_initialize(void);
#endif

View file

@ -1,34 +0,0 @@
#include "user.h"
#include "pc/configfile.h"
#include "pc/logfile.h"
#include "pc/crash_handler.h"
static void on_current_user_update(UNUSED void* data) {
LOGFILE_INFO(LFT_DISCORD, "> on_current_user_update");
struct DiscordUser user = { 0 };
app.users->get_current_user(app.users, &user);
// remember user id
app.userId = user.id;
gPcDebug.id = user.id;
// copy over discord username if we haven't set one yet
if (configPlayerName[0] == '\0' && strlen(user.username) > 0) {
char* cname = configPlayerName;
char* dname = user.username;
for (int i = 0; i < MAX_PLAYER_STRING - 1; i++) {
if (*dname >= '!' && *dname <= '~') {
*cname = *dname;
cname++;
}
dname++;
}
}
}
struct IDiscordUserEvents* discord_user_initialize(void) {
LOGFILE_INFO(LFT_DISCORD, "> discord_user_intitialize");
static struct IDiscordUserEvents events = { 0 };
events.on_current_user_update = on_current_user_update;
return &events;
}

View file

@ -1,7 +0,0 @@
#ifndef DISCORD_USER_H
#define DISCORD_USER_H
#include "discord.h"
struct IDiscordUserEvents* discord_user_initialize(void);
#endif

View file

@ -7,10 +7,6 @@
#include "behavior_table.h"
#include "src/game/hardcoded.h"
#include "src/game/scroll_targets.h"
#ifdef DISCORD_SDK
#include "discord/discord.h"
#include "discord/activity.h"
#endif
#include "pc/configfile.h"
#include "pc/cheats.h"
#include "pc/djui/djui.h"
@ -31,6 +27,10 @@
#include "game/level_geo.h"
#include "menu/intro_geo.h"
#ifdef DISCORD_SDK
#include "pc/discord/discord.h"
#endif
// fix warnings when including rendering_graph_node
#undef near
#undef far
@ -41,11 +41,7 @@ extern s16 sCurrPlayMode;
extern s16 gCurrCourseNum, gCurrActStarNum, gCurrLevelNum, gCurrAreaIndex;
enum NetworkType gNetworkType = NT_NONE;
#ifdef DISCORD_SDK
struct NetworkSystem* gNetworkSystem = &gNetworkSystemDiscord;
#else
struct NetworkSystem* gNetworkSystem = &gNetworkSystemSocket;
#endif
#define LOADING_LEVEL_THRESHOLD 10
#define MAX_PACKETS_PER_SECOND_PER_PLAYER ((u16)100)
@ -80,6 +76,7 @@ struct ServerSettings gServerSettings = {
.enablePlayersInLevelDisplay = 1,
.enablePlayerList = 1,
.headlessServer = 0,
.maxPlayers = MAX_PLAYERS,
};
void network_set_system(enum NetworkSystemType nsType) {
@ -87,15 +84,9 @@ void network_set_system(enum NetworkSystemType nsType) {
switch (nsType) {
case NS_SOCKET: gNetworkSystem = &gNetworkSystemSocket; break;
#ifdef DISCORD_SDK
case NS_DISCORD: gNetworkSystem = &gNetworkSystemDiscord; break;
#endif
#ifdef COOPNET
case NS_COOPNET: gNetworkSystem = &gNetworkSystemCoopNet; break;
#endif
default: gNetworkSystem = &gNetworkSystemSocket; LOG_ERROR("Unknown network system: %d", nsType); break;
}
}
@ -123,6 +114,7 @@ bool network_init(enum NetworkType inNetworkType, bool reconnecting) {
gServerSettings.shareLives = configShareLives;
gServerSettings.enableCheats = configEnableCheats;
gServerSettings.bubbleDeath = configBubbleDeath;
gServerSettings.maxPlayers = configAmountofPlayers;
#if defined(RAPI_DUMMY) || defined(WAPI_DUMMY)
gServerSettings.headlessServer = (inNetworkType == NT_SERVER);
#else
@ -162,17 +154,15 @@ bool network_init(enum NetworkType inNetworkType, bool reconnecting) {
gChangeLevelTransition = gLevelValues.entryLevel;
}
#ifdef DISCORD_SDK
if (gNetworkSystem == &gNetworkSystemDiscord) {
discord_activity_update(true);
}
#endif
djui_chat_box_create();
}
configfile_save(configfile_name());
#ifdef DISCORD_SDK
discord_activity_update();
#endif
LOG_INFO("initialized");
return true;
@ -623,11 +613,6 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnect
gNetworkType = NT_NONE;
}
#ifdef DISCORD_SDK
network_set_system(NS_DISCORD);
#endif
if (exiting) { return; }
// reset other stuff
@ -689,4 +674,8 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnect
gDjuiInMainMenu = true;
djui_panel_main_create(NULL);
}
#ifdef DISCORD_SDK
discord_activity_update();
#endif
}

View file

@ -36,7 +36,6 @@ extern struct MarioState gMarioStates[];
enum NetworkSystemType {
NS_SOCKET,
NS_DISCORD,
NS_COOPNET,
NS_MAX,
};
@ -51,6 +50,8 @@ struct NetworkSystem {
bool (*match_addr)(void* addr1, void* addr2);
void (*update)(void);
int (*send)(u8 localIndex, void* addr, u8* data, u16 dataLength);
void (*get_lobby_id)(char* destination, u32 destLength);
void (*get_lobby_secret)(char* destination, u32 destLength);
void (*shutdown)(bool reconnecting);
bool requireServerBroadcast;
char* name;
@ -73,6 +74,7 @@ struct ServerSettings {
u8 enablePlayersInLevelDisplay;
u8 enablePlayerList;
u8 headlessServer;
u8 maxPlayers;
};
// Networking-specific externs

View file

@ -11,6 +11,9 @@
#include "game/object_helpers.h"
#include "pc/lua/smlua_hooks.h"
#include "lag_compensation.h"
#ifdef DISCORD_SDK
#include "pc/discord/discord.h"
#endif
struct NetworkPlayer gNetworkPlayers[MAX_PLAYERS] = { 0 };
struct NetworkPlayer *gNetworkPlayerLocal = NULL;
@ -311,6 +314,9 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode
smlua_call_event_hooks_mario_param(HOOK_ON_PLAYER_CONNECTED, &gMarioStates[localIndex]);
#ifdef DISCORD_SDK
discord_activity_update();
#endif
return localIndex;
}
@ -360,6 +366,10 @@ u8 network_player_disconnected(u8 globalIndex) {
memset(np, 0, sizeof(struct NetworkPlayer));
#ifdef DISCORD_SDK
discord_activity_update();
#endif
return i;
}
return UNKNOWN_GLOBAL_INDEX;
@ -428,7 +438,7 @@ void network_player_update_course_level(struct NetworkPlayer* np, s16 courseNum,
}
// If this machine's player changed to a different location, then all of the other np locations are no longer valid
for (u32 i = 1; i < configAmountofPlayers; i++) {
for (u32 i = 1; i < MAX_PLAYERS; i++) {
struct NetworkPlayer* npi = &gNetworkPlayers[i];
if ((!npi->connected) || npi == gNetworkPlayerLocal) { continue; }
npi->currPositionValid = false;

View file

@ -1,6 +1,5 @@
#include <stdio.h>
#include "network_utils.h"
#include "discord/discord.h"
#include "game/mario_misc.h"
u8 network_global_index_from_local(u8 localIndex) {
@ -23,15 +22,6 @@ u8 network_local_index_from_global(u8 globalIndex) {
return globalIndex + ((globalIndex < gNetworkPlayerLocal->globalIndex) ? 1 : 0);
}
#ifdef DISCORD_SDK
char* network_discord_id_from_local_index(u8 localIndex) {
if (gNetworkSystem == &gNetworkSystemDiscord) { return gNetworkSystem->get_id_str(localIndex); }
#else
char* network_discord_id_from_local_index(UNUSED u8 localIndex) {
#endif
return NULL;
}
bool network_is_server(void) {
return gNetworkType == NT_SERVER;
}

View file

@ -7,8 +7,6 @@
u8 network_global_index_from_local(u8 localIndex);
u8 network_local_index_from_global(u8 globalIndex);
char* network_discord_id_from_local_index(u8 localIndex);
bool network_is_server(void);
bool network_is_moderator(void);

View file

@ -80,7 +80,7 @@ void network_send_join(struct Packet* joinRequestPacket) {
// figure out id
u8 globalIndex = joinRequestPacket->localIndex;
if (globalIndex == UNKNOWN_LOCAL_INDEX) {
for (u32 i = 1; i < configAmountofPlayers; i++) {
for (u32 i = 1; i < MAX_PLAYERS; i++) {
if (!gNetworkPlayers[i].connected) {
globalIndex = i;
break;
@ -119,6 +119,7 @@ void network_send_join(struct Packet* joinRequestPacket) {
packet_write(&p, &gServerSettings.enableCheats, sizeof(u8));
packet_write(&p, &gServerSettings.bubbleDeath, sizeof(u8));
packet_write(&p, &gServerSettings.headlessServer, sizeof(u8));
packet_write(&p, &gServerSettings.maxPlayers, sizeof(u8));
packet_write(&p, eeprom, sizeof(u8) * 512);
u8 modCount = string_linked_list_count(&gRegisteredMods);
@ -183,6 +184,7 @@ void network_receive_join(struct Packet* p) {
packet_read(p, &gServerSettings.enableCheats, sizeof(u8));
packet_read(p, &gServerSettings.bubbleDeath, sizeof(u8));
packet_read(p, &gServerSettings.headlessServer, sizeof(u8));
packet_read(p, &gServerSettings.maxPlayers, sizeof(u8));
packet_read(p, eeprom, sizeof(u8) * 512);
packet_read(p, &modCount, sizeof(u8));

View file

@ -180,6 +180,14 @@ static int ns_socket_send(u8 localIndex, void* address, u8* data, u16 dataLength
return rc;
}
static void ns_socket_get_lobby_id(char* destination, u32 destLength) {
snprintf(destination, destLength, "%s", ""); // TODO: we can probably hook this up
}
static void ns_socket_get_lobby_secret(char* destination, u32 destLength) {
snprintf(destination, destLength, "%s", ""); // TODO: we can probably hook this up
}
static void ns_socket_shutdown(UNUSED bool reconnecting) {
socket_shutdown(sCurSocket);
sCurSocket = INVALID_SOCKET;
@ -190,16 +198,18 @@ static void ns_socket_shutdown(UNUSED bool reconnecting) {
}
struct NetworkSystem gNetworkSystemSocket = {
.initialize = ns_socket_initialize,
.get_id = ns_socket_get_id,
.get_id_str = ns_socket_get_id_str,
.save_id = ns_socket_save_id,
.clear_id = ns_socket_clear_id,
.dup_addr = ns_socket_dup_addr,
.match_addr = ns_socket_match_addr,
.update = ns_socket_update,
.send = ns_socket_send,
.shutdown = ns_socket_shutdown,
.initialize = ns_socket_initialize,
.get_id = ns_socket_get_id,
.get_id_str = ns_socket_get_id_str,
.save_id = ns_socket_save_id,
.clear_id = ns_socket_clear_id,
.dup_addr = ns_socket_dup_addr,
.match_addr = ns_socket_match_addr,
.update = ns_socket_update,
.send = ns_socket_send,
.get_lobby_id = ns_socket_get_lobby_id,
.get_lobby_secret = ns_socket_get_lobby_secret,
.shutdown = ns_socket_shutdown,
.requireServerBroadcast = true,
.name = "Socket",
.name = "Socket",
};

View file

@ -2,8 +2,8 @@
#define VERSION_H
#define VERSION_TEXT "beta"
#define VERSION_NUMBER 33
#define MINOR_VERSION_NUMBER 1
#define VERSION_NUMBER 34
#define MINOR_VERSION_NUMBER 0
#define PATCH_VERSION_NUMBER 0
#define MAX_VERSION_LENGTH 10

View file

@ -43,9 +43,6 @@
#include "src/bass_audio/bass_audio_helpers.h"
#include "pc/lua/utils/smlua_audio_utils.h"
#ifdef DISCORDRPC
#include "pc/discord/discordrpc.h"
#endif
#include "pc/network/version.h"
#include "pc/network/socket/domain_res.h"
#include "pc/network/network_player.h"
@ -60,6 +57,10 @@
#include "menu/intro_geo.h"
#ifdef DISCORD_SDK
#include "pc/discord/discord.h"
#endif
OSMesg D_80339BEC;
OSMesgQueue gSIEventMesgQueue;
@ -246,9 +247,6 @@ void audio_shutdown(void) {
}
void game_deinit(void) {
#ifdef DISCORDRPC
discord_shutdown();
#endif
configfile_save(configfile_name());
controller_shutdown();
audio_custom_shutdown();
@ -396,14 +394,10 @@ void main_func(void) {
}
#endif
#ifdef DISCORDRPC
discord_init();
#endif
while (true) {
wm_api->main_loop(produce_one_frame);
#ifdef DISCORDRPC
discord_update_rich_presence();
#ifdef DISCORD_SDK
discord_update();
#endif
#ifdef DEBUG
fflush(stdout);