mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-20 04:31:09 +02:00
Add Switch OTA launcher with unified SD zip and quiet UI.
Ships a dual-NRO native launcher that checks GitHub Releases, updates both NROs from gen1recomp-*-switch.zip with matching NACP versions, and stays silent unless an update needs confirm.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
#ifndef GEN1_OTA_FS_H
|
||||
#define GEN1_OTA_FS_H
|
||||
|
||||
#include "ota_protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Read installed game version from sibling version.txt or NRO nacp-less stamp file.
|
||||
* Expects switch/gen1recomp/version.txt containing X.Y.Z. Returns 0 on success. */
|
||||
int ota_fs_read_installed_version(const char *install_dir, char *out, size_t out_len);
|
||||
|
||||
/* SHA-256 hex (lowercase) of file. Returns 0 on success. */
|
||||
int ota_fs_sha256_file(const char *path, char *out_hex, size_t out_len);
|
||||
|
||||
/* Apply verified temp payload (extracted game NRO) using atomic plan. Returns 0 on success. */
|
||||
int ota_fs_atomic_replace_game(const char *install_dir, const char *verified_game_nro,
|
||||
char *err, size_t err_len);
|
||||
|
||||
/* Atomically replace any named NRO under install_dir (copy→.part→rename). */
|
||||
int ota_fs_atomic_replace_nro(const char *install_dir, const char *nro_name,
|
||||
const char *verified_nro, char *err, size_t err_len);
|
||||
|
||||
/* Hand off to game NRO via envSetNextLoad (Switch) or no-op stub (host). */
|
||||
int ota_fs_handoff_to_game(const char *game_nro_path, char *err, size_t err_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef GEN1_OTA_NET_H
|
||||
#define GEN1_OTA_NET_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Download URL into memory buffer (caller frees *out). Returns 0 on success. */
|
||||
int ota_net_download_buffer(const char *url, long timeout_ms, char **out, size_t *out_len,
|
||||
char *err, size_t err_len);
|
||||
|
||||
/* Download URL to a filesystem path. Returns 0 on success. */
|
||||
int ota_net_download_file(const char *url, const char *path, long timeout_ms, char *err,
|
||||
size_t err_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
#ifndef GEN1_OTA_PROTOCOL_H
|
||||
#define GEN1_OTA_PROTOCOL_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OTA_CHECK_TIMEOUT_SEC 6
|
||||
#define OTA_GAME_NRO_NAME "gen1recomp-game.nro"
|
||||
#define OTA_LAUNCHER_NRO_NAME "gen1recomp.nro"
|
||||
#define OTA_SAVE_DIR_NAME "pokemon-love2d"
|
||||
#define OTA_INSTALL_DIR "switch/gen1recomp"
|
||||
#define OTA_RELEASES_API \
|
||||
"https://api.github.com/repos/bryanthaboi/gen1recomp/releases/latest"
|
||||
|
||||
/* Mirrors src/update/SwitchOta.lua — keep semantics in lockstep. */
|
||||
|
||||
int ota_compare_semver(const char *a, const char *b);
|
||||
int ota_is_ota_asset_name(const char *name);
|
||||
int ota_version_from_ota_asset(const char *name, char *out, size_t out_len);
|
||||
|
||||
typedef struct {
|
||||
int ok; /* 1 on success */
|
||||
char reason[64];
|
||||
char tag[64];
|
||||
char version[32];
|
||||
char asset_name[128];
|
||||
char download_url[512];
|
||||
} ota_release_t;
|
||||
|
||||
int ota_parse_release(const char *json_text, ota_release_t *out);
|
||||
|
||||
typedef struct {
|
||||
char status[32]; /* uptodate | available | error */
|
||||
char reason[64];
|
||||
char version[32];
|
||||
char asset_name[128];
|
||||
char download_url[512];
|
||||
} ota_decision_t;
|
||||
|
||||
void ota_decide_update(const char *installed_version, const ota_release_t *release,
|
||||
ota_decision_t *out);
|
||||
|
||||
/* sums: newline-separated sha256sums.txt body */
|
||||
int ota_lookup_sum(const char *sums_text, const char *asset_name, char *out_hex,
|
||||
size_t out_len);
|
||||
|
||||
typedef struct {
|
||||
int ok;
|
||||
char reason[64];
|
||||
} ota_verify_t;
|
||||
|
||||
void ota_verify_sha256(const char *asset_name, const char *actual_hex,
|
||||
const char *sums_text, ota_verify_t *out);
|
||||
|
||||
typedef struct {
|
||||
char steps[5][520]; /* human-readable ops */
|
||||
char preserve[256];
|
||||
char forbidden_delete[256];
|
||||
char forbidden_direct[256];
|
||||
char part_path[256];
|
||||
char game_nro[240];
|
||||
char launcher_nro[240];
|
||||
char launcher_part[256];
|
||||
char next_load[240];
|
||||
} ota_apply_plan_t;
|
||||
|
||||
void ota_plan_atomic_apply(const char *install_dir, const char *verified_temp,
|
||||
ota_apply_plan_t *out);
|
||||
|
||||
typedef struct {
|
||||
char action[32]; /* play_installed | keep_checking */
|
||||
char reason[64];
|
||||
char message[128];
|
||||
} ota_offline_t;
|
||||
|
||||
typedef struct {
|
||||
int user_skip;
|
||||
int network_ok; /* 0 = offline/fail, 1 = ok, -1 = unknown */
|
||||
int api_error;
|
||||
} ota_offline_events_t;
|
||||
|
||||
void ota_offline_policy(double elapsed_sec, const ota_offline_events_t *events,
|
||||
ota_offline_t *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GEN1_OTA_PROTOCOL_H */
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef GEN1_OTA_UNZIP_H
|
||||
#define GEN1_OTA_UNZIP_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Extract member_name from zip_path into dest_path.
|
||||
* Tries exact member_name, then common prefixes (switch/gen1recomp/).
|
||||
* Returns 0 on success. */
|
||||
int ota_unzip_extract_file(const char *zip_path, const char *member_name, const char *dest_path,
|
||||
char *err, size_t err_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user