#include "map.h"
#include "mapsector.h"
#include "minimap.h"
+#include "modchannels.h"
#include "nodedef.h"
#include "serialization.h"
#include "server.h"
#include "util/strfnd.h"
#include "client/clientevent.h"
+#include "client/sound.h"
#include "network/clientopcodes.h"
#include "network/connection.h"
#include "script/scripting_client.h"
// Authenticate using that method, or abort if there wasn't any method found
if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
- startAuth(chosen_auth_mechanism);
+ if (chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP
+ && !m_simple_singleplayer_mode) {
+ promptConfirmRegistration(chosen_auth_mechanism);
+ } else {
+ startAuth(chosen_auth_mechanism);
+ }
} else {
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
m_access_denied = true;
<< " dr=" << dr << std::endl;
}
-void Client::handleCommand_ChatMessageOld(NetworkPacket *pkt)
-{
- /*
- u16 command
- u16 length
- wstring message
- */
- u16 len, read_wchar;
-
- *pkt >> len;
-
- std::wstring message;
- for (u32 i = 0; i < len; i++) {
- *pkt >> read_wchar;
- message += (wchar_t)read_wchar;
- }
-
- // If chat message not consummed by client lua API
- // @TODO send this to CSM using ChatMessage object
- if (!moddingEnabled() || !m_script->on_receiving_message(wide_to_utf8(message))) {
- pushToChatQueue(new ChatMessage(message));
- }
-}
-
void Client::handleCommand_ChatMessage(NetworkPacket *pkt)
{
/*
event->player_force_move.pitch = pitch;
event->player_force_move.yaw = yaw;
m_client_event_queue.push(event);
-
- // Ignore damage for a few seconds, so that the player doesn't
- // get damage from falling on ground
- m_ignore_damage_timer = 3.0;
}
void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
float minsize;
float maxsize;
bool collisiondetection;
- u32 id;
+ u32 server_id;
*pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
>> minacc >> maxacc >> minexptime >> maxexptime >> minsize
std::string texture = pkt->readLongString();
- *pkt >> id;
+ *pkt >> server_id;
bool vertical = false;
bool collision_removal = false;
glow = readU8(is);
} catch (...) {}
+ u32 client_id = m_particle_manager.getSpawnerId();
+ m_particles_server_to_client[server_id] = client_id;
+
ClientEvent *event = new ClientEvent();
event->type = CE_ADD_PARTICLESPAWNER;
event->add_particlespawner.amount = amount;
event->add_particlespawner.attached_id = attached_id;
event->add_particlespawner.vertical = vertical;
event->add_particlespawner.texture = new std::string(texture);
- event->add_particlespawner.id = id;
+ event->add_particlespawner.id = client_id;
event->add_particlespawner.animation = animation;
event->add_particlespawner.glow = glow;
void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
{
- u32 id;
- *pkt >> id;
+ u32 server_id;
+ *pkt >> server_id;
+
+ u32 client_id;
+ auto i = m_particles_server_to_client.find(server_id);
+ if (i != m_particles_server_to_client.end())
+ client_id = i->second;
+ else
+ return;
ClientEvent *event = new ClientEvent();
event->type = CE_DELETE_PARTICLESPAWNER;
- event->delete_particlespawner.id = id;
+ event->delete_particlespawner.id = client_id;
m_client_event_queue.push(event);
}
std::string datastring(pkt->getString(0), pkt->getSize());
std::istringstream is(datastring, std::ios_base::binary);
- u32 id;
+ u32 server_id;
u8 type;
v2f pos;
std::string name;
v3f world_pos;
v2s32 size;
- *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
+ *pkt >> server_id >> type >> pos >> name >> scale >> text >> number >> item
>> dir >> align >> offset;
try {
*pkt >> world_pos;
ClientEvent *event = new ClientEvent();
event->type = CE_HUDADD;
- event->hudadd.id = id;
+ event->hudadd.server_id = server_id;
event->hudadd.type = type;
event->hudadd.pos = new v2f(pos);
event->hudadd.name = new std::string(name);
void Client::handleCommand_HudRemove(NetworkPacket* pkt)
{
- u32 id;
+ u32 server_id;
- *pkt >> id;
+ *pkt >> server_id;
- ClientEvent *event = new ClientEvent();
- event->type = CE_HUDRM;
- event->hudrm.id = id;
- m_client_event_queue.push(event);
+ auto i = m_hud_server_to_client.find(server_id);
+ if (i != m_hud_server_to_client.end()) {
+ int client_id = i->second;
+ m_hud_server_to_client.erase(i);
+
+ ClientEvent *event = new ClientEvent();
+ event->type = CE_HUDRM;
+ event->hudrm.id = client_id;
+ m_client_event_queue.push(event);
+ }
}
void Client::handleCommand_HudChange(NetworkPacket* pkt)
v3f v3fdata;
u32 intdata = 0;
v2s32 v2s32data;
- u32 id;
+ u32 server_id;
u8 stat;
- *pkt >> id >> stat;
+ *pkt >> server_id >> stat;
if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
else
*pkt >> intdata;
- ClientEvent *event = new ClientEvent();
- event->type = CE_HUDCHANGE;
- event->hudchange.id = id;
- event->hudchange.stat = (HudElementStat)stat;
- event->hudchange.v2fdata = new v2f(v2fdata);
- event->hudchange.v3fdata = new v3f(v3fdata);
- event->hudchange.sdata = new std::string(sdata);
- event->hudchange.data = intdata;
- event->hudchange.v2s32data = new v2s32(v2s32data);
- m_client_event_queue.push(event);
+ std::unordered_map<u32, u32>::const_iterator i = m_hud_server_to_client.find(server_id);
+ if (i != m_hud_server_to_client.end()) {
+ ClientEvent *event = new ClientEvent();
+ event->type = CE_HUDCHANGE;
+ event->hudchange.id = i->second;
+ event->hudchange.stat = (HudElementStat)stat;
+ event->hudchange.v2fdata = new v2f(v2fdata);
+ event->hudchange.v3fdata = new v3f(v3fdata);
+ event->hudchange.sdata = new std::string(sdata);
+ event->hudchange.data = intdata;
+ event->hudchange.v2s32data = new v2s32(v2s32data);
+ m_client_event_queue.push(event);
+ }
}
void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
void Client::handleCommand_CSMFlavourLimits(NetworkPacket *pkt)
{
*pkt >> m_csm_flavour_limits >> m_csm_noderange_limit;
+
+ // Now we have flavours, load mods if it's enabled
+ // Note: this should be moved after mods receptions from server instead
+ loadMods();
+}
+
+/*
+ * Mod channels
+ */
+
+void Client::handleCommand_ModChannelMsg(NetworkPacket *pkt)
+{
+ std::string channel_name, sender, channel_msg;
+ *pkt >> channel_name >> sender >> channel_msg;
+
+ verbosestream << "Mod channel message received from server " << pkt->getPeerId()
+ << " on channel " << channel_name << ". sender: `" << sender << "`, message: "
+ << channel_msg << std::endl;
+
+ if (!m_modchannel_mgr->channelRegistered(channel_name)) {
+ verbosestream << "Server sent us messages on unregistered channel "
+ << channel_name << ", ignoring." << std::endl;
+ return;
+ }
+
+ m_script->on_modchannel_message(channel_name, sender, channel_msg);
+}
+
+void Client::handleCommand_ModChannelSignal(NetworkPacket *pkt)
+{
+ u8 signal_tmp;
+ ModChannelSignal signal;
+ std::string channel;
+
+ *pkt >> signal_tmp >> channel;
+
+ signal = (ModChannelSignal)signal_tmp;
+
+ bool valid_signal = true;
+ // @TODO: send Signal to Lua API
+ switch (signal) {
+ case MODCHANNEL_SIGNAL_JOIN_OK:
+ m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
+ infostream << "Server ack our mod channel join on channel `" << channel
+ << "`, joining." << std::endl;
+ break;
+ case MODCHANNEL_SIGNAL_JOIN_FAILURE:
+ // Unable to join, remove channel
+ m_modchannel_mgr->leaveChannel(channel, 0);
+ infostream << "Server refused our mod channel join on channel `" << channel
+ << "`" << std::endl;
+ break;
+ case MODCHANNEL_SIGNAL_LEAVE_OK:
+#ifndef NDEBUG
+ infostream << "Server ack our mod channel leave on channel " << channel
+ << "`, leaving." << std::endl;
+#endif
+ break;
+ case MODCHANNEL_SIGNAL_LEAVE_FAILURE:
+ infostream << "Server refused our mod channel leave on channel `" << channel
+ << "`" << std::endl;
+ break;
+ case MODCHANNEL_SIGNAL_CHANNEL_NOT_REGISTERED:
+#ifndef NDEBUG
+ // Generally unused, but ensure we don't do an implementation error
+ infostream << "Server tells us we sent a message on channel `" << channel
+ << "` but we are not registered. Message was dropped." << std::endl;
+#endif
+ break;
+ case MODCHANNEL_SIGNAL_SET_STATE: {
+ u8 state;
+ *pkt >> state;
+
+ if (state == MODCHANNEL_STATE_INIT || state >= MODCHANNEL_STATE_MAX) {
+ infostream << "Received wrong channel state " << state
+ << ", ignoring." << std::endl;
+ return;
+ }
+
+ m_modchannel_mgr->setChannelState(channel, (ModChannelState) state);
+ infostream << "Server sets mod channel `" << channel
+ << "` in read-only mode." << std::endl;
+ break;
+ }
+ default:
+#ifndef NDEBUG
+ warningstream << "Received unhandled mod channel signal ID "
+ << signal << ", ignoring." << std::endl;
+#endif
+ valid_signal = false;
+ break;
+ }
+
+ // If signal is valid, forward it to client side mods
+ if (valid_signal)
+ m_script->on_modchannel_signal(channel, signal);
}