diff --git a/.hgignore b/.hgignore index 58a32bafb..0870e3c67 100644 --- a/.hgignore +++ b/.hgignore @@ -1,4 +1,5 @@ map/* +world/* CMakeFiles/* src/CMakeFiles/* src/Makefile diff --git a/doc/changelog.txt b/doc/changelog.txt index f43a68f12..cb3594a98 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -13,6 +13,7 @@ X: - Slightly updated map format - Player passwords - All textures first searched from texture_path +- Map directory ("map") has been renamed to "world" (just rename it to load an old world) 2011-04-24: - Smooth lighting with simple ambient occlusion diff --git a/minetest.conf.example b/minetest.conf.example index acdc19b0a..5e6393228 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -102,6 +102,11 @@ #enable_damage = false +#default_password = + +# Available privileges: build, teleport, settime, privs, shout +#default_privs = build, shout + # Gives some stuff to players at the beginning #give_initial_stuff = false diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 49982d310..f912f68cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,7 @@ configure_file( ) set(common_SRCS + auth.cpp collision.cpp nodemetadata.cpp serverobject.cpp diff --git a/src/auth.cpp b/src/auth.cpp new file mode 100644 index 000000000..49985e697 --- /dev/null +++ b/src/auth.cpp @@ -0,0 +1,244 @@ +/* +Minetest-c55 +Copyright (C) 2011 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "auth.h" +#include +#include +//#include "main.h" // for g_settings +#include +#include "strfnd.h" +#include "debug.h" + +// Convert a privileges value into a human-readable string, +// with each component separated by a comma. +std::string privsToString(u64 privs) +{ + std::ostringstream os(std::ios_base::binary); + if(privs & PRIV_BUILD) + os<<"build,"; + if(privs & PRIV_TELEPORT) + os<<"teleport,"; + if(privs & PRIV_SETTIME) + os<<"settime,"; + if(privs & PRIV_PRIVS) + os<<"privs,"; + if(privs & PRIV_SHOUT) + os<<"shout,"; + if(os.tellp()) + { + // Drop the trailing comma. (Why on earth can't + // you truncate a C++ stream anyway???) + std::string tmp = os.str(); + return tmp.substr(0, tmp.length() -1); + } + return os.str(); +} + +// Converts a comma-seperated list of privilege values into a +// privileges value. The reverse of privsToString(). Returns +// PRIV_INVALID if there is anything wrong with the input. +u64 stringToPrivs(std::string str) +{ + u64 privs=0; + Strfnd f(str); + while(f.atend() == false) + { + std::string s = trim(f.next(",")); + if(s == "build") + privs |= PRIV_BUILD; + else if(s == "teleport") + privs |= PRIV_TELEPORT; + else if(s == "settime") + privs |= PRIV_SETTIME; + else if(s == "privs") + privs |= PRIV_PRIVS; + else if(s == "shout") + privs |= PRIV_SHOUT; + else + return PRIV_INVALID; + } + return privs; +} + +AuthManager::AuthManager(const std::string &authfilepath): + m_authfilepath(authfilepath) +{ + m_mutex.Init(); + + try{ + load(); + } + catch(SerializationError &e) + { + dstream<<"WARNING: AuthManager: creating " + <::Iterator + i = m_authdata.getIterator(); + i.atEnd()==false; i++) + { + std::string name = i.getNode()->getKey(); + if(name == "") + continue; + AuthData ad = i.getNode()->getValue(); + os<::Node *n; + n = m_authdata.find(username); + if(n == NULL) + return false; + return true; +} + +void AuthManager::set(const std::string &username, AuthData ad) +{ + JMutexAutoLock lock(m_mutex); + + m_authdata[username] = ad; +} + +void AuthManager::add(const std::string &username) +{ + JMutexAutoLock lock(m_mutex); + + m_authdata[username] = AuthData(); +} + +std::string AuthManager::getPassword(const std::string &username) +{ + JMutexAutoLock lock(m_mutex); + + core::map::Node *n; + n = m_authdata.find(username); + if(n == NULL) + throw AuthNotFoundException(""); + + return n->getValue().pwd; +} + +void AuthManager::setPassword(const std::string &username, + const std::string &password) +{ + JMutexAutoLock lock(m_mutex); + + core::map::Node *n; + n = m_authdata.find(username); + if(n == NULL) + throw AuthNotFoundException(""); + + AuthData ad = n->getValue(); + ad.pwd = password; + n->setValue(ad); +} + +u64 AuthManager::getPrivs(const std::string &username) +{ + JMutexAutoLock lock(m_mutex); + + core::map::Node *n; + n = m_authdata.find(username); + if(n == NULL) + throw AuthNotFoundException(""); + + return n->getValue().privs; +} + +void AuthManager::setPrivs(const std::string &username, u64 privs) +{ + JMutexAutoLock lock(m_mutex); + + core::map::Node *n; + n = m_authdata.find(username); + if(n == NULL) + throw AuthNotFoundException(""); + + AuthData ad = n->getValue(); + ad.privs = privs; + n->setValue(ad); +} + diff --git a/src/auth.h b/src/auth.h new file mode 100644 index 000000000..472409d46 --- /dev/null +++ b/src/auth.h @@ -0,0 +1,99 @@ +/* +Minetest-c55 +Copyright (C) 2011 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef AUTH_HEADER +#define AUTH_HEADER + +#include +#include +#include +#include "common_irrlicht.h" +#include "exceptions.h" + +// Player privileges. These form a bitmask stored in the privs field +// of the player, and define things they're allowed to do. See also +// the static methods Player::privsToString and stringToPrivs that +// convert these to human-readable form. +const u64 PRIV_BUILD = 1; // Can build - i.e. modify the world +const u64 PRIV_TELEPORT = 2; // Can teleport +const u64 PRIV_SETTIME = 4; // Can set the time +const u64 PRIV_PRIVS = 8; // Can grant and revoke privileges +const u64 PRIV_SERVER = 16; // Can manage the server (e.g. shutodwn + // ,settings) +const u64 PRIV_SHOUT = 32; // Can broadcast chat messages to all + // players + +// Default privileges - these can be overriden for new players using the +// config option "default_privs" - however, this value still applies for +// players that existed before the privileges system was added. +const u64 PRIV_DEFAULT = PRIV_BUILD|PRIV_SHOUT; +const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL; +const u64 PRIV_INVALID = 0x8000000000000000ULL; + +// Convert a privileges value into a human-readable string, +// with each component separated by a comma. +std::string privsToString(u64 privs); + +// Converts a comma-seperated list of privilege values into a +// privileges value. The reverse of privsToString(). Returns +// PRIV_INVALID if there is anything wrong with the input. +u64 stringToPrivs(std::string str); + +struct AuthData +{ + std::string pwd; + u64 privs; + + AuthData(): + privs(PRIV_DEFAULT) + { + } +}; + +class AuthNotFoundException : public BaseException +{ +public: + AuthNotFoundException(const char *s): + BaseException(s) + {} +}; + +class AuthManager +{ +public: + AuthManager(const std::string &authfilepath); + ~AuthManager(); + void load(); + void save(); + bool exists(const std::string &username); + void set(const std::string &username, AuthData ad); + void add(const std::string &username); + std::string getPassword(const std::string &username); + void setPassword(const std::string &username, + const std::string &password); + u64 getPrivs(const std::string &username); + void setPrivs(const std::string &username, u64 privs); +private: + JMutex m_mutex; + std::string m_authfilepath; + core::map m_authdata; +}; + +#endif + diff --git a/src/client.cpp b/src/client.cpp index 5869dc77b..79bbd8021 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -610,6 +610,13 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) // to be processed even if the serialisation format has // not been agreed yet, the same as TOCLIENT_INIT. m_access_denied = true; + m_access_denied_reason = L"Unknown"; + if(datasize >= 4) + { + std::string datastring((char*)&data[2], datasize-2); + std::istringstream is(datastring, std::ios_base::binary); + m_access_denied_reason = deSerializeWideString(is); + } return; } diff --git a/src/client.h b/src/client.h index f661838ce..1bfbe6296 100644 --- a/src/client.h +++ b/src/client.h @@ -385,6 +385,11 @@ public: return m_access_denied; } + inline std::wstring accessDeniedReason() + { + return m_access_denied_reason; + } + private: // Virtual methods from con::PeerHandler @@ -440,6 +445,7 @@ private: std::string m_password; bool m_access_denied; + std::wstring m_access_denied_reason; InventoryContext m_inventory_context; diff --git a/src/clientserver.h b/src/clientserver.h index 256aed362..7972762c0 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -24,6 +24,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PROTOCOL_ID 0x4f457403 +#define PASSWORD_SIZE 28 // Maximum password length. Allows for + // base64-encoded SHA-1 (27+\0). + enum ToClientCommand { TOCLIENT_INIT = 0x10, @@ -154,6 +157,8 @@ enum ToClientCommand TOCLIENT_ACCESS_DENIED = 0x35, /* u16 command + u16 reason_length + wstring reason */ }; diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index f11b0b2d7..1d758a2a4 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -69,8 +69,10 @@ void set_default_settings() // Server stuff g_settings.setDefault("enable_experimental", "false"); g_settings.setDefault("creative_mode", "false"); - g_settings.setDefault("enable_damage", "false"); //TODO: Set to true + g_settings.setDefault("enable_damage", "false"); //TODO: Set to true when healing is possible g_settings.setDefault("give_initial_stuff", "false"); + g_settings.setDefault("default_password", ""); + g_settings.setDefault("default_privs", "build, shout"); g_settings.setDefault("objectdata_interval", "0.2"); g_settings.setDefault("active_object_range", "2"); diff --git a/src/environment.cpp b/src/environment.cpp index 3ebfef0c5..c93d11ca8 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -426,7 +426,14 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir) testplayer.deSerialize(is); } - dstream<<"Loaded test player with name "< update(ServerEnvironment *env) = 0; + virtual u32 getTriggerContentCount(){ return 1;} + virtual u8 getTriggerContent(u32 i) = 0; + virtual float getActiveInterval() = 0; + // chance of (1 / return value), 0 is disallowed + virtual u32 getActiveChance() = 0; + // This is called usually at interval for 1/chance of the nodes + virtual void triggerEvent(ServerEnvironment *env, v3s16 p) = 0; +}; + #ifndef SERVER #include "clientobject.h" diff --git a/src/game.cpp b/src/game.cpp index 603a86da3..cc758be7e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -764,8 +764,9 @@ void the_game( { if(client.accessDenied()) { - error_message = L"Access denied. Check your password and try again."; - std::cout< rect(0, 0, 130, 30); //rect += topleft_server + v2s32(size_server.X-40-130, 100+25); rect += topleft_server + v2s32(40, 100+25); - Environment->addButton(rect, this, 260, L"Delete map"); + Environment->addButton(rect, this, 260, L"Delete world"); } } diff --git a/src/main.cpp b/src/main.cpp index f67d53475..11d50bfd1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -260,6 +260,9 @@ SUGG: MovingObject::move and Player::move are basically the same. - NOTE: There is a simple move implementation now in collision.{h,cpp} - NOTE: MovingObject will be deleted (MapBlockObject) +TODO: Add a long step function to objects that is called with the time + difference when block activates + Map: ---- @@ -304,14 +307,22 @@ Making it more portable: Stuff to do before release: --------------------------- -- Player default privileges and default password -- Chat privilege -- Some simple block-based dynamic stuff in the world (finish the - ActiveBlockModifier stuff) +- Make grass grow slower; utilize timestamp difference - Protocol version field - Consider getting some textures from cisoun's texture pack -- Add a long step function to objects that is called with the time - difference when block activates + - Ask from Cisoun +- Make sure the fence implementation and data format is good + - Think about using same bits for material for fences and doors, for + example +- Make sure server handles removing grass when a block is placed (etc) + - The client should not do it by itself +- Add mouse inversion in config +- Block cube placement around player's head +- Move mineral to param2, increment map serialization version, add conversion + +Stuff to do after release: +--------------------------- +- Finish the ActiveBlockModifier stuff and use it for something ====================================================================== @@ -1188,7 +1199,7 @@ int main(int argc, char *argv[]) port = 30000; // Map directory - std::string map_dir = porting::path_userdata+"/map"; + std::string map_dir = porting::path_userdata+"/world"; if(cmd_args.exists("map-dir")) map_dir = cmd_args.get("map-dir"); else if(g_settings.exists("map-dir")) @@ -1488,13 +1499,20 @@ int main(int argc, char *argv[]) g_settings.set("creative_mode", itos(menudata.creative_mode)); g_settings.set("enable_damage", itos(menudata.enable_damage)); - // Check for valid parameters, restart menu if invalid. + /*// Check for valid parameters, restart menu if invalid. if(playername == "") { error_message = L"Name required."; continue; } - + // Check that name has only valid chars + if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false) + { + error_message = L"Characters allowed: " + +narrow_to_wide(PLAYERNAME_ALLOWED_CHARS); + continue; + }*/ + // Save settings g_settings.set("name", playername); g_settings.set("address", address); diff --git a/src/player.cpp b/src/player.cpp index 147b6c97a..efb2f3447 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -23,58 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "constants.h" #include "utility.h" -// Convert a privileges value into a human-readable string, -// with each component separated by a comma. -std::wstring privsToString(u64 privs) -{ - std::wostringstream os(std::ios_base::binary); - if(privs & PRIV_BUILD) - os< pr; - pr=str_split(str, ','); - for(std::vector::iterator i = pr.begin(); - i != pr.end(); ++i) - { - if(*i == L"build") - privs |= PRIV_BUILD; - else if(*i == L"teleport") - privs |= PRIV_TELEPORT; - else if(*i == L"settime") - privs |= PRIV_SETTIME; - else if(*i == L"privs") - privs |= PRIV_PRIVS; - else if(*i == L"shout") - privs |= PRIV_SHOUT; - else - return PRIV_INVALID; - } - return privs; -} - Player::Player(): touching_ground(false), @@ -83,7 +31,6 @@ Player::Player(): swimming_up(false), craftresult_is_preview(true), hp(20), - privs(PRIV_DEFAULT), peer_id(PEER_ID_INEXISTENT), m_pitch(0), m_yaw(0), @@ -91,7 +38,6 @@ Player::Player(): m_position(0,0,0) { updateName(""); - updatePassword(""); resetInventory(); } @@ -150,7 +96,7 @@ void Player::serialize(std::ostream &os) Settings args; args.setS32("version", 1); args.set("name", m_name); - args.set("password", m_password); + //args.set("password", m_password); args.setFloat("pitch", m_pitch); args.setFloat("yaw", m_yaw); args.setV3F("position", m_position); @@ -185,10 +131,10 @@ void Player::deSerialize(std::istream &is) //args.getS32("version"); std::string name = args.get("name"); updateName(name.c_str()); - std::string password = ""; + /*std::string password = ""; if(args.exists("password")) password = args.get("password"); - updatePassword(password.c_str()); + updatePassword(password.c_str());*/ m_pitch = args.getFloat("pitch"); m_yaw = args.getFloat("yaw"); m_position = args.getV3F("position"); @@ -202,7 +148,7 @@ void Player::deSerialize(std::istream &is) }catch(SettingNotFoundException &e){ hp = 20; } - try{ + /*try{ std::string sprivs = args.get("privs"); if(sprivs == "all") { @@ -215,7 +161,7 @@ void Player::deSerialize(std::istream &is) } }catch(SettingNotFoundException &e){ privs = PRIV_DEFAULT; - } + }*/ inventory.deSerialize(is); } diff --git a/src/player.h b/src/player.h index 4b776a03f..157a25b5b 100644 --- a/src/player.h +++ b/src/player.h @@ -25,39 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "collision.h" #define PLAYERNAME_SIZE 20 -#define PASSWORD_SIZE 28 // Maximum password length. Allows for - // base64-encoded SHA-1. -#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.," - -// Player privileges. These form a bitmask stored in the privs field -// of the player, and define things they're allowed to do. See also -// the static methods Player::privsToString and stringToPrivs that -// convert these to human-readable form. -const u64 PRIV_BUILD = 1; // Can build - i.e. modify the world -const u64 PRIV_TELEPORT = 2; // Can teleport -const u64 PRIV_SETTIME = 4; // Can set the time -const u64 PRIV_PRIVS = 8; // Can grant and revoke privileges -const u64 PRIV_SERVER = 16; // Can manage the server (e.g. shutodwn - // ,settings) -const u64 PRIV_SHOUT = 32; // Can broadcast chat messages to all - // players - -// Default privileges - these can be overriden for new players using the -// config option "default_privs" - however, this value still applies for -// players that existed before the privileges system was added. -const u64 PRIV_DEFAULT = PRIV_BUILD|PRIV_SHOUT; -const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL; -const u64 PRIV_INVALID = 0x8000000000000000ULL; - -// Convert a privileges value into a human-readable string, -// with each component separated by a comma. -std::wstring privsToString(u64 privs); - -// Converts a comma-seperated list of privilege values into a -// privileges value. The reverse of privsToString(). Returns -// PRIV_INVALID if there is anything wrong with the input. -u64 stringToPrivs(std::wstring str); +#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" class Map; @@ -128,16 +97,6 @@ public: return m_name; } - virtual void updatePassword(const char *password) - { - snprintf(m_password, PASSWORD_SIZE, "%s", password); - } - - const char * getPassword() - { - return m_password; - } - virtual bool isLocal() const = 0; virtual void updateLight(u8 light_at_pos) {}; @@ -174,7 +133,6 @@ public: protected: char m_name[PLAYERNAME_SIZE]; - char m_password[PASSWORD_SIZE]; f32 m_pitch; f32 m_yaw; v3f m_speed; diff --git a/src/server.cpp b/src/server.cpp index 9248e6298..4569d028e 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -967,6 +967,7 @@ Server::Server( ): m_env(new ServerMap(mapsavedir), this), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), + m_authmanager(mapsavedir+"/auth.txt"), m_thread(this), m_emergethread(this), m_time_counter(0), @@ -1646,7 +1647,7 @@ void Server::AsyncRunStep() } } - // Save map + // Save map, players and auth stuff { float &counter = m_savemap_timer; counter += dtime; @@ -1654,8 +1655,11 @@ void Server::AsyncRunStep() { counter = 0.0; + // Auth stuff + m_authmanager.save(); + + // Map JMutexAutoLock lock(m_env_mutex); - if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true) { // Save only changed parts @@ -1795,7 +1799,23 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) playername[i] = data[3+i]; } playername[PLAYERNAME_SIZE-1] = 0; - + + if(playername[0]=='\0') + { + derr_server<getPassword(),password)) + + std::string checkpwd; + if(m_authmanager.exists(playername)) + { + checkpwd = m_authmanager.getPassword(playername); + } + else + { + checkpwd = g_settings.get("default_password"); + } + + if(password != checkpwd) { derr_server<getPassword(),password)) + password[PASSWORD_SIZE-1] = 0;*/ + std::string oldpwd; + for(u32 i=0; igetName(); + + if(m_authmanager.exists(playername) == false) + { + dstream<<"Server: playername not found in authmanager"<updatePassword(password); + + m_authmanager.setPassword(playername, newpwd); + + dstream<<"Server: password change successful for "<peer_id = PEER_ID_INEXISTENT; player->peer_id = peer_id; player->updateName(name); - player->updatePassword(password); + m_authmanager.add(name); + m_authmanager.setPassword(name, password); + m_authmanager.setPrivs(name, + stringToPrivs(g_settings.get("default_privs"))); if(g_settings.exists("default_privs")) player->privs = g_settings.getU64("default_privs"); diff --git a/src/server.h b/src/server.h index 54330856c..a6da801be 100644 --- a/src/server.h +++ b/src/server.h @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" #include "map.h" #include "inventory.h" +#include "auth.h" /* Some random functions @@ -438,7 +439,8 @@ private: */ static void SendHP(con::Connection &con, u16 peer_id, u8 hp); - static void SendAccessDenied(con::Connection &con, u16 peer_id); + static void SendAccessDenied(con::Connection &con, u16 peer_id, + const std::wstring &reason); /* Non-static send methods @@ -514,6 +516,9 @@ private: JMutex m_con_mutex; // Connected clients (behind the con mutex) core::map m_clients; + + // User authentication + AuthManager m_authmanager; /* Threads diff --git a/src/servercommand.cpp b/src/servercommand.cpp index 5bb4f67f8..e14f326f4 100644 --- a/src/servercommand.cpp +++ b/src/servercommand.cpp @@ -35,7 +35,7 @@ void cmd_privs(std::wostringstream &os, { // Show our own real privs, without any adjustments // made for admin status - os<player->privs); + os<player->privs)); return; } @@ -52,7 +52,7 @@ void cmd_privs(std::wostringstream &os, return; } - os<privs); + os<privs)); } void cmd_grantrevoke(std::wostringstream &os, @@ -70,7 +70,7 @@ void cmd_grantrevoke(std::wostringstream &os, return; } - u64 newprivs = stringToPrivs(ctx->parms[2]); + u64 newprivs = stringToPrivs(wide_to_narrow(ctx->parms[2])); if(newprivs == PRIV_INVALID) { os<privs &= ~newprivs; os<privs); + os<privs)); } void cmd_time(std::wostringstream &os, diff --git a/src/servermain.cpp b/src/servermain.cpp index 254b1f28a..f3b17000c 100644 --- a/src/servermain.cpp +++ b/src/servermain.cpp @@ -301,7 +301,7 @@ int main(int argc, char *argv[]) } // Figure out path to map - std::string map_dir = porting::path_userdata+"/map"; + std::string map_dir = porting::path_userdata+"/world"; if(cmd_args.exists("map-dir")) map_dir = cmd_args.get("map-dir"); else if(g_settings.exists("map-dir")) diff --git a/src/utility.h b/src/utility.h index c7513e94d..f18d31278 100644 --- a/src/utility.h +++ b/src/utility.h @@ -1984,17 +1984,23 @@ inline std::string serializeString(const std::string &plain) return s; } -/*// Reads a string with the length as the first two bytes -inline std::string deSerializeString(const std::string encoded) +// Creates a string with the length as the first two bytes from wide string +inline std::string serializeWideString(const std::wstring &plain) { - u16 s_size = readU16((u8*)&encoded.c_str()[0]); - if(s_size > encoded.length() - 2) - return ""; + //assert(plain.size() <= 65535); + if(plain.size() > 65535) + throw SerializationError("String too long for serializeString"); + char buf[2]; + writeU16((u8*)buf, plain.size()); std::string s; - s.reserve(s_size); - s.append(&encoded.c_str()[2], s_size); + s.append(buf, 2); + for(u32 i=0; i encoded.length() - 4) - return ""; - std::string s; - s.reserve(s_size); - s.append(&encoded.c_str()[4], s_size); - return s; -}*/ - // Reads a string with the length as the first four bytes inline std::string deSerializeLongString(std::istream &is) {