// Deinitialize scripting
infostream << "Server: Deinitializing scripting" << std::endl;
delete m_script;
+ delete m_startup_server_map; // if available
+ delete m_game_settings;
while (!m_unsent_map_edit_queue.empty()) {
delete m_unsent_map_edit_queue.front();
infostream << "- world: " << m_path_world << std::endl;
infostream << "- game: " << m_gamespec.path << std::endl;
+ m_game_settings = Settings::createLayer(SL_GAME);
+
// Create world if it doesn't exist
try {
loadGameConfAndInitWorld(m_path_world,
// Create the Map (loads map_meta.txt, overriding configured mapgen params)
ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
+ m_startup_server_map = servermap;
// Initialize scripting
infostream << "Server: Initializing Lua" << std::endl;
m_craftdef->initHashes(this);
// Initialize Environment
+ m_startup_server_map = nullptr; // Ownership moved to ServerEnvironment
m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
m_inventory_mgr->setEnv(m_env);
// u16 id
// std::string data
buffer.append(idbuf, sizeof(idbuf));
- buffer.append(serializeString(aom.datastring));
+ buffer.append(serializeString16(aom.datastring));
}
}
/*
return *retval != -1;
}
-bool Server::getClientInfo(
- session_t peer_id,
- ClientState* state,
- u32* uptime,
- u8* ser_vers,
- u16* prot_vers,
- u8* major,
- u8* minor,
- u8* patch,
- std::string* vers_string,
- std::string* lang_code
- )
-{
- *state = m_clients.getClientState(peer_id);
+bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
+{
m_clients.lock();
RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
return false;
}
- *uptime = client->uptime();
- *ser_vers = client->serialization_version;
- *prot_vers = client->net_proto_version;
+ ret.state = client->getState();
+ ret.addr = client->getAddress();
+ ret.uptime = client->uptime();
+ ret.ser_vers = client->serialization_version;
+ ret.prot_vers = client->net_proto_version;
- *major = client->getMajor();
- *minor = client->getMinor();
- *patch = client->getPatch();
- *vers_string = client->getFull();
- *lang_code = client->getLangCode();
+ ret.major = client->getMajor();
+ ret.minor = client->getMinor();
+ ret.patch = client->getPatch();
+ ret.vers_string = client->getFullVer();
+
+ ret.lang_code = client->getLangCode();
m_clients.unlock();
return;
session_t peer_id = playersao->getPeerID();
- bool is_alive = playersao->getHP() > 0;
+ bool is_alive = !playersao->isDead();
if (is_alive)
SendPlayerHP(peer_id);
NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
u8 version = 1;
u8 type = message.type;
- pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
+ pkt << version << type << message.sender << message.message
+ << static_cast<u64>(message.timestamp);
if (peer_id != PEER_ID_INEXISTENT) {
RemotePlayer *player = m_env->getPlayer(peer_id);
PlayerSAO *sao = player->getPlayerSAO();
assert(sao);
+ // Send attachment updates instantly to the client prior updating position
+ sao->sendOutdatedData();
+
NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
writeU8((u8*)buf, type);
data.append(buf, 1);
- data.append(serializeLongString(
+ data.append(serializeString32(
obj->getClientInitializationData(client->net_proto_version)));
// Add to known objects
/*
Create a packet with the block in the right format
*/
-
+ thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
std::ostringstream os(std::ios_base::binary);
- block->serialize(os, ver, false);
+ block->serialize(os, ver, false, net_compression_level);
block->serializeNetworkSpecific(os);
std::string s = os.str();
- NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
+ NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
pkt << block->getPos();
pkt.putRawString(s.c_str(), s.size());
// Collect all media file paths
std::vector<std::string> paths;
- // The paths are ordered in descending priority
+
+ // ordered in descending priority
+ paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
m_modmgr->getModsMediaPaths(paths);
}
}
+void Server::SendMinimapModes(session_t peer_id,
+ std::vector<MinimapMode> &modes, size_t wanted_mode)
+{
+ RemotePlayer *player = m_env->getPlayer(peer_id);
+ assert(player);
+ if (player->getPeerId() == PEER_ID_INEXISTENT)
+ return;
+
+ NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
+ pkt << (u16)modes.size() << (u16)wanted_mode;
+
+ for (auto &mode : modes)
+ pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
+
+ Send(&pkt);
+}
+
void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
{
NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
}
}
-std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
+std::wstring Server::handleChat(const std::string &name,
std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
{
// If something goes wrong, this player is to blame
auto message = trim(wide_to_utf8(wmessage));
if (message.find_first_of("\n\r") != std::wstring::npos) {
- return L"New lines are not permitted in chat messages";
+ return L"Newlines are not permitted in chat messages";
}
// Run script hook, exit if script ate the chat message
the Cyrillic alphabet and some characters on older Android devices
*/
#ifdef __ANDROID__
- line += L"<" + wname + L"> " + wmessage;
+ line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
#else
- line += narrow_to_wide(m_script->formatChatMessage(name,
- wide_to_narrow(wmessage)));
+ line += utf8_to_wide(m_script->formatChatMessage(name,
+ wide_to_utf8(wmessage)));
#endif
}
/*
Send the message to others
*/
- actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
-
- std::vector<session_t> clients = m_clients.getClientIDs();
-
- /*
- Send the message back to the inital sender
- if they are using protocol version >= 29
- */
+ actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
- session_t peer_id_to_avoid_sending =
- (player ? player->getPeerId() : PEER_ID_INEXISTENT);
+ ChatMessage chatmsg(line);
- if (player && player->protocol_version >= 29)
- peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
+ std::vector<session_t> clients = m_clients.getClientIDs();
+ for (u16 cid : clients)
+ SendChatMessage(cid, chatmsg);
- for (u16 cid : clients) {
- if (cid != peer_id_to_avoid_sending)
- SendChatMessage(cid, ChatMessage(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);
+ std::wstring answer = handleChat(name, wmessage);
// If asked to send answer to sender
if (!answer.empty()) {
return player->getPlayerSAO();
}
-std::wstring Server::getStatusString()
+std::string Server::getStatusString()
{
- std::wostringstream os(std::ios_base::binary);
- os << L"# Server: ";
+ std::ostringstream os(std::ios_base::binary);
+ os << "# Server: ";
// Version
- os << L"version=" << narrow_to_wide(g_version_string);
+ os << "version=" << g_version_string;
// Uptime
- os << L", uptime=" << m_uptime_counter->get();
+ os << ", uptime=" << m_uptime_counter->get();
// Max lag estimate
- os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
+ os << ", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
// Information about clients
bool first = true;
- os << L", clients={";
+ os << ", clients={";
if (m_env) {
std::vector<session_t> clients = m_clients.getClientIDs();
for (session_t client_id : clients) {
RemotePlayer *player = m_env->getPlayer(client_id);
// Get name of player
- std::wstring name = L"unknown";
- if (player)
- name = narrow_to_wide(player->getName());
+ const char *name = player ? player->getName() : "<unknown>";
// Add name to information string
if (!first)
- os << L", ";
+ os << ", ";
else
first = false;
-
os << name;
}
}
- os << L"}";
+ os << "}";
if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
- os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
+ os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
if (!g_settings->get("motd").empty())
- os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
+ os << std::endl << "# Server: " << g_settings->get("motd");
return os.str();
}
Address Server::getPeerAddress(session_t peer_id)
{
- return m_con->GetPeerAddress(peer_id);
+ // Note that this is only set after Init was received in Server::handleCommand_Init
+ return getClient(peer_id, CS_Invalid)->getAddress();
}
void Server::setLocalPlayerAnimations(RemotePlayer *player,
SendDeleteParticleSpawner(peer_id, id);
}
-bool Server::dynamicAddMedia(const std::string &filepath)
+bool Server::dynamicAddMedia(const std::string &filepath,
+ std::vector<RemotePlayer*> &sent_to)
{
std::string filename = fs::GetFilenameFromPath(filepath.c_str());
if (m_media.find(filename) != m_media.end()) {
pkt << raw_hash << filename << (bool) true;
pkt.putLongString(filedata);
- auto client_ids = m_clients.getClientIDs(CS_DefinitionsSent);
- for (session_t client_id : client_ids) {
+ m_clients.lock();
+ for (auto &pair : m_clients.getClientList()) {
+ if (pair.second->getState() < CS_DefinitionsSent)
+ continue;
+ if (pair.second->net_proto_version < 39)
+ continue;
+
+ if (auto player = m_env->getPlayer(pair.second->peer_id))
+ sent_to.emplace_back(player);
/*
+ FIXME: this is a very awful hack
The network layer only guarantees ordered delivery inside a channel.
Since the very next packet could be one that uses the media, we have
to push the media over ALL channels to ensure it is processed before
- channel 1 (HUD)
- channel 0 (everything else: e.g. play_sound, object messages)
*/
- m_clients.send(client_id, 1, &pkt, true);
- m_clients.send(client_id, 0, &pkt, true);
+ m_clients.send(pair.second->peer_id, 1, &pkt, true);
+ m_clients.send(pair.second->peer_id, 0, &pkt, true);
}
+ m_clients.unlock();
return true;
}