When installing addons the karts/tracks are now not all completely

reloaded, only the new addon is loaded. This should also fix a
(minor) memory leak when a kart model is updated (textures and
mesh weren't freed).


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10103 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2011-11-04 05:32:31 +00:00
parent 1088fd35c8
commit 227bcdd773
6 changed files with 245 additions and 83 deletions

View File

@ -407,15 +407,19 @@ bool AddonsManager::install(const Addon &addon)
// karts will not reload their meshes.
const KartProperties *prop =
kart_properties_manager->getKart(addon.getId());
// If the model already exist (i.e. it's an update, not a new install)
// make sure to remove the cached copy of the mesh
// If the model already exist, first remove the old kart
if(prop)
{
const KartModel &model = prop->getMasterKartModel();
irr_driver->removeMeshFromCache(model.getModel());
}
kart_properties_manager->removeKart(addon.getId());
kart_properties_manager->loadKart(addon.getDataDir());
}
saveInstalled(addon.getType());
else if (addon.getType()=="track" || addon.getType()=="arena")
{
Track *track = track_manager->getTrack(addon.getId());
if(track)
track_manager->removeTrack(addon.getId());
track_manager->loadTrack(addon.getDataDir());
}
saveInstalled();
return true;
} // install
@ -437,7 +441,15 @@ bool AddonsManager::uninstall(const Addon &addon)
//remove the addons directory
bool error = !file_manager->removeDirectory(addon.getDataDir());
saveInstalled(addon.getType());
if(addon.getType()=="kart")
{
kart_properties_manager->removeKart(addon.getId());
}
else if(addon.getType()=="track" || addon.getType()=="arena")
{
track_manager->removeTrack(addon.getId());
}
saveInstalled();
return !error;
} // uninstall

View File

@ -145,21 +145,17 @@ KartModel::~KartModel()
m_wheel_node[i]->drop();
}
// For now don't drop the textures: note that the mesh is not
// dropped either (which enables a reload of kart_properties
// without reading the full mesh again when a new addon is
// installed, see KartPropertiesManager::reLoadAllKarts).
// Therefore if the textures are dropped here, the mesh would
// reference a freed texture, causing a crash.
// While this potentially causes a memory leak, this is not
// important since all kart meshes and all textures they use
// are around till the very end of STK. The textures stay in
// irrlicht's texture cache, and will be freed on exit.
//if(m_is_master && m_wheel_model[i])
// irr_driver->dropAllTextures(m_wheel_model[i]);
if(m_is_master && m_wheel_model[i])
irr_driver->dropAllTextures(m_wheel_model[i]);
}
if(m_is_master)
{
irr_driver->dropAllTextures(m_mesh);
irr_driver->removeMeshFromCache(m_mesh);
}
#ifdef DEBUG
#if SKELETON_DEBUG
irr_driver->debug_meshes.clear();
@ -285,7 +281,7 @@ bool KartModel::loadModels(const KartProperties &kart_properties)
assert(m_is_master);
std::string full_path = kart_properties.getKartDir()+"/"+m_model_filename;
m_mesh = irr_driver->getAnimatedMesh(full_path);
irr_driver->grabAllTextures(m_mesh);
if(!m_mesh)
{
printf("Problems loading mesh '%s' - kart '%s' will not be available\n",

View File

@ -68,30 +68,96 @@ void KartPropertiesManager::unloadAllKarts()
m_karts_properties.clearAndDeleteAll();
m_selected_karts.clear();
m_kart_available.clear();
m_groups.clear();
m_groups_2_indices.clear();
m_all_groups.clear();
m_kart_search_path.clear();
} // removeTextures
} // unloadAllKarts
//-----------------------------------------------------------------------------
/** Reloads all karts, i.e. reloads the meshes and textures. This is used
* when changing the screen resolution.
*/
void KartPropertiesManager::reLoadAllKarts()
{
m_karts_properties.clearAndDeleteAll();
m_selected_karts.clear();
m_kart_available.clear();
m_groups.clear();
m_groups_2_indices.clear();
m_all_groups.clear();
//m_kart_search_path.clear();
loadAllKarts(false);
}
} // reLoadAllKarts
//-----------------------------------------------------------------------------
/** Remove a kart from the kart manager.
* \param id The kart id (i.e. name of the directory) to remove.
*/
void KartPropertiesManager::removeKart(const std::string &ident)
{
// Remove the kart properties from the vector of all kart properties
int index = getKartId(ident);
const KartProperties *kp = getKart(ident); // must be done before remove
m_karts_properties.remove(index);
m_all_kart_dirs.erase(m_all_kart_dirs.begin()+index);
m_kart_available.erase(m_kart_available.begin()+index);
// Remove the just removed kart from the 'group-name to kart property
// index' mapping. If a group is now empty (i.e. the removed kart was
// the only member of this group), remove the group
const std::vector<std::string> &groups = kp->getGroups();
for (unsigned int i=0; i<groups.size(); i++)
{
std::vector<int> ::iterator it;
it = std::find(m_groups_2_indices[groups[i]].begin(),
m_groups_2_indices[groups[i]].end(), index);
// Since we are iterating over all groups the kart belongs to,
// there must be an entry found
assert(it!=m_groups_2_indices[groups[i]].end());
m_groups_2_indices[groups[i]].erase(it);
// Check if the last kart of a group was removed
if(m_groups_2_indices[groups[i]].size()==0)
{
m_groups_2_indices.erase(groups[i]);
std::vector<std::string>::iterator its;
its = std::find(m_all_groups.begin(), m_all_groups.end(),
groups[i]);
assert(its!=m_all_groups.end());
m_all_groups.erase(its);
} // if m_groups_2_indices[groups[i]].size()==0)
} // for i in all groups the kart belongs to
// Adjust the indices of all kart properties in the 'group name to
// kart property index' mapping: all kart properties with an index
// greater than index were moved one position further to the beginning
std::map<std::string, std::vector<int> >::iterator it_gr;
for(it_gr=m_groups_2_indices.begin(); it_gr != m_groups_2_indices.end();
it_gr++)
{
for(unsigned int i=0; i<(*it_gr).second.size(); i++)
{
if( (*it_gr).second[i]>index)
(*it_gr).second[i]--;
}
}
delete kp;
// Only used for networking only, and it is safe to just clear it.
// If a networking game is started it will be initialised properly.
m_selected_karts.clear();
} // removeKart
//-----------------------------------------------------------------------------
/** Loads all kart properties and models.
*/
void KartPropertiesManager::loadAllKarts(bool loading_icon)
{
m_all_kart_dirs.clear();
for(std::vector<std::string>::const_iterator dir=m_kart_search_path.begin();
dir!=m_kart_search_path.end(); dir++)
std::vector<std::string>::const_iterator dir;
for(dir = m_kart_search_path.begin(); dir!=m_kart_search_path.end(); dir++)
{
// First check if there is a kart in the current directory
// -------------------------------------------------------
@ -109,9 +175,9 @@ void KartPropertiesManager::loadAllKarts(bool loading_icon)
if (loaded && loading_icon)
{
GUIEngine::addLoadingIcon(irr_driver->getTexture(
m_karts_properties[m_karts_properties.size()-1].getAbsoluteIconFile()
)
);
m_karts_properties[m_karts_properties.size()-1]
.getAbsoluteIconFile() )
);
}
} // for all files in the currently handled directory
} // for i
@ -145,7 +211,8 @@ bool KartPropertiesManager::loadKart(const std::string &dir)
if (kart_properties->getVersion() < stk_config->m_min_kart_version ||
kart_properties->getVersion() > stk_config->m_max_kart_version)
{
fprintf(stderr, "[KartPropertiesManager] Warning: kart '%s' is not supported by this binary, ignored.\n",
fprintf(stderr, "[KartPropertiesManager] Warning: kart '%s' is not "
"supported by this binary, ignored.\n",
kart_properties->getIdent().c_str());
delete kart_properties;
return false;
@ -156,17 +223,21 @@ bool KartPropertiesManager::loadKart(const std::string &dir)
const std::vector<std::string>& groups=kart_properties->getGroups();
for(unsigned int g=0; g<groups.size(); g++)
{
if(m_groups.find(groups[g])==m_groups.end())
if(m_groups_2_indices.find(groups[g])==m_groups_2_indices.end())
{
m_all_groups.push_back(groups[g]);
}
m_groups[groups[g]].push_back(m_karts_properties.size()-1);
m_groups_2_indices[groups[g]].push_back(m_karts_properties.size()-1);
}
m_all_kart_dirs.push_back(dir);
return true;
} // loadKartData
//-----------------------------------------------------------------------------
/** Returns index of the kart properties with the given ident.
* \return Index of kart (between 0 and number of karts - 1).
*/
const int KartPropertiesManager::getKartId(const std::string &ident) const
{
for (int i=0; i<m_karts_properties.size(); i++)
@ -181,7 +252,8 @@ const int KartPropertiesManager::getKartId(const std::string &ident) const
} // getKartId
//-----------------------------------------------------------------------------
const KartProperties* KartPropertiesManager::getKart(const std::string &ident) const
const KartProperties* KartPropertiesManager::getKart(
const std::string &ident) const
{
const KartProperties* kp;
for_in (kp, m_karts_properties)
@ -227,12 +299,14 @@ void KartPropertiesManager::setUnavailableKarts(std::vector<std::string> karts)
{
if (!m_kart_available[i]) continue;
if (std::find(karts.begin(), karts.end(), m_karts_properties[i].getIdent())
if (std::find(karts.begin(), karts.end(),
m_karts_properties[i].getIdent())
== karts.end())
{
m_kart_available[i] = false;
fprintf(stderr, "Kart '%s' not available on all clients, disabled.\n",
fprintf(stderr,
"Kart '%s' not available on all clients, disabled.\n",
m_karts_properties[i].getIdent().c_str());
} // kart not in list
} // for i in m_kart_properties
@ -242,13 +316,15 @@ void KartPropertiesManager::setUnavailableKarts(std::vector<std::string> karts)
/** Returns the (global) index of the n-th kart of a given group. If there is
* no such kart, -1 is returned.
*/
int KartPropertiesManager::getKartByGroup(const std::string& group, int n) const
int KartPropertiesManager::getKartByGroup(const std::string& group,
int n) const
{
int count=0;
for (int i=0; i<m_karts_properties.size(); i++)
{
std::vector<std::string> groups = m_karts_properties[i].getGroups();
if (std::find(groups.begin(), groups.end(), group) == groups.end()) continue;
if (std::find(groups.begin(), groups.end(), group) == groups.end())
continue;
if (count == n) return i;
count = count + 1;
}
@ -293,9 +369,13 @@ void KartPropertiesManager::selectKartName(const std::string &kart_name)
} // selectKartName
//-----------------------------------------------------------------------------
const std::vector<int> KartPropertiesManager::getKartsInGroup(const std::string& g)
/** Returns a vector with the indices of all karts in the specified group.
* \param g The name of the group for which the kart indicies should be
* determined
* \return A vector of indices with the karts in the given group.
*/
const std::vector<int> KartPropertiesManager::getKartsInGroup(
const std::string& g)
{
if (g == ALL_KART_GROUPS_ID)
{
@ -308,9 +388,9 @@ const std::vector<int> KartPropertiesManager::getKartsInGroup(const std::string&
}
else
{
return m_groups[g];
return m_groups_2_indices[g];
}
}
} // getKartsInGroup
//-----------------------------------------------------------------------------
/** Returns a list of randomly selected karts. This list firstly contains
@ -323,8 +403,8 @@ const std::vector<int> KartPropertiesManager::getKartsInGroup(const std::string&
* list of karts selected by the players.
*/
void KartPropertiesManager::getRandomKartList(int count,
RemoteKartInfoList& existing_karts,
std::vector<std::string> *ai_list)
RemoteKartInfoList& existing_karts,
std::vector<std::string> *ai_list)
{
// First: set up flags (based on global kart
// index) for which karts are already used
@ -332,7 +412,7 @@ void KartPropertiesManager::getRandomKartList(int count,
std::vector<bool> used;
used.resize(getNumberOfKarts(), false);
std::vector<std::string> randomKartQueue;
std::vector<std::string> random_kart_queue;
for (unsigned int i=0; i<existing_karts.size(); i++)
{
try
@ -344,7 +424,8 @@ void KartPropertiesManager::getRandomKartList(int count,
{
(void)ex;
std::cerr <<
"[KartPropertiesManager] getRandomKartList : WARNING, can't find kart '"
"[KartPropertiesManager] getRandomKartList : WARNING, "
"can't find kart '"
<< existing_karts[i].getKartName() << "'\n";
}
}
@ -359,7 +440,8 @@ void KartPropertiesManager::getRandomKartList(int count,
{
(void)ex;
std::cerr <<
"[KartPropertiesManager] getRandomKartList : WARNING, can't find kart '"
"[KartPropertiesManager] getRandomKartList : WARNING, "
"can't find kart '"
<< (*ai_list)[i] << "'\n";
}
}
@ -367,41 +449,47 @@ void KartPropertiesManager::getRandomKartList(int count,
do
{
// if we have no karts left in our queue, re-fill it
if (count > 0 && randomKartQueue.size() == 0)
if (count > 0 && random_kart_queue.size() == 0)
{
randomKartQueue.clear();
std::vector<int> kartsInGroup = getKartsInGroup(UserConfigParams::m_last_used_kart_group);
random_kart_queue.clear();
std::vector<int> karts_in_group =
getKartsInGroup(UserConfigParams::m_last_used_kart_group);
assert(kartsInGroup.size() > 0);
assert(karts_in_group.size() > 0);
// first try not to use a kart already used by a player
for (unsigned int i=0; i<kartsInGroup.size(); i++)
for (unsigned int i=0; i<karts_in_group.size(); i++)
{
if (!used[kartsInGroup[i]] && m_kart_available[kartsInGroup[i]] &&
!unlock_manager->isLocked(m_karts_properties[kartsInGroup[i]].getIdent()) )
const KartProperties &kp=m_karts_properties[karts_in_group[i]];
if (!used[karts_in_group[i]] &&
m_kart_available[karts_in_group[i]] &&
!unlock_manager->isLocked(kp.getIdent()) )
{
randomKartQueue.push_back(m_karts_properties[kartsInGroup[i]].getIdent());
random_kart_queue.push_back(kp.getIdent());
}
}
// if we really need to, reuse the same kart as the player
if (randomKartQueue.size() == 0)
if (random_kart_queue.size() == 0)
{
for (unsigned int i=0; i<kartsInGroup.size(); i++)
for (unsigned int i=0; i<karts_in_group.size(); i++)
{
randomKartQueue.push_back(m_karts_properties[kartsInGroup[i]].getIdent());
const KartProperties &kp =
m_karts_properties[karts_in_group[i]];
random_kart_queue.push_back(kp.getIdent());
}
}
assert(randomKartQueue.size() > 0);
assert(random_kart_queue.size() > 0);
std::random_shuffle(randomKartQueue.begin(), randomKartQueue.end());
std::random_shuffle(random_kart_queue.begin(),
random_kart_queue.end() );
}
while (count > 0 && randomKartQueue.size() > 0)
while (count > 0 && random_kart_queue.size() > 0)
{
ai_list->push_back(randomKartQueue.back());
randomKartQueue.pop_back();
ai_list->push_back(random_kart_queue.back());
random_kart_queue.pop_back();
count --;
}

View File

@ -47,7 +47,7 @@ private:
std::vector<std::string> m_all_groups;
/** Mapping of group names to list of kart indices in each group. */
std::map<std::string, std::vector<int> > m_groups;
std::map<std::string, std::vector<int> > m_groups_2_indices;
/** Vector containing kart numbers that have been selected in multiplayer
* games. This it used to ensure the same kart can not be selected more
@ -58,7 +58,6 @@ private:
* all clients or not. */
std::vector<bool> m_kart_available;
bool loadKart(const std::string &dir);
protected:
typedef PtrVector<KartProperties> KartPropertiesVector;
@ -75,9 +74,11 @@ public:
int getKartByGroup(const std::string& group,
int i) const;
bool loadKart (const std::string &dir);
void loadAllKarts (bool loading_icon = true);
void unloadAllKarts ();
void reLoadAllKarts ();
void removeKart(const std::string &id);
const std::vector<int> getKartsInGroup (const std::string& g);
bool kartAvailable(int kartid);
std::vector<std::string> getAllAvailableKarts() const;

View File

@ -71,7 +71,6 @@ Track* TrackManager::getTrack(const std::string& ident) const
return *i;
}
std::cerr << "TrackManager: Couldn't find track: '" << ident << "'" << std::endl;
return NULL;
} // getTrack
@ -91,7 +90,8 @@ void TrackManager::setUnavailableTracks(const std::vector<std::string> &tracks)
if (std::find(tracks.begin(), tracks.end(), id)==tracks.end())
{
m_track_avail[i-m_tracks.begin()] = false;
fprintf(stderr, "Track '%s' not available on all clients, disabled.\n",
fprintf(stderr,
"Track '%s' not available on all clients, disabled.\n",
id.c_str());
} // if id not in tracks
} // for all available tracks in track manager
@ -161,7 +161,8 @@ bool TrackManager::loadTrack(const std::string& dirname)
if(track->getVersion()<stk_config->m_min_track_version ||
track->getVersion()>stk_config->m_max_track_version)
{
fprintf(stderr, "[TrackManager] Warning: track '%s' is not supported by this binary, ignored.\n",
fprintf(stderr, "[TrackManager] Warning: track '%s' is not supported "
"by this binary, ignored.\n",
track->getIdent().c_str());
delete track;
return false;
@ -173,6 +174,66 @@ bool TrackManager::loadTrack(const std::string& dirname)
return true;
} // loadTrack
// ----------------------------------------------------------------------------
/** Removes a track.
* \param ident Identifier of the track (i.e. the name of the directory).
*/
void TrackManager::removeTrack(const std::string &ident)
{
Track *track = getTrack(ident);
std::vector<Track*>::iterator it = std::find(m_tracks.begin(),
m_tracks.end(), track);
assert(it!=m_tracks.end());
int index = it - m_tracks.begin();
// Remove the track from all groups it belongs to
Group2Indices &group_2_indices = track->isArena() ? m_arena_groups
: m_track_groups;
std::vector<std::string> &group_names = track->isArena()
? m_arena_group_names
: m_track_group_names;
const std::vector<std::string>& groups=track->getGroups();
for(unsigned int i=0; i<groups.size(); i++)
{
std::vector<int> &indices = group_2_indices[groups[i]];
std::vector<int>::iterator j;
j = std::find(indices.begin(), indices.end(), index);
assert(j!=indices.end());
indices.erase(j);
// If the track was the last member of a group,
// completely remove the group
if(indices.size()==0)
{
group_2_indices.erase(groups[i]);
std::vector<std::string>::iterator it_g;
it_g = std::find(group_names.begin(), group_names.end(),
groups[i]);
assert(it_g!=group_names.end());
group_names.erase(it_g);
} // if complete group must be removed
} // for i in groups
// Adjust all indices of tracks with an index number higher than
// the removed track, since they have been moved down. This must
// be done for all tracks and all arenas
for(unsigned int i=0; i<2; i++) // i=0: arenas, i=1: tracks
{
Group2Indices &g2i = i==0 ? m_arena_groups : m_track_groups;
Group2Indices::iterator j;
for(j=g2i.begin(); j!=g2i.end(); j++)
{
for(unsigned int i=0; i<(*j).second.size(); i++)
if((*j).second[i]>index) (*j).second[i]--;
} // for j in group_2_indices
} // for i in arenas, tracks
m_tracks.erase(it);
m_all_track_dirs.erase(m_all_track_dirs.begin()+index);
m_track_avail.erase(m_track_avail.begin()+index);
delete track;
} // removeTrack
// ----------------------------------------------------------------------------
/** \brief Updates the groups after a track was read in.
* \param track Pointer to the new track, whose groups are now analysed.
@ -188,8 +249,10 @@ void TrackManager::updateGroups(const Track* track)
if (isArena)
{
// update the list of group names if necessary
const bool isInArenaGroupsList = (m_arena_groups.find(new_groups[i]) != m_arena_groups.end());
if (!isInArenaGroupsList) m_arena_group_names.push_back(new_groups[i]);
const bool isInArenaGroupsList =
(m_arena_groups.find(new_groups[i]) != m_arena_groups.end());
if (!isInArenaGroupsList)
m_arena_group_names.push_back(new_groups[i]);
// add this track to its group
m_arena_groups[new_groups[i]].push_back(m_tracks.size()-1);
@ -197,8 +260,10 @@ void TrackManager::updateGroups(const Track* track)
else
{
// update the list of group names if necessary
const bool isInTrackGroupsList = (m_track_groups.find(new_groups[i]) != m_track_groups.end());
if (!isInTrackGroupsList) m_track_group_names.push_back(new_groups[i]);
const bool isInTrackGroupsList =
(m_track_groups.find(new_groups[i]) != m_track_groups.end());
if (!isInTrackGroupsList)
m_track_group_names.push_back(new_groups[i]);
// add this track to its group
m_track_groups[new_groups[i]].push_back(m_tracks.size()-1);

View File

@ -44,11 +44,12 @@ private:
/** All track objects. */
Tracks m_tracks;
typedef std::map<std::string, std::vector<int> > Group2Indices;
/** List of all racing track groups. */
std::map<std::string, std::vector<int> > m_track_groups;
Group2Indices m_track_groups;
/** List of all arena groups. */
std::map<std::string, std::vector<int> > m_arena_groups;
Group2Indices m_arena_groups;
/** List of all groups (for both normal tracks and arenas) */
//std::vector<std::string> m_all_group_names;
@ -65,22 +66,18 @@ private:
std::vector<bool> m_track_avail;
void updateGroups(const Track* track);
bool loadTrack(const std::string& dirname);
public:
TrackManager();
~TrackManager();
static void addTrackSearchDir(const std::string &dir);
bool loadTrack(const std::string& dirname);
/** \brief Returns a list of all directories that contain a track. */
const std::vector<std::string>* getAllTrackDirs() const
{ return &m_all_track_dirs; }
/** \brief Returns a list of the names of all used groups (for tracks or arenas) */
//const std::vector<std::string>&
// getAllGroups() const { return m_all_group_names; }
/** \brief Returns a list of the names of all used track groups. */
const std::vector<std::string>&
getAllTrackGroups() const { return m_track_group_names; }
@ -122,7 +119,10 @@ public:
/** Load all .track files from all directories */
void loadTrackList();
};
void removeTrack(const std::string &ident);
}; // TrackManager
extern TrackManager* track_manager;