1) Added proper handling and detection of installed addons
2) Moved addon related data files into a separate 'addons' directory. 3) Directory names of addons are now lower case. (Still addons are not stable enough to be used!) git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7252 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
470832cd19
commit
3c729b4b0f
@ -20,8 +20,13 @@
|
|||||||
#ifdef ADDONS_MANAGER
|
#ifdef ADDONS_MANAGER
|
||||||
|
|
||||||
#include "addons/addon.hpp"
|
#include "addons/addon.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
//#include <iostream>
|
||||||
|
|
||||||
#include "io/file_manager.hpp"
|
#include "io/file_manager.hpp"
|
||||||
#include "io/xml_node.hpp"
|
#include "io/xml_node.hpp"
|
||||||
|
#include "utils/string_utils.hpp"
|
||||||
|
|
||||||
Addon::Addon(const XMLNode &xml, bool installed)
|
Addon::Addon(const XMLNode &xml, bool installed)
|
||||||
{
|
{
|
||||||
@ -29,17 +34,53 @@ Addon::Addon(const XMLNode &xml, bool installed)
|
|||||||
m_installed_version = 0;
|
m_installed_version = 0;
|
||||||
m_name = "";
|
m_name = "";
|
||||||
m_version = 0 ;
|
m_version = 0 ;
|
||||||
m_file = "";
|
m_zip_file = "";
|
||||||
m_description = "";
|
m_description = "";
|
||||||
m_icon = "";
|
m_icon = "";
|
||||||
m_id = "";
|
m_id = "";
|
||||||
m_type = xml.getName();
|
m_type = xml.getName();
|
||||||
|
|
||||||
xml.get("name", &m_name );
|
xml.get("name", &m_name);
|
||||||
xml.get("version", &m_version );
|
if(m_installed)
|
||||||
xml.get("file", &m_file );
|
{
|
||||||
xml.get("description", &m_description);
|
xml.get("installed-version", &m_installed_version);
|
||||||
xml.get("icon", &m_icon );
|
xml.get("id", &m_id );
|
||||||
xml.get("id", &m_id );
|
}
|
||||||
|
else // not installed
|
||||||
|
{
|
||||||
|
xml.get("file", &m_zip_file );
|
||||||
|
xml.get("description", &m_description);
|
||||||
|
xml.get("icon", &m_icon );
|
||||||
|
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);
|
||||||
|
} // if installed
|
||||||
}; // Addon(const XML&)
|
}; // Addon(const XML&)
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
/** Copies the installation data (like description, version, icon) from the
|
||||||
|
* downloaded online list to this entry.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
} // copyInstallData
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
/** Writes information about an installed addon (it is only called for
|
||||||
|
* installed addons).
|
||||||
|
* \param out_stream Output stream to write to.
|
||||||
|
*/
|
||||||
|
void Addon::writeXML(std::ofstream *out_stream)
|
||||||
|
{
|
||||||
|
(*out_stream) << " <" << m_type << " name=\"" << m_name
|
||||||
|
<< "\" id=\"" << m_id << "\" installed-version=\""
|
||||||
|
<< m_installed_version << "\"/>\n";
|
||||||
|
} // writeXML
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -29,27 +29,42 @@ class XMLNode;
|
|||||||
class Addon
|
class Addon
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/** The name to be displayed. */
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
int m_version;
|
/** Internal id for this addon, which is the name in lower case.
|
||||||
int m_installed_version;
|
* This is used to create a subdirectory for this addon. */
|
||||||
std::string m_description;
|
|
||||||
std::string m_icon;
|
|
||||||
std::string m_file;
|
|
||||||
std::string m_id;
|
std::string m_id;
|
||||||
|
/** The (highest) version available online. */
|
||||||
|
int m_version;
|
||||||
|
/** The currently installed version. */
|
||||||
|
int m_installed_version;
|
||||||
|
/** A description of this addon. */
|
||||||
|
std::string m_description;
|
||||||
|
/** Name of the icon to use. */
|
||||||
|
std::string m_icon;
|
||||||
|
/** The name of the zip file on the addon server. */
|
||||||
|
std::string m_zip_file;
|
||||||
|
/** True if the addon is installed. */
|
||||||
bool m_installed;
|
bool m_installed;
|
||||||
|
/** Type, must be 'kart' or 'track'. */
|
||||||
std::string m_type;
|
std::string m_type;
|
||||||
|
|
||||||
Addon() {};
|
Addon() {};
|
||||||
/** Initialises the object from an XML node. */
|
/** Initialises the object from an XML node. */
|
||||||
Addon(const XMLNode &xml, bool installed=false);
|
Addon(const XMLNode &xml, bool installed=false);
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
void writeXML(std::ofstream *out_stram);
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
void copyInstallData(const Addon &addon);
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
/** Returns the name of the 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. */
|
/** 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 addon. */
|
/** Returns the filename of the zip file with the addon. */
|
||||||
const std::string& getFile() const {return m_file; }
|
const std::string& getZipFileName() const {return m_zip_file; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns the name of the icon of this addon. */
|
/** Returns the name of the icon of this addon. */
|
||||||
const std::string& getIcon() const {return m_icon; }
|
const std::string& getIcon() const {return m_icon; }
|
||||||
|
@ -46,8 +46,7 @@ AddonsManager* addons_manager = 0;
|
|||||||
*/
|
*/
|
||||||
AddonsManager::AddonsManager() : m_state(STATE_INIT)
|
AddonsManager::AddonsManager() : m_state(STATE_INIT)
|
||||||
{
|
{
|
||||||
m_file_installed = file_manager->getConfigDir()
|
m_file_installed = file_manager->getAddonsFile("addons_installed.xml");
|
||||||
+ "/" + "addons_installed.xml";
|
|
||||||
loadInstalledAddons();
|
loadInstalledAddons();
|
||||||
} // AddonsManager
|
} // AddonsManager
|
||||||
|
|
||||||
@ -84,15 +83,14 @@ void AddonsManager::initOnline()
|
|||||||
for(unsigned int i=0; i<xml->getNumNodes(); i++)
|
for(unsigned int i=0; i<xml->getNumNodes(); i++)
|
||||||
{
|
{
|
||||||
const XMLNode *node = xml->getNode(i);
|
const XMLNode *node = xml->getNode(i);
|
||||||
if(node->getName()=="track")
|
if(node->getName()=="track" || node->getName()=="kart")
|
||||||
{
|
{
|
||||||
Addon addon(*node);
|
Addon addon(*node);
|
||||||
m_addons_list.push_back(addon);
|
int index = getAddonIndex(addon.getId());
|
||||||
}
|
if(index>=0)
|
||||||
else if(node->getName()=="kart")
|
m_addons_list[index].copyInstallData(addon);
|
||||||
{
|
else
|
||||||
Addon addon(*node);
|
m_addons_list.push_back(addon);
|
||||||
m_addons_list.push_back(addon);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -118,6 +116,10 @@ bool AddonsManager::onlineReady()
|
|||||||
} // onlineReady
|
} // onlineReady
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
/** Loads the installed addons from .../addons/addons_installed.xml. This is
|
||||||
|
* called before network_http is constructed (so no need to protect
|
||||||
|
* m_addons_list with a mutex).
|
||||||
|
*/
|
||||||
void AddonsManager::loadInstalledAddons()
|
void AddonsManager::loadInstalledAddons()
|
||||||
{
|
{
|
||||||
/* checking for installed addons */
|
/* checking for installed addons */
|
||||||
@ -133,25 +135,8 @@ void AddonsManager::loadInstalledAddons()
|
|||||||
if(node->getName()=="kart" ||
|
if(node->getName()=="kart" ||
|
||||||
node->getName()=="track" )
|
node->getName()=="track" )
|
||||||
{
|
{
|
||||||
std::string name="";
|
Addon addon(*node, /*installed*/ true);
|
||||||
std::string id="";
|
m_addons_list.push_back(addon);
|
||||||
int version = 0;
|
|
||||||
node->get("id", &id );
|
|
||||||
node->get("name", &name );
|
|
||||||
node->get("version", &version);
|
|
||||||
int index = getAddonIndex(id);
|
|
||||||
if(index>0)
|
|
||||||
{
|
|
||||||
m_addons_list[index].m_installed = true;
|
|
||||||
m_addons_list[index].m_installed_version = version;
|
|
||||||
std::cout << "[Addons] An addon is already installed: "
|
|
||||||
<< id << std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Addon addon(*xml, /* installed= */ true);
|
|
||||||
m_addons_list.push_back(addon);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // for i <= xml->getNumNodes()
|
} // for i <= xml->getNumNodes()
|
||||||
|
|
||||||
@ -186,14 +171,13 @@ int AddonsManager::getAddonIndex(const std::string &id) const
|
|||||||
void AddonsManager::install(const Addon &addon)
|
void AddonsManager::install(const Addon &addon)
|
||||||
{
|
{
|
||||||
bool success=true;
|
bool success=true;
|
||||||
|
std::string id = StringUtils::toLowerCase(addon.getName());
|
||||||
file_manager->checkAndCreateDirForAddons(addon.getName(),
|
file_manager->checkAndCreateDirForAddons(id, addon.getType()+ "s/");
|
||||||
addon.getType()+ "s/");
|
|
||||||
|
|
||||||
//extract the zip in the addons folder called like the addons name
|
//extract the zip in the addons folder called like the addons name
|
||||||
std::string dest_file = file_manager->getAddonsDir() + "/"
|
std::string dest_file = file_manager->getAddonsDir() + "/"
|
||||||
+ addon.getType()+ "s/" + addon.getName() + "/" ;
|
+ addon.getType()+ "s/" + addon.getName() + "/" ;
|
||||||
std::string base_name = StringUtils::getBasename(addon.getFile());
|
std::string base_name = StringUtils::getBasename(addon.getZipFileName());
|
||||||
std::string from = file_manager->getAddonsFile(base_name);
|
std::string from = file_manager->getAddonsFile(base_name);
|
||||||
std::string to = dest_file;
|
std::string to = dest_file;
|
||||||
|
|
||||||
@ -232,14 +216,7 @@ void AddonsManager::saveInstalled()
|
|||||||
{
|
{
|
||||||
if(m_addons_list[i].m_installed)
|
if(m_addons_list[i].m_installed)
|
||||||
{
|
{
|
||||||
std::ostringstream os;
|
m_addons_list[i].writeXML(&xml_installed);
|
||||||
os << m_addons_list[i].m_installed_version;
|
|
||||||
|
|
||||||
//transform the version (int) in string
|
|
||||||
xml_installed << "<"+ m_addons_list[i].m_type +" name=\"" +
|
|
||||||
m_addons_list[i].m_name + "\" id=\"" +
|
|
||||||
m_addons_list[i].m_id + "\"";
|
|
||||||
xml_installed << " version=\"" + os.str() + "\" />" << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xml_installed << "</addons>" << std::endl;
|
xml_installed << "</addons>" << std::endl;
|
||||||
|
@ -490,7 +490,7 @@ void FileManager::checkAndCreateConfigDir()
|
|||||||
void FileManager::checkAndCreateAddonsDir()
|
void FileManager::checkAndCreateAddonsDir()
|
||||||
{
|
{
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
m_addons_dir = m_config_dir;
|
m_addons_dir = m_config_dir+"/addons";
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
m_addons_dir = getenv("HOME");
|
m_addons_dir = getenv("HOME");
|
||||||
m_addons_dir += "/Library/Application Support/SuperTuxKart";
|
m_addons_dir += "/Library/Application Support/SuperTuxKart";
|
||||||
|
@ -75,7 +75,8 @@ void AddonsScreen::init()
|
|||||||
|
|
||||||
getWidget<GUIEngine::LabelWidget>("update_status")
|
getWidget<GUIEngine::LabelWidget>("update_status")
|
||||||
->setText(_("Updating the list..."));
|
->setText(_("Updating the list..."));
|
||||||
loadList("kart");
|
m_type = "kart";
|
||||||
|
loadList();
|
||||||
} // init
|
} // init
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -83,7 +84,7 @@ void AddonsScreen::init()
|
|||||||
* updated.
|
* updated.
|
||||||
* \param type Must be 'kart' or 'track'.
|
* \param type Must be 'kart' or 'track'.
|
||||||
*/
|
*/
|
||||||
void AddonsScreen::loadList(const std::string &type)
|
void AddonsScreen::loadList()
|
||||||
{
|
{
|
||||||
GUIEngine::ListWidget* w_list =
|
GUIEngine::ListWidget* w_list =
|
||||||
getWidget<GUIEngine::ListWidget>("list_addons");
|
getWidget<GUIEngine::ListWidget>("list_addons");
|
||||||
@ -92,11 +93,11 @@ void AddonsScreen::loadList(const std::string &type)
|
|||||||
{
|
{
|
||||||
const Addon &addon = addons_manager->getAddon(i);
|
const Addon &addon = addons_manager->getAddon(i);
|
||||||
// Ignore addons of a different type
|
// Ignore addons of a different type
|
||||||
if(addon.getType()!=type) continue;
|
if(addon.getType()!=m_type) continue;
|
||||||
|
|
||||||
// Get the right icon to display
|
// Get the right icon to display
|
||||||
int icon;
|
int icon;
|
||||||
if(addon.isInstalled() && addon.needsUpdate())
|
if(addon.isInstalled())
|
||||||
icon = addon.needsUpdate() ? m_icon_needs_update
|
icon = addon.needsUpdate() ? m_icon_needs_update
|
||||||
: m_icon_installed;
|
: m_icon_installed;
|
||||||
else
|
else
|
||||||
@ -109,10 +110,10 @@ void AddonsScreen::loadList(const std::string &type)
|
|||||||
m_can_load_list = false;
|
m_can_load_list = false;
|
||||||
getWidget<GUIEngine::RibbonWidget>("category")->setActivated();
|
getWidget<GUIEngine::RibbonWidget>("category")->setActivated();
|
||||||
getWidget<GUIEngine::LabelWidget>("update_status")->setText("");
|
getWidget<GUIEngine::LabelWidget>("update_status")->setText("");
|
||||||
if(type == "kart")
|
if(m_type == "kart")
|
||||||
getWidget<GUIEngine::RibbonWidget>("category")->select("tab_kart",
|
getWidget<GUIEngine::RibbonWidget>("category")->select("tab_kart",
|
||||||
PLAYER_ID_GAME_MASTER);
|
PLAYER_ID_GAME_MASTER);
|
||||||
else if(type == "track")
|
else if(m_type == "track")
|
||||||
getWidget<GUIEngine::RibbonWidget>("category")->select("tab_track",
|
getWidget<GUIEngine::RibbonWidget>("category")->select("tab_track",
|
||||||
PLAYER_ID_GAME_MASTER);
|
PLAYER_ID_GAME_MASTER);
|
||||||
else
|
else
|
||||||
@ -146,11 +147,13 @@ void AddonsScreen::eventCallback(GUIEngine::Widget* widget,
|
|||||||
StateManager::get()->replaceTopMostScreen(AddonsUpdateScreen::getInstance());
|
StateManager::get()->replaceTopMostScreen(AddonsUpdateScreen::getInstance());
|
||||||
else if (selection == "tab_track")
|
else if (selection == "tab_track")
|
||||||
{
|
{
|
||||||
loadList("track");
|
m_type = "track";
|
||||||
|
loadList();
|
||||||
}
|
}
|
||||||
else if (selection == "tab_kart")
|
else if (selection == "tab_kart")
|
||||||
{
|
{
|
||||||
loadList("kart");
|
m_type = "kart";
|
||||||
|
loadList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // eventCallback
|
} // eventCallback
|
||||||
|
@ -40,7 +40,7 @@ class AddonsScreen : public GUIEngine::Screen,
|
|||||||
public GUIEngine::ScreenSingleton<AddonsScreen>
|
public GUIEngine::ScreenSingleton<AddonsScreen>
|
||||||
{
|
{
|
||||||
friend class GUIEngine::ScreenSingleton<AddonsScreen>;
|
friend class GUIEngine::ScreenSingleton<AddonsScreen>;
|
||||||
|
private:
|
||||||
AddonsScreen();
|
AddonsScreen();
|
||||||
AddonsManager *m_addons;
|
AddonsManager *m_addons;
|
||||||
AddonsLoading *m_load;
|
AddonsLoading *m_load;
|
||||||
@ -55,13 +55,15 @@ class AddonsScreen : public GUIEngine::Screen,
|
|||||||
*m_icon_bank;
|
*m_icon_bank;
|
||||||
GUIEngine::LabelWidget
|
GUIEngine::LabelWidget
|
||||||
*m_update_status;
|
*m_update_status;
|
||||||
|
/** Currently selected type. */
|
||||||
|
std::string m_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool m_can_load_list;
|
bool m_can_load_list;
|
||||||
|
|
||||||
/** Load the addons into the main list.*/
|
/** Load the addons into the main list.*/
|
||||||
void loadList(const std::string &type);
|
void loadList();
|
||||||
|
|
||||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||||
virtual void loadedFromFile();
|
virtual void loadedFromFile();
|
||||||
|
@ -71,15 +71,15 @@ void AddonsUpdateScreen::eventCallback(GUIEngine::Widget* widget,
|
|||||||
if (selection == "tab_track")
|
if (selection == "tab_track")
|
||||||
{
|
{
|
||||||
StateManager::get()->replaceTopMostScreen(AddonsScreen::getInstance());
|
StateManager::get()->replaceTopMostScreen(AddonsScreen::getInstance());
|
||||||
AddonsScreen::getInstance()->loadList("track");
|
AddonsScreen::getInstance()->loadList();
|
||||||
}
|
}
|
||||||
else if (selection == "tab_kart")
|
else if (selection == "tab_kart")
|
||||||
{
|
{
|
||||||
StateManager::get()->replaceTopMostScreen(AddonsScreen::getInstance());
|
StateManager::get()->replaceTopMostScreen(AddonsScreen::getInstance());
|
||||||
AddonsScreen::getInstance()->loadList("kart");
|
AddonsScreen::getInstance()->loadList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // eventCallback
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ void AddonsLoading::onUpdate(float delta)
|
|||||||
{
|
{
|
||||||
// TODO: show a message in the interface
|
// TODO: show a message in the interface
|
||||||
fprintf(stderr, "[Addons] Failed to download '%s'\n",
|
fprintf(stderr, "[Addons] Failed to download '%s'\n",
|
||||||
m_addon.getFile().c_str());
|
m_addon.getZipFileName().c_str());
|
||||||
dismiss();
|
dismiss();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -218,12 +218,14 @@ void AddonsLoading::close()
|
|||||||
**/
|
**/
|
||||||
void AddonsLoading::startInstall()
|
void AddonsLoading::startInstall()
|
||||||
{
|
{
|
||||||
std::string file = "file/" + m_addon.getFile();
|
std::string file = "file/" + m_addon.getZipFileName();
|
||||||
std::string save = StringUtils::getBasename(m_addon.getFile());
|
std::string save = StringUtils::getBasename(m_addon.getZipFileName());
|
||||||
network_http->downloadFileAsynchron(file, save);
|
network_http->downloadFileAsynchron(file, save);
|
||||||
} // startInstall
|
} // startInstall
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
/** Called when the asynchronous download of the addon finished.
|
||||||
|
*/
|
||||||
void AddonsLoading::endInstall()
|
void AddonsLoading::endInstall()
|
||||||
{
|
{
|
||||||
if(!m_addon.isInstalled() || m_addon.needsUpdate())
|
if(!m_addon.isInstalled() || m_addon.needsUpdate())
|
||||||
@ -234,5 +236,8 @@ void AddonsLoading::endInstall()
|
|||||||
{
|
{
|
||||||
addons_manager->uninstall(m_addon);
|
addons_manager->uninstall(m_addon);
|
||||||
}
|
}
|
||||||
|
// The list of the addon screen needs to be updated to correctly
|
||||||
|
// display the newly (un)installed addon.
|
||||||
|
AddonsScreen::getInstance()->loadList();
|
||||||
} // endInstall
|
} // endInstall
|
||||||
#endif
|
#endif
|
||||||
|
@ -112,6 +112,16 @@ namespace StringUtils
|
|||||||
return name;
|
return name;
|
||||||
} // toUpperCase
|
} // toUpperCase
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
/** Returns a string converted to lower case.
|
||||||
|
*/
|
||||||
|
std::string toLowerCase(const std::string& str)
|
||||||
|
{
|
||||||
|
std::string name = str;
|
||||||
|
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||||
|
return name;
|
||||||
|
} // toLowerCase
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
/** Splits a string into substrings separated by a certain character, and
|
/** Splits a string into substrings separated by a certain character, and
|
||||||
* returns a std::vector of all those substring. E.g.:
|
* returns a std::vector of all those substring. E.g.:
|
||||||
|
@ -76,6 +76,7 @@ namespace StringUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string toUpperCase(const std::string&);
|
std::string toUpperCase(const std::string&);
|
||||||
|
std::string toLowerCase(const std::string&);
|
||||||
std::vector<std::string> split(const std::string& s, char c,
|
std::vector<std::string> split(const std::string& s, char c,
|
||||||
bool keepSplitChar=false);
|
bool keepSplitChar=false);
|
||||||
std::vector<irr::core::stringw> split(const irr::core::stringw& s,
|
std::vector<irr::core::stringw> split(const irr::core::stringw& s,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user