Skip to content

Commit b839a6d

Browse files
sofarparamat
authored andcommittedApr 27, 2019
Force send a mapblock to a player (#8140)
* Force send a mapblock to a player. Send a single mapblock to a specific remote player. This is badly needed for mods and games where players are teleported into terrain which may be not generated, loaded, or modified significantly since the last player visit. In all these cases, the player currently ends up in void, air, or inside blocks which not only looks bad, but has the effect that the player might end up falling and then the server needs to correct for the player position again later, which is a hack. The best solution is to send at least the single mapblock that the player will be teleported to. I've tested this with ITB which does this all the time, and I can see it functioning as expected (it even shows a half loaded entry hallway, as the further blocks aren't loaded yet). The parameter is a blockpos (table of x, y, z), not a regular pos. The function may return false if the call failed. This is most likely due to the target position not being generated or emerged yet, or another internal failure, such as the player not being initialized. * Always send mapblock on teleport or respawn. This avoids the need for mods to send a mapblock on teleport or respawn, since any call to `player:set_pos()` will pass this code.
1 parent d71e1e0 commit b839a6d

File tree

6 files changed

+55
-0
lines changed

6 files changed

+55
-0
lines changed
 

‎doc/lua_api.txt

+5
Original file line numberDiff line numberDiff line change
@@ -5382,6 +5382,11 @@ This is basically a reference to a C++ `ServerActiveObject`
53825382
* in first person view
53835383
* in third person view (max. values `{x=-10/10,y=-10,15,z=-5/5}`)
53845384
* `get_eye_offset()`: returns `offset_first` and `offset_third`
5385+
* `send_mapblock(blockpos)`:
5386+
* Sends a server-side loaded mapblock to the player.
5387+
* Returns `false` if failed.
5388+
* Resource intensive - use sparsely
5389+
* To get blockpos, integer divide pos by 16
53855390

53865391
`PcgRandom`
53875392
-----------

‎src/content_sao.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,10 @@ void PlayerSAO::setPos(const v3f &pos)
12051205
if(isAttached())
12061206
return;
12071207

1208+
// Send mapblock of target location
1209+
v3s16 blockpos = v3s16(pos.X / MAP_BLOCKSIZE, pos.Y / MAP_BLOCKSIZE, pos.Z / MAP_BLOCKSIZE);
1210+
m_env->getGameDef()->SendBlock(m_peer_id, blockpos);
1211+
12081212
setBasePosition(pos);
12091213
// Movement caused by this command is always valid
12101214
m_last_good_position = pos;

‎src/script/lua_api/l_object.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,24 @@ int ObjectRef::l_get_eye_offset(lua_State *L)
584584
return 2;
585585
}
586586

587+
// send_mapblock(self, pos)
588+
int ObjectRef::l_send_mapblock(lua_State *L)
589+
{
590+
NO_MAP_LOCK_REQUIRED;
591+
ObjectRef *ref = checkobject(L, 1);
592+
593+
RemotePlayer *player = getplayer(ref);
594+
if (!player)
595+
return 0;
596+
v3s16 p = read_v3s16(L, 2);
597+
598+
session_t peer_id = player->getPeerId();
599+
bool r = getServer(L)->SendBlock(peer_id, p);
600+
601+
lua_pushboolean(L, r);
602+
return 1;
603+
}
604+
587605
// set_animation_frame_speed(self, frame_speed)
588606
int ObjectRef::l_set_animation_frame_speed(lua_State *L)
589607
{
@@ -1958,5 +1976,6 @@ luaL_Reg ObjectRef::methods[] = {
19581976
luamethod(ObjectRef, get_local_animation),
19591977
luamethod(ObjectRef, set_eye_offset),
19601978
luamethod(ObjectRef, get_eye_offset),
1979+
luamethod(ObjectRef, send_mapblock),
19611980
{0,0}
19621981
};

‎src/script/lua_api/l_object.h

+2
Original file line numberDiff line numberDiff line change
@@ -351,4 +351,6 @@ class ObjectRef : public ModApiBase {
351351
// get_nametag_attributes(self)
352352
static int l_get_nametag_attributes(lua_State *L);
353353

354+
// send_mapblock(pos)
355+
static int l_send_mapblock(lua_State *L);
354356
};

‎src/server.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,28 @@ void Server::SendBlocks(float dtime)
23122312
m_clients.unlock();
23132313
}
23142314

2315+
bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2316+
{
2317+
MapBlock *block = nullptr;
2318+
try {
2319+
block = m_env->getMap().getBlockNoCreate(blockpos);
2320+
} catch (InvalidPositionException &e) {};
2321+
if (!block)
2322+
return false;
2323+
2324+
m_clients.lock();
2325+
RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2326+
if (!client || client->isBlockSent(blockpos)) {
2327+
m_clients.unlock();
2328+
return false;
2329+
}
2330+
SendBlockNoLock(peer_id, block, client->serialization_version,
2331+
client->net_proto_version);
2332+
m_clients.unlock();
2333+
2334+
return true;
2335+
}
2336+
23152337
void Server::fillMediaCache()
23162338
{
23172339
infostream<<"Server: Calculating media file checksums"<<std::endl;

‎src/server.h

+3
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ class Server : public con::PeerHandler, public MapEventReceiver,
344344
bool sendModChannelMessage(const std::string &channel, const std::string &message);
345345
ModChannel *getModChannel(const std::string &channel);
346346

347+
// Send block to specific player only
348+
bool SendBlock(session_t peer_id, const v3s16 &blockpos);
349+
347350
// Bind address
348351
Address m_bind_addr;
349352

0 commit comments

Comments
 (0)
Please sign in to comment.