Skip to content

Commit dbbc61b

Browse files
committed
Support Input and UI for multiple players
1 parent 1586c56 commit dbbc61b

19 files changed

+317
-65
lines changed

core/config/project_settings.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,12 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
759759

760760
load_scene_groups_cache();
761761

762+
// FIXME: Temp device_player_map population.
763+
device_player_map[0] = 1U << 0;
764+
device_player_map[1] = 1U << 1;
765+
device_player_map[2] = 1U << 2;
766+
device_player_map[3] = 1U << 3;
767+
762768
project_loaded = err == OK;
763769
return err;
764770
}

core/config/project_settings.h

+2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class ProjectSettings : public Object {
9393
HashMap<StringName, PropertyInfo> custom_prop_info;
9494
bool using_datapack = false;
9595
bool project_loaded = false;
96+
HashMap<int, uint8_t> device_player_map;
9697
List<String> input_presets;
9798

9899
HashSet<String> custom_features;
@@ -191,6 +192,7 @@ class ProjectSettings : public Object {
191192
const HashMap<StringName, PropertyInfo> &get_custom_property_info() const;
192193
uint64_t get_last_saved_time() { return last_save_time; }
193194

195+
HashMap<int, uint8_t> get_device_player_map() const { return device_player_map; }
194196
List<String> get_input_presets() const { return input_presets; }
195197

196198
Variant get_setting_with_override(const StringName &p_name) const;

core/core_constants.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ void register_global_constants() {
649649
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_PHYSICS);
650650
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_NAVIGATION);
651651
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_AVOIDANCE);
652+
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_PLAYER_MASK);
652653

653654
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FILE);
654655
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_DIR);

core/input/input.cpp

+54-22
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,13 @@ void Input::_bind_methods() {
122122
ClassDB::bind_method(D_METHOD("is_key_label_pressed", "keycode"), &Input::is_key_label_pressed);
123123
ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
124124
ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
125-
ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact_match"), &Input::is_action_pressed, DEFVAL(false));
126-
ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "exact_match"), &Input::is_action_just_pressed, DEFVAL(false));
127-
ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "exact_match"), &Input::is_action_just_released, DEFVAL(false));
128-
ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &Input::get_action_strength, DEFVAL(false));
129-
ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action", "exact_match"), &Input::get_action_raw_strength, DEFVAL(false));
130-
ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis);
131-
ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f));
125+
ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact_match", "player_mask"), &Input::is_action_pressed, DEFVAL(false), DEFVAL(PLAYER_ALL));
126+
ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "exact_match", "player_mask"), &Input::is_action_just_pressed, DEFVAL(false), DEFVAL(PLAYER_ALL));
127+
ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "exact_match", "player_mask"), &Input::is_action_just_released, DEFVAL(false), DEFVAL(PLAYER_ALL));
128+
ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match", "player_mask"), &Input::get_action_strength, DEFVAL(false), DEFVAL(PLAYER_ALL));
129+
ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action", "exact_match", "player_mask"), &Input::get_action_raw_strength, DEFVAL(false), DEFVAL(PLAYER_ALL));
130+
ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action", "player_mask"), &Input::get_axis, DEFVAL(PLAYER_ALL));
131+
ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone", "player_mask"), &Input::get_vector, DEFVAL(-1.0f), DEFVAL(PLAYER_ALL));
132132
ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
133133
ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping);
134134
ClassDB::bind_method(D_METHOD("is_joy_known", "device"), &Input::is_joy_known);
@@ -157,8 +157,8 @@ void Input::_bind_methods() {
157157
ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode);
158158
ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode);
159159
ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Input::warp_mouse);
160-
ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
161-
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
160+
ClassDB::bind_method(D_METHOD("action_press", "action", "strength", "player_mask"), &Input::action_press, DEFVAL(1.f), DEFVAL(PLAYER_ALL));
161+
ClassDB::bind_method(D_METHOD("action_release", "action", "player_mask"), &Input::action_release, DEFVAL(PLAYER_ALL));
162162
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
163163
ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &Input::get_current_cursor_shape);
164164
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
@@ -201,6 +201,17 @@ void Input::_bind_methods() {
201201
BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
202202
BIND_ENUM_CONSTANT(CURSOR_HELP);
203203

204+
BIND_ENUM_CONSTANT(PLAYER_NONE);
205+
BIND_ENUM_CONSTANT(PLAYER_1);
206+
BIND_ENUM_CONSTANT(PLAYER_2);
207+
BIND_ENUM_CONSTANT(PLAYER_3);
208+
BIND_ENUM_CONSTANT(PLAYER_4);
209+
BIND_ENUM_CONSTANT(PLAYER_5);
210+
BIND_ENUM_CONSTANT(PLAYER_6);
211+
BIND_ENUM_CONSTANT(PLAYER_7);
212+
BIND_ENUM_CONSTANT(PLAYER_8);
213+
BIND_ENUM_CONSTANT(PLAYER_ALL);
214+
204215
ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "device"), PropertyInfo(Variant::BOOL, "connected")));
205216
}
206217

@@ -369,7 +380,7 @@ bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const {
369380
return joy_buttons_pressed.has(_combine_device(p_button, p_device));
370381
}
371382

372-
bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
383+
bool Input::is_action_pressed(const StringName &p_action, bool p_exact, uint8_t p_player_mask) const {
373384
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
374385

375386
if (disable_input) {
@@ -381,10 +392,10 @@ bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
381392
return false;
382393
}
383394

384-
return E->value.cache.pressed && (p_exact ? E->value.exact : true);
395+
return E->value.cache.pressed && (p_exact ? E->value.exact : true) && p_player_mask & E->value.player_mask;
385396
}
386397

387-
bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
398+
bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact, uint8_t p_player_mask) const {
388399
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
389400

390401
if (disable_input) {
@@ -400,6 +411,10 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
400411
return false;
401412
}
402413

414+
if (!(p_player_mask & E->value.player_mask)) {
415+
return false;
416+
}
417+
403418
// Backward compatibility for legacy behavior, only return true if currently pressed.
404419
bool pressed_requirement = legacy_just_pressed_behavior ? E->value.cache.pressed : true;
405420

@@ -410,7 +425,7 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
410425
}
411426
}
412427

413-
bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
428+
bool Input::is_action_just_released(const StringName &p_action, bool p_exact, uint8_t p_player_mask) const {
414429
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
415430

416431
if (disable_input) {
@@ -426,6 +441,10 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
426441
return false;
427442
}
428443

444+
if (!(p_player_mask & E->value.player_mask)) {
445+
return false;
446+
}
447+
429448
// Backward compatibility for legacy behavior, only return true if currently released.
430449
bool released_requirement = legacy_just_pressed_behavior ? !E->value.cache.pressed : true;
431450

@@ -436,7 +455,7 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
436455
}
437456
}
438457

439-
float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
458+
float Input::get_action_strength(const StringName &p_action, bool p_exact, uint8_t p_player_mask) const {
440459
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
441460

442461
if (disable_input) {
@@ -452,10 +471,14 @@ float Input::get_action_strength(const StringName &p_action, bool p_exact) const
452471
return 0.0f;
453472
}
454473

474+
if (!(p_player_mask & E->value.player_mask)) {
475+
return 0.0f;
476+
}
477+
455478
return E->value.cache.strength;
456479
}
457480

458-
float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
481+
float Input::get_action_raw_strength(const StringName &p_action, bool p_exact, uint8_t p_player_mask) const {
459482
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
460483

461484
if (disable_input) {
@@ -471,17 +494,21 @@ float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) c
471494
return 0.0f;
472495
}
473496

497+
if (!(p_player_mask & E->value.player_mask)) {
498+
return 0.0f;
499+
}
500+
474501
return E->value.cache.raw_strength;
475502
}
476503

477-
float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const {
478-
return get_action_strength(p_positive_action) - get_action_strength(p_negative_action);
504+
float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action, uint8_t p_player_mask) const {
505+
return get_action_strength(p_positive_action, false, p_player_mask) - get_action_strength(p_negative_action, false, p_player_mask);
479506
}
480507

481-
Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone) const {
508+
Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone, uint8_t p_player_mask) const {
482509
Vector2 vector = Vector2(
483-
get_action_raw_strength(p_positive_x) - get_action_raw_strength(p_negative_x),
484-
get_action_raw_strength(p_positive_y) - get_action_raw_strength(p_negative_y));
510+
get_action_raw_strength(p_positive_x, false, p_player_mask) - get_action_raw_strength(p_negative_x, false, p_player_mask),
511+
get_action_raw_strength(p_positive_y, false, p_player_mask) - get_action_raw_strength(p_negative_y, false, p_player_mask));
485512

486513
if (p_deadzone < 0.0f) {
487514
// If the deadzone isn't specified, get it from the average of the actions.
@@ -879,6 +906,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
879906
device_state.strength[event_index] = p_event->get_action_strength(E.key);
880907
device_state.raw_strength[event_index] = p_event->get_action_raw_strength(E.key);
881908

909+
// TODO: Not sure.
910+
// uint32_t player_mask = p_event->get_player();
911+
882912
// Update the action's global state and cache.
883913
if (!is_pressed) {
884914
action_state.api_pressed = false; // Always release the event from action_press() method.
@@ -1014,7 +1044,7 @@ Point2 Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, cons
10141044
return rel_warped;
10151045
}
10161046

1017-
void Input::action_press(const StringName &p_action, float p_strength) {
1047+
void Input::action_press(const StringName &p_action, float p_strength, uint8_t p_player_mask) {
10181048
ERR_FAIL_COND_MSG(!InputMap::get_singleton()->has_action(p_action), InputMap::get_singleton()->suggest_actions(p_action));
10191049

10201050
// Create or retrieve existing action.
@@ -1028,10 +1058,11 @@ void Input::action_press(const StringName &p_action, float p_strength) {
10281058
action_state.exact = true;
10291059
action_state.api_pressed = true;
10301060
action_state.api_strength = CLAMP(p_strength, 0.0f, 1.0f);
1061+
action_state.player_mask = p_player_mask;
10311062
_update_action_cache(p_action, action_state);
10321063
}
10331064

1034-
void Input::action_release(const StringName &p_action) {
1065+
void Input::action_release(const StringName &p_action, uint8_t p_player_mask) {
10351066
ERR_FAIL_COND_MSG(!InputMap::get_singleton()->has_action(p_action), InputMap::get_singleton()->suggest_actions(p_action));
10361067

10371068
// Create or retrieve existing action.
@@ -1046,6 +1077,7 @@ void Input::action_release(const StringName &p_action) {
10461077
action_state.exact = true;
10471078
action_state.api_pressed = false;
10481079
action_state.api_strength = 0.0;
1080+
action_state.player_mask = p_player_mask;
10491081
}
10501082

10511083
void Input::set_emulate_touch_from_mouse(bool p_emulate) {

core/input/input.h

+25-9
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,19 @@ class Input : public Object {
8383
JOYPADS_MAX = 16,
8484
};
8585

86+
enum PlayerMask : uint8_t {
87+
PLAYER_NONE = 0U,
88+
PLAYER_1 = 1U << 0,
89+
PLAYER_2 = 1U << 1,
90+
PLAYER_3 = 1U << 2,
91+
PLAYER_4 = 1U << 3,
92+
PLAYER_5 = 1U << 4,
93+
PLAYER_6 = 1U << 5,
94+
PLAYER_7 = 1U << 6,
95+
PLAYER_8 = 1U << 7,
96+
PLAYER_ALL = 0xFFU,
97+
};
98+
8699
typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);
87100

88101
private:
@@ -123,6 +136,8 @@ class Input : public Object {
123136
float api_strength = 0.0;
124137
HashMap<int, DeviceState> device_states;
125138

139+
uint8_t player_mask = 1U << 0;
140+
126141
// Cache.
127142
struct ActionStateCache {
128143
bool pressed = false;
@@ -306,14 +321,14 @@ class Input : public Object {
306321
bool is_key_label_pressed(Key p_keycode) const;
307322
bool is_mouse_button_pressed(MouseButton p_button) const;
308323
bool is_joy_button_pressed(int p_device, JoyButton p_button) const;
309-
bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
310-
bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const;
311-
bool is_action_just_released(const StringName &p_action, bool p_exact = false) const;
312-
float get_action_strength(const StringName &p_action, bool p_exact = false) const;
313-
float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const;
324+
bool is_action_pressed(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
325+
bool is_action_just_pressed(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
326+
bool is_action_just_released(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
327+
float get_action_strength(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
328+
float get_action_raw_strength(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
314329

315-
float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const;
316-
Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const;
330+
float get_axis(const StringName &p_negative_action, const StringName &p_positive_action, uint8_t p_player_mask = PLAYER_ALL) const;
331+
Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f, uint8_t p_player_mask = PLAYER_ALL) const;
317332

318333
float get_joy_axis(int p_device, JoyAxis p_axis) const;
319334
String get_joy_name(int p_idx);
@@ -350,8 +365,8 @@ class Input : public Object {
350365

351366
void set_mouse_position(const Point2 &p_posf);
352367

353-
void action_press(const StringName &p_action, float p_strength = 1.f);
354-
void action_release(const StringName &p_action);
368+
void action_press(const StringName &p_action, float p_strength = 1.f, uint8_t p_player_mask = 0);
369+
void action_release(const StringName &p_action, uint8_t p_player_mask = 0);
355370

356371
void set_emulate_touch_from_mouse(bool p_emulate);
357372
bool is_emulating_touch_from_mouse() const;
@@ -403,5 +418,6 @@ class Input : public Object {
403418

404419
VARIANT_ENUM_CAST(Input::MouseMode);
405420
VARIANT_ENUM_CAST(Input::CursorShape);
421+
VARIANT_ENUM_CAST(Input::PlayerMask);
406422

407423
#endif // INPUT_H

0 commit comments

Comments
 (0)