Skip to content

Commit cf64054

Browse files
committed
Implement adding velocity to player from Lua
The intended usecase is knockback, but there's potential for more.
1 parent b19400a commit cf64054

14 files changed

+105
-2
lines changed

doc/lua_api.txt

+8
Original file line numberDiff line numberDiff line change
@@ -5465,6 +5465,14 @@ This is basically a reference to a C++ `ServerActiveObject`
54655465
* `get_player_name()`: returns `""` if is not a player
54665466
* `get_player_velocity()`: returns `nil` if is not a player, otherwise a
54675467
table {x, y, z} representing the player's instantaneous velocity in nodes/s
5468+
* `add_player_velocity(vel)`
5469+
* Adds to player velocity, this happens client-side and only once.
5470+
* Does not apply during free_move.
5471+
* Note that since the player speed is normalized at each move step,
5472+
increasing e.g. Y velocity beyond what would usually be achieved
5473+
(see: physics overrides) will cause existing X/Z velocity to be reduced.
5474+
* Example: `add_player_velocity({x=0, y=6.5, z=0})` is equivalent to
5475+
pressing the jump key (assuming default settings)
54685476
* `get_look_dir()`: get camera direction as a unit vector
54695477
* `get_look_vertical()`: pitch in radians
54705478
* Angle ranges between -pi/2 and pi/2, which are straight up and down

src/client/client.h

+1
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
227227
void handleCommand_SrpBytesSandB(NetworkPacket *pkt);
228228
void handleCommand_FormspecPrepend(NetworkPacket *pkt);
229229
void handleCommand_CSMRestrictionFlags(NetworkPacket *pkt);
230+
void handleCommand_PlayerSpeed(NetworkPacket *pkt);
230231

231232
void ProcessData(NetworkPacket *pkt);
232233

src/client/localplayer.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
188188
// Copy parent position if local player is attached
189189
if (isAttached) {
190190
setPosition(overridePosition);
191+
added_velocity = v3f(); // ignored
191192
return;
192193
}
193194

@@ -201,9 +202,13 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
201202
if (noclip && free_move) {
202203
position += m_speed * dtime;
203204
setPosition(position);
205+
added_velocity = v3f(); // ignored
204206
return;
205207
}
206208

209+
m_speed += added_velocity;
210+
added_velocity = v3f();
211+
207212
/*
208213
Collision detection
209214
*/
@@ -782,6 +787,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
782787
if (isAttached) {
783788
setPosition(overridePosition);
784789
m_sneak_node_exists = false;
790+
added_velocity = v3f();
785791
return;
786792
}
787793

@@ -795,9 +801,13 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
795801
position += m_speed * dtime;
796802
setPosition(position);
797803
m_sneak_node_exists = false;
804+
added_velocity = v3f();
798805
return;
799806
}
800807

808+
m_speed += added_velocity;
809+
added_velocity = v3f();
810+
801811
/*
802812
Collision detection
803813
*/

src/client/localplayer.h

+6
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ class LocalPlayer : public Player
149149

150150
bool getAutojump() const { return m_autojump; }
151151

152+
inline void addVelocity(const v3f &vel)
153+
{
154+
added_velocity += vel;
155+
}
156+
152157
private:
153158
void accelerate(const v3f &target_speed, const f32 max_increase_H,
154159
const f32 max_increase_V, const bool use_pitch);
@@ -194,6 +199,7 @@ class LocalPlayer : public Player
194199
float m_zoom_fov = 0.0f;
195200
bool m_autojump = false;
196201
float m_autojump_time = 0.0f;
202+
v3f added_velocity = v3f(0.0f, 0.0f, 0.0f); // cleared on each move()
197203

198204
GenericCAO *m_cao = nullptr;
199205
Client *m_client;

src/content_sao.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,7 @@ void PlayerSAO::step(float dtime, bool send_recommended)
10911091
m_time_from_last_teleport += dtime;
10921092
m_time_from_last_punch += dtime;
10931093
m_nocheat_dig_time += dtime;
1094+
m_max_speed_override_time = MYMAX(m_max_speed_override_time - dtime, 0.0f);
10941095

10951096
// Each frame, parent position is copied if the object is attached,
10961097
// otherwise it's calculated normally.
@@ -1412,6 +1413,19 @@ std::string PlayerSAO::getPropertyPacket()
14121413
return gob_cmd_set_properties(m_prop);
14131414
}
14141415

1416+
void PlayerSAO::setMaxSpeedOverride(const v3f &vel)
1417+
{
1418+
if (m_max_speed_override_time == 0.0f)
1419+
m_max_speed_override = vel;
1420+
else
1421+
m_max_speed_override += vel;
1422+
if (m_player) {
1423+
float accel = MYMIN(m_player->movement_acceleration_default,
1424+
m_player->movement_acceleration_air);
1425+
m_max_speed_override_time = m_max_speed_override.getLength() / accel / BS;
1426+
}
1427+
}
1428+
14151429
bool PlayerSAO::checkMovementCheat()
14161430
{
14171431
if (isAttached() || m_is_singleplayer ||
@@ -1431,6 +1445,14 @@ bool PlayerSAO::checkMovementCheat()
14311445
too, and much more lightweight.
14321446
*/
14331447

1448+
float override_max_H, override_max_V;
1449+
if (m_max_speed_override_time > 0.0f) {
1450+
override_max_H = MYMAX(fabs(m_max_speed_override.X), fabs(m_max_speed_override.Z));
1451+
override_max_V = fabs(m_max_speed_override.Y);
1452+
} else {
1453+
override_max_H = override_max_V = 0.0f;
1454+
}
1455+
14341456
float player_max_walk = 0; // horizontal movement
14351457
float player_max_jump = 0; // vertical upwards movement
14361458

@@ -1439,10 +1461,13 @@ bool PlayerSAO::checkMovementCheat()
14391461
else
14401462
player_max_walk = m_player->movement_speed_walk; // Normal speed
14411463
player_max_walk *= m_physics_override_speed;
1464+
player_max_walk = MYMAX(player_max_walk, override_max_H);
1465+
14421466
player_max_jump = m_player->movement_speed_jump * m_physics_override_jump;
14431467
// FIXME: Bouncy nodes cause practically unbound increase in Y speed,
14441468
// until this can be verified correctly, tolerate higher jumping speeds
14451469
player_max_jump *= 2.0;
1470+
player_max_jump = MYMAX(player_max_jump, override_max_V);
14461471

14471472
// Don't divide by zero!
14481473
if (player_max_walk < 0.0001f)

src/content_sao.h

+3
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ class PlayerSAO : public UnitSAO
322322
{
323323
return m_dig_pool;
324324
}
325+
void setMaxSpeedOverride(const v3f &vel);
325326
// Returns true if cheated
326327
bool checkMovementCheat();
327328

@@ -361,6 +362,8 @@ class PlayerSAO : public UnitSAO
361362
float m_time_from_last_punch = 0.0f;
362363
v3s16 m_nocheat_dig_pos = v3s16(32767, 32767, 32767);
363364
float m_nocheat_dig_time = 0.0f;
365+
float m_max_speed_override_time = 0.0f;
366+
v3f m_max_speed_override = v3f(0.0f, 0.0f, 0.0f);
364367

365368
// Timers
366369
IntervalLimiter m_breathing_interval;

src/network/clientopcodes.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
6767
null_command_handler,
6868
{ "TOCLIENT_TIME_OF_DAY", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_TimeOfDay }, // 0x29
6969
{ "TOCLIENT_CSM_RESTRICTION_FLAGS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CSMRestrictionFlags }, // 0x2A
70-
null_command_handler,
70+
{ "TOCLIENT_PLAYER_SPEED", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_PlayerSpeed }, // 0x2B
7171
null_command_handler,
7272
null_command_handler,
7373
null_command_handler,

src/network/clientpackethandler.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -1383,6 +1383,17 @@ void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt)
13831383
loadMods();
13841384
}
13851385

1386+
void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
1387+
{
1388+
v3f added_vel;
1389+
1390+
*pkt >> added_vel;
1391+
1392+
LocalPlayer *player = m_env.getLocalPlayer();
1393+
assert(player != NULL);
1394+
player->addVelocity(added_vel);
1395+
}
1396+
13861397
/*
13871398
* Mod channels
13881399
*/

src/network/networkprotocol.h

+6
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
194194
New network float format
195195
ContentFeatures version 13
196196
Add full Euler rotations instead of just yaw
197+
Add TOCLIENT_PLAYER_SPEED
197198
*/
198199

199200
#define LATEST_PROTOCOL_VERSION 37
@@ -295,6 +296,11 @@ enum ToClientCommand
295296
u32 CSMRestrictionFlags byteflag
296297
*/
297298

299+
TOCLIENT_PLAYER_SPEED = 0x2B,
300+
/*
301+
v3f added_vel
302+
*/
303+
298304
// (oops, there is some gap here)
299305

300306
TOCLIENT_CHAT_MESSAGE = 0x2F,

src/network/serveropcodes.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
156156
null_command_factory,
157157
{ "TOCLIENT_TIME_OF_DAY", 0, true }, // 0x29
158158
{ "TOCLIENT_CSM_RESTRICTION_FLAGS", 0, true }, // 0x2A
159-
null_command_factory,
159+
{ "TOCLIENT_PLAYER_SPEED", 0, true }, // 0x2B
160160
null_command_factory,
161161
null_command_factory,
162162
null_command_factory,

src/script/lua_api/l_object.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,27 @@ int ObjectRef::l_get_player_velocity(lua_State *L)
10921092
return 1;
10931093
}
10941094

1095+
// add_player_velocity(self, {x=num, y=num, z=num})
1096+
int ObjectRef::l_add_player_velocity(lua_State *L)
1097+
{
1098+
NO_MAP_LOCK_REQUIRED;
1099+
ObjectRef *ref = checkobject(L, 1);
1100+
v3f vel = checkFloatPos(L, 2);
1101+
1102+
RemotePlayer *player = getplayer(ref);
1103+
PlayerSAO *co = getplayersao(ref);
1104+
if (!player || !co)
1105+
return 0;
1106+
1107+
session_t peer_id = player->getPeerId();
1108+
if (peer_id == PEER_ID_INEXISTENT)
1109+
return 0;
1110+
// Do it
1111+
co->setMaxSpeedOverride(vel);
1112+
getServer(L)->SendPlayerSpeed(peer_id, vel);
1113+
return 0;
1114+
}
1115+
10951116
// get_look_dir(self)
10961117
int ObjectRef::l_get_look_dir(lua_State *L)
10971118
{
@@ -1931,6 +1952,7 @@ luaL_Reg ObjectRef::methods[] = {
19311952
luamethod(ObjectRef, is_player_connected),
19321953
luamethod(ObjectRef, get_player_name),
19331954
luamethod(ObjectRef, get_player_velocity),
1955+
luamethod(ObjectRef, add_player_velocity),
19341956
luamethod(ObjectRef, get_look_dir),
19351957
luamethod(ObjectRef, get_look_pitch),
19361958
luamethod(ObjectRef, get_look_yaw),

src/script/lua_api/l_object.h

+3
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ class ObjectRef : public ModApiBase {
212212
// get_player_velocity(self)
213213
static int l_get_player_velocity(lua_State *L);
214214

215+
// add_player_velocity(self, {x=num, y=num, z=num})
216+
static int l_add_player_velocity(lua_State *L);
217+
215218
// get_look_dir(self)
216219
static int l_get_look_dir(lua_State *L);
217220

src/server.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,13 @@ void Server::SendCSMRestrictionFlags(session_t peer_id)
19581958
Send(&pkt);
19591959
}
19601960

1961+
void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
1962+
{
1963+
NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
1964+
pkt << added_vel;
1965+
Send(&pkt);
1966+
}
1967+
19611968
s32 Server::playSound(const SimpleSoundSpec &spec,
19621969
const ServerSoundParams &params)
19631970
{

src/server.h

+1
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ class Server : public con::PeerHandler, public MapEventReceiver,
335335
void SendPlayerBreath(PlayerSAO *sao);
336336
void SendInventory(PlayerSAO* playerSAO);
337337
void SendMovePlayer(session_t peer_id);
338+
void SendPlayerSpeed(session_t peer_id, const v3f &added_vel);
338339

339340
virtual bool registerModStorage(ModMetadata *storage);
340341
virtual void unregisterModStorage(const std::string &name);

0 commit comments

Comments
 (0)