[WIP] Update checker

This commit is contained in:
Agent X 2024-03-07 17:33:43 -05:00
parent fd6dd9bd2c
commit 91eb1966a0
15 changed files with 229 additions and 18 deletions

View File

@ -904,6 +904,13 @@ endif
# Zlib
LDFLAGS += -lz
# Update checker library
ifeq ($(WINDOWS_BUILD),1)
LDFLAGS += -lwininet
else
LDFLAGS += -lcurl
endif
# Lua
ifeq ($(WINDOWS_BUILD),1)
ifeq ($(TARGET_BITS), 32)
@ -927,7 +934,7 @@ else
LDFLAGS += -Llib/lua/linux -l:liblua53.a -ldl
endif
# coopnet
# CoopNet
COOPNET_LIBS :=
ifeq ($(COOPNET),1)
ifeq ($(WINDOWS_BUILD),1)

View File

@ -12605,7 +12605,7 @@ MINOR_VERSION_NUMBER = 1
PATCH_VERSION_NUMBER = 0
--- @type string
SM64COOPDX_VERSION = "v0.1.4"
SM64COOPDX_VERSION = "0.1.5"
--- @type integer
VERSION_NUMBER = 36

View File

@ -28,6 +28,9 @@ COOPNET_VERSION = "\\#ffa0a0\\Your version is no longer compatible with CoopNet.
PEER_FAILED = "\\#ffa0a0\\Failed to connect to player '@'"
UNKNOWN = "unknown"
LOBBY_HOST = "the lobby's host"
UPDATE_AVAILABLE = "A new update is available!"
LATEST_VERSION = "Latest version"
YOUR_VERSION = "Your version"
[CHAT]
KICKING = "Kicking '@'!"

View File

@ -290,7 +290,7 @@ static void crash_handler_add_info_str(CrashHandlerText** pTextP, f32 x, f32 y,
static void crash_handler_add_version_str(CrashHandlerText** pTextP, f32 x, f32 y) {
CrashHandlerText* pText = *pTextP;
crash_handler_set_text(x, y, 0xFF, 0xFF, 0x00, "%s", "sm64coopdx ");
crash_handler_set_text(x, y, 0xFF, 0xFF, 0x00, "%s", "sm64coopdx v");
crash_handler_set_text(-1, y, 0x00, 0xFF, 0xFF, "%s", SM64COOPDX_VERSION);
*pTextP = pText;
}

View File

@ -10,6 +10,7 @@
#include "pc/network/network.h"
#include "pc/utils/misc.h"
#include "pc/configfile.h"
#include "pc/update_checker.h"
static struct DjuiRect* sRectPort = NULL;
static struct DjuiRect* sRectPassword = NULL;
@ -201,6 +202,14 @@ void djui_panel_host_create(struct DjuiBase* caller) {
? &button1->base
: &button2->base;
}
if (gUpdateMessage) {
struct DjuiText* message = djui_text_create(&panel->base, DLANG(NOTIF, UPDATE_AVAILABLE));
djui_base_set_size_type(&message->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&message->base, 1.0f, 1.0f);
djui_base_set_color(&message->base, 255, 255, 160, 255);
djui_text_set_alignment(message, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM);
}
}
djui_panel_add(caller, panel, defaultBase);

View File

@ -6,6 +6,7 @@
#include "djui_panel_join_direct.h"
#include "pc/network/network.h"
#include "pc/utils/misc.h"
#include "pc/update_checker.h"
#ifdef DISCORD_SDK
#include "pc/discord/discord.h"
#endif
@ -38,6 +39,14 @@ void djui_panel_join_create(struct DjuiBase* caller) {
djui_button_create(body, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back);
}
if (gUpdateMessage) {
struct DjuiText* message = djui_text_create(&panel->base, DLANG(NOTIF, UPDATE_AVAILABLE));
djui_base_set_size_type(&message->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&message->base, 1.0f, 1.0f);
djui_base_set_color(&message->base, 255, 255, 160, 255);
djui_text_set_alignment(message, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM);
}
djui_panel_add(caller, panel, NULL);
#endif
}

View File

@ -7,6 +7,7 @@
#include "djui_panel_confirm.h"
#include "src/pc/controller/controller_sdl.h"
#include "src/pc/pc_main.h"
#include "src/pc/update_checker.h"
extern ALIGNED8 u8 texture_coopdx_logo[];
@ -46,11 +47,20 @@ void djui_panel_main_create(struct DjuiBase* caller) {
djui_base_set_location(&button4->base, 0, -30.0f);
}
struct DjuiText* version = djui_text_create(&panel->base, SM64COOPDX_VERSION);
djui_base_set_size_type(&version->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&version->base, 1.0f, 1.0f);
djui_base_set_color(&version->base, 50, 50, 50, 255);
djui_text_set_alignment(version, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM);
// these two cannot co-exist for some reason
if (gUpdateMessage) {
struct DjuiText* message = djui_text_create(&panel->base, DLANG(NOTIF, UPDATE_AVAILABLE));
djui_base_set_size_type(&message->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&message->base, 1.0f, 1.0f);
djui_base_set_color(&message->base, 255, 255, 160, 255);
djui_text_set_alignment(message, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM);
} else {
struct DjuiText* version = djui_text_create(&panel->base, get_version_dx());
djui_base_set_size_type(&version->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&version->base, 1.0f, 1.0f);
djui_base_set_color(&version->base, 50, 50, 50, 255);
djui_text_set_alignment(version, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM);
}
}
djui_panel_add(caller, panel, NULL);

View File

@ -4396,7 +4396,7 @@ char gSmluaConstants[] = ""
"COOP_OBJ_FLAG_LUA = (1 << 1)\n"
"COOP_OBJ_FLAG_NON_SYNC = (1 << 2)\n"
"COOP_OBJ_FLAG_INITIALIZED = (1 << 3)\n"
"SM64COOPDX_VERSION = 'v0.1.4'\n"
"SM64COOPDX_VERSION = '0.1.5'\n"
"VERSION_TEXT = 'beta'\n"
"VERSION_NUMBER = 36\n"
"MINOR_VERSION_NUMBER = 1\n"

View File

@ -193,7 +193,7 @@ static u32 mods_count_directory(char* modsBasePath) {
}
static void mods_load(struct Mods* mods, char* modsBasePath, bool isUserModPath) {
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs in %s mod path:\n\\#808080\\%s", isUserModPath ? "user" : "local", modsBasePath)); }
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs In %s Mod Path:\n\\#808080\\%s", isUserModPath ? "User" : "Local", modsBasePath)); }
// generate bins
dynos_generate_packs(modsBasePath);
@ -223,7 +223,7 @@ static void mods_load(struct Mods* mods, char* modsBasePath, bool isUserModPath)
}
f32 count = (f32) mods_count_directory(modsBasePath);
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading mods in %s mod path:\n\\#808080\\%s", isUserModPath ? "user" : "local", modsBasePath)); }
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading Mods In %s Mod Path:\n\\#808080\\%s", isUserModPath ? "User" : "Local", modsBasePath)); }
// iterate
char path[SYS_MAX_PATH] = { 0 };
@ -232,7 +232,7 @@ static void mods_load(struct Mods* mods, char* modsBasePath, bool isUserModPath)
// sanity check / fill path[]
if (!directory_sanity_check(dir, modsBasePath, path)) { continue; }
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading mod:\n\\#808080\\%s/%s", modsBasePath, dir->d_name)); }
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading Mod:\n\\#808080\\%s/%s", modsBasePath, dir->d_name)); }
// load the mod
if (!mod_load(mods, modsBasePath, dir->d_name)) {

View File

@ -7,6 +7,7 @@
static char sVersionString[MAX_VERSION_LENGTH] = { 0 };
static char sLocalVersionString[MAX_LOCAL_VERSION_LENGTH] = { 0 };
static char sDxVersionString[MAX_VERSION_LENGTH] = { 0 };
const char* get_version(void) {
if (configCoopCompatibility) {
@ -25,9 +26,9 @@ const char* get_version(void) {
#endif
} else {
#if defined(VERSION_US)
snprintf(sVersionString, MAX_VERSION_LENGTH, "%s", SM64COOPDX_VERSION);
snprintf(sVersionString, MAX_VERSION_LENGTH, "v%s", SM64COOPDX_VERSION);
#else
snprintf(sVersionString, MAX_VERSION_LENGTH, "%s %s", SM64COOPDX_VERSION, VERSION_REGION);
snprintf(sVersionString, MAX_VERSION_LENGTH, "v%s %s", SM64COOPDX_VERSION, VERSION_REGION);
#endif
}
return sVersionString;
@ -46,15 +47,26 @@ const char* get_version_local(void) {
#endif
} else {
#if defined(VERSION_US)
snprintf(sLocalVersionString, MAX_LOCAL_VERSION_LENGTH, "%s", SM64COOPDX_VERSION);
snprintf(sLocalVersionString, MAX_LOCAL_VERSION_LENGTH, "v%s", SM64COOPDX_VERSION);
#else
snprintf(sLocalVersionString, MAX_LOCAL_VERSION_LENGTH, "%s %s", VERSION_TEXT, SM64COOPDX_VERSION, VERSION_REGION);
snprintf(sLocalVersionString, MAX_LOCAL_VERSION_LENGTH, "v%s %s", VERSION_TEXT, SM64COOPDX_VERSION, VERSION_REGION);
#endif
}
return sLocalVersionString;
}
// I want to redo this whole file when I remove sm64ex-coop compatibility
const char* get_version_dx(void) {
#if defined(VERSION_US)
snprintf(sDxVersionString, MAX_LOCAL_VERSION_LENGTH, "v%s", SM64COOPDX_VERSION);
#else
snprintf(sDxVersionString, MAX_LOCAL_VERSION_LENGTH, "v%s %s", VERSION_TEXT, SM64COOPDX_VERSION, VERSION_REGION);
#endif
return sDxVersionString;
}
const char* get_game_name(void) {
if (configCoopCompatibility) {
#ifdef DEVELOPMENT

View File

@ -1,7 +1,7 @@
#ifndef VERSION_H
#define VERSION_H
#define SM64COOPDX_VERSION "v0.1.4"
#define SM64COOPDX_VERSION "0.1.5"
#define VERSION_TEXT "beta"
#define VERSION_NUMBER 36
@ -22,6 +22,7 @@
#define MAX_LOCAL_VERSION_LENGTH 36
const char* get_version(void);
const char* get_version_local(void);
const char* get_version_dx(void);
const char* get_game_name(void);
#endif

View File

@ -39,6 +39,7 @@
#include "pc/network/version.h"
#include "pc/network/socket/domain_res.h"
#include "pc/network/network_player.h"
#include "pc/update_checker.h"
#include "pc/djui/djui.h"
#include "pc/djui/djui_unicode.h"
#include "pc/djui/djui_panel.h"
@ -278,6 +279,9 @@ void* main_game_init(UNUSED void* arg) {
configfile_load();
configWindow.settings_changed = true;
if (!djui_language_init(configLanguage)) { snprintf(configLanguage, MAX_CONFIG_STRING, "%s", ""); }
check_for_updates();
dynos_packs_init();
sync_objects_init_system();
@ -369,6 +373,8 @@ int main(int argc, char *argv[]) {
djui_init_late();
djui_console_message_dequeue();
show_update_popup();
// Init network
if (gCLIOpts.Network == NT_CLIENT) {
network_set_system(NS_SOCKET);

View File

@ -60,7 +60,7 @@ extern "C" {
#ifdef GIT_HASH
#define TITLE ({ char title[96] = ""; snprintf(title, 96, "sm64coopdx [%s]", GIT_HASH); title; })
#else
#define TITLE ({ char title[96] = ""; snprintf(title, 96, "sm64coopdx %s", SM64COOPDX_VERSION); title; })
#define TITLE ({ char title[96] = ""; snprintf(title, 96, "sm64coopdx v%s", SM64COOPDX_VERSION); title; })
#endif
#define AT_STARTUP __attribute__((constructor))

143
src/pc/update_checker.c Normal file
View File

@ -0,0 +1,143 @@
#include <stdio.h>
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <wininet.h>
#else
#include <curl/curl.h>
#endif
#include "update_checker.h"
#include "pc/djui/djui.h"
#include "pc/network/version.h"
#include "pc/loading.h"
#define URL "https://sm64coopdx.com/download/version.txt"
static char sVersionUpdateTextBuffer[256] = { 0 };
static char sRemoteVersion[8];
bool gUpdateMessage = false;
void show_update_popup(void) {
if (sVersionUpdateTextBuffer[0] == '\0') { return; }
djui_popup_create(sVersionUpdateTextBuffer, 3);
}
#if !(defined(_WIN32) || defined(_WIN64))
size_t write_callback(char *ptr, size_t size, size_t nmemb, char **data) {
size_t realsize = size * nmemb;
// allocate memory for the received data and copy it into the buffer
*data = realloc(*data, realsize + 1);
if (*data == NULL) { return 0; }
memcpy(*data, ptr, realsize);
(*data)[realsize] = '\0'; // null-terminate the string
return realsize;
}
#endif
// function to download a text file from the internet
const char* get_version_remote(void) {
#if defined(_WIN32) || defined(_WIN64)
HINTERNET hInternet, hUrl;
DWORD bytesRead;
char buffer[8];
// initialize WinINet
hInternet = InternetOpenA("sm64coopdx", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet) {
printf("Failed to check for updates!\n");
InternetCloseHandle(hInternet);
InternetCloseHandle(hUrl);
return NULL;
}
// open the URL
hUrl = InternetOpenUrlA(hInternet, URL, NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (!hUrl) {
printf("Failed to check for updates!\n");
InternetCloseHandle(hInternet);
InternetCloseHandle(hUrl);
return NULL;
}
// calculate the size of the file
DWORD contentLength;
DWORD dwSize = sizeof(contentLength);
HttpQueryInfo(hUrl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &contentLength, &dwSize, NULL);
// read data from the URL
if (!InternetReadFile(hUrl, buffer, sizeof(buffer), &bytesRead)) {
printf("Failed to check for updates!\n");
InternetCloseHandle(hInternet);
InternetCloseHandle(hUrl);
return NULL;
}
strncpy(sRemoteVersion, buffer, 8);
// close handles
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
#else
CURL *curl;
CURLcode res;
char *data = NULL;
// initialize libcurl
curl = curl_easy_init();
if (!curl) {
printf("Failed to check for updates!\n");
return NULL;
}
// set the URL to retrieve data from
curl_easy_setopt(curl, CURLOPT_URL, URL);
// set the write callback function to store received data into the buffer
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
// perform the request
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
printf("Failed to check for updates!\n");
curl_easy_cleanup(curl);
return NULL;
}
strncpy(sRemoteVersion, data, 8);
// Clean up
curl_easy_cleanup(curl);
#endif
return sRemoteVersion;
}
void check_for_updates(void) {
REFRESH_MUTEX(
gCurrLoadingSegment.percentage = 0;
snprintf(gCurrLoadingSegment.str, 256, "Checking For Updates");
);
#if defined(_WIN32) || defined(_WIN64)
const char* remoteVersion = get_version_remote();
if (strcmp(get_version_remote(), SM64COOPDX_VERSION)) {
snprintf(
sVersionUpdateTextBuffer, 256,
"\\#ffffa0\\%s\n\\#dcdcdc\\%s: v%s\n%s: v%s",
DLANG(NOTIF, UPDATE_AVAILABLE),
DLANG(NOTIF, LATEST_VERSION),
remoteVersion,
DLANG(NOTIF, YOUR_VERSION),
SM64COOPDX_VERSION
);
gUpdateMessage = true;
}
#else
#endif
}

11
src/pc/update_checker.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _UPDATE_CHECKER_H
#define _UPDATE_CHECKER_H
#include <stdbool.h>
extern bool gUpdateMessage;
void show_update_popup(void);
void check_for_updates(void);
#endif