Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose analog joystick input to the Lua API #14348

Merged
merged 5 commits into from
Oct 1, 2024

Conversation

grorp
Copy link
Member

@grorp grorp commented Feb 4, 2024

This PR exposes analog joystick input to the Lua API. This allows games like PRANG! to have better movement. It adds two new fields, movement_x and movement_y, to player:get_player_control().

These fields are set according to keyboard input when not available:

  • when an old client connects, this happens on the server
  • when a new client connects and the player uses the keyboard, this happens on the client

To do

This PR is a Ready for Review.

How to test

Verify that keyboard input still works.

Install PRANG! from ContentDB on an Android device and apply this patch:

diff --git a/mods/prang/init.lua b/mods/prang/init.lua
index e45550a..aadd301 100644
--- a/mods/prang/init.lua
+++ b/mods/prang/init.lua
@@ -586,11 +586,8 @@ function Player:tick(game, dtime, controls)
         speed = speed * (8/3)
     end
 
-    local dx = get_direction(speed, controls.left, controls.right)
-    local dy = get_direction(speed, controls.up, controls.down)
-    if dx ~= 0 and dy ~= 0 then
-        dx, dy = dx / sqrt_2, dy / sqrt_2
-    end
+    local dx = controls.movement_x * speed
+    local dy = -controls.movement_y * speed
     self:move(dx, dy)
 end
 

Play PRANG! and enjoy the virtual analog joystick. (Should probably use math.ceil here.)

@grorp grorp force-pushed the analog-joystick-for-mods branch from 5f7f8cf to 286254d Compare February 4, 2024 21:55
@Zughy Zughy added the Roadmap: supported by core dev PR not adhering to the roadmap, yet some core dev decided to take care of it label Feb 5, 2024
@v-rob
Copy link
Contributor

v-rob commented Feb 6, 2024

In general, I think it might be more desirable to make this work similar to how a physical joystick does in code by having two axes, X and Y, that range from [-1, 1]. It makes it consistent with how these things usually work, and you already effectively convert to that anyway by using sin and cos in your code example.

@grorp
Copy link
Member Author

grorp commented Feb 6, 2024

In general, I think it might be more desirable to make this work similar to how a physical joystick does in code by having two axes, X and Y, that range from [-1, 1]. It makes it consistent with how these things usually work, and you already effectively convert to that anyway by using sin and cos in your code example.

The problem with this approach is that for making it intuitive/understandable, we'd have to name the new fields joystick_x and joystick_y. However, modders would then incorrectly assume that they are for joysticks only and don't support keyboard input.

To avoid this, you could call them movement_x and movement_y, but then they could be misunderstood as absolute movement. Do you have an idea how we could get the intuitiveness of the joystick scheme and avoid both problems?

@v-rob
Copy link
Contributor

v-rob commented Feb 7, 2024

I think that having movement_x and movement_y is more ideal, but document it well that it may be a float for (virtual) joystick devices. If modders assume that it's a discrete -1, 0, or 1, then they'll probably end up with code that's sub-optimal, but no worse than the current up/left/etc. keys.

@grorp
Copy link
Member Author

grorp commented Feb 9, 2024

TBH, I'm still not sure which API is better - the current one forces modders to think, so maybe they're less likely to make the mistake you're describing. Both API designs, the current one or your suggestion, would be fine for me.

@rubenwardy
Copy link
Contributor

I think that movement_x and movement_y is better. Euler angles are meh and having movement_speed will be misinterpreted as being the actual desired speed, not the commanded 0-1 value.

@grorp
Copy link
Member Author

grorp commented Feb 9, 2024

I've updated the API, thanks for your input.

@sfan5
Copy link
Collaborator

sfan5 commented Feb 15, 2024

Haven't looked at the code but I wanted to note that it's important that across all combinations of old/new servers/clients the server sees the direction keys being "pressed" if the player uses the analog stick to move.
You can check this using the test code from #11924.

And I suppose with this PR there's a new requirement: If I move using direction keys the server should still see matching values for the analog stick.

@y5nw
Copy link
Contributor

y5nw commented Feb 15, 2024

It would also be nice for mods to be able to read whether the input was made with a keyboard or using a touchscreen/joystick; then mods/games that (ab)use movement input for other purposes would be able to set up different control schemes based on whether the player uses keyboard or touchscreen input.

@grorp
Copy link
Member Author

grorp commented Feb 15, 2024

sfan5: I think both requirements are fulfilled by this PR and I have done some testing with different old/new server/client combinations, but I'd be thankful if you or someone else could also verify that this works as expected.

y5nw: That's a different issue, see #12264.

@grorp grorp added the Rebase needed The PR needs to be rebased by its author label Feb 24, 2024
@grorp grorp force-pushed the analog-joystick-for-mods branch from 9516df6 to 9354f8e Compare February 24, 2024 11:12
@grorp grorp removed the Rebase needed The PR needs to be rebased by its author label Feb 24, 2024
@grorp grorp force-pushed the analog-joystick-for-mods branch from 9354f8e to 8875916 Compare March 20, 2024 16:22
@hecktest
Copy link
Contributor

@grorp If this affects clientside player movement then it needs a server-imposed deadzone. The reason is that you might want to enforce a minimum speed; the old movement implicitly has that in the form of the sneak speed. so this is a subtly breaking change.

If you can't see why that's a problem, imagine having to animate a walk cycle for someone moving at 0.01 nodes per second. Remember that we do not yet have animation mixing, so you can't just interpolate between idle and walking (not that it necessarily looks good) - all you can do is adjust the speed, so you have to choose between letting people slide around slowly in an idle animation, or display a freeze-frame of the walking animation. Neither looks very good. If you have physics such as waving hair baked into the animation, you should never play it slowed down.

I'm aware of the existing edge case created by walking into a wall, but that one is a bit less jarring than letting people perform this weird jitter on flat ground by nudging the analog sticks repeatedly.

@grorp
Copy link
Member Author

grorp commented Jun 30, 2024

@hecktest This PR doesn't change player movement. Player movement already respects analog joystick input on the master branch.

This PR is concerned with making analog joystick input accessible to the Lua API.

@rubenwardy rubenwardy added the Rebase needed The PR needs to be rebased by its author label Aug 15, 2024
@grorp grorp force-pushed the analog-joystick-for-mods branch from e6379c2 to 62e245f Compare September 24, 2024 08:32
@grorp grorp removed the Rebase needed The PR needs to be rebased by its author label Sep 24, 2024
@v-rob v-rob self-requested a review September 24, 2024 15:44
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[12+12+4+4+4+1+1+1] f32 movement_speed
[12+12+4+4+4+1+1+4] f32 movement_speed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I think the current version is actually correct since it's an offset, not a size

src/player.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@appgurueu appgurueu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with a real analog joystick, works as expected. I can attest that this makes PRANG! quite enjoyable. Code looks good.

(I noticed some joystick annoyances (for example, axes are bound pretty randomly with no way to change this; joystick input persists after you plug out the joystick, you need to restart Minetest), but that's not this PR's issue. I think we need #12888 for joysticks to work well.)

grorp and others added 3 commits September 27, 2024 17:58
Rename getMovement* to getJoystick* to reflect refactor
@grorp grorp force-pushed the analog-joystick-for-mods branch from c97857b to dc78344 Compare September 27, 2024 16:00
@grorp
Copy link
Member Author

grorp commented Sep 27, 2024

I did some backwards compat tests again, all with a new server and modified PRANG! as described in the top post:

  • new Android client: analog input works
  • new desktop client: keyboard input works (I have no physical joystick)
  • old Android client: analog input simulates keyboard input, works
  • old desktop client: keyboard input works

So that still seems to work correctly.

@grorp grorp merged commit 22ef4c8 into luanti-org:master Oct 1, 2024
15 checks passed
@grorp grorp deleted the analog-joystick-for-mods branch October 1, 2024 15:21
Mahoyomu pushed a commit to Mahoyomu/minetest that referenced this pull request Oct 7, 2024
grorp added a commit to grorp/minetest-prang that referenced this pull request Jan 27, 2025
luk3yx pushed a commit to luk3yx/minetest-prang that referenced this pull request Jan 27, 2025
@luk3yx
Copy link
Contributor

luk3yx commented Jan 27, 2025

Is movement_speed sanitised by the server anywhere?

if (pkt->getRemainingBytes() >= 1)
*pkt >> bits;

if (pkt->getRemainingBytes() >= 8) {
*pkt >> player->control.movement_speed;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It indeed looks like movement speed should be clamped between 0 and 1 here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@ Client / Controls / Input Feature ✨ PRs that add or enhance a feature One approval ✅ ◻️ Roadmap: supported by core dev PR not adhering to the roadmap, yet some core dev decided to take care of it @ Script API
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants