Path: blob/master/RSDKv5/RSDK/Core/RetroEngine.cpp
1162 views
#include "RSDK/Core/RetroEngine.hpp"12using namespace RSDK;34#if RETRO_REV0U5#include "Legacy/RetroEngineLegacy.cpp"6#endif78LogicLinkHandle RSDK::linkGameLogic = NULL;910Link::Handle gameLogicHandle = NULL;1112#if RETRO_PLATFORM == RETRO_ANDROID13#include <jni.h>14#include <unistd.h>15#endif1617int32 *RSDK::globalVarsPtr = NULL;18#if RETRO_REV0U19void (*RSDK::globalVarsInitCB)(void *globals) = NULL;20#endif2122RetroEngine RSDK::engine = RetroEngine();2324int32 RSDK::RunRetroEngine(int32 argc, char *argv[])25{26ParseArguments(argc, argv);2728if (engine.consoleEnabled)29InitConsole();30RenderDevice::isRunning = false;3132if (InitStorage()) {33SKU::InitUserCore();34LoadSettingsINI();3536#if !RETRO_USE_ORIGINAL_CODE37// temp fix till i properly figure out what exactly went wrong here38#if RETRO_REV0239SKU::curSKU.platform = SKU::userCore->GetUserPlatform();40#else41if (gameVerInfo.platform == PLATFORM_PC)42gameVerInfo.platform = engine.devMenu ? PLATFORM_DEV : PLATFORM_PC;43#endif44#endif4546#if RETRO_USE_MOD_LOADER47// do it early so we can render funny little loading bar for mods48int32 shader = videoSettings.shaderID;49strcpy(gameVerInfo.gameTitle, "RSDK" ENGINE_V_NAME);50if (RenderDevice::Init()) {51RenderDevice::isRunning = true;52currentScreen = &screens[0];53videoSettings.screenCount = 1;54}55else {56// No render device, throw a "QUIT" msg onto the message loop and call it a day :)57SendQuitMsg();58}59#if RETRO_PLATFORM == RETRO_ANDROID60// wait until we have a window61while (!RenderDevice::window) {62RenderDevice::ProcessEvents();63}64#endif6566#if RETRO_REV0U67engine.version = 0;68InitModAPI(true); // check for versions69engine.version = 5;70#endif71#endif7273#if RETRO_REV0U74DetectEngineVersion();75#endif7677// By Default we use the dummy system so this'll never be false78// its used in cases like steam where it gives the "Steam must be running to play this game" message and closes79#if RETRO_REV0280if (!SKU::userCore->CheckAPIInitialized()) {81#else82if (false) { // it's more hardcoded in rev01, so lets pretend it's here83#endif84// popup a message box saying the API failed to validate or something85// on steam this is the "steam must be running to play this game" message86return 0;87}8889InitEngine();90#if RETRO_USE_MOD_LOADER91// we confirmed the game actually is valid & running, lets start some callbacks92videoSettings.shaderID = shader;93RenderDevice::InitShaders();94RenderDevice::SetWindowTitle();95RenderDevice::lastShaderID = -1;96#else97if (RenderDevice::Init()) {98RenderDevice::isRunning = true;99}100else {101// No render device, throw a "QUIT" msg onto the message loop and call it a day :)102SendQuitMsg();103}104#endif105}106107RenderDevice::InitFPSCap();108109while (RenderDevice::isRunning) {110RenderDevice::ProcessEvents();111112if (!RenderDevice::isRunning)113break;114115if (RenderDevice::CheckFPSCap()) {116RenderDevice::UpdateFPSCap();117118AudioDevice::FrameInit();119120#if RETRO_REV02121SKU::userCore->FrameInit();122123if (SKU::userCore->CheckEnginePause())124continue;125126// Focus Checks127#if !RETRO_USE_ORIGINAL_CODE128if (customSettings.disableFocusPause)129engine.focusState = 0;130else if (SKU::userCore->CheckFocusLost()) {131#else132if (SKU::userCore->CheckFocusLost()) {133#endif134if (!(engine.focusState & 1)) {135engine.focusState = 1;136137#if !RETRO_USE_ORIGINAL_CODE138for (int32 c = 0; c < CHANNEL_COUNT; ++c) {139engine.focusPausedChannel[c] = false;140if (!(channels[c].state & CHANNEL_PAUSED)) {141PauseChannel(c);142engine.focusPausedChannel[c] = true;143}144}145#else146PauseSound();147#endif148}149}150else if (engine.focusState) {151engine.focusState = 0;152153#if !RETRO_USE_ORIGINAL_CODE154for (int32 c = 0; c < CHANNEL_COUNT; ++c) {155if (engine.focusPausedChannel[c])156ResumeChannel(c);157engine.focusPausedChannel[c] = false;158}159#else160ResumeSound();161#endif162}163#endif164165if (!engine.initialized || (engine.focusState & 1)) {166if (videoSettings.windowState != WINDOWSTATE_ACTIVE)167continue;168}169else {170if (!engine.hardPause) {171// common stuff172foreachStackPtr = foreachStackList;173#if !RETRO_USE_ORIGINAL_CODE174debugHitboxCount = 0;175#endif176177#if RETRO_USE_MOD_LOADER178#if RETRO_REV0U179if (((engine.version == 5 && sceneInfo.state != ENGINESTATE_DEVMENU)180|| (engine.version != 5 && RSDK::Legacy::gameMode != RSDK::Legacy::ENGINE_DEVMENU))181&& devMenu.modsChanged) {182engine.version = 0;183#else184if (sceneInfo.state != ENGINESTATE_DEVMENU && devMenu.modsChanged) {185#endif186devMenu.modsChanged = false;187SaveMods();188RefreshModFolders(true);189LoadModSettings();190for (int32 c = 0; c < CHANNEL_COUNT; ++c) StopChannel(c);191#if RETRO_REV02192forceHardReset = true;193#endif194195#if RETRO_REV0U196int32 preVersion = engine.version;197198DetectEngineVersion();199if (!engine.version)200engine.version = preVersion;201202SceneInfo pre = sceneInfo;203int32 preGameMode = RSDK::Legacy::gameMode;204int32 preStageMode = RSDK::Legacy::stageMode;205206// Clear some stuff207sceneInfo.listData = NULL;208sceneInfo.listCategory = NULL;209210globalVarsPtr = NULL;211globalVarsInitCB = NULL;212213dataStorage[DATASET_STG].entryCount = 0;214dataStorage[DATASET_STG].usedStorage = 0;215dataStorage[DATASET_SFX].entryCount = 0;216dataStorage[DATASET_SFX].usedStorage = 0;217218for (int32 o = 0; o < objectClassCount; ++o) {219if (objectClassList[o].staticVars && *objectClassList[o].staticVars)220(*objectClassList[o].staticVars) = NULL;221}222223InitEngine();224225switch (engine.version) {226default:227case 5:228sceneInfo.classCount = pre.classCount;229if (pre.state == ENGINESTATE_LOAD) {230sceneInfo.activeCategory = pre.activeCategory;231sceneInfo.listPos = pre.listPos;232}233break;234case 4:235case 3:236if (preGameMode == RSDK::Legacy::ENGINE_MAINGAME && preStageMode == RSDK::Legacy::STAGEMODE_LOAD) {237sceneInfo.activeCategory = pre.activeCategory;238sceneInfo.listPos = pre.listPos;239}240break;241}242243#else244SceneInfo pre = sceneInfo;245InitEngine();246sceneInfo.classCount = pre.classCount;247if (pre.state == ENGINESTATE_LOAD) {248sceneInfo.activeCategory = pre.activeCategory;249sceneInfo.listPos = pre.listPos;250}251#endif252RenderDevice::SetWindowTitle();253sceneInfo.state = ENGINESTATE_LOAD;254}255#endif256257// update device states and other stuff258ProcessInputDevices();259260if (engine.devMenu)261ProcessDebugCommands();262263#if RETRO_REV0U264switch (engine.version) {265default:266case 5: ProcessEngine(); break;267case 4: Legacy::v4::ProcessEngine(); break;268case 3: Legacy::v3::ProcessEngine(); break;269}270#else271ProcessEngine();272#endif273}274275#if RETRO_PLATFORM == RETRO_ANDROID276HideLoadingIcon(); // best spot to do it277#endif278279if (videoSettings.windowState != WINDOWSTATE_ACTIVE)280continue;281282#if !RETRO_USE_ORIGINAL_CODE283for (int32 t = 0; t < touchInfo.count; ++t) {284if (touchInfo.down[t]) {285int32 tx = (int32)(touchInfo.x[t] * screens->size.x);286int32 ty = (int32)(touchInfo.y[t] * screens->size.y);287288if (tx <= 32 && ty <= 32) {289if (engine.devMenu) {290#if RETRO_REV0U291if (sceneInfo.state != ENGINESTATE_DEVMENU && RSDK::Legacy::gameMode != RSDK::Legacy::ENGINE_DEVMENU)292#else293if (sceneInfo.state != ENGINESTATE_DEVMENU)294#endif295OpenDevMenu();296}297}298}299}300#endif301if (engine.inFocus == 1) {302// Uncomment this code to add the build number to dev menu303// overrides the game subtitle, used in switch dev menu304if (currentScreen && sceneInfo.state == ENGINESTATE_DEVMENU) {305// Switch 1.00 build # is 17051, 1.04 is 18403306// char buffer[0x40];307// sprintf(buffer, "Build #%d", 18403);308// DrawRectangle(currentScreen->center.x - 128, currentScreen->center.y - 48, 256, 8, 0x008000, 0xFF, INK_NONE, true);309// DrawDevString(buffer, currentScreen->center.x, currentScreen->center.y - 48, 1, 0xF0F0F0);310}311312RenderDevice::CopyFrameBuffer();313}314}315316if ((engine.focusState & 1) || engine.inFocus == 1)317RenderDevice::ProcessDimming();318319RenderDevice::FlipScreen();320}321}322323// Shutdown324325ReleaseInputDevices();326AudioDevice::Release();327RenderDevice::Release(false);328SaveSettingsINI(false);329SKU::ReleaseUserCore();330ReleaseStorage();331#if RETRO_USE_MOD_LOADER332UnloadMods();333#endif334335Link::Close(gameLogicHandle);336gameLogicHandle = NULL;337338if (engine.consoleEnabled)339ReleaseConsole();340341return 0;342}343344void RSDK::ProcessEngine()345{346switch (sceneInfo.state) {347default: break;348349case ENGINESTATE_LOAD:350if (!sceneInfo.listData) {351sceneInfo.state = ENGINESTATE_NONE;352}353else {354#if RETRO_USE_MOD_LOADER355if (devMenu.modsChanged)356RefreshModFolders();357#endif358LoadSceneFolder();359LoadSceneAssets();360InitObjects();361362#if RETRO_REV02363#if !RETRO_USE_ORIGINAL_CODE364AddViewableVariable("Show Hitboxes", &showHitboxes, VIEWVAR_BOOL, false, true);365AddViewableVariable("Show Palettes", &engine.showPaletteOverlay, VIEWVAR_BOOL, false, true);366AddViewableVariable("Show Obj Range", &engine.showUpdateRanges, VIEWVAR_UINT8, 0, 2);367AddViewableVariable("Show Obj Info", &engine.showEntityInfo, VIEWVAR_UINT8, 0, 2);368#endif369SKU::userCore->StageLoad();370for (int32 v = 0; v < DRAWGROUP_COUNT; ++v)371AddViewableVariable(drawGroupNames[v], &engine.drawGroupVisible[v], VIEWVAR_BOOL, false, true);372#endif373374// dim after 5 mins375videoSettings.dimLimit = (5 * 60) * videoSettings.refreshRate;376ProcessInput();377ProcessObjects();378#if RETRO_VER_EGS || RETRO_USE_DUMMY_ACHIEVEMENTS379SKU::LoadAchievementAssets();380#endif381}382383break;384385case ENGINESTATE_REGULAR:386ProcessInput();387ProcessSceneTimer();388ProcessObjects();389ProcessParallaxAutoScroll();390391for (int32 i = 1; i < engine.gameSpeed; ++i) {392if (sceneInfo.state != ENGINESTATE_REGULAR)393break;394395ProcessSceneTimer();396ProcessObjects();397ProcessParallaxAutoScroll();398}399400#if RETRO_VER_EGS || RETRO_USE_DUMMY_ACHIEVEMENTS401SKU::ProcessAchievements();402#endif403ProcessObjectDrawLists();404405break;406407case ENGINESTATE_PAUSED:408ProcessInput();409ProcessPausedObjects();410411for (int32 i = 1; i < engine.gameSpeed; ++i) {412if (sceneInfo.state != ENGINESTATE_PAUSED)413break;414415ProcessPausedObjects();416}417418#if RETRO_VER_EGS || RETRO_USE_DUMMY_ACHIEVEMENTS419SKU::ProcessAchievements();420#endif421ProcessObjectDrawLists();422break;423424case ENGINESTATE_FROZEN:425ProcessInput();426ProcessFrozenObjects();427428for (int32 i = 1; i < engine.gameSpeed; ++i) {429if (sceneInfo.state != ENGINESTATE_FROZEN)430break;431432ProcessFrozenObjects();433}434435#if RETRO_VER_EGS || RETRO_USE_DUMMY_ACHIEVEMENTS436SKU::ProcessAchievements();437#endif438ProcessObjectDrawLists();439break;440441case ENGINESTATE_LOAD | ENGINESTATE_STEPOVER:442#if RETRO_USE_MOD_LOADER443if (devMenu.modsChanged)444RefreshModFolders();445#endif446LoadSceneFolder();447LoadSceneAssets();448InitObjects();449450#if RETRO_REV02451#if !RETRO_USE_ORIGINAL_CODE452AddViewableVariable("Show Hitboxes", &showHitboxes, VIEWVAR_BOOL, false, true);453AddViewableVariable("Show Palettes", &engine.showPaletteOverlay, VIEWVAR_BOOL, false, true);454AddViewableVariable("Show Obj Range", &engine.showUpdateRanges, VIEWVAR_UINT8, 0, 2);455AddViewableVariable("Show Obj Info", &engine.showEntityInfo, VIEWVAR_UINT8, 0, 2);456#endif457SKU::userCore->StageLoad();458for (int32 v = 0; v < DRAWGROUP_COUNT; ++v)459AddViewableVariable(drawGroupNames[v], &engine.drawGroupVisible[v], VIEWVAR_BOOL, false, true);460#endif461462ProcessInput();463ProcessObjects();464sceneInfo.state = ENGINESTATE_REGULAR | ENGINESTATE_STEPOVER;465#if RETRO_VER_EGS || RETRO_USE_DUMMY_ACHIEVEMENTS466SKU::LoadAchievementAssets();467#endif468break;469470case ENGINESTATE_REGULAR | ENGINESTATE_STEPOVER:471ProcessInput();472473if (engine.frameStep) {474ProcessSceneTimer();475ProcessObjects();476ProcessParallaxAutoScroll();477#if RETRO_VER_EGS || RETRO_USE_DUMMY_ACHIEVEMENTS478SKU::ProcessAchievements();479#endif480ProcessObjectDrawLists();481engine.frameStep = false;482}483break;484485case ENGINESTATE_PAUSED | ENGINESTATE_STEPOVER:486ProcessInput();487488if (engine.frameStep) {489ProcessPausedObjects();490#if RETRO_VER_EGS || RETRO_USE_DUMMY_ACHIEVEMENTS491SKU::ProcessAchievements();492#endif493ProcessObjectDrawLists();494engine.frameStep = false;495}496break;497498case ENGINESTATE_FROZEN | ENGINESTATE_STEPOVER:499ProcessInput();500501if (engine.frameStep) {502ProcessFrozenObjects();503#if RETRO_VER_EGS || RETRO_USE_DUMMY_ACHIEVEMENTS504SKU::ProcessAchievements();505#endif506ProcessObjectDrawLists();507engine.frameStep = false;508}509break;510511case ENGINESTATE_DEVMENU:512ProcessInput();513currentScreen = &screens[0];514515if (devMenu.state)516devMenu.state();517break;518519case ENGINESTATE_VIDEOPLAYBACK:520ProcessInput();521ProcessVideo();522break;523524case ENGINESTATE_SHOWIMAGE:525ProcessInput();526527if (engine.imageFadeSpeed <= 0.0 || videoSettings.dimMax >= 1.0) {528if (engine.displayTime <= 0.0) {529videoSettings.dimMax += engine.imageFadeSpeed;530if (videoSettings.dimMax <= 0.0) {531videoSettings.shaderID = engine.storedShaderID;532videoSettings.screenCount = 1;533sceneInfo.state = engine.storedState;534videoSettings.dimMax = 1.0;535}536}537else {538engine.displayTime -= (1.0 / 60.0); // deltaTime frame-step;539#if RETRO_USE_MOD_LOADER540RunModCallbacks(MODCB_ONVIDEOSKIPCB, (void *)engine.skipCallback);541#endif542if (engine.skipCallback && engine.skipCallback()) {543engine.displayTime = 0.0;544}545}546}547else {548videoSettings.dimMax += engine.imageFadeSpeed;549if (videoSettings.dimMax >= 1.0) {550engine.imageFadeSpeed = -engine.imageFadeSpeed;551videoSettings.dimMax = 1.0;552}553}554break;555556#if RETRO_REV02557case ENGINESTATE_ERRORMSG: {558ProcessInput();559560if (controller[0].keyStart.down)561sceneInfo.state = engine.storedState;562563currentScreen = &screens[0];564int32 yOff = DevOutput_GetStringYSize(outputString);565DrawRectangle(0, currentScreen->center.y - (yOff >> 1), currentScreen->size.x, yOff, 128, 255, INK_NONE, true);566DrawDevString(outputString, 8, currentScreen->center.y - (yOff >> 1) + 8, 0, 0xF0F0F0);567break;568}569case ENGINESTATE_ERRORMSG_FATAL: {570ProcessInput();571572if (controller[0].keyStart.down)573RenderDevice::isRunning = false;574575currentScreen = &screens[0];576int32 yOff = DevOutput_GetStringYSize(outputString);577DrawRectangle(0, currentScreen->center.y - (yOff >> 1), currentScreen->size.x, yOff, 0xF00000, 255, INK_NONE, true);578DrawDevString(outputString, 8, currentScreen->center.y - (yOff >> 1) + 8, 0, 0xF0F0F0);579break;580}581#endif582}583}584585void RSDK::ParseArguments(int32 argc, char *argv[])586{587memset(currentSceneFolder, 0, sizeof(currentSceneFolder));588memset(currentSceneID, 0, sizeof(currentSceneID));589#if RETRO_REV02590sceneInfo.filter = 0;591#endif592593for (int32 a = 0; a < argc; ++a) {594const char *find = "";595596find = strstr(argv[a], "stage=");597if (find) {598int32 b = 0;599int32 c = 6;600while (find[c] && find[c] != ';') currentSceneFolder[b++] = find[c++];601currentSceneFolder[b] = 0;602}603604find = strstr(argv[a], "scene=");605if (find) {606int32 b = 0;607int32 c = 6;608while (find[c] && find[c] != ';') currentSceneID[b++] = find[c++];609currentSceneID[b] = 0;610}611612#if RETRO_REV02613find = strstr(argv[a], "filter=");614if (find) {615char buf[0x10];616617int32 b = 0;618int32 c = 7;619while (argv[a][c] && find[c] != ';') buf[b++] = find[c++];620buf[b] = 0;621sceneInfo.filter = atoi(buf);622}623#endif624625#if !RETRO_DISABLE_LOG626find = strstr(argv[a], "console=true");627if (find) {628engine.consoleEnabled = true;629engine.devMenu = true;630}631#endif632}633}634635void RSDK::InitEngine()636{637#if RETRO_PLATFORM == RETRO_ANDROID638ShowLoadingIcon(); // if valid639#endif640641#if RETRO_REV0U642switch (engine.version) {643case 5:644#endif645StartGameObjects();646#if RETRO_REV0U647break;648649case 4:650devMenu.state = DevMenu_MainMenu;651SetupFunctionTables();652653Legacy::CalculateTrigAnglesM7();654655engine.gamePlatform = (RETRO_DEVICETYPE == RETRO_STANDARD ? "STANDARD" : "MOBILE");656engine.gameRenderType = "SW_RENDERING";657engine.gameHapticSetting = "NO_F_FEEDBACK";658#if !RETRO_USE_ORIGINAL_CODE659engine.releaseType = (engine.gameReleaseID ? "USE_ORIGINS" : "USE_STANDALONE");660661Legacy::deviceType = RETRO_DEVICETYPE;662if (SKU::curSKU.language <= LANGUAGE_JP)663Legacy::language = SKU::curSKU.language;664else {665switch (SKU::curSKU.language) {666default: Legacy::language = Legacy::LEGACY_LANGUAGE_EN; break;667case LANGUAGE_KO: Legacy::language = Legacy::LEGACY_LANGUAGE_KO; break;668case LANGUAGE_SC: Legacy::language = Legacy::LEGACY_LANGUAGE_ZS; break;669case LANGUAGE_TC: Legacy::language = Legacy::LEGACY_LANGUAGE_ZH; break;670}671}672#endif673674Legacy::v4::LoadGameConfig("Data/Game/GameConfig.bin");675if (!useDataPack)676strcat(gameVerInfo.gameTitle, " (Using Data Folder)");677strcpy(gameVerInfo.version, "Legacy v4 Mode");678679RSDK::GenerateBlendLookupTable();680Legacy::GenerateBlendLookupTable();681Legacy::v4::InitFirstStage();682Legacy::ResetCurrentStageFolder();683Legacy::v4::ClearScriptData();684break;685686case 3:687devMenu.state = DevMenu_MainMenu;688SetupFunctionTables();689690Legacy::CalculateTrigAnglesM7();691692engine.gamePlatform = (RETRO_DEVICETYPE == RETRO_STANDARD ? "Standard" : "Mobile");693engine.gameRenderType = "SW_Rendering";694engine.gameHapticSetting = "No_Haptics";695#if !RETRO_USE_ORIGINAL_CODE696engine.releaseType = (engine.gameReleaseID ? "Use_Origins" : "Use_Standalone");697698Legacy::deviceType = RETRO_DEVICETYPE;699switch (RETRO_PLATFORM) {700default:701case RETRO_WIN: Legacy::gamePlatformID = Legacy::LEGACY_RETRO_WIN; break;702case RETRO_OSX: Legacy::gamePlatformID = Legacy::LEGACY_RETRO_OSX; break;703case RETRO_iOS: Legacy::gamePlatformID = Legacy::LEGACY_RETRO_iOS; break;704case RETRO_XB1: Legacy::gamePlatformID = Legacy::LEGACY_RETRO_XBOX_360; break;705case RETRO_PS4: Legacy::gamePlatformID = Legacy::LEGACY_RETRO_PS3; break;706case RETRO_ANDROID: Legacy::gamePlatformID = Legacy::LEGACY_RETRO_ANDROID; break;707}708709if (SKU::curSKU.language <= LANGUAGE_JP)710Legacy::language = SKU::curSKU.language;711else712Legacy::language = Legacy::LEGACY_LANGUAGE_EN;713#endif714715Legacy::v3::LoadGameConfig("Data/Game/GameConfig.bin");716if (!useDataPack)717strcat(gameVerInfo.gameTitle, " (Using Data Folder)");718strcpy(gameVerInfo.version, "Legacy v3 Mode");719720RSDK::GenerateBlendLookupTable();721Legacy::GenerateBlendLookupTable();722Legacy::v3::InitFirstStage();723Legacy::ResetCurrentStageFolder();724Legacy::v3::ClearScriptData();725break;726}727#endif728engine.initialized = true;729engine.hardPause = false;730#if RETRO_PLATFORM == RETRO_ANDROID731SetLoadingIcon();732#endif733734#if RETRO_USE_MOD_LOADER735RunModCallbacks(MODCB_ONGAMESTARTUP, NULL); // rerun those callbacks736#endif737}738739void RSDK::StartGameObjects()740{741#if RETRO_USE_MOD_LOADER742// ObjectClass is a non-POD struct because of std::function, we can't memset(0) or it would overwrite vtable data743for (int i = 0; i < OBJECT_COUNT; ++i) {744objectClassList[i] = {};745}746#else747memset(&objectClassList, 0, sizeof(objectClassList));748#endif749750sceneInfo.classCount = 0;751sceneInfo.activeCategory = 0;752sceneInfo.listPos = 0;753sceneInfo.state = ENGINESTATE_LOAD;754sceneInfo.inEditor = false;755sceneInfo.debugMode = engine.devMenu;756devMenu.state = DevMenu_MainMenu;757758for (int32 l = 0; l < DRAWGROUP_COUNT; ++l) engine.drawGroupVisible[l] = true;759760SetupFunctionTables();761InitGameLink();762LoadGameConfig();763}764765#if RETRO_USE_MOD_LOADER766void RSDK::LoadGameXML(bool pal)767{768FileInfo info;769SortMods();770for (int32 m = 0; m < modList.size(); ++m) {771if (!modList[m].active)772break;773SetActiveMod(m);774InitFileInfo(&info);775if (LoadFile(&info, "Data/Game/Game.xml", FMODE_RB)) {776tinyxml2::XMLDocument *doc = new tinyxml2::XMLDocument;777778char *xmlData = new char[info.fileSize + 1];779ReadBytes(&info, xmlData, info.fileSize);780xmlData[info.fileSize] = 0;781CloseFile(&info);782783doc->Parse(xmlData);784const tinyxml2::XMLElement *gameElement = doc->FirstChildElement("game"); // gameElement is nullptr if parse failure785786if (gameElement) {787if (pal)788LoadXMLPalettes(gameElement);789else {790LoadXMLWindowText(gameElement);791LoadXMLObjects(gameElement);792LoadXMLSoundFX(gameElement);793LoadXMLStages(gameElement);794}795}796else {797PrintLog(PRINT_NORMAL, "[MOD] Failed to parse Game.xml file for mod %s", modList[m].id.c_str());798}799800delete[] xmlData;801delete doc;802}803}804SetActiveMod(-1);805}806807void RSDK::LoadXMLWindowText(const tinyxml2::XMLElement *gameElement)808{809const tinyxml2::XMLElement *titleElement = gameElement->FirstChildElement("title");810if (titleElement) {811const tinyxml2::XMLAttribute *nameAttr = titleElement->FindAttribute("name");812if (nameAttr)813strcpy(gameVerInfo.gameTitle, nameAttr->Value());814}815}816817void RSDK::LoadXMLPalettes(const tinyxml2::XMLElement *gameElement)818{819const tinyxml2::XMLElement *paletteElement = gameElement->FirstChildElement("palette");820if (paletteElement) {821for (const tinyxml2::XMLElement *clrElement = paletteElement->FirstChildElement("color"); clrElement;822clrElement = clrElement->NextSiblingElement("color")) {823const tinyxml2::XMLAttribute *bankAttr = clrElement->FindAttribute("bank");824int32 bank = 0;825if (bankAttr)826bank = bankAttr->IntValue();827828const tinyxml2::XMLAttribute *indAttr = clrElement->FindAttribute("index");829int32 index = 0;830if (indAttr)831index = indAttr->IntValue();832833const tinyxml2::XMLAttribute *rAttr = clrElement->FindAttribute("r");834int32 r = 0;835if (rAttr)836r = rAttr->IntValue();837838const tinyxml2::XMLAttribute *gAttr = clrElement->FindAttribute("g");839int32 g = 0;840if (gAttr)841g = gAttr->IntValue();842843const tinyxml2::XMLAttribute *bAttr = clrElement->FindAttribute("b");844int32 b = 0;845if (bAttr)846b = bAttr->IntValue();847848SetPaletteEntry(bank, index, (r << 16) | (g << 8) | b);849}850851for (const tinyxml2::XMLElement *clrsElement = paletteElement->FirstChildElement("colors"); clrsElement;852clrsElement = clrsElement->NextSiblingElement("colors")) {853const tinyxml2::XMLAttribute *bankAttr = clrsElement->FindAttribute("bank");854int32 bank = 0;855if (bankAttr)856bank = bankAttr->IntValue();857858const tinyxml2::XMLAttribute *indAttr = clrsElement->FindAttribute("start");859int32 index = 0;860if (indAttr)861index = indAttr->IntValue();862863std::string text = clrsElement->GetText();864// working: AABBFF #FFaaFF (12,32,34) (145 53 234)865std::regex search(R"((?:#?([0-9A-F]{6}))|(?:\((\d+),?\s*(\d+),?\s*(\d+)\)))",866std::regex_constants::icase | std::regex_constants::ECMAScript);867std::smatch match;868while (std::regex_search(text, match, search)) {869int32 color;870if (match[1].matched) {871// we have hex, just set color directly lol872color = std::stoi(match[1].str(), nullptr, 16);873}874else {875// triplet876int32 r = std::stoi(match[2 + 0].str(), nullptr, 10);877int32 g = std::stoi(match[2 + 1].str(), nullptr, 10);878int32 b = std::stoi(match[2 + 2].str(), nullptr, 10);879color = (r << 16) | (g << 8) | b;880}881882SetPaletteEntry(bank, index++, color);883text = match.suffix();884}885}886}887}888889void RSDK::LoadXMLObjects(const tinyxml2::XMLElement *gameElement)890{891const tinyxml2::XMLElement *objectsElement = gameElement->FirstChildElement("objects");892if (objectsElement) {893for (const tinyxml2::XMLElement *objElement = objectsElement->FirstChildElement("object"); objElement;894objElement = objElement->NextSiblingElement("object")) {895const tinyxml2::XMLAttribute *nameAttr = objElement->FindAttribute("name");896const char *objName = "unknownObject";897if (nameAttr)898objName = nameAttr->Value();899900RETRO_HASH_MD5(hash);901GEN_HASH_MD5(objName, hash);902globalObjectIDs[globalObjectCount] = 0;903for (int32 objID = 0; objID < objectClassCount; ++objID) {904if (HASH_MATCH_MD5(hash, objectClassList[objID].hash)) {905globalObjectIDs[globalObjectCount] = objID;906globalObjectCount++;907}908}909}910}911}912913void RSDK::LoadXMLSoundFX(const tinyxml2::XMLElement *gameElement)914{915const tinyxml2::XMLElement *soundsElement = gameElement->FirstChildElement("sounds");916if (soundsElement) {917for (const tinyxml2::XMLElement *sfxElement = soundsElement->FirstChildElement("soundfx"); sfxElement;918sfxElement = sfxElement->NextSiblingElement("soundfx")) {919const tinyxml2::XMLAttribute *valAttr = sfxElement->FindAttribute("path");920const char *sfxPath = "unknownSFX.wav";921if (valAttr)922sfxPath = valAttr->Value();923924const tinyxml2::XMLAttribute *playsAttr = sfxElement->FindAttribute("maxConcurrentPlays");925int32 maxConcurrentPlays = 0;926if (playsAttr)927maxConcurrentPlays = playsAttr->IntValue();928929LoadSfx((char *)sfxPath, maxConcurrentPlays, SCOPE_GLOBAL);930}931}932}933934#if !RETRO_REV0U935std::vector<SceneListEntry> listData;936std::vector<SceneListInfo> listCategory;937#endif938939void RSDK::LoadXMLStages(const tinyxml2::XMLElement *gameElement)940{941942for (const tinyxml2::XMLElement *listElement = gameElement->FirstChildElement("category"); listElement;943listElement = listElement->NextSiblingElement("category")) {944SceneListInfo *list = nullptr;945int32 listID;946947const tinyxml2::XMLAttribute *nameAttr = listElement->FindAttribute("name");948const char *lstName = "unknown list";949if (nameAttr)950lstName = nameAttr->Value();951RETRO_HASH_MD5(hash);952GEN_HASH_MD5(lstName, hash);953954for (int l = 0; l < listCategory.size(); ++l) {955if (HASH_MATCH_MD5(hash, listCategory[l].hash)) {956list = &listCategory[l];957listID = l;958}959}960961if (!list) {962listCategory.emplace_back();963list = &listCategory.back();964sprintf_s(list->name, sizeof(list->name), "%s", lstName);965HASH_COPY_MD5(list->hash, hash);966967list->sceneOffsetStart = listData.size();968list->sceneOffsetEnd = listData.size();969list->sceneCount = 0;970sceneInfo.categoryCount++;971}972973for (const tinyxml2::XMLElement *stgElement = listElement->FirstChildElement("stage"); stgElement;974stgElement = stgElement->NextSiblingElement("stage")) {975const tinyxml2::XMLAttribute *nameAttr = stgElement->FindAttribute("name");976const char *stgName = "unknownStage";977if (nameAttr)978stgName = nameAttr->Value();979980const tinyxml2::XMLAttribute *folderAttr = stgElement->FindAttribute("folder");981const char *stgFolder = "unknownStageFolder";982if (folderAttr)983stgFolder = folderAttr->Value();984985const tinyxml2::XMLAttribute *idAttr = stgElement->FindAttribute("id");986const char *stgID = "unknownStageID";987if (idAttr)988stgID = idAttr->Value();989990#if RETRO_REV02991const tinyxml2::XMLAttribute *filterAttr = stgElement->FindAttribute("filter");992int32 stgFilter = 0;993if (stgFilter)994stgFilter = filterAttr->IntValue();995#endif996listData.emplace(listData.begin() + list->sceneOffsetEnd);997SceneListEntry *scene = &listData[list->sceneOffsetEnd];998999sprintf_s(scene->name, sizeof(scene->name), "%s", stgName);1000GEN_HASH_MD5(scene->name, scene->hash);1001sprintf_s(scene->folder, sizeof(scene->folder), "%s", stgFolder);1002sprintf_s(scene->id, sizeof(scene->id), "%s", stgID);10031004#if RETRO_REV021005scene->filter = stgFilter;1006if (scene->filter == 0x00)1007scene->filter = 0xFF;1008#endif1009list->sceneCount++;1010list->sceneOffsetEnd++;1011for (int32 l = listID + 1; l < listCategory.size(); ++l) listCategory[l].sceneOffsetStart++;1012}1013}1014sceneInfo.listData = listData.data();1015sceneInfo.listCategory = listCategory.data();1016}1017#endif10181019void RSDK::LoadGameConfig()1020{1021FileInfo info;1022InitFileInfo(&info);10231024if (LoadFile(&info, "Data/Game/GameConfig.bin", FMODE_RB)) {1025char buffer[0x100];1026uint32 sig = ReadInt32(&info, false);10271028if (sig != RSDK_SIGNATURE_CFG) {1029CloseFile(&info);1030return;1031}10321033ReadString(&info, gameVerInfo.gameTitle);1034if (!useDataPack)1035strcat(gameVerInfo.gameTitle, " (Data Folder)");1036ReadString(&info, gameVerInfo.gameSubtitle);1037ReadString(&info, gameVerInfo.version);10381039sceneInfo.activeCategory = ReadInt8(&info);1040int32 startScene = ReadInt16(&info);10411042uint8 objCnt = ReadInt8(&info);1043globalObjectCount = TYPE_DEFAULT_COUNT;1044for (int32 i = 0; i < objCnt; ++i) {1045ReadString(&info, textBuffer);10461047RETRO_HASH_MD5(hash);1048GEN_HASH_MD5_BUFFER(textBuffer, hash);10491050if (objectClassCount > 0) {1051globalObjectIDs[globalObjectCount] = 0;1052for (int32 objID = 0; objID < objectClassCount; ++objID) {1053if (HASH_MATCH_MD5(hash, objectClassList[objID].hash)) {1054globalObjectIDs[globalObjectCount] = objID;1055globalObjectCount++;1056}1057}1058}1059}10601061for (int32 i = 0; i < PALETTE_BANK_COUNT; ++i) {1062activeGlobalRows[i] = ReadInt16(&info);1063for (int32 r = 0; r < 0x10; ++r) {1064if ((activeGlobalRows[i] >> r & 1)) {1065for (int32 c = 0; c < 0x10; ++c) {1066uint8 red = ReadInt8(&info);1067uint8 green = ReadInt8(&info);1068uint8 blue = ReadInt8(&info);1069globalPalette[i][(r << 4) + c] = rgb32To16_B[blue] | rgb32To16_G[green] | rgb32To16_R[red];1070}1071}1072else {1073for (int32 c = 0; c < 0x10; ++c) globalPalette[i][(r << 4) + c] = 0;1074}1075}1076}10771078uint8 sfxCnt = ReadInt8(&info);1079for (int32 i = 0; i < sfxCnt; ++i) {1080ReadString(&info, buffer);1081uint8 maxConcurrentPlays = ReadInt8(&info);1082LoadSfx(buffer, maxConcurrentPlays, SCOPE_GLOBAL);1083}10841085uint16 totalSceneCount = ReadInt16(&info);10861087if (!totalSceneCount)1088totalSceneCount = 1;10891090if (strlen(currentSceneFolder) && strlen(currentSceneID)) {1091#if RETRO_USE_MOD_LOADER1092listData.resize(totalSceneCount + 1);1093sceneInfo.listData = listData.data();1094#else1095AllocateStorage((void **)&sceneInfo.listData, sizeof(SceneListEntry) * (totalSceneCount + 1), DATASET_STG, false);1096#endif1097SceneListEntry *scene = &sceneInfo.listData[totalSceneCount];1098strcpy(scene->name, "_RSDK_SCENE");1099strcpy(scene->folder, currentSceneFolder);1100strcpy(scene->id, currentSceneID);1101#if RETRO_REV021102scene->filter = sceneInfo.filter;1103#endif1104GEN_HASH_MD5(scene->name, scene->hash);11051106// Override existing values1107sceneInfo.activeCategory = 0;1108startScene = totalSceneCount;1109currentSceneFolder[0] = 0;1110currentSceneID[0] = 0;1111}1112else {1113#if RETRO_USE_MOD_LOADER1114listData.resize(totalSceneCount);1115sceneInfo.listData = listData.data();1116#else1117AllocateStorage((void **)&sceneInfo.listData, sizeof(SceneListEntry) * totalSceneCount, DATASET_STG, false);1118#endif1119}11201121sceneInfo.categoryCount = ReadInt8(&info);1122sceneInfo.listPos = 0;11231124int32 categoryCount = sceneInfo.categoryCount;11251126if (!categoryCount)1127categoryCount = 1;11281129#if RETRO_USE_MOD_LOADER1130listCategory.resize(categoryCount);1131sceneInfo.listCategory = listCategory.data();1132#else1133AllocateStorage((void **)&sceneInfo.listCategory, sizeof(SceneListInfo) * categoryCount, DATASET_STG, false);1134#endif1135sceneInfo.listPos = 0;11361137int32 sceneID = 0;1138for (int32 i = 0; i < sceneInfo.categoryCount; ++i) {1139SceneListInfo *category = &sceneInfo.listCategory[i];1140ReadString(&info, category->name);1141GEN_HASH_MD5(category->name, category->hash);11421143category->sceneOffsetStart = sceneID;1144category->sceneCount = ReadInt8(&info);1145for (int32 s = 0; s < category->sceneCount; ++s) {1146SceneListEntry *scene = &sceneInfo.listData[sceneID + s];1147ReadString(&info, scene->name);1148GEN_HASH_MD5(scene->name, scene->hash);11491150ReadString(&info, scene->folder);1151ReadString(&info, scene->id);11521153#if RETRO_REV021154scene->filter = ReadInt8(&info);1155if (scene->filter == 0x00)1156scene->filter = 0xFF;1157#endif1158}1159category->sceneOffsetEnd = category->sceneCount ? category->sceneOffsetStart + category->sceneCount - 1 : 0;1160sceneID += category->sceneCount;1161}11621163uint8 varCount = ReadInt8(&info);1164for (int32 i = 0; i < varCount; ++i) {1165#if RETRO_REV0U1166// v5U Ditches this in favour of the InitVarsCB method1167ReadInt32(&info, false);1168int32 count = ReadInt32(&info, false);1169for (int32 v = 0; v < count; ++v) ReadInt32(&info, false);1170#else1171if (!globalVarsPtr)1172break;1173// standard v5 loads variables directly into the struct1174int32 offset = ReadInt32(&info, false);1175int32 count = ReadInt32(&info, false);1176for (int32 v = 0; v < count; ++v) {1177globalVarsPtr[offset + v] = ReadInt32(&info, false);1178}1179#endif1180}11811182CloseFile(&info);1183#if RETRO_USE_MOD_LOADER1184LoadGameXML();1185#endif11861187#if RETRO_REV0U1188if (globalVarsInitCB)1189globalVarsInitCB(globalVarsPtr);1190#endif11911192sceneInfo.listPos = sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart + startScene;1193}1194}11951196void RSDK::InitGameLink()1197{1198#if RETRO_USE_MOD_LOADER1199objectClassCount = 0;1200memset(globalObjectIDs, 0, sizeof(globalObjectIDs));1201memset(objectEntityList, 0, sizeof(objectEntityList));1202editableVarCount = 0;1203foreachStackPtr = foreachStackList;1204currentMod = NULL;1205#endif12061207#if RETRO_REV0U1208RegisterObject((Object **)&DefaultObject, ":DefaultObject:", sizeof(EntityBase), sizeof(ObjectDefaultObject), DefaultObject_Update,1209DefaultObject_LateUpdate, DefaultObject_StaticUpdate, DefaultObject_Draw, DefaultObject_Create, DefaultObject_StageLoad,1210DefaultObject_EditorLoad, DefaultObject_EditorDraw, DefaultObject_Serialize, (void (*)(Object *))DefaultObject_StaticLoad);12111212RegisterObject((Object **)&DevOutput, ":DevOutput:", sizeof(EntityDevOutput), sizeof(ObjectDevOutput), DevOutput_Update, DevOutput_LateUpdate,1213DevOutput_StaticUpdate, DevOutput_Draw, DevOutput_Create, DevOutput_StageLoad, DevOutput_EditorLoad, DevOutput_EditorDraw,1214DevOutput_Serialize, (void (*)(Object *))DevOutput_StaticLoad);1215#elif RETRO_REV021216RegisterObject((Object **)&DefaultObject, ":DefaultObject:", sizeof(EntityBase), sizeof(ObjectDefaultObject), DefaultObject_Update,1217DefaultObject_LateUpdate, DefaultObject_StaticUpdate, DefaultObject_Draw, DefaultObject_Create, DefaultObject_StageLoad,1218DefaultObject_EditorLoad, DefaultObject_EditorDraw, DefaultObject_Serialize);12191220RegisterObject((Object **)&DevOutput, ":DevOutput:", sizeof(EntityDevOutput), sizeof(ObjectDevOutput), DevOutput_Update, DevOutput_LateUpdate,1221DevOutput_StaticUpdate, DevOutput_Draw, DevOutput_Create, DevOutput_StageLoad, DevOutput_EditorLoad, DevOutput_EditorDraw,1222DevOutput_Serialize);1223#else // RETRO_REV011224RegisterObject((Object **)&DefaultObject, ":DefaultObject:", sizeof(EntityDefaultObject), sizeof(ObjectDefaultObject), DefaultObject_Update,1225DefaultObject_LateUpdate, DefaultObject_StaticUpdate, DefaultObject_Draw, DefaultObject_Create, DefaultObject_StageLoad,1226DefaultObject_EditorLoad, DefaultObject_EditorDraw, DefaultObject_Serialize);1227#endif12281229globalObjectIDs[0] = TYPE_DEFAULTOBJECT;1230#if RETRO_REV021231globalObjectIDs[1] = TYPE_DEVOUTPUT;1232#endif12331234globalObjectCount = TYPE_DEFAULT_COUNT;12351236#if RETRO_REV021237EngineInfo info;12381239info.functionTable = RSDKFunctionTable;1240info.APITable = APIFunctionTable;12411242info.currentSKU = &SKU::curSKU;1243info.gameInfo = &gameVerInfo;1244info.sceneInfo = &sceneInfo;12451246info.controller = controller;1247info.stickL = stickL;1248info.stickR = stickR;1249info.triggerL = triggerL;1250info.triggerR = triggerR;1251info.touchMouse = &touchInfo;12521253info.unknown = &SKU::unknownInfo;12541255info.screenInfo = screens;12561257#if RETRO_USE_MOD_LOADER1258info.modTable = modFunctionTable;1259#endif1260#else1261EngineInfo info;12621263info.functionTable = RSDKFunctionTable;12641265info.gameInfo = &gameVerInfo;1266info.sceneInfo = &sceneInfo;12671268info.controllerInfo = controller;1269info.stickInfo = stickL;1270info.touchInfo = &touchInfo;12711272info.screenInfo = screens;12731274#if RETRO_USE_MOD_LOADER1275info.modTable = modFunctionTable;1276#endif1277#endif12781279bool32 linked = false;12801281#if RETRO_USE_MOD_LOADER1282if (!modSettings.disableGameLogic) {1283#endif1284if (engine.useExternalCode) {1285char buffer[0x100];1286#if RETRO_PLATFORM == RETRO_WIN1287strcpy_s(buffer, 0x100, gameLogicName);1288#else1289sprintf(buffer, "%s%s", SKU::userFileDir, gameLogicName);1290#endif1291if (!gameLogicHandle)1292gameLogicHandle = Link::Open(buffer);12931294if (gameLogicHandle) {1295bool32 canLink = true;1296#if !RETRO_USE_ORIGINAL_CODE1297int32 *RSDKRevision = (int32 *)Link::GetSymbol(gameLogicHandle, "RSDKRevision");1298if (RSDKRevision) {1299canLink = *RSDKRevision == RETRO_REVISION;1300if (!canLink)1301PrintLog(PRINT_NORMAL, "ERROR: Game Logic RSDK Revision doesn't match Engine RSDK Revision!");1302}1303#endif13041305LogicLinkHandle linkGameLogic = (LogicLinkHandle)Link::GetSymbol(gameLogicHandle, "LinkGameLogicDLL");1306if (canLink && linkGameLogic) {1307#if RETRO_REV021308linkGameLogic(&info);1309#else1310linkGameLogic(info);1311#endif1312linked = true;1313}1314else if (canLink && !linkGameLogic) {1315PrintLog(PRINT_ERROR, "ERROR: Failed to find 'LinkGameLogicDLL' -> %s", Link::GetError());1316}1317}1318else {1319PrintLog(PRINT_ERROR, "ERROR: Failed to open game logic file -> %s", Link::GetError());1320}13211322if (!linked)1323PrintLog(PRINT_NORMAL, "ERROR: Failed to link game logic!");1324}1325else {1326#if RETRO_REV021327linkGameLogic(&info);1328#else1329linkGameLogic(info);1330#endif1331}1332#if RETRO_USE_MOD_LOADER1333}13341335for (int32 m = 0; m < modList.size(); ++m) {1336currentMod = &modList[m];1337if (!currentMod->active)1338break;1339for (modLinkSTD linkModLogic : modList[m].linkModLogic) {1340if (!linkModLogic(&info, modList[m].id.c_str())) {1341modList[m].active = false;1342PrintLog(PRINT_ERROR, "[MOD] Failed to link logic for mod %s!", modList[m].id.c_str());1343}1344}1345}13461347currentMod = NULL;1348#endif1349}13501351void RSDK::ProcessDebugCommands()1352{1353#if !RETRO_USE_ORIGINAL_CODE1354if (!customSettings.enableControllerDebugging)1355return;1356#endif13571358if (controller[CONT_P1].keySelect.press) {1359#if RETRO_REV0U1360if (sceneInfo.state == ENGINESTATE_DEVMENU || RSDK::Legacy::gameMode == RSDK::Legacy::ENGINE_DEVMENU)1361#else1362if (sceneInfo.state == ENGINESTATE_DEVMENU)1363#endif1364CloseDevMenu();1365else1366OpenDevMenu();1367}13681369#if RETRO_REV0U1370int32 state = engine.version == 5 ? sceneInfo.state : Legacy::stageMode;1371const int32 stepOver = engine.version == 5 ? (int32)ENGINESTATE_STEPOVER : (int32)Legacy::STAGEMODE_STEPOVER;1372#else1373uint8 state = sceneInfo.state;1374const uint8 stepOver = ENGINESTATE_STEPOVER;1375#endif13761377bool32 framePaused = (state & stepOver) == stepOver;13781379#if RETRO_REV021380if (triggerL[CONT_P1].keyBumper.down) {1381if (triggerL[CONT_P1].keyTrigger.down || triggerL[CONT_P1].triggerDelta >= 0.3) {1382if (!framePaused)1383state ^= stepOver;1384}1385else {1386if (framePaused)1387state ^= stepOver;1388}13891390framePaused = (state & stepOver) == stepOver;13911392if (framePaused) {1393if (triggerR[CONT_P1].keyBumper.press)1394engine.frameStep = true;1395}1396else {1397engine.gameSpeed = (triggerR[CONT_P1].keyTrigger.down || triggerR[CONT_P1].triggerDelta >= 0.3) ? 8 : 1;1398}1399}1400else {1401if (engine.gameSpeed == 8)1402engine.gameSpeed = 1;14031404if (framePaused)1405state ^= stepOver;1406}14071408#if RETRO_REV0U1409if (engine.version != 5)1410Legacy::stageMode = state;1411else1412#endif1413sceneInfo.state = state;1414#else1415if (controller[CONT_P1].keyBumperL.down) {1416if (controller[CONT_P1].keyTriggerL.down || stickL[CONT_P1].triggerDeltaL >= 0.3) {1417if (!framePaused)1418sceneInfo.state ^= ENGINESTATE_STEPOVER;1419}1420else {1421if (framePaused)1422sceneInfo.state ^= ENGINESTATE_STEPOVER;1423}14241425framePaused = (sceneInfo.state >> 2) & 1;1426if (framePaused) {1427if (controller[CONT_P1].keyBumperR.press)1428engine.frameStep = true;1429}1430else {1431engine.gameSpeed = (controller[CONT_P1].keyTriggerR.down || stickL[CONT_P1].triggerDeltaR >= 0.3) ? 8 : 1;1432}1433}1434else {1435if (engine.gameSpeed == 8)1436engine.gameSpeed = 1;14371438if (framePaused)1439sceneInfo.state ^= ENGINESTATE_STEPOVER;1440}1441#endif1442}14431444#ifdef __SWITCH__1445#include <switch.h>1446#include <stdlib.h>1447#include <stdio.h>1448#include <string.h>1449#include <sys/socket.h>1450#include <sys/errno.h>1451#include <arpa/inet.h>1452#include <unistd.h>1453#include "RetroEngine.hpp"14541455static int32 s_nxlinkSock = -1;14561457static void initNxLink()1458{1459if (R_FAILED(socketInitializeDefault()))1460return;14611462s_nxlinkSock = nxlinkStdio();1463if (s_nxlinkSock >= 0)1464printf("printf output now goes to nxlink server\n");1465else1466socketExit();1467}1468#endif14691470void RSDK::InitCoreAPI()1471{1472#if RETRO_RENDERDEVICE_DIRECTX9 || RETRO_RENDERDEVICE_DIRECTX111473MSG Msg;1474PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE);1475InitCommonControls();1476#endif14771478#ifdef __SWITCH__1479Result res;1480if (R_FAILED(res = dynInitialize()))1481diagAbortWithResult(res);1482#endif14831484#if RETRO_RENDERDEVICE_SDL2 || RETRO_AUDIODEVICE_SDL2 || RETRO_INPUTDEVICE_SDL21485SDL_Init(0);1486#endif1487}1488void RSDK::ReleaseCoreAPI()1489{1490#if RETRO_RENDERDEVICE_SDL2 || RETRO_AUDIODEVICE_SDL2 || RETRO_INPUTDEVICE_SDL21491SDL_Quit();1492#endif14931494#ifdef __SWITCH__1495dynExit();1496#endif1497}14981499void RSDK::InitConsole()1500{1501#if RETRO_PLATFORM == RETRO_WIN1502AllocConsole();1503AttachConsole(GetCurrentProcessId());15041505freopen("CON", "w", stdout);1506#endif15071508#if RETRO_PLATFORM == RETRO_SWITCH1509consoleInit(NULL);1510#endif1511}1512void RSDK::ReleaseConsole()1513{1514#if RETRO_PLATFORM == RETRO_WIN1515FreeConsole();1516#endif1517}15181519void RSDK::SendQuitMsg()1520{1521#if RETRO_RENDERDEVICE_DIRECTX9 || RETRO_RENDERDEVICE_DIRECTX111522PostQuitMessage(0);1523#endif1524}152515261527