Skip to content

Commit 5cd289c

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

22 files changed

+407
-102
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

+56-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,19 @@ void Input::_bind_methods() {
201201
BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
202202
BIND_ENUM_CONSTANT(CURSOR_HELP);
203203

204+
BIND_CONSTANT(PLAYERS_MAX);
205+
206+
BIND_ENUM_CONSTANT(PLAYER_NONE);
207+
BIND_ENUM_CONSTANT(PLAYER_1);
208+
BIND_ENUM_CONSTANT(PLAYER_2);
209+
BIND_ENUM_CONSTANT(PLAYER_3);
210+
BIND_ENUM_CONSTANT(PLAYER_4);
211+
BIND_ENUM_CONSTANT(PLAYER_5);
212+
BIND_ENUM_CONSTANT(PLAYER_6);
213+
BIND_ENUM_CONSTANT(PLAYER_7);
214+
BIND_ENUM_CONSTANT(PLAYER_8);
215+
BIND_ENUM_CONSTANT(PLAYER_ALL);
216+
204217
ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "device"), PropertyInfo(Variant::BOOL, "connected")));
205218
}
206219

@@ -369,7 +382,7 @@ bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const {
369382
return joy_buttons_pressed.has(_combine_device(p_button, p_device));
370383
}
371384

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

375388
if (disable_input) {
@@ -381,10 +394,10 @@ bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
381394
return false;
382395
}
383396

384-
return E->value.cache.pressed && (p_exact ? E->value.exact : true);
397+
return E->value.cache.pressed && (p_exact ? E->value.exact : true) && p_player_mask & E->value.player_mask;
385398
}
386399

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

390403
if (disable_input) {
@@ -400,6 +413,10 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
400413
return false;
401414
}
402415

416+
if (!(p_player_mask & E->value.player_mask)) {
417+
return false;
418+
}
419+
403420
// Backward compatibility for legacy behavior, only return true if currently pressed.
404421
bool pressed_requirement = legacy_just_pressed_behavior ? E->value.cache.pressed : true;
405422

@@ -410,7 +427,7 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
410427
}
411428
}
412429

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

416433
if (disable_input) {
@@ -426,6 +443,10 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
426443
return false;
427444
}
428445

446+
if (!(p_player_mask & E->value.player_mask)) {
447+
return false;
448+
}
449+
429450
// Backward compatibility for legacy behavior, only return true if currently released.
430451
bool released_requirement = legacy_just_pressed_behavior ? !E->value.cache.pressed : true;
431452

@@ -436,7 +457,7 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
436457
}
437458
}
438459

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

442463
if (disable_input) {
@@ -452,10 +473,14 @@ float Input::get_action_strength(const StringName &p_action, bool p_exact) const
452473
return 0.0f;
453474
}
454475

476+
if (!(p_player_mask & E->value.player_mask)) {
477+
return 0.0f;
478+
}
479+
455480
return E->value.cache.strength;
456481
}
457482

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

461486
if (disable_input) {
@@ -471,17 +496,21 @@ float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) c
471496
return 0.0f;
472497
}
473498

499+
if (!(p_player_mask & E->value.player_mask)) {
500+
return 0.0f;
501+
}
502+
474503
return E->value.cache.raw_strength;
475504
}
476505

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);
506+
float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action, uint8_t p_player_mask) const {
507+
return get_action_strength(p_positive_action, false, p_player_mask) - get_action_strength(p_negative_action, false, p_player_mask);
479508
}
480509

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 {
510+
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 {
482511
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));
512+
get_action_raw_strength(p_positive_x, false, p_player_mask) - get_action_raw_strength(p_negative_x, false, p_player_mask),
513+
get_action_raw_strength(p_positive_y, false, p_player_mask) - get_action_raw_strength(p_negative_y, false, p_player_mask));
485514

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

911+
// TODO: Not sure.
912+
// uint32_t player_mask = p_event->get_player();
913+
882914
// Update the action's global state and cache.
883915
if (!is_pressed) {
884916
action_state.api_pressed = false; // Always release the event from action_press() method.
@@ -1014,7 +1046,7 @@ Point2 Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, cons
10141046
return rel_warped;
10151047
}
10161048

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

10201052
// Create or retrieve existing action.
@@ -1028,10 +1060,11 @@ void Input::action_press(const StringName &p_action, float p_strength) {
10281060
action_state.exact = true;
10291061
action_state.api_pressed = true;
10301062
action_state.api_strength = CLAMP(p_strength, 0.0f, 1.0f);
1063+
action_state.player_mask = p_player_mask;
10311064
_update_action_cache(p_action, action_state);
10321065
}
10331066

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

10371070
// Create or retrieve existing action.
@@ -1046,6 +1079,7 @@ void Input::action_release(const StringName &p_action) {
10461079
action_state.exact = true;
10471080
action_state.api_pressed = false;
10481081
action_state.api_strength = 0.0;
1082+
action_state.player_mask = p_player_mask;
10491083
}
10501084

10511085
void Input::set_emulate_touch_from_mouse(bool p_emulate) {

core/input/input.h

+11-9
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class Input : public Object {
123123
float api_strength = 0.0;
124124
HashMap<int, DeviceState> device_states;
125125

126+
uint8_t player_mask = 1U << 0;
127+
126128
// Cache.
127129
struct ActionStateCache {
128130
bool pressed = false;
@@ -306,14 +308,14 @@ class Input : public Object {
306308
bool is_key_label_pressed(Key p_keycode) const;
307309
bool is_mouse_button_pressed(MouseButton p_button) const;
308310
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;
311+
bool is_action_pressed(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
312+
bool is_action_just_pressed(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
313+
bool is_action_just_released(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
314+
float get_action_strength(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
315+
float get_action_raw_strength(const StringName &p_action, bool p_exact = false, uint8_t p_player_mask = PLAYER_ALL) const;
314316

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;
317+
float get_axis(const StringName &p_negative_action, const StringName &p_positive_action, uint8_t p_player_mask = PLAYER_ALL) const;
318+
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;
317319

318320
float get_joy_axis(int p_device, JoyAxis p_axis) const;
319321
String get_joy_name(int p_idx);
@@ -350,8 +352,8 @@ class Input : public Object {
350352

351353
void set_mouse_position(const Point2 &p_posf);
352354

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

356358
void set_emulate_touch_from_mouse(bool p_emulate);
357359
bool is_emulating_touch_from_mouse() const;

core/input/input_enums.h

+17
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,21 @@ inline MouseButtonMask mouse_button_to_mask(MouseButton button) {
138138
return MouseButtonMask(1 << ((int)button - 1));
139139
}
140140

141+
enum {
142+
PLAYERS_MAX = 8,
143+
};
144+
145+
enum PlayerMask : uint8_t {
146+
PLAYER_NONE = 0U,
147+
PLAYER_1 = 1U << 0,
148+
PLAYER_2 = 1U << 1,
149+
PLAYER_3 = 1U << 2,
150+
PLAYER_4 = 1U << 3,
151+
PLAYER_5 = 1U << 4,
152+
PLAYER_6 = 1U << 5,
153+
PLAYER_7 = 1U << 6,
154+
PLAYER_8 = 1U << 7,
155+
PLAYER_ALL = 0xFFU,
156+
};
157+
141158
#endif // INPUT_ENUMS_H

0 commit comments

Comments
 (0)