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:
parent
8a919816e1
commit
7e5f51b270
@ -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;
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user