metaforce/Runtime/MP1/MP1.cpp

738 lines
24 KiB
C++
Raw Normal View History

#include "Runtime/MP1/MP1.hpp"
#include <array>
#include "Runtime/CDependencyGroup.hpp"
#include "Runtime/CGameHintInfo.hpp"
#include "Runtime/CWorldSaveGameInfo.hpp"
#include "Runtime/CScannableObjectInfo.hpp"
#include "Runtime/CStateManager.hpp"
#include "Runtime/CStopwatch.hpp"
#include "Runtime/CTextureCache.hpp"
#include "Runtime/Audio/CAudioGroupSet.hpp"
#include "Runtime/Audio/CMidiManager.hpp"
#include "Runtime/Audio/CSfxManager.hpp"
#include "Runtime/Audio/CStreamAudioManager.hpp"
#include "Runtime/AutoMapper/CMapArea.hpp"
#include "Runtime/AutoMapper/CMapUniverse.hpp"
#include "Runtime/AutoMapper/CMapWorld.hpp"
#include "Runtime/Character/CAllFormatsAnimSource.hpp"
#include "Runtime/Character/CAnimCharacterSet.hpp"
#include "Runtime/Character/CAnimPOIData.hpp"
#include "Runtime/Character/CCharLayoutInfo.hpp"
#include "Runtime/Character/CSkinRules.hpp"
#include "Runtime/Collision/CCollidableOBBTreeGroup.hpp"
#include "Runtime/Collision/CCollisionResponseData.hpp"
2022-03-07 15:53:42 -08:00
#include "Runtime/Graphics/CFont.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/Graphics/CTexture.hpp"
#include "Runtime/GuiSys/CGuiFrame.hpp"
#include "Runtime/GuiSys/CRasterFont.hpp"
#include "Runtime/GuiSys/CStringTable.hpp"
#include "Runtime/MP1/CGBASupport.hpp"
#include "Runtime/Particle/CDecalDataFactory.hpp"
#include "Runtime/Particle/CParticleDataFactory.hpp"
#include "Runtime/Particle/CParticleElectricDataFactory.hpp"
#include "Runtime/Particle/CParticleSwooshDataFactory.hpp"
#include "Runtime/Particle/CProjectileWeaponDataFactory.hpp"
#include "Runtime/Particle/CWeaponDescription.hpp"
2020-10-02 23:28:05 -07:00
#include "Runtime/World/CPatterned.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "Runtime/World/CStateMachine.hpp"
#include "Runtime/World/CScriptMazeNode.hpp"
#include "Runtime/MP1/CCredits.hpp"
#include <magic_enum.hpp>
2022-01-31 16:06:54 -08:00
#ifdef ENABLE_DISCORD
#include <discord_rpc.h>
2022-01-31 16:06:54 -08:00
#endif
#if _WIN32
inline void* memmem(const void* haystack, size_t hlen, const void* needle, size_t nlen) {
int needle_first;
const uint8_t* p = static_cast<const uint8_t*>(haystack);
size_t plen = hlen;
if (!nlen)
return NULL;
needle_first = *(unsigned char*)needle;
while (plen >= nlen && (p = static_cast<const uint8_t*>(memchr(p, needle_first, plen - nlen + 1)))) {
if (!memcmp(p, needle, nlen))
return (void*)p;
p++;
plen = hlen - (p - static_cast<const uint8_t*>(haystack));
}
return NULL;
}
#endif
2021-04-10 01:42:06 -07:00
namespace metaforce::MP1 {
static logvisor::Module Log{"MP1"};
namespace {
struct AudioGroupInfo {
const char* name;
u32 id;
};
constexpr std::array<AudioGroupInfo, 5> StaticAudioGroups{{
{"Misc_AGSC", GRPMisc},
{"MiscSamus_AGSC", GRPMiscSamus},
{"UI_AGSC", GRPUI},
{"Weapons_AGSC", GRPWeapons},
{"ZZZ_AGSC", GRPZZZ},
}};
} // Anonymous namespace
2023-10-22 09:21:20 -07:00
CGameArchitectureSupport::CGameArchitectureSupport(CMain& parent)
2018-12-07 21:30:43 -08:00
: m_parent(parent)
2023-10-22 09:21:20 -07:00
, x0_audioSys(0, 0, 0, 0, 0)
, x30_inputGenerator(/*osCtx, */ g_tweakPlayer->GetLeftLogicalThreshold(), g_tweakPlayer->GetRightLogicalThreshold())
2018-12-07 21:30:43 -08:00
, x44_guiSys(*g_ResFactory, *g_SimplePool, CGuiSys::EUsageMode::Zero) {
2020-04-15 04:27:06 -07:00
auto* m = static_cast<CMain*>(g_Main);
2016-09-13 22:54:09 -07:00
2018-12-07 21:30:43 -08:00
g_InputGenerator = &x30_inputGenerator;
g_Controller = x30_inputGenerator.GetController();
2016-09-13 22:54:09 -07:00
2018-12-07 21:30:43 -08:00
CAudioSys::SysSetVolume(0x7f);
CAudioSys::SetDefaultVolumeScale(0x75);
CAudioSys::SetVolumeScale(CAudioSys::GetDefaultVolumeScale());
CStreamAudioManager::Initialize();
CStreamAudioManager::SetMusicVolume(0x7f);
m->ResetGameState();
2017-01-19 19:53:32 -08:00
2019-04-16 01:00:46 -07:00
if (!g_tweakGame->GetSplashScreensDisabled()) {
2018-12-07 21:30:43 -08:00
std::shared_ptr<CIOWin> splash = std::make_shared<CSplashScreen>(CSplashScreen::ESplashScreen::Nintendo);
x58_ioWinManager.AddIOWin(splash, 1000, 10000);
}
2017-01-19 19:53:32 -08:00
2018-12-07 21:30:43 -08:00
std::shared_ptr<CIOWin> mf = std::make_shared<CMainFlow>();
x58_ioWinManager.AddIOWin(mf, 0, 0);
2017-01-19 19:53:32 -08:00
2018-12-07 21:30:43 -08:00
std::shared_ptr<CIOWin> console = std::make_shared<CConsoleOutputWindow>(8, 5.f, 0.75f);
x58_ioWinManager.AddIOWin(console, 100, 0);
2017-01-19 19:53:32 -08:00
2018-12-07 21:30:43 -08:00
std::shared_ptr<CIOWin> audState = std::make_shared<CAudioStateWin>();
x58_ioWinManager.AddIOWin(audState, 100, -1);
2017-01-19 19:53:32 -08:00
2018-12-07 21:30:43 -08:00
std::shared_ptr<CIOWin> errWin = std::make_shared<CErrorOutputWindow>(false);
x58_ioWinManager.AddIOWin(errWin, 10000, 100000);
2017-01-19 19:53:32 -08:00
2018-12-07 21:30:43 -08:00
g_GuiSys = &x44_guiSys;
g_GameState->GameOptions().EnsureSettings();
2017-01-19 19:53:32 -08:00
}
void CGameArchitectureSupport::UpdateTicks(float dt) {
2018-12-07 21:30:43 -08:00
x4_archQueue.Push(MakeMsg::CreateFrameBegin(EArchMsgTarget::Game, x78_gameFrameCount));
x4_archQueue.Push(MakeMsg::CreateTimerTick(EArchMsgTarget::Game, dt));
2016-09-13 22:54:09 -07:00
}
void CGameArchitectureSupport::Update(float dt) {
2018-12-07 21:30:43 -08:00
g_GameState->GetWorldTransitionManager()->TouchModels();
x30_inputGenerator.Update(dt, x4_archQueue);
2018-12-07 21:30:43 -08:00
x4_archQueue.Push(MakeMsg::CreateFrameEnd(EArchMsgTarget::Game, x78_gameFrameCount));
x58_ioWinManager.PumpMessages(x4_archQueue);
}
2018-12-07 21:30:43 -08:00
bool CGameArchitectureSupport::LoadAudio() {
2020-04-15 04:27:06 -07:00
if (x88_audioLoadStatus == EAudioLoadStatus::Loaded) {
2018-12-07 21:30:43 -08:00
return true;
2020-04-15 04:27:06 -07:00
}
2016-09-13 22:54:09 -07:00
2018-12-07 21:30:43 -08:00
for (int i = 0; i < 5; ++i) {
TToken<CAudioGroupSet>& tok = x8c_pendingAudioGroups[i];
if (tok.IsLocked()) {
if (tok.IsLoaded()) {
CAudioGroupSet* set = tok.GetObj();
if (!CAudioSys::SysIsGroupSetLoaded(set->GetName())) {
CAudioSys::SysLoadGroupSet(tok, set->GetName(), tok.GetObjectTag()->id);
CAudioSys::SysAddGroupIntoAmuse(set->GetName());
}
} else {
return false;
}
} else {
/* Lock next pending group */
tok.Lock();
return false;
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
}
CSfxManager::LoadTranslationTable(g_SimplePool, g_ResFactory->GetResourceIdByName("sound_lookup"));
x8c_pendingAudioGroups = std::vector<TToken<CAudioGroupSet>>();
x88_audioLoadStatus = EAudioLoadStatus::Loaded;
2017-10-25 22:37:46 -07:00
2018-12-07 21:30:43 -08:00
return true;
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
void CGameArchitectureSupport::PreloadAudio() {
if (x88_audioLoadStatus != EAudioLoadStatus::Uninitialized) {
2018-12-07 21:30:43 -08:00
return;
}
2018-12-07 21:30:43 -08:00
x8c_pendingAudioGroups.clear();
x8c_pendingAudioGroups.reserve(5);
for (size_t i = 0; i < StaticAudioGroups.size(); ++i) {
2018-12-07 21:30:43 -08:00
const AudioGroupInfo& info = StaticAudioGroups[i];
CToken grp = g_SimplePool->GetObj(info.name);
// Lock first group in sequence
if (i == 0) {
2018-12-07 21:30:43 -08:00
grp.Lock();
}
x8c_pendingAudioGroups.emplace_back(std::move(grp));
2018-12-07 21:30:43 -08:00
}
x88_audioLoadStatus = EAudioLoadStatus::Loading;
}
void CGameArchitectureSupport::UnloadAudio() {
for (const AudioGroupInfo& info : StaticAudioGroups) {
2018-12-07 21:30:43 -08:00
const SObjectTag* tag = g_ResFactory->GetResourceIdByName(info.name);
auto name = CAudioSys::SysGetGroupSetName(tag->id);
CAudioSys::SysRemoveGroupFromAmuse(name);
CAudioSys::SysUnloadAudioGroupSet(name);
}
x8c_pendingAudioGroups = std::vector<TToken<CAudioGroupSet>>();
x88_audioLoadStatus = EAudioLoadStatus::Uninitialized;
}
void CGameArchitectureSupport::Draw() {
x58_ioWinManager.Draw();
if (m_parent.x161_24_gameFrameDrawn) {
++x78_gameFrameCount;
m_parent.x161_24_gameFrameDrawn = false;
}
}
CGameArchitectureSupport::~CGameArchitectureSupport() {
x58_ioWinManager.RemoveAllIOWins();
UnloadAudio();
CSfxManager::Shutdown();
CStreamAudioManager::Shutdown();
}
2022-01-31 16:06:54 -08:00
CMain::CMain(IFactory* resFactory, CSimplePool* resStore)
: xe4_gameplayResult(EGameplayResult::Playing)
2020-05-07 20:20:23 -07:00
, x128_globalObjects(std::make_unique<CGameGlobalObjects>(resFactory, resStore)) {
2018-12-07 21:30:43 -08:00
g_Main = this;
}
CMain::~CMain() { g_Main = nullptr; }
2018-12-07 21:30:43 -08:00
void CMain::RegisterResourceTweaks() {}
void CGameGlobalObjects::AddPaksAndFactories() {
CGraphics::SetViewPointMatrix(zeus::CTransform());
CGraphics::SetModelMatrix(zeus::CTransform());
2018-12-07 21:30:43 -08:00
if (CResLoader* loader = g_ResFactory->GetResLoader()) {
loader->AddPakFileAsync("Tweaks", false, false);
loader->AddPakFileAsync("NoARAM", false, false);
loader->AddPakFileAsync("AudioGrp", false, false);
loader->AddPakFileAsync("MiscData", false, false);
loader->AddPakFileAsync("SamusGun", true, false);
loader->AddPakFileAsync("TestAnim", true, false);
loader->AddPakFileAsync("SamGunFx", true, false);
loader->AddPakFileAsync("MidiData", false, false);
loader->AddPakFileAsync("GGuiSys", false, false);
2017-10-27 03:10:32 -07:00
loader->WaitForPakFileLoadingComplete();
2018-12-07 21:30:43 -08:00
}
if (CFactoryMgr* fmgr = g_ResFactory->GetFactoryMgr()) {
fmgr->AddFactory(FOURCC('TXTR'), FFactoryFunc(FTextureFactory));
2018-12-07 21:30:43 -08:00
fmgr->AddFactory(FOURCC('PART'), FFactoryFunc(FParticleFactory));
fmgr->AddFactory(FOURCC('FRME'), FFactoryFunc(RGuiFrameFactoryInGame));
fmgr->AddFactory(FOURCC('FONT'), FFactoryFunc(FRasterFontFactory));
fmgr->AddFactory(FOURCC('CMDL'), FMemFactoryFunc(FModelFactory));
2018-12-07 21:30:43 -08:00
fmgr->AddFactory(FOURCC('CINF'), FFactoryFunc(FCharLayoutInfo));
fmgr->AddFactory(FOURCC('CSKR'), FFactoryFunc(FSkinRulesFactory));
fmgr->AddFactory(FOURCC('ANCS'), FFactoryFunc(FAnimCharacterSet));
fmgr->AddFactory(FOURCC('ANIM'), FFactoryFunc(AnimSourceFactory));
fmgr->AddFactory(FOURCC('EVNT'), FFactoryFunc(AnimPOIDataFactory));
fmgr->AddFactory(FOURCC('DCLN'), FFactoryFunc(FCollidableOBBTreeGroupFactory));
fmgr->AddFactory(FOURCC('DGRP'), FFactoryFunc(FDependencyGroupFactory));
fmgr->AddFactory(FOURCC('AGSC'), FMemFactoryFunc(FAudioGroupSetDataFactory));
fmgr->AddFactory(FOURCC('CSNG'), FFactoryFunc(FMidiDataFactory));
fmgr->AddFactory(FOURCC('ATBL'), FFactoryFunc(FAudioTranslationTableFactory));
fmgr->AddFactory(FOURCC('STRG'), FFactoryFunc(FStringTableFactory));
fmgr->AddFactory(FOURCC('HINT'), FFactoryFunc(FHintFactory));
fmgr->AddFactory(FOURCC('SAVW'), FFactoryFunc(FWorldSaveGameInfoFactory));
2018-12-07 21:30:43 -08:00
fmgr->AddFactory(FOURCC('MAPW'), FFactoryFunc(FMapWorldFactory));
fmgr->AddFactory(FOURCC('SCAN'), FFactoryFunc(FScannableObjectInfoFactory));
fmgr->AddFactory(FOURCC('CRSC'), FFactoryFunc(FCollisionResponseDataFactory));
fmgr->AddFactory(FOURCC('SWHC'), FFactoryFunc(FParticleSwooshDataFactory));
fmgr->AddFactory(FOURCC('ELSC'), FFactoryFunc(FParticleElectricDataFactory));
fmgr->AddFactory(FOURCC('WPSC'), FFactoryFunc(FProjectileWeaponDataFactory));
fmgr->AddFactory(FOURCC('DPSC'), FFactoryFunc(FDecalDataFactory));
fmgr->AddFactory(FOURCC('MAPA'), FFactoryFunc(FMapAreaFactory));
fmgr->AddFactory(FOURCC('MAPU'), FFactoryFunc(FMapUniverseFactory));
fmgr->AddFactory(FOURCC('AFSM'), FFactoryFunc(FAiFiniteStateMachineFactory));
fmgr->AddFactory(FOURCC('PATH'), FMemFactoryFunc(FPathFindAreaFactory));
fmgr->AddFactory(FOURCC('TMET'), FFactoryFunc(FTextureCacheFactory));
2018-12-07 21:30:43 -08:00
}
}
CGameGlobalObjects::~CGameGlobalObjects() {
g_ResFactory = nullptr;
g_SimplePool = nullptr;
g_CharFactoryBuilder = nullptr;
g_AiFuncMap = nullptr;
g_GameState = nullptr;
g_TweakManager = nullptr;
}
void CGameGlobalObjects::PostInitialize() {
2020-04-15 04:27:06 -07:00
AddPaksAndFactories();
LoadTextureCache();
LoadStringTable();
m_renderer.reset(AllocateRenderer(*xcc_simplePool, *x4_resFactory));
CEnvFxManager::Initialize();
CScriptMazeNode::LoadMazeSeeds();
}
2018-12-07 21:30:43 -08:00
void CMain::AddWorldPaks() {
CResLoader* loader = g_ResFactory->GetResLoader();
2020-04-15 04:27:06 -07:00
if (loader == nullptr) {
2018-12-07 21:30:43 -08:00
return;
2020-04-15 04:27:06 -07:00
}
2018-12-07 21:30:43 -08:00
auto pakPrefix = g_tweakGame->GetWorldPrefix();
for (int i = 0; i < 10; ++i) {
2018-12-07 21:30:43 -08:00
std::string path(pakPrefix);
2020-04-15 04:27:06 -07:00
if (i != 0) {
path += '0' + char(i);
}
2018-12-07 21:30:43 -08:00
2022-01-31 16:06:54 -08:00
if (CDvdFile::FileExists(path + ".pak")) {
2018-12-07 21:30:43 -08:00
loader->AddPakFileAsync(path, false, true);
}
2018-12-07 21:30:43 -08:00
}
loader->WaitForPakFileLoadingComplete();
}
2019-11-21 07:37:08 -08:00
void CMain::AddOverridePaks() {
CResLoader* loader = g_ResFactory->GetResLoader();
2020-04-15 04:27:06 -07:00
if (loader == nullptr) {
return;
2020-04-15 04:27:06 -07:00
}
/* Inversely load each pak starting at 999, to ensure proper priority order
* the higher the number the higer the priority, e.g: Override0 has less priority than Override1 etc.
*/
2022-01-31 16:06:54 -08:00
for (size_t i = 9; i > 0; --i) {
2020-04-11 15:51:39 -07:00
const std::string path = fmt::format(FMT_STRING("Override{}"), i);
2022-01-31 16:06:54 -08:00
if (CDvdFile::FileExists(path + ".pak")) {
loader->AddPakFileAsync(path, false, false, true);
}
2019-11-21 07:37:08 -08:00
}
2022-01-31 16:06:54 -08:00
/* Make sure all Override paks are ready before attempting to load URDE.pak */
loader->WaitForPakFileLoadingComplete();
2020-09-17 17:04:06 -07:00
/* Load Trilogy PAKs */
2022-01-31 16:06:54 -08:00
if (CDvdFile::FileExists("RS5.pak")) {
2020-09-17 17:04:06 -07:00
loader->AddPakFile("RS5", false, false, true);
}
2022-01-31 16:06:54 -08:00
if (CDvdFile::FileExists("Strings.pak")) {
2020-09-17 17:04:06 -07:00
loader->AddPakFile("Strings", false, false, true);
}
2022-01-31 16:06:54 -08:00
/* Attempt to load URDE.pak
* NOTE(phil): Should we fatal here if it's not found?
*/
2022-01-31 16:06:54 -08:00
if (CDvdFile::FileExists("URDE.pak")) {
loader->AddPakFile("URDE", false, false, true);
2020-09-17 16:50:36 -07:00
}
2019-11-21 07:37:08 -08:00
}
2018-12-07 21:30:43 -08:00
void CMain::ResetGameState() {
CPersistentOptions sysOpts = g_GameState->SystemOptions();
CGameOptions gameOpts = g_GameState->GameOptions();
2020-05-07 20:20:23 -07:00
x128_globalObjects->ResetGameState();
2018-12-07 21:30:43 -08:00
g_GameState->ImportPersistentOptions(sysOpts);
g_GameState->SetGameOptions(gameOpts);
g_GameState->GetPlayerState()->SetIsFusionEnabled(g_GameState->SystemOptions().GetPlayerFusionSuitActive());
}
void CMain::InitializeSubsystems() {
CBasics::Initialize();
CElementGen::Initialize();
CAnimData::InitializeCache();
CDecalManager::Initialize();
CGBASupport::Initialize();
2020-10-02 23:28:05 -07:00
CPatterned::Initialize();
// Metaforce additions
CMoviePlayer::Initialize();
2018-12-07 21:30:43 -08:00
}
void CMain::MemoryCardInitializePump() {
2020-04-15 04:27:06 -07:00
if (g_MemoryCardSys != nullptr) {
return;
}
2020-05-07 20:20:23 -07:00
std::unique_ptr<CMemoryCardSys>& memSys = x128_globalObjects->x0_memoryCardSys;
if (!memSys) {
memSys = std::make_unique<CMemoryCardSys>();
}
if (memSys->InitializePump()) {
g_MemoryCardSys = memSys.get();
g_GameState->InitializeMemoryStates();
2018-12-07 21:30:43 -08:00
}
}
2019-08-03 17:02:53 -07:00
void CMain::FillInAssetIDs() {
if (const SObjectTag* tag = g_ResFactory->GetResourceIdByName(g_tweakGame->GetDefaultRoom())) {
g_GameState->SetCurrentWorldId(tag->id);
}
}
2017-01-19 19:53:32 -08:00
2018-12-07 21:30:43 -08:00
bool CMain::LoadAudio() {
2020-04-15 04:27:06 -07:00
if (x164_archSupport) {
2018-12-07 21:30:43 -08:00
return x164_archSupport->LoadAudio();
2020-04-15 04:27:06 -07:00
}
2018-12-07 21:30:43 -08:00
return true;
2015-08-26 17:23:46 -07:00
}
2018-12-07 21:30:43 -08:00
void CMain::EnsureWorldPaksReady() {}
2017-04-14 22:32:25 -07:00
2019-10-05 07:07:13 -07:00
void CMain::EnsureWorldPakReady(CAssetId mlvl) { /* TODO: Schedule resource list load for World Pak containing mlvl */
}
2017-04-14 22:32:25 -07:00
void CMain::StreamNewGameState(CInputStream& r, u32 idx) {
2018-12-07 21:30:43 -08:00
bool fusionBackup = g_GameState->SystemOptions().GetPlayerFusionSuitActive();
2020-05-07 20:20:23 -07:00
x128_globalObjects->x134_gameState = std::make_unique<CGameState>(r, idx);
g_GameState = x128_globalObjects->x134_gameState.get();
2018-12-07 21:30:43 -08:00
g_GameState->SystemOptions().SetPlayerFusionSuitActive(fusionBackup);
g_GameState->GetPlayerState()->SetIsFusionEnabled(fusionBackup);
g_GameState->HintOptions().SetNextHintTime();
2016-12-29 22:37:01 -08:00
}
2018-12-07 21:30:43 -08:00
void CMain::RefreshGameState() {
CPersistentOptions sysOpts = g_GameState->SystemOptions();
u64 cardSerial = g_GameState->GetCardSerial();
std::vector<u8> saveData = g_GameState->BackupBuf();
CGameOptions gameOpts = g_GameState->GameOptions();
CMemoryInStream r(saveData.data(), saveData.size(), CMemoryInStream::EOwnerShip::NotOwned);
2020-05-07 20:20:23 -07:00
x128_globalObjects->StreamInGameState(r, g_GameState->GetFileIdx());
2018-12-07 21:30:43 -08:00
g_GameState->SetPersistentOptions(sysOpts);
g_GameState->SetGameOptions(gameOpts);
g_GameState->GameOptions().EnsureSettings();
g_GameState->SetCardSerial(cardSerial);
g_GameState->GetPlayerState()->SetIsFusionEnabled(g_GameState->SystemOptions().GetPlayerFusionSuitActive());
}
static logvisor::Module DiscordLog("Discord");
2020-04-15 06:42:44 -07:00
static logvisor::Module MainLog("MP1::CMain");
static const char* DISCORD_APPLICATION_ID = "402571593815031819";
static int64_t DiscordStartTime;
static CAssetId DiscordWorldSTRG;
static TLockedToken<CStringTable> DiscordWorldSTRGObj;
static std::string DiscordWorldName;
static u32 DiscordItemPercent = 0xffffffff;
static std::string DiscordState;
2018-12-07 21:30:43 -08:00
void CMain::InitializeDiscord() {
2022-01-31 16:06:54 -08:00
#ifdef ENABLE_DISCORD
DiscordStartTime = std::time(nullptr);
2018-12-07 21:30:43 -08:00
DiscordEventHandlers handlers = {};
handlers.ready = HandleDiscordReady;
handlers.disconnected = HandleDiscordDisconnected;
handlers.errored = HandleDiscordErrored;
Discord_Initialize(DISCORD_APPLICATION_ID, &handlers, 1, nullptr);
2022-01-31 16:06:54 -08:00
#endif
}
2018-12-07 21:30:43 -08:00
void CMain::ShutdownDiscord() {
2022-01-31 16:06:54 -08:00
#ifdef ENABLE_DISCORD
2018-12-07 21:30:43 -08:00
DiscordWorldSTRGObj = TLockedToken<CStringTable>();
Discord_Shutdown();
2022-01-31 16:06:54 -08:00
#endif
}
2018-12-07 21:30:43 -08:00
void CMain::UpdateDiscordPresence(CAssetId worldSTRG) {
2022-01-31 16:06:54 -08:00
#ifdef ENABLE_DISCORD
2018-12-07 21:30:43 -08:00
bool updated = false;
2018-12-07 21:30:43 -08:00
if (worldSTRG != DiscordWorldSTRG) {
DiscordWorldSTRG = worldSTRG;
DiscordWorldSTRGObj = g_SimplePool->GetObj(SObjectTag{FOURCC('STRG'), worldSTRG});
}
if (DiscordWorldSTRGObj.IsLoaded()) {
DiscordWorldName = hecl::Char16ToUTF8(DiscordWorldSTRGObj->GetString(0));
DiscordWorldSTRGObj = TLockedToken<CStringTable>();
updated = true;
}
2020-04-15 04:27:06 -07:00
if (g_GameState != nullptr) {
if (const CPlayerState* pState = g_GameState->GetPlayerState().get()) {
const u32 itemPercent = pState->CalculateItemCollectionRate() * 100 / pState->GetPickupTotal();
2018-12-07 21:30:43 -08:00
if (DiscordItemPercent != itemPercent) {
DiscordItemPercent = itemPercent;
2020-04-11 15:51:39 -07:00
DiscordState = fmt::format(FMT_STRING("{}%"), itemPercent);
updated = true;
2018-12-07 21:30:43 -08:00
}
}
2018-12-07 21:30:43 -08:00
}
if (updated) {
DiscordRichPresence discordPresence = {};
discordPresence.state = DiscordState.c_str();
discordPresence.details = DiscordWorldName.c_str();
discordPresence.largeImageKey = "default";
discordPresence.startTimestamp = DiscordStartTime;
Discord_UpdatePresence(&discordPresence);
}
2022-01-31 16:06:54 -08:00
#endif
2018-12-07 21:30:43 -08:00
}
2020-04-15 04:27:06 -07:00
void CMain::HandleDiscordReady(const DiscordUser* request) {
DiscordLog.report(logvisor::Info, FMT_STRING("Discord Ready"));
}
2018-12-07 21:30:43 -08:00
void CMain::HandleDiscordDisconnected(int errorCode, const char* message) {
2020-04-11 15:51:39 -07:00
DiscordLog.report(logvisor::Warning, FMT_STRING("Discord Disconnected: {}"), message);
2018-12-07 21:30:43 -08:00
}
void CMain::HandleDiscordErrored(int errorCode, const char* message) {
2020-04-11 15:51:39 -07:00
DiscordLog.report(logvisor::Error, FMT_STRING("Discord Error: {}"), message);
2018-12-07 21:30:43 -08:00
}
2023-10-22 09:21:20 -07:00
std::string CMain::Init(int argc, char** argv, const FileStoreManager& storeMgr, CVarManager* cvarMgr) {
2018-12-07 21:30:43 -08:00
m_cvarMgr = cvarMgr;
2022-02-22 22:38:01 -08:00
{
auto discInfo = CDvdFile::DiscInfo();
2022-02-22 22:38:01 -08:00
if (discInfo.gameId[4] != '0' || discInfo.gameId[5] != '1') {
return fmt::format(FMT_STRING("Unknown game ID {}"), std::string_view{discInfo.gameId.data(), 6});
2022-02-22 22:38:01 -08:00
}
if (strncmp(discInfo.gameId.data(), "GM8", 3) == 0) {
2022-02-22 22:38:01 -08:00
m_version.game = EGame::MetroidPrime1;
m_version.platform = EPlatform::GameCube;
} else if (strncmp(discInfo.gameId.data(), "R3I", 3) == 0) {
m_version.game = EGame::MetroidPrime1;
m_version.platform = EPlatform::Wii;
} else if (strncmp(discInfo.gameId.data(), "G2M", 3) == 0) {
2022-02-22 22:38:01 -08:00
m_version.game = EGame::MetroidPrime2;
m_version.platform = EPlatform::GameCube;
} else if (strncmp(discInfo.gameId.data(), "R32", 3) == 0) {
m_version.game = EGame::MetroidPrime2;
m_version.platform = EPlatform::Wii;
2022-02-22 22:38:01 -08:00
} else if (strncmp(discInfo.gameId.data(), "RM3", 3) == 0) {
m_version.game = EGame::MetroidPrime3;
m_version.platform = EPlatform::Wii;
} else if (strncmp(discInfo.gameId.data(), "R3M", 3) == 0) {
2022-02-22 22:38:01 -08:00
m_version.game = EGame::MetroidPrimeTrilogy;
m_version.platform = EPlatform::Wii;
} else {
return fmt::format(FMT_STRING("Unknown game ID {}"), std::string_view{discInfo.gameId.data(), 6});
2022-02-22 22:38:01 -08:00
}
switch (discInfo.gameId[3]) {
case 'E':
if (m_version.game == EGame::MetroidPrime1 && discInfo.version == 48) {
m_version.region = ERegion::KOR;
} else {
m_version.region = ERegion::USA;
}
break;
case 'J':
m_version.region = ERegion::JPN;
break;
case 'P':
m_version.region = ERegion::PAL;
break;
default:
return fmt::format(FMT_STRING("Unknown region {}"), discInfo.gameId[3]);
2020-04-15 06:42:44 -07:00
}
2022-02-22 22:38:01 -08:00
m_version.gameTitle = std::move(discInfo.gameTitle);
}
if (m_version.game != EGame::MetroidPrime1 && m_version.game != EGame::MetroidPrimeTrilogy) {
return fmt::format(FMT_STRING("Unsupported game {}"), magic_enum::enum_name(m_version.game));
}
{
auto dolFile = "default.dol"sv;
if (m_version.game == EGame::MetroidPrimeTrilogy) {
dolFile = "rs5mp1_p.dol"sv;
} else if (m_version.platform == EPlatform::Wii) {
dolFile = "rs5mp1jpn_p.dol"sv;
}
CDvdFile file(dolFile);
if (!file) {
return fmt::format(FMT_STRING("Failed to open {}"), dolFile);
2022-01-31 16:06:54 -08:00
}
std::unique_ptr<u8[]> buf = std::make_unique<u8[]>(file.Length());
u32 readLen = file.SyncRead(buf.get(), file.Length());
const char* buildInfo = static_cast<char*>(memmem(buf.get(), readLen, "MetroidBuildInfo", 16)) + 19;
if (buildInfo == nullptr) {
return fmt::format(FMT_STRING("Failed to locate MetroidBuildInfo"));
}
m_version.version = buildInfo;
2020-04-15 06:42:44 -07:00
}
MainLog.report(logvisor::Level::Info, FMT_STRING("Loading data from {} {} ({})"), GetGameTitle(),
magic_enum::enum_name(GetRegion()), GetVersionString());
InitializeDiscord();
if (m_version.game == EGame::MetroidPrimeTrilogy) {
CDvdFile::SetRootDirectory("MP1");
} else if (m_version.platform == EPlatform::Wii) {
CDvdFile::SetRootDirectory("MP1JPN");
}
2020-04-15 23:57:04 -07:00
InitializeSubsystems();
AddOverridePaks();
2020-05-07 20:20:23 -07:00
x128_globalObjects->PostInitialize();
2020-04-15 23:57:04 -07:00
x70_tweaks.RegisterTweaks(m_cvarMgr);
x70_tweaks.RegisterResourceTweaks(m_cvarMgr);
AddWorldPaks();
2022-07-29 13:16:55 -07:00
for (int i = 1; i < argc; ++i) {
std::string arg = argv[i];
if (arg == "--warp" && i < argc - 2) {
const char* worldIdxStr = argv[i + 1];
const char* areaIdxStr = argv[i + 2];
2018-12-07 21:30:43 -08:00
char* endptr = nullptr;
m_warpWorldIdx = TAreaId(strtoul(worldIdxStr, &endptr, 0));
2020-04-15 04:27:06 -07:00
if (endptr == worldIdxStr) {
2018-12-07 21:30:43 -08:00
m_warpWorldIdx = 0;
2020-04-15 04:27:06 -07:00
}
m_warpAreaId = TAreaId(strtoul(areaIdxStr, &endptr, 0));
2020-04-15 04:27:06 -07:00
if (endptr == areaIdxStr) {
2018-12-07 21:30:43 -08:00
m_warpAreaId = 0;
2020-04-15 04:27:06 -07:00
}
2018-12-07 21:30:43 -08:00
bool found = false;
for (const auto& pak : g_ResFactory->GetResLoader()->GetPaks()) {
if (*(pak->GetPath().end() - 5) == '0' + m_warpWorldIdx) {
2018-12-07 21:30:43 -08:00
found = true;
break;
}
2018-12-07 21:30:43 -08:00
}
if (!found) {
m_warpWorldIdx = -1;
break;
}
2022-07-29 13:16:55 -07:00
while (i < argc - 3) {
const char* layerStr = argv[i + 3];
if (!(layerStr[0] == '0' && layerStr[1] == 'x') && (layerStr[0] == '0' || layerStr[0] == '1')) {
for (const auto* cur = layerStr; *cur != '\0'; ++cur)
if (*cur == '1')
2019-01-29 00:28:35 -08:00
m_warpLayerBits |= u64(1) << (cur - layerStr);
} else if (layerStr[0] == '0' && layerStr[1] == 'x') {
m_warpMemoryRelays.emplace_back(TAreaId(strtoul(layerStr + 2, nullptr, 16)));
2019-02-09 20:41:35 -08:00
}
2022-07-29 13:16:55 -07:00
++i;
2018-12-07 21:30:43 -08:00
}
SetFlowState(EClientFlowStates::StateSetter);
2019-02-09 20:41:35 -08:00
break;
}
2018-12-07 21:30:43 -08:00
}
2018-12-07 21:30:43 -08:00
FillInAssetIDs();
2023-10-22 09:21:20 -07:00
x164_archSupport = std::make_unique<CGameArchitectureSupport>(*this);
2018-12-07 21:30:43 -08:00
g_archSupport = x164_archSupport.get();
x164_archSupport->PreloadAudio();
std::srand(static_cast<u32>(CBasics::GetTime()));
2018-12-07 21:30:43 -08:00
// g_TweakManager->ReadFromMemoryCard("AudioTweaks");
return {};
}
2021-05-24 14:25:31 -07:00
bool CMain::Proc(float dt) {
CRandom16::ResetNumNextCalls();
2019-03-09 00:58:27 -08:00
if (!m_loadedPersistentResources) {
2020-05-07 20:20:23 -07:00
x128_globalObjects->m_gameResFactory->LoadPersistentResources(*g_SimplePool);
2019-03-09 00:58:27 -08:00
m_loadedPersistentResources = true;
}
2017-10-16 22:51:53 -07:00
2021-05-25 09:24:05 -07:00
if (!m_paused) {
2018-12-07 21:30:43 -08:00
CGBASupport::GlobalPoll();
x164_archSupport->UpdateTicks(dt);
x164_archSupport->Update(dt);
CSfxManager::Update(dt);
CStreamAudioManager::Update(dt);
2018-12-07 21:30:43 -08:00
}
2018-01-15 08:00:20 -08:00
2018-12-07 21:30:43 -08:00
if (x164_archSupport->GetIOWinManager().IsEmpty() || CheckReset()) {
CStreamAudioManager::StopAll();
/*
x164_archSupport.reset();
g_archSupport = x164_archSupport.get();
x164_archSupport->PreloadAudio();
*/
x160_24_finished = true;
}
2022-01-31 16:06:54 -08:00
#ifdef ENABLE_DISCORD
2018-12-07 21:30:43 -08:00
Discord_RunCallbacks();
2022-01-31 16:06:54 -08:00
#endif
2018-12-07 21:30:43 -08:00
return x160_24_finished;
2016-04-15 13:42:40 -07:00
}
void CMain::Draw() { x164_archSupport->Draw(); }
2018-12-07 21:30:43 -08:00
void CMain::ShutdownSubsystems() {
CDecalManager::Shutdown();
CElementGen::Shutdown();
CAnimData::FreeCache();
CMemoryCardSys::Shutdown();
CMappableObject::Shutdown();
// Metaforce additions
CMoviePlayer::Shutdown();
2022-03-07 15:53:42 -08:00
CFont::Shutdown();
2022-03-08 15:35:40 -08:00
CFluidPlaneManager::Shutdown();
2018-12-07 21:30:43 -08:00
}
void CMain::Shutdown() {
2020-05-07 20:20:23 -07:00
x128_globalObjects->m_gameResFactory->UnloadPersistentResources();
2018-12-07 21:30:43 -08:00
x164_archSupport.reset();
ShutdownSubsystems();
// CBooModel::Shutdown();
// CGraphics::ShutdownBoo();
2018-12-07 21:30:43 -08:00
ShutdownDiscord();
}
2020-05-07 20:20:23 -07:00
#if 0
int CMain::RsMain(int argc, char** argv, boo::IAudioVoiceEngine* voiceEngine,
2020-05-07 20:20:23 -07:00
amuse::IBackendVoiceAllocator& backend) {
// PPCSetFpIEEEMode();
// uVar21 = OSGetTime();
// LCEnable();
x128_globalObjects = std::make_unique<CGameGlobalObjects>(nullptr, nullptr);
xf0_.resize(4, 0.3f);
x104_.resize(4, 0.2f);
x118_ = 0.3f;
x11c_ = 0.2f;
InitializeSubsystems();
x128_globalObjects->PostInitialize(); // COsContext*, CMemorySys*
x70_tweaks.RegisterTweaks(m_cvarMgr);
AddWorldPaks();
std::string msg;
if (!g_TweakManager->ReadFromMemoryCard("AudioTweaks"sv)) {
msg = "Loaded audio tweaks from memory card\n"s;
} else {
msg = "FAILED to load audio tweaks from memory card\n";
}
FillInAssetIDs();
x164_archSupport = std::make_unique<CGameArchitectureSupport>(*this, voiceEngine, backend);
x164_archSupport->PreloadAudio();
return 0;
}
#endif
2021-04-10 01:42:06 -07:00
} // namespace metaforce::MP1