Files
GTASource/game/system/StreamingInstall.winrt.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

441 lines
13 KiB
C++

//
// system/StreamingInstall.winrt.cpp
//
// Copyright (C) 2014 Rockstar Games. All Rights Reserved.
//
#include "StreamingInstall.winrt.h"
#if RSG_ORBIS
#include "audio/northaudioengine.h"
#include "system/controlMgr.h"
#include "frontend/WarningScreen.h"
#endif // RSG_ORBIS
#include "frontend/loadingscreens.h"
#include "fwrenderer/renderthread.h"
#include "grcore/debugdraw.h"
#include "grcore/light.h"
#include "grcore/setup.h"
#include "grcore/stateblock.h"
#include "grcore/viewport.h"
#include "grprofile/timebars.h"
#include "grmodel/setup.h"
#include "network/Network.h"
#include "renderer/color.h"
#include "renderer/sprite2d.h"
#include "system/system.h"
#include "text/text.h"
#if RSG_ORBIS
#include <libsysmodule.h>
#include <playgo.h>
#pragma comment(lib, "libScePlayGo_stub_weak.a")
ScePlayGoHandle s_playGoHandle = -1;
ScePlayGoInitParams s_playGoParams;
u32 s_numChunks = 0;
ScePlayGoChunkId s_chunkIds[100] = {0};
#elif RSG_DURANGO
#using <windows.winmd>
Windows::Xbox::Management::Deployment::PackageTransferWatcher^ s_playGoTransferWatcher = nullptr;
// windows.winmd plays havoc with the game code for some reason, so #including northaudioengine.h here causes weird errors
void InitialiseAudioForInstall();
#endif
u32 s_playGoPercentComplete = 0;
static grcDepthStencilStateHandle s_installerState_DS;
static grcRasterizerStateHandle s_installerState_R;
static grcBlendStateHandle s_installerState_B;
bool StreamingInstall::ms_installedThisSession = false;
#if RSG_DURANGO
Windows::Foundation::EventRegistrationToken s_ProgressToken;
Windows::Foundation::EventRegistrationToken s_ProcessCompleteToken;
// Init Handler
void StreamingInstall::InitTransferPackageWatcher()
{
s_playGoPercentComplete = 0;
s_playGoTransferWatcher = Windows::Xbox::Management::Deployment::PackageTransferWatcher::Create(Windows::ApplicationModel::Package::Current);
Displayf("[PLAYGO] TransferWatcher Initialized");
s_ProgressToken = s_playGoTransferWatcher->ProgressChanged += ref new Windows::Foundation::TypedEventHandler<Windows::Xbox::Management::Deployment::PackageTransferWatcher^, Windows::Xbox::Management::Deployment::ProgressChangedEventArgs^>(
[&] (Windows::Xbox::Management::Deployment::PackageTransferWatcher^ ptm, Windows::Xbox::Management::Deployment::ProgressChangedEventArgs^ args)
{
Displayf("[PLAYGO] TransferWatcher::ProgressChanged Called");
s_playGoPercentComplete = args->PercentComplete;
});
// s_ProcessCompleteToken = s_playGoTransferWatcher->TransferCompleted += ref new Windows::Foundation::TypedEventHandler<Windows::Xbox::Management::Deployment::PackageTransferWatcher^, Windows::Xbox::Management::Deployment::TransferCompletedEventArgs^>(
// [&] (Windows::Xbox::Management::Deployment::PackageTransferWatcher^ ptm, Windows::Xbox::Management::Deployment::TransferCompletedEventArgs^)
// {
// Displayf("[PLAYGO] TransferWatcher::TransferCompleted Called");
// s_playGoPercentComplete = 100;
// });
ms_installedThisSession = s_playGoPercentComplete > 0 && s_playGoPercentComplete < 100;
}
// Shutdown Handler
void StreamingInstall::ShutdownTransferPackageWatcher()
{
if( s_playGoTransferWatcher != nullptr)
{
s_playGoTransferWatcher->ProgressChanged -= s_ProgressToken;
s_playGoTransferWatcher->TransferCompleted -= s_ProcessCompleteToken;
s_playGoTransferWatcher = nullptr;
}
}
// Resume Delegate
static ServiceDelegate s_StreamingInstallResumeFromSuspendDelegate;
// The actual delegate
void sysStreamingInstallResumeFromSuspend(sysServiceEvent* evnt)
{
if(evnt != NULL)
{
switch(evnt->GetType())
{
case sysServiceEvent::RESUME_IMMEDIATE:
// Shutdown Handler
StreamingInstall::ShutdownTransferPackageWatcher();
// And Start it again
StreamingInstall::InitTransferPackageWatcher();
break;
default:
break;
}
}
}
// Added Delegate
void StreamingInstall::AddResumeDelegate()
{
s_StreamingInstallResumeFromSuspendDelegate.Bind(&sysStreamingInstallResumeFromSuspend);
g_SysService.AddDelegate(&s_StreamingInstallResumeFromSuspendDelegate);
}
// Remove Delegate
void StreamingInstall::RemoveResumeDelegate()
{
g_SysService.RemoveDelegate(&s_StreamingInstallResumeFromSuspendDelegate);
s_StreamingInstallResumeFromSuspendDelegate.Unbind();
}
#endif //RSG_DURANGO
bool StreamingInstall::Init()
{
#if RSG_ORBIS
if (sceSysmoduleLoadModule(SCE_SYSMODULE_PLAYGO) != SCE_OK)
{
Quitf("Failed to load PlayGo module!");
}
s_playGoParams.bufAddr = new u8[SCE_PLAYGO_HEAP_SIZE];
s_playGoParams.bufSize = SCE_PLAYGO_HEAP_SIZE;
s_playGoParams.reserved = 0;
if (scePlayGoInitialize(&s_playGoParams) != SCE_OK)
{
Displayf("[PLAYGO] Failed to initialize PlayGo library!");
}
s_numChunks = 0;
if (scePlayGoOpen(&s_playGoHandle, NULL) != SCE_OK)
{
s_playGoHandle = -1;
Displayf("[PLAYGO] Failed to open PlayGo package!");
}
else
{
ScePlayGoToDo chunks[100];
if (scePlayGoGetToDoList(s_playGoHandle, chunks, 100, &s_numChunks) != SCE_OK)
{
Displayf("[PLAYGO] Failed to get PlayGo ToDo list!");
}
Assertf(s_numChunks <= 100, "Too many PlayGo chunks, increase the array size!");
// numChunks will be set to the number of PlayGo chunks that are still scheduled to change their locus.
// i.e. they need to be copied somewhere. the copy only happens psn->hdd or odd->hdd, and in either way we need
// to wait for the copy to finish before we can play the game, since we don't support streaming from odd
// while playing.
Displayf("[PLAYGO] Found %d PlayGo chunks in the ToDo list", s_numChunks);
// save chunk ids so we can later check the progress
for (u32 i = 0; i < s_numChunks; ++i)
s_chunkIds[i] = chunks[i].chunkId;
}
ms_installedThisSession = s_numChunks > 0;
return s_numChunks == 0;
#elif RSG_DURANGO
// Start the package transfer watcher
InitTransferPackageWatcher();
// Add the ResumeFromSuspend Delegate
AddResumeDelegate();
// when 0, we don't even have the initial payload installed, meaning we run a non-packaged
// build (streamed or deployed). this shouldn't happen in retail since we can't boot the game until the
// // initial payload is installed, putting the percentage at >0
Displayf("[PLAYGO] Percent complete: %d", s_playGoPercentComplete);
return s_playGoPercentComplete == 0 || s_playGoPercentComplete >= 100;
#else
return true;
#endif
}
bool StreamingInstall::HasInstallFinished()
{
if (!ms_installedThisSession)
return true;
#if RSG_ORBIS
if (s_playGoHandle == -1)
return true;
ScePlayGoProgress progress;
s32 ret = scePlayGoGetProgress(s_playGoHandle, s_chunkIds, s_numChunks, &progress);
if (ret != SCE_OK )
{
Displayf("[PLAYGO] Failed to get progress for PlayGo chunks! (%d)", ret);
return true;
}
s_playGoPercentComplete = (u32)(100.f * progress.progressSize / (float)progress.totalSize);
Displayf("[PLAYGO] Progress: %lu / %lu", progress.progressSize, progress.totalSize);
return progress.progressSize >= progress.totalSize;
#elif RSG_DURANGO
Displayf("[PLAYGO] Progress: %d%%", s_playGoPercentComplete);
return s_playGoPercentComplete >= 100;
#else
return true;
#endif
}
void StreamingInstall::BlockUntilFinished()
{
if (HasInstallFinished())
return;
#if RSG_ORBIS
CLoadingScreens::SleepUntilPastLegalScreens();
CLoadingScreens::Suspend();
while(true)
{
PF_FRAMEINIT_TIMEBARS(0);
if(UpdateSleepWarning())
{
CWarningScreen::Update();
break;
}
fwTimer::Update();
CControlMgr::Update();
CWarningScreen::Update();
PF_FRAMEEND_TIMEBARS();
sysIpcSleep(16);
}
CLoadingScreens::Resume();
#endif // RSG_ORBIS
// we need our own render function to flip the buffers while we block for the install to finish
RenderFn oldRenderFunc = gRenderThreadInterface.GetRenderFunction();
gRenderThreadInterface.SetRenderFunction(MakeFunctor(RenderInstallProgress));
gRenderThreadInterface.Flush();
#if RSG_DURANGO
sysTimer audioTimer;
bool hasInitialisedAudio = false;
#endif
while (!HasInstallFinished())
{
CNetwork::Update(true);
CLoadingScreens::KeepAliveUpdate();
sysIpcSleep(16);
#if RSG_DURANGO
// Wait until after the bink movie, then initialise audio to start the loading music
if(audioTimer.GetTime() > 15.f && !hasInitialisedAudio)
{
InitialiseAudioForInstall();
hasInitialisedAudio = true;
}
#endif // RSG_DURANGO
}
gRenderThreadInterface.SetRenderFunction(oldRenderFunc);
gRenderThreadInterface.Flush();
}
void StreamingInstall::RenderInstallProgress()
{
if (CLoadingScreens::GetLegalMainMovieIndex() == LOADINGCREEN_MOVIE_INDEX_STARTUP_FINAL)
{
if (CLoadingScreens::GetCurrentContext() != LOADINGSCREEN_CONTEXT_LEGALMAIN) // Only override the actual loading screen (not the legal text)
{
char infoStr[256] = {0};
formatf(infoStr, "%d %s", s_playGoPercentComplete, "%");
float percentComplete = (float)s_playGoPercentComplete;
CLoadingScreens::SetInstallerInfo(percentComplete, infoStr);
}
CLoadingScreens::RenderLoadingScreens();
return;
}
PF_FRAMEINIT_TIMEBARS(0);
TIME.Update();
CSystem::BeginRender();
const grcViewport* pVp = grcViewport::GetDefaultScreen();
GRCDEVICE.Clear(true, Color32(0,0,0), false, 0, false, 0);
if (!s_installerState_R)
CreateStateBlocks();
grcViewport::SetCurrent(pVp);
grcStateBlock::SetRasterizerState(s_installerState_R);
grcStateBlock::SetBlendState(s_installerState_B);
grcStateBlock::SetDepthStencilState(s_installerState_DS);
grcLightState::SetEnabled(false);
grcWorldIdentity();
CTextLayout textLayout;
Vector2 textPos(0.5f, 0.6f);
Vector2 textSize = Vector2(0.33f, 0.4785f);
CRGBA textColor(100, 250, 100, 255);
textLayout.SetScale(&textSize);
textLayout.SetColor(textColor);
textLayout.SetOrientation(FONT_CENTRE);
char debugText[1024];
formatf(debugText, "Installing content: %d%s", s_playGoPercentComplete, "%");
textLayout.Render(&textPos, debugText);
CText::Flush();
Vector2 sliderSize(400.f, 20.f);
Vector2 totalSliderPos(440.f, 460.f);
Vector2 fileSliderPos(440.f, 535.f);
CRGBA shadow(0, 0, 0, 100);
CRGBA front(100, 250, 100, 250);
CRGBA back(80, 200, 80, 80);
CSprite2d::DrawRect(fwRect(totalSliderPos.x, totalSliderPos.y, (totalSliderPos.x + sliderSize.x), (totalSliderPos.y + sliderSize.y)), back); // back of slider
float totalSliderValue = sliderSize.x * (10.f / 100.f);
CSprite2d::DrawRect(fwRect(totalSliderPos.x, totalSliderPos.y, (totalSliderPos.x + totalSliderValue), (totalSliderPos.y + sliderSize.y)), front); // front of slider
CSprite2d::DrawRect(fwRect(fileSliderPos.x, fileSliderPos.y, (fileSliderPos.x + sliderSize.x), (fileSliderPos.y + sliderSize.y)), back); // back of slider
float fileSliderValue = sliderSize.x * (5.f / 10.f);
CSprite2d::DrawRect(fwRect(fileSliderPos.x, fileSliderPos.y, (fileSliderPos.x + fileSliderValue), (fileSliderPos.y + sliderSize.y)), front); // front of slider
grcViewport::SetCurrent(NULL);
CSystem::EndRender();
}
#if RSG_ORBIS
bool StreamingInstall::UpdateSleepWarning()
{
bool bAccepted = false;
CWarningScreen::SetMessage(WARNING_MESSAGE_STANDARD, "WARN_SLEEP_TIMER", static_cast<eWarningButtonFlags>(FE_WARNING_OK | FE_WARNING_NOSOUND));
if (CWarningScreen::CheckAllInput(false) == FE_WARNING_OK)
{
CWarningScreen::Remove();
if(!audNorthAudioEngine::InitClass())
{
Errorf("Failed to initialise audio");
}
bAccepted = true;
}
return bAccepted;
}
#endif // RSG_ORBIS
void StreamingInstall::CreateStateBlocks()
{
// state blocks for install screen (create on first use
grcRasterizerStateDesc rsd;
rsd.CullMode = grcRSV::CULL_NONE;
rsd.FillMode = grcRSV::FILL_SOLID;
rsd.HalfPixelOffset = 1;
s_installerState_R = grcStateBlock::CreateRasterizerState(rsd);
grcBlendStateDesc bsd;
bsd.BlendRTDesc[0].BlendEnable = 1;
bsd.BlendRTDesc[0].DestBlend = grcRSV::BLEND_INVSRCALPHA;
bsd.BlendRTDesc[0].SrcBlend = grcRSV::BLEND_SRCALPHA;
bsd.BlendRTDesc[0].BlendOp = grcRSV::BLENDOP_ADD;
s_installerState_B = grcStateBlock::CreateBlendState(bsd);
grcDepthStencilStateDesc dssd;
dssd.DepthWriteMask = 0;
dssd.DepthEnable = 0;
s_installerState_DS = grcStateBlock::CreateDepthStencilState(dssd);
}
void StreamingInstall::Shutdown()
{
#if RSG_ORBIS
if (s_playGoHandle == -1)
return;
Displayf("[PLAYGO] Closing PlayGo handle.");
if (scePlayGoClose(s_playGoHandle) != SCE_OK)
{
Displayf("[PLAYGO] Failed to close PlayGo handle!");
}
if (scePlayGoTerminate() != SCE_OK)
{
Displayf("[PLAYGO] Terminating PlayGo library.");
}
s_playGoHandle = -1;
delete[] (u8*)s_playGoParams.bufAddr;
s_playGoParams.bufSize = 0;
if (sceSysmoduleIsLoaded(SCE_SYSMODULE_PLAYGO) == SCE_SYSMODULE_LOADED)
{
if (sceSysmoduleUnloadModule(SCE_SYSMODULE_PLAYGO) != SCE_OK)
{
Displayf("[PLAYGO] Failed to unload PlayGo module!");
}
}
#elif RSG_DURANGO
RemoveResumeDelegate();
ShutdownTransferPackageWatcher();
#endif
}