Skip to content

Commit

Permalink
Rewrite favorite system
Browse files Browse the repository at this point in the history
  • Loading branch information
CodingJellyfish committed Aug 9, 2024
1 parent c61ab02 commit 7f78b5b
Show file tree
Hide file tree
Showing 14 changed files with 563 additions and 189 deletions.
13 changes: 10 additions & 3 deletions data/gui/screens/arenas.stkgui
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@
<icon-button id="back" x="1%" y="0" height="9%" icon="gui/icons/back.png"/>

<div x="2%" y="1%" width="96%" height="99%" layout="vertical-row" >
<header height="8%" width="80%" I18N="Section in arena tracks selection screen" text="Arenas"
align="center" text_align="center" />
<spacer width="20" height="1%" />
<div width="100%" height="8%" layout="horizontal-row" >
<spacer width="30%" height="100%" />
<header height="8%" width="40%" I18N="Section in arena tracks selection screen" text="Arenas"
align="center" text_align="center" />
<spacer width="1%" height="100%" />
<checkbox id="favorite" align="center"/>
<spacer width="1%" height="100%" />
<bright width="30%" height="100%" I18N="In the track and grand prix selection screen" text="Edit favorite tracks"/>
<spacer width="20" height="1%" />
</div>

<box proportion="1" width="100%" layout="vertical-row" padding="2">
<ribbon_grid id="tracks" proportion="1" width="100%" square_items="true"
Expand Down
4 changes: 2 additions & 2 deletions data/gui/screens/tracks_and_gp.stkgui
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
<div width="100%" height="fit" layout="horizontal-row" >
<header width="30%" I18N="In the track and grand prix selection screen" text="All Tracks"
align="center" text_align="center" />
<textbox width="35%" id="search"/>
<textbox width="40%" id="search"/>
<spacer width="1%" height="100%" />
<checkbox id="favorite"/>
<spacer width="1%" height="100%" />
<label width="30%" height="100%" I18N="In the track and grand prix selection screen" text="Edit favorite tracks"/>
<bright width="25%" height="100%" I18N="In the track and grand prix selection screen" text="Edit favorite tracks"/>
</div>

<spacer width="100%" height="1%" />
Expand Down
129 changes: 129 additions & 0 deletions src/config/favorite_track_status.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2012-2015 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/favorite_track_status.hpp"

#include "config/player_manager.hpp"
#include "io/utf_writer.hpp"
#include "io/xml_node.hpp"
#include "utils/string_utils.hpp"

const std::string FavoriteTrackStatus::DEFAULT_FAVORITE_GROUP_NAME = "Favorites";

//------------------------------------------------------------------------------
FavoriteTrackStatus::FavoriteTrackStatus(const XMLNode* node)
{
std::vector<XMLNode*> xml_favorite_tracks;
std::vector<XMLNode*> xml_favorite_groups;

if (node)
{
node->getNodes("track", xml_favorite_tracks);
node->getNodes("group", xml_favorite_groups);
}
for (unsigned int i = 0; i < xml_favorite_tracks.size(); i++)
{
std::string temp_string;
xml_favorite_tracks[i]->get("ident", &temp_string);
m_favorite_tracks[DEFAULT_FAVORITE_GROUP_NAME].insert(temp_string);
}
for (unsigned int i = 0; i < xml_favorite_groups.size(); i++)
{
std::string temp_group_string;
std::vector<XMLNode*> temp_group;

xml_favorite_groups[i]->get("name", &temp_group_string);
xml_favorite_groups[i]->getNodes("track", temp_group);

for (unsigned int j = 0; j < temp_group.size(); j++)
{
std::string temp_string;
temp_group[j]->get("ident", &temp_string);
m_favorite_tracks[temp_group_string].insert(temp_string);
}
}
} // FavoriteTrackStatus

//------------------------------------------------------------------------------
FavoriteTrackStatus::~FavoriteTrackStatus()
{

} // ~FavoriteTrackStatus

//------------------------------------------------------------------------------
/** Adds a new favorite track to this player profile and to the group
* of favorite tracks of the Track Manager.
* To be used only if this player profile is the current player.
*/
bool FavoriteTrackStatus::isFavoriteTrack(std::string ident)
{
return m_favorite_tracks[DEFAULT_FAVORITE_GROUP_NAME].find(ident)
!= m_favorite_tracks[DEFAULT_FAVORITE_GROUP_NAME].end();
} // addFavoriteTrack

//------------------------------------------------------------------------------
/** Adds a new favorite track to this player profile and to the group
* of favorite tracks of the Track Manager.
*/
void FavoriteTrackStatus::addFavoriteTrack(std::string ident, std::string group)
{
m_favorite_tracks[group].insert(ident);
} // addFavoriteTrack

//------------------------------------------------------------------------------
/** Removes a favorite track from this player profile and from the group
* of favorite tracks of the Track Manager.
*/
void FavoriteTrackStatus::removeFavoriteTrack(std::string ident, std::string group)
{
if (m_favorite_tracks[group].find(ident) != m_favorite_tracks[group].end())
{
m_favorite_tracks[group].erase(ident);
}
} // removeFavoriteTrack

//------------------------------------------------------------------------------
/** Writes the data for this player to the specified UTFWriter.
* \param out The utf writer to write the data to.
*/
void FavoriteTrackStatus::save(UTFWriter &out)
{
out << " <favorites>\n";
for (auto it_group = m_favorite_tracks.begin(); it_group != m_favorite_tracks.end(); it_group++)
{
std::string group_name = it_group->first;

if (group_name == DEFAULT_FAVORITE_GROUP_NAME)
{
for (auto it_track = it_group->second.begin(); it_track != it_group->second.end(); it_track++)
{
out << " <track ident=\"" << *it_track << "\"/>\n";
}
}
else
{
out << " <group name=\"" << group_name << "\">\n";
for (auto it_track = it_group->second.begin(); it_track != it_group->second.end(); it_track++)
{
out << " <track ident=\"" << *it_track << "\"/>\n";
}
out << " </group>\n";
}
}
out << " </favorites>\n";
} // save
74 changes: 74 additions & 0 deletions src/config/favorite_track_status.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2024 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.

#ifndef HEADER_FAVORITE_TRACK_STATUS_HPP
#define HEADER_FAVORITE_TRACK_STATUS_HPP

#include "utils/leak_check.hpp"

#include <irrString.h>

#include <set>
#include <string>
#include <unordered_map>

using namespace irr;

class TrackManager;
class UTFWriter;
class XMLNode;

/** Class for managing player profiles (name, usage frequency,
* etc.). All PlayerProfiles are managed by the PlayerManager.
* A PlayerProfile keeps track of the story mode progress using an instance
* of StoryModeStatus, and achievements with AchievementsStatus. All data
* is saved in the players.xml file.
* This class also defines the interface for handling online data. All of
* the online handling is done in the derived class OnlinePlayerProfile,
* where the interface is fully implemented.
* \ingroup config
*/
class FavoriteTrackStatus
{
private:
LEAK_CHECK()

/** unordered_map<Group Name, set<Track Name> > .*/
std::unordered_map<std::string, std::set<std::string> > m_favorite_tracks;

public:
friend class TrackManager;

static const std::string DEFAULT_FAVORITE_GROUP_NAME;

FavoriteTrackStatus(const XMLNode *node);

virtual ~FavoriteTrackStatus();

void save(UTFWriter &out);

bool isFavoriteTrack(std::string ident);

void addFavoriteTrack(std::string ident, std::string group = DEFAULT_FAVORITE_GROUP_NAME);

void removeFavoriteTrack(std::string ident, std::string group = DEFAULT_FAVORITE_GROUP_NAME);
}; // class PlayerProfile

#endif

/*EOF*/
5 changes: 0 additions & 5 deletions src/config/player_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,6 @@ void PlayerManager::initRemainingData()

// Sort player by frequency
m_all_players.insertionSort(/*start*/0, /*desc*/true);

// Load favorite tracks for the current player
if (m_current_player)
m_current_player->setFavoriteTracks();
} // initRemainingData

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -486,7 +482,6 @@ void PlayerManager::setCurrentPlayer(PlayerProfile *player)
if(m_current_player)
{
m_current_player->computeActive();
m_current_player->setFavoriteTracks();
}

if (player_has_changed)
Expand Down
81 changes: 15 additions & 66 deletions src/config/player_profile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ PlayerProfile::PlayerProfile(const XMLNode* node)
m_remember_password = false;
m_story_mode_status = NULL;
m_achievements_status = NULL;
m_favorite_tracks.clear();
m_favorite_track_status = NULL;
m_default_kart_color = 0.0f;
m_icon_filename = "";

Expand All @@ -106,6 +106,7 @@ PlayerProfile::~PlayerProfile()
{
delete m_story_mode_status;
delete m_achievements_status;
delete m_favorite_track_status;
#ifdef DEBUG
m_magic_number = 0xDEADBEEF;
#endif
Expand All @@ -118,29 +119,20 @@ PlayerProfile::~PlayerProfile()
*/
void PlayerProfile::loadRemainingData(const XMLNode *node)
{
assert(m_story_mode_status == NULL);
const XMLNode *xml_story_mode = node->getNode("story-mode");
m_story_mode_status =
unlock_manager->createStoryModeStatus(xml_story_mode);
m_story_mode_status = unlock_manager->createStoryModeStatus(xml_story_mode);

assert(m_achievements_status == NULL);
const XMLNode *xml_achievements = node->getNode("achievements");
m_achievements_status = AchievementsManager::get()
->createAchievementsStatus(xml_achievements, m_unique_id == 1);
->createAchievementsStatus(xml_achievements, m_unique_id == 1);

// We first load the list of all favorite tracks
// Some favorites may correspond to uninstalled addons, so we do not sanitize the strings
// TODO : handle Arena and Soccer fields
assert(m_favorite_track_statuss == NULL);
const XMLNode *xml_favorites = node->getNode("favorites");
std::vector<XMLNode*> xml_favorite_tracks;
xml_favorites->getNodes("track", xml_favorite_tracks);
for (unsigned int i = 0; i < xml_favorite_tracks.size(); i++)
{
std::string temp_string;
xml_favorite_tracks[i]->get("ident", &temp_string);
m_favorite_tracks.push_back(temp_string);
}
// Deduplicate the list just in case.
std::sort(m_favorite_tracks.begin(), m_favorite_tracks.end());
auto it = std::unique(m_favorite_tracks.begin(), m_favorite_tracks.end());
m_favorite_tracks.erase(it, m_favorite_tracks.end());
m_favorite_track_status = new FavoriteTrackStatus(xml_favorites);

// Fix up any potentially missing icons.
addIcon();
Expand All @@ -155,49 +147,10 @@ void PlayerProfile::initRemainingData()
m_story_mode_status = unlock_manager->createStoryModeStatus();
m_achievements_status =
AchievementsManager::get()->createAchievementsStatus();
m_favorite_track_status = new FavoriteTrackStatus(NULL);
addIcon();
} // initRemainingData

//------------------------------------------------------------------------------
/** Update the group of favorite tracks handled by the Track Manager.
* To be used only if this player profile is the current player.
*/
void PlayerProfile::setFavoriteTracks()
{
// Update the group data from the Track Manager
track_manager->clearFavoriteTracks();
for (unsigned int i = 0; i < m_favorite_tracks.size(); i++)
{
track_manager->addFavoriteTrack(m_favorite_tracks[i]);
}
} // setFavoriteTracks

//------------------------------------------------------------------------------
/** Adds a new favorite track to this player profile and to the group
* of favorite tracks of the Track Manager.
* To be used only if this player profile is the current player.
*/
void PlayerProfile::addFavoriteTrack(std::string ident)
{
m_favorite_tracks.push_back(ident);
track_manager->addFavoriteTrack(ident);
} // addFavoriteTrack

//------------------------------------------------------------------------------
/** Removes a favorite track from this player profile and from the group
* of favorite tracks of the Track Manager.
* To be used only if this player profile is the current player.
*/
void PlayerProfile::removeFavoriteTrack(std::string ident)
{
auto it = std::find(m_favorite_tracks.begin(), m_favorite_tracks.end(), ident);
if (it != m_favorite_tracks.end()) // the track to remove has been found
{
m_favorite_tracks.erase(it);
setFavoriteTracks();
}
} // removeFavoriteTrack

//------------------------------------------------------------------------------
/** 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
Expand Down Expand Up @@ -282,18 +235,14 @@ void PlayerProfile::save(UTFWriter &out)
if (player != NULL && (getName() == player->getName()))
is_current_player = true;

if(m_story_mode_status)
if (m_story_mode_status)
m_story_mode_status->save(out, is_current_player);

if(m_achievements_status)
if (m_achievements_status)
m_achievements_status->save(out);

out << " <favorites>\n";
for (unsigned int i=0; i < m_favorite_tracks.size(); i++)
{
out << " <track ident=\"" << m_favorite_tracks[i] << "\"/>\n";
}
out << " </favorites>\n";

if (m_favorite_track_status)
m_favorite_track_status->save(out);
}
out << " </player>\n";
} // save
Expand Down
Loading

0 comments on commit 7f78b5b

Please sign in to comment.