diff --git a/Makefile b/Makefile index 4d851ef32..9fd07ee04 100644 --- a/Makefile +++ b/Makefile @@ -443,7 +443,7 @@ TOOLS_DIR := tools # on tools and assets, and we use directory globs further down # in the makefile that we want should cover assets.) -PYTHON := py +PYTHON := python3 ifeq ($(filter clean distclean print-%,$(MAKECMDGOALS)),) @@ -483,10 +483,6 @@ BUILD_DIR_BASE := build # BUILD_DIR is the location where all build artifacts are placed BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_pc -ifeq ($(HEADLESS),1) -BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_headless -endif - ifeq ($(WINDOWS_BUILD),1) EXE := $(BUILD_DIR)/sm64coopdx.exe else # Linux builds/binary namer diff --git a/README.md b/README.md index fc81b4b17..24a521c11 100644 --- a/README.md +++ b/README.md @@ -1 +1,18 @@ -Custom build of sm64coopdx to add helpful features for both dedicated server hosting and the client experience \ No newline at end of file +![sm64coopdx Logo](textures/segment2/custom_coopdx_logo.rgba32.png) + +sm64coopdx is an online multiplayer project for the Super Mario 64 PC port that synchronizes all entities and every level for multiple players. The project was started by the Coop Deluxe Team. The purpose is to actively maintain and improve, but also continue sm64ex-coop, created by djoslin0. More features, customization, and power to the Lua API allow modders and players to enjoy Super Mario 64 more than ever! + +Feel free to report bugs or contribute to the project. + +## Initial Goal (Accomplished) +Create a mod for the PC port where multiple people can play together online. + +Unlike previous multiplayer projects, this one synchronizes enemies and events. This allows players to interact with the same world at the same time. + +Interestingly enough though, the goal of the project has slowly evolved over time from simply just making a Super Mario 64 multiplayer mod to constantly maintaining and improving the project (notably the Lua API.) + +## Lua +sm64coopdx is moddable via Lua, similar to Roblox and Garry's Mod's Lua APIs. To get started, click [here](docs/lua/lua.md) to see the Lua documentation. + +## Wiki +The wiki is made using GitHub's wiki feature, you can go to the wiki tab or click [here](https://github.com/coop-deluxe/sm64coopdx/wiki). \ No newline at end of file diff --git a/extract_assets.py b/extract_assets.py index 6ecc3dc34..160fb7c66 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -174,7 +174,7 @@ def main(): if mio0 == "@sound": rom = roms[lang] args = [ - "py", + "python3", "tools/disassemble_sound.py", "baserom." + lang + ".z64", ] diff --git a/src/pc/cliopts.c b/src/pc/cliopts.c index 26a5ef81c..2493b05c5 100644 --- a/src/pc/cliopts.c +++ b/src/pc/cliopts.c @@ -68,10 +68,6 @@ bool parse_cli_opts(int argc, char* argv[]) { gCLIOpts.fullscreen = 2; } else if (!strcmp(argv[i], "--skip-intro")) { gCLIOpts.skipIntro = true; - } else if (!strcmp(argv[i], "--network") && (i + 1) < argc) { - arg_uint("--network ", argv[++i], &gCLIOpts.netSystemType); - } else if (!strcmp(argv[i], "--maxplayers") && (i + 1) < argc) { - arg_uint("--maxplayers ", argv[++i], &gCLIOpts.maxPlayers); } else if (!strcmp(argv[i], "--server") && (i + 1) < argc) { gCLIOpts.network = NT_SERVER; arg_uint("--server ", argv[++i], &gCLIOpts.networkPort); @@ -85,12 +81,6 @@ bool parse_cli_opts(int argc, char* argv[]) { } } else if (!strcmp(argv[i], "--playername") && (i + 1) < argc) { arg_string("--playername", argv[++i], gCLIOpts.playerName, MAX_CONFIG_STRING); - } else if (!strcmp(argv[i],"--servername") && (i + 1) < argc) { - arg_string("--servername", argv[++i], gCLIOpts.coopnetName, MAX_CONFIG_STRING); - } else if (!strcmp(argv[i],"--serverdesc") && (i + 1) < argc) { - arg_string("--serverdesc", argv[++i], gCLIOpts.coopnetDesc, 1024); - } else if (!strcmp(argv[i],"--serverpass") && (i + 1) < argc) { - arg_string("--serverpass", argv[++i], gCLIOpts.coopnetPass, 64); } else if (!strcmp(argv[i], "--skip-update-check")) { gCLIOpts.skipUpdateCheck = true; } else if (!strcmp(argv[i], "--help")) { diff --git a/src/pc/cliopts.h b/src/pc/cliopts.h index ff1fe06e7..98b1abfbe 100644 --- a/src/pc/cliopts.h +++ b/src/pc/cliopts.h @@ -22,14 +22,9 @@ struct CLIOptions { unsigned int fullscreen; bool skipIntro; enum NetworkType network; - unsigned int netSystemType; unsigned int networkPort; - unsigned int maxPlayers; char joinIp[IP_MAX_LEN]; char playerName[MAX_CONFIG_STRING]; - char coopnetName[MAX_CONFIG_STRING]; - char coopnetDesc[1024]; - char coopnetPass[64]; bool hideLoadingScreen; bool skipUpdateCheck; }; diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 996d8bede..aa080e1e7 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -17,8 +17,6 @@ #define DEFAULT_COOPNET_IP "net.coop64.us" #define DEFAULT_COOPNET_PORT 34197 -#define DEVELOPMENT - typedef struct { unsigned int x, y, w, h; bool vsync; diff --git a/src/pc/lua/utils/smlua_audio_utils.c b/src/pc/lua/utils/smlua_audio_utils.c index 23574202c..d818ea1ce 100644 --- a/src/pc/lua/utils/smlua_audio_utils.c +++ b/src/pc/lua/utils/smlua_audio_utils.c @@ -169,12 +169,10 @@ static struct DynamicPool *sModAudioPool; static void smlua_audio_custom_init(void) { sModAudioPool = dynamic_pool_init(); - #ifndef NO_AUDIO ma_result result = ma_engine_init(NULL, &sModAudioEngine); if (result != MA_SUCCESS) { LOG_ERROR("failed to init Miniaudio: %d", result); } - #endif } static struct ModAudio* find_mod_audio(struct ModFile* file) { @@ -189,9 +187,6 @@ static struct ModAudio* find_mod_audio(struct ModFile* file) { } static bool audio_sanity_check(struct ModAudio* audio, bool isStream, const char* action) { - #ifdef NO_AUDIO - return false; - #endif if (!audio || !audio->loaded) { LOG_LUA_LINE("Tried to %s unloaded audio %s", action, audio ? (audio->isStream ? "stream" : "sample") : "(NULL)"); return false; @@ -270,7 +265,6 @@ struct ModAudio* audio_load_internal(const char* filename, bool isStream) { audio->file = modFile; // load audio - #ifndef NO_AUDIO FILE *f = f_open_r(modFile->cachedPath); if (!f) { LOG_ERROR("failed to load audio file '%s': file not found", filename); @@ -321,7 +315,6 @@ struct ModAudio* audio_load_internal(const char* filename, bool isStream) { audio->bufferSize = size; audio->isStream = isStream; audio->loaded = true; - #endif return audio; } diff --git a/src/pc/network/coopnet/coopnet.c b/src/pc/network/coopnet/coopnet.c index 90fa84013..57eb5877b 100644 --- a/src/pc/network/coopnet/coopnet.c +++ b/src/pc/network/coopnet/coopnet.c @@ -186,17 +186,6 @@ static void coopnet_populate_description(void) { buffer += versionLength; bufferLength -= versionLength; - //this will probably result in a buffer overflow - int customDescLen = strlen(gCLIOpts.coopnetDesc); - if (customDescLen > 0) { - snprintf(buffer, bufferLength, "\n\n"); - buffer += 2; - bufferLength -= 2; - snprintf(buffer, bufferLength, "%s", gCLIOpts.coopnetDesc); - buffer += customDescLen; - bufferLength -= customDescLen; - } - // get mod strings if (gActiveMods.entryCount <= 0) { return; } char* strings[gActiveMods.entryCount]; @@ -215,10 +204,6 @@ static void coopnet_populate_description(void) { str_seperator_concat(buffer, bufferLength, strings, gActiveMods.entryCount, "\\#dcdcdc\\\n"); } -const char* coopnet_ServerName() { - return strlen(gCLIOpts.coopnetName) > 0 ? gCLIOpts.coopnetName : configPlayerName; -} - void ns_coopnet_update(void) { if (!coopnet_is_connected()) { return; } @@ -230,12 +215,12 @@ void ns_coopnet_update(void) { if (sReconnecting) { LOG_INFO("Update lobby"); coopnet_populate_description(); - coopnet_lobby_update(sLocalLobbyId, GAME_NAME, get_version_online(), coopnet_ServerName(), mode, sCoopNetDescription); + coopnet_lobby_update(sLocalLobbyId, GAME_NAME, get_version_online(), configPlayerName, mode, sCoopNetDescription); } else { LOG_INFO("Create lobby"); snprintf(gCoopNetPassword, 64, "%s", configPassword); coopnet_populate_description(); - coopnet_lobby_create(GAME_NAME, get_version_online(), coopnet_ServerName(), mode, (uint16_t)configAmountofPlayers, gCoopNetPassword, sCoopNetDescription); + coopnet_lobby_create(GAME_NAME, get_version_online(), configPlayerName, mode, (uint16_t)configAmountofPlayers, gCoopNetPassword, sCoopNetDescription); } } else if (sNetworkType == NT_CLIENT) { LOG_INFO("Join lobby"); @@ -302,7 +287,7 @@ static CoopNetRc coopnet_initialize(void) { char* endptr = NULL; uint64_t destId = strtoull(configDestId, &endptr, 10); - CoopNetRc rc = coopnet_begin(configCoopNetIp, configCoopNetPort, coopnet_ServerName(), destId); + CoopNetRc rc = coopnet_begin(configCoopNetIp, configCoopNetPort, configPlayerName, destId); if (rc == COOPNET_FAILED) { djui_popup_create(DLANG(NOTIF, COOPNET_CONNECTION_FAILED), 2); } diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index 5b832bc41..1aa01d6c2 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -337,7 +337,6 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode construct_player_popup(np, DLANG(NOTIF, CONNECTED), NULL); } LOG_INFO("player connected, local %d, global %d", localIndex, np->globalIndex); - printf("%s connected\n",np->name); smlua_call_event_hooks_mario_param(HOOK_ON_PLAYER_CONNECTED, &gMarioStates[localIndex]); @@ -368,8 +367,6 @@ u8 network_player_disconnected(u8 globalIndex) { if (!np->connected) { continue; } if (np->globalIndex != globalIndex) { continue; } - printf("%s disconnected\n",np->name); - if (gNetworkType == NT_SERVER) { network_send_leaving(np->globalIndex); } np->connected = false; np->currCourseNum = -1; diff --git a/src/pc/network/packets/packet_chat.c b/src/pc/network/packets/packet_chat.c index 80c7fe5d1..232db8462 100644 --- a/src/pc/network/packets/packet_chat.c +++ b/src/pc/network/packets/packet_chat.c @@ -103,7 +103,6 @@ void network_receive_chat(struct Packet* p) { if (gNetworkSystem && gNetworkSystem->get_id_str && np->connected && strlen(np->name) > 0) { LOG_CONSOLE("[%s] %s: %s", gNetworkSystem->get_id_str(np->localIndex), np->name, remoteMessage); LOG_INFO("[%s] %s: %s", gNetworkSystem->get_id_str(np->localIndex), np->name, remoteMessage); - printf("[%s]: %s\n", np->name, remoteMessage); } else { LOG_INFO("rx chat: %s", remoteMessage); } diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index ed9ab1dee..663ab8f74 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -246,9 +246,6 @@ inline static void buffer_audio(void) { audio_api->play((u8 *)audioBuffer, 2 * numAudioSamples * 4); } -#include -pthread_mutex_t luaMutex = PTHREAD_MUTEX_INITIALIZER; - void produce_one_frame(void) { CTX_EXTENT(CTX_NETWORK, network_update); @@ -256,9 +253,7 @@ void produce_one_frame(void) { CTX_EXTENT(CTX_GAME_LOOP, game_loop_one_iteration); - pthread_mutex_lock(&luaMutex); CTX_EXTENT(CTX_SMLUA, smlua_update); - pthread_mutex_unlock(&luaMutex); CTX_EXTENT(CTX_AUDIO, buffer_audio); @@ -361,37 +356,6 @@ void* main_game_init(UNUSED void* dummy) { gGameInited = true; } -//used with console only -pthread_t mainLoopThread; - -void* mainLoopFunc(UNUSED void* dummy) { - while (true) { - debug_context_reset(); - CTX_BEGIN(CTX_TOTAL); - WAPI.main_loop(produce_one_frame); -#ifdef DISCORD_SDK - discord_update(); -#endif - mumble_update(); -#ifdef DEBUG - fflush(stdout); - fflush(stderr); -#endif - CTX_END(CTX_TOTAL); - -#ifdef DEVELOPMENT - djui_ctx_display_update(); -#endif - djui_lua_profiler_update(); - } -} - -#ifdef _WIN32 -#define clrscr() system("cls") -#else -#define clrscr() system("clear") -#endif - int main(int argc, char *argv[]) { // handle terminal arguments if (!parse_cli_opts(argc, argv)) { return 0; } @@ -488,15 +452,8 @@ int main(int argc, char *argv[]) { configJoinPort = gCLIOpts.networkPort; network_init(NT_CLIENT, false); } else if (gCLIOpts.network == NT_SERVER) { - //configNetworkSystem = NS_SOCKET; - configNetworkSystem = gCLIOpts.netSystemType; + configNetworkSystem = NS_SOCKET; configHostPort = gCLIOpts.networkPort; - - if (gCLIOpts.maxPlayers > 0) - configAmountofPlayers = gCLIOpts.maxPlayers; - - if (strlen(gCLIOpts.coopnetPass) > 0) - snprintf(configPassword,64,"%s",gCLIOpts.coopnetPass); // horrible, hacky fix for mods that access marioObj straight away // best fix: host with the standard main menu method @@ -510,60 +467,25 @@ int main(int argc, char *argv[]) { } // main loop - if (gCLIOpts.console && gCLIOpts.network == NT_SERVER) { - pthread_create(&mainLoopThread, NULL, mainLoopFunc, NULL); - char input[256]; - while (true) { - //read console input - fgets(input,256,stdin); - input[strcspn(input, "\n")] = '\0'; - - if (strlen(input) > 1) { - if (!strcmp(input,"stop")) { - printf("Server shutting down..."); - network_shutdown(true,true,false,false); - break; - } - /*else if (!strcmp(input,"restart")) { - printf("Restarting..."); - network_reset_reconnect_and_rehost(); - network_shutdown(false, false, false, true); - static struct Object sHackyObject = { 0 }; - gMarioStates[0].marioObj = &sHackyObject; - network_init(NT_SERVER,true); - }*/ - else if (!memcmp(input,"clear",5)) { - clrscr(); - continue; - } - else if (!memcmp(input,"say ",4) && strlen(input) > 4) { - network_send_chat(&input[4], gNetworkPlayerLocal->globalIndex); - continue; - } - else if (!memcmp(input,"luaf ",5) && strlen(input) > 5) { - pthread_mutex_lock(&luaMutex); - smlua_exec_file(&input[5]); - pthread_mutex_unlock(&luaMutex); - continue; - } - else if (!memcmp(input,"lua ",4) && strlen(input) > 4) { - pthread_mutex_lock(&luaMutex); - smlua_exec_str(&input[4]); - pthread_mutex_unlock(&luaMutex); - continue; - } - - //try chat commands - pthread_mutex_lock(&luaMutex); - extern bool exec_chat_command(char* command); - exec_chat_command(input); - pthread_mutex_unlock(&luaMutex); - } - } - } - else { - mainLoopFunc(NULL); - } + while (true) { + debug_context_reset(); + CTX_BEGIN(CTX_TOTAL); + WAPI.main_loop(produce_one_frame); +#ifdef DISCORD_SDK + discord_update(); +#endif + mumble_update(); +#ifdef DEBUG + fflush(stdout); + fflush(stderr); +#endif + CTX_END(CTX_TOTAL); + +#ifdef DEVELOPMENT + djui_ctx_display_update(); +#endif + djui_lua_profiler_update(); + } return 0; } diff --git a/tools/asm_processor/build.py b/tools/asm_processor/build.py index e221bac9e..228dcb030 100644 --- a/tools/asm_processor/build.py +++ b/tools/asm_processor/build.py @@ -6,7 +6,7 @@ import subprocess import tempfile dir_path = os.path.dirname(os.path.realpath(__file__)) -asm_processor = ['py', os.path.join(dir_path, "asm-processor.py")] +asm_processor = ['python3', os.path.join(dir_path, "asm-processor.py")] prelude = os.path.join(dir_path, "prelude.inc") all_args = sys.argv[1:] diff --git a/tools/assemble_sound.py b/tools/assemble_sound.py index efa3f7885..f0918bb82 100755 --- a/tools/assemble_sound.py +++ b/tools/assemble_sound.py @@ -754,7 +754,7 @@ def serialize_seqfile( out_offsets_filename = out_filename.replace('sound_data.tbl', 'samples_offsets.inc.c') with open(out_offsets_filename, "w") as f: for fname in asset_offsets: - macro_name = 'SAMPLE_' + fname.split('/samples/')[-1].replace('/', '_').replace('.', '_').replace('-', '_').replace("\\","_") + macro_name = 'SAMPLE_' + fname.split('/samples/')[-1].replace('/', '_').replace('.', '_').replace('-', '_') f.write(f'#define {macro_name} {hex(asset_offsets[fname] + data_start)} // {fname}\n') if out_filename.endswith('sequences.bin'):