mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-18 17:29:17 +01:00
c51b2304c2
* added direct list of emu nand channels without activating emu nand (for speed up) * removed autoclose of search bar and changed the search engine to have both methods * added setting for switching "Beginning" and "Content" search methods and a quick switch button on search window * added autocomplete if only one search character is available and more than one match * added seperate path and setting for emu nand channels/saves * added caching of emu nand channel titles * fixed a few alignment issues when activating emu nand (thanks daveboal) * some minor clean ups TODO/Next Rev: * add channels banner sounds * remove unneeded game settings options on channels
329 lines
5.3 KiB
C++
329 lines
5.3 KiB
C++
#include <ogcsys.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "CGameStatistics.h"
|
|
#include "FileOperations/fileops.h"
|
|
#include "svnrev.h"
|
|
|
|
#define VALID_CONFIG_REV 1031
|
|
|
|
CGameStatistics GameStatistics;
|
|
|
|
|
|
CGameStatistics::CGameStatistics()
|
|
{
|
|
}
|
|
|
|
CGameStatistics::~CGameStatistics()
|
|
{
|
|
}
|
|
|
|
GameStatus * CGameStatistics::GetGameStatus(const char * id) const
|
|
{
|
|
if(!id)
|
|
return NULL;
|
|
|
|
for(u32 i = 0; i < GameList.size(); ++i)
|
|
{
|
|
if(strncasecmp(id, GameList[i].id, 6) == 0)
|
|
{
|
|
return (GameStatus *) &GameList[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool CGameStatistics::AddGame(const GameStatus & NewGame)
|
|
{
|
|
for(u32 i = 0; i < GameList.size(); ++i)
|
|
{
|
|
if(strncasecmp(NewGame.id, GameList[i].id, 6) == 0)
|
|
{
|
|
memcpy(&GameList[i], &NewGame, sizeof(GameStatus));
|
|
return true;
|
|
}
|
|
}
|
|
|
|
GameList.push_back(NewGame);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CGameStatistics::RemoveAll()
|
|
{
|
|
GameList.clear();
|
|
std::vector<GameStatus>().swap(GameList);
|
|
|
|
return Save();
|
|
}
|
|
|
|
bool CGameStatistics::Remove(const char * id)
|
|
{
|
|
if(!id)
|
|
return false;
|
|
|
|
for(u32 i = 0; i < GameList.size(); ++i)
|
|
{
|
|
if(strncasecmp(id, GameList[i].id, 6) == 0)
|
|
{
|
|
GameList.erase(GameList.begin()+i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CGameStatistics::Load(const char * path)
|
|
{
|
|
char line[1024];
|
|
char filepath[300];
|
|
snprintf(filepath, sizeof(filepath), "%sGXGameStatistics.cfg", path);
|
|
|
|
ConfigPath = filepath;
|
|
|
|
FILE *file = fopen(filepath, "r");
|
|
if (!file) return false;
|
|
|
|
if(!ValidVersion(file))
|
|
{
|
|
fclose(file);
|
|
return false;
|
|
}
|
|
|
|
while (fgets(line, sizeof(line), file))
|
|
{
|
|
if (line[0] == '#')
|
|
continue;
|
|
|
|
this->ParseLine(line);
|
|
}
|
|
fclose(file);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CGameStatistics::ValidVersion(FILE * file)
|
|
{
|
|
if(!file) return false;
|
|
|
|
char line[255];
|
|
int revision = 0;
|
|
|
|
while (fgets(line, sizeof(line), file))
|
|
{
|
|
const char * ptr = strcasestr(line, "USB Loader GX R");
|
|
if(ptr)
|
|
{
|
|
ptr += strlen("USB Loader GX R");
|
|
revision = atoi(ptr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
rewind(file);
|
|
|
|
return revision >= VALID_CONFIG_REV;
|
|
}
|
|
|
|
bool CGameStatistics::Save()
|
|
{
|
|
char filepath[300];
|
|
strcpy(filepath, ConfigPath.c_str());
|
|
|
|
char * ptr = strrchr(filepath, '/');
|
|
if(ptr)
|
|
ptr[0] = 0;
|
|
|
|
if(!CreateSubfolder(filepath))
|
|
return false;
|
|
|
|
FILE * f = fopen(ConfigPath.c_str(), "w");
|
|
if (!f) return false;
|
|
|
|
fprintf(f, "# USB Loader GX R%s - Game statistics file\n", GetRev());
|
|
fprintf(f, "# note: this file is automatically generated\n");
|
|
fprintf(f, "# Num Games: %d\n", GameList.size());
|
|
for (u32 i = 0; i < GameList.size(); i++)
|
|
{
|
|
fprintf(f, "game:%s = ", GameList[i].id);
|
|
fprintf(f, "FavoriteRank:%d; ", GameList[i].FavoriteRank);
|
|
fprintf(f, "PlayCount:%d;\n", GameList[i].PlayCount);
|
|
}
|
|
fprintf(f, "# END\n");
|
|
fclose(f);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CGameStatistics::SetSetting(GameStatus & game, char *name, char *value)
|
|
{
|
|
int i = 0;
|
|
|
|
if(strcmp(name, "FavoriteRank") == 0)
|
|
{
|
|
if (sscanf(value, "%d", &i) == 1)
|
|
{
|
|
game.FavoriteRank = i;
|
|
}
|
|
return true;
|
|
}
|
|
else if(strcmp(name, "PlayCount") == 0)
|
|
{
|
|
if (sscanf(value, "%d", &i) == 1)
|
|
{
|
|
game.PlayCount = i;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CGameStatistics::ReadGameID(const char * src, char * GameID, int size)
|
|
{
|
|
if(strncasecmp(src, "game:", 5) != 0)
|
|
return false;
|
|
|
|
char * ptr = strchr(src, ':');
|
|
if(!ptr)
|
|
return false;
|
|
|
|
ptr++;
|
|
|
|
int i = 0;
|
|
|
|
for(i = 0; i < size; i++, ptr++)
|
|
{
|
|
if(*ptr == ' ' || *ptr == '\0')
|
|
break;
|
|
|
|
GameID[i] = *ptr;
|
|
}
|
|
|
|
GameID[i] = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CGameStatistics::ParseLine(char *line)
|
|
{
|
|
char name[1024], value[1024];
|
|
char GameID[8];
|
|
|
|
if(!ReadGameID(line, GameID, 6))
|
|
return;
|
|
|
|
if(strlen(GameID) != 6 && strlen(GameID) != 4)
|
|
return;
|
|
|
|
GameStatus NewGame;
|
|
memset(&NewGame, 0, sizeof(GameStatus));
|
|
|
|
snprintf(NewGame.id, sizeof(NewGame.id), GameID);
|
|
|
|
char * LinePtr = strchr(line, '=');
|
|
|
|
while(LinePtr != NULL)
|
|
{
|
|
LinePtr++;
|
|
|
|
char * eq = strchr(LinePtr, ':');
|
|
|
|
if (!eq) break;
|
|
|
|
this->TrimLine(name, LinePtr, sizeof(name));
|
|
this->TrimLine(value, eq + 1, sizeof(value));
|
|
|
|
SetSetting(NewGame, name, value);
|
|
|
|
LinePtr = strchr(LinePtr, ';');
|
|
}
|
|
|
|
AddGame(NewGame);
|
|
}
|
|
|
|
void CGameStatistics::TrimLine(char *dest, const char *src, int size)
|
|
{
|
|
while (*src == ' ')
|
|
src++;
|
|
|
|
int i = 0;
|
|
|
|
for(i = 0; i < size; i++, src++)
|
|
{
|
|
if(*src == ';' || *src == ':' || *src == '\n' ||
|
|
*src == '\r' || *src == '\0')
|
|
break;
|
|
|
|
dest[i] = *src;
|
|
}
|
|
|
|
dest[i] = '\0';
|
|
}
|
|
|
|
void CGameStatistics::SetPlayCount(const char * id, int count)
|
|
{
|
|
if(!id)
|
|
return;
|
|
|
|
GameStatus NewStatus;
|
|
snprintf(NewStatus.id, sizeof(NewStatus.id), id);
|
|
NewStatus.FavoriteRank = 0;
|
|
NewStatus.PlayCount = count;
|
|
|
|
GameStatus * game = GetGameStatus(id);
|
|
if(game)
|
|
{
|
|
NewStatus.FavoriteRank = game->FavoriteRank;
|
|
}
|
|
|
|
AddGame(NewStatus);
|
|
}
|
|
|
|
void CGameStatistics::SetFavoriteRank(const char * id, int rank)
|
|
{
|
|
if(!id)
|
|
return;
|
|
|
|
GameStatus NewStatus;
|
|
snprintf(NewStatus.id, sizeof(NewStatus.id), id);
|
|
NewStatus.FavoriteRank = rank;
|
|
NewStatus.PlayCount = 0;
|
|
|
|
GameStatus * game = GetGameStatus(id);
|
|
if(game)
|
|
{
|
|
NewStatus.PlayCount = game->PlayCount;
|
|
}
|
|
|
|
AddGame(NewStatus);
|
|
}
|
|
|
|
int CGameStatistics::GetPlayCount(const char * id) const
|
|
{
|
|
if(!id)
|
|
return 0;
|
|
|
|
GameStatus * game = GetGameStatus(id);
|
|
if(game)
|
|
return game->PlayCount;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CGameStatistics::GetFavoriteRank(const char * id) const
|
|
{
|
|
if(!id)
|
|
return 0;
|
|
|
|
GameStatus * game = GetGameStatus(id);
|
|
if(game)
|
|
return game->FavoriteRank;
|
|
|
|
return 0;
|
|
}
|