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

Rudimental Controller support with libgamepad (small C++ lib) #701

Draft
wants to merge 95 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
351fb84
implement basic functions for controller support
Schlumpf7 Nov 19, 2024
dee805c
...
Schlumpf7 Nov 19, 2024
0508a17
...
Schlumpf7 Nov 19, 2024
6d857e7
...
Schlumpf7 Nov 19, 2024
5a4c9a5
...
Schlumpf7 Nov 19, 2024
1190885
...
Schlumpf7 Nov 19, 2024
ed6322a
...
Schlumpf7 Nov 19, 2024
ad707e9
Added for std::shared_ptr
Schlumpf7 Nov 19, 2024
099a181
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
0dc709e
Update playercontrol.h
Schlumpf7 Nov 28, 2024
f6a89af
Merge branch 'Try:master' into master
Schlumpf7 Nov 28, 2024
1fff9f1
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
a71b031
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
ccce7d4
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
d931ff9
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
bf17d2b
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
ca27937
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
6787923
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
9d535bf
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
8fdd8f0
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
26f65cb
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
ec15357
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
b8727a5
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
93710d5
Update playercontrol.cpp
Schlumpf7 Nov 28, 2024
3c4b2ba
path
Schlumpf7 Nov 28, 2024
471c5a9
1234
Schlumpf7 Nov 28, 2024
4987467
1234
Schlumpf7 Nov 28, 2024
93244b9
test
Schlumpf7 Nov 28, 2024
35d32d3
test
Schlumpf7 Nov 28, 2024
943702d
oh no
Schlumpf7 Nov 28, 2024
6563194
maybe now?
Schlumpf7 Nov 28, 2024
7df4357
now?
Schlumpf7 Nov 28, 2024
66e119c
?
Schlumpf7 Nov 28, 2024
ceea9e5
asfa
Schlumpf7 Nov 28, 2024
2ba6464
falesly deleted
Schlumpf7 Nov 28, 2024
7b364b6
...
Schlumpf7 Nov 28, 2024
999cb27
now it should get called
Schlumpf7 Nov 28, 2024
cca847e
11
Schlumpf7 Nov 28, 2024
8edfc3b
...
Schlumpf7 Nov 28, 2024
be46606
...
Schlumpf7 Nov 28, 2024
5367e34
erase debug
Schlumpf7 Nov 28, 2024
c35bf11
controller configuration
Schlumpf7 Nov 28, 2024
97ac679
debug
Schlumpf7 Nov 28, 2024
d1fa2d7
debug
Schlumpf7 Nov 28, 2024
0d4b948
debug
Schlumpf7 Nov 28, 2024
75f771e
debug
Schlumpf7 Nov 28, 2024
bf72256
debug
Schlumpf7 Nov 28, 2024
13845f0
wrong axis name
Schlumpf7 Nov 28, 2024
563c951
debug
Schlumpf7 Nov 28, 2024
2113108
debug
Schlumpf7 Nov 28, 2024
4414301
debug
Schlumpf7 Nov 28, 2024
66065ab
debug
Schlumpf7 Nov 28, 2024
7c6ea9f
debug
Schlumpf7 Nov 28, 2024
8ead7ef
less console bloat
Schlumpf7 Nov 28, 2024
2305b61
deleted wrong code
Schlumpf7 Nov 28, 2024
9f0bd06
revert
Schlumpf7 Nov 28, 2024
b01ead0
more controls
Schlumpf7 Nov 28, 2024
0294584
more control
Schlumpf7 Nov 28, 2024
df80f89
debug
Schlumpf7 Nov 28, 2024
cd0fc26
debug
Schlumpf7 Nov 28, 2024
409791b
debug
Schlumpf7 Nov 28, 2024
d590eaf
debug
Schlumpf7 Nov 28, 2024
77a5b13
debug
Schlumpf7 Nov 28, 2024
994a13c
debug
Schlumpf7 Nov 28, 2024
f70c2d6
deadzone
Schlumpf7 Nov 28, 2024
90fef6d
debug
Schlumpf7 Nov 28, 2024
c46bbc9
debug
Schlumpf7 Nov 28, 2024
6eadefe
debug
Schlumpf7 Nov 28, 2024
4c004bd
debug
Schlumpf7 Nov 28, 2024
fe7527d
debug
Schlumpf7 Nov 28, 2024
3221eca
look around
Schlumpf7 Nov 28, 2024
0ad105c
debug
Schlumpf7 Nov 28, 2024
f702c20
Weapon on Y
Schlumpf7 Nov 28, 2024
90e4dc0
weapon on b
Schlumpf7 Nov 28, 2024
8e677c5
debug
Schlumpf7 Nov 28, 2024
4fdd2af
ActionGeneric on A
Schlumpf7 Nov 28, 2024
3afcb38
A ActionGeneric
Schlumpf7 Nov 28, 2024
294dc72
K_LShift
Schlumpf7 Nov 28, 2024
650349a
coninuous a press
Schlumpf7 Nov 28, 2024
ac74943
debug
Schlumpf7 Nov 28, 2024
09641f5
debug
Schlumpf7 Nov 28, 2024
49b9c4e
action forward
Schlumpf7 Nov 28, 2024
8d82919
debug
Schlumpf7 Nov 28, 2024
238c1ec
debug
Schlumpf7 Nov 28, 2024
e9578d4
debug
Schlumpf7 Nov 28, 2024
1837851
debug
Schlumpf7 Nov 28, 2024
be6083a
debug
Schlumpf7 Nov 28, 2024
ec694a5
debug
Schlumpf7 Nov 28, 2024
dbdccfd
debug
Schlumpf7 Nov 28, 2024
5d5e20f
debug
Schlumpf7 Nov 28, 2024
3f95a6c
debug
Schlumpf7 Nov 28, 2024
bb63daa
debug
Schlumpf7 Nov 28, 2024
d0dc79a
debug
Schlumpf7 Nov 28, 2024
8f6f883
debug
Schlumpf7 Nov 28, 2024
6413ae9
added submodul
Schlumpf7 Nov 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
[submodule "lib/dmusic"]
path = lib/dmusic
url = https://github.com/GothicKit/dmusic.git
[submodule "lib/libgamepad"]
path = lib/libgamepad
url = https://github.com/univrsal/libgamepad.git
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ if(NOT MSVC)
endif()
endif()

# Add the libgamepad include directory
include_directories(${CMAKE_SOURCE_DIR}/lib/libgamepad/include)

# Add the libgamepad subdirectory if it contains its own CMakeLists.txt
add_subdirectory(lib/libgamepad)

target_link_libraries(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/lib/libgamepad/libgamepad.a)

if(WIN32)
if(MSVC)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup" )
Expand Down
223 changes: 211 additions & 12 deletions game/game/playercontrol.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#include "playercontrol.h"

#include <cmath>
#include <libgamepad.hpp>
#include <iostream>
#include <chrono>
#include <thread>

#include "world/objects/npc.h"
#include "world/objects/item.h"
Expand All @@ -10,23 +14,40 @@
#include "ui/inventorymenu.h"
#include "gothic.h"

PlayerControl::PlayerControl(DialogMenu& dlg, InventoryMenu &inv)
:dlg(dlg),inv(inv) {
Gothic::inst().onSettingsChanged.bind(this,&PlayerControl::setupSettings);
setupSettings();
}
static volatile bool run_flag = true;

// Signal handler for clean exit
#ifdef LGP_UNIX
#include <csignal>
void handler(int s) {
LGP_UNUSED(s);
run_flag = false;
}
#else
#include <windows.h>
BOOL WINAPI handler(DWORD s) {
LGP_UNUSED(s);
run_flag = false;
return TRUE;
}
#endif


PlayerControl::~PlayerControl() {
Gothic::inst().onSettingsChanged.ubind(this,&PlayerControl::setupSettings);
}

void PlayerControl::setupSettings() {
if(Gothic::inst().version().game==2) {
g2Ctrl = Gothic::inst().settingsGetI("GAME","USEGOTHIC1CONTROLS")==0;
} else {
g2Ctrl = false;
}
}
PlayerControl::PlayerControl(DialogMenu& dlg, InventoryMenu &inv)
: dlg(dlg), inv(inv) {
Gothic::inst().onSettingsChanged.bind(this, &PlayerControl::setupSettings);
setupSettings();

#ifdef LGP_UNIX
signal(SIGINT, handler);
#else
SetConsoleCtrlHandler(handler, TRUE);
#endif
}

void PlayerControl::setTarget(Npc *other) {
auto w = Gothic::inst().world();
Expand Down Expand Up @@ -1092,3 +1113,181 @@ void PlayerControl::processAutoRotate(Npc& pl, float& rot, uint64_t dt) {
}
}
}

void PlayerControl::handleButtonInput(std::shared_ptr<gamepad::device> dev) {
if (dev->is_button_pressed(gamepad::button::DPAD_UP)) {
std::cout << "DPAD pressed" << std::endl;
onKeyPressed(Action::WeaponMele, Tempest::KeyEvent::K_Space, KeyCodec::Mapping::Primary);
}
if (dev->is_button_pressed(gamepad::button::DPAD_RIGHT)) {
std::cout << "DPAD pressed" << std::endl;
onKeyPressed(Action::WeaponBow, Tempest::KeyEvent::K_Space, KeyCodec::Mapping::Primary);
}
if (dev->is_button_pressed(gamepad::button::DPAD_DOWN)) {
std::cout << "DPAD pressed" << std::endl;
static int currentMagicSlot = Action::WeaponMage3;
onKeyPressed(static_cast<Action>(currentMagicSlot), Tempest::KeyEvent::K_Space, KeyCodec::Mapping::Primary);
currentMagicSlot++;
if (currentMagicSlot > Action::WeaponMage10) {
currentMagicSlot = Action::WeaponMage3;
}
}
if (dev->is_button_pressed(gamepad::button::LB)) {
std::cout << "Lshoulder pressed" << std::endl;
movement.strafeRightLeft.reverse[0] = true;
} else {
movement.strafeRightLeft.reverse[0] = false;
}

if (dev->is_button_pressed(gamepad::button::RB)) {
std::cout << "Rshoulder pressed" << std::endl;
movement.strafeRightLeft.main[0] = true;
} else {
movement.strafeRightLeft.main[0] = false;
}

if (dev->is_button_pressed(gamepad::button::Y)) {
std::cout << "Y pressed" << std::endl;
ctrl[Action::Jump] = true;
} else {
ctrl[Action::Jump] = false;
}

if (dev->is_button_pressed(gamepad::button::B)) {
std::cout << "B pressed" << std::endl;
// Trigger Action::Weapon
onKeyPressed(KeyCodec::Action::Weapon, Tempest::KeyEvent::KeyType::K_Return, KeyCodec::Mapping());
}

if (dev->is_button_pressed(gamepad::button::A)) {
std::cout << "A pressed" << std::endl;
// Perform continuous action for A button
onKeyPressed(KeyCodec::Action::ActionGeneric, Tempest::KeyEvent::KeyType::K_LShift, KeyCodec::Mapping());
} else {
std::cout << "A released" << std::endl;
// Correcting the call to only pass two parameters (KeyCodec::Action and KeyCodec::Mapping)
onKeyReleased(KeyCodec::Action::ActionGeneric, KeyCodec::Mapping());
}

if (dev->is_button_pressed(gamepad::button::X)) {
std::cout << "X pressed" << std::endl;
ctrl[Action::Weapon] = true;
} else {
ctrl[Action::Weapon] = false;
}

if (dev->is_button_pressed(gamepad::button::R_THUMB)) {
std::cout << "R_THUMB pressed" << std::endl;
onKeyPressed(KeyCodec::Action::FirstPerson, Tempest::KeyEvent::KeyType::K_F, KeyCodec::Mapping());
}
if (dev->is_button_pressed(gamepad::button::L_THUMB)) {
std::cout << "L_THUMB pressed" << std::endl;
onKeyPressed(KeyCodec::Action::Sneak, Tempest::KeyEvent::KeyType::K_X, KeyCodec::Mapping());
}
}

void PlayerControl::handleAxisInput(std::shared_ptr<gamepad::device> dev) {

auto leftX = dev->get_axis(gamepad::axis::LEFT_STICK_X);
auto leftY = dev->get_axis(gamepad::axis::LEFT_STICK_Y);
if (std::abs(leftX) > 0.51) {
std::cout << "Left Stick Right" << std::endl;
onKeyPressed(KeyCodec::Action::Right, Tempest::KeyEvent::KeyType::K_D, KeyCodec::Mapping());
} else if (std::abs(leftX) < 0.49){
std::cout << "Left Stick Left" << std::endl;
onKeyPressed(KeyCodec::Action::Left, Tempest::KeyEvent::KeyType::K_A, KeyCodec::Mapping());

} else if (std::abs(leftX) >= 0.49 && std::abs(leftX) <= 0.51){
handleMovementAction(KeyCodec::ActionMapping{Action::Right, KeyCodec::Mapping::Primary}, false);
handleMovementAction(KeyCodec::ActionMapping{Action::Left, KeyCodec::Mapping::Primary}, false);
actrl[ActLeft] = false;
actrl[ActRight] = false;
}

if (std::abs(leftY) > 0.51) {
std::cout << "Left Stick Backward" << std::endl;
onKeyPressed(KeyCodec::Action::Back, Tempest::KeyEvent::KeyType::K_S, KeyCodec::Mapping());
} else if (std::abs(leftY) < 0.49){
std::cout << "Left Stick Forward" << std::endl;
onKeyPressed(KeyCodec::Action::Forward, Tempest::KeyEvent::KeyType::K_W, KeyCodec::Mapping());

} else if (std::abs(leftY) >= 0.49 && std::abs(leftY) <= 0.51){
handleMovementAction(KeyCodec::ActionMapping{Action::Back, KeyCodec::Mapping::Primary}, false);
handleMovementAction(KeyCodec::ActionMapping{Action::Forward, KeyCodec::Mapping::Primary}, false);
actrl[ActBack] = false;
actrl[ActForward] = false;
}

auto rightX = dev->get_axis(gamepad::axis::RIGHT_STICK_X);
auto rightY = dev->get_axis(gamepad::axis::RIGHT_STICK_Y);
if (std::abs(rightX) > 0.51) {
std::cout << "Right Stick Right" << std::endl;
handleMovementAction(KeyCodec::ActionMapping{Action::RotateR, KeyCodec::Mapping::Primary}, true);
} else if (std::abs(rightX) < 0.49){
std::cout << "Right Stick Left" << std::endl;
handleMovementAction(KeyCodec::ActionMapping{Action::RotateL, KeyCodec::Mapping::Primary}, true);

} else if (std::abs(rightX) >= 0.49 && std::abs(rightX) <= 0.51){
handleMovementAction(KeyCodec::ActionMapping{Action::RotateR, KeyCodec::Mapping::Primary}, false);
handleMovementAction(KeyCodec::ActionMapping{Action::RotateL, KeyCodec::Mapping::Primary}, false);
}

if (std::abs(rightY) != 0.5) {
float dAngle = (leftX - 0.5f) * 200.0f;
dAngle = std::max(-100.f, std::min(dAngle, 100.f));
rotMouseY += dAngle * 0.2f;
}
}

void PlayerControl::setupSettings() {
// Ensure the gamepad hook is initialized
auto h = gamepad::hook::make();

// Set plug-and-play and polling sleep time
h->set_plug_and_play(true, gamepad::ms(1000));
h->set_sleep_time(gamepad::ms(5));

// Reassign handlers to ensure they are correctly hooked
h->set_button_event_handler([this](std::shared_ptr<gamepad::device> dev) {
this->handleButtonInput(dev);
});

h->set_axis_event_handler([this](std::shared_ptr<gamepad::device> dev) {
this->handleAxisInput(dev);
});

h->set_connect_event_handler([h](std::shared_ptr<gamepad::device> dev) {
ginfo("%s connected", dev->get_name().c_str());
if (!dev->has_binding()) {
#ifdef LGP_ENABLE_JSON
ginfo("Found device, running config wizard");
json11::Json cfg;
h->make_xbox_config(dev, cfg);
ginfo("Result config: %s", cfg.dump().c_str());
#else
ginfo("Json isn't enabled for libgamepad, so the config wizard can't be used");
#endif
}
});

h->set_disconnect_event_handler([](std::shared_ptr<gamepad::device> dev) {
ginfo("%s disconnected", dev->get_name().c_str());
});

// Start the gamepad hook if not already started
if (!h->start()) {
gerr("Couldn't start gamepad hook");
throw std::runtime_error("Failed to initialize gamepad hook");
}

// Log gamepad setup success
ginfo("Gamepad hook initialized and handlers set");

// Set Gothic 2 control mode if applicable
if (Gothic::inst().version().game == 2) {
g2Ctrl = Gothic::inst().settingsGetI("GAME", "USEGOTHIC1CONTROLS") == 0;
} else {
g2Ctrl = false;
}
}

13 changes: 10 additions & 3 deletions game/game/playercontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#include "world/focus.h"
#include "utils/keycodec.h"
#include "constants.h"
#include <libgamepad.hpp>

#include <array>
#include <memory>

class DialogMenu;
class InventoryMenu;
Expand All @@ -20,6 +22,9 @@ class PlayerControl final {
PlayerControl(DialogMenu& dlg, InventoryMenu& inv);
~PlayerControl();

void handleButtonInput(std::shared_ptr<gamepad::device> dev);
void handleAxisInput(std::shared_ptr<gamepad::device> dev);

void onKeyPressed (KeyCodec::Action a, Tempest::Event::KeyType key, KeyCodec::Mapping mapping = KeyCodec::Mapping::Primary);
void onKeyReleased(KeyCodec::Action a, KeyCodec::Mapping mapping = KeyCodec::Mapping::Primary);
bool isPressed(KeyCodec::Action a) const;
Expand Down Expand Up @@ -47,6 +52,8 @@ class PlayerControl final {
bool tickCameraMove(uint64_t dt);

private:
std::shared_ptr<gamepad::hook> hook; // Hook für Gamepad-Ereignisse

enum WeaponAction : uint8_t {
WeaponClose,
WeaponMele,
Expand All @@ -61,7 +68,7 @@ class PlayerControl final {
Weapon10,

Last,
};
};

enum FocusAction : uint8_t {
ActForward=0,
Expand All @@ -71,7 +78,7 @@ class PlayerControl final {
ActGeneric=4,
ActMove =5,
ActKill =6,
};
};

using Action=KeyCodec::Action;

Expand Down Expand Up @@ -207,4 +214,4 @@ class PlayerControl final {
/// @param actionMapping - the pressed/released action
/// @param pressed - true if the key was pressed, false if it was released
auto handleMovementAction(KeyCodec::ActionMapping actionMapping, bool pressed) -> void;
};
};
1 change: 1 addition & 0 deletions lib/libgamepad
Submodule libgamepad added at db34bb