mirror of
https://github.com/minetest/minetest.git
synced 2024-12-21 21:52:25 +01:00
Expose analog joystick input to the Lua API (#14348)
This commit is contained in:
parent
6569fdd4d1
commit
22ef4c8be1
@ -8249,12 +8249,18 @@ child will follow movement and rotation of that bone.
|
||||
bgcolor[], any non-style elements (eg: label) may result in weird behavior.
|
||||
* Only affects formspecs shown after this is called.
|
||||
* `get_formspec_prepend()`: returns a formspec string.
|
||||
* `get_player_control()`: returns table with player pressed keys
|
||||
* The table consists of fields with the following boolean values
|
||||
representing the pressed keys: `up`, `down`, `left`, `right`, `jump`,
|
||||
`aux1`, `sneak`, `dig`, `place`, `LMB`, `RMB`, and `zoom`.
|
||||
* `get_player_control()`: returns table with player input
|
||||
* The table contains the following boolean fields representing the pressed
|
||||
keys: `up`, `down`, `left`, `right`, `jump`, `aux1`, `sneak`, `dig`,
|
||||
`place`, `LMB`, `RMB` and `zoom`.
|
||||
* The fields `LMB` and `RMB` are equal to `dig` and `place` respectively,
|
||||
and exist only to preserve backwards compatibility.
|
||||
* The table also contains the fields `movement_x` and `movement_y`.
|
||||
* They represent the movement of the player. Values are numbers in the
|
||||
range [-1.0,+1.0].
|
||||
* They take both keyboard and joystick input into account.
|
||||
* You should prefer them over `up`, `down`, `left` and `right` to
|
||||
support different input methods correctly.
|
||||
* Returns an empty table `{}` if the object is not a player.
|
||||
* `get_player_control_bits()`: returns integer with bit packed player pressed
|
||||
keys.
|
||||
|
@ -1034,7 +1034,7 @@ void Client::Send(NetworkPacket* pkt)
|
||||
m_con->Send(PEER_ID_SERVER, scf.channel, pkt, scf.reliable);
|
||||
}
|
||||
|
||||
// Will fill up 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1 bytes
|
||||
// Will fill up 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1 + 4 + 4 bytes
|
||||
void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *pkt, bool camera_inverted)
|
||||
{
|
||||
v3f pf = myplayer->getPosition() * 100;
|
||||
@ -1046,6 +1046,8 @@ void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *
|
||||
u8 fov = std::fmin(255.0f, clientMap->getCameraFov() * 80.0f);
|
||||
u8 wanted_range = std::fmin(255.0f,
|
||||
std::ceil(clientMap->getWantedRange() * (1.0f / MAP_BLOCKSIZE)));
|
||||
f32 movement_speed = myplayer->control.movement_speed;
|
||||
f32 movement_dir = myplayer->control.movement_direction;
|
||||
|
||||
v3s32 position(pf.X, pf.Y, pf.Z);
|
||||
v3s32 speed(sf.X, sf.Y, sf.Z);
|
||||
@ -1060,10 +1062,13 @@ void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *
|
||||
[12+12+4+4+4] u8 fov*80
|
||||
[12+12+4+4+4+1] u8 ceil(wanted_range / MAP_BLOCKSIZE)
|
||||
[12+12+4+4+4+1+1] u8 camera_inverted (bool)
|
||||
[12+12+4+4+4+1+1+1] f32 movement_speed
|
||||
[12+12+4+4+4+1+1+1+4] f32 movement_direction
|
||||
*/
|
||||
*pkt << position << speed << pitch << yaw << keyPressed;
|
||||
*pkt << fov << wanted_range;
|
||||
*pkt << camera_inverted;
|
||||
*pkt << movement_speed << movement_dir;
|
||||
}
|
||||
|
||||
void Client::interact(InteractAction action, const PointedThing& pointed)
|
||||
@ -1397,6 +1402,8 @@ void Client::sendPlayerPos()
|
||||
|
||||
u32 keyPressed = player->control.getKeysPressed();
|
||||
bool camera_inverted = m_camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT;
|
||||
f32 movement_speed = player->control.movement_speed;
|
||||
f32 movement_dir = player->control.movement_direction;
|
||||
|
||||
if (
|
||||
player->last_position == player->getPosition() &&
|
||||
@ -1406,7 +1413,9 @@ void Client::sendPlayerPos()
|
||||
player->last_keyPressed == keyPressed &&
|
||||
player->last_camera_fov == camera_fov &&
|
||||
player->last_camera_inverted == camera_inverted &&
|
||||
player->last_wanted_range == wanted_range)
|
||||
player->last_wanted_range == wanted_range &&
|
||||
player->last_movement_speed == movement_speed &&
|
||||
player->last_movement_dir == movement_dir)
|
||||
return;
|
||||
|
||||
player->last_position = player->getPosition();
|
||||
@ -1417,8 +1426,10 @@ void Client::sendPlayerPos()
|
||||
player->last_camera_fov = camera_fov;
|
||||
player->last_camera_inverted = camera_inverted;
|
||||
player->last_wanted_range = wanted_range;
|
||||
player->last_movement_speed = movement_speed;
|
||||
player->last_movement_dir = movement_dir;
|
||||
|
||||
NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1);
|
||||
NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1 + 4 + 4);
|
||||
|
||||
writePlayerPos(player, &map, &pkt, camera_inverted);
|
||||
|
||||
|
@ -2752,9 +2752,10 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
|
||||
isKeyDown(KeyType::PLACE),
|
||||
cam.camera_pitch,
|
||||
cam.camera_yaw,
|
||||
input->getMovementSpeed(),
|
||||
input->getMovementDirection()
|
||||
input->getJoystickSpeed(),
|
||||
input->getJoystickDirection()
|
||||
);
|
||||
control.setMovementFromKeys();
|
||||
|
||||
// autoforward if set: move at maximum speed
|
||||
if (player->getPlayerSettings().continuous_forward &&
|
||||
|
@ -220,48 +220,19 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
|
||||
/*
|
||||
* RealInputHandler
|
||||
*/
|
||||
float RealInputHandler::getMovementSpeed()
|
||||
float RealInputHandler::getJoystickSpeed()
|
||||
{
|
||||
bool f = m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]),
|
||||
b = m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]),
|
||||
l = m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]),
|
||||
r = m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]);
|
||||
if (f || b || l || r)
|
||||
{
|
||||
// if contradictory keys pressed, stay still
|
||||
if (f && b && l && r)
|
||||
return 0.0f;
|
||||
else if (f && b && !l && !r)
|
||||
return 0.0f;
|
||||
else if (!f && !b && l && r)
|
||||
return 0.0f;
|
||||
return 1.0f; // If there is a keyboard event, assume maximum speed
|
||||
}
|
||||
if (g_touchcontrols && g_touchcontrols->getMovementSpeed())
|
||||
return g_touchcontrols->getMovementSpeed();
|
||||
if (g_touchcontrols && g_touchcontrols->getJoystickSpeed())
|
||||
return g_touchcontrols->getJoystickSpeed();
|
||||
return joystick.getMovementSpeed();
|
||||
}
|
||||
|
||||
float RealInputHandler::getMovementDirection()
|
||||
float RealInputHandler::getJoystickDirection()
|
||||
{
|
||||
float x = 0, z = 0;
|
||||
|
||||
/* Check keyboard for input */
|
||||
if (m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]))
|
||||
z += 1;
|
||||
if (m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]))
|
||||
z -= 1;
|
||||
if (m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]))
|
||||
x += 1;
|
||||
if (m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]))
|
||||
x -= 1;
|
||||
|
||||
if (x != 0 || z != 0) /* If there is a keyboard event, it takes priority */
|
||||
return std::atan2(x, z);
|
||||
// `getMovementDirection() == 0` means forward, so we cannot use
|
||||
// `getMovementDirection()` as a condition.
|
||||
else if (g_touchcontrols && g_touchcontrols->getMovementSpeed())
|
||||
return g_touchcontrols->getMovementDirection();
|
||||
// `getJoystickDirection() == 0` means forward, so we cannot use
|
||||
// `getJoystickDirection()` as a condition.
|
||||
if (g_touchcontrols && g_touchcontrols->getJoystickSpeed())
|
||||
return g_touchcontrols->getJoystickDirection();
|
||||
return joystick.getMovementDirection();
|
||||
}
|
||||
|
||||
@ -320,25 +291,11 @@ void RandomInputHandler::step(float dtime)
|
||||
counterMovement -= dtime;
|
||||
if (counterMovement < 0.0) {
|
||||
counterMovement = 0.1 * Rand(1, 40);
|
||||
movementSpeed = Rand(0,100)*0.01;
|
||||
movementDirection = Rand(-100, 100)*0.01 * M_PI;
|
||||
joystickSpeed = Rand(0,100)*0.01;
|
||||
joystickDirection = Rand(-100, 100)*0.01 * M_PI;
|
||||
}
|
||||
} else {
|
||||
bool f = keydown[keycache.key[KeyType::FORWARD]],
|
||||
l = keydown[keycache.key[KeyType::LEFT]];
|
||||
if (f || l) {
|
||||
movementSpeed = 1.0f;
|
||||
if (f && !l)
|
||||
movementDirection = 0.0;
|
||||
else if (!f && l)
|
||||
movementDirection = -M_PI_2;
|
||||
else if (f && l)
|
||||
movementDirection = -M_PI_4;
|
||||
else
|
||||
movementDirection = 0.0;
|
||||
} else {
|
||||
movementSpeed = 0.0;
|
||||
movementDirection = 0.0;
|
||||
}
|
||||
joystickSpeed = 0.0f;
|
||||
joystickDirection = 0.0f;
|
||||
}
|
||||
}
|
||||
|
@ -247,8 +247,8 @@ public:
|
||||
virtual bool wasKeyReleased(GameKeyType k) = 0;
|
||||
virtual bool cancelPressed() = 0;
|
||||
|
||||
virtual float getMovementSpeed() = 0;
|
||||
virtual float getMovementDirection() = 0;
|
||||
virtual float getJoystickSpeed() = 0;
|
||||
virtual float getJoystickDirection() = 0;
|
||||
|
||||
virtual void clearWasKeyPressed() {}
|
||||
virtual void clearWasKeyReleased() {}
|
||||
@ -304,9 +304,9 @@ public:
|
||||
return m_receiver->WasKeyReleased(keycache.key[k]) || joystick.wasKeyReleased(k);
|
||||
}
|
||||
|
||||
virtual float getMovementSpeed();
|
||||
virtual float getJoystickSpeed();
|
||||
|
||||
virtual float getMovementDirection();
|
||||
virtual float getJoystickDirection();
|
||||
|
||||
virtual bool cancelPressed()
|
||||
{
|
||||
@ -388,8 +388,8 @@ public:
|
||||
virtual bool wasKeyPressed(GameKeyType k) { return false; }
|
||||
virtual bool wasKeyReleased(GameKeyType k) { return false; }
|
||||
virtual bool cancelPressed() { return false; }
|
||||
virtual float getMovementSpeed() { return movementSpeed; }
|
||||
virtual float getMovementDirection() { return movementDirection; }
|
||||
virtual float getJoystickSpeed() { return joystickSpeed; }
|
||||
virtual float getJoystickDirection() { return joystickDirection; }
|
||||
virtual v2s32 getMousePos() { return mousepos; }
|
||||
virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
|
||||
|
||||
@ -403,6 +403,6 @@ private:
|
||||
KeyList keydown;
|
||||
v2s32 mousepos;
|
||||
v2s32 mousespeed;
|
||||
float movementSpeed;
|
||||
float movementDirection;
|
||||
float joystickSpeed;
|
||||
float joystickDirection;
|
||||
};
|
||||
|
@ -105,6 +105,8 @@ public:
|
||||
u8 last_camera_fov = 0;
|
||||
u8 last_wanted_range = 0;
|
||||
bool last_camera_inverted = false;
|
||||
f32 last_movement_speed = 0.0f;
|
||||
f32 last_movement_dir = 0.0f;
|
||||
|
||||
float camera_impact = 0.0f;
|
||||
|
||||
|
@ -163,8 +163,8 @@ public:
|
||||
*/
|
||||
line3d<f32> getShootline() { return m_shootline; }
|
||||
|
||||
float getMovementDirection() { return m_joystick_direction; }
|
||||
float getMovementSpeed() { return m_joystick_speed; }
|
||||
float getJoystickDirection() { return m_joystick_direction; }
|
||||
float getJoystickSpeed() { return m_joystick_speed; }
|
||||
|
||||
void step(float dtime);
|
||||
inline void setUseCrosshair(bool use_crosshair) { m_draw_crosshair = use_crosshair; }
|
||||
|
@ -962,6 +962,8 @@ enum ToServerCommand : u16
|
||||
[2+12+12+4+4+4] u8 fov*80
|
||||
[2+12+12+4+4+4+1] u8 ceil(wanted_range / MAP_BLOCKSIZE)
|
||||
[2+12+12+4+4+4+1+1] u8 camera_inverted (bool)
|
||||
[2+12+12+4+4+4+1+1+1] f32 movement_speed
|
||||
[2+12+12+4+4+4+1+1+1+4] f32 movement_direction
|
||||
|
||||
*/
|
||||
|
||||
|
@ -477,12 +477,24 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
|
||||
u8 bits = 0; // bits instead of bool so it is extensible later
|
||||
|
||||
*pkt >> keyPressed;
|
||||
player->control.unpackKeysPressed(keyPressed);
|
||||
|
||||
*pkt >> f32fov;
|
||||
fov = (f32)f32fov / 80.0f;
|
||||
*pkt >> wanted_range;
|
||||
|
||||
if (pkt->getRemainingBytes() >= 1)
|
||||
*pkt >> bits;
|
||||
|
||||
if (pkt->getRemainingBytes() >= 8) {
|
||||
*pkt >> player->control.movement_speed;
|
||||
*pkt >> player->control.movement_direction;
|
||||
} else {
|
||||
player->control.movement_speed = 0.0f;
|
||||
player->control.movement_direction = 0.0f;
|
||||
player->control.setMovementFromKeys();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -501,8 +513,6 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
|
||||
playersao->setWantedRange(wanted_range);
|
||||
playersao->setCameraInverted(bits & 0x01);
|
||||
|
||||
player->control.unpackKeysPressed(keyPressed);
|
||||
|
||||
if (playersao->checkMovementCheat()) {
|
||||
// Call callbacks
|
||||
m_script->on_cheat(playersao, "moved_too_fast");
|
||||
|
@ -173,6 +173,42 @@ u16 Player::getMaxHotbarItemcount()
|
||||
return mainlist ? std::min(mainlist->getSize(), (u32) hud_hotbar_itemcount) : 0;
|
||||
}
|
||||
|
||||
void PlayerControl::setMovementFromKeys()
|
||||
{
|
||||
bool a_up = direction_keys & (1 << 0),
|
||||
a_down = direction_keys & (1 << 1),
|
||||
a_left = direction_keys & (1 << 2),
|
||||
a_right = direction_keys & (1 << 3);
|
||||
|
||||
if (a_up || a_down || a_left || a_right) {
|
||||
// if contradictory keys pressed, stay still
|
||||
if (a_up && a_down && a_left && a_right)
|
||||
movement_speed = 0.0f;
|
||||
else if (a_up && a_down && !a_left && !a_right)
|
||||
movement_speed = 0.0f;
|
||||
else if (!a_up && !a_down && a_left && a_right)
|
||||
movement_speed = 0.0f;
|
||||
else
|
||||
// If there is a keyboard event, assume maximum speed
|
||||
movement_speed = 1.0f;
|
||||
}
|
||||
|
||||
// Check keyboard for input
|
||||
float x = 0, y = 0;
|
||||
if (a_up)
|
||||
y += 1;
|
||||
if (a_down)
|
||||
y -= 1;
|
||||
if (a_left)
|
||||
x -= 1;
|
||||
if (a_right)
|
||||
x += 1;
|
||||
|
||||
if (x != 0 || y != 0)
|
||||
// If there is a keyboard event, it takes priority
|
||||
movement_direction = std::atan2(x, y);
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
|
||||
u32 PlayerControl::getKeysPressed() const
|
||||
@ -231,6 +267,11 @@ void PlayerControl::unpackKeysPressed(u32 keypress_bits)
|
||||
zoom = keypress_bits & (1 << 9);
|
||||
}
|
||||
|
||||
v2f PlayerControl::getMovement() const
|
||||
{
|
||||
return v2f(std::sin(movement_direction), std::cos(movement_direction)) * movement_speed;
|
||||
}
|
||||
|
||||
static auto tie(const PlayerPhysicsOverride &o)
|
||||
{
|
||||
// Make sure to add new members to this list!
|
||||
|
@ -86,6 +86,11 @@ struct PlayerControl
|
||||
movement_direction = a_movement_direction;
|
||||
}
|
||||
|
||||
// Sets movement_speed and movement_direction according to direction_keys
|
||||
// if direction_keys != 0, otherwise leaves them unchanged to preserve
|
||||
// joystick input.
|
||||
void setMovementFromKeys();
|
||||
|
||||
#ifndef SERVER
|
||||
// For client use
|
||||
u32 getKeysPressed() const;
|
||||
@ -94,6 +99,7 @@ struct PlayerControl
|
||||
|
||||
// For server use
|
||||
void unpackKeysPressed(u32 keypress_bits);
|
||||
v2f getMovement() const;
|
||||
|
||||
u8 direction_keys = 0;
|
||||
bool jump = false;
|
||||
@ -102,7 +108,7 @@ struct PlayerControl
|
||||
bool zoom = false;
|
||||
bool dig = false;
|
||||
bool place = false;
|
||||
// Note: These four are NOT available on the server
|
||||
// Note: These two are NOT available on the server
|
||||
float pitch = 0.0f;
|
||||
float yaw = 0.0f;
|
||||
float movement_speed = 0.0f;
|
||||
|
@ -260,12 +260,13 @@ int LuaLocalPlayer::l_get_control(lua_State *L)
|
||||
set("zoom", c.zoom);
|
||||
set("dig", c.dig);
|
||||
set("place", c.place);
|
||||
// Player movement in polar coordinates and non-binary speed
|
||||
lua_pushnumber(L, c.movement_speed);
|
||||
lua_setfield(L, -2, "movement_speed");
|
||||
lua_pushnumber(L, c.movement_direction);
|
||||
lua_setfield(L, -2, "movement_direction");
|
||||
// Provide direction keys to ensure compatibility
|
||||
|
||||
v2f movement = c.getMovement();
|
||||
lua_pushnumber(L, movement.X);
|
||||
lua_setfield(L, -2, "movement_x");
|
||||
lua_pushnumber(L, movement.Y);
|
||||
lua_setfield(L, -2, "movement_y");
|
||||
|
||||
set("up", c.direction_keys & (1 << 0));
|
||||
set("down", c.direction_keys & (1 << 1));
|
||||
set("left", c.direction_keys & (1 << 2));
|
||||
|
@ -1622,6 +1622,13 @@ int ObjectRef::l_get_player_control(lua_State *L)
|
||||
lua_setfield(L, -2, "dig");
|
||||
lua_pushboolean(L, control.place);
|
||||
lua_setfield(L, -2, "place");
|
||||
|
||||
v2f movement = control.getMovement();
|
||||
lua_pushnumber(L, movement.X);
|
||||
lua_setfield(L, -2, "movement_x");
|
||||
lua_pushnumber(L, movement.Y);
|
||||
lua_setfield(L, -2, "movement_y");
|
||||
|
||||
// Legacy fields to ensure mod compatibility
|
||||
lua_pushboolean(L, control.dig);
|
||||
lua_setfield(L, -2, "LMB");
|
||||
|
Loading…
Reference in New Issue
Block a user