Skip to content

Commit 22ef4c8

Browse files
authored
Expose analog joystick input to the Lua API (luanti-org#14348)
1 parent 6569fdd commit 22ef4c8

13 files changed

+127
-83
lines changed

doc/lua_api.md

+10-4
Original file line numberDiff line numberDiff line change
@@ -8249,12 +8249,18 @@ child will follow movement and rotation of that bone.
82498249
bgcolor[], any non-style elements (eg: label) may result in weird behavior.
82508250
* Only affects formspecs shown after this is called.
82518251
* `get_formspec_prepend()`: returns a formspec string.
8252-
* `get_player_control()`: returns table with player pressed keys
8253-
* The table consists of fields with the following boolean values
8254-
representing the pressed keys: `up`, `down`, `left`, `right`, `jump`,
8255-
`aux1`, `sneak`, `dig`, `place`, `LMB`, `RMB`, and `zoom`.
8252+
* `get_player_control()`: returns table with player input
8253+
* The table contains the following boolean fields representing the pressed
8254+
keys: `up`, `down`, `left`, `right`, `jump`, `aux1`, `sneak`, `dig`,
8255+
`place`, `LMB`, `RMB` and `zoom`.
82568256
* The fields `LMB` and `RMB` are equal to `dig` and `place` respectively,
82578257
and exist only to preserve backwards compatibility.
8258+
* The table also contains the fields `movement_x` and `movement_y`.
8259+
* They represent the movement of the player. Values are numbers in the
8260+
range [-1.0,+1.0].
8261+
* They take both keyboard and joystick input into account.
8262+
* You should prefer them over `up`, `down`, `left` and `right` to
8263+
support different input methods correctly.
82588264
* Returns an empty table `{}` if the object is not a player.
82598265
* `get_player_control_bits()`: returns integer with bit packed player pressed
82608266
keys.

src/client/client.cpp

+14-3
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ void Client::Send(NetworkPacket* pkt)
10341034
m_con->Send(PEER_ID_SERVER, scf.channel, pkt, scf.reliable);
10351035
}
10361036

1037-
// Will fill up 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1 bytes
1037+
// Will fill up 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1 + 4 + 4 bytes
10381038
void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *pkt, bool camera_inverted)
10391039
{
10401040
v3f pf = myplayer->getPosition() * 100;
@@ -1046,6 +1046,8 @@ void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *
10461046
u8 fov = std::fmin(255.0f, clientMap->getCameraFov() * 80.0f);
10471047
u8 wanted_range = std::fmin(255.0f,
10481048
std::ceil(clientMap->getWantedRange() * (1.0f / MAP_BLOCKSIZE)));
1049+
f32 movement_speed = myplayer->control.movement_speed;
1050+
f32 movement_dir = myplayer->control.movement_direction;
10491051

10501052
v3s32 position(pf.X, pf.Y, pf.Z);
10511053
v3s32 speed(sf.X, sf.Y, sf.Z);
@@ -1060,10 +1062,13 @@ void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *
10601062
[12+12+4+4+4] u8 fov*80
10611063
[12+12+4+4+4+1] u8 ceil(wanted_range / MAP_BLOCKSIZE)
10621064
[12+12+4+4+4+1+1] u8 camera_inverted (bool)
1065+
[12+12+4+4+4+1+1+1] f32 movement_speed
1066+
[12+12+4+4+4+1+1+1+4] f32 movement_direction
10631067
*/
10641068
*pkt << position << speed << pitch << yaw << keyPressed;
10651069
*pkt << fov << wanted_range;
10661070
*pkt << camera_inverted;
1071+
*pkt << movement_speed << movement_dir;
10671072
}
10681073

10691074
void Client::interact(InteractAction action, const PointedThing& pointed)
@@ -1397,6 +1402,8 @@ void Client::sendPlayerPos()
13971402

13981403
u32 keyPressed = player->control.getKeysPressed();
13991404
bool camera_inverted = m_camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT;
1405+
f32 movement_speed = player->control.movement_speed;
1406+
f32 movement_dir = player->control.movement_direction;
14001407

14011408
if (
14021409
player->last_position == player->getPosition() &&
@@ -1406,7 +1413,9 @@ void Client::sendPlayerPos()
14061413
player->last_keyPressed == keyPressed &&
14071414
player->last_camera_fov == camera_fov &&
14081415
player->last_camera_inverted == camera_inverted &&
1409-
player->last_wanted_range == wanted_range)
1416+
player->last_wanted_range == wanted_range &&
1417+
player->last_movement_speed == movement_speed &&
1418+
player->last_movement_dir == movement_dir)
14101419
return;
14111420

14121421
player->last_position = player->getPosition();
@@ -1417,8 +1426,10 @@ void Client::sendPlayerPos()
14171426
player->last_camera_fov = camera_fov;
14181427
player->last_camera_inverted = camera_inverted;
14191428
player->last_wanted_range = wanted_range;
1429+
player->last_movement_speed = movement_speed;
1430+
player->last_movement_dir = movement_dir;
14201431

1421-
NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1);
1432+
NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1 + 4 + 4);
14221433

14231434
writePlayerPos(player, &map, &pkt, camera_inverted);
14241435

src/client/game.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -2752,9 +2752,10 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
27522752
isKeyDown(KeyType::PLACE),
27532753
cam.camera_pitch,
27542754
cam.camera_yaw,
2755-
input->getMovementSpeed(),
2756-
input->getMovementDirection()
2755+
input->getJoystickSpeed(),
2756+
input->getJoystickDirection()
27572757
);
2758+
control.setMovementFromKeys();
27582759

27592760
// autoforward if set: move at maximum speed
27602761
if (player->getPlayerSettings().continuous_forward &&

src/client/inputhandler.cpp

+12-55
Original file line numberDiff line numberDiff line change
@@ -220,48 +220,19 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
220220
/*
221221
* RealInputHandler
222222
*/
223-
float RealInputHandler::getMovementSpeed()
223+
float RealInputHandler::getJoystickSpeed()
224224
{
225-
bool f = m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]),
226-
b = m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]),
227-
l = m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]),
228-
r = m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]);
229-
if (f || b || l || r)
230-
{
231-
// if contradictory keys pressed, stay still
232-
if (f && b && l && r)
233-
return 0.0f;
234-
else if (f && b && !l && !r)
235-
return 0.0f;
236-
else if (!f && !b && l && r)
237-
return 0.0f;
238-
return 1.0f; // If there is a keyboard event, assume maximum speed
239-
}
240-
if (g_touchcontrols && g_touchcontrols->getMovementSpeed())
241-
return g_touchcontrols->getMovementSpeed();
225+
if (g_touchcontrols && g_touchcontrols->getJoystickSpeed())
226+
return g_touchcontrols->getJoystickSpeed();
242227
return joystick.getMovementSpeed();
243228
}
244229

245-
float RealInputHandler::getMovementDirection()
230+
float RealInputHandler::getJoystickDirection()
246231
{
247-
float x = 0, z = 0;
248-
249-
/* Check keyboard for input */
250-
if (m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]))
251-
z += 1;
252-
if (m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]))
253-
z -= 1;
254-
if (m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]))
255-
x += 1;
256-
if (m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]))
257-
x -= 1;
258-
259-
if (x != 0 || z != 0) /* If there is a keyboard event, it takes priority */
260-
return std::atan2(x, z);
261-
// `getMovementDirection() == 0` means forward, so we cannot use
262-
// `getMovementDirection()` as a condition.
263-
else if (g_touchcontrols && g_touchcontrols->getMovementSpeed())
264-
return g_touchcontrols->getMovementDirection();
232+
// `getJoystickDirection() == 0` means forward, so we cannot use
233+
// `getJoystickDirection()` as a condition.
234+
if (g_touchcontrols && g_touchcontrols->getJoystickSpeed())
235+
return g_touchcontrols->getJoystickDirection();
265236
return joystick.getMovementDirection();
266237
}
267238

@@ -320,25 +291,11 @@ void RandomInputHandler::step(float dtime)
320291
counterMovement -= dtime;
321292
if (counterMovement < 0.0) {
322293
counterMovement = 0.1 * Rand(1, 40);
323-
movementSpeed = Rand(0,100)*0.01;
324-
movementDirection = Rand(-100, 100)*0.01 * M_PI;
294+
joystickSpeed = Rand(0,100)*0.01;
295+
joystickDirection = Rand(-100, 100)*0.01 * M_PI;
325296
}
326297
} else {
327-
bool f = keydown[keycache.key[KeyType::FORWARD]],
328-
l = keydown[keycache.key[KeyType::LEFT]];
329-
if (f || l) {
330-
movementSpeed = 1.0f;
331-
if (f && !l)
332-
movementDirection = 0.0;
333-
else if (!f && l)
334-
movementDirection = -M_PI_2;
335-
else if (f && l)
336-
movementDirection = -M_PI_4;
337-
else
338-
movementDirection = 0.0;
339-
} else {
340-
movementSpeed = 0.0;
341-
movementDirection = 0.0;
342-
}
298+
joystickSpeed = 0.0f;
299+
joystickDirection = 0.0f;
343300
}
344301
}

src/client/inputhandler.h

+8-8
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,8 @@ class InputHandler
247247
virtual bool wasKeyReleased(GameKeyType k) = 0;
248248
virtual bool cancelPressed() = 0;
249249

250-
virtual float getMovementSpeed() = 0;
251-
virtual float getMovementDirection() = 0;
250+
virtual float getJoystickSpeed() = 0;
251+
virtual float getJoystickDirection() = 0;
252252

253253
virtual void clearWasKeyPressed() {}
254254
virtual void clearWasKeyReleased() {}
@@ -304,9 +304,9 @@ class RealInputHandler final : public InputHandler
304304
return m_receiver->WasKeyReleased(keycache.key[k]) || joystick.wasKeyReleased(k);
305305
}
306306

307-
virtual float getMovementSpeed();
307+
virtual float getJoystickSpeed();
308308

309-
virtual float getMovementDirection();
309+
virtual float getJoystickDirection();
310310

311311
virtual bool cancelPressed()
312312
{
@@ -388,8 +388,8 @@ class RandomInputHandler final : public InputHandler
388388
virtual bool wasKeyPressed(GameKeyType k) { return false; }
389389
virtual bool wasKeyReleased(GameKeyType k) { return false; }
390390
virtual bool cancelPressed() { return false; }
391-
virtual float getMovementSpeed() { return movementSpeed; }
392-
virtual float getMovementDirection() { return movementDirection; }
391+
virtual float getJoystickSpeed() { return joystickSpeed; }
392+
virtual float getJoystickDirection() { return joystickDirection; }
393393
virtual v2s32 getMousePos() { return mousepos; }
394394
virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
395395

@@ -403,6 +403,6 @@ class RandomInputHandler final : public InputHandler
403403
KeyList keydown;
404404
v2s32 mousepos;
405405
v2s32 mousespeed;
406-
float movementSpeed;
407-
float movementDirection;
406+
float joystickSpeed;
407+
float joystickDirection;
408408
};

src/client/localplayer.h

+2
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ class LocalPlayer : public Player
105105
u8 last_camera_fov = 0;
106106
u8 last_wanted_range = 0;
107107
bool last_camera_inverted = false;
108+
f32 last_movement_speed = 0.0f;
109+
f32 last_movement_dir = 0.0f;
108110

109111
float camera_impact = 0.0f;
110112

src/gui/touchcontrols.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ class TouchControls
163163
*/
164164
line3d<f32> getShootline() { return m_shootline; }
165165

166-
float getMovementDirection() { return m_joystick_direction; }
167-
float getMovementSpeed() { return m_joystick_speed; }
166+
float getJoystickDirection() { return m_joystick_direction; }
167+
float getJoystickSpeed() { return m_joystick_speed; }
168168

169169
void step(float dtime);
170170
inline void setUseCrosshair(bool use_crosshair) { m_draw_crosshair = use_crosshair; }

src/network/networkprotocol.h

+2
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,8 @@ enum ToServerCommand : u16
962962
[2+12+12+4+4+4] u8 fov*80
963963
[2+12+12+4+4+4+1] u8 ceil(wanted_range / MAP_BLOCKSIZE)
964964
[2+12+12+4+4+4+1+1] u8 camera_inverted (bool)
965+
[2+12+12+4+4+4+1+1+1] f32 movement_speed
966+
[2+12+12+4+4+4+1+1+1+4] f32 movement_direction
965967
966968
*/
967969

src/network/serverpackethandler.cpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -477,12 +477,24 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
477477
u8 bits = 0; // bits instead of bool so it is extensible later
478478

479479
*pkt >> keyPressed;
480+
player->control.unpackKeysPressed(keyPressed);
481+
480482
*pkt >> f32fov;
481483
fov = (f32)f32fov / 80.0f;
482484
*pkt >> wanted_range;
485+
483486
if (pkt->getRemainingBytes() >= 1)
484487
*pkt >> bits;
485488

489+
if (pkt->getRemainingBytes() >= 8) {
490+
*pkt >> player->control.movement_speed;
491+
*pkt >> player->control.movement_direction;
492+
} else {
493+
player->control.movement_speed = 0.0f;
494+
player->control.movement_direction = 0.0f;
495+
player->control.setMovementFromKeys();
496+
}
497+
486498
v3f position((f32)ps.X / 100.0f, (f32)ps.Y / 100.0f, (f32)ps.Z / 100.0f);
487499
v3f speed((f32)ss.X / 100.0f, (f32)ss.Y / 100.0f, (f32)ss.Z / 100.0f);
488500

@@ -501,8 +513,6 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
501513
playersao->setWantedRange(wanted_range);
502514
playersao->setCameraInverted(bits & 0x01);
503515

504-
player->control.unpackKeysPressed(keyPressed);
505-
506516
if (playersao->checkMovementCheat()) {
507517
// Call callbacks
508518
m_script->on_cheat(playersao, "moved_too_fast");

src/player.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,42 @@ u16 Player::getMaxHotbarItemcount()
173173
return mainlist ? std::min(mainlist->getSize(), (u32) hud_hotbar_itemcount) : 0;
174174
}
175175

176+
void PlayerControl::setMovementFromKeys()
177+
{
178+
bool a_up = direction_keys & (1 << 0),
179+
a_down = direction_keys & (1 << 1),
180+
a_left = direction_keys & (1 << 2),
181+
a_right = direction_keys & (1 << 3);
182+
183+
if (a_up || a_down || a_left || a_right) {
184+
// if contradictory keys pressed, stay still
185+
if (a_up && a_down && a_left && a_right)
186+
movement_speed = 0.0f;
187+
else if (a_up && a_down && !a_left && !a_right)
188+
movement_speed = 0.0f;
189+
else if (!a_up && !a_down && a_left && a_right)
190+
movement_speed = 0.0f;
191+
else
192+
// If there is a keyboard event, assume maximum speed
193+
movement_speed = 1.0f;
194+
}
195+
196+
// Check keyboard for input
197+
float x = 0, y = 0;
198+
if (a_up)
199+
y += 1;
200+
if (a_down)
201+
y -= 1;
202+
if (a_left)
203+
x -= 1;
204+
if (a_right)
205+
x += 1;
206+
207+
if (x != 0 || y != 0)
208+
// If there is a keyboard event, it takes priority
209+
movement_direction = std::atan2(x, y);
210+
}
211+
176212
#ifndef SERVER
177213

178214
u32 PlayerControl::getKeysPressed() const
@@ -231,6 +267,11 @@ void PlayerControl::unpackKeysPressed(u32 keypress_bits)
231267
zoom = keypress_bits & (1 << 9);
232268
}
233269

270+
v2f PlayerControl::getMovement() const
271+
{
272+
return v2f(std::sin(movement_direction), std::cos(movement_direction)) * movement_speed;
273+
}
274+
234275
static auto tie(const PlayerPhysicsOverride &o)
235276
{
236277
// Make sure to add new members to this list!

src/player.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ struct PlayerControl
8686
movement_direction = a_movement_direction;
8787
}
8888

89+
// Sets movement_speed and movement_direction according to direction_keys
90+
// if direction_keys != 0, otherwise leaves them unchanged to preserve
91+
// joystick input.
92+
void setMovementFromKeys();
93+
8994
#ifndef SERVER
9095
// For client use
9196
u32 getKeysPressed() const;
@@ -94,6 +99,7 @@ struct PlayerControl
9499

95100
// For server use
96101
void unpackKeysPressed(u32 keypress_bits);
102+
v2f getMovement() const;
97103

98104
u8 direction_keys = 0;
99105
bool jump = false;
@@ -102,7 +108,7 @@ struct PlayerControl
102108
bool zoom = false;
103109
bool dig = false;
104110
bool place = false;
105-
// Note: These four are NOT available on the server
111+
// Note: These two are NOT available on the server
106112
float pitch = 0.0f;
107113
float yaw = 0.0f;
108114
float movement_speed = 0.0f;

src/script/lua_api/l_localplayer.cpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,13 @@ int LuaLocalPlayer::l_get_control(lua_State *L)
260260
set("zoom", c.zoom);
261261
set("dig", c.dig);
262262
set("place", c.place);
263-
// Player movement in polar coordinates and non-binary speed
264-
lua_pushnumber(L, c.movement_speed);
265-
lua_setfield(L, -2, "movement_speed");
266-
lua_pushnumber(L, c.movement_direction);
267-
lua_setfield(L, -2, "movement_direction");
268-
// Provide direction keys to ensure compatibility
263+
264+
v2f movement = c.getMovement();
265+
lua_pushnumber(L, movement.X);
266+
lua_setfield(L, -2, "movement_x");
267+
lua_pushnumber(L, movement.Y);
268+
lua_setfield(L, -2, "movement_y");
269+
269270
set("up", c.direction_keys & (1 << 0));
270271
set("down", c.direction_keys & (1 << 1));
271272
set("left", c.direction_keys & (1 << 2));

0 commit comments

Comments
 (0)