thobbsinteractive / magic-carpet-2-hd

Recode Binary code of game Magic Carpet2 to C/C++ language(remake MC2 for any platform)
GNU General Public License v3.0
27 stars 4 forks source link

flawless-er joystick implementation #235

Closed rodan closed 1 year ago

rodan commented 1 year ago

ChangeLog

if you try this patch and your mouse seems to be unresponsive while the joystick is resting, consider increasing JOYSTICK_DEAD_ZONE as per my comments in the code.

you can try out both my push requests, but I really really prefer this one ;)

patch tested with Logitech Attack 3 and Logitech Extreme 3D PRO.

best regards, peter

thobbsinteractive commented 1 year ago

Yeah, this one I am even more excited about testing

rodan commented 1 year ago

ok, let me give some context.

my joystick implementation has two operating modes:

why this approach? the original game does not provide the generic pointer algorithm equivalent to my 'menu navigation'. neither the boulder menu nor the map with level selection scenes accept any joystick input. menus that happen during flight (options, pause, exit, spell selection) all have a hardcoded method of taking joystick input and selecting the adjacent press-able button in a specified direction. my guess is that implementing this non-general movement type will be very taxing implementation-wise. that's why I opted to my method that provides a generic way of translating stick movement inside menus.

how do I switch between modes? whenever CTRL or the joystick key equivalent (config.ini->button_spell) is kept pressed, any stick moves are considered to be 'menu navigation'. otherwise we're flying.

how should we switch between modes? well, CTRL should be one of the ways whenever the player needs the spell selection menu to open during flight. but also the game should automatically select one of the modes based on the current scene.

I'm currently doing function call graphs based on the '-finstrument-functions' compiler option to try to understand this recompiled code and see where the scene changes happen. and progress is slow :)

thobbsinteractive commented 1 year ago

Cool. I will try and test it tonight. Chances are I will merge it because we had nothing working before. I obviously want all the controls to be definable in the config.ini one day as you can remap some in the game, but that functionality is a mess right now (I might even disable that menu). Some keys are also hard coded (F1, F2 etc..) and I want rid of that too so that one day I can implement a custom menu for controllers.

Ideally we want some abstraction so any action can be mapped.

Eventually I'll develop a launcher (for windows but maybe in Mawi so it works on Linux) to configure the config.ini file.

The good news is the installer is almost finished. I just have an error with the x64 installation to fix. Wix is hell and time consuming to work with but i am almost done 👍

On Mon, 17 Apr 2023, 11:30 Petre Rodan, @.***> wrote:

ok, let me give some context.

my joystick implementation has two operating modes:

-

the first one (called 'flight mode' in my code) is used whenever the player is flying the carpet. in this mode any given stick position is equivalent to a given coordinate in the(0,0) (gameResW,H) interval. when the stick is resting the pointer coordinate is always 320,200 which basically zeroes any roll and pitch.

the second is 'menu navigation' mode and it's used whenever a button/icon/spell needs to be clicked in the current scene. in this mode any stick movement translates to a relative movement in the stick's general direction. the distance traveled by the pointer is directly proportional to the angle of the stick. when the stick is resting the pointer's location remains unchanged. this emulates the functionality of a mouse, since we can reach any corner of the screen by small movement increments, there is no direct equation that translates a stick position to a pointer position like in the first method.

why this approach? the original game does not provide the generic pointer algorithm equivalent to my 'menu navigation'. neither the boulder menu nor the map with level selection scenes accept any joystick input. menus that happen during flight (options, pause, exit, spell selection) all have a hardcoded method of taking joystick input and selecting the adjacent press-able button in a specified direction. my guess is that implementing this non-general movement type will be very taxing implementation-wise. that's why I opted to my method that provides a generic way of translating stick movement inside menus.

how do I switch between modes? whenever CTRL or the joystick key equivalent (config.ini->button_spell) is kept pressed, any stick moves are considered to be 'menu navigation'. otherwise we're flying.

how should we switch between modes? well, CTRL should be one of the ways whenever the player needs the spell selection menu to open during flight. but also the game should automatically select one of the modes based on the current scene.

I'm currently doing function call graphs based on the '-finstrument-functions' compiler option to try to understand this recompiled code and see where the scene changes happen. and progress is slow :)

— Reply to this email directly, view it on GitHub https://github.com/thobbsinteractive/magic-carpet-2-hd/pull/235#issuecomment-1511009671, or unsubscribe https://github.com/notifications/unsubscribe-auth/AETQQFBHSHONP3JZ4AWSHTLXBUETJANCNFSM6AAAAAAW2Q2FVA . You are receiving this because you commented.Message ID: @.***>

rodan commented 1 year ago

Hello!

Cool. I will try and test it tonight. Chances are I will merge it because we had nothing working before. I obviously want all the controls to be definable in the config.ini one day as you can remap some in the game, but that functionality is a mess right now (I might even disable that menu).

yeah, I also feel that the config.ini is the way to go.

Some keys are also hard coded (F1, F2 etc..) and I want rid of that too so that one day I can implement a custom menu for controllers. Ideally we want some abstraction so any action can be mapped. Eventually I'll develop a launcher (for windows but maybe in Mawi so it works on Linux) to configure the config.ini file. The good news is the installer is almost finished. I just have an error with the x64 installation to fix. Wix is hell and time consuming to work with but i am almost done.

nice. as far as linux is concerned, the users tend to install software using the distribution's package manager, I will definitely help with a gentoo package and an overlay for the game itself. hand-editing config files are a requirement for linux guys so there is no immediate need for a graphical launcher, but something like OpenMW's launcher (based on Qt libs) would be nice. never heard of Mawi and my google-foo is failing me today. I just hope it does not depend on .net stuff.

and yeah, I thought you might prefer using globals for the scene_id stuff instead of modifying existing functions so I added some of that functionality in the second patch of this pull req.

best regards, peter

thobbsinteractive commented 1 year ago

It was spelt in incorrectly. It is "Maui". QT is C++ and also not fun to use. .Net is just easier for anything not exe related. https://learn.microsoft.com/en-us/dotnet/maui/what-is-maui?view=net-maui-7.0

So I tested it out. It is good. With the Xbox controller it has problems. Namely that the button mapping (not surprising every controller is different), but I realize that is configurable in the ini file. I would like to be able to configure the buttons or axis for movement and pitch and roll as I would like the dpad or second analogue stick to move the player forward/backward/left/right.

I realize with a flight stick you don't have a second analogue stick and the game originally was not written for one, so this is a challenge.

In a perfect world, in the menus the cursor would move around like the mouse. Like you said it was difficult to select items with it resetting to the middle of the screen.

But this is a good start. How would you like me to proceed. Merge this and I can enhance it later when I finish that damn installer or keep this open and make enhancements on this branch?

rodan commented 1 year ago

good morning Tim,

thank you for taking your time testing the patch out.

It was spelt in incorrectly. It is "Maui". QT is C++ and also not fun to use. .Net is just easier for anything not exe related. https://learn.microsoft.com/en-us/dotnet/maui/what-is-maui?view=net-maui-7.0

finding a cross-platform GUI toolkit is always a pain. I'm just pointing out that .net is not really a thing in linux. it might be supported via the mono project, but in most cases there is no reason for users to install those libraries. if you do decide to go this route please make sure that the launcher is only optional and the user is able to modify any of the options either by editing the config files or via CLI arguments.

So I tested it out. It is good. With the Xbox controller it has problems. Namely that the button mapping (not surprising every controller is different), but I realize that is configurable in the ini file.

correct, in port_sdl_vga_mouse.cpp:1145 there is a Logger->trace("Key {} press detected", event.jbutton.button + 1); that will show you the exact button number that needs to be entered into the config.ini file.

I would like to be able to configure the buttons or axis for movement and pitch and roll as I would like the dpad or second analogue stick to move the player forward/backward/left/right. I realize with a flight stick you don't have a second analogue stick and the game originally was not written for one, so this is a challenge.

interesting. I have never played on such a device. I'll go and buy one to check it out.

In a perfect world, in the menus the cursor would move around like the mouse. Like you said it was difficult to select items with it resetting to the middle of the screen.

But this is a good start. How would you like me to proceed. Merge this and I can enhance it later when I finish that damn installer or keep this open and make enhancements on this branch?

I would prefer you to be happy with the code first. let me get an xbox controller and see what I can come up with.

best regards, peter

rodan commented 1 year ago

work in progress.

ChangeLog

I still have to clean things up and make sure my previous joysticks are still working.

tested on an xbox elite series 2 controller

please report what issues you are facing

thobbsinteractive commented 1 year ago

Hey, So with this change I would like to completely abstract the game input with an interface/abstract class called IInput. The idea being we can then implement a Class for Joystick and a Class for Keyboard and mouse etc... All in game inputs would be represented by an int. So e.g. int MainMenu, int Reflections, int Shadows, int Threads etc... with Int we can have 0,1 or some other positive and negative value. I did something similar to this pattern with the render. So what I will do is try and finish the installer. Then start implementing this interface before I merge your changes. What do you think?

rodan commented 1 year ago

the further into OOP you go the less I understand you :) I have no idea what the meaning is of that int representation.

do whatever floats your boat, I will keep polishing the gamepad support and maybe I'll be able to isolate where the scene change functions are so we get rid of the extra key press requirement for navigation mode.

peter

thobbsinteractive commented 1 year ago

Hey Rodan, I have not forgotten about this. The MSI is finished. so i will have time to test it / work on it this week.

rodan commented 1 year ago

bravo on the installer! it's no rush, take your time. and see the README_controllers file first.

cheers, peter

thobbsinteractive commented 1 year ago

Hey, so I think I can merge this. I will give it a test, if all is good I will do my refactor after

rodan commented 1 year ago

yeah, try it out and tell me if you need something extra. or maybe an explanation. you'll have to add the extra files to your IDE (since I only use the Makefiles to build the project).

if you want we could talk tomorrow over discord if our timezones overlap (I'm in EEST)

thobbsinteractive commented 1 year ago

It is looking very good! I think we need to increase the deadzone for the Xbox controllers analogue sticks. There are a bit sensitive by default for movement and pitch/yaw. On the other-side, with the triggers, I think we could be more sensitive as to fire quickly takes a lot of effort. There was a bug where after the first level, the level selection screen the cursor was springing back to center. This did not happen when I exited the level on the same screen. Ideally it would be nice if the main button e.g. "A" on the xbox controller could do selection of items as well as the triggers on the main menu/map screen. I was a bit lost at first. Finally, in a perfect world, I would like the speed of the player to depend on how hard the analogue stick is pushed, but the original code did not do this, it just sped up the longer you press. So that might not be possible without a lot of rewriting. It is something I can look into. Oh and SDL_JoystickRumbleTriggers was not recognised as part of SDL2. It might be SDL3 (according to the docs)? I had to comment it out to build. Is there a file missing?

rodan commented 1 year ago

It is looking very good! I think we need to increase the deadzone for the Xbox controllers analogue sticks. There are a bit sensitive by default for movement and pitch/yaw. On the other-side, with the triggers, I think we could be more sensitive as to fire quickly takes a lot of effort.

ok, we can have two separate deadzone variables - one for sticks and one for triggers, just in case people have sticks with lots of drift. for triggers I configured the hardware to have the smallest throw from the three possible options - via the two trigger stops on the back of the controller. this way they almost feel like buttons.

There was a bug where after the first level, the level selection screen the cursor was springing back to center. This did not happen when I exited the level on the same screen.

ok, looks like the scene change is not detected at that point. I'll have a look.

Ideally it would be nice if the main button e.g. "A" on the xbox controller could do selection of items as well as the triggers on the main menu/map screen. I was a bit lost at first.

so you want 'A' to act like mouse left button? I guess we can have an extra action button configuration option in the config for this. I think we also need an escape button to be bind-able to the controller, since I think it's the only input accepted once the player dies.

I think the feeling of being lost comes from the fact that the left trigger is tied to mouse left button and the right trigger to MRB. it's got to be this way during flight so that the proper trigger controls the proper hand that shoots out the spell. also for when spells are selected from the spellbook. but for menu navigation it's not ideal, as you have experienced :)

Finally, in a perfect world, I would like the speed of the player to depend on how hard the analogue stick is pushed, but the original code did not do this, it just sped up the longer you press. So that might not be possible without a lot of rewriting. It is something I can look into.

agree 100%. this first implementation interfaces with the recode only by setPress() and MouseEvents(). the next iteration should definitely do direct access to longitudinal/transversal movement without executing setPress().

as far as yaw/pitch is concerned, the harder you push on the stick the harder the flight banks. so we have this functionality already. also during menu navigation the pointer has 8 different levels of acceleration based on stick position in gamepad_axis_nav_conv().

Oh and SDL_JoystickRumbleTriggers was not recognised as part of SDL2. It might be SDL3 (according to the docs)? I had to comment it out to build. Is there a file missing?

based on https://wiki.libsdl.org/SDL2/SDL_JoystickRumbleTriggers it's present since 2.0.14 in SDL2/SDL_joystick.h. I'm using 2.24.2 which has the functionality, but my xpadneo linux driver is too old to know how to control the rumble trigger motors. it's ok we can have it disabled for now.

peter

rodan commented 1 year ago

ChangeLog:

thobbsinteractive commented 1 year ago

So I have added dead zones for each axis. I think what I actually need to adjust the sensitivity of each axis. So I will look into this tomorrow and maybe put it the dead zones back to one value. I have implement the Start button to open the option panel. And Back button bring up the escape menu. This works pretty well

thobbsinteractive commented 1 year ago

two things definitely need to change, see the inline comments.

also, is it ok to have that absolutely huge dead zone as default? people with controllers that have large drift can tweak their config.ini (or change the pots), the rest should enjoy sane defaults that do not waste 1/5 of the stick's range of motion.

I was finding a lot of drift and sensitivity with the XBox controller. But I plan to add an option to make it less sensitive in the earlier stages (so it is not linear). I can default it back to 3000

rodan commented 1 year ago

haha, I was also copy-pasting apparently :)

thobbsinteractive commented 1 year ago

So, one more thing I would like to do is to make the axis value calculation optionally curved, that way I can reduce the sensitivity for smaller movements. I am looking into the maths on how to do this, it is not too complex and I will make it adjustable. I am also going to use the Scene states you created so that the "A" button can be also used for menu selection. I should have this done today and we can merge this thing!

rodan commented 1 year ago

the non-linear axis conversion is a cool idea. just beware that the center point (gps.rest_x, gps.rest_y) is not at the center of the screen, and you will need two equations just like in the linear case in order to provide the same delta to both sides of the axis for the same amount of stick lean angle. the test to see if your equation is correct is to forcefully enable flight mode in a menu and see if the pointer reaches all screen corners exactly when the stick reaches the max lean angle in that direction.

'(A)' for menu selection? that's a simple config.ini setting like axis_fire_L = 3 ; left trigger axis that does action fire L button_fire_L = 1 ; a secondary action button. the trigger axis above can also do firing at the same time.

the set_scene() call is placed in various places in the recode where we detect the need to switch from one mode to the other. but maybe I misunderstood your comment.

sonarcloud[bot] commented 1 year ago

SonarCloud Quality Gate failed.    Quality Gate failed

Bug C 1 Bug
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell B 159 Code Smells

0.0% 0.0% Coverage
0.0% 0.0% Duplication