mirror of
https://github.com/mupen64plus/mupen64plus-ui-console.git
synced 2025-04-02 10:52:34 -04:00
594 lines
21 KiB
C
594 lines
21 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Mupen64plus-ui-console - main.c *
|
|
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
|
* Copyright (C) 2007-2009 Richard42 *
|
|
* Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 *
|
|
* Copyright (C) 2002 Hacktarux *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/* This is the main application entry point for the console-only front-end
|
|
* for Mupen64Plus v2.0.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
// The mac version of SDL requires inclusion of SDL_main in the executable
|
|
#ifdef __APPLE__
|
|
#include <SDL/SDL_main.h>
|
|
#endif
|
|
|
|
#include "cheat.h"
|
|
#include "main.h"
|
|
#include "plugin.h"
|
|
#include "version.h"
|
|
#include "core_interface.h"
|
|
#include "compare_core.h"
|
|
#include "osal_preproc.h"
|
|
|
|
/** global variables **/
|
|
int g_Verbose = 0;
|
|
|
|
/** static (local) variables **/
|
|
static m64p_handle l_ConfigCore = NULL;
|
|
static m64p_handle l_ConfigVideo = NULL;
|
|
static m64p_handle l_ConfigUI = NULL;
|
|
|
|
static const char *l_CoreLibPath = NULL;
|
|
static const char *l_ConfigDirPath = NULL;
|
|
static const char *l_ROMFilepath = NULL; // filepath of ROM to load & run at startup
|
|
|
|
#if defined(SHAREDIR)
|
|
static const char *l_DataDirPath = SHAREDIR;
|
|
#else
|
|
static const char *l_DataDirPath = NULL;
|
|
#endif
|
|
|
|
static int *l_TestShotList = NULL; // list of screenshots to take for regression test support
|
|
static int l_TestShotIdx = 0; // index of next screenshot frame in list
|
|
static int l_SaveOptions = 0; // save command-line options in configuration file
|
|
static int l_CoreCompareMode = 0; // 0 = disable, 1 = send, 2 = receive
|
|
|
|
static eCheatMode l_CheatMode = CHEAT_DISABLE;
|
|
static int *l_CheatNumList = NULL;
|
|
static int l_CheatListLength = 0;
|
|
|
|
/*********************************************************************************************************
|
|
* Callback functions from the core
|
|
*/
|
|
|
|
void DebugCallback(void *Context, int level, const char *message)
|
|
{
|
|
if (level <= 1)
|
|
printf("%s Error: %s\n", (const char *) Context, message);
|
|
else if (level == 2)
|
|
printf("%s Warning: %s\n", (const char *) Context, message);
|
|
else if (level == 3 || (level == 5 && g_Verbose))
|
|
printf("%s: %s\n", (const char *) Context, message);
|
|
else if (level == 4)
|
|
printf("%s Status: %s\n", (const char *) Context, message);
|
|
/* ignore the verbose info for now */
|
|
}
|
|
|
|
static void FrameCallback(unsigned int FrameIndex)
|
|
{
|
|
// take a screenshot if we need to
|
|
if (l_TestShotList != NULL)
|
|
{
|
|
int nextshot = l_TestShotList[l_TestShotIdx];
|
|
if (nextshot == FrameIndex)
|
|
{
|
|
(*CoreDoCommand)(M64CMD_TAKE_NEXT_SCREENSHOT, 0, NULL); /* tell the core take a screenshot */
|
|
// advance list index to next screenshot frame number. If it's 0, then quit
|
|
l_TestShotIdx++;
|
|
}
|
|
else if (nextshot == 0)
|
|
{
|
|
(*CoreDoCommand)(M64CMD_STOP, 0, NULL); /* tell the core to shut down ASAP */
|
|
free(l_TestShotList);
|
|
l_TestShotList = NULL;
|
|
}
|
|
}
|
|
}
|
|
/*********************************************************************************************************
|
|
* Configuration handling
|
|
*/
|
|
|
|
static m64p_error OpenConfigurationHandles(void)
|
|
{
|
|
m64p_error rval;
|
|
|
|
/* Open Configuration sections for core library and console User Interface */
|
|
rval = (*ConfigOpenSection)("Core", &l_ConfigCore);
|
|
if (rval != M64ERR_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Error: failed to open 'Core' configuration section\n");
|
|
return rval;
|
|
}
|
|
|
|
rval = (*ConfigOpenSection)("Video-General", &l_ConfigVideo);
|
|
if (rval != M64ERR_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Error: failed to open 'Video-General' configuration section\n");
|
|
return rval;
|
|
}
|
|
|
|
rval = (*ConfigOpenSection)("UI-Console", &l_ConfigUI);
|
|
if (rval != M64ERR_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Error: failed to open 'UI-Console' configuration section\n");
|
|
return rval;
|
|
}
|
|
|
|
/* Set default values for my Config parameters */
|
|
(*ConfigSetDefaultString)(l_ConfigUI, "PluginDir", OSAL_CURRENT_DIR, "Directory in which to search for plugins");
|
|
(*ConfigSetDefaultString)(l_ConfigUI, "VideoPlugin", "m64p_video_rice" OSAL_DLL_EXTENSION, "Filename of video plugin");
|
|
(*ConfigSetDefaultString)(l_ConfigUI, "AudioPlugin", "m64p_audio_jttl" OSAL_DLL_EXTENSION, "Filename of audio plugin");
|
|
(*ConfigSetDefaultString)(l_ConfigUI, "InputPlugin", "m64p_input_blight" OSAL_DLL_EXTENSION, "Filename of input plugin");
|
|
(*ConfigSetDefaultString)(l_ConfigUI, "RspPlugin", "m64p_rsp_hle" OSAL_DLL_EXTENSION, "Filename of RSP plugin");
|
|
|
|
return M64ERR_SUCCESS;
|
|
}
|
|
|
|
static m64p_error SaveConfigurationOptions(void)
|
|
{
|
|
/* if shared data directory was given on the command line, write it into the config file */
|
|
if (l_DataDirPath != NULL)
|
|
(*ConfigSetParameter)(l_ConfigCore, "SharedDataPath", M64TYPE_STRING, l_DataDirPath);
|
|
|
|
/* if any plugin filepaths were given on the command line, write them into the config file */
|
|
if (g_PluginDir != NULL)
|
|
(*ConfigSetParameter)(l_ConfigUI, "PluginDir", M64TYPE_STRING, g_PluginDir);
|
|
if (g_GfxPlugin != NULL)
|
|
(*ConfigSetParameter)(l_ConfigUI, "VideoPlugin", M64TYPE_STRING, g_GfxPlugin);
|
|
if (g_AudioPlugin != NULL)
|
|
(*ConfigSetParameter)(l_ConfigUI, "AudioPlugin", M64TYPE_STRING, g_AudioPlugin);
|
|
if (g_InputPlugin != NULL)
|
|
(*ConfigSetParameter)(l_ConfigUI, "InputPlugin", M64TYPE_STRING, g_InputPlugin);
|
|
if (g_RspPlugin != NULL)
|
|
(*ConfigSetParameter)(l_ConfigUI, "RspPlugin", M64TYPE_STRING, g_RspPlugin);
|
|
|
|
return (*ConfigSaveFile)();
|
|
}
|
|
|
|
/*********************************************************************************************************
|
|
* Command-line parsing
|
|
*/
|
|
|
|
static void printUsage(const char *progname)
|
|
{
|
|
printf("Usage: %s [parameters] [romfile]\n"
|
|
"\n"
|
|
"Parameters:\n"
|
|
" --noosd : disable onscreen display\n"
|
|
" --osd : enable onscreen display\n"
|
|
" --fullscreen : use fullscreen display mode\n"
|
|
" --windowed : use windowed display mode\n"
|
|
" --resolution (res) : display resolution (640x480, 800x600, 1024x768, etc)\n"
|
|
" --cheats (cheat-spec) : enable or list cheat codes for the given rom file\n"
|
|
" --corelib (filepath) : use core library (filepath) (can be only filename or full path)\n"
|
|
" --configdir (dir) : force configation directory to (dir); should contain mupen64plus.conf\n"
|
|
" --datadir (dir) : search for shared data files (.ini files, languages, etc) in (dir)\n"
|
|
" --plugindir (dir) : search for plugins in (dir)\n"
|
|
" --sshotdir (dir) : set screenshot directory to (dir)\n"
|
|
" --gfx (plugin-spec) : use gfx plugin given by (plugin-spec)\n"
|
|
" --audio (plugin-spec) : use audio plugin given by (plugin-spec)\n"
|
|
" --input (plugin-spec) : use input plugin given by (plugin-spec)\n"
|
|
" --rsp (plugin-spec) : use rsp plugin given by (plugin-spec)\n"
|
|
" --emumode (mode) : set emu mode to: 0=Pure Interpreter 1=Interpreter 2=DynaRec\n"
|
|
" --testshots (list) : take screenshots at frames given in comma-separated (list), then quit\n"
|
|
" --core-compare-send : use the Core Comparison debugging feature, in data sending mode\n"
|
|
" --core-compare-recv : use the Core Comparison debugging feature, in data receiving mode\n"
|
|
" --saveoptions : save the given command-line options in configuration file for future\n"
|
|
" --verbose : print lots of information\n"
|
|
" --help : see this help message\n\n"
|
|
"(plugin-spec):\n"
|
|
" (pluginname) : filename (without path) of plugin to find in plugin directory\n"
|
|
" (pluginpath) : full path and filename of plugin\n"
|
|
" 'dummy' : use dummy plugin\n\n"
|
|
"(cheat-spec):\n"
|
|
" 'list' : show all of the available cheat codes\n"
|
|
" 'all' : enable all of the available cheat codes\n"
|
|
" (codelist) : a comma-separated list of cheat code numbers to enable\n"
|
|
"\n", progname);
|
|
|
|
return;
|
|
}
|
|
|
|
static int *ParseNumberList(const char *InputString, int *ValuesFound)
|
|
{
|
|
const char *str;
|
|
int *OutputList;
|
|
|
|
/* count the number of integers in the list */
|
|
int values = 1;
|
|
str = InputString;
|
|
while ((str = strchr(str, ',')) != NULL)
|
|
{
|
|
str++;
|
|
values++;
|
|
}
|
|
|
|
/* create a list and populate it with the frame counter values at which to take screenshots */
|
|
if ((OutputList = (int *) malloc(sizeof(int) * (values + 1))) != NULL)
|
|
{
|
|
int idx = 0;
|
|
str = InputString;
|
|
while (str != NULL)
|
|
{
|
|
OutputList[idx++] = atoi(str);
|
|
str = strchr(str, ',');
|
|
if (str != NULL) str++;
|
|
}
|
|
OutputList[idx] = 0;
|
|
}
|
|
|
|
if (ValuesFound != NULL)
|
|
*ValuesFound = values;
|
|
return OutputList;
|
|
}
|
|
|
|
static int ParseCommandLineInitial(int argc, const char **argv)
|
|
{
|
|
int i;
|
|
|
|
/* look through commandline options */
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
int ArgsLeft = argc - i - 1;
|
|
|
|
if (strcmp(argv[i], "--corelib") == 0 && ArgsLeft >= 1)
|
|
{
|
|
l_CoreLibPath = argv[i+1];
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--configdir") == 0 && ArgsLeft >= 1)
|
|
{
|
|
l_ConfigDirPath = argv[i+1];
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--datadir") == 0 && ArgsLeft >= 1)
|
|
{
|
|
l_DataDirPath = argv[i+1];
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
|
|
{
|
|
printUsage(argv[0]);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static m64p_error ParseCommandLineFinal(int argc, const char **argv)
|
|
{
|
|
int i;
|
|
|
|
/* parse commandline options */
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
int ArgsLeft = argc - i - 1;
|
|
if (strcmp(argv[i], "--noosd") == 0)
|
|
{
|
|
int Osd = 0;
|
|
(*ConfigSetParameter)(l_ConfigCore, "OnScreenDisplay", M64TYPE_BOOL, &Osd);
|
|
}
|
|
else if (strcmp(argv[i], "--osd") == 0)
|
|
{
|
|
int Osd = 1;
|
|
(*ConfigSetParameter)(l_ConfigCore, "OnScreenDisplay", M64TYPE_BOOL, &Osd);
|
|
}
|
|
else if (strcmp(argv[i], "--fullscreen") == 0)
|
|
{
|
|
int Fullscreen = 1;
|
|
(*ConfigSetParameter)(l_ConfigVideo, "Fullscreen", M64TYPE_BOOL, &Fullscreen);
|
|
}
|
|
else if (strcmp(argv[i], "--windowed") == 0)
|
|
{
|
|
int Fullscreen = 0;
|
|
(*ConfigSetParameter)(l_ConfigVideo, "Fullscreen", M64TYPE_BOOL, &Fullscreen);
|
|
}
|
|
else if ((strcmp(argv[i], "--corelib") == 0 || strcmp(argv[i], "--configdir") == 0 ||
|
|
strcmp(argv[i], "--datadir") == 0) && ArgsLeft >= 1)
|
|
{ /* these are handled in ParseCommandLineInitial */
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--resolution") == 0 && ArgsLeft >= 1)
|
|
{
|
|
const char *res = argv[i+1];
|
|
int xres, yres;
|
|
i++;
|
|
if (sscanf(res, "%ix%i", &xres, &yres) != 2)
|
|
fprintf(stderr, "Warning: couldn't parse resolution '%s'\n", res);
|
|
else
|
|
{
|
|
(*ConfigSetParameter)(l_ConfigVideo, "ScreenWidth", M64TYPE_INT, &xres);
|
|
(*ConfigSetParameter)(l_ConfigVideo, "ScreenHeight", M64TYPE_INT, &yres);
|
|
}
|
|
}
|
|
else if (strcmp(argv[i], "--cheats") == 0 && ArgsLeft >= 1)
|
|
{
|
|
if (strcmp(argv[i+1], "all") == 0)
|
|
l_CheatMode = CHEAT_ALL;
|
|
else if (strcmp(argv[i+1], "list") == 0)
|
|
l_CheatMode = CHEAT_SHOW_LIST;
|
|
else
|
|
{
|
|
l_CheatMode = CHEAT_LIST;
|
|
l_CheatNumList = ParseNumberList(argv[i+1], &l_CheatListLength);
|
|
}
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--plugindir") == 0 && ArgsLeft >= 1)
|
|
{
|
|
g_PluginDir = argv[i+1];
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--sshotdir") == 0 && ArgsLeft >= 1)
|
|
{
|
|
(*ConfigSetParameter)(l_ConfigCore, "ScreenshotPath", M64TYPE_STRING, argv[i+1]);
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--gfx") == 0 && ArgsLeft >= 1)
|
|
{
|
|
g_GfxPlugin = argv[i+1];
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--audio") == 0 && ArgsLeft >= 1)
|
|
{
|
|
g_AudioPlugin = argv[i+1];
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--input") == 0 && ArgsLeft >= 1)
|
|
{
|
|
g_InputPlugin = argv[i+1];
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--rsp") == 0 && ArgsLeft >= 1)
|
|
{
|
|
g_RspPlugin = argv[i+1];
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--emumode") == 0 && ArgsLeft >= 1)
|
|
{
|
|
int emumode = atoi(argv[i+1]);
|
|
(*ConfigSetParameter)(l_ConfigCore, "R4300Emulator", M64TYPE_INT, &emumode);
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--testshots") == 0 && ArgsLeft >= 1)
|
|
{
|
|
l_TestShotList = ParseNumberList(argv[i+1], NULL);
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i], "--core-compare-send") == 0)
|
|
{
|
|
l_CoreCompareMode = 1;
|
|
}
|
|
else if (strcmp(argv[i], "--core-compare-recv") == 0)
|
|
{
|
|
l_CoreCompareMode = 2;
|
|
}
|
|
else if (strcmp(argv[i], "--saveoptions") == 0)
|
|
{
|
|
l_SaveOptions = 1;
|
|
}
|
|
else if (ArgsLeft == 0)
|
|
{
|
|
/* this is the last arg, it should be a ROM filename */
|
|
l_ROMFilepath = argv[i];
|
|
return M64ERR_SUCCESS;
|
|
}
|
|
else if (strcmp(argv[i], "--verbose") == 0)
|
|
{
|
|
g_Verbose = 1;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Warning: unrecognized command-line parameter '%s'\n", argv[i]);
|
|
}
|
|
/* continue argv loop */
|
|
}
|
|
|
|
/* missing ROM filepath */
|
|
fprintf(stderr, "Error: no ROM filepath given\n");
|
|
exit(2);
|
|
return M64ERR_INTERNAL;
|
|
}
|
|
|
|
/*********************************************************************************************************
|
|
* main function
|
|
*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int i;
|
|
|
|
printf(" __ __ __ _ _ ____ _ \n");
|
|
printf("| \\/ |_ _ _ __ ___ _ __ / /_ | || | | _ \\| |_ _ ___ \n");
|
|
printf("| |\\/| | | | | '_ \\ / _ \\ '_ \\| '_ \\| || |_| |_) | | | | / __| \n");
|
|
printf("| | | | |_| | |_) | __/ | | | (_) |__ _| __/| | |_| \\__ \\ \n");
|
|
printf("|_| |_|\\__,_| .__/ \\___|_| |_|\\___/ |_| |_| |_|\\__,_|___/ \n");
|
|
printf(" |_| http://code.google.com/p/mupen64plus/ \n");
|
|
printf("%s Version %i.%i.%i\n\n", CONSOLE_UI_NAME, VERSION_PRINTF_SPLIT(CONSOLE_UI_VERSION));
|
|
|
|
/* bootstrap some special parameters from the command line */
|
|
if (ParseCommandLineInitial(argc, (const char **) argv) != 0)
|
|
return 1;
|
|
|
|
/* load the Mupen64Plus core library */
|
|
if (AttachCoreLib(l_CoreLibPath) != M64ERR_SUCCESS)
|
|
return 2;
|
|
|
|
/* start the Mupen64Plus core library, load the configuration file */
|
|
m64p_error rval = (*CoreStartup)(CONSOLE_API_VERSION, l_ConfigDirPath, l_DataDirPath, "Core", DebugCallback, NULL, NULL);
|
|
if (rval != M64ERR_SUCCESS)
|
|
{
|
|
printf("UI-console: error starting Mupen64Plus core library.\n");
|
|
DetachCoreLib();
|
|
return 3;
|
|
}
|
|
|
|
/* Open configuration sections */
|
|
rval = OpenConfigurationHandles();
|
|
if (rval != M64ERR_SUCCESS)
|
|
{
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
return 4;
|
|
}
|
|
|
|
/* parse command-line options */
|
|
rval = ParseCommandLineFinal(argc, (const char **) argv);
|
|
if (rval != M64ERR_SUCCESS)
|
|
{
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
return 5;
|
|
}
|
|
|
|
/* Handle the core comparison feature */
|
|
if (l_CoreCompareMode != 0 && !(g_CoreCapabilities & M64CAPS_CORE_COMPARE))
|
|
{
|
|
printf("UI-console: can't use --core-compare feature with this Mupen64Plus core library.\n");
|
|
DetachCoreLib();
|
|
return 3;
|
|
}
|
|
compare_core_init(l_CoreCompareMode);
|
|
|
|
/* save the given command-line options in configuration file if requested */
|
|
if (l_SaveOptions)
|
|
SaveConfigurationOptions();
|
|
|
|
/* load ROM image */
|
|
FILE *fPtr = fopen(l_ROMFilepath, "rb");
|
|
if (fPtr == NULL)
|
|
{
|
|
fprintf(stderr, "Error: couldn't open ROM file '%s' for reading.\n", l_ROMFilepath);
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
return 6;
|
|
}
|
|
|
|
/* get the length of the ROM, allocate memory buffer, load it from disk */
|
|
long romlength = 0;
|
|
fseek(fPtr, 0L, SEEK_END);
|
|
romlength = ftell(fPtr);
|
|
fseek(fPtr, 0L, SEEK_SET);
|
|
unsigned char *ROM_buffer = (unsigned char *) malloc(romlength);
|
|
if (ROM_buffer == NULL)
|
|
{
|
|
fprintf(stderr, "Error: couldn't allocate %li-byte buffer for ROM image file '%s'.\n", romlength, l_ROMFilepath);
|
|
fclose(fPtr);
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
return 7;
|
|
}
|
|
else if (fread(ROM_buffer, 1, romlength, fPtr) != romlength)
|
|
{
|
|
fprintf(stderr, "Error: couldn't read %li bytes from ROM image file '%s'.\n", romlength, l_ROMFilepath);
|
|
free(ROM_buffer);
|
|
fclose(fPtr);
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
return 8;
|
|
}
|
|
fclose(fPtr);
|
|
|
|
/* Try to load the ROM image into the core */
|
|
if ((*CoreDoCommand)(M64CMD_ROM_OPEN, (int) romlength, ROM_buffer) != M64ERR_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Error: core failed to open ROM image file '%s'.\n", l_ROMFilepath);
|
|
free(ROM_buffer);
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
return 9;
|
|
}
|
|
free(ROM_buffer); /* the core copies the ROM image, so we can release this buffer immediately */
|
|
|
|
/* handle the cheat codes */
|
|
CheatStart(l_CheatMode, l_CheatNumList, l_CheatListLength);
|
|
if (l_CheatMode == CHEAT_SHOW_LIST)
|
|
{
|
|
(*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
return 10;
|
|
}
|
|
|
|
/* search for and load plugins */
|
|
rval = PluginSearchLoad(l_ConfigUI);
|
|
if (rval != M64ERR_SUCCESS)
|
|
{
|
|
(*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
return 11;
|
|
}
|
|
|
|
/* attach plugins to core */
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if ((*CoreAttachPlugin)(g_PluginMap[i].type, g_PluginMap[i].handle) != M64ERR_SUCCESS)
|
|
{
|
|
fprintf(stderr, "UI-Console: error from core while attaching %s plugin.\n", g_PluginMap[i].name);
|
|
(*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
return 12;
|
|
}
|
|
}
|
|
|
|
/* set up Frame Callback if --testshots is enabled */
|
|
if (l_TestShotList != NULL)
|
|
{
|
|
if ((*CoreDoCommand)(M64CMD_SET_FRAME_CALLBACK, 0, FrameCallback) != M64ERR_SUCCESS)
|
|
{
|
|
fprintf(stderr, "UI-Console: warning: couldn't set frame callback, so --testshots won't work.\n");
|
|
}
|
|
}
|
|
|
|
/* run the game */
|
|
(*CoreDoCommand)(M64CMD_EXECUTE, 0, NULL);
|
|
|
|
/* detach plugins from core and unload them */
|
|
for (i = 0; i < 4; i++)
|
|
(*CoreDetachPlugin)(g_PluginMap[i].type);
|
|
PluginUnload();
|
|
|
|
/* close the ROM image */
|
|
(*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
|
|
|
|
/* save the configuration file again if --saveoptions was specified, to keep any updated parameters from the core/plugins */
|
|
if (l_SaveOptions)
|
|
SaveConfigurationOptions();
|
|
|
|
/* Shut down and release the Core library */
|
|
(*CoreShutdown)();
|
|
DetachCoreLib();
|
|
|
|
/* free allocated memory */
|
|
if (l_TestShotList != NULL)
|
|
free(l_TestShotList);
|
|
if (l_CheatNumList != NULL)
|
|
free(l_CheatNumList);
|
|
|
|
return 0;
|
|
}
|
|
|