summaryrefslogtreecommitdiff
path: root/src/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.cpp')
-rw-r--r--src/server.cpp137
1 files changed, 131 insertions, 6 deletions
diff --git a/src/server.cpp b/src/server.cpp
index 8c42ab5fd..6cb79c875 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -148,7 +148,8 @@ Server::Server(
const std::string &path_world,
const SubgameSpec &gamespec,
bool simple_singleplayer_mode,
- bool ipv6
+ bool ipv6,
+ ChatInterface *iface
):
m_path_world(path_world),
m_gamespec(gamespec),
@@ -175,6 +176,7 @@ Server::Server(
m_clients(&m_con),
m_shutdown_requested(false),
m_shutdown_ask_reconnect(false),
+ m_admin_chat(iface),
m_ignore_map_edit_events(false),
m_ignore_map_edit_events_peer_id(0),
m_next_sound_id(0)
@@ -576,6 +578,36 @@ void Server::AsyncRunStep(bool initial_step)
}
/*
+ Listen to the admin chat, if available
+ */
+ if (m_admin_chat) {
+ if (!m_admin_chat->command_queue.empty()) {
+ MutexAutoLock lock(m_env_mutex);
+ while (!m_admin_chat->command_queue.empty()) {
+ ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
+ if (evt->type == CET_NICK_ADD) {
+ // The terminal informed us of its nick choice
+ m_admin_nick = ((ChatEventNick *)evt)->nick;
+ if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
+ errorstream << "You haven't set up an account." << std::endl
+ << "Please log in using the client as '"
+ << m_admin_nick << "' with a secure password." << std::endl
+ << "Until then, you can't execute admin tasks via the console," << std::endl
+ << "and everybody can claim the user account instead of you," << std::endl
+ << "giving them full control over this server." << std::endl;
+ }
+ } else {
+ assert(evt->type == CET_CHAT);
+ handleAdminChat((ChatEventChat *)evt);
+ }
+ delete evt;
+ }
+ }
+ m_admin_chat->outgoing_queue.push_back(
+ new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
+ }
+
+ /*
Do background stuff
*/
@@ -1100,16 +1132,19 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
// Send information about joining in chat
{
- std::wstring name = L"unknown";
+ std::string name = "unknown";
Player *player = m_env->getPlayer(peer_id);
if(player != NULL)
- name = narrow_to_wide(player->getName());
+ name = player->getName();
std::wstring message;
message += L"*** ";
- message += name;
+ message += narrow_to_wide(name);
message += L" joined the game.";
SendChatMessage(PEER_ID_INEXISTENT,message);
+ if (m_admin_chat)
+ m_admin_chat->outgoing_queue.push_back(
+ new ChatEventNick(CET_NICK_ADD, name));
}
}
Address addr = getPeerAddress(player->peer_id);
@@ -1432,6 +1467,16 @@ void Server::handlePeerChanges()
}
}
+void Server::printToConsoleOnly(const std::string &text)
+{
+ if (m_admin_chat) {
+ m_admin_chat->outgoing_queue.push_back(
+ new ChatEventChat("", utf8_to_wide(text)));
+ } else {
+ std::cout << text;
+ }
+}
+
void Server::Send(NetworkPacket* pkt)
{
m_clients.send(pkt->getPeerId(),
@@ -2665,9 +2710,13 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
os << player->getName() << " ";
}
- actionstream << player->getName() << " "
+ std::string name = player->getName();
+ actionstream << name << " "
<< (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
<< " List of players: " << os.str() << std::endl;
+ if (m_admin_chat)
+ m_admin_chat->outgoing_queue.push_back(
+ new ChatEventNick(CET_NICK_REMOVE, name));
}
}
{
@@ -2700,6 +2749,77 @@ void Server::UpdateCrafting(Player* player)
plist->changeItem(0, preview);
}
+std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
+ const std::wstring &wmessage, u16 peer_id_to_avoid_sending)
+{
+ // If something goes wrong, this player is to blame
+ RollbackScopeActor rollback_scope(m_rollback,
+ std::string("player:") + name);
+
+ // Line to send
+ std::wstring line;
+ // Whether to send line to the player that sent the message, or to all players
+ bool broadcast_line = true;
+
+ // Run script hook
+ bool ate = m_script->on_chat_message(name,
+ wide_to_utf8(wmessage));
+ // If script ate the message, don't proceed
+ if (ate)
+ return L"";
+
+ // Commands are implemented in Lua, so only catch invalid
+ // commands that were not "eaten" and send an error back
+ if (wmessage[0] == L'/') {
+ std::wstring wcmd = wmessage.substr(1);
+ broadcast_line = false;
+ if (wcmd.length() == 0)
+ line += L"-!- Empty command";
+ else
+ line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
+ } else {
+ line += L"<";
+ line += wname;
+ line += L"> ";
+ line += wmessage;
+ }
+
+ /*
+ Tell calling method to send the message to sender
+ */
+ if (!broadcast_line) {
+ return line;
+ } else {
+ /*
+ Send the message to others
+ */
+ actionstream << "CHAT: " << wide_to_narrow(line) << std::endl;
+
+ std::vector<u16> clients = m_clients.getClientIDs();
+
+ for (u16 i = 0; i < clients.size(); i++) {
+ u16 cid = clients[i];
+ if (cid != peer_id_to_avoid_sending)
+ SendChatMessage(cid, line);
+ }
+ }
+ return L"";
+}
+
+void Server::handleAdminChat(const ChatEventChat *evt)
+{
+ std::string name = evt->nick;
+ std::wstring wname = utf8_to_wide(name);
+ std::wstring wmessage = evt->evt_msg;
+
+ std::wstring answer = handleChat(name, wname, wmessage);
+
+ // If asked to send answer to sender
+ if (!answer.empty()) {
+ m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
+ }
+}
+
RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
{
RemoteClient *client = getClientNoEx(peer_id,state_min);
@@ -2831,9 +2951,14 @@ void Server::notifyPlayer(const char *name, const std::wstring &msg)
if (!m_env)
return;
+ if (m_admin_nick == name && !m_admin_nick.empty()) {
+ m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
+ }
+
Player *player = m_env->getPlayer(name);
- if (!player)
+ if (!player) {
return;
+ }
if (player->peer_id == PEER_ID_INEXISTENT)
return;