diff --git a/3rdparty/version_check.sh b/3rdparty/version_check.sh index 2b721fe28f..0e195b553e 100644 --- a/3rdparty/version_check.sh +++ b/3rdparty/version_check.sh @@ -1,7 +1,11 @@ -#!/bin/sh -ex +#!/bin/bash -ex verbose=0 git_verbose=0 +max_jobs=16 + +lockfile="$(pwd)/version_check.lock" +resultfile="$(pwd)/version_check_results.txt" if [ "$1" = "-v" ]; then verbose=1 @@ -10,9 +14,13 @@ elif [ "$1" = "-vv" ]; then git_verbose=1 fi -max_dir_length=0 -result_dirs=() -result_msgs=() +# Limit concurrent jobs +job_control() +{ + while [ "$(jobs | wc -l)" -ge "$max_jobs" ]; do + sleep 0.1 + done +} git_call() { @@ -27,20 +35,20 @@ git_call() check_tags() { - path=$(echo "$1" | sed 's:/*$::') + local path=$(echo "$1" | sed 's:/*$::') echo "Checking $path" - git_call fetch --prune --all + # git_call fetch --prune --all # Get the latest tag (by commit date, not tag name) - tag_list=$(git_call rev-list --tags --max-count=1) - latest_tag=$(git_call describe --tags "$tag_list") + local tag_list=$(git_call rev-list --tags --max-count=1) + local latest_tag=$(git_call describe --tags "$tag_list") if [ -n "$latest_tag" ]; then # Get the current tag - current_tag=$(git_call describe --tags --abbrev=0) + local current_tag=$(git_call describe --tags --abbrev=0) if [ -n "$current_tag" ]; then @@ -48,8 +56,8 @@ check_tags() echo "$path -> latest: $latest_tag, current: $current_tag" fi - ts1=$(git_call log -1 --format=%ct $latest_tag) - ts2=$(git_call log -1 --format=%ct $current_tag) + local ts1=$(git_call log -1 --format=%ct $latest_tag) + local ts2=$(git_call log -1 --format=%ct $current_tag) if (( ts1 > ts2 )); then if [ "$verbose" -eq 1 ]; then @@ -58,12 +66,11 @@ check_tags() echo "$path -> latest: $latest_tag, current: $current_tag" fi - path_length=${#path} - if (( $path_length > $max_dir_length )); then - max_dir_length=$path_length - fi - result_dirs+=("$path") - result_msgs+=("latest: $latest_tag, current: $current_tag") + # Critical section guarded by flock + ( + flock 200 + echo "$path -> latest: $latest_tag, current: $current_tag" >> "$resultfile" + ) 200>"$lockfile" fi elif [ "$verbose" -eq 1 ]; then @@ -79,19 +86,21 @@ check_tags() fi } +# Fetch and check repositories multi threaded for submoduledir in */ ; do cd "$submoduledir" || continue if [ -e ".git" ]; then - check_tags "$submoduledir" + job_control + check_tags "$submoduledir" & else - # find */ -mindepth 1 -maxdepth 1 -type d | while read -r sub; for sub in */ ; do if [ -e "$sub/.git" ]; then cd "$sub" || continue - check_tags "$submoduledir$sub" + job_control + check_tags "$submoduledir$sub" & cd .. || exit fi done @@ -100,16 +109,27 @@ do cd .. || exit done +# Wait for all background jobs to finish +wait + +# Print results echo -e "\n\nResult:\n" -i=0 -for result_dir in "${result_dirs[@]}"; do - msg="" - diff=$(($max_dir_length - ${#result_dir})) - if (( $diff > 0 )); then - msg+=$(printf "%${diff}s" "") + +# Find the max length of the paths (before '->') +max_len=0 +while IFS='->' read -r left _; do + len=$(echo -n "$left" | wc -c) + if (( len > max_len )); then + max_len=$len fi - msg+="$result_dir" - echo "$msg -> ${result_msgs[$i]}" - ((i++)) -done -echo "" +done < "$resultfile" + +# Print with padding so '->' lines up +while IFS='->' read -r left right; do + right=$(echo "$right" | sed 's/^[[:space:]]*>*[[:space:]]*//') + printf "%-${max_len}s -> %s\n" "$left" "$right" +done < "$resultfile" + +# Remove tmp files +rm -f "$resultfile" +rm -f "$lockfile" diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index ddb582c5d8..bfbeb416df 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -351,7 +351,7 @@ public: for (u32 i = 0; i < CELL_GEM_MAX_NUM; i++) { const auto& pad = ::at32(handler->GetPads(), pad_num(i)); - const bool connected = pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && i < attribute.max_connect; + const bool connected = pad && pad->is_connected() && i < attribute.max_connect; const bool is_real_move = g_cfg.io.move != move_handler::real || pad->m_pad_handler == pad_handler::move; update_connection(i, connected && is_real_move); @@ -469,7 +469,7 @@ public: for (u32 i = 0; i < std::min(attribute.max_connect, CELL_GEM_MAX_NUM); i++) { const auto& pad = ::at32(handler->GetPads(), pad_num(i)); - if (pad && pad->m_pad_handler == pad_handler::move && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad && pad->m_pad_handler == pad_handler::move && pad->is_connected()) { connected_controllers++; @@ -490,7 +490,7 @@ public: for (u32 i = 0; i < std::min(attribute.max_connect, CELL_GEM_MAX_NUM); i++) { const auto& pad = ::at32(handler->GetPads(), pad_num(i)); - if (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad && pad->is_connected()) { connected_controllers++; @@ -1776,7 +1776,7 @@ static void ds3_input_to_pad(const u32 gem_num, be_t& digital_buttons, be_t const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) { return; } @@ -1864,7 +1864,7 @@ static void ds3_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& contro const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) { return; } @@ -1895,7 +1895,7 @@ static void ps_move_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& co const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); - if (pad->m_pad_handler != pad_handler::move || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->m_pad_handler != pad_handler::move || !pad->is_connected()) { return; } @@ -1940,7 +1940,7 @@ static void ds3_input_to_ext(u32 gem_num, gem_config::gem_controller& controller const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) { return; } @@ -2777,7 +2777,7 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); - if (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad && pad->is_connected()) { inertial_state->temperature = pad->move_data.temperature; inertial_state->accelerometer[0] = pad->move_data.accelerometer_x; @@ -3392,7 +3392,7 @@ error_code cellGemReadExternalPortDeviceInfo(u32 gem_num, vm::ptr ext_id, v const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); - if (pad->m_pad_handler != pad_handler::move || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->m_pad_handler != pad_handler::move || !pad->is_connected()) { return CELL_GEM_NOT_CONNECTED; } @@ -3706,7 +3706,7 @@ error_code cellGemWriteExternalPort(u32 gem_num, vm::ptrGetPads(), pad_num(gem_num)); - if (pad->m_pad_handler != pad_handler::move || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->m_pad_handler != pad_handler::move || !pad->is_connected()) { return CELL_GEM_NOT_CONNECTED; } diff --git a/rpcs3/Emu/Cell/Modules/cellPad.cpp b/rpcs3/Emu/Cell/Modules/cellPad.cpp index f28d96d1ce..61e29805aa 100644 --- a/rpcs3/Emu/Cell/Modules/cellPad.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPad.cpp @@ -272,7 +272,7 @@ error_code cellPadInit(ppu_thread& ppu, u32 max_connect) for (usz i = 0; i < config.get_max_connect(); ++i) { - if (!pads[i]->is_fake_pad && (pads[i]->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pads[i]->is_fake_pad && pads[i]->is_connected()) { send_sys_io_connect_event(i, CELL_PAD_STATUS_CONNECTED); } @@ -339,7 +339,7 @@ error_code cellPadClearBuf(u32 port_no) const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; - if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !pad->is_connected()) return not_an_error(CELL_PAD_ERROR_NO_DEVICE); clear_pad_buffer(pad); @@ -411,26 +411,59 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) } }; - for (Button& button : pad->m_buttons) + for (const Button& button : pad->m_buttons) { // here we check btns, and set pad accordingly, // if something changed, set btnChanged + bool pressed = button.m_pressed; + u16 value = button.m_value; + + // Merge copilots + if (!pad->copilots.empty()) + { + for (const auto& copilot : pad->copilots) + { + if (!copilot || !copilot->is_connected()) + { + continue; + } + + for (const Button& other : copilot->m_buttons) + { + if (button.m_offset == other.m_offset && button.m_outKeyCode == other.m_outKeyCode) + { + if (other.m_pressed) + { + pressed = true; + + if (value < other.m_value) + { + value = other.m_value; + } + } + + break; + } + } + } + } + switch (button.m_offset) { case CELL_PAD_BTN_OFFSET_DIGITAL1: { - if (button.m_pressed) + if (pressed) pad->m_digital_1 |= button.m_outKeyCode; else pad->m_digital_1 &= ~button.m_outKeyCode; switch (button.m_outKeyCode) { - case CELL_PAD_CTRL_LEFT: set_value(pad->m_press_left, button.m_value); break; - case CELL_PAD_CTRL_DOWN: set_value(pad->m_press_down, button.m_value); break; - case CELL_PAD_CTRL_RIGHT: set_value(pad->m_press_right, button.m_value); break; - case CELL_PAD_CTRL_UP: set_value(pad->m_press_up, button.m_value); break; + case CELL_PAD_CTRL_LEFT: set_value(pad->m_press_left, value); break; + case CELL_PAD_CTRL_DOWN: set_value(pad->m_press_down, value); break; + case CELL_PAD_CTRL_RIGHT: set_value(pad->m_press_right, value); break; + case CELL_PAD_CTRL_UP: set_value(pad->m_press_up, value); break; // These arent pressure btns case CELL_PAD_CTRL_R3: case CELL_PAD_CTRL_L3: @@ -442,21 +475,21 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) } case CELL_PAD_BTN_OFFSET_DIGITAL2: { - if (button.m_pressed) + if (pressed) pad->m_digital_2 |= button.m_outKeyCode; else pad->m_digital_2 &= ~button.m_outKeyCode; switch (button.m_outKeyCode) { - case CELL_PAD_CTRL_SQUARE: set_value(pad->m_press_square, button.m_value); break; - case CELL_PAD_CTRL_CROSS: set_value(pad->m_press_cross, button.m_value); break; - case CELL_PAD_CTRL_CIRCLE: set_value(pad->m_press_circle, button.m_value); break; - case CELL_PAD_CTRL_TRIANGLE: set_value(pad->m_press_triangle, button.m_value); break; - case CELL_PAD_CTRL_R1: set_value(pad->m_press_R1, button.m_value); break; - case CELL_PAD_CTRL_L1: set_value(pad->m_press_L1, button.m_value); break; - case CELL_PAD_CTRL_R2: set_value(pad->m_press_R2, button.m_value); break; - case CELL_PAD_CTRL_L2: set_value(pad->m_press_L2, button.m_value); break; + case CELL_PAD_CTRL_SQUARE: set_value(pad->m_press_square, value); break; + case CELL_PAD_CTRL_CROSS: set_value(pad->m_press_cross, value); break; + case CELL_PAD_CTRL_CIRCLE: set_value(pad->m_press_circle, value); break; + case CELL_PAD_CTRL_TRIANGLE: set_value(pad->m_press_triangle, value); break; + case CELL_PAD_CTRL_R1: set_value(pad->m_press_R1, value); break; + case CELL_PAD_CTRL_L1: set_value(pad->m_press_L1, value); break; + case CELL_PAD_CTRL_R2: set_value(pad->m_press_R2, value); break; + case CELL_PAD_CTRL_L2: set_value(pad->m_press_L2, value); break; default: break; } break; @@ -465,18 +498,18 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) { switch (button.m_outKeyCode) { - case CELL_PAD_CTRL_PRESS_RIGHT: set_value(pad->m_press_right, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_LEFT: set_value(pad->m_press_left, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_UP: set_value(pad->m_press_up, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_DOWN: set_value(pad->m_press_down, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_TRIANGLE: set_value(pad->m_press_triangle, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard - case CELL_PAD_CTRL_PRESS_CIRCLE: set_value(pad->m_press_circle, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard - case CELL_PAD_CTRL_PRESS_CROSS: set_value(pad->m_press_cross, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard - case CELL_PAD_CTRL_PRESS_SQUARE: set_value(pad->m_press_square, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard - case CELL_PAD_CTRL_PRESS_L1: set_value(pad->m_press_L1, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_R1: set_value(pad->m_press_R1, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_L2: set_value(pad->m_press_L2, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_R2: set_value(pad->m_press_R2, button.m_value, true); break; + case CELL_PAD_CTRL_PRESS_RIGHT: set_value(pad->m_press_right, value, true); break; + case CELL_PAD_CTRL_PRESS_LEFT: set_value(pad->m_press_left, value, true); break; + case CELL_PAD_CTRL_PRESS_UP: set_value(pad->m_press_up, value, true); break; + case CELL_PAD_CTRL_PRESS_DOWN: set_value(pad->m_press_down, value, true); break; + case CELL_PAD_CTRL_PRESS_TRIANGLE: set_value(pad->m_press_triangle, value, true, 255, 63); break; // Infrared on RIDE Skateboard + case CELL_PAD_CTRL_PRESS_CIRCLE: set_value(pad->m_press_circle, value, true, 255, 63); break; // Infrared on RIDE Skateboard + case CELL_PAD_CTRL_PRESS_CROSS: set_value(pad->m_press_cross, value, true, 255, 63); break; // Infrared on RIDE Skateboard + case CELL_PAD_CTRL_PRESS_SQUARE: set_value(pad->m_press_square, value, true, 255, 63); break; // Infrared on RIDE Skateboard + case CELL_PAD_CTRL_PRESS_L1: set_value(pad->m_press_L1, value, true); break; + case CELL_PAD_CTRL_PRESS_R1: set_value(pad->m_press_R1, value, true); break; + case CELL_PAD_CTRL_PRESS_L2: set_value(pad->m_press_L2, value, true); break; + case CELL_PAD_CTRL_PRESS_R2: set_value(pad->m_press_R2, value, true); break; default: break; } break; @@ -488,12 +521,44 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) for (const AnalogStick& stick : pad->m_sticks) { + u16 value = stick.m_value; + + // Merge copilots + if (!pad->copilots.empty()) + { + const auto normalize = [](s32 value) + { + return (value - 128) / 127.0f; + }; + + f32 accumulated_value = normalize(value); + + for (const auto& copilot : pad->copilots) + { + if (!copilot || !copilot->is_connected()) + { + continue; + } + + for (const AnalogStick& other : copilot->m_sticks) + { + if (stick.m_offset == other.m_offset) + { + accumulated_value += normalize(other.m_value); + break; + } + } + } + + value = static_cast(std::round(std::clamp(accumulated_value * 127.0f + 128.0f, 0.0f, 255.0f))); + } + switch (stick.m_offset) { - case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X: set_value(pad->m_analog_left_x, stick.m_value); break; - case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: set_value(pad->m_analog_left_y, stick.m_value); break; - case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: set_value(pad->m_analog_right_x, stick.m_value); break; - case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: set_value(pad->m_analog_right_y, stick.m_value); break; + case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X: set_value(pad->m_analog_left_x, value); break; + case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: set_value(pad->m_analog_left_y, value); break; + case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: set_value(pad->m_analog_right_x, value); break; + case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: set_value(pad->m_analog_right_y, value); break; default: break; } } @@ -712,7 +777,7 @@ error_code cellPadGetData(u32 port_no, vm::ptr data) const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; - if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !pad->is_connected()) return not_an_error(CELL_PAD_ERROR_NO_DEVICE); pad_get_data(port_no, data.get_ptr()); @@ -798,7 +863,7 @@ error_code cellPadPeriphGetData(u32 port_no, vm::ptr data) const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; - if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !pad->is_connected()) return not_an_error(CELL_PAD_ERROR_NO_DEVICE); pad_get_data(port_no, &data->cellpad_data, true); @@ -830,7 +895,7 @@ error_code cellPadGetRawData(u32 port_no, vm::ptr data) const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; - if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !pad->is_connected()) return not_an_error(CELL_PAD_ERROR_NO_DEVICE); // ? @@ -843,7 +908,7 @@ error_code cellPadGetDataExtra(u32 port_no, vm::ptr device_type, vm::ptr param) const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; - if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !pad->is_connected()) return not_an_error(CELL_PAD_ERROR_NO_DEVICE); // TODO: find out if this is checked here or later or at all @@ -1021,7 +1086,7 @@ error_code cellPadGetCapabilityInfo(u32 port_no, vm::ptr const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; - if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !pad->is_connected()) return not_an_error(CELL_PAD_ERROR_NO_DEVICE); // Should return the same as device capability mask, psl1ght has it backwards in pad->h @@ -1077,7 +1142,7 @@ error_code cellPadInfoPressMode(u32 port_no) const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; - if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !pad->is_connected()) return not_an_error(CELL_PAD_ERROR_NO_DEVICE); return not_an_error((pad->m_device_capability & CELL_PAD_CAPABILITY_PRESS_MODE) ? 1 : 0); @@ -1104,7 +1169,7 @@ error_code cellPadInfoSensorMode(u32 port_no) const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; - if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (pad->is_fake_pad || !config.is_reportedly_connected(port_no) || !pad->is_connected()) return not_an_error(CELL_PAD_ERROR_NO_DEVICE); return not_an_error((pad->m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE) ? 1 : 0); diff --git a/rpcs3/Emu/Cell/Modules/cellPad.h b/rpcs3/Emu/Cell/Modules/cellPad.h index 0fdd4b23a7..3394fe6b2b 100644 --- a/rpcs3/Emu/Cell/Modules/cellPad.h +++ b/rpcs3/Emu/Cell/Modules/cellPad.h @@ -42,13 +42,13 @@ enum struct pad_data_internal { - u16 vendor_id; - u16 product_id; - u32 port_status; - u32 device_capability; - u32 device_type; - u32 pclass_type; - u32 pclass_profile; + u16 vendor_id = 0; + u16 product_id = 0; + u32 port_status = 0; + u32 device_capability = 0; + u32 device_type = 0; + u32 pclass_type = 0; + u32 pclass_profile = 0; ENABLE_BITWISE_SERIALIZATION; }; diff --git a/rpcs3/Emu/Io/Buzz.cpp b/rpcs3/Emu/Io/Buzz.cpp index 7c7890d41e..d5b7fe4f23 100644 --- a/rpcs3/Emu/Io/Buzz.cpp +++ b/rpcs3/Emu/Io/Buzz.cpp @@ -173,7 +173,7 @@ void usb_device_buzz::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/ { const auto& pad = pads[i]; - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) { continue; } diff --git a/rpcs3/Emu/Io/GHLtar.cpp b/rpcs3/Emu/Io/GHLtar.cpp index e520e53c7f..9a2b9d0ce6 100644 --- a/rpcs3/Emu/Io/GHLtar.cpp +++ b/rpcs3/Emu/Io/GHLtar.cpp @@ -152,7 +152,7 @@ void usb_device_ghltar::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), m_controller_index); - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) { return; } diff --git a/rpcs3/Emu/Io/GameTablet.cpp b/rpcs3/Emu/Io/GameTablet.cpp index 31ed81f3af..0b87a709bf 100644 --- a/rpcs3/Emu/Io/GameTablet.cpp +++ b/rpcs3/Emu/Io/GameTablet.cpp @@ -198,7 +198,7 @@ void usb_device_gametablet::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endp const auto gamepad_handler = pad::get_pad_thread(); const auto& pads = gamepad_handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); - if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) + if (pad->is_connected()) { for (Button& button : pad->m_buttons) { diff --git a/rpcs3/Emu/Io/GunCon3.cpp b/rpcs3/Emu/Io/GunCon3.cpp index d229693907..8dc5688f73 100644 --- a/rpcs3/Emu/Io/GunCon3.cpp +++ b/rpcs3/Emu/Io/GunCon3.cpp @@ -258,7 +258,7 @@ void usb_device_guncon3::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, const auto gamepad_handler = pad::get_pad_thread(); const auto& pads = gamepad_handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); - if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) + if (pad->is_connected()) { cfg->handle_input(pad, true, input_callback); } diff --git a/rpcs3/Emu/Io/TopShotElite.cpp b/rpcs3/Emu/Io/TopShotElite.cpp index 06cddab9f0..b7e2b64b98 100644 --- a/rpcs3/Emu/Io/TopShotElite.cpp +++ b/rpcs3/Emu/Io/TopShotElite.cpp @@ -318,7 +318,7 @@ void usb_device_topshotelite::interrupt_transfer(u32 buf_size, u8* buf, u32 /*en const auto gamepad_handler = pad::get_pad_thread(); const auto& pads = gamepad_handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); - if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) + if (pad->is_connected()) { cfg->handle_input(pad, true, input_callback); } diff --git a/rpcs3/Emu/Io/TopShotFearmaster.cpp b/rpcs3/Emu/Io/TopShotFearmaster.cpp index 98b54700d9..03c634d839 100644 --- a/rpcs3/Emu/Io/TopShotFearmaster.cpp +++ b/rpcs3/Emu/Io/TopShotFearmaster.cpp @@ -342,7 +342,7 @@ void usb_device_topshotfearmaster::interrupt_transfer(u32 buf_size, u8* buf, u32 const auto gamepad_handler = pad::get_pad_thread(); const auto& pads = gamepad_handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); - if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) + if (pad->is_connected()) { cfg->handle_input(pad, true, input_callback); } diff --git a/rpcs3/Emu/Io/Turntable.cpp b/rpcs3/Emu/Io/Turntable.cpp index eca1926825..ec67fabc22 100644 --- a/rpcs3/Emu/Io/Turntable.cpp +++ b/rpcs3/Emu/Io/Turntable.cpp @@ -166,7 +166,7 @@ void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpo const auto& pads = handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) return; const auto& cfg = ::at32(g_cfg_turntable.players, m_controller_index); diff --git a/rpcs3/Emu/Io/pad_types.h b/rpcs3/Emu/Io/pad_types.h index e6761a295f..57634a66b4 100644 --- a/rpcs3/Emu/Io/pad_types.h +++ b/rpcs3/Emu/Io/pad_types.h @@ -151,6 +151,13 @@ enum CELL_PAD_FAKE_TYPE_TOP_SHOT_ELITE = 0xa001, CELL_PAD_FAKE_TYPE_TOP_SHOT_FEARMASTER = 0xa002, CELL_PAD_FAKE_TYPE_GAMETABLET = 0xa003, + CELL_PAD_FAKE_TYPE_COPILOT_1 = 0xa004, + CELL_PAD_FAKE_TYPE_COPILOT_2 = 0xa005, + CELL_PAD_FAKE_TYPE_COPILOT_3 = 0xa006, + CELL_PAD_FAKE_TYPE_COPILOT_4 = 0xa007, + CELL_PAD_FAKE_TYPE_COPILOT_5 = 0xa008, + CELL_PAD_FAKE_TYPE_COPILOT_6 = 0xa009, + CELL_PAD_FAKE_TYPE_COPILOT_7 = 0xa00a, CELL_PAD_FAKE_TYPE_LAST, CELL_PAD_PCLASS_TYPE_MAX // last item @@ -536,6 +543,8 @@ struct Pad std::array m_sensors{}; std::array m_vibrateMotors{}; + std::vector> copilots; + // These hold bits for their respective buttons u16 m_digital_1{0}; u16 m_digital_2{0}; @@ -592,4 +601,19 @@ struct Pad m_product_id = product_id; m_pressure_intensity = (255 * pressure_intensity_percent) / 100; } + + u32 copilot_player() const + { + if (m_class_type >= CELL_PAD_FAKE_TYPE_COPILOT_1 && m_class_type <= CELL_PAD_FAKE_TYPE_COPILOT_7) + { + return m_class_type - CELL_PAD_FAKE_TYPE_COPILOT_1; + } + + return umax; + } + + bool is_connected() const + { + return !!(m_port_status & CELL_PAD_STATUS_CONNECTED); + } }; diff --git a/rpcs3/Emu/Io/usio.cpp b/rpcs3/Emu/Io/usio.cpp index e01deccf8a..0bfc5bcd59 100644 --- a/rpcs3/Emu/Io/usio.cpp +++ b/rpcs3/Emu/Io/usio.cpp @@ -210,7 +210,7 @@ void usb_device_usio::translate_input_taiko() const usz offset = player * 8ULL; auto& status = m_io_status[0]; - if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed()) + if (const auto& pad = ::at32(handler->GetPads(), pad_number); pad->is_connected() && is_input_allowed()) { const auto& cfg = ::at32(g_cfg_usio.players, pad_number); cfg->handle_input(pad, false, [&](usio_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/) @@ -295,7 +295,7 @@ void usb_device_usio::translate_input_tekken() auto& status = m_io_status[player / 2]; auto& input = digital_input[player / 2]; - if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed()) + if (const auto& pad = ::at32(handler->GetPads(), pad_number); pad->is_connected() && is_input_allowed()) { const auto& cfg = ::at32(g_cfg_usio.players, pad_number); cfg->handle_input(pad, false, [&](usio_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/) diff --git a/rpcs3/Emu/RSX/Overlays/overlays.cpp b/rpcs3/Emu/RSX/Overlays/overlays.cpp index 47e7ee3f87..aadf03e44a 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlays.cpp @@ -225,7 +225,7 @@ namespace rsx continue; } - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) { continue; } diff --git a/rpcs3/Emu/RSX/RSXFIFO.h b/rpcs3/Emu/RSX/RSXFIFO.h index d62d32a134..91f7ffb050 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.h +++ b/rpcs3/Emu/RSX/RSXFIFO.h @@ -93,7 +93,7 @@ namespace rsx std::array register_properties{}; - for (const auto &method : ignorable_ranges) + for (const auto& method : ignorable_ranges) { for (u32 i = 0; i < method.second; ++i) { @@ -175,4 +175,4 @@ namespace rsx bool skip_methods(u32 count); }; } -} \ No newline at end of file +} diff --git a/rpcs3/Input/gui_pad_thread.cpp b/rpcs3/Input/gui_pad_thread.cpp index f0bf833a46..3aa81efb29 100644 --- a/rpcs3/Input/gui_pad_thread.cpp +++ b/rpcs3/Input/gui_pad_thread.cpp @@ -283,7 +283,7 @@ void gui_pad_thread::run() void gui_pad_thread::process_input() { - if (!m_pad || !(m_pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!m_pad || !m_pad->is_connected()) { return; } diff --git a/rpcs3/Input/pad_thread.cpp b/rpcs3/Input/pad_thread.cpp index 2f4bea7b34..58c9da78a6 100644 --- a/rpcs3/Input/pad_thread.cpp +++ b/rpcs3/Input/pad_thread.cpp @@ -227,18 +227,47 @@ void pad_thread::Init() connect_usb_controller(i, input::get_product_by_vid_pid(pad->m_vendor_id, pad->m_product_id)); } + // Set copilots + for (usz i = 0; i < m_pads.size(); i++) + { + if (!m_pads[i]) continue; + + m_pads[i]->copilots.clear(); + + for (usz j = 0; j < m_pads.size(); j++) + { + if (i == j || !m_pads[j] || m_pads[j]->copilot_player() != i) + continue; + + m_pads[i]->copilots.push_back(m_pads[j]); + } + } + // Initialize active mouse and keyboard. Activate pad handler if one exists. input::set_mouse_and_keyboard(m_handlers.contains(pad_handler::keyboard) ? input::active_mouse_and_keyboard::pad : input::active_mouse_and_keyboard::emulated); } -void pad_thread::SetRumble(const u32 pad, u8 large_motor, bool small_motor) +void pad_thread::SetRumble(u32 pad, u8 large_motor, bool small_motor) { - if (pad >= m_pads.size()) + if (pad >= m_pads.size() || !m_pads[pad]) return; - m_pads[pad]->m_last_rumble_time_us = get_system_time(); + const u64 now_us = get_system_time(); + + m_pads[pad]->m_last_rumble_time_us = now_us; m_pads[pad]->m_vibrateMotors[0].m_value = large_motor; m_pads[pad]->m_vibrateMotors[1].m_value = small_motor ? 255 : 0; + + // Rumble copilots as well + for (const auto& copilot : m_pads[pad]->copilots) + { + if (copilot && copilot->is_connected()) + { + copilot->m_last_rumble_time_us = now_us; + copilot->m_vibrateMotors[0].m_value = large_motor; + copilot->m_vibrateMotors[1].m_value = small_motor ? 255 : 0; + } + } } void pad_thread::SetIntercepted(bool intercepted) @@ -263,7 +292,7 @@ void pad_thread::update_pad_states() // Simulate unplugging and plugging in a new controller if (pad && pad->m_disconnection_timer > 0) { - const bool is_connected = pad->m_port_status & CELL_PAD_STATUS_CONNECTED; + const bool is_connected = pad->is_connected(); const u64 now = get_system_time(); if (is_connected && now < pad->m_disconnection_timer) @@ -278,7 +307,7 @@ void pad_thread::update_pad_states() } } - const bool connected = pad && !pad->is_fake_pad && !!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED); + const bool connected = pad && !pad->is_fake_pad && pad->is_connected(); if (m_pads_connected[i] == connected) continue; @@ -431,7 +460,7 @@ void pad_thread::operator()() { const auto& pad = m_pads[i]; - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) continue; for (const auto& button : pad->m_buttons) @@ -468,7 +497,7 @@ void pad_thread::operator()() const auto& pad = m_pads[i]; - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) continue; // Check if an LDD pad pressed the PS button (bit 0 of the first button) @@ -535,7 +564,7 @@ void pad_thread::operator()() { const auto& pad = m_pads[i]; - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + if (!pad->is_connected()) continue; for (const auto& button : pad->m_buttons) @@ -640,11 +669,11 @@ s32 pad_thread::AddLddPad() void pad_thread::UnregisterLddPad(u32 handle) { - ensure(handle < m_pads.size()); + auto& pad = ::at32(m_pads, handle); - m_pads[handle]->ldd = false; - m_pads[handle]->m_port_status &= ~CELL_PAD_STATUS_CONNECTED; - m_pads[handle]->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; + pad->ldd = false; + pad->m_port_status &= ~CELL_PAD_STATUS_CONNECTED; + pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; num_ldd_pad--; } diff --git a/rpcs3/Input/pad_thread.h b/rpcs3/Input/pad_thread.h index 1939ce0104..70fb0f9de3 100644 --- a/rpcs3/Input/pad_thread.h +++ b/rpcs3/Input/pad_thread.h @@ -26,7 +26,7 @@ public: PadInfo& GetInfo() { return m_info; } std::array, CELL_PAD_MAX_PORT_NUM>& GetPads() { return m_pads; } - void SetRumble(const u32 pad, u8 large_motor, bool small_motor); + void SetRumble(u32 pad, u8 large_motor, bool small_motor); void SetIntercepted(bool intercepted); s32 AddLddPad(); diff --git a/rpcs3/Input/product_info.cpp b/rpcs3/Input/product_info.cpp index 825b50d0c1..120354014d 100644 --- a/rpcs3/Input/product_info.cpp +++ b/rpcs3/Input/product_info.cpp @@ -261,6 +261,11 @@ namespace input std::vector get_products_by_class(int class_id) { + if (class_id >= CELL_PAD_FAKE_TYPE_COPILOT_1 && class_id <= CELL_PAD_FAKE_TYPE_COPILOT_7) + { + class_id = CELL_PAD_PCLASS_TYPE_STANDARD; + } + std::vector ret; for (const auto& [type, product] : input_products) { diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index fdad85e08e..4710ad4ec4 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -183,6 +183,13 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti ui->chooseClass->addItem(tr("Top Shot Elite"), u32{CELL_PAD_FAKE_TYPE_TOP_SHOT_ELITE}); ui->chooseClass->addItem(tr("Top Shot Fearmaster"),u32{CELL_PAD_FAKE_TYPE_TOP_SHOT_FEARMASTER}); ui->chooseClass->addItem(tr("uDraw GameTablet"), u32{CELL_PAD_FAKE_TYPE_GAMETABLET}); + ui->chooseClass->addItem(tr("Copilot for Player 1"), u32{CELL_PAD_FAKE_TYPE_COPILOT_1}); + ui->chooseClass->addItem(tr("Copilot for Player 2"), u32{CELL_PAD_FAKE_TYPE_COPILOT_2}); + ui->chooseClass->addItem(tr("Copilot for Player 3"), u32{CELL_PAD_FAKE_TYPE_COPILOT_3}); + ui->chooseClass->addItem(tr("Copilot for Player 4"), u32{CELL_PAD_FAKE_TYPE_COPILOT_4}); + ui->chooseClass->addItem(tr("Copilot for Player 5"), u32{CELL_PAD_FAKE_TYPE_COPILOT_5}); + ui->chooseClass->addItem(tr("Copilot for Player 6"), u32{CELL_PAD_FAKE_TYPE_COPILOT_6}); + ui->chooseClass->addItem(tr("Copilot for Player 7"), u32{CELL_PAD_FAKE_TYPE_COPILOT_7}); connect(ui->chooseClass, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) {