Condividi tramite


Installazione su richiesta di giochi

Questo articolo tecnico illustra due tecniche, l'installazione su richiesta e l'installazione in background, con Windows Installer. I giochi possono utilizzare queste tecniche di installazione per offrire un'esperienza di gioco migliore e più piacevole per i giocatori riducendo il tempo di installazione.

Panoramica

L'installazione è stata un elemento di applicazioni basate su computer da molto tempo. La maggior parte delle applicazioni richiede oggi di essere installata sul disco rigido locale dell'utente prima di poterle usare. I giochi informatici non fanno eccezione; quando un consumer acquista un gioco di Microsoft Windows e tenta di eseguirlo, deve prima eseguire un processo di installazione che copia i file necessari dal disco del gioco al disco rigido. Questo processo di installazione è in genere lungo e può richiedere fino a un'ora per il completamento. Il tempo di installazione è un fattore che rende i giochi console più auspicabili rispetto ai giochi basati su computer per alcuni giocatori, in quanto sono in grado di giocare immediatamente un gioco console dopo aver inserito il disco del gioco. La tecnologia descritta in questo articolo tenterà di risolvere questo problema riducendo drasticamente il tempo di installazione.

Tradizionalmente, i giochi richiedono che tutti o la maggior parte dei file siano installati prima dell'avvio. Per ottenere l'installazione su richiesta, le risorse del gioco devono essere modulari; ovvero, lo sviluppatore deve dividere le risorse dell'applicazione (grafica, audio e così via) in componenti. Ogni componente è un set di risorse che possono essere installate o rimosse come unità. Al termine, lo sviluppatore di giochi definisce una o più funzionalità, in genere una o più per livello o zona. Ogni funzionalità di un'applicazione specifica un set di componenti necessari per l'esecuzione di tale funzionalità specifica. Quando un'applicazione viene installata, le relative funzionalità possono essere contrassegnate come "install" (componenti copiati nel disco rigido locale al momento dell'installazione) o "annunciate" (componenti copiati nel disco rigido locale dopo l'installazione iniziale quando l'applicazione usa tale funzionalità). Uno sviluppatore di giochi può ridurre il tempo di installazione progettando il gioco per l'avvio e l'esecuzione con un set minimo di funzionalità installate. Il resto delle sue funzionalità può essere contrassegnato come annunciato e installato su richiesta quando l'applicazione deve effettivamente usare le funzionalità fornite da tali funzionalità.

I giochi possono chiamare Windows Installer per installare una particolare funzionalità che potrebbe non essere stata installata. Per visualizzare l'installazione in background, è possibile usare un thread di lavoro per effettuare le chiamate al programma di installazione mentre il thread primario continua a gestire la logica del gioco e a eseguire il rendering dello schermo. Ciò riduce al minimo l'interruzione del gioco causato dall'installazione. Il gioco può avviare l'installazione in qualsiasi momento. Tuttavia, poiché l'installazione utilizza cicli del processore, in genere non è consigliabile eseguire l'installazione quando il thread primario è in un'esigenza critica di potenza di elaborazione, ad esempio quando l'utente si trova al centro dell'azione. Ad esempio, un buon momento per eseguire l'installazione può essere durante il momento in cui l'utente si trova nel menu del gioco, quando il gioco viene sospeso o ridotto a icona o quando l'utente sta guardando il filmato introduttivo o i tagli.

Supporto per l'applicazione di patch

La maggior parte dei giochi oggi deve essere aggiornata anche dopo la spedizione come bug vengono corretti e vengono aggiunte nuove funzionalità. L'aggiornamento spesso richiede l'applicazione di patch, che tradizionalmente è una procedura semplice per i giochi. Poiché tutti i file necessari vengono installati sul disco rigido dell'utente, l'applicazione di patch a un gioco comporta la copia di file rivisti nel disco rigido, sovrascrivendo i file esistenti. Quando viene usata l'installazione su richiesta, non tutti i file vengono installati e copiati al momento dell'applicazione di patch. Pertanto, il patcher non può semplicemente scrivere file aggiornati nella cartella del gioco.

Windows Installer include funzionalità per l'applicazione di patch alle applicazioni che usano l'installazione su richiesta. Quando si applica una patch, il programma di installazione memorizza nella cache la patch nel sistema. Questa funzionalità funziona bene per le patch con delta di piccole dimensioni. I file originariamente rilasciati non devono più trovarsi sul disco al momento dell'applicazione di patch, in modo che tali file possano essere annunciati. Successivamente, quando l'applicazione viene eseguita e deve accedere ai file, il programma di installazione installa la versione più recente di tali file copiando la versione originariamente rilasciata dal supporto (ad esempio, I CD) e applicando la patch dopo aver letto i dati delle patch salvate.

Esempio di InstallOnDemand SDK

L'esempio Install-on-Demand for Games illustra le tecniche di installazione su richiesta descritte in questo articolo. A differenza di altri esempi, non è possibile eseguire Install-on-Demand for Games direttamente dal browser di esempio. Poiché l'esempio usa Windows Installer per gestire l'installazione, deve essere incluso nel database del programma di installazione di applicazioni installate.

Per avviare l'esempio

  1. Usare il collegamento Installa progetto nel browser di esempio per copiare i file dell'esempio in una cartella.
  2. Fare doppio clic su InstallOnDemand.msi per installare l'esempio.
  3. Selezionare Installazione tipica.
  4. Avviare l'esempio avviando InstallOnDemand.exe nella cartella installata (in genere Programmi\InstallOnDemand) o avviando da Start Menu\Programmi.

InstallOnDemand.msi è un database riconosciuto dal programma di installazione. Definisce l'intero processo di installazione: la struttura di directory, il contenuto e la mancata copia, le risorse che verranno copiate insieme, i valori del Registro di sistema da scrivere, i collegamenti da creare e così via.

All'avvio, l'esempio riproduce una sequenza introduttiva. Il giocatore può terminare e immettere il menu principale premendo ESC. Dopo l'introduzione, il giocatore può avviare un nuovo gioco immettendo un nome di carattere e scorrendo le statistiche. Prima che l'esempio inizi a riprodurre la sequenza di introduzione, l'esempio chiama una funzione del programma di installazione per verificare se è installata la funzionalità per il livello 1. Se la funzionalità di livello 1 non è stata installata, l'esempio usa un thread in background per chiedere al programma di installazione di installare il gioco, mentre il thread primario sta eseguendo un'altra operazione (ad esempio giocando la sequenza di introduzione, eseguendo il rendering del menu o interagendo con il giocatore durante la creazione del carattere). L'esperienza è diversa dall'installazione tradizionale del gioco in quanto l'utente è occupato nel gioco (guardando l'introduzione o creando un nuovo personaggio) mentre l'installazione è in corso. Al termine della creazione di un carattere, l'esempio carica le risorse per il livello 1.

Sul lato destro della schermata di esempio sono presenti cinque pulsanti contrassegnati come "Play Level 1" tramite "Play Level 5". Questi pulsanti simulano il completamento del livello corrente e l'avanzamento al successivo. Quando si fa clic su uno di questi pulsanti, viene visualizzata una schermata delle statistiche che mostra le informazioni sul livello appena terminato. L'esempio richiede anche questo tempo per chiedere al programma di installazione di controllare e installare il livello successivo, se non è già installato. L'installazione viene eseguita mentre il lettore legge la schermata delle statistiche, in modo che quando l'utente fa clic su OK per entrare nel livello successivo, tutte le risorse del livello sono installate e pronte per essere caricate.

Caratteristiche e componenti dell'esempio

Tradizionalmente, i giochi richiedono che tutti o la maggior parte dei file siano installati prima dell'avvio. Per ottenere l'installazione su richiesta, le risorse del gioco devono essere modulari; ovvero, lo sviluppatore deve dividere le risorse dell'applicazione (grafica, audio e così via) in componenti. Ogni componente è un set di risorse che possono essere installate o rimosse come unità. Al termine, lo sviluppatore di giochi definisce una o più funzionalità, in genere una o più per livello o zona. Ogni funzionalità di un'applicazione specifica un set di componenti necessari per l'esecuzione di tale funzionalità specifica. Quando un'applicazione viene installata, le relative funzionalità possono essere contrassegnate come "installa" (componenti copiati nel disco rigido locale al momento dell'installazione) o "annunciate" (componenti copiati nel disco rigido locale quando l'applicazione usa successivamente tale funzionalità). Uno sviluppatore di giochi può ridurre il tempo di installazione progettando il gioco per avviare e avviare l'esecuzione con un set minimo di funzionalità installate. Il resto delle sue funzionalità può essere contrassegnato come annunciato e installato su richiesta quando l'applicazione deve effettivamente usare le funzionalità fornite da tali funzionalità.

Nella tabella seguente sono elencate le sei funzionalità di primo livello definite dall'esempio.

Nome della funzionalità Funzionalità Componenti File
Core Include le risorse necessarie in qualsiasi momento, indipendentemente dal livello. Queste risorse sono: eseguibile di esempio, supporto richiesto dalla sequenza di introduzione e schermata di caricamento e file fx che gestisce tutto il rendering nell'esempio. Core InstallOnDemand.exe, InstallOnDemand.fx, Loading.bmp, Level.x
Core (uguale a quanto sopra) CoreUI Media\UI\dxutcontrols.dds, Media\UI\DXUTShared.fx, Media\UI\arrow.x
Core (uguale a quanto sopra) CoreMisc Media\Misc\sea floor.x, Media\Misc\sea floor.bmp
Core (uguale a quanto sopra) CoreSpeeder Media\PRT Demo\LandShark.x, Media\PRT Demo\speeder_diff.jpg
Core (uguale a quanto sopra) CoreReg N/D (valore del Registro di sistema)
Level1 Fornisce le risorse usate dal livello 1. Level1 Level1.jpg
Level1 (uguale a quello precedente) L1Skybox Media\Probes\galileo_cross.dds
Level2 Fornisce le risorse usate dal livello 2. Level2 Level2.jpg
Level2 (uguale a quello precedente) L2Skybox Media\Probes\grace_cross.dds
Level3 Fornisce le risorse usate dal livello 3. Level3 Level3.jpg
Level3 (uguale a quello precedente) L3Skybox Media\Probes\rnl_cross.dds
Level4 Fornisce le risorse usate dal livello 4. Level4 Level4.jpg
Level4 (uguale a quello precedente) L4Skybox Media\Probes\stpeters_cross.dds
Level5 Fornisce le risorse usate dal livello 5. Level5 Level5.jpg
Level5 (uguale a quello precedente) L5Skybox Media\Probes\uffizi_cross.dds

 

Le funzionalità da Level1 a Level5 hanno funzionalità secondarie aggiuntive che contengono file non usati direttamente dall'esempio. Questi file di funzionalità secondarie sono stati aggiunti per rendere l'installazione più lunga. Questa operazione viene eseguita per illustrare l'operazione di installazione in corso in esecuzione in background durante l'esecuzione dell'esempio.

Nella tabella seguente sono elencate le funzionalità secondarie.

Funzionalità Funzionalità secondarie File
Level1 L1PH1, L1PH2, L1PH3, L1PH4, L1PH5 Level1 Placeholder Data\L1PH1.dat Level1 Placeholder Data\L1PH2.dat Level1 Placeholder Data\L1PH3.dat Level1 Placeholder Data\L1PH4.dat Level1 Placeholder Data\L1PH5.dat
Level2 L2PH1, L2PH2, L2PH3, L2PH4, L2PH5 Dati segnaposto Level2\L2PH1.dat Level2 Placeholder Data\L2PH2.dat Level2 Placeholder Data\L2PH3.dat Level2 Placeholder Data\L2PH4.dat Level2 Placeholder Data\L2PH5.dat
Level3 L3PH1, L3PH2, L3PH3, L3PH4, L3PH5 Level3 Placeholder Data\L3PH1.dat Level3 Placeholder Data\L3PH2.dat Level3 Placeholder Data\L3PH3.dat Level3 Placeholder Data\L3PH4.dat Level3 Placeholder Data\L3PH5.dat
Level4 L4PH1, L4PH2, L4PH3, L4PH4, L4PH5 Dati segnaposto Level4\L4PH1.dat Level4 Placeholder Data\L4PH2.dat Level4 Placeholder Data\L4PH3.dat Level4 Placeholder Data\L4PH4.dat Level4 Placeholder Data\L4PH5.dat
Level5 L5PH1, L5PH2, L5PH3, L5PH4, L5PH5 Level5 Placeholder Data\L5PH1.dat Level5 Placeholder Data\L5PH2.dat Level5 Placeholder Data\L5PH3.dat Level5 Placeholder Data\L5PH4.dat Level5 Placeholder Data\L5PH5.dat

 

Durante l'installazione, la funzionalità principale deve essere contrassegnata come "installa" e tutte le altre funzionalità devono essere contrassegnate come "annunciate". Installando una sola funzionalità invece di sei, il tempo che il giocatore deve attendere fino al lancio del gioco è notevolmente ridotto.

Installazione

Windows Installer fornisce un meccanismo che consente a un'applicazione di richiedere l'installazione di una funzionalità annunciata. Tuttavia, il meccanismo è una chiamata API (Application Programming Interface) sincrona, il che significa che l'applicazione deve attendere all'interno della chiamata fino al completamento dell'installazione. Per ottenere l'installazione in background, è necessario un thread di lavoro in modo che il thread dell'applicazione principale sia libero di eseguire altre attività importanti, ad esempio il rendering sullo schermo per continuare a fornire feedback visivo al lettore.

Nell'esempio sono presenti tre stati di installazione che si verificano durante l'esecuzione dell'esempio: installazione attiva, installazione passiva e nessuna installazione.

  • L'installazione attiva è una richiesta avviata dall'esempio quando deve accedere o caricare le risorse fornite da una o più funzionalità. L'esempio esegue questa operazione quando non può continuare finché non viene installata la risorsa.
  • L'installazione passiva viene avviata quando l'esempio non esegue un'attività critica, ad esempio quando il giocatore si trova in un menu o si guarda una scena di taglio. In questo caso, il thread di lavoro controlla se una funzionalità dell'esempio è ancora pubblicizzata. Se può trovarne uno, chiama il programma di installazione per installare tale funzionalità. Questo processo viene ripetuto fino a quando non viene installata ogni funzionalità dell'esempio. Essenzialmente, l'installazione passiva utilizza cicli di processore aggiuntivi per eseguire l'installazione in background quando è meno invadente per l'esempio principale.
  • Non si verifica alcuna installazione quando il giocatore è attivamente impegnato nel gioco; in questo modo si impedisce un calo della frequenza dei fotogrammi che interrompe l'esperienza utente.

Nell'esempio viene definita una classe CMsiUtil per gestire tutte le attività correlate all'installazione. Essenzialmente, CMsiUtil usa un thread di lavoro che richiama il programma di installazione per installare le funzionalità dell'esempio in un ciclo. La classe ha due code che archivia le richieste di installazione: una coda ad alta priorità per l'installazione attiva e una coda con priorità bassa per l'installazione passiva. Durante l'inizializzazione, la classe enumera tutte le funzionalità del prodotto e le aggiunge alla coda di installazione passiva. Poiché l'intero prodotto viene accodato in questo modo, l'intero prodotto verrà infine installato se l'esempio ha cicli di processore liberi sufficienti.

Quando l'esempio deve richiedere un'installazione attiva, l'esempio può chiamare CMsiUtil::UseFeatureSet() e passare il nome della funzionalità di primo livello. UseFeatureSet() accoderà la funzionalità richiesta e tutte le relative funzionalità secondarie nella coda di installazione attiva in modo che il thread di lavoro possa installarle.

Durante l'esecuzione di una richiesta di installazione, il thread di lavoro verificherà la coda di installazione attiva e la coda di installazione passiva per verificare se una delle due code contiene richieste aggiuntive. Ogni volta che il thread trova una richiesta, chiamerà l'API del programma di installazione per eseguire l'installazione effettiva. Quando entrambe le code sono vuote, il thread di lavoro passerà alla sospensione con una chiamata a WaitForSingleObject. Poiché l'intero prodotto viene inserito nella coda di installazione passiva durante l'inizializzazione, una coda vuota implica che l'intero prodotto è stato installato.

L'esempio chiama CMsiUtil::EnablePassiveInstall() per abilitare o disabilitare l'installazione passiva. EnablePassiveInstall(true) incrementa il numero di abilitazioni per l'installazione passiva e EnablePassiveInstall(false) lo decrementa. Se il numero di abilitazioni è maggiore di 0, la classe elabora la coda di installazione passiva. L'esempio consente l'installazione passiva quando si verifica una delle condizioni seguenti:

  • L'utente sta visualizzando la sequenza iniziale di introduzione.
  • L'utente sta navigando nel menu di esempio.
  • L'utente sta visualizzando le statistiche alla fine di un livello.
  • L'applicazione di esempio perde lo stato attivo e passa allo sfondo.

I metodi di CMsiUtil sono elencati di seguito:

Metodo Descrizione
AbortAllRequests Causa l'interruzione dell'installazione corrente e svuota la coda di richieste di installazione attiva.
AbortCurrentRequest Causa l'interruzione dell'installazione in corso. Il thread di lavoro elabora quindi la richiesta successiva nella coda, se presente.
EnablePassiveInstall Incrementa o decrementa il numero di attivazioni dell'installazione passiva. L'esempio usa questa chiamata per controllare quando l'installazione passiva può e non può verificarsi.
GetCurrentFeatureName Restituisce il nome della funzionalità in fase di installazione attiva.
GetFeatureProgress Restituisce la posizione di graduazione corrente per la funzionalità in fase di installazione.
GetFeatureProgressMax Restituisce il numero massimo di segni di avanzamento per la funzionalità in fase di installazione.
GetLastError Utilizzare questo metodo per recuperare il codice restituito dalla richiesta di installazione precedente.
GetPassiveProgress Restituisce la posizione di graduazione dell'indicatore di stato per l'installazione passiva.
GetPassiveProgressMax Restituisce la posizione di graduazione corrente e il numero massimo di tick per l'installazione passiva. Insieme, l'esempio può usarli per mostrare l'avanzamento complessivo dell'installazione passiva.
GetProgress Restituisce la posizione di graduazione dell'indicatore di stato per l'installazione del set di funzionalità attivo. Questa operazione viene utilizzata quando l'esempio esegue il rendering della barra di stato dell'installazione. Poiché Windows Installer fornisce solo informazioni sullo stato di avanzamento per l'installazione di una funzionalità, il metodo divide l'indicatore di stato tra le funzionalità richieste in modo che l'utente veda ancora l'intera installazione come un'unica attività.
GetProgressMax Restituisce il numero massimo di segni di graduazione della barra di stato per l'installazione del set di funzionalità attivo. Questa operazione viene utilizzata quando l'esempio esegue il rendering della barra di stato dell'installazione.
Inizializzare Inizializza la classe con l'identificatore univoco globale del prodotto (GUID). Questo metodo enumera anche ogni funzionalità dell'applicazione che è stata pubblicizzata ma non ancora installata e la inserisce nella coda di installazione passiva per configurare l'installazione passiva.
IsInstallInProgress Utilizzare questo metodo per determinare se è in corso l'elaborazione di un'installazione attiva.
UseFeature Metodo privato chiamato da UseFeatureSet. Controlla se è installata una funzionalità. Se la funzionalità richiesta viene installata, viene restituito il metodo . Se la funzionalità non è ancora installata (pubblicizzata), il metodo accoda una nuova richiesta di installazione attiva per il thread di lavoro e quindi restituisce. Handle di eventi facoltativo che verrà segnalato al termine dell'installazione richiesta.
UseFeatureSet Chiamato dall'esempio quando deve accedere alle funzionalità fornite da una particolare funzionalità o da una delle relative funzionalità secondarie. Il metodo enumera tutte le funzionalità dell'esempio e chiama UseFeature() per le funzionalità secondarie della funzionalità radice specificata. L'esempio può passare un handle di eventi che verrà segnalato quando viene installato l'intero set di funzionalità. Poiché tutte le funzionalità installate come set, l'handle viene specificato per l'ultima funzionalità accodata da UseFeature() invece di ogni funzionalità, in modo che l'esempio riceve una notifica una volta dopo l'installazione di tutte le funzionalità richieste.
UseProduct Accoda una richiesta di installazione attiva per il thread di lavoro per chiamare il programma di installazione per eseguire un'installazione completa del prodotto. Handle di eventi facoltativo che verrà segnalato al termine dell'installazione richiesta.

 

Limitazione

La versione corrente del programma di installazione non è progettata per l'accesso simultaneo da più thread. Pertanto, quando il thread di lavoro chiama il programma di installazione, il thread principale non deve chiamare il programma di installazione. Un esempio di questa limitazione si verifica nell'esempio quando il thread principale richiede una funzionalità, quindi richiede di nuovo la stessa funzionalità prima che il thread di lavoro completi l'installazione. La seconda richiesta chiama MsiQueryFeatureState() per scoprire se la funzionalità richiesta è già installata, poiché il programma di installazione può talvolta indicare che la funzionalità è completamente installata quando il thread di lavoro sta ancora copiando i file.

Fortunatamente, c'è un facile lavoro per questo. CMsiUtil verificherà se una funzionalità viene installata dal thread di lavoro prima di chiamare funzioni come MsiQueryFeatureState() o MsiUseFeature() per chiedere lo stato di installazione della funzionalità in questione. Tenere presente che questa limitazione può anche diventare un problema altrove.

L'applicazione di patch può influire sul funzionamento dell'installazione su richiesta nel computer di un utente finale. L'applicazione di una patch contenente solo i dati modificati dalla versione precedente potrebbe richiedere l'installazione della versione precedente del file aggiornato per applicare il delta. In questo caso, la patch deve richiedere che l'installazione del programma di installazione influisca sulle funzionalità annunciate prima di applicare la patch al gioco.

L'esempio viene installato avviando InstallOnDemand.msi perché presuppone che Windows Installer sia presente nel computer. Se il programma di installazione è assente, i file msi non vengono riconosciuti e l'avvio non funzionerà. Per risolvere questo problema, un'applicazione deve usare un programma di installazione per eseguire l'attività. Questo programma deve prima verificare se il programma di installazione è presente e, in caso affermativo, la relativa versione. Se la versione non soddisfa i requisiti dell'applicazione, il programma di installazione deve installare Windows Installer, quindi avviare il file msi. Questo processo è noto come bootstrap. Le applicazioni in genere denominano il programma di installazione di bootstrap Setup.exe. L'esempio non gestisce il bootstrap. Tuttavia, i dettagli completi sul bootstrap sono disponibili in Windows Installer.

Gli sviluppatori devono prestare attenzione anche alle dimensioni di ogni funzionalità nei loro giochi. Quando si annulla un'installazione in corso, il programma di installazione ripristina lo stato del computer prima dell'installazione. Ciò significa che l'installazione della funzionalità è completamente annullata e non è disponibile alcuna installazione parziale delle funzionalità. Una funzionalità di grandi dimensioni richiede più tempo per l'installazione, aumentando la probabilità che l'installazione venga interrotta e annullata o l'installazione interferisca con l'applicazione principale. Un esempio potrebbe essere l'abilitazione dell'installazione passiva quando l'utente visualizza il menu del gioco al centro della partita. Se una funzionalità viene installata e l'utente torna a giocare, il gioco può eseguire una delle due operazioni seguenti: può consentire il completamento dell'installazione passiva o annullare l'installazione passiva. Una funzionalità di grandi dimensioni si adatta male a entrambi i modelli. Se il gioco consente il completamento dell'installazione di grandi dimensioni, l'installazione potrebbe ostacolare le prestazioni di rendering del gioco per molto tempo. Viceversa, se il gioco annulla l'installazione, l'utente deve rimanere nel menu per molto tempo prima di tornare al gioco. Gli sviluppatori dovrebbero trovare una dimensione di funzionalità bilanciata che funziona meglio per i singoli giochi.