274 lines
11 KiB
C++
274 lines
11 KiB
C++
//
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
// Copyright (C) 2012-2013 SuperTuxKart-Team
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 3
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
#include "config/player_profile.hpp"
|
|
|
|
#include "achievements/achievements_manager.hpp"
|
|
#include "challenges/unlock_manager.hpp"
|
|
#include "config/player_manager.hpp"
|
|
#include "karts/kart_properties.hpp"
|
|
#include "karts/kart_properties_manager.hpp"
|
|
#include "online/online_player_profile.hpp"
|
|
#include "io/xml_node.hpp"
|
|
#include "io/utf_writer.hpp"
|
|
#include "utils/string_utils.hpp"
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** Constructor to create a new player that didn't exist before.
|
|
* \param name Name of the player.
|
|
* \param is_guest True if this is a guest account.
|
|
*/
|
|
PlayerProfile::PlayerProfile(const core::stringw& name, bool is_guest)
|
|
{
|
|
#ifdef DEBUG
|
|
m_magic_number = 0xABCD1234;
|
|
#endif
|
|
m_local_name = name;
|
|
m_is_guest_account = is_guest;
|
|
m_use_frequency = is_guest ? -1 : 0;
|
|
m_unique_id = PlayerManager::get()->getUniqueId();
|
|
m_saved_session = false;
|
|
m_saved_token = "";
|
|
m_saved_user_id = 0;
|
|
m_last_online_name = "";
|
|
m_last_was_online = false;
|
|
m_remember_password = false;
|
|
initRemainingData();
|
|
} // PlayerProfile
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** Constructor to deserialize player data that was saved to a XML file. The
|
|
* constructor will only load the main player data (like name, id, saved
|
|
* online data), but not the achievements and story mode data. Reason is
|
|
* that the achievement and story mode data depends on other data to be
|
|
* read first (challenges and achievement files), which in turn can only be
|
|
* created later in the startup process (they depend on e.g. all tracks to
|
|
* be known). On the other hand, automatic login needs to happen asap (i.e.
|
|
* as soon as the network thread is started) to avoid the player having to
|
|
* wait for the login to finish , which needs the main player data (i.e.
|
|
* the default player, and saved session data). So the constructor only
|
|
* reads this data, the rest of the player data is handled in
|
|
* loadRemainingData later in the initialisation process.
|
|
* \param node The XML node representing this player.
|
|
*/
|
|
PlayerProfile::PlayerProfile(const XMLNode* node)
|
|
{
|
|
m_saved_session = false;
|
|
m_saved_token = "";
|
|
m_saved_user_id = 0;
|
|
m_last_online_name = "";
|
|
m_last_was_online = false;
|
|
m_remember_password = false;
|
|
m_story_mode_status = NULL;
|
|
m_achievements_status = NULL;
|
|
m_icon_filename = "";
|
|
|
|
node->get("name", &m_local_name );
|
|
node->get("guest", &m_is_guest_account );
|
|
node->get("use-frequency", &m_use_frequency );
|
|
node->get("unique-id", &m_unique_id );
|
|
node->get("saved-session", &m_saved_session );
|
|
node->get("saved-user", &m_saved_user_id );
|
|
node->get("saved-token", &m_saved_token );
|
|
node->get("last-online-name", &m_last_online_name );
|
|
node->get("last-was-online", &m_last_was_online );
|
|
node->get("remember-password", &m_remember_password);
|
|
node->get("icon-filename", &m_icon_filename );
|
|
|
|
#ifdef DEBUG
|
|
m_magic_number = 0xABCD1234;
|
|
#endif
|
|
|
|
} // PlayerProfile
|
|
|
|
//------------------------------------------------------------------------------
|
|
PlayerProfile::~PlayerProfile()
|
|
{
|
|
#ifdef DEBUG
|
|
m_magic_number = 0xDEADBEEF;
|
|
#endif
|
|
} // ~PlayerProfile
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** This function loads the achievement and story mode data. These can only
|
|
* be loaded after the UnlockManager is created, which needs the karts
|
|
* and tracks to be loaded first.
|
|
*/
|
|
void PlayerProfile::loadRemainingData(const XMLNode *node)
|
|
{
|
|
const XMLNode *xml_story_mode = node->getNode("story-mode");
|
|
m_story_mode_status =
|
|
unlock_manager->createStoryModeStatus(xml_story_mode);
|
|
const XMLNode *xml_achievements = node->getNode("achievements");
|
|
m_achievements_status = AchievementsManager::get()
|
|
->createAchievementsStatus(xml_achievements);
|
|
// Fix up any potentially missing icons.
|
|
addIcon();
|
|
} // initRemainingData
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** Initialises the story- and achievement data structure in case of the first
|
|
* start of STK.
|
|
*/
|
|
void PlayerProfile::initRemainingData()
|
|
{
|
|
m_story_mode_status = unlock_manager->createStoryModeStatus();
|
|
m_achievements_status =
|
|
AchievementsManager::get()->createAchievementsStatus();
|
|
addIcon();
|
|
} // initRemainingData
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** Creates an icon for a player if non exist so far. It takes the unique
|
|
* player id modulo the number of karts to pick an icon from the karts. It
|
|
* then uses the unique number plus the extentsion of the original icon as the
|
|
* file name (it's not possible to use the player name, since the name is in
|
|
* utf-16, but typically the file systems are not, resulting in incorrect file
|
|
* names). The icon is then copied to the user config directory, so that it
|
|
* can be replaced by an icon made by the user.
|
|
* If there should be an error copying the file, the icon filename is set
|
|
* to "". Every time stk is started, it will try to fix missing icons
|
|
* (which allows it to start from old/incompatible config files).
|
|
* \pre This function must only be called after all karts are read in.
|
|
*/
|
|
void PlayerProfile::addIcon()
|
|
{
|
|
if (m_icon_filename.size() > 0 || isGuestAccount())
|
|
return;
|
|
|
|
int n = m_unique_id % kart_properties_manager->getNumberOfKarts();
|
|
std::string source = kart_properties_manager->getKartById(n)
|
|
->getAbsoluteIconFile();
|
|
// Create the filename for the icon of this player: the unique id
|
|
// followed by .png or .jpg.
|
|
std::ostringstream out;
|
|
out << m_unique_id <<"."<<StringUtils::getExtension(source);
|
|
if(file_manager->copyFile(source,
|
|
file_manager->getUserConfigFile(out.str())) )
|
|
{
|
|
m_icon_filename = out.str();
|
|
}
|
|
else
|
|
{
|
|
m_icon_filename = "";
|
|
}
|
|
} // addIcon
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** Returns the name of the icon file for this player. If the player icon
|
|
* file is undefined, it returns a "?" mark texture. Note, getAsset does
|
|
* not return a reference, but only a temporary string. So we must return a
|
|
* copy of the string (not a reference to).
|
|
*/
|
|
const std::string PlayerProfile::getIconFilename() const
|
|
{
|
|
// If the icon file is undefined or does not exist, return the "?" icon
|
|
if(m_icon_filename.size()==0 ||
|
|
!file_manager->fileExists(file_manager->getUserConfigFile(m_icon_filename)))
|
|
{
|
|
return file_manager->getAsset(FileManager::GUI, "main_help.png");
|
|
}
|
|
|
|
return file_manager->getUserConfigFile(m_icon_filename);
|
|
} // getIconFilename
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** Writes the data for this player to the specified UTFWriter.
|
|
* \param out The utf writer to write the data to.
|
|
*/
|
|
void PlayerProfile::save(UTFWriter &out)
|
|
{
|
|
out << L" <player name=\"" << m_local_name
|
|
<< L"\" guest=\"" << m_is_guest_account
|
|
<< L"\" use-frequency=\"" << m_use_frequency << L"\"\n";
|
|
|
|
out << L" icon-filename=\"" << m_icon_filename <<L"\"\n";
|
|
|
|
out << L" unique-id=\"" << m_unique_id
|
|
<< L"\" saved-session=\"" << m_saved_session << L"\"\n";
|
|
|
|
out << L" saved-user=\"" << m_saved_user_id
|
|
<< L"\" saved-token=\"" << m_saved_token << L"\"\n";
|
|
out << L" last-online-name=\"" << m_last_online_name
|
|
<< L"\" last-was-online=\"" << m_last_was_online << L"\"\n";
|
|
out << L" remember-password=\"" << m_remember_password << L"\">\n";
|
|
{
|
|
if(m_story_mode_status)
|
|
m_story_mode_status->save(out);
|
|
|
|
if(m_achievements_status)
|
|
m_achievements_status->save(out);
|
|
}
|
|
out << L" </player>\n";
|
|
} // save
|
|
|
|
//------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------
|
|
/** Saves the online data, so that it will automatically re-connect
|
|
* next time this profile is loaded.
|
|
* \param user_id Id of the online profile.
|
|
* \param token Token used for authentication.
|
|
*/
|
|
void PlayerProfile::saveSession(int user_id, const std::string &token)
|
|
{
|
|
m_saved_session = true;
|
|
m_saved_user_id = user_id;
|
|
m_saved_token = token;
|
|
PlayerManager::get()->save();
|
|
} // saveSession
|
|
|
|
// ------------------------------------------------------------------------
|
|
/** Unsets any saved session data. */
|
|
void PlayerProfile::clearSession()
|
|
{
|
|
m_saved_session = false;
|
|
m_saved_user_id = 0;
|
|
m_saved_token = "";
|
|
PlayerManager::get()->save();
|
|
} // clearSession
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** Increments how often that account was used. Guest accounts are not counted.
|
|
*/
|
|
void PlayerProfile::incrementUseFrequency()
|
|
{
|
|
if (m_is_guest_account) m_use_frequency = -1;
|
|
else m_use_frequency++;
|
|
} // incrementUseFrequency
|
|
|
|
// ------------------------------------------------------------------------
|
|
/** Notification of a finished race, which can trigger fulfilling
|
|
* challenges. */
|
|
void PlayerProfile::raceFinished()
|
|
{
|
|
m_story_mode_status->raceFinished();
|
|
m_achievements_status->onRaceEnd();
|
|
} // raceFinished
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** Comparison used to sort players.
|
|
*/
|
|
bool PlayerProfile::operator<(const PlayerProfile &other)
|
|
{
|
|
return m_use_frequency < other.m_use_frequency;
|
|
} // operator<
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|