Beispiel #1
0
CFileItem* CSavestateDatabase::CreateFileItem(const CVariant& object) const
{
  using namespace ADDON;

  CSavestate save;
  save.Deserialize(object);
  CFileItem* item = new CFileItem(save.Label());

  item->SetPath(save.Path());
  if (!save.Thumbnail().empty())
    item->SetArt("thumb", save.Thumbnail());
  else
  {
    AddonPtr addon;
    if (CAddonMgr::GetInstance().GetAddon(save.GameClient(), addon, ADDON_GAMEDLL))
      item->SetArt("thumb", addon->Icon());
  }

  // Use the slot number as the second label
  if (save.Type() == SAVETYPE::SLOT)
    item->SetLabel2(StringUtils::Format("%u", save.Slot()));

  item->m_dateTime = save.Timestamp();
  item->SetProperty(FILEITEM_PROPERTY_SAVESTATE_DURATION, static_cast<uint64_t>(save.PlaytimeWallClock()));
  item->GetGameInfoTag()->SetGameClient(save.GameClient());
  item->m_dwSize = save.Size();
  item->m_bIsFolder = false;

  return item;
}
Beispiel #2
0
bool CRetroPlayer::OpenFile(const CFileItem& file, const CPlayerOptions& options)
{
  CFileItem fileCopy(file);

  // When playing a game, set the game client that we'll use to open the game
  // Currently this may prompt the user, the goal is to figure this out silently
  if (!GAME::CGameUtils::FillInGameClient(fileCopy, true))
  {
    CLog::Log(LOGINFO, "RetroPlayer: No compatible game client selected, aborting playback");
    return false;
  }

  // Check if we should open in standalone mode
  const bool bStandalone = fileCopy.GetPath().empty();

  m_processInfo.reset(CRPProcessInfo::CreateInstance());
  if (!m_processInfo)
  {
    CLog::Log(LOGERROR, "Failed to create RetroPlayer - no process info registered");
    return false;
  }

  m_processInfo->SetDataCache(&CServiceBroker::GetDataCacheCore());
  m_processInfo->ResetInfo();

  m_renderManager.reset(new CRPRenderManager(*m_processInfo));

  CSingleLock lock(m_mutex);

  if (IsPlaying())
    CloseFile();

  PrintGameInfo(fileCopy);

  bool bSuccess = false;

  std::string gameClientId = fileCopy.GetGameInfoTag()->GetGameClient();

  ADDON::AddonPtr addon;
  if (gameClientId.empty())
  {
    CLog::Log(LOGERROR, "Can't play game, no game client was passed to RetroPlayer!");
  }
  else if (!CServiceBroker::GetAddonMgr().GetAddon(gameClientId, addon, ADDON::ADDON_GAMEDLL))
  {
    CLog::Log(LOGERROR, "Can't find add-on %s for game file!", gameClientId.c_str());
  }
  else
  {
    m_gameClient = std::static_pointer_cast<CGameClient>(addon);
    if (m_gameClient->Initialize())
    {
      m_audio.reset(new CRetroPlayerAudio(*m_processInfo));
      m_video.reset(new CRetroPlayerVideo(*m_renderManager, *m_processInfo));
      m_input.reset(new CRetroPlayerInput(CServiceBroker::GetPeripherals()));

      if (!bStandalone)
      {
        std::string redactedPath = CURL::GetRedacted(fileCopy.GetPath());
        CLog::Log(LOGINFO, "RetroPlayer: Opening: %s", redactedPath.c_str());
        bSuccess = m_gameClient->OpenFile(fileCopy, m_audio.get(), m_video.get(), m_input.get());
      }
      else
      {
        CLog::Log(LOGINFO, "RetroPlayer: Opening standalone");
        bSuccess = m_gameClient->OpenStandalone(m_audio.get(), m_video.get(), m_input.get());
      }

      if (bSuccess)
        CLog::Log(LOGDEBUG, "RetroPlayer: Using game client %s", gameClientId.c_str());
      else
        CLog::Log(LOGERROR, "RetroPlayer: Failed to open file using %s", gameClientId.c_str());
    }
    else
      CLog::Log(LOGERROR, "RetroPlayer: Failed to initialize %s", gameClientId.c_str());
  }

  if (bSuccess && !bStandalone)
  {
    std::string savestatePath = CSavestateUtils::MakeMetadataPath(fileCopy.GetPath());

    CSavestate save;
    if (save.Deserialize(savestatePath))
    {
      // Check if game client is the same
      if (save.GameClient() != m_gameClient->ID())
      {
        ADDON::AddonPtr addon;
        if (CServiceBroker::GetAddonMgr().GetAddon(save.GameClient(), addon))
        {
          // Warn the user that continuing with a different game client will
          // overwrite the save
          bool dummy;
          if (!CGUIDialogYesNo::ShowAndGetInput(438, StringUtils::Format(g_localizeStrings.Get(35217), addon->Name()), dummy, 222, 35218, 0))
            bSuccess = false;
        }
      }
    }

    if (bSuccess)
    {
      std::string redactedSavestatePath = CURL::GetRedacted(savestatePath);
      CLog::Log(LOGDEBUG, "RetroPlayer: Loading savestate %s", redactedSavestatePath.c_str());

      if (!SetPlayerState(savestatePath))
        CLog::Log(LOGERROR, "RetroPlayer: Failed to load savestate");
    }
  }

  if (bSuccess)
  {
    RegisterWindowCallbacks();
    SetSpeedInternal(1.0);
    m_callback.OnPlayBackStarted(fileCopy);
    if (!bStandalone)
      m_autoSave.reset(new CRetroPlayerAutoSave(*m_gameClient));
    m_processInfo->SetVideoFps(static_cast<float>(m_gameClient->Timing().GetFrameRate()));
  }
  else
  {
    m_gameClient.reset();
    m_audio.reset();
    m_video.reset();
  }

  return bSuccess;
}
std::string CGUIDialogSelectGameClient::ShowAndGetGameClient(const std::string &gamePath, const GameClientVector& candidates, const GameClientVector& installable)
{
  std::string gameClient;

  LogGameClients(candidates, installable);

  std::string extension = URIUtils::GetExtension(gamePath);
  std::string xmlPath = CSavestateUtils::MakeMetadataPath(gamePath);

  // Load savestate
  CSavestate save;
  CSavestateDatabase db;
  CLog::Log(LOGDEBUG, "Select game client dialog: Loading savestate metadata %s", CURL::GetRedacted(xmlPath).c_str());
  const bool bLoaded = db.GetSavestate(xmlPath, save);

  // Get savestate game client
  std::string saveGameClient;
  if (bLoaded)
  {
    saveGameClient = save.GameClient();
    CLog::Log(LOGDEBUG, "Select game client dialog: Auto-selecting %s", saveGameClient.c_str());
  }

  // "Select emulator for {0:s}"
  CGUIDialogSelect *dialog = GetDialog(StringUtils::Format(g_localizeStrings.Get(35258), extension));
  if (dialog != nullptr)
  {
    // Turn the addons into items
    CFileItemList items;
    for (const auto &candidate : candidates)
    {
      CFileItemPtr item(XFILE::CAddonsDirectory::FileItemFromAddon(candidate, candidate->ID()));
      item->SetLabel2(g_localizeStrings.Get(35257)); // "Installed"
      if (item->GetPath() == saveGameClient)
        item->SetLabel2(item->GetLabel2() + ", " + g_localizeStrings.Get(35259)); // "Saved"
      items.Add(std::move(item));
    }
    for (const auto &addon : installable)
    {
      CFileItemPtr item(XFILE::CAddonsDirectory::FileItemFromAddon(addon, addon->ID()));
      items.Add(std::move(item));
    }
    items.Sort(SortByLabel, SortOrderAscending);

    dialog->SetItems(items);

    for (int i = 0; i < items.Size(); i++)
    {
      if (items[i]->GetPath() == saveGameClient)
        dialog->SetSelected(i);
    }

    dialog->Open();

    // If the "Get More" button has been pressed, show a list of installable addons
    if (dialog->IsConfirmed())
    {
      int selectedIndex = dialog->GetSelectedItem();

      if (0 <= selectedIndex && selectedIndex < items.Size())
      {
        gameClient = items[selectedIndex]->GetPath();

        CLog::Log(LOGDEBUG, "Select game client dialog: User selected emulator %s", gameClient.c_str());

        if (Install(gameClient))
        {
          // If the addon is disabled we need to enable it
          if (!Enable(gameClient))
            CLog::Log(LOGDEBUG, "Failed to enable game client %s", gameClient.c_str());
        }
        else
          CLog::Log(LOGDEBUG, "Failed to install game client: %s", gameClient.c_str());
      }
      else
      {
        CLog::Log(LOGDEBUG, "Select game client dialog: User selected invalid emulator %d", selectedIndex);
      }
    }
    else
    {
      CLog::Log(LOGDEBUG, "Select game client dialog: User cancelled game client installation");
    }
  }

  return gameClient;
}