mirror of
https://github.com/pumpitupdev/pumptools.git
synced 2026-09-26 16:38:29 +03:00
Used the static array which always pointed to the first, nx2, entry instead of the dynamic ref that is determined on init and points to the correct mnt point info data accoring to the game version.
632 lines
20 KiB
C
632 lines
20 KiB
C
#define LOG_MODULE "patch-net-profile"
|
|
|
|
#include <pthread.h>
|
|
#include <string.h>
|
|
|
|
#include "asset/nx2/lib/usb-rank.h"
|
|
#include "asset/nx2/lib/usb-save.h"
|
|
#include "asset/nxa/lib/usb-rank.h"
|
|
#include "asset/nxa/lib/usb-save.h"
|
|
|
|
#include "capnhook/hook/filehook.h"
|
|
|
|
#include "pumpnet/lib/profile-token.h"
|
|
#include "pumpnet/lib/pumpnet.h"
|
|
|
|
#include "util/fs.h"
|
|
#include "util/log.h"
|
|
#include "util/time.h"
|
|
|
|
#define PUMPNET_MAX_NUM_PLAYERS 2
|
|
#define PUMPNET_PROFILE_FILE_NAME "pumpnet.bin"
|
|
#define PUMPNET_TRY_CONNECT_TIMEOUT_MS 2000
|
|
|
|
struct profile_virtual_mnt_point_file_info {
|
|
int player;
|
|
enum pumpnet_lib_file_type file_type;
|
|
const char* file_path;
|
|
size_t file_size;
|
|
};
|
|
|
|
struct profile_virtual_mnt_point_info {
|
|
struct {
|
|
struct profile_virtual_mnt_point_file_info file_info[PUMPNET_LIB_FILE_TYPE_COUNT];
|
|
} player[PUMPNET_MAX_NUM_PLAYERS];
|
|
};
|
|
|
|
struct profile_virtual_file {
|
|
uint64_t player_ref_id;
|
|
FILE* handle;
|
|
const struct profile_virtual_mnt_point_file_info* file_info;
|
|
size_t buffer_pos;
|
|
uint8_t* buffer;
|
|
bool is_written;
|
|
};
|
|
|
|
struct profile_virtual_mnt_point {
|
|
struct profile_virtual_file files[PUMPNET_LIB_FILE_TYPE_COUNT];
|
|
};
|
|
|
|
static enum cnh_result _patch_net_profile_filehook(struct cnh_filehook_irp* irp);
|
|
static enum cnh_result _patch_net_profile_fopen(struct cnh_filehook_irp* irp);
|
|
static enum cnh_result _patch_net_profile_fclose(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file);
|
|
static enum cnh_result _patch_net_profile_fread(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file);
|
|
static enum cnh_result _patch_net_profile_fwrite(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file);
|
|
static enum cnh_result _patch_net_profile_fseek(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file);
|
|
static enum cnh_result _patch_net_profile_ftell(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file);
|
|
static enum cnh_result _patch_net_profile_feof(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file);
|
|
|
|
static struct profile_virtual_file* _patch_net_profile_get_virtual_mnt_point(FILE* handle);
|
|
static bool _patch_net_profile_determine_is_profile_and_player_and_file_type(
|
|
struct cnh_filehook_irp* irp,
|
|
uint8_t* player,
|
|
enum pumpnet_lib_file_type* file_type);
|
|
static enum cnh_result _patch_net_profile_open_pumpnet_profile_file(
|
|
struct cnh_filehook_irp* irp,
|
|
uint8_t player,
|
|
enum pumpnet_lib_file_type file_type);
|
|
static bool _patch_net_profile_close_pumpnet_profile_file(struct profile_virtual_file* virtual_file);
|
|
|
|
static const struct profile_virtual_mnt_point_info _patch_net_profile_virtual_mnt_point_infos[] = {
|
|
{
|
|
.player = {
|
|
{
|
|
.file_info = {
|
|
{
|
|
.player = 0,
|
|
.file_type = PUMPNET_LIB_FILE_TYPE_SAVE,
|
|
.file_path = "/mnt/0/nx2save.bin",
|
|
.file_size = ASSET_NX2_USB_SAVE_SIZE
|
|
},
|
|
{
|
|
.player = 0,
|
|
.file_type = PUMPNET_LIB_FILE_TYPE_RANK,
|
|
.file_path = "/mnt/0/nx2rank.bin",
|
|
.file_size = ASSET_NX2_USB_RANK_SIZE
|
|
}
|
|
}
|
|
},
|
|
{
|
|
.file_info = {
|
|
{
|
|
.player = 1,
|
|
.file_type = PUMPNET_LIB_FILE_TYPE_SAVE,
|
|
.file_path = "/mnt/1/nx2save.bin",
|
|
.file_size = ASSET_NX2_USB_SAVE_SIZE
|
|
},
|
|
{
|
|
.player = 1,
|
|
.file_type = PUMPNET_LIB_FILE_TYPE_RANK,
|
|
.file_path = "/mnt/1/nx2rank.bin",
|
|
.file_size = ASSET_NX2_USB_RANK_SIZE
|
|
}
|
|
}
|
|
},
|
|
}
|
|
},
|
|
{
|
|
.player = {
|
|
{
|
|
.file_info = {
|
|
{
|
|
.player = 0,
|
|
.file_type = PUMPNET_LIB_FILE_TYPE_SAVE,
|
|
.file_path = "/mnt/0/nxasave.bin",
|
|
.file_size = ASSET_NXA_USB_SAVE_SIZE
|
|
},
|
|
{
|
|
.player = 0,
|
|
.file_type = PUMPNET_LIB_FILE_TYPE_RANK,
|
|
.file_path = "/mnt/0/nxarank.bin",
|
|
.file_size = ASSET_NXA_USB_RANK_SIZE
|
|
}
|
|
}
|
|
},
|
|
{
|
|
.file_info = {
|
|
{
|
|
.player = 1,
|
|
.file_type = PUMPNET_LIB_FILE_TYPE_SAVE,
|
|
.file_path = "/mnt/1/nxasave.bin",
|
|
.file_size = ASSET_NXA_USB_SAVE_SIZE
|
|
},
|
|
{
|
|
.player = 1,
|
|
.file_type = PUMPNET_LIB_FILE_TYPE_RANK,
|
|
.file_path = "/mnt/1/nxarank.bin",
|
|
.file_size = ASSET_NXA_USB_RANK_SIZE
|
|
}
|
|
}
|
|
},
|
|
}
|
|
}
|
|
};
|
|
|
|
static const struct profile_virtual_mnt_point_info* _patch_net_profile_file_info_ref;
|
|
static struct profile_virtual_mnt_point _patch_net_profile_virtual_mnt_points[PUMPNET_MAX_NUM_PLAYERS];
|
|
static pthread_mutex_t _patch_net_profile_mutex;
|
|
|
|
static enum cnh_result _patch_net_profile_filehook(struct cnh_filehook_irp* irp)
|
|
{
|
|
if (irp->op == CNH_FILEHOOK_IRP_OP_OPEN) {
|
|
return _patch_net_profile_fopen(irp);
|
|
} else {
|
|
struct profile_virtual_file* virt_file = _patch_net_profile_get_virtual_mnt_point(irp->file);
|
|
|
|
if (virt_file != NULL) {
|
|
switch (irp->op) {
|
|
case CNH_FILEHOOK_IRP_OP_CLOSE:
|
|
return _patch_net_profile_fclose(irp, virt_file);
|
|
|
|
case CNH_FILEHOOK_IRP_OP_READ:
|
|
return _patch_net_profile_fread(irp, virt_file);
|
|
|
|
case CNH_FILEHOOK_IRP_OP_WRITE:
|
|
return _patch_net_profile_fwrite(irp, virt_file);
|
|
|
|
case CNH_FILEHOOK_IRP_OP_FGETS:
|
|
log_die("Unsupported operation");
|
|
return CNH_RESULT_OTHER_ERROR;
|
|
|
|
case CNH_FILEHOOK_IRP_OP_SEEK:
|
|
return _patch_net_profile_fseek(irp, virt_file);
|
|
|
|
case CNH_FILEHOOK_IRP_OP_TELL:
|
|
return _patch_net_profile_ftell(irp, virt_file);
|
|
|
|
case CNH_FILEHOOK_IRP_OP_EOF:
|
|
return _patch_net_profile_feof(irp, virt_file);
|
|
|
|
default:
|
|
log_die("Unhandled switch case");
|
|
return CNH_RESULT_OTHER_ERROR;
|
|
}
|
|
} else {
|
|
return cnh_filehook_invoke_next(irp);
|
|
}
|
|
}
|
|
}
|
|
|
|
static enum cnh_result _patch_net_profile_fopen(struct cnh_filehook_irp* irp)
|
|
{
|
|
uint8_t player;
|
|
enum pumpnet_lib_file_type file_type;
|
|
player = -1;
|
|
file_type = PUMPNET_LIB_FILE_TYPE_COUNT;
|
|
|
|
// not a profile file, pass
|
|
if (!_patch_net_profile_determine_is_profile_and_player_and_file_type(irp, &player, &file_type)) {
|
|
return cnh_filehook_invoke_next(irp);
|
|
}
|
|
|
|
return _patch_net_profile_open_pumpnet_profile_file(irp, player, file_type);
|
|
}
|
|
|
|
static enum cnh_result _patch_net_profile_fclose(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file)
|
|
{
|
|
log_debug("fclose %s", virtual_file->file_info->file_path);
|
|
|
|
return _patch_net_profile_close_pumpnet_profile_file(virtual_file) ? CNH_RESULT_SUCCESS : CNH_RESULT_OTHER_ERROR;
|
|
}
|
|
|
|
static enum cnh_result _patch_net_profile_fread(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file)
|
|
{
|
|
uint32_t len;
|
|
|
|
pthread_mutex_lock(&_patch_net_profile_mutex);
|
|
|
|
log_debug("fread %s, pos 0x%X, bytes %d", virtual_file->file_info->file_path, virtual_file->buffer_pos,
|
|
irp->read.nbytes);
|
|
|
|
/* read up to eof, only */
|
|
if (virtual_file->buffer_pos + irp->read.nbytes < virtual_file->file_info->file_size) {
|
|
len = irp->read.nbytes;
|
|
} else {
|
|
len = virtual_file->file_info->file_size - virtual_file->buffer_pos;
|
|
}
|
|
|
|
memcpy(&irp->read.bytes[irp->read.pos], virtual_file->buffer + virtual_file->buffer_pos, len);
|
|
|
|
virtual_file->buffer_pos += len;
|
|
irp->read.pos += len;
|
|
|
|
pthread_mutex_unlock(&_patch_net_profile_mutex);
|
|
|
|
return CNH_RESULT_SUCCESS;
|
|
}
|
|
|
|
static enum cnh_result _patch_net_profile_fwrite(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file)
|
|
{
|
|
uint32_t len;
|
|
|
|
pthread_mutex_lock(&_patch_net_profile_mutex);
|
|
|
|
log_debug("fwrite %s, pos 0x%X, bytes %d", virtual_file->file_info->file_path, virtual_file->buffer_pos,
|
|
irp->read.nbytes);
|
|
|
|
/* write up to eof, only */
|
|
if (virtual_file->buffer_pos + irp->write.nbytes < virtual_file->file_info->file_size) {
|
|
len = irp->write.nbytes;
|
|
} else {
|
|
len = virtual_file->file_info->file_size - virtual_file->buffer_pos;
|
|
}
|
|
|
|
memcpy(virtual_file->buffer + virtual_file->buffer_pos, irp->write.bytes, len);
|
|
|
|
virtual_file->buffer_pos += len;
|
|
virtual_file->is_written = true;
|
|
irp->write.pos += len;
|
|
|
|
pthread_mutex_unlock(&_patch_net_profile_mutex);
|
|
|
|
return CNH_RESULT_SUCCESS;
|
|
}
|
|
|
|
static enum cnh_result _patch_net_profile_fseek(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file)
|
|
{
|
|
pthread_mutex_lock(&_patch_net_profile_mutex);
|
|
|
|
switch (irp->seek_origin) {
|
|
case SEEK_SET:
|
|
virtual_file->buffer_pos = (size_t) irp->seek_offset;
|
|
break;
|
|
|
|
case SEEK_CUR:
|
|
virtual_file->buffer_pos += (size_t) irp->seek_offset;
|
|
break;
|
|
|
|
case SEEK_END:
|
|
virtual_file->buffer_pos = virtual_file->file_info->file_size;
|
|
virtual_file->buffer_pos += (size_t) irp->seek_offset;
|
|
break;
|
|
|
|
default:
|
|
log_die("Unhandled origin %d", irp->seek_origin);
|
|
break;
|
|
}
|
|
|
|
log_debug("fseek %s, offset 0x%X, origin %d", virtual_file->file_info->file_path, irp->seek_offset,
|
|
irp->seek_origin);
|
|
|
|
pthread_mutex_unlock(&_patch_net_profile_mutex);
|
|
|
|
return CNH_RESULT_SUCCESS;
|
|
}
|
|
|
|
static enum cnh_result _patch_net_profile_ftell(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file)
|
|
{
|
|
pthread_mutex_lock(&_patch_net_profile_mutex);
|
|
|
|
irp->tell_offset = virtual_file->buffer_pos;
|
|
|
|
pthread_mutex_unlock(&_patch_net_profile_mutex);
|
|
|
|
return CNH_RESULT_SUCCESS;
|
|
}
|
|
|
|
static enum cnh_result _patch_net_profile_feof(struct cnh_filehook_irp* irp,
|
|
struct profile_virtual_file* virtual_file)
|
|
{
|
|
pthread_mutex_lock(&_patch_net_profile_mutex);
|
|
|
|
irp->eof = virtual_file->buffer_pos == virtual_file->file_info->file_size;
|
|
|
|
pthread_mutex_unlock(&_patch_net_profile_mutex);
|
|
|
|
return CNH_RESULT_SUCCESS;
|
|
}
|
|
|
|
// =====================================================================================================================
|
|
|
|
static struct profile_virtual_file* _patch_net_profile_get_virtual_mnt_point(FILE* handle)
|
|
{
|
|
for (int i = 0; i < PUMPNET_MAX_NUM_PLAYERS; i++) {
|
|
for (int j = 0; j < PUMPNET_LIB_FILE_TYPE_COUNT; j++) {
|
|
if (_patch_net_profile_virtual_mnt_points->files[j].handle == handle) {
|
|
return &_patch_net_profile_virtual_mnt_points->files[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static bool _patch_net_profile_determine_is_profile_and_player_and_file_type(
|
|
struct cnh_filehook_irp* irp,
|
|
uint8_t* player,
|
|
enum pumpnet_lib_file_type* file_type)
|
|
{
|
|
log_assert(irp);
|
|
log_assert(player);
|
|
log_assert(file_type);
|
|
|
|
// compare to static string to avoid slowing everything down
|
|
for (int i = 0; i < PUMPNET_MAX_NUM_PLAYERS; i++) {
|
|
for (int j = 0; j < PUMPNET_LIB_FILE_TYPE_COUNT; j++) {
|
|
if (!strcmp(irp->open_filename,
|
|
_patch_net_profile_file_info_ref->player[i].file_info[j].file_path)) {
|
|
*player = i;
|
|
*file_type = (enum pumpnet_lib_file_type) j;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static struct profile_virtual_file* _patch_net_profile_setup_virtual_file(
|
|
uint8_t player,
|
|
enum pumpnet_lib_file_type file_type,
|
|
uint64_t player_ref_id)
|
|
{
|
|
struct profile_virtual_file* virtual_file;
|
|
|
|
log_debug("Setup virtual file, player %d, file_type %d", player, file_type);
|
|
|
|
virtual_file = &_patch_net_profile_virtual_mnt_points[player].files[file_type];
|
|
|
|
// sanity checks
|
|
log_assert(!virtual_file->handle);
|
|
log_assert(!virtual_file->file_info);
|
|
log_assert(!virtual_file->buffer);
|
|
|
|
virtual_file->player_ref_id = player_ref_id;
|
|
virtual_file->handle = cnh_filehook_open_dummy_file_handle();
|
|
virtual_file->file_info = &_patch_net_profile_file_info_ref->player[player].file_info[file_type];
|
|
virtual_file->buffer_pos = 0;
|
|
virtual_file->is_written = false;
|
|
|
|
virtual_file->buffer = (uint8_t*) malloc(virtual_file->file_info->file_size);
|
|
|
|
log_debug("Setup virtual file done, size %d", virtual_file->file_info->file_size);
|
|
|
|
return virtual_file;
|
|
}
|
|
|
|
static void _patch_net_profile_destroy_virtual_file(uint8_t player, enum pumpnet_lib_file_type file_type)
|
|
{
|
|
struct profile_virtual_file* virtual_file;
|
|
|
|
log_debug("Destroying virtual file, player %d, file_type %d", player, file_type);
|
|
|
|
virtual_file = &_patch_net_profile_virtual_mnt_points[player].files[file_type];
|
|
|
|
// sanity checks
|
|
log_assert(virtual_file->handle);
|
|
log_assert(virtual_file->file_info);
|
|
log_assert(virtual_file->buffer);
|
|
|
|
cnh_filehook_close_dummy_file_handle(virtual_file->handle);
|
|
virtual_file->handle = NULL;
|
|
virtual_file->file_info = NULL;
|
|
free(virtual_file->buffer);
|
|
virtual_file->buffer = NULL;
|
|
}
|
|
|
|
static bool _patch_net_profile_get_token(int player, uint64_t* player_ref_id)
|
|
{
|
|
log_assert(player_ref_id);
|
|
log_assert(player >= 0);
|
|
log_assert(player <= 1);
|
|
|
|
char path_profile_token[128];
|
|
|
|
*player_ref_id = 0;
|
|
|
|
sprintf(path_profile_token, "/mnt/%d/%s", player, PUMPNET_PROFILE_FILE_NAME);
|
|
|
|
if (util_fs_path_exists(path_profile_token)) {
|
|
log_info("Found pumpnet profile file %s", path_profile_token);
|
|
|
|
if (pumpnet_lib_profile_token_load(path_profile_token, player_ref_id)) {
|
|
return true;
|
|
} else {
|
|
log_error("Loading pumpnet profile token %s failed, fallback to local profiles", path_profile_token);
|
|
}
|
|
} else {
|
|
log_info("No pumpnet profile found, fallback to local profile");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool _patch_net_profile_download_profile_file(struct profile_virtual_file* virtual_file)
|
|
{
|
|
int player;
|
|
enum pumpnet_lib_file_type file_type;
|
|
uint64_t player_ref_id;
|
|
|
|
player = virtual_file->file_info->player;
|
|
file_type = virtual_file->file_info->file_type;
|
|
player_ref_id = virtual_file->player_ref_id;
|
|
|
|
log_info("Profile file player %d, file_type %d, refId %llX downloading from server...",
|
|
player,
|
|
file_type,
|
|
player_ref_id);
|
|
|
|
if (!pumpnet_lib_get(file_type, player_ref_id, virtual_file->buffer, virtual_file->file_info->file_size)) {
|
|
log_error("Downloading file player %d, file_type %d, refId %llX failed",
|
|
player,
|
|
file_type,
|
|
player_ref_id);
|
|
return false;
|
|
}
|
|
|
|
log_info("Downloading file player %d, file_type %d, refId %llX successful",
|
|
player,
|
|
file_type,
|
|
player_ref_id);
|
|
return true;
|
|
}
|
|
|
|
static enum cnh_result _patch_net_profile_open_pumpnet_profile_file(
|
|
struct cnh_filehook_irp* irp,
|
|
uint8_t player,
|
|
enum pumpnet_lib_file_type file_type)
|
|
{
|
|
uint64_t player_ref_id;
|
|
|
|
log_debug("open %s %d %d", irp->open_filename, player, file_type);
|
|
|
|
// check if pumpnet.bin token is available and server reachable
|
|
// download all profile files on the first file request and hook all following files to virtual endpoints of
|
|
// the already downloaded and buffered data
|
|
if (_patch_net_profile_get_token(player, &player_ref_id)) {
|
|
struct profile_virtual_file* virtual_file =
|
|
_patch_net_profile_setup_virtual_file(player, file_type, player_ref_id);
|
|
|
|
if (_patch_net_profile_download_profile_file(virtual_file)) {
|
|
irp->file = virtual_file->handle;
|
|
pthread_mutex_unlock(&_patch_net_profile_mutex);
|
|
|
|
return CNH_RESULT_SUCCESS;
|
|
} else {
|
|
_patch_net_profile_destroy_virtual_file(player, file_type);
|
|
|
|
pthread_mutex_unlock(&_patch_net_profile_mutex);
|
|
|
|
return CNH_RESULT_NO_SUCH_FILE_OR_DIR;
|
|
}
|
|
}
|
|
|
|
return cnh_filehook_invoke_next(irp);
|
|
}
|
|
|
|
static bool _patch_net_profile_upload_profile_file(struct profile_virtual_file* virtual_file)
|
|
{
|
|
int player;
|
|
enum pumpnet_lib_file_type file_type;
|
|
uint64_t player_ref_id;
|
|
|
|
player = virtual_file->file_info->player;
|
|
file_type = virtual_file->file_info->file_type;
|
|
player_ref_id = virtual_file->player_ref_id;
|
|
|
|
log_info("Profile file player %d, file_type %d, refId %llX uploading to server...",
|
|
player,
|
|
file_type,
|
|
player_ref_id);
|
|
|
|
if (!pumpnet_lib_put(file_type, player_ref_id, virtual_file->buffer, virtual_file->file_info->file_size)) {
|
|
log_error("Uploading file player %d, file_type %d, refId %llX failed",
|
|
player,
|
|
file_type,
|
|
player_ref_id);
|
|
return false;
|
|
}
|
|
|
|
log_info("Uploading file player %d, file_type %d, refId %llX successful",
|
|
player,
|
|
file_type,
|
|
player_ref_id);
|
|
return true;
|
|
}
|
|
|
|
static bool _patch_net_profile_close_pumpnet_profile_file(struct profile_virtual_file* virtual_file)
|
|
{
|
|
bool res = true;
|
|
|
|
pthread_mutex_lock(&_patch_net_profile_mutex);
|
|
|
|
if (virtual_file->is_written) {
|
|
res = _patch_net_profile_upload_profile_file(virtual_file);
|
|
}
|
|
|
|
_patch_net_profile_destroy_virtual_file(virtual_file->file_info->player, virtual_file->file_info->file_type);
|
|
|
|
pthread_mutex_unlock(&_patch_net_profile_mutex);
|
|
|
|
return res;
|
|
}
|
|
|
|
// =====================================================================================================================
|
|
|
|
void patch_net_profile_init(
|
|
enum asset_game_version game,
|
|
const char* pumpnet_server_addr,
|
|
uint64_t machine_id,
|
|
const char* cert_dir_path,
|
|
bool verbose_debug_log)
|
|
{
|
|
uint8_t idx;
|
|
|
|
/* use a switch instead of offset'ing the enum for additional safety and block unsupported games */
|
|
switch (game) {
|
|
case ASSET_GAME_VERSION_NX2:
|
|
idx = 0;
|
|
break;
|
|
|
|
case ASSET_GAME_VERSION_NXA:
|
|
idx = 1;
|
|
break;
|
|
//
|
|
// case ASSET_GAME_VERSION_FIESTA:
|
|
// idx = 2;
|
|
// break;
|
|
//
|
|
// case ASSET_GAME_VERSION_FIESTA_EX:
|
|
// idx = 3;
|
|
// break;
|
|
//
|
|
// case ASSET_GAME_VERSION_FIESTA_2:
|
|
// idx = 4;
|
|
// break;
|
|
|
|
case ASSET_GAME_VERSION_FIESTA:
|
|
case ASSET_GAME_VERSION_FIESTA_EX:
|
|
case ASSET_GAME_VERSION_FIESTA_2:
|
|
|
|
default:
|
|
log_error("Unsupported game version %d specified, disabled network service", game);
|
|
return;
|
|
}
|
|
|
|
_patch_net_profile_file_info_ref = &_patch_net_profile_virtual_mnt_point_infos[idx];
|
|
|
|
size_t max_data_size = 0;
|
|
|
|
// determine max file size for network buffers, file sizes identical on for all players.
|
|
for (int i = 0; i < PUMPNET_LIB_FILE_TYPE_COUNT; i++) {
|
|
max_data_size += _patch_net_profile_file_info_ref->player[0].file_info[i].file_size;
|
|
}
|
|
|
|
// set buffers to NULL to detect illegal states
|
|
for (int i = 0; i < PUMPNET_LIB_FILE_TYPE_COUNT; i++) {
|
|
for (int j = 0; j < PUMPNET_MAX_NUM_PLAYERS; j++) {
|
|
_patch_net_profile_virtual_mnt_points[j].files[i].player_ref_id = 0;
|
|
_patch_net_profile_virtual_mnt_points[j].files[i].handle = NULL;
|
|
_patch_net_profile_virtual_mnt_points[j].files[i].file_info = NULL;
|
|
_patch_net_profile_virtual_mnt_points[j].files[i].buffer = NULL;
|
|
}
|
|
}
|
|
|
|
pumpnet_lib_init(game, pumpnet_server_addr, machine_id, cert_dir_path, verbose_debug_log);
|
|
|
|
cnh_filehook_push_handler(_patch_net_profile_filehook);
|
|
|
|
pthread_mutex_init(&_patch_net_profile_mutex, NULL);
|
|
|
|
log_info("Initialized: game %d, server %s, machine id %llX", game, pumpnet_server_addr, machine_id);
|
|
}
|
|
|
|
void patch_net_profile_shutdown()
|
|
{
|
|
pumpnet_lib_shutdown();
|
|
|
|
pthread_mutex_destroy(&_patch_net_profile_mutex);
|
|
|
|
log_info("Shut down");
|
|
} |