Skip to content
Permalink
Browse files

Merge pull request #7629 from JosJuice/auto-disc-change

Automatic disc change for 2-disc games
  • Loading branch information...
JMC47 committed Jan 15, 2019
2 parents e253525 + 0c62292 commit 1d3e3de44b177eb7bdd07a02afefb83ac9ba5812
Showing with 480 additions and 124 deletions.
  1. +2 −2 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java
  2. +18 −8 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java
  3. +4 −0 ...d/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java
  4. +1 −0 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java
  5. +10 −11 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java
  6. +4 −0 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.java
  7. +20 −0 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/GameFileCacheService.java
  8. +1 −0 Source/Android/app/src/main/res/values/strings.xml
  9. +13 −0 Source/Android/jni/AndroidCommon/AndroidCommon.cpp
  10. +1 −0 Source/Android/jni/AndroidCommon/AndroidCommon.h
  11. +16 −0 Source/Android/jni/GameList/GameFile.cpp
  12. +10 −9 Source/Android/jni/MainAndroid.cpp
  13. +98 −16 Source/Core/Core/Boot/Boot.cpp
  14. +4 −1 Source/Core/Core/Boot/Boot.h
  15. +1 −0 Source/Core/Core/Config/MainSettings.cpp
  16. +1 −0 Source/Core/Core/Config/MainSettings.h
  17. +1 −0 Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp
  18. +77 −4 Source/Core/Core/HW/DVD/DVDInterface.cpp
  19. +6 −3 Source/Core/Core/HW/DVD/DVDInterface.h
  20. +10 −0 Source/Core/Core/HW/DVD/DVDThread.cpp
  21. +1 −0 Source/Core/Core/HW/DVD/DVDThread.h
  22. +5 −21 Source/Core/Core/Movie.cpp
  23. +4 −1 Source/Core/DolphinNoGUI/MainNoGUI.cpp
  24. +11 −0 Source/Core/DolphinQt/GameList/GameList.cpp
  25. +2 −0 Source/Core/DolphinQt/GameList/GameList.h
  26. +32 −3 Source/Core/DolphinQt/GameList/GameListModel.cpp
  27. +4 −1 Source/Core/DolphinQt/GameList/GameListModel.h
  28. +1 −0 Source/Core/DolphinQt/Info.plist.in
  29. +4 −1 Source/Core/DolphinQt/Main.cpp
  30. +88 −38 Source/Core/DolphinQt/MainWindow.cpp
  31. +21 −3 Source/Core/DolphinQt/MainWindow.h
  32. +6 −0 Source/Core/DolphinQt/Settings/GeneralPane.cpp
  33. +1 −0 Source/Core/DolphinQt/Settings/GeneralPane.h
  34. +1 −1 Source/Core/DolphinQt/Settings/PathPane.cpp
  35. +1 −1 Source/Core/UICommon/CommandLineParse.cpp
@@ -341,12 +341,12 @@ public static native String GetConfig(String configFile, String Section, String
/**
* Begins emulation.
*/
public static native void Run(String path, boolean firstOpen);
public static native void Run(String[] path, boolean firstOpen);

/**
* Begins emulation from the specified savestate.
*/
public static native void Run(String path, String savestatePath, boolean deleteSavestate);
public static native void Run(String[] path, String savestatePath, boolean deleteSavestate);

public static native void ChangeDisc(String path);

@@ -37,6 +37,7 @@
import org.dolphinemu.dolphinemu.fragments.MenuFragment;
import org.dolphinemu.dolphinemu.fragments.SaveLoadStateFragment;
import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
import org.dolphinemu.dolphinemu.ui.main.MainActivity;
import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
@@ -74,10 +75,10 @@
private boolean activityRecreated;
private String mSelectedTitle;
private int mPlatform;
private String mPath;
private String[] mPaths;
private boolean backPressedOnce = false;

public static final String EXTRA_SELECTED_GAME = "SelectedGame";
public static final String EXTRA_SELECTED_GAMES = "SelectedGames";
public static final String EXTRA_SELECTED_TITLE = "SelectedTitle";
public static final String EXTRA_PLATFORM = "Platform";

@@ -166,11 +167,20 @@
.append(R.id.menu_emulation_reset_overlay, EmulationActivity.MENU_ACTION_RESET_OVERLAY);
}

private static String[] scanForSecondDisc(GameFile gameFile)
{
GameFile secondFile = GameFileCacheService.findSecondDisc(gameFile);
if (secondFile == null)
return new String[]{gameFile.getPath()};
else
return new String[]{gameFile.getPath(), secondFile.getPath()};
}

public static void launch(FragmentActivity activity, GameFile gameFile)
{
Intent launcher = new Intent(activity, EmulationActivity.class);

launcher.putExtra(EXTRA_SELECTED_GAME, gameFile.getPath());
launcher.putExtra(EXTRA_SELECTED_GAMES, scanForSecondDisc(gameFile));
launcher.putExtra(EXTRA_SELECTED_TITLE, gameFile.getTitle());
launcher.putExtra(EXTRA_PLATFORM, gameFile.getPlatform());
Bundle options = new Bundle();
@@ -193,15 +203,15 @@ protected void onCreate(Bundle savedInstanceState)
{
// Get params we were passed
Intent gameToEmulate = getIntent();
mPath = gameToEmulate.getStringExtra(EXTRA_SELECTED_GAME);
mPaths = gameToEmulate.getStringArrayExtra(EXTRA_SELECTED_GAMES);
mSelectedTitle = gameToEmulate.getStringExtra(EXTRA_SELECTED_TITLE);
mPlatform = gameToEmulate.getIntExtra(EXTRA_PLATFORM, 0);
activityRecreated = false;
}
else
{
// Could have recreated the activity(rotate) before creating the fragment. If the fragment
// doesn't exist, treat this as a new start.
// doesn't exist, treat this as a new start.
activityRecreated = mEmulationFragment != null;
restoreState(savedInstanceState);
}
@@ -264,7 +274,7 @@ protected void onCreate(Bundle savedInstanceState)
getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) &&
mEmulationFragment == null)
{
mEmulationFragment = EmulationFragment.newInstance(mPath);
mEmulationFragment = EmulationFragment.newInstance(mPaths);
getSupportFragmentManager().beginTransaction()
.add(R.id.frame_emulation_fragment, mEmulationFragment)
.commit();
@@ -286,15 +296,15 @@ protected void onSaveInstanceState(Bundle outState)
{
mEmulationFragment.saveTemporaryState();
}
outState.putString(EXTRA_SELECTED_GAME, mPath);
outState.putStringArray(EXTRA_SELECTED_GAMES, mPaths);
outState.putString(EXTRA_SELECTED_TITLE, mSelectedTitle);
outState.putInt(EXTRA_PLATFORM, mPlatform);
super.onSaveInstanceState(outState);
}

protected void restoreState(Bundle savedInstanceState)
{
mPath = savedInstanceState.getString(EXTRA_SELECTED_GAME);
mPaths = savedInstanceState.getStringArray(EXTRA_SELECTED_GAMES);
mSelectedTitle = savedInstanceState.getString(EXTRA_SELECTED_TITLE);
mPlatform = savedInstanceState.getInt(EXTRA_PLATFORM);
}
@@ -218,6 +218,7 @@ private void addGeneralSettings(ArrayList<SettingsItem> sl)
Setting overclock = null;
Setting speedLimit = null;
Setting audioStretch = null;
Setting autoDiscChange = null;
Setting analytics = null;
Setting enableSaveState;
Setting lockToLandscape;
@@ -230,6 +231,7 @@ private void addGeneralSettings(ArrayList<SettingsItem> sl)
overclock = coreSection.getSetting(SettingsFile.KEY_OVERCLOCK_PERCENT);
speedLimit = coreSection.getSetting(SettingsFile.KEY_SPEED_LIMIT);
audioStretch = coreSection.getSetting(SettingsFile.KEY_AUDIO_STRETCH);
autoDiscChange = coreSection.getSetting(SettingsFile.KEY_AUTO_DISC_CHANGE);
analytics = analyticsSection.getSetting(SettingsFile.KEY_ANALYTICS_ENABLED);
enableSaveState = coreSection.getSetting(SettingsFile.KEY_ENABLE_SAVE_STATES);
lockToLandscape = coreSection.getSetting(SettingsFile.KEY_LOCK_LANDSCAPE);
@@ -269,6 +271,8 @@ else if (defaultCpuCore == 4) // AArch64
R.string.speed_limit, 0, 200, "%", 100, speedLimit));
sl.add(new CheckBoxSetting(SettingsFile.KEY_AUDIO_STRETCH, Settings.SECTION_INI_CORE,
R.string.audio_stretch, R.string.audio_stretch_description, false, audioStretch));
sl.add(new CheckBoxSetting(SettingsFile.KEY_AUTO_DISC_CHANGE, Settings.SECTION_INI_CORE,
R.string.auto_disc_change, 0, false, autoDiscChange));
sl.add(new CheckBoxSetting(SettingsFile.KEY_ENABLE_SAVE_STATES, Settings.SECTION_INI_CORE,
R.string.enable_save_states, R.string.enable_save_states_description, false,
enableSaveState));
@@ -45,6 +45,7 @@
public static final String KEY_SPEED_LIMIT = "EmulationSpeed";
public static final String KEY_VIDEO_BACKEND = "GFXBackend";
public static final String KEY_AUDIO_STRETCH = "AudioStretch";
public static final String KEY_AUTO_DISC_CHANGE = "AutoDiscChange";
public static final String KEY_GAME_CUBE_LANGUAGE = "SelectedLanguage";
public static final String KEY_OVERRIDE_GAME_CUBE_LANGUAGE = "OverrideGCLang";
public static final String KEY_SLOT_A_DEVICE = "SlotA";
@@ -30,7 +30,7 @@

public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
{
private static final String KEY_GAMEPATH = "gamepath";
private static final String KEY_GAMEPATHS = "gamepaths";

private SharedPreferences mPreferences;

@@ -42,11 +42,10 @@

private EmulationActivity activity;

public static EmulationFragment newInstance(String gamePath)
public static EmulationFragment newInstance(String[] gamePaths)
{

Bundle args = new Bundle();
args.putString(KEY_GAMEPATH, gamePath);
args.putStringArray(KEY_GAMEPATHS, gamePaths);

EmulationFragment fragment = new EmulationFragment();
fragment.setArguments(args);
@@ -82,13 +81,13 @@ public void onCreate(Bundle savedInstanceState)

mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());

String gamePath = getArguments().getString(KEY_GAMEPATH);
String[] gamePaths = getArguments().getStringArray(KEY_GAMEPATHS);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
boolean firstOpen = preferences.getBoolean(StartupHandler.NEW_SESSION, true);
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putBoolean(StartupHandler.NEW_SESSION, false);
sPrefsEditor.apply();
mEmulationState = new EmulationState(gamePath, getTemporaryStateFilePath(), firstOpen);
mEmulationState = new EmulationState(gamePaths, getTemporaryStateFilePath(), firstOpen);
}

/**
@@ -273,7 +272,7 @@ public boolean isConfiguringControls()
STOPPED, RUNNING, PAUSED
}

private final String mGamePath;
private final String[] mGamePaths;
private Thread mEmulationThread;
private State state;
private Surface mSurface;
@@ -282,10 +281,10 @@ public boolean isConfiguringControls()
private boolean firstOpen;
private final String temporaryStatePath;

EmulationState(String gamePath, String temporaryStatePath, boolean firstOpen)
EmulationState(String[] gamePaths, String temporaryStatePath, boolean firstOpen)
{
this.firstOpen = firstOpen;
mGamePath = gamePath;
mGamePaths = gamePaths;
this.temporaryStatePath = temporaryStatePath;
// Starting state is stopped.
state = State.STOPPED;
@@ -423,12 +422,12 @@ private void runWithValidSurface()
if (loadPreviousTemporaryState)
{
Log.debug("[EmulationFragment] Starting emulation thread from previous state.");
NativeLibrary.Run(mGamePath, temporaryStatePath, true);
NativeLibrary.Run(mGamePaths, temporaryStatePath, true);
}
else
{
Log.debug("[EmulationFragment] Starting emulation thread.");
NativeLibrary.Run(mGamePath, firstOpen);
NativeLibrary.Run(mGamePaths, firstOpen);
}
}, "NativeEmulation");
mEmulationThread.start();
@@ -30,6 +30,10 @@ private GameFile(long pointer)

public native String getGameId();

public native int getDiscNumber();

public native int getRevision();

public native int[] getBanner();

public native int getBannerWidth();
@@ -61,6 +61,26 @@ public static GameFile getGameFileByGameId(String gameId)
return null;
}

public static GameFile findSecondDisc(GameFile game)
{
GameFile matchWithoutRevision = null;

GameFile[] allGames = gameFiles.get();
for (GameFile otherGame : allGames)
{
if (game.getGameId().equals(otherGame.getGameId()) &&
game.getDiscNumber() != otherGame.getDiscNumber())
{
if (game.getRevision() == otherGame.getRevision())
return otherGame;
else
matchWithoutRevision = otherGame;
}
}

return matchWithoutRevision;
}

private static void startService(Context context, String action)
{
Intent intent = new Intent(context, GameFileCacheService.class);
@@ -136,6 +136,7 @@
<string name="wiimote_speaker_description">Enable sound output through the speaker on a real Wiimote (DolphinBar required).</string>
<string name="audio_stretch">Audio Stretching</string>
<string name="audio_stretch_description">Stretches audio to reduce stuttering. Increases latency.</string>
<string name="auto_disc_change">Change Discs Automatically</string>
<string name="enable_save_states">Enable Savestates</string>
<string name="enable_save_states_description">WARNING: Savestates may not be compatible with future versions of Dolphin and can make it impossible to create normal saves in some cases. Never use savestates as the only way of saving your progress.</string>
<string name="lock_emulation_landscape">Lock screen to landscape</string>
@@ -5,6 +5,7 @@
#include "jni/AndroidCommon/AndroidCommon.h"

#include <string>
#include <vector>

#include <jni.h>

@@ -24,3 +25,15 @@ jstring ToJString(JNIEnv* env, const std::string& str)
{
return env->NewStringUTF(str.c_str());
}

std::vector<std::string> JStringArrayToVector(JNIEnv* env, jobjectArray array)
{
const jsize size = env->GetArrayLength(array);
std::vector<std::string> result;
result.reserve(size);

for (jsize i = 0; i < size; ++i)
result.push_back(GetJString(env, (jstring)env->GetObjectArrayElement(array, i)));

return result;
}
@@ -10,3 +10,4 @@

std::string GetJString(JNIEnv* env, jstring jstr);
jstring ToJString(JNIEnv* env, const std::string& str);
std::vector<std::string> JStringArrayToVector(JNIEnv* env, jobjectArray array);
@@ -58,6 +58,10 @@ JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getPath(
jobject obj);
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getGameId(JNIEnv* env,
jobject obj);
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getDiscNumber(JNIEnv* env,
jobject obj);
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getRevision(JNIEnv* env,
jobject obj);
JNIEXPORT jintArray JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBanner(JNIEnv* env,
jobject obj);
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBannerWidth(JNIEnv* env,
@@ -119,6 +123,18 @@ JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getGameI
return ToJString(env, GetRef(env, obj)->GetGameID());
}

JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getDiscNumber(JNIEnv* env,
jobject obj)
{
return env, GetRef(env, obj)->GetDiscNumber();
}

JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getRevision(JNIEnv* env,
jobject obj)
{
return env, GetRef(env, obj)->GetRevision();
}

JNIEXPORT jintArray JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBanner(JNIEnv* env,
jobject obj)
{
@@ -571,10 +571,11 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimo
WiimoteReal::Refresh();
}

static void Run(const std::string& path, bool first_open,
static void Run(const std::vector<std::string>& paths, bool first_open,
std::optional<std::string> savestate_path = {}, bool delete_savestate = false)
{
__android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", path.c_str());
ASSERT(!paths.empty());
__android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", paths[0].c_str());

// Install our callbacks
OSD::AddCallback(OSD::CallbackType::Shutdown, ButtonManager::Shutdown);
@@ -595,7 +596,7 @@ static void Run(const std::string& path, bool first_open,

// No use running the loop when booting fails
s_have_wm_user_stop = false;
std::unique_ptr<BootParameters> boot = BootParameters::GenerateFromFile(path, savestate_path);
std::unique_ptr<BootParameters> boot = BootParameters::GenerateFromFile(paths, savestate_path);
boot->delete_savestate = delete_savestate;
WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf);
if (BootManager::BootCore(std::move(boot), wsi))
@@ -630,17 +631,17 @@ static void Run(const std::string& path, bool first_open,
}
}

JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run__Ljava_lang_String_2Z(
JNIEnv* env, jobject obj, jstring jFile, jboolean jfirstOpen)
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2Z(
JNIEnv* env, jobject obj, jobjectArray jPaths, jboolean jfirstOpen)
{
Run(GetJString(env, jFile), jfirstOpen);
Run(JStringArrayToVector(env, jPaths), jfirstOpen);
}

JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z(
JNIEnv* env, jobject obj, jstring jFile, jstring jSavestate, jboolean jDeleteSavestate)
Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2Ljava_lang_String_2Z(
JNIEnv* env, jobject obj, jobjectArray jPaths, jstring jSavestate, jboolean jDeleteSavestate)
{
Run(GetJString(env, jFile), false, GetJString(env, jSavestate), jDeleteSavestate);
Run(JStringArrayToVector(env, jPaths), false, GetJString(env, jSavestate), jDeleteSavestate);
}

JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(JNIEnv* env,

0 comments on commit 1d3e3de

Please sign in to comment.
You can’t perform that action at this time.