CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/HLE/Plugins.cpp
Views: 1401
// Copyright (c) 2020- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <set>18#include <mutex>1920#include "Common/Data/Format/IniFile.h"21#include "Common/File/FileUtil.h"22#include "Common/File/DirListing.h"23#include "Common/Serialize/SerializeFuncs.h"24#include "Common/System/OSD.h"25#include "Common/Data/Text/I18n.h"26#include "Common/StringUtils.h"27#include "Core/Config.h"28#include "Core/MemMap.h"29#include "Core/System.h"30#include "Core/ELF/ParamSFO.h"31#include "Core/HLE/Plugins.h"32#include "Core/HLE/sceKernelModule.h"3334namespace HLEPlugins {3536std::mutex g_inputMutex;37float PluginDataAxis[JOYSTICK_AXIS_MAX];38std::map<int, uint8_t> PluginDataKeys;3940static bool anyEnabled = false;41static std::vector<std::string> prxPlugins;4243static PluginInfo ReadPluginIni(const std::string &subdir, IniFile &ini) {44PluginInfo info;4546auto options = ini.GetOrCreateSection("options");47std::string value;4849if (options->Get("type", &value, "")) {50if (value == "prx") {51info.type = PluginType::PRX;52}53}5455if (options->Get("filename", &value, "")) {56info.name = value;57info.filename = "ms0:/PSP/PLUGINS/" + subdir + "/" + value;58} else {59info.type = PluginType::INVALID;60}6162if (options->Get("name", &value, "")) {63info.name = value;64}6566options->Get("version", &info.version, 0);67options->Get("memory", &info.memory, 0);68if (info.memory > 93) {69ERROR_LOG(Log::System, "Plugin memory too high, using 93 MB");70info.memory = 93;71}7273if (info.version == 0) {74ERROR_LOG(Log::System, "Plugin without version ignored: %s", subdir.c_str());75info.type = PluginType::INVALID;76info.memory = 0;77} else if (info.type == PluginType::INVALID && !info.filename.empty()) {78ERROR_LOG(Log::System, "Plugin without valid type: %s", subdir.c_str());79}8081return info;82}8384std::vector<PluginInfo> FindPlugins(const std::string &gameID, const std::string &lang) {85std::vector<File::FileInfo> pluginDirs;86GetFilesInDir(GetSysDirectory(DIRECTORY_PLUGINS), &pluginDirs);8788std::vector<PluginInfo> found;89for (const auto &subdir : pluginDirs) {90const Path &subdirFullName = subdir.fullName;91if (!subdir.isDirectory || !File::Exists(subdirFullName / "plugin.ini"))92continue;9394IniFile ini;95if (!ini.Load(subdirFullName / "plugin.ini")) {96ERROR_LOG(Log::System, "Failed to load plugin ini: %s/plugin.ini", subdirFullName.c_str());97continue;98}99100std::set<std::string> matches;101102std::string gameIni;103104// TODO: Should just use getsection and fail the ini if not found, I guess.105const Section *games = ini.GetSection("games");106if (games) {107if (games->Get(gameID.c_str(), &gameIni, "")) {108if (!strcasecmp(gameIni.c_str(), "true")) {109matches.insert("plugin.ini");110} else if (!strcasecmp(gameIni.c_str(), "false")) {111continue;112} else if (!gameIni.empty()) {113matches.insert(gameIni);114}115}116117if (games->Get("ALL", &gameIni, "")) {118if (!strcasecmp(gameIni.c_str(), "true")) {119matches.insert("plugin.ini");120} else if (!gameIni.empty()) {121matches.insert(gameIni);122}123}124}125126std::set<std::string> langMatches;127for (const std::string &subini : matches) {128if (!ini.Load(subdirFullName / subini)) {129ERROR_LOG(Log::System, "Failed to load plugin ini: %s/%s", subdirFullName.c_str(), subini.c_str());130continue;131}132133found.push_back(ReadPluginIni(subdir.name, ini));134135if (ini.GetOrCreateSection("lang")->Get(lang.c_str(), &gameIni, "")) {136if (!gameIni.empty() && matches.find(gameIni) == matches.end()) {137langMatches.insert(gameIni);138}139}140}141142for (const std::string &subini : langMatches) {143if (!ini.Load(subdirFullName / subini)) {144ERROR_LOG(Log::System, "Failed to load plugin ini: %s/%s", subdirFullName.c_str(), subini.c_str());145continue;146}147148found.push_back(ReadPluginIni(subdir.name, ini));149}150}151152return found;153}154155void Init() {156if (!g_Config.bLoadPlugins) {157return;158}159160std::vector<PluginInfo> plugins = FindPlugins(g_paramSFO.GetDiscID(), g_Config.sLanguageIni);161for (auto &plugin : plugins) {162if (plugin.memory << 20 > Memory::g_MemorySize) {163Memory::g_MemorySize = plugin.memory << 20;164anyEnabled = true;165}166167if (plugin.type == PluginType::PRX) {168prxPlugins.push_back(plugin.filename);169anyEnabled = true;170}171}172}173174bool Load() {175bool started = false;176177auto sy = GetI18NCategory(I18NCat::SYSTEM);178179for (const std::string &filename : prxPlugins) {180if (!g_Config.bEnablePlugins) {181WARN_LOG(Log::System, "Plugins are disabled, ignoring enabled plugin %s", filename.c_str());182continue;183}184185std::string error_string = "";186SceUID module = KernelLoadModule(filename, &error_string);187if (!error_string.empty() || module < 0) {188ERROR_LOG(Log::System, "Unable to load plugin %s (module %d): '%s'", filename.c_str(), module, error_string.c_str());189continue;190}191192int ret = KernelStartModule(module, 0, 0, 0, nullptr, nullptr);193if (ret < 0) {194ERROR_LOG(Log::System, "Unable to start plugin %s: %08x", filename.c_str(), ret);195} else {196std::string shortName = Path(filename).GetFilename();197g_OSD.Show(OSDType::MESSAGE_SUCCESS, ApplySafeSubstitutions(sy->T("Loaded plugin: %1"), shortName), 6.0f);198started = true;199}200201INFO_LOG(Log::System, "Loaded plugin: %s", filename.c_str());202}203204std::lock_guard<std::mutex> guard(g_inputMutex);205PluginDataKeys.clear();206return started;207}208209void Unload() {210// Nothing to do here, for now.211}212213void Shutdown() {214prxPlugins.clear();215anyEnabled = false;216std::lock_guard<std::mutex> guard(g_inputMutex);217PluginDataKeys.clear();218}219220void DoState(PointerWrap &p) {221auto s = p.Section("Plugins", 0, 1);222if (!s)223return;224225// Remember if any were enabled.226Do(p, anyEnabled);227}228229bool HasEnabled() {230return anyEnabled;231}232233void SetKey(int key, uint8_t value) {234if (anyEnabled) {235std::lock_guard<std::mutex> guard(g_inputMutex);236PluginDataKeys[key] = value;237}238}239240uint8_t GetKey(int key) {241std::lock_guard<std::mutex> guard(g_inputMutex);242return PluginDataKeys[key];243}244245} // namespace246247248