Identify players by a unique ID and no more by their name, so that when you rename a player game slots are no longer so confused. This is a somewhat painful change, please report any breakage

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@11146 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2012-04-24 01:28:43 +00:00
parent 8a919816e1
commit 7e5f51b270
11 changed files with 112 additions and 35 deletions

View File

@ -188,7 +188,7 @@ void GameSlot::grandPrixFinished()
void GameSlot::save(XMLWriter& out)
{
out << L" <gameslot player=\"" << m_player_name.c_str() << L"\" kart=\""
out << L" <gameslot playerID=\"" << m_player_unique_id.c_str() << L"\" kart=\""
<< m_kart_ident.c_str() << L"\" firstTime=\"" << (m_first_time ? L"true" : L"false")
<< L"\">\n";
std::map<std::string, Challenge*>::const_iterator i;

View File

@ -38,9 +38,13 @@ class XMLWriter;
class GameSlot
{
irr::core::stringw m_player_name;
std::string m_kart_ident;
/** Profile names can change, so rather than try to make sure all renames are done everywhere,
* assign a unique ID to each profiler. Will save much headaches.
*/
std::string m_player_unique_id;
/** Contains whether each feature of the challenge is locked or unlocked */
std::map<std::string, bool> m_locked_features;
@ -61,14 +65,16 @@ class GameSlot
public:
GameSlot(const irr::core::stringw& player_name)
// do NOT attempt to pass 'player_unique_id' by reference here. I don't know why (compiler bug
// maybe?) but this screws up everything. Better pass by copy.
GameSlot(std::string player_unique_id)
{
m_player_name = player_name;
m_player_unique_id = player_unique_id;
m_points = 0;
m_first_time = true;
}
const irr::core::stringw& getPlayerName() const { return m_player_name; }
const std::string& getPlayerID() const { return m_player_unique_id; }
const std::string& getKartIdent () const { return m_kart_ident; }
void setKartIdent(const std::string& kart_ident) { m_kart_ident = kart_ident; }

View File

@ -46,7 +46,7 @@ UnlockManager::UnlockManager()
// in main).
unlock_manager = this;
m_current_game_slot = L"";
m_current_game_slot = "";
m_locked_sound = sfx_manager->createSoundSource("locked");
@ -92,7 +92,7 @@ UnlockManager::~UnlockManager()
}
std::map<irr::core::stringw, GameSlot*>::iterator it;
std::map<std::string, GameSlot*>::iterator it;
for (it = m_game_slots.begin(); it != m_game_slots.end(); it++)
{
delete it->second;
@ -213,16 +213,20 @@ void UnlockManager::load()
root->getNodes("gameslot", xml_game_slots);
for (unsigned int n=0; n<xml_game_slots.size(); n++)
{
core::stringw player_name;
xml_game_slots[n]->get("player", &player_name);
GameSlot* slot = new GameSlot(player_name);
std::string player_id;
if (!xml_game_slots[n]->get("playerID", &player_id))
{
fprintf(stderr, "[UnlockManager] WARNING: Found game slot without a player ID attached. Discarding it\n");
continue;
}
GameSlot* slot = new GameSlot(player_id);
std::string kart_id;
xml_game_slots[n]->get("kart", &kart_id);
slot->setKartIdent(kart_id);
m_game_slots[player_name] = slot;
m_game_slots[player_id] = slot;
bool first_time = true;
xml_game_slots[n]->get("firstTime", &first_time);
@ -263,7 +267,7 @@ void UnlockManager::save()
challenge_file << "<challenges>\n";
std::map<irr::core::stringw, GameSlot*>::iterator it;
std::map<std::string, GameSlot*>::iterator it;
for (it = m_game_slots.begin(); it != m_game_slots.end(); it++)
{
it->second->save(challenge_file);
@ -285,11 +289,11 @@ bool UnlockManager::createSlotsIfNeeded()
{
bool exists = false;
std::map<irr::core::stringw, GameSlot*>::iterator it;
std::map<std::string, GameSlot*>::iterator it;
for (it = m_game_slots.begin(); it != m_game_slots.end(); it++)
{
GameSlot* curr_slot = it->second;
if (curr_slot->getPlayerName() == players[n].getName())
if (curr_slot->getPlayerID() == players[n].getUniqueID())
{
exists = true;
break;
@ -298,8 +302,7 @@ bool UnlockManager::createSlotsIfNeeded()
if (!exists)
{
GameSlot* slot = new GameSlot(players[n].getName());
GameSlot* slot = new GameSlot(players[n].getUniqueID());
for(AllChallengesType::iterator i = m_all_challenges.begin();
i!=m_all_challenges.end(); i++)
{
@ -307,7 +310,8 @@ bool UnlockManager::createSlotsIfNeeded()
slot->m_challenges_state[cd->getId()] = new Challenge(cd);
}
slot->computeActive();
m_game_slots[players[n].getName()] = slot;
m_game_slots[players[n].getUniqueID()] = slot;
something_changed = true;
}
@ -341,7 +345,7 @@ PlayerProfile* UnlockManager::getCurrentPlayer()
PtrVector<PlayerProfile>& players = UserConfigParams::m_all_players;
for (int n=0; n<players.size(); n++)
{
if (players[n].getName() == m_current_game_slot) return players.get(n);
if (players[n].getUniqueID() == m_current_game_slot) return players.get(n);
}
return NULL;
}

View File

@ -48,12 +48,13 @@ private:
typedef std::map<std::string, ChallengeData*> AllChallengesType;
AllChallengesType m_all_challenges;
std::map<irr::core::stringw, GameSlot*> m_game_slots;
std::map<std::string, GameSlot*> m_game_slots;
void readAllChallengesInDirs(const std::vector<std::string>* all_dirs);
bool createSlotsIfNeeded();
irr::core::stringw m_current_game_slot;
/** ID of the active player */
std::string m_current_game_slot;
friend class GameSlot;
@ -71,12 +72,16 @@ public:
/** Eye- (or rather ear-) candy. Play a sound when user tries to access a locked area */
void playLockSound() const;
const core::stringw& getCurrentSlotName() const { return m_current_game_slot; }
const std::string& getCurrentSlotID() const { return m_current_game_slot; }
GameSlot* getCurrentSlot() { return m_game_slots[m_current_game_slot]; }
GameSlot* getCurrentSlot()
{
assert(m_game_slots.find(m_current_game_slot) != m_game_slots.end());
return m_game_slots[m_current_game_slot];
}
/** \param slotid name of the player */
void setCurrentSlot(irr::core::stringw slotid) { m_current_game_slot = slotid; }
void setCurrentSlot(std::string slotid) { m_current_game_slot = slotid; }
PlayerProfile* getCurrentPlayer();

View File

@ -22,6 +22,7 @@
#include <string>
#include "config/user_config.hpp"
#include "utils/no_copy.hpp"
#include "utils/string_utils.hpp"
#include <irrString.h>
using namespace irr;
@ -48,6 +49,18 @@ protected:
IntUserConfigParam m_use_frequency;
/** Profile names can change, so rather than try to make sure all renames are done everywhere,
* assign a unique ID to each profiler. Will save much headaches.
*/
StringUserConfigParam m_unique_id;
int64_t generateUniqueId(const char* playerName)
{
return ((int64_t)(Time::getTimeSinceEpoch()) << 32) |
(rand()%65536) << 16 |
(StringUtils::simpleHash(playerName) & 0xFFFF);
}
public:
/**
@ -56,11 +69,16 @@ public:
PlayerProfile(const core::stringw& name) : m_player_group("Player", "Represents one human player"),
m_name(name, "name", &m_player_group), //, m_last_kart_id(-1)
m_is_guest_account(false, "guest", &m_player_group),
m_use_frequency(0, "use_frequency", &m_player_group)
m_use_frequency(0, "use_frequency", &m_player_group),
m_unique_id("", "unique_id", &m_player_group)
{
#ifdef DEBUG
m_magic_number = 0xABCD1234;
#endif
int64_t unique_id = generateUniqueId(core::stringc(name.c_str()).c_str());
char buffer[32];
sprintf(buffer, "%llx", unique_id);
m_unique_id = buffer;
}
/**
@ -71,12 +89,23 @@ public:
PlayerProfile(const XMLNode* node) : m_player_group("Player", "Represents one human player"),
m_name("-", "name", &m_player_group), //, m_last_kart_id(-1)
m_is_guest_account(false, "guest", &m_player_group),
m_use_frequency(0, "use_frequency", &m_player_group)
m_use_frequency(0, "use_frequency", &m_player_group),
m_unique_id("", "unique_id", &m_player_group)
{
//m_player_group.findYourDataInAChildOf(node);
m_name.findYourDataInAnAttributeOf(node);
m_is_guest_account.findYourDataInAnAttributeOf(node);
m_use_frequency.findYourDataInAnAttributeOf(node);
m_unique_id.findYourDataInAnAttributeOf(node);
if ((std::string)m_unique_id == "")
{
fprintf(stderr, "** WARNING: Player has no unique ID, probably it is from an older STK version\n");
int64_t unique_id = generateUniqueId(core::stringc(m_name.c_str()).c_str());
char buffer[32];
sprintf(buffer, "%llx", unique_id);
m_unique_id = buffer;
}
#ifdef DEBUG
m_magic_number = 0xABCD1234;
@ -128,6 +157,12 @@ public:
else m_use_frequency++;
}
// please do NOT try to optimise this to return a reference, I don't know why,
// maybe compiler bug, but hell breaks loose when you do that
std::string getUniqueID() const
{
return m_unique_id;
}
};
#endif

View File

@ -976,7 +976,7 @@ int handleCmdLine(int argc, char **argv)
} // for i <argc
if(UserConfigParams::m_no_start_screen)
unlock_manager->setCurrentSlot(UserConfigParams::m_all_players[0]
.getName() );
.getUniqueID() );
if(ProfileWorld::isProfileMode())
{
UserConfigParams::m_sfx = false; // Disable sound effects
@ -1155,6 +1155,7 @@ bool ShowDumpResults(const wchar_t* dump_path,
}
#endif
int main(int argc, char *argv[] )
{
#ifdef BREAKPAD
@ -1162,7 +1163,7 @@ int main(int argc, char *argv[] )
NULL, google_breakpad::ExceptionHandler::HANDLER_ALL);
#endif
srand(( unsigned ) time( 0 ));
try {
// Init the minimum managers so that user config exists, then
// handle all command line options that do not need (or must

View File

@ -155,7 +155,7 @@ void PlayerInfoDialog::showConfirmDialog()
_("Do you really want to delete player '%s' ?", m_player->getName());
if (unlock_manager->getCurrentSlotName() == m_player->getName())
if (unlock_manager->getCurrentSlotID() == m_player->getUniqueID())
{
message = _("You cannot delete this player because it is currently in use.");
}
@ -169,7 +169,7 @@ void PlayerInfoDialog::showConfirmDialog()
m_irrlicht_window);
a->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
if (unlock_manager->getCurrentSlotName() != m_player->getName())
if (unlock_manager->getCurrentSlotID() != m_player->getUniqueID())
{
ButtonWidget* widget = new ButtonWidget();
widget->m_properties[PROP_ID] = "confirmremove";

View File

@ -87,7 +87,18 @@ void OptionsScreenPlayers::init()
}
ButtonWidget* you = getWidget<ButtonWidget>("playername");
you->setText( unlock_manager->getCurrentSlot()->getPlayerName() );
const std::string& playerID = unlock_manager->getCurrentSlot()->getPlayerID();
core::stringw playerName = L"-";
PlayerProfile* curr;
for_in (curr, UserConfigParams::m_all_players)
{
if (curr->getUniqueID() == playerID)
{
playerName = curr->getName();
break;
}
}
you->setText( playerName );
((gui::IGUIButton*)you->getIrrlichtElement())->setOverrideFont( GUIEngine::getSmallFont() );
if (StateManager::get()->getGameState() == GUIEngine::INGAME_MENU)

View File

@ -61,7 +61,7 @@ void StoryModeLobbyScreen::init()
{
if (players[n].getName() == UserConfigParams::m_default_player.toString())
{
unlock_manager->setCurrentSlot(players[n].getName());
unlock_manager->setCurrentSlot(players[n].getUniqueID());
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
return;
}
@ -113,9 +113,9 @@ void StoryModeLobbyScreen::eventCallback(Widget* widget, const std::string& name
{
if (list->getSelectionLabel() == players[n].getName())
{
unlock_manager->setCurrentSlot(players[n].getName());
unlock_manager->setCurrentSlot(players[n].getUniqueID());
slot_found = true;
break;;
break;
}
}
@ -155,7 +155,7 @@ void StoryModeLobbyScreen::onNewPlayerWithName(const stringw& newName)
{
if (players[n].getName() == newName)
{
unlock_manager->setCurrentSlot(players[n].getName());
unlock_manager->setCurrentSlot(players[n].getUniqueID());
slot_found = true;
break;
}

View File

@ -620,6 +620,18 @@ namespace StringUtils
return output.str();
} // encodeToHtmlEntities
// ------------------------------------------------------------------------
unsigned int simpleHash(const char* input)
{
int hash = 0;
for (int n=0; input[n] != 0; n++)
{
hash += (hash << (hash & 0xF)) ^ input[n];
}
return hash;
}
} // namespace StringUtils

View File

@ -362,6 +362,9 @@ namespace StringUtils
std::string encodeToHtmlEntities(const irr::core::stringw &output);
/** Compute a simple hash of a string */
unsigned int simpleHash(const char* input);
} // namespace StringUtils
#endif