Ctrl+C handling on POSIX, some commands for server and other tweaking

This commit is contained in:
Perttu Ahola 2011-02-15 16:11:24 +02:00
parent be7391c2b1
commit d065bae323
13 changed files with 384 additions and 111 deletions

@ -1,5 +1,7 @@
Minetest-c55 changelog Minetest-c55 changelog
---------------------- ----------------------
This should contain all the major changes.
For minor stuff, refer to the commit log of the repository.
2011-02-14: 2011-02-14:
- Created changelog.txt - Created changelog.txt

@ -31,6 +31,8 @@
#map-dir = /home/palle/custom_map #map-dir = /home/palle/custom_map
#operator_name =
#plants_amount = 1.0 #plants_amount = 1.0
#ravines_amount = 1.0 #ravines_amount = 1.0
#coal_amount = 1.0 #coal_amount = 1.0

@ -5,6 +5,8 @@ if(RUN_IN_PLACE)
add_definitions ( -DRUN_IN_PLACE ) add_definitions ( -DRUN_IN_PLACE )
endif(RUN_IN_PLACE) endif(RUN_IN_PLACE)
set(USE_GPROF 0 CACHE BOOL "Use -pg flag for g++")
# Use cmake_config.h # Use cmake_config.h
add_definitions ( -DUSE_CMAKE_CONFIG_H ) add_definitions ( -DUSE_CMAKE_CONFIG_H )
@ -162,6 +164,10 @@ else()
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${WARNING_FLAGS} -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops") set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${WARNING_FLAGS} -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O1 -Wall") set(CMAKE_CXX_FLAGS_DEBUG "-g -O1 -Wall")
if(USE_GPROF)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg")
endif()
if(BUILD_SERVER) if(BUILD_SERVER)
set_target_properties(minetestserver PROPERTIES set_target_properties(minetestserver PROPERTIES
COMPILE_FLAGS "-DSERVER") COMPILE_FLAGS "-DSERVER")

@ -174,11 +174,19 @@ bool GUIPauseMenu::OnEvent(const SEvent& event)
{ {
if(event.EventType==EET_KEY_INPUT_EVENT) if(event.EventType==EET_KEY_INPUT_EVENT)
{ {
if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown) if(event.KeyInput.PressedDown)
{
if(event.KeyInput.Key==KEY_ESCAPE)
{ {
quitMenu(); quitMenu();
return true; return true;
} }
else if(event.KeyInput.Key==KEY_RETURN)
{
quitMenu();
return true;
}
}
} }
if(event.EventType==EET_GUI_EVENT) if(event.EventType==EET_GUI_EVENT)
{ {

@ -268,7 +268,7 @@ Doing now (most important at the top):
# maybe done # maybe done
* not done * not done
=== Stuff to do before release === Fixmes
* Make server find the spawning place from the real map data, not from * Make server find the spawning place from the real map data, not from
the heightmap the heightmap
- But the changing borders of chunk have to be avoided, because - But the changing borders of chunk have to be avoided, because
@ -277,15 +277,15 @@ Doing now (most important at the top):
placement and transfer placement and transfer
* only_from_disk might not work anymore - check and fix it. * only_from_disk might not work anymore - check and fix it.
* Check the fixmes in the list above * Check the fixmes in the list above
* FIXME: Sneaking doesn't switch sneak node when moving sideways * When sending blocks to the client, the server takes way too much
CPU time (20-30% for single player), find out what it is doing.
- Make a simple profiler
=== Making it more portable === Making it more portable
* Some MSVC: std::sto* are defined without a namespace and collide * Some MSVC: std::sto* are defined without a namespace and collide
with the ones in utility.h with the ones in utility.h
* On Kray's machine, the new find_library(XXF86VM_LIBRARY, Xxf86vm)
line doesn't find the library.
=== Stuff to do after release === Features
* Make an "environment metafile" to store at least time of day * Make an "environment metafile" to store at least time of day
* Move digging property stuff from material.{h,cpp} to mapnode.cpp... * Move digging property stuff from material.{h,cpp} to mapnode.cpp...
- Or maybe move content_features to material.{h,cpp}? - Or maybe move content_features to material.{h,cpp}?
@ -567,7 +567,25 @@ struct TextDestChat : public TextDest
} }
void gotText(std::wstring text) void gotText(std::wstring text)
{ {
// Discard empty line
if(text == L"")
return;
// Parse command (server command starts with "/#")
if(text[0] == L'/' && text[1] != L'#')
{
std::wstring reply = L"Local: ";
reply += L"Local commands not yet supported. "
"Server prefix is \"/#\".";
m_client->addChatMessage(reply);
return;
}
// Send to others
m_client->sendChatMessage(text); m_client->sendChatMessage(text);
// Show locally
m_client->addChatMessage(text); m_client->addChatMessage(text);
} }
@ -1546,6 +1564,9 @@ int main(int argc, char *argv[])
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
porting::signal_handler_init();
bool &kill = *porting::signal_handler_killstatus();
porting::initializePaths(); porting::initializePaths();
// Create user data directory // Create user data directory
fs::CreateDir(porting::path_userdata); fs::CreateDir(porting::path_userdata);
@ -1681,7 +1702,7 @@ int main(int argc, char *argv[])
server.start(port); server.start(port);
// Run server // Run server
dedicated_server_loop(server); dedicated_server_loop(server, kill);
return 0; return 0;
} }

@ -1771,11 +1771,11 @@ void MapBlock::serialize(std::ostream &os, u8 version)
// First byte // First byte
u8 flags = 0; u8 flags = 0;
if(is_underground) if(is_underground)
flags |= 1; flags |= 0x01;
if(m_day_night_differs) if(m_day_night_differs)
flags |= 2; flags |= 0x02;
if(m_lighting_expired) if(m_lighting_expired)
flags |= 3; flags |= 0x04;
os.write((char*)&flags, 1); os.write((char*)&flags, 1);
u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
@ -1895,9 +1895,9 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
u8 flags; u8 flags;
is.read((char*)&flags, 1); is.read((char*)&flags, 1);
is_underground = (flags & 1) ? true : false; is_underground = (flags & 0x01) ? true : false;
m_day_night_differs = (flags & 2) ? true : false; m_day_night_differs = (flags & 0x02) ? true : false;
m_lighting_expired = (flags & 3) ? true : false; m_lighting_expired = (flags & 0x04) ? true : false;
// Uncompress data // Uncompress data
std::ostringstream os(std::ios_base::binary); std::ostringstream os(std::ios_base::binary);

@ -29,6 +29,53 @@ with this program; if not, write to the Free Software Foundation, Inc.,
namespace porting namespace porting
{ {
/*
Signal handler (grabs Ctrl-C on POSIX systems)
*/
#if !defined(_WIN32) // POSIX
#include <signal.h>
bool g_killed = false;
void sigint_handler(int sig)
{
if(g_killed == false)
{
dstream<<DTIME<<"sigint_handler(): "
<<"Ctrl-C pressed, shutting down."<<std::endl;
g_killed = true;
}
else
{
(void)signal(SIGINT, SIG_DFL);
}
}
void signal_handler_init(void)
{
dstream<<"signal_handler_init()"<<std::endl;
(void)signal(SIGINT, sigint_handler);
}
#else // _WIN32
void signal_handler_init(void)
{
// No-op
}
#endif
bool * signal_handler_killstatus(void)
{
return &g_killed;
}
/*
Path mangler
*/
std::string path_data = "../data"; std::string path_data = "../data";
std::string path_userdata = "../"; std::string path_userdata = "../";

@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PORTING_HEADER #define PORTING_HEADER
#include <string> #include <string>
// Included for u64 and such // Included for u32 and such
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include "debug.h" #include "debug.h"
#include "constants.h" #include "constants.h"
@ -47,6 +47,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
namespace porting namespace porting
{ {
/*
Signal handler (grabs Ctrl-C on POSIX systems)
*/
void signal_handler_init(void);
// Returns a pointer to a bool.
// When the bool is true, program should quit.
bool * signal_handler_killstatus(void);
/* /*
Path of static data directory. Path of static data directory.
*/ */

@ -46,7 +46,12 @@ void * ServerThread::Thread()
while(getRun()) while(getRun())
{ {
try{ try{
//TimeTaker timer("AsyncRunStep() + Receive()");
{
//TimeTaker timer("AsyncRunStep()");
m_server->AsyncRunStep(); m_server->AsyncRunStep();
}
//dout_server<<"Running m_server->Receive()"<<std::endl; //dout_server<<"Running m_server->Receive()"<<std::endl;
m_server->Receive(); m_server->Receive();
@ -967,7 +972,8 @@ Server::Server(
m_time_counter(0), m_time_counter(0),
m_time_of_day_send_timer(0), m_time_of_day_send_timer(0),
m_uptime(0), m_uptime(0),
m_mapsavedir(mapsavedir) m_mapsavedir(mapsavedir),
m_shutdown_requested(false)
{ {
//m_flowwater_timer = 0.0; //m_flowwater_timer = 0.0;
m_liquid_transform_timer = 0.0; m_liquid_transform_timer = 0.0;
@ -987,12 +993,45 @@ Server::Server(
Server::~Server() Server::~Server()
{ {
// Save players /*
Send shutdown message
*/
{
JMutexAutoLock conlock(m_con_mutex);
std::wstring line = L"*** Server shutting down";
/*
Send the message to clients
*/
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
// Get client and check that it is valid
RemoteClient *client = i.getNode()->getValue();
assert(client->peer_id == i.getNode()->getKey());
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
SendChatMessage(client->peer_id, line);
}
}
/*
Save players
*/
m_env.serializePlayers(m_mapsavedir); m_env.serializePlayers(m_mapsavedir);
// Stop threads /*
Stop threads
*/
stop(); stop();
/*
Delete clients
*/
{
JMutexAutoLock clientslock(m_con_mutex); JMutexAutoLock clientslock(m_con_mutex);
for(core::map<u16, RemoteClient*>::Iterator for(core::map<u16, RemoteClient*>::Iterator
@ -1010,6 +1049,7 @@ Server::~Server()
// Delete client // Delete client
delete i.getNode()->getValue(); delete i.getNode()->getValue();
} }
}
} }
void Server::start(unsigned short port) void Server::start(unsigned short port)
@ -1588,37 +1628,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
} }
// Send information about server to player in chat // Send information about server to player in chat
{ SendChatMessage(peer_id, getStatusString());
std::wostringstream os(std::ios_base::binary);
os<<L"# Server: ";
// Uptime
os<<L"uptime="<<m_uptime.get();
// Information about clients
os<<L", clients={";
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
// Get client and check that it is valid
RemoteClient *client = i.getNode()->getValue();
assert(client->peer_id == i.getNode()->getKey());
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
// Get player
Player *player = m_env.getPlayer(client->peer_id);
// Get name of player
std::wstring name = L"unknown";
if(player != NULL)
name = narrow_to_wide(player->getName());
// Add name to information string
os<<name<<L",";
}
os<<L"}";
if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
os<<" WARNING: Map saving is disabled."<<std::endl;
// Send message
SendChatMessage(peer_id, os.str());
}
// Send information about joining in chat // Send information about joining in chat
{ {
@ -2462,12 +2472,94 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Get player name of this client // Get player name of this client
std::wstring name = narrow_to_wide(player->getName()); std::wstring name = narrow_to_wide(player->getName());
std::wstring line = std::wstring(L"<")+name+L"> "+message; // Line to send to players
std::wstring line;
// Whether to send to the player that sent the line
bool send_to_sender = false;
// Whether to send to other players
bool send_to_others = false;
// Parse commands
std::wstring commandprefix = L"/#";
if(message.substr(0, commandprefix.size()) == commandprefix)
{
line += L"Server: ";
message = message.substr(commandprefix.size());
// Get player name as narrow string
std::string name_s = player->getName();
// Convert message to narrow string
std::string message_s = wide_to_narrow(message);
// Operator is the single name defined in config.
std::string operator_name = g_settings.get("name");
bool is_operator = (operator_name != "" &&
wide_to_narrow(name) == operator_name);
bool valid_command = false;
if(message_s == "help")
{
line += L"-!- Available commands: ";
line += L"status ";
if(is_operator)
{
line += L"shutdown setting ";
}
else
{
}
send_to_sender = true;
valid_command = true;
}
else if(message_s == "status")
{
line = getStatusString();
send_to_sender = true;
valid_command = true;
}
else if(is_operator)
{
if(message_s == "shutdown")
{
dstream<<DTIME<<" Server: Operator requested shutdown."
<<std::endl;
m_shutdown_requested.set(true);
line += L"*** Server shutting down (operator request)";
send_to_sender = true;
valid_command = true;
}
else if(message_s.substr(0,8) == "setting ")
{
std::string confline = message_s.substr(8);
g_settings.parseConfigLine(confline);
line += L"-!- Setting changed.";
send_to_sender = true;
valid_command = true;
}
}
if(valid_command == false)
{
line += L"-!- Invalid command: " + message;
send_to_sender = true;
}
}
else
{
line += L"<";
/*if(is_operator)
line += L"@";*/
line += name;
line += L"> ";
line += message;
send_to_others = true;
}
if(line != L"")
{
dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl; dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
/* /*
Send the message to all other clients Send the message to clients
*/ */
for(core::map<u16, RemoteClient*>::Iterator for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator(); i = m_clients.getIterator();
@ -2479,13 +2571,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(client->serialization_version == SER_FMT_VER_INVALID) if(client->serialization_version == SER_FMT_VER_INVALID)
continue; continue;
// Don't send if it's the same one // Filter recipient
if(peer_id == client->peer_id) bool sender_selected = (peer_id == client->peer_id);
if(sender_selected == true && send_to_sender == false)
continue;
if(sender_selected == false && send_to_others == false)
continue; continue;
SendChatMessage(client->peer_id, line); SendChatMessage(client->peer_id, line);
} }
} }
}
else else
{ {
derr_server<<"WARNING: Server::ProcessData(): Ignoring " derr_server<<"WARNING: Server::ProcessData(): Ignoring "
@ -2580,6 +2676,7 @@ core::list<PlayerInfo> Server::getPlayerInfo()
return list; return list;
} }
void Server::peerAdded(con::Peer *peer) void Server::peerAdded(con::Peer *peer)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
@ -3020,6 +3117,8 @@ void Server::SendBlocks(float dtime)
JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock envlock(m_env_mutex);
//TimeTaker timer("Server::SendBlocks");
core::array<PrioritySortedBlockTransfer> queue; core::array<PrioritySortedBlockTransfer> queue;
s32 total_sending = 0; s32 total_sending = 0;
@ -3087,6 +3186,39 @@ RemoteClient* Server::getClient(u16 peer_id)
return n->getValue(); return n->getValue();
} }
std::wstring Server::getStatusString()
{
std::wostringstream os(std::ios_base::binary);
os<<L"# Server: ";
// Uptime
os<<L"uptime="<<m_uptime.get();
// Information about clients
os<<L", clients={";
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
// Get client and check that it is valid
RemoteClient *client = i.getNode()->getValue();
assert(client->peer_id == i.getNode()->getKey());
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
// Get player
Player *player = m_env.getPlayer(client->peer_id);
// Get name of player
std::wstring name = L"unknown";
if(player != NULL)
name = narrow_to_wide(player->getName());
// Add name to information string
os<<name<<L",";
}
os<<L"}";
if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
os<<" WARNING: Map saving is disabled."<<std::endl;
return os.str();
}
void setCreativeInventory(Player *player) void setCreativeInventory(Player *player)
{ {
player->resetInventory(); player->resetInventory();
@ -3455,11 +3587,11 @@ void Server::handlePeerChanges()
} }
} }
void dedicated_server_loop(Server &server) void dedicated_server_loop(Server &server, bool &kill)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
std::cout<<std::endl; std::cout<<DTIME<<std::endl;
std::cout<<"========================"<<std::endl; std::cout<<"========================"<<std::endl;
std::cout<<"Running dedicated server"<<std::endl; std::cout<<"Running dedicated server"<<std::endl;
std::cout<<"========================"<<std::endl; std::cout<<"========================"<<std::endl;
@ -3472,6 +3604,12 @@ void dedicated_server_loop(Server &server)
sleep_ms(30); sleep_ms(30);
server.step(0.030); server.step(0.030);
if(server.getShutdownRequested() || kill)
{
std::cout<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
break;
}
static int counter = 0; static int counter = 0;
counter--; counter--;
if(counter <= 0) if(counter <= 0)

@ -390,14 +390,10 @@ public:
void Receive(); void Receive();
void ProcessData(u8 *data, u32 datasize, u16 peer_id); void ProcessData(u8 *data, u32 datasize, u16 peer_id);
/*void Send(u16 peer_id, u16 channelnum,
SharedBuffer<u8> data, bool reliable);*/
// Environment and Connection must be locked when called // Environment and Connection must be locked when called
void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver); void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
// Environment and Connection must be locked when called //
//void SendSectorMeta(u16 peer_id, core::list<v2s16> ps, u8 ver);
core::list<PlayerInfo> getPlayerInfo(); core::list<PlayerInfo> getPlayerInfo();
@ -413,6 +409,11 @@ public:
return 1000; return 1000;
} }
bool getShutdownRequested()
{
return m_shutdown_requested.get();
}
private: private:
// Virtual methods from con::PeerHandler. // Virtual methods from con::PeerHandler.
@ -433,6 +434,9 @@ private:
// When called, connection mutex should be locked // When called, connection mutex should be locked
RemoteClient* getClient(u16 peer_id); RemoteClient* getClient(u16 peer_id);
// Connection must be locked when called
std::wstring getStatusString();
/* /*
Get a player from memory or creates one. Get a player from memory or creates one.
If player is already connected, return NULL If player is already connected, return NULL
@ -508,14 +512,18 @@ private:
std::string m_mapsavedir; std::string m_mapsavedir;
MutexedVariable<bool> m_shutdown_requested;
friend class EmergeThread; friend class EmergeThread;
friend class RemoteClient; friend class RemoteClient;
}; };
/* /*
Runs a simple dedicated server loop Runs a simple dedicated server loop.
Shuts down when run is set to false.
*/ */
void dedicated_server_loop(Server &server); void dedicated_server_loop(Server &server, bool &run);
#endif #endif

@ -98,7 +98,6 @@ std::ostream *derr_server_ptr = &dstream;
std::ostream *dout_client_ptr = &dstream; std::ostream *dout_client_ptr = &dstream;
std::ostream *derr_client_ptr = &dstream; std::ostream *derr_client_ptr = &dstream;
/* /*
gettime.h implementation gettime.h implementation
*/ */
@ -129,6 +128,9 @@ int main(int argc, char *argv[])
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
porting::signal_handler_init();
bool &kill = *porting::signal_handler_killstatus();
porting::initializePaths(); porting::initializePaths();
initializeMaterialProperties(); initializeMaterialProperties();
@ -251,6 +253,11 @@ int main(int argc, char *argv[])
srand(time(0)); srand(time(0));
mysrand(time(0)); mysrand(time(0));
// Initialize stuff
init_mapnode();
init_mineral();
/* /*
Run unit tests Run unit tests
*/ */
@ -260,11 +267,6 @@ int main(int argc, char *argv[])
run_tests(); run_tests();
} }
// Initialize stuff
init_mapnode();
init_mineral();
/* /*
Check parameters Check parameters
*/ */
@ -310,7 +312,7 @@ int main(int argc, char *argv[])
server.start(port); server.start(port);
// Run server // Run server
dedicated_server_loop(server); dedicated_server_loop(server, kill);
} //try } //try
catch(con::PeerNotFoundException &e) catch(con::PeerNotFoundException &e)

@ -192,7 +192,7 @@ struct TestMapNode
// Transparency // Transparency
n.d = CONTENT_AIR; n.d = CONTENT_AIR;
assert(n.light_propagates() == true); assert(n.light_propagates() == true);
n.d = 0; n.d = CONTENT_STONE;
assert(n.light_propagates() == false); assert(n.light_propagates() == false);
} }
}; };

@ -802,9 +802,15 @@ struct ValueSpec
class Settings class Settings
{ {
public: public:
Settings()
{
m_mutex.Init();
}
void writeLines(std::ostream &os) void writeLines(std::ostream &os)
{ {
JMutexAutoLock lock(m_mutex);
for(core::map<std::string, std::string>::Iterator for(core::map<std::string, std::string>::Iterator
i = m_settings.getIterator(); i = m_settings.getIterator();
i.atEnd() == false; i++) i.atEnd() == false; i++)
@ -817,6 +823,8 @@ public:
bool parseConfigLine(const std::string &line) bool parseConfigLine(const std::string &line)
{ {
JMutexAutoLock lock(m_mutex);
std::string trimmedline = trim(line); std::string trimmedline = trim(line);
// Ignore comments // Ignore comments
@ -899,6 +907,8 @@ public:
core::list<std::string> &dst, core::list<std::string> &dst,
core::map<std::string, bool> &updated) core::map<std::string, bool> &updated)
{ {
JMutexAutoLock lock(m_mutex);
if(is.eof()) if(is.eof())
return false; return false;
@ -981,6 +991,8 @@ public:
} }
} }
JMutexAutoLock lock(m_mutex);
// Write stuff back // Write stuff back
{ {
std::ofstream os(filename); std::ofstream os(filename);
@ -1087,21 +1099,29 @@ public:
void set(std::string name, std::string value) void set(std::string name, std::string value)
{ {
JMutexAutoLock lock(m_mutex);
m_settings[name] = value; m_settings[name] = value;
} }
void setDefault(std::string name, std::string value) void setDefault(std::string name, std::string value)
{ {
JMutexAutoLock lock(m_mutex);
m_defaults[name] = value; m_defaults[name] = value;
} }
bool exists(std::string name) bool exists(std::string name)
{ {
JMutexAutoLock lock(m_mutex);
return (m_settings.find(name) || m_defaults.find(name)); return (m_settings.find(name) || m_defaults.find(name));
} }
std::string get(std::string name) std::string get(std::string name)
{ {
JMutexAutoLock lock(m_mutex);
core::map<std::string, std::string>::Node *n; core::map<std::string, std::string>::Node *n;
n = m_settings.find(name); n = m_settings.find(name);
if(n == NULL) if(n == NULL)
@ -1139,7 +1159,7 @@ public:
bool getBoolAsk(std::string name, std::string question, bool def) bool getBoolAsk(std::string name, std::string question, bool def)
{ {
// If it is in settings // If it is in settings
if(m_settings.find(name)) if(exists(name))
return getBool(name); return getBool(name);
std::string s; std::string s;
@ -1167,7 +1187,7 @@ public:
u16 getU16Ask(std::string name, std::string question, u16 def) u16 getU16Ask(std::string name, std::string question, u16 def)
{ {
// If it is in settings // If it is in settings
if(m_settings.find(name)) if(exists(name))
return getU16(name); return getU16(name);
std::string s; std::string s;
@ -1238,12 +1258,17 @@ public:
void clear() void clear()
{ {
JMutexAutoLock lock(m_mutex);
m_settings.clear(); m_settings.clear();
m_defaults.clear(); m_defaults.clear();
} }
Settings & operator+=(Settings &other) Settings & operator+=(Settings &other)
{ {
JMutexAutoLock lock(m_mutex);
JMutexAutoLock lock2(other.m_mutex);
if(&other == this) if(&other == this)
return *this; return *this;
@ -1267,6 +1292,9 @@ public:
Settings & operator=(Settings &other) Settings & operator=(Settings &other)
{ {
JMutexAutoLock lock(m_mutex);
JMutexAutoLock lock2(other.m_mutex);
if(&other == this) if(&other == this)
return *this; return *this;
@ -1279,6 +1307,8 @@ public:
private: private:
core::map<std::string, std::string> m_settings; core::map<std::string, std::string> m_settings;
core::map<std::string, std::string> m_defaults; core::map<std::string, std::string> m_defaults;
// All methods that access m_settings/m_defaults directly should lock this.
JMutex m_mutex;
}; };
/* /*