mirror of
https://github.com/Fledge68/WiiFlow_Lite.git
synced 2024-11-30 15:14:18 +01:00
Add Plugins databases
This commit is contained in:
parent
baf4855a5e
commit
09525023a2
@ -31,6 +31,9 @@
|
||||
#include "config/config.hpp"
|
||||
#include "gecko/gecko.hpp"
|
||||
#include "memory/mem2.hpp"
|
||||
#include "types.h"
|
||||
#include "gui/coverflow.hpp"
|
||||
|
||||
#define NAME_OFFSET_DB "gametdb_offsets.bin"
|
||||
#define MAXREADSIZE 1024*1024 //Cache size only for parsing the offsets: 1MB
|
||||
|
||||
@ -458,6 +461,17 @@ bool GameTDB::ParseFile()
|
||||
|
||||
bool GameTDB::FindTitle(char *data, const char * &title, const string &langCode)
|
||||
{
|
||||
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
{
|
||||
title = GetNodeText(data, "<title>", "</title>");
|
||||
|
||||
if(title == NULL)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
char *language = SeekLang(data, langCode.c_str());
|
||||
if(language == NULL)
|
||||
{
|
||||
@ -465,6 +479,7 @@ bool GameTDB::FindTitle(char *data, const char * &title, const string &langCode)
|
||||
if(language == NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
title = GetNodeText(language, "<title>", "</title>");
|
||||
|
||||
if(title == NULL)
|
||||
@ -487,6 +502,24 @@ bool GameTDB::GetTitle(const char *id, const char * &title)
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool GameTDB::GetName(const char *id, const char * &name)
|
||||
{
|
||||
name = NULL;
|
||||
if(!id)
|
||||
return false;
|
||||
|
||||
char *data = GetGameNode(id);
|
||||
if(!data)
|
||||
return false;
|
||||
|
||||
name = GetNodeText(data, "<game name=\"", "\"");
|
||||
MEM2_free(data);
|
||||
|
||||
if(name == NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GameTDB::GetSynopsis(const char *id, const char * &synopsis)
|
||||
{
|
||||
synopsis = NULL;
|
||||
@ -508,6 +541,22 @@ bool GameTDB::GetSynopsis(const char *id, const char * &synopsis)
|
||||
}
|
||||
}
|
||||
synopsis = GetNodeText(language, "<synopsis>", "</synopsis>");
|
||||
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
{
|
||||
// Default to English
|
||||
if(synopsis == NULL)
|
||||
{
|
||||
language = SeekLang(data, "EN");
|
||||
if(language == NULL)
|
||||
{
|
||||
MEM2_free(data);
|
||||
return false;
|
||||
}
|
||||
synopsis = GetNodeText(language, "<synopsis>", "</synopsis>");
|
||||
}
|
||||
}
|
||||
|
||||
MEM2_free(data);
|
||||
|
||||
if(synopsis == NULL)
|
||||
@ -619,6 +668,46 @@ bool GameTDB::GetGenres(const char *id, const char * &gen)
|
||||
{
|
||||
gen = NULL;
|
||||
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
{
|
||||
if(!id)
|
||||
return false;
|
||||
|
||||
char *data = GetGameNode(id);
|
||||
if(!data)
|
||||
return false;
|
||||
|
||||
char *language = SeekLang(data, LangCode.c_str());
|
||||
if(language == NULL)
|
||||
{
|
||||
language = SeekLang(data, "EN");
|
||||
if(language == NULL)
|
||||
{
|
||||
MEM2_free(data);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
gen = GetNodeText(language, "<genre>", "</genre>");
|
||||
|
||||
// If not found try in English
|
||||
if(gen == NULL)
|
||||
{
|
||||
language = SeekLang(data, "EN");
|
||||
if(language == NULL)
|
||||
{
|
||||
MEM2_free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
gen = GetNodeText(language, "<genre>", "</genre>");
|
||||
}
|
||||
MEM2_free(data);
|
||||
|
||||
if(gen == NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(id == NULL)
|
||||
return false;
|
||||
|
||||
|
@ -74,6 +74,8 @@ public:
|
||||
const char * GetLanguageCode() { return LangCode.c_str(); };
|
||||
//! Get the title of a specific game id in the language defined in LangCode
|
||||
bool GetTitle(const char *id, const char * &title);
|
||||
//! Get the name of a specific game id
|
||||
bool GetName(const char *id, const char * &name);
|
||||
//! Get the synopsis of a specific game id in the language defined in LangCode
|
||||
bool GetSynopsis(const char *id, const char * &synopsis);
|
||||
//! Get the region of a game for a specific game id
|
||||
|
@ -220,6 +220,9 @@ bool CMenu::init()
|
||||
m_fanartDir = m_cfg.getString("GENERAL", "dir_fanart", fmt("%s/fanart", m_dataDir.c_str()));
|
||||
m_screenshotDir = m_cfg.getString("GENERAL", "dir_screenshot", fmt("%s/screenshots", m_dataDir.c_str()));
|
||||
m_helpDir = m_cfg.getString("GENERAL", "dir_help", fmt("%s/help", m_dataDir.c_str()));
|
||||
m_cartDir = m_cfg.getString("GENERAL", "dir_cart", fmt("%s/cart_disk", m_dataDir.c_str()));
|
||||
m_snapDir = m_cfg.getString("GENERAL", "dir_snap", fmt("%s/snapshots", m_dataDir.c_str()));
|
||||
m_pluginDataDir = m_cfg.getString("GENERAL", "dir_plugins_data", fmt("%s/plugins_data", m_dataDir.c_str()));
|
||||
|
||||
/* Create our Folder Structure */
|
||||
fsop_MakeFolder(m_dataDir.c_str()); //D'OH!
|
||||
|
@ -142,6 +142,9 @@ private:
|
||||
string m_screenshotDir;
|
||||
string m_settingsDir;
|
||||
string m_languagesDir;
|
||||
string m_cartDir;
|
||||
string m_snapDir;
|
||||
string m_pluginDataDir;
|
||||
string m_helpDir;
|
||||
|
||||
/* NandEmulation */
|
||||
@ -618,6 +621,12 @@ private:
|
||||
s16 m_gameinfoLblUser[5];
|
||||
s16 m_gameinfoLblControlsReq[4];
|
||||
s16 m_gameinfoLblControls[4];
|
||||
s16 m_gameinfoLblSnap;
|
||||
s16 m_gameinfoLblCartDisk;
|
||||
s16 m_gameinfoLblOverlay;
|
||||
TexData m_snap;
|
||||
TexData m_cart;
|
||||
TexData m_overlay;
|
||||
TexData m_rating;
|
||||
TexData m_wifi;
|
||||
TexData m_controlsreq[4];
|
||||
|
@ -586,7 +586,7 @@ void CMenu::_game(bool launch)
|
||||
}
|
||||
}
|
||||
/* display game info screen */
|
||||
else if(BTN_PLUS_PRESSED && !NoGameID(hdr->type) && !coverFlipped && !m_video_playing)
|
||||
else if(BTN_PLUS_PRESSED && hdr->type != TYPE_HOMEBREW && hdr->type != TYPE_SOURCE && !coverFlipped && !m_video_playing)
|
||||
{
|
||||
_hideGame();// stops trailer movie too
|
||||
m_banner.SetShowBanner(false);
|
||||
|
@ -1,6 +1,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include "menu.hpp"
|
||||
#include "gui/GameTDB.hpp"
|
||||
#include "plugin/plugin.hpp"
|
||||
#include "plugin/crc32.h"
|
||||
|
||||
wstringEx gameinfo_Synopsis_w;
|
||||
wstringEx gameinfo_Title_w;
|
||||
@ -64,6 +67,9 @@ void CMenu::_gameinfo(void)
|
||||
m_btnMgr.hide(m_gameinfoLblGenre, true);
|
||||
m_btnMgr.hide(m_gameinfoLblRating, true);
|
||||
m_btnMgr.hide(m_gameinfoLblWifiplayers, true);
|
||||
m_btnMgr.hide(m_gameinfoLblSnap, true);
|
||||
m_btnMgr.hide(m_gameinfoLblCartDisk, true);
|
||||
m_btnMgr.hide(m_gameinfoLblOverlay, true);
|
||||
|
||||
for(u8 i = 0; i < ARRAY_SIZE(m_gameinfoLblControlsReq); ++i)
|
||||
if(m_gameinfoLblControlsReq[i] != -1)
|
||||
@ -96,6 +102,9 @@ void CMenu::_gameinfo(void)
|
||||
m_btnMgr.show(m_gameinfoLblGenre);
|
||||
m_btnMgr.show(m_gameinfoLblRating);
|
||||
m_btnMgr.show(m_gameinfoLblWifiplayers);
|
||||
m_btnMgr.show(m_gameinfoLblSnap);
|
||||
m_btnMgr.show(m_gameinfoLblCartDisk);
|
||||
m_btnMgr.show(m_gameinfoLblOverlay);
|
||||
|
||||
for(u8 i = 0; i < ARRAY_SIZE(m_gameinfoLblControlsReq); ++i)
|
||||
if(m_gameinfoLblControlsReq[i] != -1 && i < cnt_controlsreq)
|
||||
@ -130,6 +139,9 @@ void CMenu::_hideGameInfo(bool instant)
|
||||
m_btnMgr.hide(m_gameinfoLblGenre, instant);
|
||||
m_btnMgr.hide(m_gameinfoLblRating, instant);
|
||||
m_btnMgr.hide(m_gameinfoLblWifiplayers, instant);
|
||||
m_btnMgr.hide(m_gameinfoLblSnap, instant);
|
||||
m_btnMgr.hide(m_gameinfoLblCartDisk, instant);
|
||||
m_btnMgr.hide(m_gameinfoLblOverlay, instant);
|
||||
|
||||
for(u8 i = 0; i < ARRAY_SIZE(m_gameinfoLblControlsReq); ++i)
|
||||
if(m_gameinfoLblControlsReq[i] != -1)
|
||||
@ -161,6 +173,13 @@ void CMenu::_showGameInfo(void)
|
||||
m_btnMgr.show(m_gameinfoLblGenre);
|
||||
m_btnMgr.show(m_gameinfoLblWifiplayers);
|
||||
|
||||
if(m_current_view == COVERFLOW_PLUGIN)
|
||||
{
|
||||
m_btnMgr.show(m_gameinfoLblSnap);
|
||||
m_btnMgr.show(m_gameinfoLblCartDisk);
|
||||
m_btnMgr.show(m_gameinfoLblOverlay);
|
||||
}
|
||||
|
||||
for(u8 i = 0; i < ARRAY_SIZE(m_gameinfoLblUser); ++i)
|
||||
if(i < ARRAY_SIZE(m_gameinfoLblUser) / 2)
|
||||
m_btnMgr.show(m_gameinfoLblUser[i]);
|
||||
@ -190,9 +209,12 @@ void CMenu::_initGameInfoMenu()
|
||||
m_gameinfoLblPublisher = _addLabel("GAMEINFO/PUBLISHER", theme.txtFont, L"", 40, 200, 460, 56, theme.txtFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
|
||||
m_gameinfoLblRlsdate = _addLabel("GAMEINFO/RLSDATE", theme.txtFont, L"", 40, 230, 460, 56, theme.txtFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
|
||||
m_gameinfoLblRegion = _addLabel("GAMEINFO/REGION", theme.txtFont, L"", 40, 260, 460, 56, theme.txtFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
|
||||
m_gameinfoLblRating = _addLabel("GAMEINFO/RATING", theme.titleFont, L"", 550, 380, 48, 60, theme.titleFontColor, 0, m_rating);
|
||||
m_gameinfoLblRating = _addLabel("GAMEINFO/RATING", theme.txtFont, L"", 550, 380, 48, 60, theme.txtFontColor, 0, m_rating);
|
||||
m_gameinfoLblSynopsis = _addLabel("GAMEINFO/SYNOPSIS", theme.txtFont, L"", 40, 80, 560, 280, theme.txtFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
|
||||
m_gameinfoLblWifiplayers = _addLabel("GAMEINFO/WIFIPLAYERS", theme.txtFont, L"", 550, 110, 68, 60, theme.txtFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP,m_wifi);
|
||||
m_gameinfoLblSnap = _addLabel("GAMEINFO/SNAP", theme.titleFont, L"", 485, 200, m_snap.width, m_snap.height, theme.titleFontColor, 0, m_snap);
|
||||
m_gameinfoLblOverlay = _addLabel("GAMEINFO/OVERLAY", theme.txtFont, L"", 485, 200, m_snap.width, m_snap.height, theme.titleFontColor, 0, m_overlay);
|
||||
m_gameinfoLblCartDisk = _addLabel("GAMEINFO/CART", theme.txtFont, L"", 435, 364, m_cart.width, m_cart.height, theme.txtFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE,m_cart);
|
||||
|
||||
_addUserLabels(m_gameinfoLblUser, 1, 1, "GAMEINFO");
|
||||
_addUserLabels(m_gameinfoLblUser, 3, 2, "GAMEINFO");
|
||||
@ -223,6 +245,9 @@ void CMenu::_initGameInfoMenu()
|
||||
_setHideAnim(m_gameinfoLblRlsdate, "GAMEINFO/RLSDATE", 0, -100, 0.f, 0.f);
|
||||
_setHideAnim(m_gameinfoLblGenre, "GAMEINFO/GENRE", 0, -100, 0.f, 0.f);
|
||||
_setHideAnim(m_gameinfoLblWifiplayers, "GAMEINFO/WIFIPLAYERS", 0, -100, 0.f, 0.f);
|
||||
_setHideAnim(m_gameinfoLblSnap, "GAMEINFO/SNAP", 0, -100, 0.f, 0.f);
|
||||
_setHideAnim(m_gameinfoLblCartDisk, "GAMEINFO/CART", 0, -100, 0.f, 0.f);
|
||||
_setHideAnim(m_gameinfoLblOverlay, "GAMEINFO/OVERLAY", 0, -100, 0.f, 0.f);
|
||||
//
|
||||
_hideGameInfo(true);
|
||||
synopsis_h = m_theme.getInt("GAMEINFO/SYNOPSIS", "height", 280);
|
||||
@ -234,7 +259,25 @@ void CMenu::_textGameInfo(void)
|
||||
cnt_controls = 0;
|
||||
|
||||
GameTDB gametdb;
|
||||
gametdb.OpenFile(fmt("%s/wiitdb.xml", m_settingsDir.c_str()));
|
||||
char platformName[264];
|
||||
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
{
|
||||
// Check the platform name corresponding to the current magic number.
|
||||
// We can't use magic # directly since it'd require hardcoding values and a # can be several systems(genplus)
|
||||
// We can't rely on coverfolder either. Different systems can share the same folder. Or combined plugins used for the same system.
|
||||
Config m_platform;
|
||||
m_platform.unload();
|
||||
m_platform.load(fmt("%s/platform.ini", m_pluginDataDir.c_str()) );
|
||||
snprintf(platformName, sizeof(platformName), "%s", m_platform.getString("PLUGINS", m_plugin.PluginMagicWord).c_str());
|
||||
m_platform.unload();
|
||||
gametdb.OpenFile(fmt("%s/%s/%s.xml", m_pluginDataDir.c_str(), platformName, platformName));
|
||||
}
|
||||
else
|
||||
{
|
||||
gametdb.OpenFile(fmt("%s/wiitdb.xml", m_settingsDir.c_str()));
|
||||
}
|
||||
|
||||
gametdb.SetLanguageCode(m_loc.getString(m_curLanguage, "gametdb_code", "EN").c_str());
|
||||
const char *TMP_Char = NULL;
|
||||
tdb_found = gametdb.IsLoaded();
|
||||
@ -242,11 +285,100 @@ void CMenu::_textGameInfo(void)
|
||||
{
|
||||
char GameID[7];
|
||||
GameID[6] = '\0';
|
||||
strncpy(GameID, CoverFlow.getId(), 6);
|
||||
|
||||
string ShortName;
|
||||
|
||||
// Clear text and textures
|
||||
TexData emptyTex;
|
||||
gameinfo_Synopsis_w.fromUTF8("");
|
||||
m_btnMgr.setText(m_gameinfoLblDev, wfmt(_fmt("",L"")), true);
|
||||
m_btnMgr.setText(m_gameinfoLblPublisher, wfmt(_fmt("",L"")), true);
|
||||
m_btnMgr.setText(m_gameinfoLblRegion, wfmt(_fmt("",L"")), true);
|
||||
m_btnMgr.setText(m_gameinfoLblRating, wfmt(_fmt("",L"")), true);
|
||||
m_btnMgr.setTexture(m_gameinfoLblRating, emptyTex);
|
||||
|
||||
m_btnMgr.setTexture(m_gameinfoLblSnap, emptyTex);
|
||||
m_btnMgr.setTexture(m_gameinfoLblCartDisk, emptyTex);
|
||||
m_btnMgr.setTexture(m_gameinfoLblOverlay, emptyTex);
|
||||
|
||||
// Get Game ID
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
{
|
||||
const dir_discHdr *GameHdr = CoverFlow.getHdr();
|
||||
ShortName = m_plugin.GetRomName(GameHdr);
|
||||
strncpy(GameID, m_plugin.GetRomId(GameHdr, m_pluginDataDir.c_str(), platformName, ShortName).c_str(), 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(GameID, CoverFlow.getId(), 6);
|
||||
}
|
||||
|
||||
if(gametdb.GetTitle(GameID, TMP_Char))
|
||||
{
|
||||
gameinfo_Title_w.fromUTF8(TMP_Char);
|
||||
m_btnMgr.setText(m_gameinfoLblTitle, gameinfo_Title_w);
|
||||
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
{
|
||||
// Try to find images by game's name
|
||||
if(gametdb.GetName(GameID, TMP_Char))
|
||||
{
|
||||
const char *snap_path = NULL;
|
||||
const char *cart_path = NULL;
|
||||
const char *overlay_path = NULL;
|
||||
|
||||
// Use real filename without extension for arcade games.
|
||||
if(strcasestr(platformName, "ARCADE") || strcasestr(platformName, "CPS") || !strncasecmp(platformName, "NEOGEO", 6))
|
||||
{
|
||||
snap_path = fmt("%s/%s/%s.png", m_snapDir.c_str(), platformName, ShortName.c_str());
|
||||
cart_path = fmt("%s/%s/%s_2D.png", m_cartDir.c_str(), platformName, ShortName.c_str());
|
||||
}
|
||||
// Name from the database.
|
||||
else
|
||||
{
|
||||
snap_path = fmt("%s/%s/%s.png", m_snapDir.c_str(), platformName, TMP_Char);
|
||||
cart_path = fmt("%s/%s/%s_2D.png", m_cartDir.c_str(), platformName, TMP_Char);
|
||||
}
|
||||
|
||||
// Try to find images by game's ID
|
||||
if(!fsop_FileExist( snap_path ))
|
||||
{
|
||||
snap_path = fmt("%s/%s/%s.png", m_snapDir.c_str(), platformName, GameID);
|
||||
cart_path = fmt("%s/%s/%s_2D.png", m_cartDir.c_str(), platformName, GameID);
|
||||
|
||||
if(!fsop_FileExist( snap_path ))
|
||||
{
|
||||
TexHandle.Cleanup(m_snap);
|
||||
TexHandle.Cleanup(m_cart);
|
||||
}
|
||||
}
|
||||
|
||||
TexHandle.fromImageFile(m_snap, snap_path);
|
||||
m_btnMgr.setTexture(m_gameinfoLblSnap, m_snap, m_snap.width, m_snap.height);
|
||||
TexHandle.fromImageFile(m_cart, cart_path);
|
||||
|
||||
if( m_cart.height > 112 )
|
||||
{
|
||||
m_btnMgr.setTexture(m_gameinfoLblCartDisk, m_cart, 114, 128);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_btnMgr.setTexture(m_gameinfoLblCartDisk, m_cart, 160, 112);
|
||||
}
|
||||
|
||||
overlay_path = fmt("%s/%s_overlay.png", m_snapDir.c_str(), platformName);
|
||||
|
||||
if(fsop_FileExist( overlay_path ))
|
||||
{
|
||||
TexHandle.fromImageFile(m_overlay, overlay_path);
|
||||
m_btnMgr.setTexture(m_gameinfoLblOverlay, m_overlay, m_overlay.width, m_overlay.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_btnMgr.setTexture(m_gameinfoLblOverlay, emptyTex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -254,29 +386,54 @@ void CMenu::_textGameInfo(void)
|
||||
gametdb.CloseFile();
|
||||
return;
|
||||
}
|
||||
|
||||
if(gametdb.GetSynopsis(GameID, TMP_Char))
|
||||
{
|
||||
gameinfo_Synopsis_w.fromUTF8(TMP_Char);
|
||||
m_btnMgr.setText(m_gameinfoLblSynopsis, gameinfo_Synopsis_w);
|
||||
}
|
||||
m_btnMgr.setText(m_gameinfoLblID, wfmt(L"GameID: %s", GameID), true);
|
||||
if(gametdb.GetDeveloper(GameID, TMP_Char))
|
||||
m_btnMgr.setText(m_gameinfoLblDev, wfmt(_fmt("gameinfo1",L"Developer: %s"), TMP_Char), true);
|
||||
if(gametdb.GetPublisher(GameID, TMP_Char))
|
||||
m_btnMgr.setText(m_gameinfoLblPublisher, wfmt(_fmt("gameinfo2",L"Publisher: %s"), TMP_Char), true);
|
||||
if(gametdb.GetRegion(GameID, TMP_Char))
|
||||
m_btnMgr.setText(m_gameinfoLblRegion, wfmt(_fmt("gameinfo3",L"Region: %s"), TMP_Char), true);
|
||||
if(gametdb.GetGenres(GameID, TMP_Char))
|
||||
|
||||
// Only show retrieved data else the text is often underneath the snapshot.
|
||||
// It's still too long sometimes. Maybe, we should cut the string at a max length.
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
{
|
||||
vector<string> genres = stringToVector(TMP_Char, ',');
|
||||
string s;
|
||||
for(u32 i = 0; i < genres.size(); ++i)
|
||||
if(gametdb.GetDeveloper(GameID, TMP_Char))
|
||||
m_btnMgr.setText(m_gameinfoLblDev, wfmt(_fmt("",L"%s"), TMP_Char), true);
|
||||
if(gametdb.GetPublisher(GameID, TMP_Char))
|
||||
m_btnMgr.setText(m_gameinfoLblPublisher, wfmt(_fmt("",L"%s"), TMP_Char), true);
|
||||
if(gametdb.GetRegion(GameID, TMP_Char))
|
||||
m_btnMgr.setText(m_gameinfoLblRegion, wfmt(_fmt("gameinfo3",L"Region: %s"), TMP_Char), true);
|
||||
if(gametdb.GetGenres(GameID, TMP_Char))
|
||||
{
|
||||
if(i > 0)
|
||||
s.append(", ");// add comma & space between genres
|
||||
s.append(genres[i]);
|
||||
m_btnMgr.setText(m_gameinfoLblGenre, wfmt(_fmt("",L"%s"), TMP_Char), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Genre not found, show nothing.
|
||||
m_btnMgr.setText(m_gameinfoLblGenre, wfmt(_fmt("",L"")), true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(gametdb.GetDeveloper(GameID, TMP_Char))
|
||||
m_btnMgr.setText(m_gameinfoLblDev, wfmt(_fmt("gameinfo1",L"Developer: %s"), TMP_Char), true);
|
||||
if(gametdb.GetPublisher(GameID, TMP_Char))
|
||||
m_btnMgr.setText(m_gameinfoLblPublisher, wfmt(_fmt("gameinfo2",L"Publisher: %s"), TMP_Char), true);
|
||||
if(gametdb.GetRegion(GameID, TMP_Char))
|
||||
m_btnMgr.setText(m_gameinfoLblRegion, wfmt(_fmt("gameinfo3",L"Region: %s"), TMP_Char), true);
|
||||
if(gametdb.GetGenres(GameID, TMP_Char))
|
||||
{
|
||||
vector<string> genres = stringToVector(TMP_Char, ',');
|
||||
string s;
|
||||
for(u32 i = 0; i < genres.size(); ++i)
|
||||
{
|
||||
if(i > 0)
|
||||
s.append(", ");// add comma & space between genres
|
||||
s.append(genres[i]);
|
||||
}
|
||||
m_btnMgr.setText(m_gameinfoLblGenre, wfmt(_fmt("gameinfo5",L"Genre: %s"), s.c_str()), true);
|
||||
}
|
||||
m_btnMgr.setText(m_gameinfoLblGenre, wfmt(_fmt("gameinfo5",L"Genre: %s"), s.c_str()), true);
|
||||
}
|
||||
|
||||
int PublishDate = gametdb.GetPublishDate(GameID);
|
||||
@ -288,15 +445,34 @@ void CMenu::_textGameInfo(void)
|
||||
case 0:
|
||||
case 4:
|
||||
case 5:
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("gameinfo4",L"Release Date: %i-%i-%i"), year, month, day), true);
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("",L"%i-%i-%i"), year, month, day), true);
|
||||
else
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("gameinfo4",L"Release Date: %i-%i-%i"), year, month, day), true);
|
||||
break;
|
||||
case 1:
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("gameinfo4",L"Release Date: %i-%i-%i"), month, day, year), true);
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("",L"%i-%i-%i"), month, day, year), true);
|
||||
else
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("gameinfo4",L"Release Date: %i-%i-%i"), month, day, year), true);
|
||||
break;
|
||||
case 2:
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("gameinfo4",L"Release Date: %i-%i-%i"), day, month, year), true);
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("",L"%i-%i-%i"), day, month, year), true);
|
||||
else
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("gameinfo4",L"Release Date: %i-%i-%i"), day, month, year), true);
|
||||
break;
|
||||
}
|
||||
|
||||
// Only display year or nothing if there's no date at all
|
||||
if(day == 0 && month == 0)
|
||||
{
|
||||
if(year != 0)
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("",L"%i"), year), true);
|
||||
else
|
||||
m_btnMgr.setText(m_gameinfoLblRlsdate, wfmt(_fmt("",L"")), true);
|
||||
}
|
||||
|
||||
//Ratings
|
||||
TexHandle.fromImageFile(m_rating, fmt("%s/norating.png", m_imgsDir.c_str()));
|
||||
const char *RatingValue = NULL;
|
||||
@ -356,10 +532,28 @@ void CMenu::_textGameInfo(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_btnMgr.setTexture(m_gameinfoLblRating, m_rating);
|
||||
// Display the user's mark /20 instead because most of the rating data is missing.
|
||||
if(CoverFlow.getHdr()->type == TYPE_PLUGIN)
|
||||
{
|
||||
if(gametdb.GetRatingValue(GameID, RatingValue))
|
||||
{
|
||||
if(RatingValue[0] != '\0')
|
||||
{
|
||||
m_btnMgr.setText(m_gameinfoLblRating, wfmt(_fmt("",L"%s/20"), RatingValue), true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_btnMgr.setText(m_gameinfoLblRating, wfmt(_fmt("",L"")), true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_btnMgr.setText(m_gameinfoLblRating, wfmt(_fmt("",L"")), true);
|
||||
m_btnMgr.setTexture(m_gameinfoLblRating, m_rating);
|
||||
}
|
||||
//Wifi players
|
||||
int WifiPlayers = gametdb.GetWifiPlayers(GameID);
|
||||
TexData emptyTex;
|
||||
if(WifiPlayers == 1)
|
||||
TexHandle.fromImageFile(m_wifi, fmt("%s/wifi1.png", m_imgsDir.c_str()));
|
||||
else if(WifiPlayers == 2)
|
||||
@ -440,6 +634,8 @@ void CMenu::_textGameInfo(void)
|
||||
TexHandle.fromImageFile(m_controlsreq[x], fmt("%s/wiimote3.png", m_imgsDir.c_str()));
|
||||
else if(players == 4)
|
||||
TexHandle.fromImageFile(m_controlsreq[x], fmt("%s/wiimote4.png", m_imgsDir.c_str()));
|
||||
else if(players == 5)
|
||||
TexHandle.fromImageFile(m_controlsreq[x], fmt("%s/wiimote5.png", m_imgsDir.c_str()));
|
||||
else if(players == 6)
|
||||
TexHandle.fromImageFile(m_controlsreq[x], fmt("%s/wiimote6.png", m_imgsDir.c_str()));
|
||||
else if(players == 8)
|
||||
|
@ -29,6 +29,13 @@
|
||||
#include "types.h"
|
||||
#include "crc32.h"
|
||||
|
||||
// For PS1 serial
|
||||
#ifdef MSB_FIRST
|
||||
#define MODETEST_VAL 0x00ffffff
|
||||
#else
|
||||
#define MODETEST_VAL 0xffffff00
|
||||
#endif
|
||||
|
||||
Plugin m_plugin;
|
||||
void Plugin::init(const string& m_pluginsDir)
|
||||
{
|
||||
@ -280,6 +287,322 @@ vector<string> Plugin::CreateArgs(const char *device, const char *path,
|
||||
return args;
|
||||
}
|
||||
|
||||
/* Give the current game a simplified name */
|
||||
string Plugin::GetRomName(const dir_discHdr *gameHeader)
|
||||
{
|
||||
if(strrchr(gameHeader->path, '/') != NULL)
|
||||
{
|
||||
// Remove extension
|
||||
string FullName = strrchr(gameHeader->path, '/') + 1;
|
||||
FullName = FullName.substr(0, FullName.find_last_of("."));
|
||||
|
||||
// Remove common suffixes and replace unwanted characters.
|
||||
string ShortName = FullName.substr(0, FullName.find(" (")).substr(0, FullName.find(" ["));
|
||||
replace(ShortName.begin(), ShortName.end(), '_', ' ');
|
||||
return ShortName;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get serial from PS1 header's iso (Borrowed from Retroarch with a few c++ changes)*/
|
||||
static int GetSerialPS1(const char *path, string &Serial, int sub_channel_mixed)
|
||||
{
|
||||
char *tmp;
|
||||
int skip, frame_size, is_mode1, cd_sector;
|
||||
char buffer[2048 * 2];
|
||||
|
||||
ifstream fp;
|
||||
fp.open(path, ios::binary);
|
||||
|
||||
buffer[0] = '\0';
|
||||
is_mode1 = 0;
|
||||
|
||||
if ( !fp.seekg(0, ios::end) )
|
||||
goto error;
|
||||
|
||||
if (!sub_channel_mixed)
|
||||
{
|
||||
if ( (!fp.tellg()) & 0x7FF)
|
||||
{
|
||||
unsigned int mode_test = 0;
|
||||
|
||||
if ( !fp.seekg(0, ios::beg) )
|
||||
goto error;
|
||||
|
||||
fp.read(reinterpret_cast<char *>(mode_test), 4);
|
||||
|
||||
if (mode_test != MODETEST_VAL)
|
||||
is_mode1 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
skip = is_mode1? 0: 24;
|
||||
frame_size = sub_channel_mixed? 2448: is_mode1? 2048: 2352;
|
||||
|
||||
if ( !fp.seekg(156 + skip + 16 * frame_size, ios::beg) )
|
||||
goto error;
|
||||
|
||||
fp.read(buffer, 6);
|
||||
|
||||
cd_sector = buffer[2] | (buffer[3] << 8) | (buffer[4] << 16);
|
||||
|
||||
if ( !fp.seekg(skip + cd_sector * frame_size, ios::beg) )
|
||||
goto error;
|
||||
|
||||
fp.read(buffer, 2048 * 2);
|
||||
|
||||
tmp = buffer;
|
||||
while (tmp < (buffer + 2048 * 2))
|
||||
{
|
||||
if (!*tmp)
|
||||
goto error;
|
||||
|
||||
if (!strncasecmp((const char*)(tmp + 33), "SYSTEM.CNF;1", 12))
|
||||
break;
|
||||
tmp += *tmp;
|
||||
}
|
||||
|
||||
if(tmp >= (buffer + 2048 * 2))
|
||||
goto error;
|
||||
|
||||
cd_sector = tmp[2] | (tmp[3] << 8) | (tmp[4] << 16);
|
||||
if ( !fp.seekg(skip + cd_sector * frame_size, ios::beg) )
|
||||
goto error;
|
||||
|
||||
fp.read(buffer, 256);
|
||||
buffer[256] = '\0';
|
||||
|
||||
tmp = buffer;
|
||||
while(*tmp && strncasecmp((const char*)tmp, "boot", 4))
|
||||
tmp++;
|
||||
|
||||
if(!*tmp)
|
||||
goto error;
|
||||
|
||||
Serial = tmp;
|
||||
Serial.erase(0, Serial.find_first_of('\\') + 1);
|
||||
replace(Serial.begin(), Serial.end(), '_', '-');
|
||||
Serial.erase(remove(Serial.begin(), Serial.end(), '.'), Serial.end());
|
||||
Serial.erase(Serial.find_first_of(';'));
|
||||
|
||||
fp.close();
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get serial from MegaCD header's iso
|
||||
*
|
||||
* All headers should have "SEGADISCSYSTEM" in the first bytes.
|
||||
* The offset differs, the serial search depends on it.
|
||||
*/
|
||||
|
||||
void GetSerialMegaCD(const char *path, string &Serial)
|
||||
{
|
||||
ifstream infile;
|
||||
char buf[10];
|
||||
|
||||
infile.open(path, ios::binary);
|
||||
infile.seekg(0, ios::beg);
|
||||
infile.read ((char*)buf, 4);
|
||||
buf[4] = '\0';
|
||||
|
||||
// iso or bin offset.
|
||||
if (!strcasecmp(buf, "SEGA"))
|
||||
infile.seekg(0x182, ios::beg);
|
||||
else
|
||||
{
|
||||
infile.seekg(0x10, ios::beg);
|
||||
infile.read ((char*)buf, 4);
|
||||
|
||||
if (!strcasecmp(buf, "SEGA"))
|
||||
infile.seekg(0x192, ios::beg);
|
||||
}
|
||||
|
||||
infile.read(buf, 9);
|
||||
buf[9] = '\0';
|
||||
infile.close();
|
||||
|
||||
Serial = buf;
|
||||
Serial.erase(remove(Serial.begin(), Serial.end(), ' '), Serial.end());
|
||||
|
||||
// Cut at second dash, we don't need any extra code.
|
||||
// Sonic CD : MK-4407(-00)
|
||||
size_t dash = std::count(Serial.begin(), Serial.end(), '-');
|
||||
|
||||
if(dash > 1)
|
||||
Serial.erase(Serial.find_last_of('-'));
|
||||
|
||||
infile.close();
|
||||
}
|
||||
|
||||
|
||||
/* Get the Game ID based on name or CRC/Serial
|
||||
*
|
||||
* It returns the ID used to search in the platform database(SUPERNES.xml for instance)
|
||||
* and can also be used for snapshots/cartriges/discs images.
|
||||
* The Game ID is a 6 length alphanumerical value. It's screenscraper ID filled with 'A' letter.
|
||||
*/
|
||||
string Plugin::GetRomId(const dir_discHdr *gameHeader, const char *datadir, char *platform, const string &name)
|
||||
{
|
||||
string GameID;
|
||||
string CRC_Serial(12, '*');
|
||||
|
||||
// Load a platform list that is used to identify the current game.
|
||||
// It contains a default filename(preferably No-intro without region flag), the GameID and then all known CRC32/serials.
|
||||
// filename=GameID|crc1|crc2|etc...
|
||||
// For example in SUPERNES.ini : Super Aleste=2241AA|5CA5781B|...
|
||||
Config m_crc;
|
||||
m_crc.unload();
|
||||
m_crc.load(fmt("%s/%s/%s.ini", datadir, platform, platform) );
|
||||
|
||||
bool found_name = false;
|
||||
found_name = m_crc.has(platform, name.c_str());
|
||||
|
||||
// Get game ID based on the filename
|
||||
if(found_name)
|
||||
{
|
||||
vector<string> searchID = m_crc.getStrings(platform, name.c_str(), '|');
|
||||
|
||||
if(!searchID.empty())
|
||||
{
|
||||
GameID = searchID[0];
|
||||
}
|
||||
|
||||
m_crc.unload();
|
||||
}
|
||||
// Get game ID by CRC or serial
|
||||
else
|
||||
{
|
||||
m_crc.unload();
|
||||
|
||||
char crc_string[9];
|
||||
crc_string[0] = '\0';
|
||||
u32 buffer;
|
||||
ifstream infile;
|
||||
|
||||
// For arcade games use the crc zip
|
||||
if(strcasestr(platform, "ARCADE") || strcasestr(platform, "CPS") || !strncasecmp(platform, "NEOGEO", 6))
|
||||
{
|
||||
strncpy(crc_string, fmt("%08x", crc32file(gameHeader->path)), 8);
|
||||
crc_string[8] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Look for for the file's crc inside the archive
|
||||
if(strstr(gameHeader->path, ".zip") != NULL)
|
||||
{
|
||||
infile.open(gameHeader->path, ios::binary);
|
||||
infile.seekg(0x0e, ios::beg);
|
||||
infile.read((char*)&buffer, 8);
|
||||
infile.close();
|
||||
strncpy(crc_string, fmt("%08x", (u32)__builtin_bswap32(buffer)), 8);
|
||||
crc_string[8] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check a serial in header's file instead of crc for these CD based platforms.
|
||||
// CRC calculation would take up to 30 seconds!
|
||||
if(!strcasecmp(platform, "MEGACD"))
|
||||
{
|
||||
GetSerialMegaCD(gameHeader->path, CRC_Serial);
|
||||
}
|
||||
else if(!strcasecmp(platform, "PS1"))
|
||||
{
|
||||
bool found;
|
||||
found = GetSerialPS1(gameHeader->path, CRC_Serial, 0);
|
||||
|
||||
if(!found)
|
||||
GetSerialPS1(gameHeader->path, CRC_Serial, 1);
|
||||
}
|
||||
else if(!strcasecmp(platform, "ATARIST"))
|
||||
{
|
||||
s8 pos = m_plugin.GetPluginPosition(gameHeader->settings[0]);
|
||||
string FileTypes = m_plugin.GetFileTypes(pos);
|
||||
string path;
|
||||
|
||||
// Parse config to get floppy A path
|
||||
if(strcasestr(FileTypes.c_str(), ".cfg"))
|
||||
{
|
||||
Config m_cfg;
|
||||
m_cfg.unload();
|
||||
m_cfg.load(fmt("%s", gameHeader->path) );
|
||||
path = m_cfg.getString("Floppy", "szDiskAFileName", "");
|
||||
m_cfg.unload();
|
||||
|
||||
// Replace usb:/ with usb1:/ if needed
|
||||
if (path.find("usb:/") != std::string::npos)
|
||||
{
|
||||
path.insert(3, "1");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
path = gameHeader->path;
|
||||
}
|
||||
|
||||
if (path.find(".zip") != std::string::npos)
|
||||
{
|
||||
infile.open(path, ios::binary);
|
||||
infile.seekg(0x0e, ios::beg);
|
||||
infile.read((char*)&buffer, 8);
|
||||
infile.close();
|
||||
strncpy(crc_string, fmt("%08x", (u32)__builtin_bswap32(buffer)), 8);
|
||||
crc_string[8] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(crc_string, fmt("%08x", crc32file(path.c_str())), 8);
|
||||
crc_string[8] = '\0';
|
||||
}
|
||||
}
|
||||
// Just check CRC for a regular file on any other system.
|
||||
else
|
||||
{
|
||||
strncpy(crc_string, fmt("%08x", crc32file(gameHeader->path)), 8);
|
||||
crc_string[8] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(crc_string[0] != '\0')
|
||||
CRC_Serial = crc_string;
|
||||
|
||||
// Now search ID with the obtained CRC/Serial
|
||||
// Just add 2 pipes in the pattern to be sure we don't find a crc instead of ID
|
||||
size_t idx;
|
||||
idx=CRC_Serial.length();
|
||||
CRC_Serial.insert(0, "|").insert(idx+1, "|");
|
||||
|
||||
ifstream inputFile;
|
||||
inputFile.open( fmt("%s/%s/%s.ini", datadir, platform, platform) );
|
||||
string line;
|
||||
|
||||
while(getline(inputFile, line))
|
||||
{
|
||||
// FIXME ahem, ignore case...
|
||||
if (line.find(lowerCase( CRC_Serial ), 0) != string::npos || line.find(upperCase( CRC_Serial ), 0) != string::npos)
|
||||
{
|
||||
unsigned first = (line.find('=') + 1);
|
||||
unsigned last = line.find_first_of('|');
|
||||
string ID = line.substr (first,last-first);
|
||||
|
||||
if(ID.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
GameID = ID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GameID;
|
||||
}
|
||||
|
||||
string Plugin::GenerateCoverLink(dir_discHdr gameHeader, const string& constURL, Config &Checksums)
|
||||
{
|
||||
string url(constURL);
|
||||
|
@ -65,6 +65,8 @@ public:
|
||||
const char *GetDolName(u32 magic);
|
||||
const char *GetCoverFolderName(u32 magic);
|
||||
const char *GetRomDir(u8 pos);
|
||||
string GetRomName(const dir_discHdr *gameHeader);
|
||||
string GetRomId(const dir_discHdr *gameHeader,const char *datadir, char *platform, const string &name);
|
||||
int GetRomPartition(u8 pos);
|
||||
const string& GetFileTypes(u8 pos);
|
||||
wstringEx GetPluginName(u8 pos);
|
||||
|
Loading…
Reference in New Issue
Block a user