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
end
assert(moveresult,
"Collision info missing, this is caused by an out-of-date/buggy mod or game")
-- assert(moveresult,
-- "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
-- future TODO: items should probably decelerate in air

Binary file not shown.

View File

@ -44,15 +44,18 @@ enum ActiveObjectType {
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_),
reliable(reliable_),
datastring(data_)
datastring(data_),
legacystring(legacy_)
{}
u16 id;
bool reliable;
std::string datastring;
std::string legacystring;
};
enum ActiveObjectCommand {

View File

@ -750,8 +750,8 @@ void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacyp
} else if (client->net_proto_version != 0) {
pkt_to_send = legacypkt;
} else {
warningstream << "Client with unhandled version to handle: '"
<< client->net_proto_version << "'";
// This will happen if a client is connecting when sendToAllCompat
// is called, this can safely be ignored.
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)
{
RecursiveMutexAutoLock clientslock(m_clients_mutex);

View File

@ -458,6 +458,8 @@ public:
/* send to all clients */
void sendToAll(NetworkPacket *pkt);
void sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt, u16 min_proto_ver);
void oldSendToAll(NetworkPacket *pkt);
void newSendToAll(NetworkPacket *pkt);
/* delete a client */
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
u8 version = 6;
// protocol_version < 37
if (protocol_version < 37)
version = 3;
writeU8(os, version);
writeU8(os, type);
os << serializeString(name);
@ -153,13 +158,25 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
os << serializeString(node_placement_prediction);
// Version from ContentFeatures::serialize to keep in sync
sound_place.serialize(os, CONTENTFEATURES_VERSION);
sound_place_failed.serialize(os, CONTENTFEATURES_VERSION);
if (version == 3) {
os << serializeString(sound_place.name);
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);
writeARGB8(os, color);
if (version == 3)
return;
os << serializeString(inventory_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))
throw VersionMismatchException("ERROR: MapBlock format not supported");
@ -411,7 +411,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
Node metadata
*/
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);
/*

View File

@ -482,7 +482,8 @@ public:
// These don't write or read version by itself
// Set disk to true for on-disk format, false for over-the-network format
// 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
// unknown blocks from id-name mapping to wndef
void deSerialize(std::istream &is, u8 version, bool disk);

View File

@ -44,6 +44,7 @@ public:
u16 getCommand() { return m_command; }
const u32 getRemainingBytes() const { return m_datasize - m_read_offset; }
const char *getRemainingString() { return getString(m_read_offset); }
u16 getProtocolVersion() const { return m_protocol_version; }
// Returns a c-string without copying.
// 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)
// 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
// 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, // 0x3f
{ "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
{ "TOSERVER_CLIENT_READY", TOSERVER_STATE_STARTUP, &Server::handleCommand_ClientReady }, // 0x43
null_command_handler, // 0x44

View File

@ -324,7 +324,7 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
sendDetachedInventories(peer_id, false);
// Send player movement settings
SendMovement(peer_id);
SendMovement(peer_id, protocol_version);
// Send time of day
u16 time = m_env->getTimeOfDay();
@ -454,7 +454,7 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
NetworkPacket *pkt)
{
if (pkt->getRemainingBytes() < 12 + 12 + 4 + 4 + 4 + 1 + 1)
if (pkt->getRemainingBytes() < 12 + 12 + 4 + 4)
return;
v3s32 ps, ss;
@ -474,10 +474,14 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
f32 fov = 0;
u8 wanted_range = 0;
*pkt >> keyPressed;
*pkt >> f32fov;
fov = (f32)f32fov / 80.0f;
*pkt >> wanted_range;
if (pkt->getRemainingBytes() >= 4)
*pkt >> keyPressed;
if (pkt->getRemainingBytes() >= 1) {
*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 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)
{
u16 damage;
*pkt >> damage;
session_t peer_id = pkt->getPeerId();
RemotePlayer *player = m_env->getPlayer(peer_id);
@ -806,6 +807,17 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
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();
if (playersao == NULL) {
errorstream <<
@ -1670,7 +1682,7 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt)
if (client->chosen_mech != AUTH_MECHANISM_SRP &&
client->chosen_mech != AUTH_MECHANISM_LEGACY_PASSWORD) {
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;
if (wantSudo) {
DenySudoAccess(peer_id);

View File

@ -74,7 +74,13 @@ void NodeBox::reset()
void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
{
// 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);
switch (type) {
@ -84,28 +90,38 @@ void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
writeU16(os, fixed.size());
for (const aabb3f &nodebox : fixed) {
writeV3F32(os, nodebox.MinEdge);
writeV3F32(os, nodebox.MaxEdge);
writeV3F(os, nodebox.MinEdge, protocol_version);
writeV3F(os, nodebox.MaxEdge, protocol_version);
}
break;
case NODEBOX_WALLMOUNTED:
writeU8(os, type);
writeV3F32(os, wall_top.MinEdge);
writeV3F32(os, wall_top.MaxEdge);
writeV3F32(os, wall_bottom.MinEdge);
writeV3F32(os, wall_bottom.MaxEdge);
writeV3F32(os, wall_side.MinEdge);
writeV3F32(os, wall_side.MaxEdge);
writeV3F(os, wall_top.MinEdge, protocol_version);
writeV3F(os, wall_top.MaxEdge, protocol_version);
writeV3F(os, wall_bottom.MinEdge, protocol_version);
writeV3F(os, wall_bottom.MaxEdge, protocol_version);
writeV3F(os, wall_side.MinEdge, protocol_version);
writeV3F(os, wall_side.MaxEdge, protocol_version);
break;
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);
#define WRITEBOX(box) \
writeU16(os, (box).size()); \
for (const aabb3f &i: (box)) { \
writeV3F32(os, i.MinEdge); \
writeV3F32(os, i.MaxEdge); \
writeV3F(os, i.MinEdge, protocol_version); \
writeV3F(os, i.MaxEdge, protocol_version); \
};
WRITEBOX(fixed);
@ -115,14 +131,17 @@ void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
WRITEBOX(connect_left);
WRITEBOX(connect_back);
WRITEBOX(connect_right);
WRITEBOX(disconnected_top);
WRITEBOX(disconnected_bottom);
WRITEBOX(disconnected_front);
WRITEBOX(disconnected_left);
WRITEBOX(disconnected_back);
WRITEBOX(disconnected_right);
WRITEBOX(disconnected);
WRITEBOX(disconnected_sides);
if (version > 5) {
WRITEBOX(disconnected_top);
WRITEBOX(disconnected_bottom);
WRITEBOX(disconnected_front);
WRITEBOX(disconnected_left);
WRITEBOX(disconnected_back);
WRITEBOX(disconnected_right);
WRITEBOX(disconnected);
WRITEBOX(disconnected_sides);
}
break;
default:
writeU8(os, type);
@ -207,12 +226,41 @@ void NodeBox::deSerialize(std::istream &is)
void TileDef::serialize(std::ostream &os, u16 protocol_version) const
{
// protocol_version >= 36
u8 version = 6;
u8 version;
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);
os << serializeString(name);
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;
u16 flags = 0;
if (backface_culling)
@ -424,7 +472,14 @@ void ContentFeatures::reset()
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);
// general
@ -440,7 +495,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
// visual
writeU8(os, drawtype);
os << serializeString(mesh);
writeF32(os, visual_scale);
writeF(os, visual_scale, protocol_version);
writeU8(os, 6);
for (const TileDef &td : tiledef)
td.serialize(os, protocol_version);
@ -1125,6 +1180,105 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
}
#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
*/

View File

@ -414,6 +414,7 @@ struct ContentFeatures
void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is);
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
* adds opacity directly to the texture pixels.

View File

@ -40,7 +40,8 @@ NodeMetadata::~NodeMetadata()
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();
writeU32(os, num_vars);
@ -50,7 +51,11 @@ void NodeMetadata::serialize(std::ostream &os, u8 version, bool disk) const
continue;
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)
writeU8(os, (priv) ? 1 : 0);
}
@ -113,7 +118,7 @@ int NodeMetadata::countNonPrivate() const
*/
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."
@ -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;
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();
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 clear();
@ -82,7 +83,7 @@ public:
~NodeMetadataList();
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,
bool absolute_pos = false);

View File

@ -73,28 +73,62 @@ std::string ObjectProperties::dump()
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);
writeU8(os, physical);
writeF32(os, 0.f); // Removed property (weight)
writeV3F32(os, collisionbox.MinEdge);
writeV3F32(os, collisionbox.MaxEdge);
writeV3F32(os, selectionbox.MinEdge);
writeV3F32(os, selectionbox.MaxEdge);
writeU8(os, pointable);
os << serializeString(visual);
writeV3F32(os, visual_size);
writeU16(os, textures.size());
for (const std::string &texture : textures) {
os << serializeString(texture);
writeF(os, 0.f, protocol_version); // Removed property (weight)
if (protocol_version > 36) {
writeV3F32(os, collisionbox.MinEdge);
writeV3F32(os, collisionbox.MaxEdge);
writeV3F32(os, selectionbox.MinEdge);
writeV3F32(os, selectionbox.MaxEdge);
writeU8(os, pointable);
} else if (pointable) {
writeV3F1000(os, selectionbox.MinEdge);
writeV3F1000(os, selectionbox.MaxEdge);
} 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, initial_sprite_basepos);
writeU8(os, is_visible);
writeU8(os, makes_footstep_sound);
writeF32(os, automatic_rotate);
writeF(os, automatic_rotate, protocol_version);
// Added in protocol version 14
os << serializeString(mesh);
writeU16(os, colors.size());
@ -102,16 +136,21 @@ void ObjectProperties::serialize(std::ostream &os) const
writeARGB8(os, color);
}
writeU8(os, collideWithObjects);
writeF32(os, stepheight);
writeF(os, stepheight, protocol_version);
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);
os << serializeString(nametag);
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(wield_item);
writeS8(os, glow);
// Everything after this can use writeF32().
if (protocol_version < 37)
return;
writeU16(os, breath_max);
writeF32(os, eye_height);
writeF32(os, zoom_fov);

View File

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

View File

@ -771,7 +771,11 @@ void Server::AsyncRunStep(bool initial_step)
// u16 id
// std::string data
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;
}
RemoteClient *client = getClient(peer_id);
if (client)
pkt->setProtocolVersion(client->net_proto_version);
handleCommand(pkt);
} catch (SendFailedException &e) {
errorstream << "Server::ProcessData(): SendFailedException: "
@ -1154,7 +1161,7 @@ void Server::ProcessData(NetworkPacket *pkt)
<< std::endl;
} catch (PacketError &e) {
actionstream << "Server::ProcessData(): PacketError: "
<< "what=" << e.what()
<< "what=" << e.what() << ", command=" << pkt->getCommand() // TODO: REMOVE COMMAND=
<< std::endl;
}
}
@ -1296,11 +1303,11 @@ void Server::Send(session_t peer_id, NetworkPacket *pkt)
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);
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_air");
@ -1335,7 +1342,13 @@ void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason
void Server::SendHP(session_t peer_id, u16 hp)
{
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);
}
@ -1454,6 +1467,9 @@ void Server::SendInventory(PlayerSAO *sao, bool incremental)
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);
u8 version = 1;
u8 type = message.type;
@ -1464,9 +1480,12 @@ void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
if (!player)
return;
Send(&pkt);
if (player->protocol_version < 35)
Send(&legacypkt);
else
Send(&pkt);
} 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("");
} else {
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;
@ -1522,7 +1546,7 @@ void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
}
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...
@ -1569,7 +1593,7 @@ void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
}
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
<< 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)
{
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
<< 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)
{
NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id, m_clients.getProtocolVersion(peer_id));
pkt << id << (u8) 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)
{
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
<< params.height << params.thickness << params.speed;
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)
{
NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
pkt << time << time_speed;
if (peer_id != PEER_ID_INEXISTENT) {
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);
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)
@ -1792,7 +1822,7 @@ void Server::SendMovePlayer(session_t peer_id)
PlayerSAO *sao = player->getPlayerSAO();
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;
{
@ -1821,7 +1851,7 @@ void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames
f32 animation_speed)
{
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]
<< 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)
{
NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id, m_clients.getProtocolVersion(peer_id));
pkt << first << third;
Send(&pkt);
}
@ -1864,7 +1894,12 @@ void Server::SendPlayerInventoryFormspec(session_t peer_id)
return;
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);
}
@ -1875,6 +1910,10 @@ void Server::SendPlayerFormspecPrepend(session_t peer_id)
assert(player);
if (player->getPeerId() == PEER_ID_INEXISTENT)
return;
if (player->protocol_version < 37) {
SendPlayerInventoryFormspec(peer_id);
return;
}
NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
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)
{
const u16 protocol_version = m_clients.getProtocolVersion(peer_id);
if (protocol_version < 35 && protocol_version != 0)
return;
NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
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;
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
NetworkPacket legacypkt(TOCLIENT_PLAY_SOUND, 0, PEER_ID_INEXISTENT, 32);
pkt << id << spec.name << gain
<< (u8) params.type << pos << params.object
<< params.loop << params.fade << params.pitch
<< ephemeral;
legacypkt << id << spec.name << gain
<< (u8) params.type << pos << params.object
<< params.loop << params.fade;
bool as_reliable = !ephemeral;
bool play_sound = gain > 0;
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)
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;
}
@ -2257,6 +2312,13 @@ void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far
if (!client)
continue;
if (client->net_proto_version < 37) {
for (const v3s16 &pos : meta_updates) {
client->SetBlockNotSent(getNodeBlockPos(pos));
}
continue;
}
ServerActiveObject *player = m_env->getActiveObject(i);
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);
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);
std::string s = os.str();
@ -2483,7 +2550,10 @@ void Server::fillMediaCache()
std::vector<std::string> paths;
m_modmgr->getModsMediaPaths(paths);
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
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)
{
NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
NetworkPacket legacy_pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
pkt << name;
legacy_pkt << name;
if (!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();
pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
pkt.putRawString(os_str);
legacy_pkt.putRawString(os_str);
}
if (peer_id == PEER_ID_INEXISTENT)
m_clients.sendToAll(&pkt);
else
Send(&pkt);
if (peer_id == PEER_ID_INEXISTENT) {
m_clients.newSendToAll(&pkt);
if (inventory)
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)
@ -2774,7 +2859,7 @@ void Server::acceptAuth(session_t peer_id, bool forSudoMode)
if (!forSudoMode) {
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.
u32 sudo_auth_mechs = client->allowed_auth_mechs;

View File

@ -374,7 +374,7 @@ private:
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 SendBreath(session_t peer_id, u16 breath);
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)
{
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
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.
@ -228,19 +229,26 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
os << serializeString(""); // name
writeU8(os, 0); // is_player
writeU16(os, getId()); //id
writeV3F32(os, m_base_position);
writeV3F32(os, m_rotation);
writeV3F(os, m_base_position, protocol_version);
if (protocol_version >= 37)
writeV3F32(os, m_rotation);
else
writeF1000(os, m_rotation.Y);
writeU16(os, m_hp);
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(generateUpdateAnimationCommand()); // 3
msg_os << serializeLongString(generateUpdateAnimationCommand(
protocol_version)); // 3
for (const auto &bone_pos : m_bone_position) {
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();
@ -472,9 +480,9 @@ std::string LuaEntitySAO::getName()
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)
@ -500,10 +508,23 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
m_rotation,
do_interpolate,
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
m_messages_out.emplace(getId(), false, str);
m_messages_out.emplace(getId(), false, str, legacy_str);
}
bool LuaEntitySAO::getCollisionBox(aabb3f *toset) const

View File

@ -71,7 +71,7 @@ public:
bool collideWithObjects() const;
private:
std::string getPropertyPacket();
std::string getPropertyPacket(const u16 protocol_version);
void sendPosition(bool do_interpolate, bool is_movement_end);
std::string generateSetTextureModCommand() const;
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
writeU8(os, 1); // is_player
writeS16(os, getId()); // id
writeV3F32(os, m_base_position);
writeV3F32(os, m_rotation);
writeU16(os, getHP());
if (protocol_version >= 37) {
writeV3F32(os, m_base_position);
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);
msg_os << serializeLongString(getPropertyPacket()); // message 1
msg_os << serializeLongString(getPropertyPacket(
protocol_version)); // message 1
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) {
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(generateUpdatePhysicsOverrideCommand()); // 5
msg_os << serializeLongString(generateUpdateAttachmentCommand(
protocol_version)); // 4
msg_os << serializeLongString(generateUpdatePhysicsOverrideCommand(
protocol_version)); // 5
int message_count = 5 + m_bone_position.size();
@ -221,9 +238,10 @@ void PlayerSAO::step(float dtime, bool send_recommended)
if (!m_properties_sent) {
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
m_messages_out.emplace(getId(), true, str);
m_messages_out.emplace(getId(), true, str, legacy_str);
m_env->getScriptIface()->player_event(this, "properties_changed");
}
@ -286,30 +304,45 @@ void PlayerSAO::step(float dtime, bool send_recommended)
m_rotation,
true,
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
m_messages_out.emplace(getId(), false, str);
m_messages_out.emplace(getId(), false, str, legacy_str);
}
if (!m_physics_override_sent) {
m_physics_override_sent = true;
// create message and add to list
m_messages_out.emplace(getId(), true, generateUpdatePhysicsOverrideCommand());
m_messages_out.emplace(getId(), true,
generateUpdatePhysicsOverrideCommand(37),
generateUpdatePhysicsOverrideCommand(32));
}
sendOutdatedData();
}
std::string PlayerSAO::generateUpdatePhysicsOverrideCommand() const
std::string PlayerSAO::generateUpdatePhysicsOverrideCommand(const u16 protocol_version) const
{
std::ostringstream os(std::ios::binary);
// command
writeU8(os, AO_CMD_SET_PHYSICS_OVERRIDE);
// parameters
writeF32(os, m_physics_override_speed);
writeF32(os, m_physics_override_jump);
writeF32(os, m_physics_override_gravity);
writeF(os, m_physics_override_speed, protocol_version);
writeF(os, m_physics_override_jump, protocol_version);
writeF(os, m_physics_override_gravity, protocol_version);
// 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_glitch);
@ -537,10 +570,26 @@ void PlayerSAO::unlinkPlayerSessionAndSave()
m_env->removePlayer(m_player);
}
std::string PlayerSAO::getPropertyPacket()
std::string PlayerSAO::getPropertyPacket(const u16 protocol_version)
{
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)

View File

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

View File

@ -99,24 +99,34 @@ void UnitSAO::sendOutdatedData()
if (!m_animation_sent) {
m_animation_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) {
// Animation speed is also sent when 'm_animation_sent == false'
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) {
m_bone_position_sent = true;
for (const auto &bone_pos : m_bone_position) {
m_messages_out.emplace(getId(), true, generateUpdateBonePositionCommand(
bone_pos.first, bone_pos.second.X, bone_pos.second.Y));
std::string str = generateUpdateBonePositionCommand(
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) {
m_attachment_sent = true;
m_messages_out.emplace(getId(), true, generateUpdateAttachmentCommand());
m_messages_out.emplace(getId(), true,
generateUpdateAttachmentCommand(37),
generateUpdateAttachmentCommand(32));
}
}
// clang-format on
@ -235,7 +245,7 @@ void UnitSAO::notifyObjectPropertiesModified()
m_properties_sent = false;
}
std::string UnitSAO::generateUpdateAttachmentCommand() const
std::string UnitSAO::generateUpdateAttachmentCommand(const u16 protocol_version) const
{
std::ostringstream os(std::ios::binary);
// command
@ -243,21 +253,37 @@ std::string UnitSAO::generateUpdateAttachmentCommand() const
// parameters
writeS16(os, m_attachment_parent_id);
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();
}
std::string UnitSAO::generateUpdateBonePositionCommand(
const std::string &bone, const v3f &position, const v3f &rotation)
std::string UnitSAO::generateUpdateBonePositionCommand(const std::string &bone,
const v3f &position, const v3f &rotation, const u16 protocol_version)
{
std::ostringstream os(std::ios::binary);
// command
writeU8(os, AO_CMD_SET_BONE_POSITION);
// parameters
os << serializeString(bone);
writeV3F32(os, position);
writeV3F32(os, rotation);
writeV3F(os, position, protocol_version);
writeV3F(os, rotation, protocol_version);
return os.str();
}
@ -271,15 +297,15 @@ std::string UnitSAO::generateUpdateAnimationSpeedCommand() const
return os.str();
}
std::string UnitSAO::generateUpdateAnimationCommand() const
std::string UnitSAO::generateUpdateAnimationCommand(const u16 protocol_version) const
{
std::ostringstream os(std::ios::binary);
// command
writeU8(os, AO_CMD_SET_ANIMATION);
// parameters
writeV2F32(os, m_animation_range);
writeF32(os, m_animation_speed);
writeF32(os, m_animation_blend);
writeV2F(os, m_animation_range, protocol_version);
writeF(os, m_animation_speed, protocol_version);
writeF(os, m_animation_blend, protocol_version);
// these are sent inverted so we get true when the server sends nothing
writeU8(os, !m_animation_loop);
return os.str();
@ -299,33 +325,38 @@ std::string UnitSAO::generateUpdateArmorGroupsCommand() const
std::string UnitSAO::generateUpdatePositionCommand(const v3f &position,
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);
// command
writeU8(os, AO_CMD_UPDATE_POSITION);
// pos
writeV3F32(os, position);
writeV3F(os, position, protocol_version);
// velocity
writeV3F32(os, velocity);
writeV3F(os, velocity, protocol_version);
// acceleration
writeV3F32(os, acceleration);
writeV3F(os, acceleration, protocol_version);
// rotation
writeV3F32(os, rotation);
if (protocol_version >= 37)
writeV3F32(os, rotation);
else
writeF1000(os, rotation.Y);
// do_interpolate
writeU8(os, do_interpolate);
// is_end_position (for interpolation)
writeU8(os, is_movement_end);
// update_interval (for interpolation)
writeF32(os, update_interval);
writeF(os, update_interval, protocol_version);
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);
writeU8(os, AO_CMD_SET_PROPERTIES);
prop.serialize(os);
prop.serialize(os, protocol_version);
return os.str();
}
@ -339,7 +370,19 @@ std::string UnitSAO::generatePunchCommand(u16 result_hp) const
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()
{
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
#include "constants.h"
#include "object_properties.h"
#include "serveractiveobject.h"
@ -79,16 +80,19 @@ public:
void sendOutdatedData();
// Update packets
std::string generateUpdateAttachmentCommand() const;
std::string generateUpdateAttachmentCommand(const u16 protocol_version) const;
std::string generateUpdateAnimationSpeedCommand() const;
std::string generateUpdateAnimationCommand() const;
std::string generateUpdateAnimationCommand(const u16 protocol_version) const;
std::string generateUpdateArmorGroupsCommand() const;
static std::string generateUpdatePositionCommand(const v3f &position,
const v3f &velocity, const v3f &acceleration, const v3f &rotation,
bool do_interpolate, bool is_movement_end, f32 update_interval);
std::string generateSetPropertiesCommand(const ObjectProperties &prop) const;
bool do_interpolate, bool is_movement_end, f32 update_interval,
const u16 protocol_version);
std::string generateSetPropertiesCommand(
const ObjectProperties &prop, const u16 protocol_version) const;
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();
protected:
@ -112,6 +116,7 @@ private:
void onDetach(int parent_id);
std::string generatePunchCommand(u16 result_hp) const;
std::string generateLegacyPunchCommand(u16 result_hp) const;
// Armor groups
bool m_armor_groups_sent = false;

View File

@ -40,6 +40,12 @@ struct SimpleSoundSpec
void serialize(std::ostream &os, u8 cf_version) const
{
os << serializeString(name);
if (cf_version < 13) {
writeF1000(os, gain);
if (cf_version > 10)
writeF1000(os, pitch);
return;
}
writeF32(os, gain);
writeF32(os, pitch);
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
{
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);
// Approximate protocol version
const u16 protocol_version = tiledef_version >= 6 ? 37 : 32;
if (type == TAT_VERTICAL_FRAMES) {
writeU16(os, vertical_frames.aspect_w);
writeU16(os, vertical_frames.aspect_h);
writeF32(os, vertical_frames.length);
writeF(os, vertical_frames.length, protocol_version);
} else if (type == TAT_SHEET_2D) {
writeU8(os, sheet_2d.frames_w);
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)
writeU8(os, 5);
else
else if (protocol_version == 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);
writeU32(os, groupcaps.size());
for (const auto &groupcap : groupcaps) {
@ -72,7 +74,7 @@ void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const
writeU32(os, cap->times.size());
for (const auto &time : cap->times) {
writeS16(os, time.first);
writeF32(os, time.second);
writeF(os, time.second, protocol_version);
}
}