Implemented icon caching, and updated to support the future
web page (unfortunately the web server isn't up to that standard yet, so expect error messages, addons that don't work etc.). git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7367 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
3da1080eba
commit
9dde70687f
@ -36,7 +36,10 @@ Addon::Addon(const XMLNode &xml, bool installed)
|
||||
m_version = 0 ;
|
||||
m_zip_file = "";
|
||||
m_description = "";
|
||||
m_icon = "";
|
||||
m_icon_url = "";
|
||||
m_icon_basename = "";
|
||||
m_icon_version = 0;
|
||||
m_icon_ready = false;
|
||||
m_id = "";
|
||||
m_type = xml.getName();
|
||||
|
||||
@ -44,17 +47,19 @@ Addon::Addon(const XMLNode &xml, bool installed)
|
||||
if(m_installed)
|
||||
{
|
||||
xml.get("installed-version", &m_installed_version);
|
||||
xml.get("id", &m_id );
|
||||
xml.get("id", &m_id );
|
||||
xml.get("icon-version", &m_icon_version );
|
||||
}
|
||||
else // not installed
|
||||
{
|
||||
xml.get("file", &m_zip_file );
|
||||
xml.get("description", &m_description);
|
||||
xml.get("icon", &m_icon );
|
||||
xml.get("icon", &m_icon_url );
|
||||
xml.get("version", &m_version );
|
||||
// The online list has a numeric id, which is not used.
|
||||
// So ignore it.
|
||||
m_id = StringUtils::toLowerCase(m_name);
|
||||
m_icon_basename = StringUtils::getBasename(m_icon_url);
|
||||
} // if installed
|
||||
}; // Addon(const XML&)
|
||||
|
||||
@ -64,10 +69,12 @@ Addon::Addon(const XMLNode &xml, bool installed)
|
||||
*/
|
||||
void Addon::copyInstallData(const Addon &addon)
|
||||
{
|
||||
m_description = addon.m_description;
|
||||
m_version = addon.m_version;
|
||||
m_zip_file = addon.m_zip_file;
|
||||
m_icon = addon.m_icon;
|
||||
m_description = addon.m_description;
|
||||
m_version = addon.m_version;
|
||||
m_zip_file = addon.m_zip_file;
|
||||
m_icon_url = addon.m_icon_url;
|
||||
m_icon_basename = addon.m_icon_basename;
|
||||
m_icon_version = addon.m_version;
|
||||
} // copyInstallData
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -77,9 +84,13 @@ void Addon::copyInstallData(const Addon &addon)
|
||||
*/
|
||||
void Addon::writeXML(std::ofstream *out_stream)
|
||||
{
|
||||
(*out_stream) << " <" << m_type << " name=\"" << m_name
|
||||
<< "\" id=\"" << m_id << "\" installed-version=\""
|
||||
<< m_installed_version << "\"/>\n";
|
||||
(*out_stream) << " <" << m_type
|
||||
<< " name=\"" << m_name
|
||||
<< "\" id=\"" << m_id
|
||||
<< "\" installed=\"" << m_installed
|
||||
<< "\" installed-version=\"" << m_installed_version
|
||||
<<"\" icon-version=\"" << m_icon_version
|
||||
<< "\"/>\n";
|
||||
} // writeXML
|
||||
|
||||
#endif
|
||||
|
@ -38,10 +38,16 @@ public:
|
||||
int m_version;
|
||||
/** The currently installed version. */
|
||||
int m_installed_version;
|
||||
/** The version of the icon that was downloaded. */
|
||||
int m_icon_version;
|
||||
/** A description of this addon. */
|
||||
std::string m_description;
|
||||
/** The URL of the icon (relative to the server) */
|
||||
std::string m_icon_url;
|
||||
/** Name of the icon to use. */
|
||||
std::string m_icon;
|
||||
std::string m_icon_basename;
|
||||
/** True if the icon is cached/loaded and can be displayed. */
|
||||
bool m_icon_ready;
|
||||
/** The name of the zip file on the addon server. */
|
||||
std::string m_zip_file;
|
||||
/** True if the addon is installed. */
|
||||
@ -58,39 +64,51 @@ public:
|
||||
void copyInstallData(const Addon &addon);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of the addon. */
|
||||
const std::string& getName() const {return m_name; }
|
||||
const std::string& getName() const { return m_name; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the type of the addon. */
|
||||
const std::string& getType() const {return m_type; }
|
||||
const std::string& getType() const { return m_type; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the filename of the zip file with the addon. */
|
||||
const std::string& getZipFileName() const {return m_zip_file; }
|
||||
const std::string& getZipFileName() const { return m_zip_file; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of the icon of this addon. */
|
||||
const std::string& getIcon() const {return m_icon; }
|
||||
const std::string& getIconURL() const { return m_icon_url; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of the icon (i.e. the basename of the url). */
|
||||
const std::string getIconBasename() const { return m_icon_basename; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of the addon. */
|
||||
const std::string& getDescription() const {return m_description; }
|
||||
const std::string& getDescription() const { return m_description; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the addon is installed. */
|
||||
bool isInstalled() const {return m_installed; }
|
||||
bool isInstalled() const { return m_installed; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the installed version of an addon. */
|
||||
int getInstalledVersion() const {return m_installed_version; }
|
||||
int getInstalledVersion() const { return m_installed_version; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the latest version of this addon.
|
||||
* m_version>m_installed_version if a newer version is available
|
||||
* online. */
|
||||
int getVersion() const {return m_version; }
|
||||
int getVersion() const { return m_version; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the ID of this addon. */
|
||||
const std::string& getId() const {return m_id; }
|
||||
const std::string& getId() const { return m_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** True if this addon needs to be updated. */
|
||||
bool needsUpdate() const
|
||||
{
|
||||
return m_installed && getInstalledVersion() < getVersion();
|
||||
}
|
||||
} // needsUpdate
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if the (cached) icon needs to be updated. This is the
|
||||
* case if the addon version number is higher than the version number
|
||||
* of the icon (this leaves some chance of false positives - i.e. icons
|
||||
* that were not changed will still be downloaded). */
|
||||
bool iconNeedsUpdate() const
|
||||
{
|
||||
return m_version > m_icon_version;
|
||||
} // iconNeedsUpdate
|
||||
// ------------------------------------------------------------------------
|
||||
/** Marks this addon to be installed. If the addon is marked as being
|
||||
* installed, it also updates the installed version number to be the
|
||||
@ -102,6 +120,17 @@ public:
|
||||
m_installed_version = m_version;
|
||||
} // setInstalled
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if the icon of this addon was downloaded and is ready
|
||||
* to be displayed. */
|
||||
bool iconReady() const { return m_icon_ready; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Marks that the icon for this addon can be displayed. */
|
||||
void setIconReady()
|
||||
{
|
||||
m_icon_version = m_version;
|
||||
m_icon_ready=true;
|
||||
} // setIconReady
|
||||
// ------------------------------------------------------------------------
|
||||
}; // Addon
|
||||
|
||||
|
||||
|
@ -59,37 +59,59 @@ AddonsManager::AddonsManager() : m_state(STATE_INIT)
|
||||
* main GUI is not blocked). This function will update the state variable
|
||||
*
|
||||
*/
|
||||
void AddonsManager::initOnline()
|
||||
void AddonsManager::initOnline(const XMLNode *xml)
|
||||
{
|
||||
if(UserConfigParams::m_verbosity>=3)
|
||||
printf("[addons] Init online addons manager\n");
|
||||
int download_state = 0;
|
||||
m_download_state = download_state;
|
||||
|
||||
if(UserConfigParams::m_verbosity>=3)
|
||||
printf("[addons] Addons manager downloading list\n");
|
||||
if(!network_http->downloadFileSynchron("list"))
|
||||
{
|
||||
m_state.set(STATE_ERROR);
|
||||
return;
|
||||
}
|
||||
if(UserConfigParams::m_verbosity>=3)
|
||||
printf("[addons] Addons manager list downloaded\n");
|
||||
|
||||
std::string xml_file = file_manager->getAddonsFile("list");
|
||||
|
||||
const XMLNode *xml = new XMLNode(xml_file);
|
||||
for(unsigned int i=0; i<xml->getNumNodes(); i++)
|
||||
{
|
||||
const XMLNode *node = xml->getNode(i);
|
||||
const std::string &name = node->getName();
|
||||
// Ignore news/redirect, which is handled by network_http
|
||||
if(name=="news" || name=="redirect") continue;
|
||||
if(node->getName()=="track" || node->getName()=="kart")
|
||||
{
|
||||
Addon addon(*node);
|
||||
int index = getAddonIndex(addon.getId());
|
||||
|
||||
float stk_version=0;
|
||||
node->get("stkversion", &stk_version);
|
||||
int testing=-1;
|
||||
node->get("testing", &testing);
|
||||
|
||||
bool wrong_version=false;
|
||||
#ifdef WHILE_WEBPAGE_IS_NOT_UPDATED_YET
|
||||
if(addon.getType()=="kart")
|
||||
wrong_version = stk_version <stk_config->m_min_kart_version ||
|
||||
stk_version >stk_config->m_max_kart_version ;
|
||||
else
|
||||
wrong_version = stk_version <stk_config->m_min_track_version ||
|
||||
stk_version >stk_config->m_max_track_version ;
|
||||
#endif
|
||||
// Check which version to use: only for this stk version,
|
||||
// and not addons that are marked as hidden (testing=0)
|
||||
if(stk_version!=0.7f || testing==0)
|
||||
{
|
||||
// If the version is too old (e.g. after an update of stk)
|
||||
// remove a cached icon.
|
||||
std::string full_path =
|
||||
file_manager->getAddonsFile("icons/"
|
||||
+addon.getIconBasename());
|
||||
if(file_manager->fileExists(full_path))
|
||||
{
|
||||
if(UserConfigParams::m_verbosity>=3)
|
||||
printf("Removing cached icon '%s'.\n",
|
||||
addon.getIconBasename());
|
||||
file_manager->removeFile(full_path);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(index>=0)
|
||||
m_addons_list[index].copyInstallData(addon);
|
||||
else
|
||||
{
|
||||
m_addons_list.push_back(addon);
|
||||
index = m_addons_list.size()-1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -102,8 +124,82 @@ void AddonsManager::initOnline()
|
||||
delete xml;
|
||||
|
||||
m_state.set(STATE_READY);
|
||||
|
||||
pthread_mutex_init(&m_mutex_icon, NULL);
|
||||
|
||||
pthread_t id;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&id, &attr, downloadIcons, this);
|
||||
|
||||
} // initOnline
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** A separate thread to download all necessary icons (i.e. icons that are
|
||||
* either missing or have been updated since they were downloaded).
|
||||
*/
|
||||
void *AddonsManager::downloadIcons(void *obj)
|
||||
{
|
||||
AddonsManager *me=(AddonsManager*)obj;
|
||||
|
||||
me->m_icon_queue.clear();
|
||||
|
||||
for(unsigned int i=0; i<me->m_addons_list.size(); i++)
|
||||
{
|
||||
const Addon &addon = me->m_addons_list[i];
|
||||
const std::string &icon = addon.getIconBasename();
|
||||
if(addon.iconNeedsUpdate())
|
||||
{
|
||||
pthread_mutex_lock(&(me->m_mutex_icon));
|
||||
me->m_icon_queue.push_back(addon.getId());
|
||||
pthread_mutex_unlock(&(me->m_mutex_icon));
|
||||
continue;
|
||||
}
|
||||
std::string icon_path=file_manager->getAddonsFile("icons/"+icon);
|
||||
if(!file_manager->fileExists(icon_path))
|
||||
{
|
||||
pthread_mutex_lock(&(me->m_mutex_icon));
|
||||
me->m_icon_queue.push_back(addon.getId());
|
||||
pthread_mutex_unlock(&(me->m_mutex_icon));
|
||||
continue;
|
||||
}
|
||||
me->m_addons_list[i].setIconReady();
|
||||
} // for i<m_addons_list.size()
|
||||
|
||||
pthread_mutex_lock(&(me->m_mutex_icon));
|
||||
int count = me->m_icon_queue.size();
|
||||
pthread_mutex_unlock(&(me->m_mutex_icon));
|
||||
while(count!=0)
|
||||
{
|
||||
pthread_mutex_lock(&(me->m_mutex_icon));
|
||||
unsigned int indx = me->getAddonIndex(me->m_icon_queue[0]);
|
||||
Addon *addon = &(me->m_addons_list[indx]);
|
||||
me->m_icon_queue.erase(me->m_icon_queue.begin());
|
||||
count --;
|
||||
pthread_mutex_unlock(&(me->m_mutex_icon));
|
||||
|
||||
const std::string &url = addon->getIconURL();
|
||||
const std::string &icon = addon->getIconBasename();
|
||||
std::string save = "icons/"+icon;
|
||||
if(network_http->downloadFileSynchron(url, save))
|
||||
{
|
||||
addon->setIconReady();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[addons] Could not download icon '%s' from '%s'.\n",
|
||||
icon.c_str(), url.c_str());
|
||||
}
|
||||
} // while count!=0
|
||||
for(unsigned int i=0; i<me->m_addons_list.size(); i++)
|
||||
{
|
||||
if(!me->m_addons_list[i].iconReady())
|
||||
printf("No icon for '%s'.\n", me->m_addons_list[i].getId());
|
||||
}
|
||||
me->saveInstalled();
|
||||
return NULL;
|
||||
} // downloadIcons
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns true if the list of online addons has been downloaded. This is
|
||||
* used to grey out the 'addons' entry till a network connections could be
|
||||
@ -179,8 +275,6 @@ void AddonsManager::install(const Addon &addon)
|
||||
std::string to = file_manager->getAddonsDir() + "/"
|
||||
+ addon.getType()+ "s/" + id + "/" ;
|
||||
|
||||
m_str_state = "Unzip the addons...";
|
||||
|
||||
success = extract_zip(from, to);
|
||||
if (!success)
|
||||
{
|
||||
@ -194,7 +288,6 @@ void AddonsManager::install(const Addon &addon)
|
||||
assert(index>=0 && index < (int)m_addons_list.size());
|
||||
m_addons_list[index].setInstalled(true);
|
||||
|
||||
m_str_state = "Reloading kart list...";
|
||||
if(addon.getType()=="kart")
|
||||
{
|
||||
// We have to remove the mesh of the kart since otherwise it remains
|
||||
@ -211,11 +304,11 @@ void AddonsManager::install(const Addon &addon)
|
||||
irr_driver->removeMesh(model.getModel());
|
||||
}
|
||||
}
|
||||
saveInstalled();
|
||||
saveInstalled(addon.getType());
|
||||
} // install
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void AddonsManager::saveInstalled()
|
||||
void AddonsManager::saveInstalled(const std::string &type)
|
||||
{
|
||||
//Put the addons in the xml file
|
||||
//Manually because the irrlicht xml writer doesn't seem finished, FIXME ?
|
||||
@ -228,18 +321,23 @@ void AddonsManager::saveInstalled()
|
||||
|
||||
for(unsigned int i = 0; i < m_addons_list.size(); i++)
|
||||
{
|
||||
if(m_addons_list[i].m_installed)
|
||||
//if(m_addons_list[i].m_installed)
|
||||
{
|
||||
m_addons_list[i].writeXML(&xml_installed);
|
||||
}
|
||||
}
|
||||
xml_installed << "</addons>" << std::endl;
|
||||
xml_installed.close();
|
||||
kart_properties_manager->reLoadAllKarts();
|
||||
track_manager->loadTrackList();
|
||||
if(type=="kart")
|
||||
kart_properties_manager->reLoadAllKarts();
|
||||
else if(type=="track")
|
||||
track_manager->loadTrackList();
|
||||
} // saveInstalled
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Removes all files froma login.
|
||||
\param addon The addon to be removed.
|
||||
*/
|
||||
void AddonsManager::uninstall(const Addon &addon)
|
||||
{
|
||||
std::cout << "[Addons] Uninstalling <"
|
||||
@ -257,22 +355,9 @@ void AddonsManager::uninstall(const Addon &addon)
|
||||
|
||||
//remove the addons directory
|
||||
file_manager->removeDirectory(dest_file);
|
||||
saveInstalled();
|
||||
saveInstalled(addon.getType());
|
||||
|
||||
} // uninstall
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
int AddonsManager::getDownloadState()
|
||||
{
|
||||
int value = m_download_state;
|
||||
return value;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const std::string& AddonsManager::getDownloadStateAsStr() const
|
||||
{
|
||||
return m_str_state;
|
||||
} // getDownloadStateAsStr
|
||||
|
||||
#endif
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "addons/addon.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "utils/synchronised.hpp"
|
||||
@ -33,11 +35,20 @@ class AddonsManager
|
||||
private:
|
||||
std::vector<Addon> m_addons_list;
|
||||
std::string m_file_installed;
|
||||
void saveInstalled();
|
||||
void saveInstalled(const std::string &type="");
|
||||
void loadInstalledAddons();
|
||||
std::string m_type;
|
||||
int m_download_state;
|
||||
std::string m_str_state;
|
||||
|
||||
/** List of loaded icons. */
|
||||
std::vector<std::string> m_icon_list;
|
||||
|
||||
/** Queue of icons to download. This queue is used by the
|
||||
* GUI to increase priority of icons that are needed now. */
|
||||
std::vector<const std::string> m_icon_queue;
|
||||
|
||||
/** Mutex to protect access to icon_list. */
|
||||
pthread_mutex_t m_mutex_icon;
|
||||
|
||||
/** Which state the addons manager is:
|
||||
* INIT: Waiting to download the list of addons.
|
||||
@ -47,11 +58,14 @@ private:
|
||||
// Synchronise the state between threads (e.g. GUI and update thread)
|
||||
Synchronised<STATE_TYPE> m_state;
|
||||
|
||||
public:
|
||||
AddonsManager();
|
||||
static void *downloadIcons(void *obj);
|
||||
|
||||
void initOnline();
|
||||
public:
|
||||
AddonsManager();
|
||||
void initOnline(const XMLNode *xml);
|
||||
bool onlineReady();
|
||||
/** Marks addon as not being available. */
|
||||
void setErrorState() { m_state.set(STATE_ERROR); }
|
||||
|
||||
/** Returns the list of addons (installed and uninstalled). */
|
||||
unsigned int getNumAddons() const { return m_addons_list.size(); }
|
||||
@ -68,8 +82,6 @@ public:
|
||||
* directory of the addon.*/
|
||||
void uninstall(const Addon &addon);
|
||||
|
||||
int getDownloadState();
|
||||
|
||||
/** Get the install state (if it is the download, unzip...)*/
|
||||
const std::string& getDownloadStateAsStr() const;
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "io/file_manager.hpp"
|
||||
#include "states_screens/addons_screen.hpp"
|
||||
#include "states_screens/main_menu_screen.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
// Use Sleep, which takes time in msecs. It must be defined after the
|
||||
@ -75,12 +76,26 @@ void *NetworkHttp::mainLoop(void *obj)
|
||||
{
|
||||
NetworkHttp *me=(NetworkHttp*)obj;
|
||||
|
||||
// FIXME: this needs better error handling!
|
||||
me->checkNewServer();
|
||||
me->updateNews();
|
||||
|
||||
// Initialise the online portion of the addons manager.
|
||||
addons_manager->initOnline();
|
||||
if(UserConfigParams::m_verbosity>=3)
|
||||
printf("[addons] Downloading list.\n");
|
||||
if(me->downloadFileSynchron("list"))
|
||||
{
|
||||
std::string xml_file = file_manager->getAddonsFile("list");
|
||||
|
||||
const XMLNode *xml = new XMLNode(xml_file);
|
||||
me->checkNewServer(xml);
|
||||
me->updateNews(xml);
|
||||
addons_manager->initOnline(xml);
|
||||
if(UserConfigParams::m_verbosity>=3)
|
||||
printf("[addons] Addons manager list downloaded\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
addons_manager->setErrorState();
|
||||
if(UserConfigParams::m_verbosity>=3)
|
||||
printf("[addons] Can't download addons list.\n");
|
||||
}
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||
@ -100,7 +115,7 @@ void *NetworkHttp::mainLoop(void *obj)
|
||||
case HC_SLEEP:
|
||||
break;
|
||||
case HC_NEWS:
|
||||
me->updateNews();
|
||||
assert(false);
|
||||
break;
|
||||
case HC_DOWNLOAD_FILE:
|
||||
me->downloadFileInternal(me->m_file, me->m_save_filename,
|
||||
@ -135,38 +150,37 @@ NetworkHttp::~NetworkHttp()
|
||||
/** Checks if a redirect is received, causing a new server to be used for
|
||||
* downloading addons.
|
||||
*/
|
||||
void NetworkHttp::checkNewServer()
|
||||
void NetworkHttp::checkNewServer(const XMLNode *xml)
|
||||
{
|
||||
std::string newserver = downloadToStrInternal("redirect");
|
||||
if (newserver != "")
|
||||
std::string new_server;
|
||||
int result = xml->get("redirect", &new_server);
|
||||
if(result==1 && new_server!="")
|
||||
{
|
||||
newserver.replace(newserver.find("\n"), 1, "");
|
||||
|
||||
if(UserConfigParams::m_verbosity>=4)
|
||||
if(UserConfigParams::m_verbosity>=3)
|
||||
{
|
||||
std::cout << "[Addons] Current server: "
|
||||
<< (std::string)UserConfigParams::m_server_addons
|
||||
<< std::endl
|
||||
<< "[Addons] New server: " << newserver << std::endl;
|
||||
<< "[Addons] New server: " << new_server << std::endl;
|
||||
}
|
||||
UserConfigParams::m_server_addons = newserver;
|
||||
UserConfigParams::m_server_addons = new_server;
|
||||
user_config->saveConfig();
|
||||
}
|
||||
else if(UserConfigParams::m_verbosity>=4)
|
||||
{
|
||||
std::cout << "[Addons] No new server." << std::endl;
|
||||
}
|
||||
} // checkNewServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Updates the 'news' string to be displayed in the main menu.
|
||||
*/
|
||||
void NetworkHttp::updateNews()
|
||||
void NetworkHttp::updateNews(const XMLNode *xml)
|
||||
{
|
||||
// Only lock the actual assignment, not the downloading!
|
||||
const std::string tmp_str = downloadToStrInternal("news");
|
||||
m_news.set(tmp_str);
|
||||
|
||||
for(unsigned int i=0; i<xml->getNumNodes(); i++)
|
||||
{
|
||||
const XMLNode *node = xml->getNode(i);
|
||||
if(node->getName()!="news") continue;
|
||||
std::string news;
|
||||
node->get("text", &news);
|
||||
m_news.set(news);
|
||||
}
|
||||
} // updateNews
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -223,7 +237,7 @@ bool NetworkHttp::downloadFileInternal(const std::string &file,
|
||||
const std::string &save_filename,
|
||||
bool is_asynchron)
|
||||
{
|
||||
|
||||
printf("Downloading %s\n", file.c_str());
|
||||
CURL *session = curl_easy_init();
|
||||
std::string full_url = (std::string)UserConfigParams::m_server_addons
|
||||
+ "/" + file;
|
||||
@ -335,4 +349,5 @@ float NetworkHttp::getProgress() const
|
||||
{
|
||||
return m_progress.get();
|
||||
} // getProgress
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
#include "utils/synchronised.hpp"
|
||||
|
||||
class XMLNode;
|
||||
|
||||
class NetworkHttp
|
||||
{
|
||||
public:
|
||||
@ -66,15 +68,16 @@ private:
|
||||
pthread_t m_thread_id;
|
||||
|
||||
static void *mainLoop(void *obj);
|
||||
void checkNewServer();
|
||||
void checkNewServer(const XMLNode *xml);
|
||||
|
||||
void updateNews();
|
||||
void updateNews(const XMLNode *xml);
|
||||
std::string downloadToStrInternal(std::string url);
|
||||
bool downloadFileInternal(const std::string &file,
|
||||
const std::string &save_filename,
|
||||
bool is_asynchron);
|
||||
static int progressDownload(void *clientp, double dltotal, double dlnow,
|
||||
double ultotal, double ulnow);
|
||||
|
||||
public:
|
||||
NetworkHttp();
|
||||
~NetworkHttp();
|
||||
@ -88,7 +91,8 @@ public:
|
||||
const std::string
|
||||
getNewsMessage() const;
|
||||
float getProgress() const;
|
||||
};
|
||||
|
||||
}; // NetworkHttp
|
||||
|
||||
extern NetworkHttp *network_http;
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
using namespace irr;
|
||||
using namespace io;
|
||||
@ -56,7 +57,7 @@ bool extract_zip(const std::string &from, const std::string &to)
|
||||
{
|
||||
//Add the zip to the file system
|
||||
IFileSystem *file_system = irr_driver->getDevice()->getFileSystem();
|
||||
file_system->addZipFileArchive(from.c_str(), /*ignoreCase*/false);
|
||||
file_system->addZipFileArchive(from.c_str(), /*ignoreCase*/false, false);
|
||||
|
||||
// Get the recently added archive, which is necessary to get a
|
||||
// list of file in the zip archive.
|
||||
@ -68,26 +69,37 @@ bool extract_zip(const std::string &from, const std::string &to)
|
||||
{
|
||||
const std::string current_file=zip_file_list->getFileName(i).c_str();
|
||||
std::cout << current_file << std::endl;
|
||||
IReadFile* srcFile = file_system->createAndOpenFile(current_file.c_str());
|
||||
IWriteFile* dstFile =
|
||||
file_system->createAndWriteFile((to+"/"+current_file).c_str());
|
||||
if(dstFile == NULL)
|
||||
if(zip_file_list->isDirectory(i)) continue;
|
||||
if(current_file[0]=='.') continue;
|
||||
|
||||
IReadFile* src_file =
|
||||
file_system->createAndOpenFile(current_file.c_str());
|
||||
if(!src_file)
|
||||
{
|
||||
printf("Couldn't open the file '%s', and copy the archive files in it.\n",
|
||||
printf("Can't read file '%s'.\n", current_file.c_str());
|
||||
printf("This is ignored, but the addon might not work.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
IWriteFile* dst_file =
|
||||
file_system->createAndWriteFile((to+"/"+current_file).c_str());
|
||||
if(dst_file == NULL)
|
||||
{
|
||||
printf("Couldn't create the file '%s'.\n",
|
||||
(to+"/"+current_file).c_str());
|
||||
printf("The directory might not exist.\n");
|
||||
printf("This is ignored, but the addon might not work.\n");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
if (IFileSystem_copyFileToFile(dst_file, src_file) < 0)
|
||||
{
|
||||
if (IFileSystem_copyFileToFile(dstFile, srcFile) < 0)
|
||||
{
|
||||
printf("Could not copy '%s' from archive '%s'.\n",
|
||||
current_file.c_str(), from.c_str());
|
||||
printf("This is ignored, but the addon might not work.\n");
|
||||
}
|
||||
dstFile->drop();
|
||||
printf("Could not copy '%s' from archive '%s'.\n",
|
||||
current_file.c_str(), from.c_str());
|
||||
printf("This is ignored, but the addon might not work.\n");
|
||||
}
|
||||
srcFile->drop();
|
||||
dst_file->drop();
|
||||
src_file->drop();
|
||||
}
|
||||
// Remove the zip from the filesystem to save memory and avoid
|
||||
// problem with a name conflict. Note that we have to convert
|
||||
|
@ -686,13 +686,26 @@ void FileManager::checkAndCreateDirForAddons(std::string addons_name,
|
||||
checkAndCreateDirectory(path+"/"+addons_name);
|
||||
} // checkAndCreateDirForAddons
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Removes the specified file, returns true if successful, or false
|
||||
* if the file is not a regular file or can not be removed.
|
||||
*/
|
||||
bool FileManager::removeFile(const std::string &name) const
|
||||
{
|
||||
struct stat mystat;
|
||||
if(stat(name.c_str(), &mystat) < 0) return false;
|
||||
if( S_ISREG(mystat.st_mode))
|
||||
return remove(name.c_str())==0;
|
||||
return false;
|
||||
} // removeFile
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Removes a directory (including all files contained). The function could
|
||||
* easily recursively delete further subdirectories, but this is commented
|
||||
* out atm (to limit the amount of damage in case of a bug).
|
||||
* \param name Directory name to remove.
|
||||
*/
|
||||
bool FileManager::removeDirectory(const std::string &name)
|
||||
bool FileManager::removeDirectory(const std::string &name) const
|
||||
{
|
||||
std::set<std::string> files;
|
||||
listFiles(files, name, /*is full path*/ true);
|
||||
@ -711,10 +724,7 @@ bool FileManager::removeDirectory(const std::string &name)
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat mystat;
|
||||
if(stat(full_path.c_str(), &mystat) < 0) return false;
|
||||
if( S_ISREG(mystat.st_mode))
|
||||
remove(full_path.c_str());
|
||||
removeFile(full_path);
|
||||
}
|
||||
}
|
||||
#ifdef WIN32
|
||||
|
@ -87,7 +87,8 @@ public:
|
||||
std::string getAddonsFile(const std::string &name);
|
||||
void checkAndCreateDirForAddons(std::string addons_name,
|
||||
std::string addons_type);
|
||||
bool removeDirectory(const std::string &name);
|
||||
bool removeFile(const std::string &name) const;
|
||||
bool removeDirectory(const std::string &name) const;
|
||||
#endif
|
||||
std::string getDataDir () const;
|
||||
std::string getTranslationDir() const;
|
||||
|
@ -39,14 +39,13 @@ using namespace irr::gui;
|
||||
AddonsLoading::AddonsLoading(const float w, const float h,
|
||||
const std::string &id)
|
||||
: ModalDialog(w, h)
|
||||
, m_icon_loaded(ICON_NOT_LOADED)
|
||||
{
|
||||
loadFromFile("addons_view_dialog.stkgui");
|
||||
|
||||
m_addon = *(addons_manager->getAddon(id));
|
||||
m_progress = NULL;
|
||||
m_can_install = false;
|
||||
m_percent_update = false;
|
||||
m_icon_shown = false;
|
||||
|
||||
/*Init the icon here to be able to load a single image*/
|
||||
m_icon = getWidget<IconButtonWidget>("icon");
|
||||
@ -71,30 +70,8 @@ AddonsLoading::AddonsLoading(const float w, const float h,
|
||||
m_addon.getVersion());
|
||||
getWidget<LabelWidget>("version")->setText(version);
|
||||
|
||||
pthread_t thread_id;
|
||||
pthread_create(&thread_id, NULL, &AddonsLoading::downloadIcon, this);
|
||||
} // AddonsLoading
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void * AddonsLoading::downloadIcon( void * pthis)
|
||||
{
|
||||
AddonsLoading *me = (AddonsLoading*)pthis;
|
||||
std::string icon_name = StringUtils::getBasename(me->m_addon.getIcon());
|
||||
std::string icon_path = me->m_addon.getIcon();
|
||||
|
||||
// FIXME: addons_loading might be removed before this finishes!
|
||||
if(network_http->downloadFileSynchron(icon_path, "icons/"+icon_name))
|
||||
{
|
||||
me->m_icon_loaded.set(ICON_LOADED);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "[Addons] Download icon '%s' failed\n",
|
||||
icon_path.c_str());
|
||||
}
|
||||
return NULL;
|
||||
} // downloadIcon
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
GUIEngine::EventPropagation
|
||||
@ -138,11 +115,11 @@ GUIEngine::EventPropagation
|
||||
getWidget<ButtonWidget>("cancel")->setDeactivated();
|
||||
getWidget<ButtonWidget>("install")->setDeactivated();
|
||||
m_percent_update = true;
|
||||
startInstall();
|
||||
startDownload();
|
||||
}
|
||||
else // uninstall
|
||||
{
|
||||
endInstall();
|
||||
doInstall();
|
||||
}
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
@ -167,52 +144,37 @@ void AddonsLoading::onUpdate(float delta)
|
||||
else if(progress>=1.0f)
|
||||
{
|
||||
printf("Download finished.\n");
|
||||
endInstall();
|
||||
doInstall();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// See if the icon is loaded (but not yet displayed)
|
||||
if(m_icon_loaded.get()==ICON_LOADED)
|
||||
if(!m_icon_shown && m_addon.iconReady())
|
||||
{
|
||||
const std::string icon = "icons/"
|
||||
+ StringUtils::getBasename(m_addon.getIcon());
|
||||
const std::string icon = "icons/"+m_addon.getIconBasename();
|
||||
m_icon->setImage( file_manager->getAddonsFile(icon).c_str(),
|
||||
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE );
|
||||
m_icon_loaded.set(ICON_SHOWN);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
if(m_can_install)
|
||||
{
|
||||
close();
|
||||
m_icon_shown = true;
|
||||
}
|
||||
} // onUpdate
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void AddonsLoading::close()
|
||||
{
|
||||
AddonsScreen* curr_screen = AddonsScreen::getInstance();
|
||||
dismiss();
|
||||
} // close
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function is called when the user click on 'Install', 'Uninstall', or
|
||||
* 'Update'.
|
||||
**/
|
||||
void AddonsLoading::startInstall()
|
||||
void AddonsLoading::startDownload()
|
||||
{
|
||||
std::string file = m_addon.getZipFileName();
|
||||
std::string save = "tmp/"
|
||||
+ StringUtils::getBasename(m_addon.getZipFileName());
|
||||
network_http->downloadFileAsynchron(file, save);
|
||||
} // startInstall
|
||||
} // startDownload
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called when the asynchronous download of the addon finished.
|
||||
*/
|
||||
void AddonsLoading::endInstall()
|
||||
void AddonsLoading::doInstall()
|
||||
{
|
||||
if(!m_addon.isInstalled() || m_addon.needsUpdate())
|
||||
{
|
||||
@ -226,5 +188,5 @@ void AddonsLoading::endInstall()
|
||||
// display the newly (un)installed addon.
|
||||
AddonsScreen::getInstance()->loadList();
|
||||
dismiss();
|
||||
} // endInstall
|
||||
} // doInstall
|
||||
#endif
|
||||
|
@ -44,15 +44,8 @@ private:
|
||||
|
||||
/** The addon to load. */
|
||||
Addon m_addon;
|
||||
void startInstall();
|
||||
void endInstall();
|
||||
|
||||
/**
|
||||
* This function handle the downllading of the addons icon.
|
||||
* It is started using a thread. When it is ended, it change the flag
|
||||
* 'm_can_load_icon' and the onUpdate function reload the icon
|
||||
* */
|
||||
static void * downloadIcon(void*);
|
||||
void startDownload();
|
||||
void doInstall();
|
||||
|
||||
/* These three bool are some flags.
|
||||
* m_can_install : when the installation is finidhed, onUpdate close the
|
||||
@ -61,9 +54,8 @@ private:
|
||||
bool m_can_install;
|
||||
bool m_percent_update;
|
||||
|
||||
/** True if the icon was successfully downloaded. */
|
||||
enum IconState {ICON_NOT_LOADED, ICON_LOADED, ICON_SHOWN};
|
||||
Synchronised<IconState> m_icon_loaded;
|
||||
/** True if the icon is being displayed. */
|
||||
bool m_icon_shown;
|
||||
|
||||
public:
|
||||
/**
|
||||
@ -79,9 +71,7 @@ public:
|
||||
* */
|
||||
void onUpdate(float delta);
|
||||
|
||||
/** To close the dialog when the (un)installation is finished.*/
|
||||
void close();
|
||||
};
|
||||
}; // AddonsLoading
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -762,7 +762,9 @@ void RaceGUI::drawEnergyMeter(int x, int y, const Kart *kart,
|
||||
|
||||
const int EMPTY_TOP_PIXELS = 4;
|
||||
const int EMPTY_BOTTOM_PIXELS = 3;
|
||||
int y1 = y + EMPTY_TOP_PIXELS + (h - EMPTY_TOP_PIXELS - EMPTY_BOTTOM_PIXELS)*(1.0f - coin_target);
|
||||
int y1 = y + (int)(EMPTY_TOP_PIXELS +
|
||||
(h - EMPTY_TOP_PIXELS - EMPTY_BOTTOM_PIXELS)
|
||||
*(1.0f - coin_target) );
|
||||
if (state >= 1.0f) y1 = y;
|
||||
|
||||
core::rect<s32> clip(x, y1, x + w, y + h);
|
||||
@ -776,7 +778,9 @@ void RaceGUI::drawEnergyMeter(int x, int y, const Kart *kart,
|
||||
{
|
||||
const int EMPTY_TOP_PIXELS = 4;
|
||||
const int EMPTY_BOTTOM_PIXELS = 3;
|
||||
int y1 = y + EMPTY_TOP_PIXELS + (h - EMPTY_TOP_PIXELS - EMPTY_BOTTOM_PIXELS)*(1.0f - state);
|
||||
int y1 = y + (int)(EMPTY_TOP_PIXELS
|
||||
+ (h - EMPTY_TOP_PIXELS - EMPTY_BOTTOM_PIXELS)
|
||||
*(1.0f - state) );
|
||||
if (state >= 1.0f) y1 = y;
|
||||
|
||||
core::rect<s32> clip(x, y1, x + w, y + h);
|
||||
|
Loading…
x
Reference in New Issue
Block a user