Example #1
0
void emu_settings::OpenCorrectionDialog(QWidget* parent)
{
	if (m_broken_types.size() && QMessageBox::question(parent, tr("Fix invalid settings?"),
		tr(
			"Your config file contained one or more unrecognized settings.\n"
			"Their default value will be used until they are corrected.\n"
			"Consider that a correction might render them invalid for other versions of RPCS3.\n"
			"\n"
			"Do you wish to let the program correct them for you?\n"
			"This change will only be final when you save the config."
		),
		QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
	{
		for (const auto& type : m_broken_types)
		{
			std::string def = GetSettingDefault(type);
			std::string old = GetSetting(type);
			SetSetting(type, def);
			LOG_SUCCESS(GENERAL, "The config entry '%s' was corrected from '%s' to '%s'", GetSettingName(type), old, def);
		}

		m_broken_types.clear();
		LOG_SUCCESS(GENERAL, "You need to save the settings in order to make these changes permanent!");
	}
}
Example #2
0
XAudio2Thread::XAudio2Thread()
{
	if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
	{
		LOG_ERROR(GENERAL, "XAudio: failed to increase thread priority");
	}

	if (auto lib2_9 = LoadLibraryExW(L"XAudio2_9.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
	{
		// xa28* implementation is fully compatible with library 2.9
		xa28_init(lib2_9);

		m_funcs.destroy = &xa28_destroy;
		m_funcs.play    = &xa28_play;
		m_funcs.flush   = &xa28_flush;
		m_funcs.stop    = &xa28_stop;
		m_funcs.open    = &xa28_open;
		m_funcs.add     = &xa28_add;

		LOG_SUCCESS(GENERAL, "XAudio 2.9 initialized");
		return;
	}

	if (auto lib2_7 = LoadLibraryExW(L"XAudio2_7.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
	{
		xa27_init(lib2_7);

		m_funcs.destroy = &xa27_destroy;
		m_funcs.play    = &xa27_play;
		m_funcs.flush   = &xa27_flush;
		m_funcs.stop    = &xa27_stop;
		m_funcs.open    = &xa27_open;
		m_funcs.add     = &xa27_add;

		LOG_SUCCESS(GENERAL, "XAudio 2.7 initialized");
		return;
	}
	
	if (auto lib2_8 = LoadLibraryExW(L"XAudio2_8.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
	{
		xa28_init(lib2_8);

		m_funcs.destroy = &xa28_destroy;
		m_funcs.play    = &xa28_play;
		m_funcs.flush   = &xa28_flush;
		m_funcs.stop    = &xa28_stop;
		m_funcs.open    = &xa28_open;
		m_funcs.add     = &xa28_add;

		LOG_SUCCESS(GENERAL, "XAudio 2.8 initialized");
		return;
	}

	fmt::throw_exception("No supported XAudio2 library found");
}
Example #3
0
void PPUThread::dump_info() const
{
	if (~hle_code < 1024)
	{
		LOG_SUCCESS(HLE, "Last syscall: %lld (%s)", ~hle_code, SysCalls::GetFuncName(hle_code));
	}
	else if (hle_code)
	{
		LOG_SUCCESS(HLE, "Last function: %s (0x%llx)", SysCalls::GetFuncName(hle_code), hle_code);
	}

	CPUThread::dump_info();
}
Example #4
0
void game_list_frame::RemoveCustomConfiguration(int row)
{
	const std::string config_path = fs::get_config_dir() + "data/" + m_game_data[row].info.serial + "/config.yml";

	if (fs::is_file(config_path))
	{
		if (QMessageBox::question(this, tr("Confirm Delete"), tr("Delete custom game configuration?")) == QMessageBox::Yes)
		{
			if (fs::remove_file(config_path))
			{
				LOG_SUCCESS(GENERAL, "Removed configuration file: %s", config_path);
			}
			else
			{
				QMessageBox::warning(this, tr("Warning!"), tr("Failed to delete configuration file!"));
				LOG_FATAL(GENERAL, "Failed to delete configuration file: %s\nError: %s", config_path, fs::g_tls_error);
			}
		}
	}
	else
	{
		QMessageBox::warning(this, tr("Warning!"), tr("No custom configuration found!"));
		LOG_ERROR(GENERAL, "Configuration file not found: %s", config_path);
	}
}
Example #5
0
void MainFrame::BootGame(wxCommandEvent& WXUNUSED(event))
{
	bool stopped = false;

	if(Emu.IsRunning())
	{
		Emu.Pause();
		stopped = true;
	}

	wxDirDialog ctrl(this, L"Select game folder", wxEmptyString);

	if(ctrl.ShowModal() == wxID_CANCEL)
	{
		if(stopped) Emu.Resume();
		return;
	}

	Emu.Stop();
	
	if(Emu.BootGame(ctrl.GetPath().ToStdString()))
	{
		LOG_SUCCESS(HLE, "Game: boot done.");

		if (Ini.HLEAlwaysStart.GetValue() && Emu.IsReady())
		{
			Emu.Run();
		}
	}
	else
	{
		LOG_ERROR(HLE, "PS3 executable not found in selected folder (%s)", fmt::ToUTF8(ctrl.GetPath())); // passing std::string (test)
	}
}
Example #6
0
	virtual u8* allocateDataSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
	{
		// Simple allocation
		const u64 next = ::align((u64)m_next + size, 4096);

		if (next > (u64)s_memory + s_memory_size)
		{
			LOG_FATAL(GENERAL, "LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
			return nullptr;
		}

		if (!is_ro)
		{
			LOG_ERROR(GENERAL, "LLVM: Writeable data section not supported!");
		}

#ifdef _WIN32
		if (!VirtualAlloc(m_next, size, MEM_COMMIT, PAGE_READWRITE))
#else
		if (::mprotect(m_next, size, PROT_READ | PROT_WRITE))
#endif
		{
			LOG_FATAL(GENERAL, "LLVM: Failed to allocate memory at %p", m_next);
			return nullptr;
		}

		LOG_SUCCESS(GENERAL, "LLVM: Data section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x, %s)", sec_id, sec_name.data(), m_next, size, align, is_ro ? "ro" : "rw");
		return (u8*)std::exchange(m_next, (void*)next);
	}
Example #7
0
void MainFrame::BootElf(wxCommandEvent& WXUNUSED(event))
{
	bool stopped = false;

	if(Emu.IsRunning())
	{
		Emu.Pause();
		stopped = true;
	}

	wxFileDialog ctrl(this, L"Select (S)ELF", wxEmptyString, wxEmptyString,
		"(S)ELF files (*BOOT.BIN;*.elf;*.self)|*BOOT.BIN;*.elf;*.self"
		"|ELF files (BOOT.BIN;*.elf)|BOOT.BIN;*.elf"
		"|SELF files (EBOOT.BIN;*.self)|EBOOT.BIN;*.self"
		"|BOOT files (*BOOT.BIN)|*BOOT.BIN"
		"|BIN files (*.bin)|*.bin"
		"|All files (*.*)|*.*",
		wxFD_OPEN | wxFD_FILE_MUST_EXIST);

	if(ctrl.ShowModal() == wxID_CANCEL)
	{
		if(stopped) Emu.Resume();
		return;
	}

	LOG_NOTICE(LOADER, "(S)ELF: booting...");

	Emu.Stop();
	Emu.SetPath(fmt::ToUTF8(ctrl.GetPath()));
	Emu.Load();

	LOG_SUCCESS(LOADER, "(S)ELF: boot done.");
}
Example #8
0
int test_matrix_update(void) {
    Matrix *matrix = new_matrix();
    int res = fill_matrix(matrix, 20, 20);
    if(res != 0) {
        LOG_ERR("test matrix update -> fill matrix error");
        return res;
    }
    
    Element *new_element = element_new(10, 10, 10+10);
    Status status = matrix_update(matrix, new_element);
    if(status != STAT_SUCCESS) {
        LOG_ERR("test matrix update");
        return 1;
    } else {
        Element *element = matrix_find_by_pos(matrix, 10, 10);
        if(element == NULL) {
            LOG_ERR("test matrix update -> find element error");
            return 1;
        } else {
            if(new_element->value == element->value) {
                LOG_SUCCESS("test matrix update");
                return 0;
            } else {
                LOG_ERR("test matrix update, can't update");
                return 1;
            }
        }
    }
        
}
Example #9
0
int test_matrix_add_element(void) {
    Matrix *matrix = new_matrix();
    if(matrix == NULL) {
        LOG_ERR("add element to matrix -> new matrix");
        return 1;
    }
        
    Element *element = element_new(0,0,100);
    if(element == NULL) {
        safe_free(matrix);
        LOG_ERR("add element to matrix -> new element");
        return 1;
    }
    
    Status status = matrix_add(matrix, element);
    if(status != STAT_SUCCESS) {
        safe_free(matrix);
        safe_free(element);
        LOG_ERR("add element to matrix");
        return 1;    
    }
    
    safe_free(element);
    safe_free(matrix);
    LOG_SUCCESS("add element to matrix");
    return 0;
}
Example #10
0
	virtual u8* allocateCodeSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name) override
	{
		// Simple allocation
		const u64 next = ::align((u64)m_next + size, 4096);

		if (next > (u64)s_memory + s_memory_size)
		{
			LOG_FATAL(GENERAL, "LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
			return nullptr;
		}

#ifdef _WIN32
		if (!VirtualAlloc(m_next, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
#else
		if (::mprotect(m_next, size, PROT_READ | PROT_WRITE | PROT_EXEC))
#endif
		{
			LOG_FATAL(GENERAL, "LLVM: Failed to allocate memory at %p", m_next);
			return nullptr;
		}

		s_code_addr = (u8*)m_next;
		s_code_size = size;

		LOG_SUCCESS(GENERAL, "LLVM: Code section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x)", sec_id, sec_name.data(), m_next, size, align);
		return (u8*)std::exchange(m_next, (void*)next);
	}
Example #11
0
void MainFrame::BootGameAndRun(wxCommandEvent& WXUNUSED(event))
{
	bool stopped = false;

	if (Emu.IsRunning())
	{
		Emu.Pause();
		stopped = true;
	}

	wxDirDialog ctrl(this, L"Select game folder", wxEmptyString);

	if (ctrl.ShowModal() == wxID_CANCEL)
	{
		if (stopped) Emu.Resume();
		return;
	}

	Emu.Stop();

	if (Emu.BootGame(ctrl.GetPath().ToStdString()))
	{
		LOG_SUCCESS(HLE, "Game: boot done.");
	}
	else
	{
		LOG_ERROR(HLE, "PS3 executable not found in selected folder (%s)", ctrl.GetPath().wx_str());
	}

	if (Emu.IsReady())
	{
		Emu.Run();
	}
}
Example #12
0
int test_matrix_find_element(void) {
    Element *element_by_pos;
    Element *element_by_val;
    Matrix *matrix = new_matrix();
    int res = fill_matrix(matrix, 20, 20);
    if(res != 0) {
        LOG_ERR("test matrix find element -> fill matrix error");
        return res;
    }
    
    //find element by pos
    element_by_pos = matrix_find_by_pos(matrix, 3, 15);
    if(element_by_pos == NULL) {
        LOG_ERR("find element from matrix by pos");
        return 1;
    }
    if(element_by_pos->value == 3*15) {
        LOG_SUCCESS("find element from matrix by pos");
    } else {
        LOG_ERR("find element from matrix by pos");
        return 1;
    }
    
    //find element by value
    element_by_val = matrix_find_by_val(matrix, 3*15);
    if(element_by_val == NULL) {
        LOG_ERR("find element from matrix by value");
        return 1;
    }
    while(element_by_val != NULL) {
        if(element_by_val->row == 3 && element_by_val->col == 15) {
            LOG_SUCCESS("find element from matrix by value");
            break;
        } else if(element_by_val->next == NULL){
            LOG_ERR("find element from matrix by value");
            return 1;
        } else {
            element_by_val = element_by_val->next;
        }
    }
    
    return 0;
}
Example #13
0
int test_config_new(void) {
    Config *config = config_new(TEST_RAW_LEN, TEST_COL_LEN);
    if(config == NULL) {
        LOG_ERR("new config");
        return 1;
    } else {
        LOG_SUCCESS("new config");
        return 0;
    }
}
Example #14
0
void ARMv7Thread::dump_info() const
{
	if (hle_func)
	{
		const auto func = get_psv_func_by_nid(hle_func);
		
		LOG_SUCCESS(HLE, "Last function: %s (0x%x)", func ? func->name : "?????????", hle_func);
	}

	CPUThread::dump_info();
}
Example #15
0
bool debug::autopause::pause_function(u32 code)
{
	if (g_cfg_debug_autopause_func_call && get_instance().m_pause_function.count(code) != 0)
	{
		Emu.Pause();
		LOG_SUCCESS(HLE, "Autopause triggered at function 0x%08x", code);
		return true;
	}

	return false;
}
Example #16
0
bool debug::autopause::pause_syscall(u64 code)
{
	if (g_cfg_debug_autopause_syscall && get_instance().m_pause_syscall.count(code) != 0)
	{
		Emu.Pause();
		LOG_SUCCESS(HLE, "Autopause triggered at syscall %lld", code);
		return true;
	}

	return false;
}
Example #17
0
int test_new_element(void) {
    Element *element = element_new(0,0,100);
    if(element == NULL) {
        LOG_ERR("new element");
        return 1;
    }

    safe_free(element);
    LOG_SUCCESS("new element");
    return 0;
        
}
Example #18
0
int test_matrix_print(void) {
    Matrix *matrix = new_matrix();
    int res = fill_matrix(matrix, 20, 20);
    if(res != 0) {
        LOG_ERR("test matrix print -> fill matrix error");
        return res;
    }
    
    matrix_print(matrix);
    LOG_SUCCESS("matrix print");
    return 0;
}
Example #19
0
static void FunctionStackOne()
{
	int nRandomNumber = rand();
	LOG_ERROR(nRandomNumber % 2);
	LOG_SUCCESS(nRandomNumber % 2);

Error:
Success:
Exit0:
Exit1:
	return;
}
Example #20
0
int sys_process_exit(s32 errorcode)
{
	sc_p.Warning("sys_process_exit(%d)", errorcode);
	Emu.Pause(); // Emu.Stop() does crash
	LOG_SUCCESS(HLE, "Process finished");

	if (Ini.HLEExitOnStop.GetValue())
	{
		Ini.HLEExitOnStop.SetValue(false);
		// TODO: Find a way of calling Emu.Stop() and/or exiting RPCS3 (that is, TheApp->Exit()) without crashes
	}
	return CELL_OK;
}
Example #21
0
int test_new_matrix(void) {
    Config *config = config_new(TEST_RAW_LEN, TEST_COL_LEN);
    Matrix *matrix = matrix_new(config);
    if(matrix == NULL) {
        LOG_ERR("new matrix");
        return 1;
    }
    
    safe_free(config);
    safe_free(matrix);
    LOG_SUCCESS("new matrix");
    return 0;
}
Example #22
0
void game_list_frame::Boot(int row)
{
	const std::string& path = Emu.GetGameDir() + m_game_data[row].info.root;
	emit RequestIconPathSet(path);

	Emu.Stop();

	if (!Emu.BootGame(path))
	{
		QMessageBox::warning(this, tr("Warning!"), tr("Failed to boot ") + qstr(m_game_data[row].info.root));
		LOG_ERROR(LOADER, "Failed to boot /dev_hdd0/game/%s", m_game_data[row].info.root);
	}
	else
	{
		LOG_SUCCESS(LOADER, "Boot from gamelist per Boot: done");
		emit RequestAddRecentGame(q_string_pair(qstr(path), qstr("[" + m_game_data[row].info.serial + "] " + m_game_data[row].info.name)));
	}
}
Example #23
0
int test_matrix_clear(void) {
    Matrix *matrix = new_matrix();
    int res = fill_matrix(matrix, 20, 20);
    if(res != 0) {
        LOG_ERR("test matrix clear -> fill matrix error");
        return res;
    }
    
    Status status = matrix_clear(matrix);
    if(status != STAT_SUCCESS) {
        LOG_ERR("test matrix clear");
        return 1;
    } else {
        LOG_SUCCESS("test matrix clear");
        return 0;
    }
    
}
Example #24
0
void MainFrame::DecryptSPRXLibraries(wxCommandEvent& WXUNUSED(event))
{
	wxFileDialog ctrl(this, L"Select SPRX files", wxEmptyString, wxEmptyString,
		"SPRX files (*.sprx)|*sprx",
		wxFD_OPEN | wxFD_MULTIPLE);

	if (ctrl.ShowModal() == wxID_CANCEL)
	{
		return;
	}

	wxArrayString modules;
	ctrl.GetPaths(modules);

	LOG_NOTICE(GENERAL, "Decrypting SPRX libraries...");

	for (const wxString& module : modules)
	{
		std::string prx_path = fmt::ToUTF8(module);
		const std::string& prx_dir = fs::get_parent_dir(prx_path);

		if (IsSelf(prx_path))
		{
			const std::size_t prx_ext_pos = prx_path.find_last_of('.');
			const std::string& prx_ext = fmt::to_upper(prx_path.substr(prx_ext_pos != -1 ? prx_ext_pos : prx_path.size()));
			const std::string& prx_name = prx_path.substr(prx_dir.size());

			prx_path.erase(prx_path.size() - 4, 1); // change *.sprx to *.prx

			if (DecryptSelf(prx_path, prx_dir + prx_name))
			{
				LOG_SUCCESS(GENERAL, "Decrypted %s", prx_dir + prx_name);
			}

			else
			{
				LOG_ERROR(GENERAL, "Failed to decrypt %s", prx_dir + prx_name);
			}
		}
	}

	LOG_NOTICE(GENERAL, "Finished decrypting all SPRX libraries.");
}
Example #25
0
void game_list_frame::doubleClickedSlot(const QModelIndex& index)
{
	int i;

	if (m_isListLayout)
	{
		i = gameList->item(index.row(), 0)->data(Qt::UserRole).toInt();
	}
	else
	{
		i = m_xgrid->item(index.row(), index.column())->data(Qt::ItemDataRole::UserRole).toInt();
	}

	QString category = qstr(m_game_data[i].info.category);
	
	// Boot these categories
	if (category == category::hdd_Game || category == category::disc_Game || category == category::audio_Video)
	{
		const std::string& path = Emu.GetGameDir() + m_game_data[i].info.root;
		emit RequestIconPathSet(path);
	
		Emu.Stop();
	
		if (!Emu.BootGame(path))
		{
			LOG_ERROR(LOADER, "Failed to boot /dev_hdd0/game/%s", m_game_data[i].info.root);
		}
		else
		{
			LOG_SUCCESS(LOADER, "Boot from gamelist per doubleclick: done");
			emit RequestAddRecentGame(q_string_pair(qstr(path), qstr("[" + m_game_data[i].info.serial + "] " + m_game_data[i].info.name)));
		}
	}
	else
	{
		open_dir(Emu.GetGameDir() + m_game_data[i].info.root);
	}
}
Example #26
0
void ThreadBase::Start()
{
	if(m_executor) Stop();

	std::lock_guard<std::mutex> lock(m_main_mutex);

	m_destroy = false;
	m_alive = true;

	m_executor = new std::thread(
		[this]()
		{
			g_tls_this_thread = this;
			g_thread_count++;

			try
			{
				Task();
			}
			catch (const std::string& e)
			{
				LOG_ERROR(GENERAL, "Exception: %s", e.c_str());
			}
			catch (const char* e)
			{
				LOG_ERROR(GENERAL, "Exception: %s", e);
			}
			catch (int exitcode)
			{
				LOG_SUCCESS(GENERAL, "Exit Code: %d", exitcode);
			}

			m_alive = false;
			g_thread_count--;
		});
}
bool GLFont::initialize( const std::string &name )
{
	LOG_INFO("Creating font");
	_Texture = shared_ptr< Texture >( new Texture(name) );
	_Renderer->load_texture( _Texture );

	LOG_INFO("Creating font display list");
	float x, y;

	_DisplayList = glGenLists(256);
	_Renderer->apply_render_state( _Texture );
	_ActiveColor = Color( Vector3ub( 255, 255, 255 ) );

	for (int i=0; i<256; ++i)
	{
		x = float(i%16)/16.0f;
		y = float(i/16)/16.0f;

		glNewList( _DisplayList + i, GL_COMPILE );
			glBegin( GL_QUADS );
				glTexCoord2f( x+0.0125f, 1-y-0.0625f );
				glVertex2i( 0, 0 );
				glTexCoord2f( x+0.075f,	1-y-0.0625f );
				glVertex2i( 16, 0 );
				glTexCoord2f( x+0.075f, 1-y );
				glVertex2i( 16, 16 );
				glTexCoord2f( x+0.0125f, 1-y );
				glVertex2i( 0, 16 );
			glEnd();
			glTranslated( 10, 0, 0);
		glEndList();
	}

	LOG_SUCCESS( "Font created successfully -- " + name );
	return true;
}
Example #28
0
void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist, const std::vector<std::string>& buttons)
{
	if (get_blacklist)
		blacklist.clear();

	int device_number = GetDeviceNumber(padId);
	if (device_number < 0)
		return fail_callback(padId);

	DWORD dwResult;
	XINPUT_STATE state;
	ZeroMemory(&state, sizeof(XINPUT_STATE));

	// Simply get the state of the controller from XInput.
	dwResult = (*xinputGetState)(static_cast<u32>(device_number), &state);
	if (dwResult != ERROR_SUCCESS)
		return fail_callback(padId);

	// Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed.
	// Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold)
	// Use a pair to get all the legally pressed buttons and use the one with highest value (prioritize first)
	std::pair<u16, std::string> pressed_button = { 0, "" };
	auto data = GetButtonValues(state);
	for (const auto& button : button_list)
	{
		u32 keycode = button.first;
		u16 value = data[keycode];

		if (!get_blacklist && std::find(blacklist.begin(), blacklist.end(), keycode) != blacklist.end())
			continue;

		if (((keycode < XInputKeyCodes::LT) && (value > 0))
		 || ((keycode == XInputKeyCodes::LT) && (value > m_trigger_threshold))
		 || ((keycode == XInputKeyCodes::RT) && (value > m_trigger_threshold))
		 || ((keycode >= XInputKeyCodes::LSXNeg && keycode <= XInputKeyCodes::LSYPos) && (value > m_thumb_threshold))
		 || ((keycode >= XInputKeyCodes::RSXNeg && keycode <= XInputKeyCodes::RSYPos) && (value > m_thumb_threshold)))
		{
			if (get_blacklist)
			{
				blacklist.emplace_back(keycode);
				LOG_ERROR(HLE, "XInput Calibration: Added key [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value);
			}
			else if (value > pressed_button.first)
				pressed_button = { value, button.second };
		}
	}

	if (get_blacklist)
	{
		if (blacklist.size() <= 0)
			LOG_SUCCESS(HLE, "XInput Calibration: Blacklist is clear. No input spam detected");
		return;
	}

	int preview_values[6] = { data[LT], data[RT], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] };

	if (pressed_button.first > 0)
		return callback(pressed_button.first, pressed_button.second, padId, preview_values);
	else
		return callback(0, "", padId, preview_values);
}
Example #29
0
void xinput_pad_handler::ThreadProc()
{
	for (int i = 0; i < static_cast<int>(bindings.size()); ++i)
	{
		auto& bind = bindings[i];
		m_dev = bind.first;
		auto padnum = m_dev->deviceNumber;
		auto profile = m_dev->config;
		auto pad = bind.second;

		result = (*xinputGetState)(padnum, &state);

		switch (result)
		{
		case ERROR_DEVICE_NOT_CONNECTED:
		{
			if (last_connection_status[i] == true)
			{
				LOG_ERROR(HLE, "XInput device %d disconnected", padnum);
				pad->m_port_status &= ~CELL_PAD_STATUS_CONNECTED;
				pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
				last_connection_status[i] = false;
				connected--;
			}
			continue;
		}
		case ERROR_SUCCESS:
		{
			if (last_connection_status[i] == false)
			{
				LOG_SUCCESS(HLE, "XInput device %d reconnected", padnum);
				pad->m_port_status |= CELL_PAD_STATUS_CONNECTED;
				pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
				last_connection_status[i] = true;
				connected++;
			}

			std::array<u16, XInputKeyCodes::KeyCodeCount> button_values = GetButtonValues(state);

			// Translate any corresponding keycodes to our normal DS3 buttons and triggers
			for (auto& btn : pad->m_buttons)
			{
				btn.m_value = button_values[btn.m_keyCode];
				TranslateButtonPress(btn.m_keyCode, btn.m_pressed, btn.m_value);
			}

			for (const auto& btn : pad->m_buttons)
			{
				if (btn.m_pressed)
				{
					SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
					break;
				}
			}

			// used to get the absolute value of an axis
			s32 stick_val[4];

			// Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now)
			for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++)
			{
				bool pressed;

				// m_keyCodeMin is the mapped key for left or down
				u32 key_min = pad->m_sticks[i].m_keyCodeMin;
				u16 val_min = button_values[key_min];
				TranslateButtonPress(key_min, pressed, val_min, true);

				// m_keyCodeMax is the mapped key for right or up
				u32 key_max = pad->m_sticks[i].m_keyCodeMax;
				u16 val_max = button_values[key_max];
				TranslateButtonPress(key_max, pressed, val_max, true);

				// cancel out opposing values and get the resulting difference
				stick_val[i] = val_max - val_min;
			}

			u16 lx, ly, rx, ry;

			// Normalize our two stick's axis based on the thresholds
			std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone);
			std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], profile->rstickdeadzone);

			if (profile->padsquircling != 0)
			{
				std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling);
				std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling);
			}

			pad->m_sticks[0].m_value = lx;
			pad->m_sticks[1].m_value = 255 - ly;
			pad->m_sticks[2].m_value = rx;
			pad->m_sticks[3].m_value = 255 - ry;

			// Receive Battery Info. If device is not on cable, get battery level, else assume full
			XINPUT_BATTERY_INFORMATION battery_info;
			(*xinputGetBatteryInformation)(padnum, BATTERY_DEVTYPE_GAMEPAD, &battery_info);
			pad->m_cable_state = battery_info.BatteryType == BATTERY_TYPE_WIRED ? 1 : 0;
			pad->m_battery_level = pad->m_cable_state ? BATTERY_LEVEL_FULL : battery_info.BatteryLevel;

			// The left motor is the low-frequency rumble motor. The right motor is the high-frequency rumble motor.
			// The two motors are not the same, and they create different vibration effects. Values range between 0 to 65535.
			int idx_l = profile->switch_vibration_motors ? 1 : 0;
			int idx_s = profile->switch_vibration_motors ? 0 : 1;

			int speed_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min;
			int speed_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min;

			m_dev->newVibrateData = m_dev->newVibrateData || m_dev->largeVibrate != speed_large || m_dev->smallVibrate != speed_small;

			m_dev->largeVibrate = speed_large;
			m_dev->smallVibrate = speed_small;

			// XBox One Controller can't handle faster vibration updates than ~10ms. Elite is even worse. So I'll use 20ms to be on the safe side. No lag was noticable.
			if (m_dev->newVibrateData && (clock() - m_dev->last_vibration > 20))
			{
				XINPUT_VIBRATION vibrate;
				vibrate.wLeftMotorSpeed = speed_large;
				vibrate.wRightMotorSpeed = speed_small;

				if ((*xinputSetState)(padnum, &vibrate) == ERROR_SUCCESS)
				{
					m_dev->newVibrateData = false;
					m_dev->last_vibration = clock();
				}
			}
			break;
		}
		default:
			break;
		}
	}
}
void game_compatibility::RequestCompatibility(bool online)
{
	// Creates new map from database
	auto ReadJSON = [=](const QJsonObject& json_data, bool after_download)
	{
		int return_code = json_data["return_code"].toInt();

		if (return_code < 0)
		{
			if (after_download)
			{
				std::string error_message;
				switch (return_code)
				{
				case -1:
					error_message = "Server Error - Internal Error";
					break;
				case -2:
					error_message = "Server Error - Maintenance Mode";
					break;
				default:
					error_message = "Server Error - Unknown Error";
					break;
				}
				LOG_ERROR(GENERAL, "Compatibility error: { %s: return code %d }", error_message, return_code);
				Q_EMIT DownloadError(qstr(error_message) + " " + QString::number(return_code));
			}
			else
			{
				LOG_ERROR(GENERAL, "Compatibility error: { Database Error - Invalid: return code %d }", return_code);
			}
			return false;
		}

		if (!json_data["results"].isObject())
		{
			LOG_ERROR(GENERAL, "Compatibility error: { Database Error - No Results found }");
			return false;
		}

		m_compat_database.clear();

		QJsonObject json_results = json_data["results"].toObject();

		// Retrieve status data for every valid entry
		for (const auto& key : json_results.keys())
		{
			if (!json_results[key].isObject())
			{
				LOG_ERROR(GENERAL, "Compatibility error: { Database Error - Unusable object %s }", sstr(key));
				continue;
			}

			QJsonObject json_result = json_results[key].toObject();

			// Retrieve compatibility information from json
			compat_status status = Status_Data.at(json_result.value("status").toString("NoResult"));

			// Add date if possible
			status.date = json_result.value("date").toString();

			// Add status to map
			m_compat_database.emplace(std::pair<std::string, compat_status>(sstr(key), status));
		}

		return true;
	};

	if (!online)
	{
		// Retrieve database from file
		QFile file(m_filepath);

		if (!file.exists())
		{
			LOG_NOTICE(GENERAL, "Compatibility notice: { Database file not found: %s }", sstr(m_filepath));
			return;
		}

		if (!file.open(QIODevice::ReadOnly))
		{
			LOG_ERROR(GENERAL, "Compatibility error: { Database Error - Could not read database from file: %s }", sstr(m_filepath));
			return;
		}

		QByteArray data = file.readAll();
		file.close();

		LOG_NOTICE(GENERAL, "Compatibility notice: { Finished reading database from file: %s }", sstr(m_filepath));

		// Create new map from database
		ReadJSON(QJsonDocument::fromJson(data).object(), online);

		return;
	}

	if (QSslSocket::supportsSsl() == false)
	{
		LOG_ERROR(GENERAL, "Can not retrieve the online database! Please make sure your system supports SSL.");
		QMessageBox::warning(nullptr, tr("Warning!"), tr("Can not retrieve the online database! Please make sure your system supports SSL."));
		return;
	}

	LOG_NOTICE(GENERAL, "SSL supported! Beginning compatibility database download from: %s", sstr(m_url));

	// Send request and wait for response
	m_network_access_manager.reset(new QNetworkAccessManager());
	QNetworkReply* network_reply = m_network_access_manager->get(m_network_request);

	// Show Progress
	m_progress_dialog.reset(new QProgressDialog(tr(".Please wait."), tr("Abort"), 0, 100));
	m_progress_dialog->setWindowTitle(tr("Downloading Database"));
	m_progress_dialog->setFixedWidth(QLabel("This is the very length of the progressbar due to hidpi reasons.").sizeHint().width());
	m_progress_dialog->setValue(0);
	m_progress_dialog->show();

	// Animate progress dialog a bit more
	m_progress_timer.reset(new QTimer(this));
	connect(m_progress_timer.get(), &QTimer::timeout, [&]()
	{
		switch (++m_timer_count % 3)
		{
		case 0:
			m_timer_count = 0;
			m_progress_dialog->setLabelText(tr(".Please wait."));
			break;
		case 1:
			m_progress_dialog->setLabelText(tr("..Please wait.."));
			break;
		default:
			m_progress_dialog->setLabelText(tr("...Please wait..."));
			break;
		}
	});
	m_progress_timer->start(500);

	// Handle abort
	connect(m_progress_dialog.get(), &QProgressDialog::rejected, network_reply, &QNetworkReply::abort);

	// Handle progress
	connect(network_reply, &QNetworkReply::downloadProgress, [&](qint64 bytesReceived, qint64 bytesTotal)
	{
		m_progress_dialog->setMaximum(bytesTotal);
		m_progress_dialog->setValue(bytesReceived);
	});

	// Handle response according to its contents
	connect(network_reply, &QNetworkReply::finished, [=]()
	{
		// Clean up Progress Dialog
		if (m_progress_dialog)
		{
			m_progress_dialog->close();
		}
		if (m_progress_timer)
		{
			m_progress_timer->stop();
		}

		// Handle Errors
		if (network_reply->error() != QNetworkReply::NoError)
		{
			// We failed to retrieve a new database, therefore refresh gamelist to old state
			QString error = network_reply->errorString();
			Q_EMIT DownloadError(error);
			LOG_ERROR(GENERAL, "Compatibility error: { Network Error - %s }", sstr(error));
			return;
		}

		LOG_NOTICE(GENERAL, "Compatibility notice: { Database download finished }");

		// Read data from network reply
		QByteArray data = network_reply->readAll();
		network_reply->deleteLater();

		// Create new map from database and write database to file if database was valid
		if (ReadJSON(QJsonDocument::fromJson(data).object(), online))
		{
			// We have a new database in map, therefore refresh gamelist to new state
			Q_EMIT DownloadFinished();

			// Write database to file
			QFile file(m_filepath);

			if (file.exists())
			{
				LOG_NOTICE(GENERAL, "Compatibility notice: { Database file found: %s }", sstr(m_filepath));
			}

			if (!file.open(QIODevice::WriteOnly))
			{
				LOG_ERROR(GENERAL, "Compatibility error: { Database Error - Could not write database to file: %s }", sstr(m_filepath));
				return;
			}

			file.write(data);
			file.close();

			LOG_SUCCESS(GENERAL, "Compatibility success: { Write database to file: %s }", sstr(m_filepath));
		}
	});

	// We want to retrieve a new database, therefore refresh gamelist and indicate that
	Q_EMIT DownloadStarted();
}