Re-add protocol v25-33 support for servers.

master
luk3yx 2020-02-18 11:54:18 +01:00 committed by MoNTE48
parent 205893620c
commit 7b37f2c1d8
29 changed files with 665 additions and 173 deletions

View File

@ -195,8 +195,12 @@ core.register_entity(":__builtin:item", {
return -- Don't do anything return -- Don't do anything
end end
assert(moveresult, -- assert(moveresult,
"Collision info missing, this is caused by an out-of-date/buggy mod or game") -- "Collision info missing, this is caused by an out-of-date/buggy mod or game")
if not moveresult then
self.object:set_velocity({x=0, y=0, z=0})
return
end
if not moveresult.collides then if not moveresult.collides then
-- future TODO: items should probably decelerate in air -- future TODO: items should probably decelerate in air

Binary file not shown.

View File

@ -44,15 +44,18 @@ enum ActiveObjectType {
struct ActiveObjectMessage struct ActiveObjectMessage
{ {
ActiveObjectMessage(u16 id_, bool reliable_=true, const std::string &data_ = "") : ActiveObjectMessage(u16 id_, bool reliable_ = true,
const std::string &data_ = "", const std::string legacy_ = "") :
id(id_), id(id_),
reliable(reliable_), reliable(reliable_),
datastring(data_) datastring(data_),
legacystring(legacy_)
{} {}
u16 id; u16 id;
bool reliable; bool reliable;
std::string datastring; std::string datastring;
std::string legacystring;
}; };
enum ActiveObjectCommand { enum ActiveObjectCommand {

View File

@ -750,8 +750,8 @@ void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacyp
} else if (client->net_proto_version != 0) { } else if (client->net_proto_version != 0) {
pkt_to_send = legacypkt; pkt_to_send = legacypkt;
} else { } else {
warningstream << "Client with unhandled version to handle: '" // This will happen if a client is connecting when sendToAllCompat
<< client->net_proto_version << "'"; // is called, this can safely be ignored.
continue; continue;
} }
@ -762,6 +762,34 @@ void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacyp
} }
} }
void ClientInterface::oldSendToAll(NetworkPacket *pkt)
{
RecursiveMutexAutoLock clientslock(m_clients_mutex);
for (auto &client_it : m_clients) {
RemoteClient *client = client_it.second;
if (client->net_proto_version != 0 && client->net_proto_version < 37) {
m_con->Send(client->peer_id,
clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
clientCommandFactoryTable[pkt->getCommand()].reliable);
}
}
}
void ClientInterface::newSendToAll(NetworkPacket *pkt)
{
RecursiveMutexAutoLock clientslock(m_clients_mutex);
for (auto &client_it : m_clients) {
RemoteClient *client = client_it.second;
if (client->net_proto_version > 36) {
m_con->Send(client->peer_id,
clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
clientCommandFactoryTable[pkt->getCommand()].reliable);
}
}
}
RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min) RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
{ {
RecursiveMutexAutoLock clientslock(m_clients_mutex); RecursiveMutexAutoLock clientslock(m_clients_mutex);

View File

@ -458,6 +458,8 @@ public:
/* send to all clients */ /* send to all clients */
void sendToAll(NetworkPacket *pkt); void sendToAll(NetworkPacket *pkt);
void sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt, u16 min_proto_ver); void sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt, u16 min_proto_ver);
void oldSendToAll(NetworkPacket *pkt);
void newSendToAll(NetworkPacket *pkt);
/* delete a client */ /* delete a client */
void DeleteClient(session_t peer_id); void DeleteClient(session_t peer_id);

View File

@ -126,6 +126,11 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
{ {
// protocol_version >= 37 // protocol_version >= 37
u8 version = 6; u8 version = 6;
// protocol_version < 37
if (protocol_version < 37)
version = 3;
writeU8(os, version); writeU8(os, version);
writeU8(os, type); writeU8(os, type);
os << serializeString(name); os << serializeString(name);
@ -153,13 +158,25 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
os << serializeString(node_placement_prediction); os << serializeString(node_placement_prediction);
// Version from ContentFeatures::serialize to keep in sync if (version == 3) {
sound_place.serialize(os, CONTENTFEATURES_VERSION); os << serializeString(sound_place.name);
sound_place_failed.serialize(os, CONTENTFEATURES_VERSION); writeF1000(os, sound_place.gain);
writeF1000(os, range);
os << serializeString(sound_place_failed.name);
writeF1000(os, sound_place_failed.gain);
} else {
// Version from ContentFeatures::serialize to keep in sync
sound_place.serialize(os, CONTENTFEATURES_VERSION);
sound_place_failed.serialize(os, CONTENTFEATURES_VERSION);
writeF32(os, range);
}
writeF(os, range, protocol_version);
os << serializeString(palette_image); os << serializeString(palette_image);
writeARGB8(os, color); writeARGB8(os, color);
if (version == 3)
return;
os << serializeString(inventory_overlay); os << serializeString(inventory_overlay);
os << serializeString(wield_overlay); os << serializeString(wield_overlay);
} }

View File

@ -355,7 +355,7 @@ static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
} }
} }
void MapBlock::serialize(std::ostream &os, u8 version, bool disk) void MapBlock::serialize(std::ostream &os, u8 version, bool disk, std::string formspec_prepend)
{ {
if(!ser_ver_supported(version)) if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapBlock format not supported"); throw VersionMismatchException("ERROR: MapBlock format not supported");
@ -411,7 +411,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
Node metadata Node metadata
*/ */
std::ostringstream oss(std::ios_base::binary); std::ostringstream oss(std::ios_base::binary);
m_node_metadata.serialize(oss, version, disk); m_node_metadata.serialize(oss, version, disk, false, formspec_prepend);
compressZlib(oss.str(), os); compressZlib(oss.str(), os);
/* /*

View File

@ -482,7 +482,8 @@ public:
// These don't write or read version by itself // These don't write or read version by itself
// Set disk to true for on-disk format, false for over-the-network format // Set disk to true for on-disk format, false for over-the-network format
// Precondition: version >= SER_FMT_VER_LOWEST_WRITE // Precondition: version >= SER_FMT_VER_LOWEST_WRITE
void serialize(std::ostream &os, u8 version, bool disk); void serialize(std::ostream &os, u8 version, bool disk,
std::string formspec_prepend="");
// If disk == true: In addition to doing other things, will add // If disk == true: In addition to doing other things, will add
// unknown blocks from id-name mapping to wndef // unknown blocks from id-name mapping to wndef
void deSerialize(std::istream &is, u8 version, bool disk); void deSerialize(std::istream &is, u8 version, bool disk);

View File

@ -44,6 +44,7 @@ public:
u16 getCommand() { return m_command; } u16 getCommand() { return m_command; }
const u32 getRemainingBytes() const { return m_datasize - m_read_offset; } const u32 getRemainingBytes() const { return m_datasize - m_read_offset; }
const char *getRemainingString() { return getString(m_read_offset); } const char *getRemainingString() { return getString(m_read_offset); }
u16 getProtocolVersion() const { return m_protocol_version; }
// Returns a c-string without copying. // Returns a c-string without copying.
// A better name for this would be getRawString() // A better name for this would be getRawString()

View File

@ -210,7 +210,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION) #define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION)
// Server's supported network protocol range // Server's supported network protocol range
#define SERVER_PROTOCOL_VERSION_MIN 37 #define SERVER_PROTOCOL_VERSION_MIN 25
#define SERVER_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION #define SERVER_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION
// Client's supported network protocol range // Client's supported network protocol range

View File

@ -89,7 +89,7 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
null_command_handler, // 0x3e null_command_handler, // 0x3e
null_command_handler, // 0x3f null_command_handler, // 0x3f
{ "TOSERVER_REQUEST_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_RequestMedia }, // 0x40 { "TOSERVER_REQUEST_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_RequestMedia }, // 0x40
null_command_handler, // 0x41 { "TOSERVER_RECEIVED_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_Deprecated }, // 0x41 not used by the server since protocol version 23
null_command_handler, // 0x42 null_command_handler, // 0x42
{ "TOSERVER_CLIENT_READY", TOSERVER_STATE_STARTUP, &Server::handleCommand_ClientReady }, // 0x43 { "TOSERVER_CLIENT_READY", TOSERVER_STATE_STARTUP, &Server::handleCommand_ClientReady }, // 0x43
null_command_handler, // 0x44 null_command_handler, // 0x44

View File

@ -324,7 +324,7 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
sendDetachedInventories(peer_id, false); sendDetachedInventories(peer_id, false);
// Send player movement settings // Send player movement settings
SendMovement(peer_id); SendMovement(peer_id, protocol_version);
// Send time of day // Send time of day
u16 time = m_env->getTimeOfDay(); u16 time = m_env->getTimeOfDay();
@ -454,7 +454,7 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao, void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
NetworkPacket *pkt) NetworkPacket *pkt)
{ {
if (pkt->getRemainingBytes() < 12 + 12 + 4 + 4 + 4 + 1 + 1) if (pkt->getRemainingBytes() < 12 + 12 + 4 + 4)
return; return;
v3s32 ps, ss; v3s32 ps, ss;
@ -474,10 +474,14 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
f32 fov = 0; f32 fov = 0;
u8 wanted_range = 0; u8 wanted_range = 0;
*pkt >> keyPressed; if (pkt->getRemainingBytes() >= 4)
*pkt >> f32fov; *pkt >> keyPressed;
fov = (f32)f32fov / 80.0f; if (pkt->getRemainingBytes() >= 1) {
*pkt >> wanted_range; *pkt >> f32fov;
fov = (f32)f32fov / 80.0f;
if (pkt->getRemainingBytes() >= 1)
*pkt >> wanted_range;
}
v3f position((f32)ps.X / 100.0f, (f32)ps.Y / 100.0f, (f32)ps.Z / 100.0f); v3f position((f32)ps.X / 100.0f, (f32)ps.Y / 100.0f, (f32)ps.Z / 100.0f);
v3f speed((f32)ss.X / 100.0f, (f32)ss.Y / 100.0f, (f32)ss.Z / 100.0f); v3f speed((f32)ss.X / 100.0f, (f32)ss.Y / 100.0f, (f32)ss.Z / 100.0f);
@ -791,9 +795,6 @@ void Server::handleCommand_ChatMessage(NetworkPacket* pkt)
void Server::handleCommand_Damage(NetworkPacket* pkt) void Server::handleCommand_Damage(NetworkPacket* pkt)
{ {
u16 damage;
*pkt >> damage;
session_t peer_id = pkt->getPeerId(); session_t peer_id = pkt->getPeerId();
RemotePlayer *player = m_env->getPlayer(peer_id); RemotePlayer *player = m_env->getPlayer(peer_id);
@ -806,6 +807,17 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
return; return;
} }
u16 damage;
// Minetest 0.4 uses 8-bit integers for damage.
if (player->protocol_version >= 37) {
*pkt >> damage;
} else {
u8 raw_damage;
*pkt >> raw_damage;
damage = raw_damage;
}
PlayerSAO *playersao = player->getPlayerSAO(); PlayerSAO *playersao = player->getPlayerSAO();
if (playersao == NULL) { if (playersao == NULL) {
errorstream << errorstream <<
@ -1670,7 +1682,7 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt)
if (client->chosen_mech != AUTH_MECHANISM_SRP && if (client->chosen_mech != AUTH_MECHANISM_SRP &&
client->chosen_mech != AUTH_MECHANISM_LEGACY_PASSWORD) { client->chosen_mech != AUTH_MECHANISM_LEGACY_PASSWORD) {
actionstream << "Server: got SRP _M packet, while auth" actionstream << "Server: got SRP _M packet, while auth"
<< "is going on with mech " << client->chosen_mech << " from " << "is going on with mech " << client->chosen_mech << " from "
<< addr_s << " (wantSudo=" << wantSudo << "). Denying." << std::endl; << addr_s << " (wantSudo=" << wantSudo << "). Denying." << std::endl;
if (wantSudo) { if (wantSudo) {
DenySudoAccess(peer_id); DenySudoAccess(peer_id);

View File

@ -74,7 +74,13 @@ void NodeBox::reset()
void NodeBox::serialize(std::ostream &os, u16 protocol_version) const void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
{ {
// Protocol >= 36 // Protocol >= 36
const u8 version = 6; u8 version;
if (protocol_version >= 36)
version = 6;
else if (protocol_version >= 27)
version = 3;
else
version = 2;
writeU8(os, version); writeU8(os, version);
switch (type) { switch (type) {
@ -84,28 +90,38 @@ void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
writeU16(os, fixed.size()); writeU16(os, fixed.size());
for (const aabb3f &nodebox : fixed) { for (const aabb3f &nodebox : fixed) {
writeV3F32(os, nodebox.MinEdge); writeV3F(os, nodebox.MinEdge, protocol_version);
writeV3F32(os, nodebox.MaxEdge); writeV3F(os, nodebox.MaxEdge, protocol_version);
} }
break; break;
case NODEBOX_WALLMOUNTED: case NODEBOX_WALLMOUNTED:
writeU8(os, type); writeU8(os, type);
writeV3F32(os, wall_top.MinEdge); writeV3F(os, wall_top.MinEdge, protocol_version);
writeV3F32(os, wall_top.MaxEdge); writeV3F(os, wall_top.MaxEdge, protocol_version);
writeV3F32(os, wall_bottom.MinEdge); writeV3F(os, wall_bottom.MinEdge, protocol_version);
writeV3F32(os, wall_bottom.MaxEdge); writeV3F(os, wall_bottom.MaxEdge, protocol_version);
writeV3F32(os, wall_side.MinEdge); writeV3F(os, wall_side.MinEdge, protocol_version);
writeV3F32(os, wall_side.MaxEdge); writeV3F(os, wall_side.MaxEdge, protocol_version);
break; break;
case NODEBOX_CONNECTED: case NODEBOX_CONNECTED:
if (version <= 2) {
// send old clients nodes that can't be walked through
// to prevent abuse
writeU8(os, NODEBOX_FIXED);
writeU16(os, 1);
writeV3F1000(os, v3f(-BS/2, -BS/2, -BS/2));
writeV3F1000(os, v3f(BS/2, BS/2, BS/2));
break;
}
writeU8(os, type); writeU8(os, type);
#define WRITEBOX(box) \ #define WRITEBOX(box) \
writeU16(os, (box).size()); \ writeU16(os, (box).size()); \
for (const aabb3f &i: (box)) { \ for (const aabb3f &i: (box)) { \
writeV3F32(os, i.MinEdge); \ writeV3F(os, i.MinEdge, protocol_version); \
writeV3F32(os, i.MaxEdge); \ writeV3F(os, i.MaxEdge, protocol_version); \
}; };
WRITEBOX(fixed); WRITEBOX(fixed);
@ -115,14 +131,17 @@ void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
WRITEBOX(connect_left); WRITEBOX(connect_left);
WRITEBOX(connect_back); WRITEBOX(connect_back);
WRITEBOX(connect_right); WRITEBOX(connect_right);
WRITEBOX(disconnected_top);
WRITEBOX(disconnected_bottom); if (version > 5) {
WRITEBOX(disconnected_front); WRITEBOX(disconnected_top);
WRITEBOX(disconnected_left); WRITEBOX(disconnected_bottom);
WRITEBOX(disconnected_back); WRITEBOX(disconnected_front);
WRITEBOX(disconnected_right); WRITEBOX(disconnected_left);
WRITEBOX(disconnected); WRITEBOX(disconnected_back);
WRITEBOX(disconnected_sides); WRITEBOX(disconnected_right);
WRITEBOX(disconnected);
WRITEBOX(disconnected_sides);
}
break; break;
default: default:
writeU8(os, type); writeU8(os, type);
@ -207,12 +226,41 @@ void NodeBox::deSerialize(std::istream &is)
void TileDef::serialize(std::ostream &os, u16 protocol_version) const void TileDef::serialize(std::ostream &os, u16 protocol_version) const
{ {
// protocol_version >= 36 u8 version;
u8 version = 6; if (protocol_version >= 37)
version = 6;
else if (protocol_version >= 30)
version = 4;
else if (protocol_version >= 29)
version = 3;
else if (protocol_version >= 26)
version = 2;
else
version = 1;
writeU8(os, version); writeU8(os, version);
os << serializeString(name); os << serializeString(name);
animation.serialize(os, version); animation.serialize(os, version);
// Compatibility with Minetest 0.4.
if (version < 6) {
writeU8(os, backface_culling);
if (version < 2)
return;
writeU8(os, tileable_horizontal);
writeU8(os, tileable_vertical);
if (version < 3)
return;
writeU8(os, has_color);
if (has_color) {
writeU8(os, color.getRed());
writeU8(os, color.getGreen());
writeU8(os, color.getBlue());
}
return;
}
bool has_scale = scale > 0; bool has_scale = scale > 0;
u16 flags = 0; u16 flags = 0;
if (backface_culling) if (backface_culling)
@ -424,7 +472,14 @@ void ContentFeatures::reset()
void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
{ {
const u8 version = CONTENTFEATURES_VERSION; if (protocol_version < 31) {
serializeOld(os, protocol_version);
return;
}
u8 version = CONTENTFEATURES_VERSION;
if (protocol_version < 37)
version = 10;
writeU8(os, version); writeU8(os, version);
// general // general
@ -440,7 +495,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
// visual // visual
writeU8(os, drawtype); writeU8(os, drawtype);
os << serializeString(mesh); os << serializeString(mesh);
writeF32(os, visual_scale); writeF(os, visual_scale, protocol_version);
writeU8(os, 6); writeU8(os, 6);
for (const TileDef &td : tiledef) for (const TileDef &td : tiledef)
td.serialize(os, protocol_version); td.serialize(os, protocol_version);
@ -1125,6 +1180,105 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
} }
#endif #endif
//// Serialization of old ContentFeatures formats
void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
{
u8 compatible_param_type_2 = param_type_2;
if ((protocol_version < 28)
&& (compatible_param_type_2 == CPT2_MESHOPTIONS))
compatible_param_type_2 = CPT2_NONE;
else if (protocol_version < 30) {
if (compatible_param_type_2 == CPT2_COLOR)
compatible_param_type_2 = CPT2_NONE;
else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
compatible_param_type_2 = CPT2_FACEDIR;
else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
compatible_param_type_2 = CPT2_WALLMOUNTED;
}
float compatible_visual_scale = visual_scale;
if (protocol_version < 30 && drawtype == NDT_PLANTLIKE)
compatible_visual_scale = sqrt(visual_scale);
TileDef compatible_tiles[6];
for (u8 i = 0; i < 6; i++) {
compatible_tiles[i] = tiledef[i];
if (tiledef_overlay[i].name != "") {
std::stringstream s;
s << "(" << tiledef[i].name << ")^(" << tiledef_overlay[i].name
<< ")";
compatible_tiles[i].name = s.str();
}
}
// Protocol >= 24
if (protocol_version < 31) {
const u8 version = protocol_version < 27 ? 7 : 8;
writeU8(os, version);
os << serializeString(name);
writeU16(os, groups.size());
for (ItemGroupList::const_iterator i = groups.begin();
i != groups.end(); ++i) {
os << serializeString(i->first);
writeS16(os, i->second);
}
writeU8(os, drawtype);
writeF1000(os, compatible_visual_scale);
writeU8(os, 6);
for (u32 i = 0; i < 6; i++)
compatible_tiles[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
tiledef_special[i].serialize(os, protocol_version);
writeU8(os, alpha);
writeU8(os, post_effect_color.getAlpha());
writeU8(os, post_effect_color.getRed());
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
writeU8(os, compatible_param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
writeU8(os, walkable);
writeU8(os, pointable);
writeU8(os, diggable);
writeU8(os, climbable);
writeU8(os, buildable_to);
os << serializeString(""); // legacy: used to be metadata_name
writeU8(os, liquid_type);
os << serializeString(liquid_alternative_flowing);
os << serializeString(liquid_alternative_source);
writeU8(os, liquid_viscosity);
writeU8(os, liquid_renewable);
writeU8(os, light_source);
writeU32(os, damage_per_second);
node_box.serialize(os, protocol_version);
selection_box.serialize(os, protocol_version);
writeU8(os, legacy_facedir_simple);
writeU8(os, legacy_wallmounted);
sound_footstep.serialize(os, version);
sound_dig.serialize(os, version);
sound_dug.serialize(os, version);
writeU8(os, rightclickable);
writeU8(os, drowning);
writeU8(os, leveled);
writeU8(os, liquid_range);
writeU8(os, waving);
os << serializeString(mesh);
collision_box.serialize(os, protocol_version);
writeU8(os, floodable);
writeU16(os, connects_to_ids.size());
for (u16 connects_to_id : connects_to_ids)
writeU16(os, connects_to_id);
writeU8(os, connect_sides);
} else {
throw SerializationError("ContentFeatures::serialize(): "
"Unsupported version requested");
}
}
/* /*
NodeDefManager NodeDefManager
*/ */

View File

@ -414,6 +414,7 @@ struct ContentFeatures
void serialize(std::ostream &os, u16 protocol_version) const; void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is); void deSerialize(std::istream &is);
void deSerializeOld(std::istream &is, int version); void deSerializeOld(std::istream &is, int version);
void serializeOld(std::ostream &os, u16 protocol_version) const;
/*! /*!
* Since vertex alpha is no longer supported, this method * Since vertex alpha is no longer supported, this method
* adds opacity directly to the texture pixels. * adds opacity directly to the texture pixels.

View File

@ -40,7 +40,8 @@ NodeMetadata::~NodeMetadata()
delete m_inventory; delete m_inventory;
} }
void NodeMetadata::serialize(std::ostream &os, u8 version, bool disk) const void NodeMetadata::serialize(std::ostream &os, u8 version, bool disk,
std::string formspec_prepend) const
{ {
int num_vars = disk ? m_stringvars.size() : countNonPrivate(); int num_vars = disk ? m_stringvars.size() : countNonPrivate();
writeU32(os, num_vars); writeU32(os, num_vars);
@ -50,7 +51,11 @@ void NodeMetadata::serialize(std::ostream &os, u8 version, bool disk) const
continue; continue;
os << serializeString(sv.first); os << serializeString(sv.first);
os << serializeLongString(sv.second); if (!formspec_prepend.empty() && sv.first == "formspec" &&
sv.second.find("no_prepend[]") == std::string::npos)
os << serializeLongString(sv.second + formspec_prepend);
else
os << serializeLongString(sv.second);
if (version >= 2) if (version >= 2)
writeU8(os, (priv) ? 1 : 0); writeU8(os, (priv) ? 1 : 0);
} }
@ -113,7 +118,7 @@ int NodeMetadata::countNonPrivate() const
*/ */
void NodeMetadataList::serialize(std::ostream &os, u8 blockver, bool disk, void NodeMetadataList::serialize(std::ostream &os, u8 blockver, bool disk,
bool absolute_pos) const bool absolute_pos, std::string formspec_prepend) const
{ {
/* /*
Version 0 is a placeholder for "nothing to see here; go away." Version 0 is a placeholder for "nothing to see here; go away."
@ -146,7 +151,7 @@ void NodeMetadataList::serialize(std::ostream &os, u8 blockver, bool disk,
u16 p16 = (p.Z * MAP_BLOCKSIZE + p.Y) * MAP_BLOCKSIZE + p.X; u16 p16 = (p.Z * MAP_BLOCKSIZE + p.Y) * MAP_BLOCKSIZE + p.X;
writeU16(os, p16); writeU16(os, p16);
} }
data->serialize(os, version, disk); data->serialize(os, version, disk, formspec_prepend);
} }
} }

View File

@ -40,7 +40,8 @@ public:
NodeMetadata(IItemDefManager *item_def_mgr); NodeMetadata(IItemDefManager *item_def_mgr);
~NodeMetadata(); ~NodeMetadata();
void serialize(std::ostream &os, u8 version, bool disk=true) const; void serialize(std::ostream &os, u8 version, bool disk=true,
std::string formspec_prepend="") const;
void deSerialize(std::istream &is, u8 version); void deSerialize(std::istream &is, u8 version);
void clear(); void clear();
@ -82,7 +83,7 @@ public:
~NodeMetadataList(); ~NodeMetadataList();
void serialize(std::ostream &os, u8 blockver, bool disk = true, void serialize(std::ostream &os, u8 blockver, bool disk = true,
bool absolute_pos = false) const; bool absolute_pos = false, std::string formspec_prepend = "") const;
void deSerialize(std::istream &is, IItemDefManager *item_def_mgr, void deSerialize(std::istream &is, IItemDefManager *item_def_mgr,
bool absolute_pos = false); bool absolute_pos = false);

View File

@ -73,28 +73,62 @@ std::string ObjectProperties::dump()
return os.str(); return os.str();
} }
void ObjectProperties::serialize(std::ostream &os) const void ObjectProperties::serialize(std::ostream &os, u16 protocol_version) const
{ {
writeU8(os, 4); // PROTOCOL_VERSION >= 37 if (protocol_version > 36)
writeU8(os, 4); // PROTOCOL_VERSION >= 37
else
writeU8(os, 1);
writeU16(os, hp_max); writeU16(os, hp_max);
writeU8(os, physical); writeU8(os, physical);
writeF32(os, 0.f); // Removed property (weight) writeF(os, 0.f, protocol_version); // Removed property (weight)
writeV3F32(os, collisionbox.MinEdge); if (protocol_version > 36) {
writeV3F32(os, collisionbox.MaxEdge); writeV3F32(os, collisionbox.MinEdge);
writeV3F32(os, selectionbox.MinEdge); writeV3F32(os, collisionbox.MaxEdge);
writeV3F32(os, selectionbox.MaxEdge); writeV3F32(os, selectionbox.MinEdge);
writeU8(os, pointable); writeV3F32(os, selectionbox.MaxEdge);
os << serializeString(visual); writeU8(os, pointable);
writeV3F32(os, visual_size); } else if (pointable) {
writeU16(os, textures.size()); writeV3F1000(os, selectionbox.MinEdge);
for (const std::string &texture : textures) { writeV3F1000(os, selectionbox.MaxEdge);
os << serializeString(texture); } else {
// A hack to emulate unpointable objects
for (u8 i = 0; i < 6; i++)
writeF1000(os, 0);
} }
// The "wielditem" type isn't exactly the same as "item", however this
// is the most similar compatible option
if (visual == "item" && protocol_version < 37)
os << serializeString("wielditem");
else
os << serializeString(visual);
if (protocol_version > 36) {
writeV3F32(os, visual_size);
} else {
writeF1000(os, visual_size.X);
writeF1000(os, visual_size.Y);
}
// MT 0.4.15 and below don't have the wield_item property and expect
// wield_item to be in textures[0].
if (protocol_version < 37 && (visual == "item" || visual == "wielditem") &&
!wield_item.empty()) {
writeU16(os, 1);
os << serializeString(wield_item);
} else {
writeU16(os, textures.size());
for (const std::string &texture : textures) {
os << serializeString(texture);
}
}
writeV2S16(os, spritediv); writeV2S16(os, spritediv);
writeV2S16(os, initial_sprite_basepos); writeV2S16(os, initial_sprite_basepos);
writeU8(os, is_visible); writeU8(os, is_visible);
writeU8(os, makes_footstep_sound); writeU8(os, makes_footstep_sound);
writeF32(os, automatic_rotate); writeF(os, automatic_rotate, protocol_version);
// Added in protocol version 14 // Added in protocol version 14
os << serializeString(mesh); os << serializeString(mesh);
writeU16(os, colors.size()); writeU16(os, colors.size());
@ -102,16 +136,21 @@ void ObjectProperties::serialize(std::ostream &os) const
writeARGB8(os, color); writeARGB8(os, color);
} }
writeU8(os, collideWithObjects); writeU8(os, collideWithObjects);
writeF32(os, stepheight); writeF(os, stepheight, protocol_version);
writeU8(os, automatic_face_movement_dir); writeU8(os, automatic_face_movement_dir);
writeF32(os, automatic_face_movement_dir_offset); writeF(os, automatic_face_movement_dir_offset, protocol_version);
writeU8(os, backface_culling); writeU8(os, backface_culling);
os << serializeString(nametag); os << serializeString(nametag);
writeARGB8(os, nametag_color); writeARGB8(os, nametag_color);
writeF32(os, automatic_face_movement_max_rotation_per_sec); writeF(os, automatic_face_movement_max_rotation_per_sec, protocol_version);
os << serializeString(infotext); os << serializeString(infotext);
os << serializeString(wield_item); os << serializeString(wield_item);
writeS8(os, glow); writeS8(os, glow);
// Everything after this can use writeF32().
if (protocol_version < 37)
return;
writeU16(os, breath_max); writeU16(os, breath_max);
writeF32(os, eye_height); writeF32(os, eye_height);
writeF32(os, zoom_fov); writeF32(os, zoom_fov);

View File

@ -65,6 +65,6 @@ struct ObjectProperties
ObjectProperties(); ObjectProperties();
std::string dump(); std::string dump();
void serialize(std::ostream &os) const; void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is); void deSerialize(std::istream &is);
}; };

View File

@ -771,7 +771,11 @@ void Server::AsyncRunStep(bool initial_step)
// u16 id // u16 id
// std::string data // std::string data
buffer.append(idbuf, sizeof(idbuf)); buffer.append(idbuf, sizeof(idbuf));
buffer.append(serializeString(aom.datastring)); if (client->net_proto_version >= 37 ||
aom.legacystring.empty())
buffer.append(serializeString(aom.datastring));
else
buffer.append(serializeString(aom.legacystring));
} }
} }
/* /*
@ -1147,6 +1151,9 @@ void Server::ProcessData(NetworkPacket *pkt)
return; return;
} }
RemoteClient *client = getClient(peer_id);
if (client)
pkt->setProtocolVersion(client->net_proto_version);
handleCommand(pkt); handleCommand(pkt);
} catch (SendFailedException &e) { } catch (SendFailedException &e) {
errorstream << "Server::ProcessData(): SendFailedException: " errorstream << "Server::ProcessData(): SendFailedException: "
@ -1154,7 +1161,7 @@ void Server::ProcessData(NetworkPacket *pkt)
<< std::endl; << std::endl;
} catch (PacketError &e) { } catch (PacketError &e) {
actionstream << "Server::ProcessData(): PacketError: " actionstream << "Server::ProcessData(): PacketError: "
<< "what=" << e.what() << "what=" << e.what() << ", command=" << pkt->getCommand() // TODO: REMOVE COMMAND=
<< std::endl; << std::endl;
} }
} }
@ -1296,11 +1303,11 @@ void Server::Send(session_t peer_id, NetworkPacket *pkt)
clientCommandFactoryTable[pkt->getCommand()].reliable); clientCommandFactoryTable[pkt->getCommand()].reliable);
} }
void Server::SendMovement(session_t peer_id) void Server::SendMovement(session_t peer_id, u16 protocol_version)
{ {
std::ostringstream os(std::ios_base::binary); std::ostringstream os(std::ios_base::binary);
NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id); NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id, protocol_version);
pkt << g_settings->getFloat("movement_acceleration_default"); pkt << g_settings->getFloat("movement_acceleration_default");
pkt << g_settings->getFloat("movement_acceleration_air"); pkt << g_settings->getFloat("movement_acceleration_air");
@ -1335,7 +1342,13 @@ void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason
void Server::SendHP(session_t peer_id, u16 hp) void Server::SendHP(session_t peer_id, u16 hp)
{ {
NetworkPacket pkt(TOCLIENT_HP, 1, peer_id); NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
pkt << hp; // Minetest 0.4 uses 8-bit integers for HPP.
if (m_clients.getProtocolVersion(peer_id) >= 37) {
pkt << hp;
} else {
u8 raw_hp = hp & 0xFF;
pkt << raw_hp;
}
Send(&pkt); Send(&pkt);
} }
@ -1454,6 +1467,9 @@ void Server::SendInventory(PlayerSAO *sao, bool incremental)
void Server::SendChatMessage(session_t peer_id, const ChatMessage &message) void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
{ {
NetworkPacket legacypkt(TOCLIENT_CHAT_MESSAGE_OLD, 0, peer_id);
legacypkt << message.message;
NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id); NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
u8 version = 1; u8 version = 1;
u8 type = message.type; u8 type = message.type;
@ -1464,9 +1480,12 @@ void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
if (!player) if (!player)
return; return;
Send(&pkt); if (player->protocol_version < 35)
Send(&legacypkt);
else
Send(&pkt);
} else { } else {
m_clients.sendToAll(&pkt); m_clients.sendToAllCompat(&pkt, &legacypkt, 35);
} }
} }
@ -1484,7 +1503,12 @@ void Server::SendShowFormspecMessage(session_t peer_id, const std::string &forms
pkt.putLongString(""); pkt.putLongString("");
} else { } else {
m_formspec_state_data[peer_id] = formname; m_formspec_state_data[peer_id] = formname;
pkt.putLongString(formspec); RemotePlayer *player = m_env->getPlayer(peer_id);
if (player && player->protocol_version < 37 &&
formspec.find("no_prepend[]") == std::string::npos)
pkt.putLongString(formspec + player->formspec_prepend);
else
pkt.putLongString(formspec);
} }
pkt << formname; pkt << formname;
@ -1522,7 +1546,7 @@ void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
} }
assert(protocol_version != 0); assert(protocol_version != 0);
NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id); NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id, protocol_version);
{ {
// NetworkPacket and iostreams are incompatible... // NetworkPacket and iostreams are incompatible...
@ -1569,7 +1593,7 @@ void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
} }
assert(protocol_version != 0); assert(protocol_version != 0);
NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id); NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id, protocol_version);
pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
<< p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
@ -1604,7 +1628,7 @@ void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form) void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
{ {
NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id); NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id, m_clients.getProtocolVersion(peer_id));
pkt << id << (u8) form->type << form->pos << form->name << form->scale pkt << id << (u8) form->type << form->pos << form->name << form->scale
<< form->text << form->number << form->item << form->dir << form->text << form->number << form->item << form->dir
@ -1623,7 +1647,7 @@ void Server::SendHUDRemove(session_t peer_id, u32 id)
void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value) void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
{ {
NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id); NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id, m_clients.getProtocolVersion(peer_id));
pkt << id << (u8) stat; pkt << id << (u8) stat;
switch (stat) { switch (stat) {
@ -1735,7 +1759,8 @@ void Server::SendSetStars(session_t peer_id, const StarParams &params)
void Server::SendCloudParams(session_t peer_id, const CloudParams &params) void Server::SendCloudParams(session_t peer_id, const CloudParams &params)
{ {
NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id); NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id,
m_clients.getProtocolVersion(peer_id));
pkt << params.density << params.color_bright << params.color_ambient pkt << params.density << params.color_bright << params.color_ambient
<< params.height << params.thickness << params.speed; << params.height << params.thickness << params.speed;
Send(&pkt); Send(&pkt);
@ -1754,15 +1779,20 @@ void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed) void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
{ {
NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id); if (peer_id != PEER_ID_INEXISTENT) {
pkt << time << time_speed; NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id,
m_clients.getProtocolVersion(peer_id));
pkt << time << time_speed;
if (peer_id == PEER_ID_INEXISTENT) {
m_clients.sendToAll(&pkt);
}
else {
Send(&pkt); Send(&pkt);
return;
} }
NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id, 37);
NetworkPacket legacypkt(TOCLIENT_TIME_OF_DAY, 0, peer_id, 32);
pkt << time << time_speed;
legacypkt << time << time_speed;
m_clients.sendToAllCompat(&pkt, &legacypkt, 37);
} }
void Server::SendPlayerHP(session_t peer_id) void Server::SendPlayerHP(session_t peer_id)
@ -1792,7 +1822,7 @@ void Server::SendMovePlayer(session_t peer_id)
PlayerSAO *sao = player->getPlayerSAO(); PlayerSAO *sao = player->getPlayerSAO();
assert(sao); assert(sao);
NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id); NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id, player->protocol_version);
pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y; pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
{ {
@ -1821,7 +1851,7 @@ void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames
f32 animation_speed) f32 animation_speed)
{ {
NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0, NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
peer_id); peer_id, m_clients.getProtocolVersion(peer_id));
pkt << animation_frames[0] << animation_frames[1] << animation_frames[2] pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
<< animation_frames[3] << animation_speed; << animation_frames[3] << animation_speed;
@ -1831,7 +1861,7 @@ void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames
void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third) void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
{ {
NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id); NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id, m_clients.getProtocolVersion(peer_id));
pkt << first << third; pkt << first << third;
Send(&pkt); Send(&pkt);
} }
@ -1864,7 +1894,12 @@ void Server::SendPlayerInventoryFormspec(session_t peer_id)
return; return;
NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id); NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
pkt.putLongString(player->inventory_formspec); if (player->protocol_version < 37 && player->inventory_formspec.find(
"no_prepend[]") == std::string::npos)
pkt.putLongString(player->inventory_formspec +
player->formspec_prepend);
else
pkt.putLongString(player->inventory_formspec);
Send(&pkt); Send(&pkt);
} }
@ -1875,6 +1910,10 @@ void Server::SendPlayerFormspecPrepend(session_t peer_id)
assert(player); assert(player);
if (player->getPeerId() == PEER_ID_INEXISTENT) if (player->getPeerId() == PEER_ID_INEXISTENT)
return; return;
if (player->protocol_version < 37) {
SendPlayerInventoryFormspec(peer_id);
return;
}
NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id); NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
pkt << player->formspec_prepend; pkt << player->formspec_prepend;
@ -1995,6 +2034,10 @@ void Server::SendActiveObjectMessages(session_t peer_id, const std::string &data
void Server::SendCSMRestrictionFlags(session_t peer_id) void Server::SendCSMRestrictionFlags(session_t peer_id)
{ {
const u16 protocol_version = m_clients.getProtocolVersion(peer_id);
if (protocol_version < 35 && protocol_version != 0)
return;
NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS, NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id); sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
pkt << m_csm_restriction_flags << m_csm_restriction_noderange; pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
@ -2086,17 +2129,29 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
float gain = params.gain * spec.gain; float gain = params.gain * spec.gain;
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0); NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
NetworkPacket legacypkt(TOCLIENT_PLAY_SOUND, 0, PEER_ID_INEXISTENT, 32);
pkt << id << spec.name << gain pkt << id << spec.name << gain
<< (u8) params.type << pos << params.object << (u8) params.type << pos << params.object
<< params.loop << params.fade << params.pitch << params.loop << params.fade << params.pitch
<< ephemeral; << ephemeral;
legacypkt << id << spec.name << gain
<< (u8) params.type << pos << params.object
<< params.loop << params.fade;
bool as_reliable = !ephemeral; bool as_reliable = !ephemeral;
bool play_sound = gain > 0;
for (const u16 dst_client : dst_clients) { for (const u16 dst_client : dst_clients) {
const u16 protocol_version = m_clients.getProtocolVersion(dst_client);
if (!play_sound && protocol_version < 32)
continue;
if (psound) if (psound)
psound->clients.insert(dst_client); psound->clients.insert(dst_client);
m_clients.send(dst_client, 0, &pkt, as_reliable);
if (protocol_version >= 37)
m_clients.send(dst_client, 0, &pkt, as_reliable);
else
m_clients.send(dst_client, 0, &legacypkt, as_reliable);
} }
return id; return id;
} }
@ -2257,6 +2312,13 @@ void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far
if (!client) if (!client)
continue; continue;
if (client->net_proto_version < 37) {
for (const v3s16 &pos : meta_updates) {
client->SetBlockNotSent(getNodeBlockPos(pos));
}
continue;
}
ServerActiveObject *player = m_env->getActiveObject(i); ServerActiveObject *player = m_env->getActiveObject(i);
v3f player_pos = player ? player->getBasePosition() : v3f(); v3f player_pos = player ? player->getBasePosition() : v3f();
@ -2303,7 +2365,12 @@ void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
*/ */
std::ostringstream os(std::ios_base::binary); std::ostringstream os(std::ios_base::binary);
block->serialize(os, ver, false);
RemotePlayer *player = m_env->getPlayer(peer_id);
if (player && player->protocol_version < 37)
block->serialize(os, ver, false, player->formspec_prepend);
else
block->serialize(os, ver, false);
block->serializeNetworkSpecific(os); block->serializeNetworkSpecific(os);
std::string s = os.str(); std::string s = os.str();
@ -2483,7 +2550,10 @@ void Server::fillMediaCache()
std::vector<std::string> paths; std::vector<std::string> paths;
m_modmgr->getModsMediaPaths(paths); m_modmgr->getModsMediaPaths(paths);
fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures"); fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server"); fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" +
DIR_DELIM + "server");
fs::GetRecursiveDirs(paths, porting::path_share + DIR_DELIM + "builtin" +
DIR_DELIM + "game" + DIR_DELIM + "models");
// Collect media file information from paths into cache // Collect media file information from paths into cache
for (const std::string &mediapath : paths) { for (const std::string &mediapath : paths) {
@ -2645,7 +2715,9 @@ void Server::sendRequestedMedia(session_t peer_id,
void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id) void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
{ {
NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id); NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
NetworkPacket legacy_pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
pkt << name; pkt << name;
legacy_pkt << name;
if (!inventory) { if (!inventory) {
pkt << false; // Remove inventory pkt << false; // Remove inventory
@ -2660,12 +2732,25 @@ void Server::sendDetachedInventory(Inventory *inventory, const std::string &name
const std::string &os_str = os.str(); const std::string &os_str = os.str();
pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
pkt.putRawString(os_str); pkt.putRawString(os_str);
legacy_pkt.putRawString(os_str);
} }
if (peer_id == PEER_ID_INEXISTENT) if (peer_id == PEER_ID_INEXISTENT) {
m_clients.sendToAll(&pkt); m_clients.newSendToAll(&pkt);
else if (inventory)
Send(&pkt); m_clients.oldSendToAll(&legacy_pkt);
} else {
RemoteClient *client = getClientNoEx(peer_id, CS_Created);
if (!client) {
warningstream << "Could not get client in sendDetachedInventory!"
<< std::endl;
}
if (!client || client->net_proto_version >= 37)
Send(&pkt);
else if (inventory)
Send(&legacy_pkt);
}
} }
void Server::sendDetachedInventories(session_t peer_id, bool incremental) void Server::sendDetachedInventories(session_t peer_id, bool incremental)
@ -2774,7 +2859,7 @@ void Server::acceptAuth(session_t peer_id, bool forSudoMode)
if (!forSudoMode) { if (!forSudoMode) {
RemoteClient* client = getClient(peer_id, CS_Invalid); RemoteClient* client = getClient(peer_id, CS_Invalid);
NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id); NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id, client->net_proto_version);
// Right now, the auth mechs don't change between login and sudo mode. // Right now, the auth mechs don't change between login and sudo mode.
u32 sudo_auth_mechs = client->allowed_auth_mechs; u32 sudo_auth_mechs = client->allowed_auth_mechs;

View File

@ -374,7 +374,7 @@ private:
void init(); void init();
void SendMovement(session_t peer_id); void SendMovement(session_t peer_id, u16 protocol_version);
void SendHP(session_t peer_id, u16 hp); void SendHP(session_t peer_id, u16 hp);
void SendBreath(session_t peer_id, u16 breath); void SendBreath(session_t peer_id, u16 breath);
void SendAccessDenied(session_t peer_id, AccessDeniedCode reason, void SendAccessDenied(session_t peer_id, AccessDeniedCode reason,

View File

@ -117,9 +117,10 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
if(!m_properties_sent) if(!m_properties_sent)
{ {
m_properties_sent = true; m_properties_sent = true;
std::string str = getPropertyPacket(); std::string str = getPropertyPacket(37);
std::string legacy_str = getPropertyPacket(32);
// create message and add to list // create message and add to list
m_messages_out.emplace(getId(), true, str); m_messages_out.emplace(getId(), true, str, legacy_str);
} }
// If attached, check that our parent is still there. If it isn't, detach. // If attached, check that our parent is still there. If it isn't, detach.
@ -228,19 +229,26 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
os << serializeString(""); // name os << serializeString(""); // name
writeU8(os, 0); // is_player writeU8(os, 0); // is_player
writeU16(os, getId()); //id writeU16(os, getId()); //id
writeV3F32(os, m_base_position); writeV3F(os, m_base_position, protocol_version);
writeV3F32(os, m_rotation); if (protocol_version >= 37)
writeV3F32(os, m_rotation);
else
writeF1000(os, m_rotation.Y);
writeU16(os, m_hp); writeU16(os, m_hp);
std::ostringstream msg_os(std::ios::binary); std::ostringstream msg_os(std::ios::binary);
msg_os << serializeLongString(getPropertyPacket()); // message 1 msg_os << serializeLongString(getPropertyPacket(
protocol_version)); // message 1
msg_os << serializeLongString(generateUpdateArmorGroupsCommand()); // 2 msg_os << serializeLongString(generateUpdateArmorGroupsCommand()); // 2
msg_os << serializeLongString(generateUpdateAnimationCommand()); // 3 msg_os << serializeLongString(generateUpdateAnimationCommand(
protocol_version)); // 3
for (const auto &bone_pos : m_bone_position) { for (const auto &bone_pos : m_bone_position) {
msg_os << serializeLongString(generateUpdateBonePositionCommand( msg_os << serializeLongString(generateUpdateBonePositionCommand(
bone_pos.first, bone_pos.second.X, bone_pos.second.Y)); // m_bone_position.size bone_pos.first, bone_pos.second.X, bone_pos.second.Y,
protocol_version)); // m_bone_position.size
} }
msg_os << serializeLongString(generateUpdateAttachmentCommand()); // 4 msg_os << serializeLongString(generateUpdateAttachmentCommand(
protocol_version)); // 4
int message_count = 4 + m_bone_position.size(); int message_count = 4 + m_bone_position.size();
@ -472,9 +480,9 @@ std::string LuaEntitySAO::getName()
return m_init_name; return m_init_name;
} }
std::string LuaEntitySAO::getPropertyPacket() std::string LuaEntitySAO::getPropertyPacket(const u16 protocol_version)
{ {
return generateSetPropertiesCommand(m_prop); return generateSetPropertiesCommand(m_prop, protocol_version);
} }
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
@ -500,10 +508,23 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
m_rotation, m_rotation,
do_interpolate, do_interpolate,
is_movement_end, is_movement_end,
update_interval update_interval,
37
); );
std::string legacy_str = generateUpdatePositionCommand(
m_base_position,
m_velocity,
m_acceleration,
m_rotation,
do_interpolate,
is_movement_end,
update_interval,
32
);
// create message and add to list // create message and add to list
m_messages_out.emplace(getId(), false, str); m_messages_out.emplace(getId(), false, str, legacy_str);
} }
bool LuaEntitySAO::getCollisionBox(aabb3f *toset) const bool LuaEntitySAO::getCollisionBox(aabb3f *toset) const

View File

@ -71,7 +71,7 @@ public:
bool collideWithObjects() const; bool collideWithObjects() const;
private: private:
std::string getPropertyPacket(); std::string getPropertyPacket(const u16 protocol_version);
void sendPosition(bool do_interpolate, bool is_movement_end); void sendPosition(bool do_interpolate, bool is_movement_end);
std::string generateSetTextureModCommand() const; std::string generateSetTextureModCommand() const;
static std::string generateSetSpriteCommand(v2s16 p, u16 num_frames, static std::string generateSetSpriteCommand(v2s16 p, u16 num_frames,

View File

@ -112,20 +112,37 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
os << serializeString(m_player->getName()); // name os << serializeString(m_player->getName()); // name
writeU8(os, 1); // is_player writeU8(os, 1); // is_player
writeS16(os, getId()); // id writeS16(os, getId()); // id
writeV3F32(os, m_base_position); if (protocol_version >= 37) {
writeV3F32(os, m_rotation); writeV3F32(os, m_base_position);
writeU16(os, getHP()); writeV3F32(os, m_rotation);
writeU16(os, getHP());
} else {
writeV3F1000(os, m_base_position + v3f(0, BS, 0));
writeF1000(os, m_rotation.Y);
// HP is sent as a signed integer
const u16 hp = getHP();
if (hp > S16_MAX)
writeS16(os, S16_MAX);
else
writeS16(os, static_cast<s16>(hp));
}
std::ostringstream msg_os(std::ios::binary); std::ostringstream msg_os(std::ios::binary);
msg_os << serializeLongString(getPropertyPacket()); // message 1 msg_os << serializeLongString(getPropertyPacket(
protocol_version)); // message 1
msg_os << serializeLongString(generateUpdateArmorGroupsCommand()); // 2 msg_os << serializeLongString(generateUpdateArmorGroupsCommand()); // 2
msg_os << serializeLongString(generateUpdateAnimationCommand()); // 3 msg_os << serializeLongString(generateUpdateAnimationCommand(
protocol_version)); // 3
for (const auto &bone_pos : m_bone_position) { for (const auto &bone_pos : m_bone_position) {
msg_os << serializeLongString(generateUpdateBonePositionCommand( msg_os << serializeLongString(generateUpdateBonePositionCommand(
bone_pos.first, bone_pos.second.X, bone_pos.second.Y)); // m_bone_position.size bone_pos.first, bone_pos.second.X, bone_pos.second.Y,
protocol_version)); // m_bone_position.size
} }
msg_os << serializeLongString(generateUpdateAttachmentCommand()); // 4 msg_os << serializeLongString(generateUpdateAttachmentCommand(
msg_os << serializeLongString(generateUpdatePhysicsOverrideCommand()); // 5 protocol_version)); // 4
msg_os << serializeLongString(generateUpdatePhysicsOverrideCommand(
protocol_version)); // 5
int message_count = 5 + m_bone_position.size(); int message_count = 5 + m_bone_position.size();
@ -221,9 +238,10 @@ void PlayerSAO::step(float dtime, bool send_recommended)
if (!m_properties_sent) { if (!m_properties_sent) {
m_properties_sent = true; m_properties_sent = true;
std::string str = getPropertyPacket(); std::string str = getPropertyPacket(37);
std::string legacy_str = getPropertyPacket(32);
// create message and add to list // create message and add to list
m_messages_out.emplace(getId(), true, str); m_messages_out.emplace(getId(), true, str, legacy_str);
m_env->getScriptIface()->player_event(this, "properties_changed"); m_env->getScriptIface()->player_event(this, "properties_changed");
} }
@ -286,30 +304,45 @@ void PlayerSAO::step(float dtime, bool send_recommended)
m_rotation, m_rotation,
true, true,
false, false,
update_interval update_interval,
37
); );
std::string legacy_str = generateUpdatePositionCommand(
pos + v3f(0.0f, BS, 0.0f),
v3f(0.0f, 0.0f, 0.0f),
v3f(0.0f, 0.0f, 0.0f),
m_rotation,
true,
false,
update_interval,
32
);
// create message and add to list // create message and add to list
m_messages_out.emplace(getId(), false, str); m_messages_out.emplace(getId(), false, str, legacy_str);
} }
if (!m_physics_override_sent) { if (!m_physics_override_sent) {
m_physics_override_sent = true; m_physics_override_sent = true;
// create message and add to list // create message and add to list
m_messages_out.emplace(getId(), true, generateUpdatePhysicsOverrideCommand()); m_messages_out.emplace(getId(), true,
generateUpdatePhysicsOverrideCommand(37),
generateUpdatePhysicsOverrideCommand(32));
} }
sendOutdatedData(); sendOutdatedData();
} }
std::string PlayerSAO::generateUpdatePhysicsOverrideCommand() const std::string PlayerSAO::generateUpdatePhysicsOverrideCommand(const u16 protocol_version) const
{ {
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
// command // command
writeU8(os, AO_CMD_SET_PHYSICS_OVERRIDE); writeU8(os, AO_CMD_SET_PHYSICS_OVERRIDE);
// parameters // parameters
writeF32(os, m_physics_override_speed); writeF(os, m_physics_override_speed, protocol_version);
writeF32(os, m_physics_override_jump); writeF(os, m_physics_override_jump, protocol_version);
writeF32(os, m_physics_override_gravity); writeF(os, m_physics_override_gravity, protocol_version);
// these are sent inverted so we get true when the server sends nothing // these are sent inverted so we get true when the server sends nothing
writeU8(os, !m_physics_override_sneak); writeU8(os, !m_physics_override_sneak);
writeU8(os, !m_physics_override_sneak_glitch); writeU8(os, !m_physics_override_sneak_glitch);
@ -537,10 +570,26 @@ void PlayerSAO::unlinkPlayerSessionAndSave()
m_env->removePlayer(m_player); m_env->removePlayer(m_player);
} }
std::string PlayerSAO::getPropertyPacket() std::string PlayerSAO::getPropertyPacket(const u16 protocol_version)
{ {
m_prop.is_visible = (true); m_prop.is_visible = (true);
return generateSetPropertiesCommand(m_prop);
ObjectProperties prop = m_prop;
if (protocol_version < 37 && (m_prop.mesh == "3d_armor_character.b3d" ||
m_prop.mesh == "character.b3d" ||
m_prop.mesh == "skinsdb_3d_armor_character_5.b3d")) {
prop.mesh = "mc_compat_character.b3d";
for (u16 i = prop.textures.size(); i < 5; i++) {
prop.textures.emplace_back("blank.png");
}
}
// Remove a one-node offset from a copy of the object properties for MT 0.4
if (protocol_version < 37) {
prop.selectionbox.MinEdge.Y -= 1.0f;
prop.selectionbox.MaxEdge.Y -= 1.0f;
}
return generateSetPropertiesCommand(prop, protocol_version);
} }
void PlayerSAO::setMaxSpeedOverride(const v3f &vel) void PlayerSAO::setMaxSpeedOverride(const v3f &vel)

View File

@ -180,9 +180,10 @@ public:
inline Metadata &getMeta() { return m_meta; } inline Metadata &getMeta() { return m_meta; }
private: private:
std::string getPropertyPacket(); std::string getPropertyPacket(const u16 protocol_version);
void unlinkPlayerSessionAndSave(); void unlinkPlayerSessionAndSave();
std::string generateUpdatePhysicsOverrideCommand() const; std::string generateUpdatePhysicsOverrideCommand(
const u16 protocol_version) const;
RemotePlayer *m_player = nullptr; RemotePlayer *m_player = nullptr;
session_t m_peer_id = 0; session_t m_peer_id = 0;

View File

@ -99,24 +99,34 @@ void UnitSAO::sendOutdatedData()
if (!m_animation_sent) { if (!m_animation_sent) {
m_animation_sent = true; m_animation_sent = true;
m_animation_speed_sent = true; m_animation_speed_sent = true;
m_messages_out.emplace(getId(), true, generateUpdateAnimationCommand()); m_messages_out.emplace(getId(), true,
generateUpdateAnimationCommand(37),
generateUpdateAnimationCommand(32));
} else if (!m_animation_speed_sent) { } else if (!m_animation_speed_sent) {
// Animation speed is also sent when 'm_animation_sent == false' // Animation speed is also sent when 'm_animation_sent == false'
m_animation_speed_sent = true; m_animation_speed_sent = true;
m_messages_out.emplace(getId(), true, generateUpdateAnimationSpeedCommand()); m_messages_out.emplace(getId(), true,
generateUpdateAnimationSpeedCommand(),
// MT 0.4 has no update animation speed command
generateUpdateAnimationCommand(32));
} }
if (!m_bone_position_sent) { if (!m_bone_position_sent) {
m_bone_position_sent = true; m_bone_position_sent = true;
for (const auto &bone_pos : m_bone_position) { for (const auto &bone_pos : m_bone_position) {
m_messages_out.emplace(getId(), true, generateUpdateBonePositionCommand( std::string str = generateUpdateBonePositionCommand(
bone_pos.first, bone_pos.second.X, bone_pos.second.Y)); bone_pos.first, bone_pos.second.X, bone_pos.second.Y, 37);
std::string legacy_str = generateUpdateBonePositionCommand(
bone_pos.first, bone_pos.second.X, bone_pos.second.Y, 32);
m_messages_out.emplace(getId(), true, str, legacy_str);
} }
} }
if (!m_attachment_sent) { if (!m_attachment_sent) {
m_attachment_sent = true; m_attachment_sent = true;
m_messages_out.emplace(getId(), true, generateUpdateAttachmentCommand()); m_messages_out.emplace(getId(), true,
generateUpdateAttachmentCommand(37),
generateUpdateAttachmentCommand(32));
} }
} }
// clang-format on // clang-format on
@ -235,7 +245,7 @@ void UnitSAO::notifyObjectPropertiesModified()
m_properties_sent = false; m_properties_sent = false;
} }
std::string UnitSAO::generateUpdateAttachmentCommand() const std::string UnitSAO::generateUpdateAttachmentCommand(const u16 protocol_version) const
{ {
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
// command // command
@ -243,21 +253,37 @@ std::string UnitSAO::generateUpdateAttachmentCommand() const
// parameters // parameters
writeS16(os, m_attachment_parent_id); writeS16(os, m_attachment_parent_id);
os << serializeString(m_attachment_bone); os << serializeString(m_attachment_bone);
writeV3F32(os, m_attachment_position);
writeV3F32(os, m_attachment_rotation); // Add/remove offsets to compensate for MT 0.4
if (protocol_version >= 37) {
writeV3F32(os, m_attachment_position);
} else {
v3f compat_attachment_position = m_attachment_position;
if (getType() == ACTIVEOBJECT_TYPE_PLAYER) {
compat_attachment_position.Y += BS;
} else {
ServerActiveObject *p =
m_env->getActiveObject(m_attachment_parent_id);
if (p && p->getType() == ACTIVEOBJECT_TYPE_PLAYER)
compat_attachment_position.Y -= BS;
}
writeV3F1000(os, compat_attachment_position);
}
writeV3F(os, m_attachment_rotation, protocol_version);
return os.str(); return os.str();
} }
std::string UnitSAO::generateUpdateBonePositionCommand( std::string UnitSAO::generateUpdateBonePositionCommand(const std::string &bone,
const std::string &bone, const v3f &position, const v3f &rotation) const v3f &position, const v3f &rotation, const u16 protocol_version)
{ {
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
// command // command
writeU8(os, AO_CMD_SET_BONE_POSITION); writeU8(os, AO_CMD_SET_BONE_POSITION);
// parameters // parameters
os << serializeString(bone); os << serializeString(bone);
writeV3F32(os, position); writeV3F(os, position, protocol_version);
writeV3F32(os, rotation); writeV3F(os, rotation, protocol_version);
return os.str(); return os.str();
} }
@ -271,15 +297,15 @@ std::string UnitSAO::generateUpdateAnimationSpeedCommand() const
return os.str(); return os.str();
} }
std::string UnitSAO::generateUpdateAnimationCommand() const std::string UnitSAO::generateUpdateAnimationCommand(const u16 protocol_version) const
{ {
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
// command // command
writeU8(os, AO_CMD_SET_ANIMATION); writeU8(os, AO_CMD_SET_ANIMATION);
// parameters // parameters
writeV2F32(os, m_animation_range); writeV2F(os, m_animation_range, protocol_version);
writeF32(os, m_animation_speed); writeF(os, m_animation_speed, protocol_version);
writeF32(os, m_animation_blend); writeF(os, m_animation_blend, protocol_version);
// these are sent inverted so we get true when the server sends nothing // these are sent inverted so we get true when the server sends nothing
writeU8(os, !m_animation_loop); writeU8(os, !m_animation_loop);
return os.str(); return os.str();
@ -299,33 +325,38 @@ std::string UnitSAO::generateUpdateArmorGroupsCommand() const
std::string UnitSAO::generateUpdatePositionCommand(const v3f &position, std::string UnitSAO::generateUpdatePositionCommand(const v3f &position,
const v3f &velocity, const v3f &acceleration, const v3f &rotation, const v3f &velocity, const v3f &acceleration, const v3f &rotation,
bool do_interpolate, bool is_movement_end, f32 update_interval) bool do_interpolate, bool is_movement_end, f32 update_interval,
const u16 protocol_version)
{ {
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
// command // command
writeU8(os, AO_CMD_UPDATE_POSITION); writeU8(os, AO_CMD_UPDATE_POSITION);
// pos // pos
writeV3F32(os, position); writeV3F(os, position, protocol_version);
// velocity // velocity
writeV3F32(os, velocity); writeV3F(os, velocity, protocol_version);
// acceleration // acceleration
writeV3F32(os, acceleration); writeV3F(os, acceleration, protocol_version);
// rotation // rotation
writeV3F32(os, rotation); if (protocol_version >= 37)
writeV3F32(os, rotation);
else
writeF1000(os, rotation.Y);
// do_interpolate // do_interpolate
writeU8(os, do_interpolate); writeU8(os, do_interpolate);
// is_end_position (for interpolation) // is_end_position (for interpolation)
writeU8(os, is_movement_end); writeU8(os, is_movement_end);
// update_interval (for interpolation) // update_interval (for interpolation)
writeF32(os, update_interval); writeF(os, update_interval, protocol_version);
return os.str(); return os.str();
} }
std::string UnitSAO::generateSetPropertiesCommand(const ObjectProperties &prop) const std::string UnitSAO::generateSetPropertiesCommand(
const ObjectProperties &prop, const u16 protocol_version) const
{ {
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
writeU8(os, AO_CMD_SET_PROPERTIES); writeU8(os, AO_CMD_SET_PROPERTIES);
prop.serialize(os); prop.serialize(os, protocol_version);
return os.str(); return os.str();
} }
@ -339,7 +370,19 @@ std::string UnitSAO::generatePunchCommand(u16 result_hp) const
return os.str(); return os.str();
} }
std::string UnitSAO::generateLegacyPunchCommand(u16 result_hp) const
{
std::ostringstream os(std::ios::binary);
// command
writeU8(os, AO_CMD_PUNCHED);
// result_hp
writeU16(os, result_hp);
return os.str();
}
void UnitSAO::sendPunchCommand() void UnitSAO::sendPunchCommand()
{ {
m_messages_out.emplace(getId(), true, generatePunchCommand(getHP())); const u16 result_hp = getHP();
m_messages_out.emplace(getId(), true, generatePunchCommand(result_hp),
generateLegacyPunchCommand(result_hp));
} }

View File

@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include "constants.h"
#include "object_properties.h" #include "object_properties.h"
#include "serveractiveobject.h" #include "serveractiveobject.h"
@ -79,16 +80,19 @@ public:
void sendOutdatedData(); void sendOutdatedData();
// Update packets // Update packets
std::string generateUpdateAttachmentCommand() const; std::string generateUpdateAttachmentCommand(const u16 protocol_version) const;
std::string generateUpdateAnimationSpeedCommand() const; std::string generateUpdateAnimationSpeedCommand() const;
std::string generateUpdateAnimationCommand() const; std::string generateUpdateAnimationCommand(const u16 protocol_version) const;
std::string generateUpdateArmorGroupsCommand() const; std::string generateUpdateArmorGroupsCommand() const;
static std::string generateUpdatePositionCommand(const v3f &position, static std::string generateUpdatePositionCommand(const v3f &position,
const v3f &velocity, const v3f &acceleration, const v3f &rotation, const v3f &velocity, const v3f &acceleration, const v3f &rotation,
bool do_interpolate, bool is_movement_end, f32 update_interval); bool do_interpolate, bool is_movement_end, f32 update_interval,
std::string generateSetPropertiesCommand(const ObjectProperties &prop) const; const u16 protocol_version);
std::string generateSetPropertiesCommand(
const ObjectProperties &prop, const u16 protocol_version) const;
static std::string generateUpdateBonePositionCommand(const std::string &bone, static std::string generateUpdateBonePositionCommand(const std::string &bone,
const v3f &position, const v3f &rotation); const v3f &position, const v3f &rotation,
const u16 protocol_version);
void sendPunchCommand(); void sendPunchCommand();
protected: protected:
@ -112,6 +116,7 @@ private:
void onDetach(int parent_id); void onDetach(int parent_id);
std::string generatePunchCommand(u16 result_hp) const; std::string generatePunchCommand(u16 result_hp) const;
std::string generateLegacyPunchCommand(u16 result_hp) const;
// Armor groups // Armor groups
bool m_armor_groups_sent = false; bool m_armor_groups_sent = false;

View File

@ -40,6 +40,12 @@ struct SimpleSoundSpec
void serialize(std::ostream &os, u8 cf_version) const void serialize(std::ostream &os, u8 cf_version) const
{ {
os << serializeString(name); os << serializeString(name);
if (cf_version < 13) {
writeF1000(os, gain);
if (cf_version > 10)
writeF1000(os, pitch);
return;
}
writeF32(os, gain); writeF32(os, gain);
writeF32(os, pitch); writeF32(os, pitch);
writeF32(os, fade); writeF32(os, fade);

View File

@ -21,15 +21,27 @@ with this program; if not, write to the Free Software Foundation, Inc.,
void TileAnimationParams::serialize(std::ostream &os, u8 tiledef_version) const void TileAnimationParams::serialize(std::ostream &os, u8 tiledef_version) const
{ {
if (tiledef_version < 3 && type != TAT_VERTICAL_FRAMES) {
writeU8(os, TAT_NONE);
writeU16(os, 1);
writeU16(os, 1);
writeF1000(os, 1.0f);
return;
}
writeU8(os, type); writeU8(os, type);
// Approximate protocol version
const u16 protocol_version = tiledef_version >= 6 ? 37 : 32;
if (type == TAT_VERTICAL_FRAMES) { if (type == TAT_VERTICAL_FRAMES) {
writeU16(os, vertical_frames.aspect_w); writeU16(os, vertical_frames.aspect_w);
writeU16(os, vertical_frames.aspect_h); writeU16(os, vertical_frames.aspect_h);
writeF32(os, vertical_frames.length); writeF(os, vertical_frames.length, protocol_version);
} else if (type == TAT_SHEET_2D) { } else if (type == TAT_SHEET_2D) {
writeU8(os, sheet_2d.frames_w); writeU8(os, sheet_2d.frames_w);
writeU8(os, sheet_2d.frames_h); writeU8(os, sheet_2d.frames_h);
writeF32(os, sheet_2d.frame_length); writeF(os, sheet_2d.frame_length, protocol_version);
} }
} }

View File

@ -58,9 +58,11 @@ void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const
{ {
if (protocol_version >= 38) if (protocol_version >= 38)
writeU8(os, 5); writeU8(os, 5);
else else if (protocol_version == 37)
writeU8(os, 4); // proto == 37 writeU8(os, 4); // proto == 37
writeF32(os, full_punch_interval); else
writeU8(os, 2); // proto >= 18
writeF(os, full_punch_interval, protocol_version);
writeS16(os, max_drop_level); writeS16(os, max_drop_level);
writeU32(os, groupcaps.size()); writeU32(os, groupcaps.size());
for (const auto &groupcap : groupcaps) { for (const auto &groupcap : groupcaps) {
@ -72,7 +74,7 @@ void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const
writeU32(os, cap->times.size()); writeU32(os, cap->times.size());
for (const auto &time : cap->times) { for (const auto &time : cap->times) {
writeS16(os, time.first); writeS16(os, time.first);
writeF32(os, time.second); writeF(os, time.second, protocol_version);
} }
} }