Podczas pakowania gry, Defold pakuje wszystkie zasoby gry do końcowego pakietu specyficznego dla platformy. W większości przypadków jest to preferowane rozwiązanie, ponieważ działający silnik ma natychmiastowy dostęp do wszystkich zasobów i może szybko je ładować. Jednak istnieją sytuacje, w których chcielibyśmy odłożyć ładowanie zasobów na późniejszy etap. Na przykład:
Funkcja Aktualizacji na żywo Live Update) rozszerza koncepcję pełnomocnika kolekcji (collection proxy), oferując mechanizm, który pozwala na pobieranie i przechowywanie zasobów w pakiecie aplikacji, które celowo zostały pominięte podczas tworzenia pakietu na etapie kompilacji.
Załóżmy, że tworzymy grę zawierającą duże zasoby graficzne o wysokiej rozdzielczości. Gra przechowuje te obrazy w kolekcjach z obiektami gry i sprite’ami wykorzystującymi te obrazy:
Aby silnik mógł dynamicznie ładować taką kolekcję, możemy po prostu dodać komponent pełnomocnika kolekcji, będącego pełnomocnikiem właśnie kolekcji monalisa.collection
. Teraz gra może wybrać, kiedy załadować zawartość kolekcji do pamięci, wysyłając komunikat load
do pełnomocnika kolekcji. Jeśli chcielibyśmy pójść dalej i kontrolować ładowanie zasobów zawartych w kolekcji samodzielnie możemy to zrobić, zaznaczając opcję Exclude w właściwościach pełnomocnika kolekcji, informując kompilator, że zawartość w monalisa.collection
powinna być pominięta podczas tworzenia pakietu aplikacji.
Kiedy kompilator tworzy pakiet aplikacji, musi gdzieś przechować te wykluczone zasoby. Ustawienia projektu dla Aktualizacji na żywo (Live update settings) określają lokalizację tych zasobów. Ustawienia te znajdują się w Project ▸ Live update Settings.... Kliknięcie w tę opcję spowoduje utworzenie pliku ustawień, jeśli jeszcze nie istnieje. W pliku game.project
wybierz, które ustawienia Aktualizacji na żywo chcesz użyć podczas kompilacji. Dzięki temu można używać różnych ustawień Aktualizacji na żywo w różnych środowiskach, na przykład na żywo, w QA, w trybie deweloperskim itp.
When the bundler creates an application bundle it needs to store any excluded resources somewhere. The project settings for Live update govern the location for those resources. The settings are found under Project ▸ Live update Settings.... This will create a settings file if none exists. In game.project, select which liveupdate settings file to use when bundling. This allows for using different liveupdate settings for different environments, for example for live, QA, dev etc.
Obecnie istnieją dwie metody, które Defold może wykorzystać do przechowywania zasobów. Wybierz metodę z rozwijanego menu Mode w oknie ustawień:
Amazon
Zip
Pełnomocnik kolekcji (collection proxy), które zostały wykluczone z kompilacji, działają jak zwykłe proksy kolekcji, z jedną ważną różnicą. Wysłanie im komunikatu load
, podczas gdy wciąż mają zasoby, które nie są dostępne w składzie pakietu, spowoduje ich niepowodzenie.
Dlatego zanim wyślemy komunikat load
, musimy sprawdzić, czy brakuje jakichkolwiek zasobów. Jeśli tak, musimy je pobrać, a następnie przechować. Poniższy, przykładowy kod zakłada, że zasoby są przechowywane w Amazon S3, w kubełku o nazwie "my-game-bucket"
z prefiksem my-resources
.
function init(self)
self.resources_pending = 0 -- <1>
msg.post("#", "attempt_load_resources")
end
-- This function is called whenever we have tried to store a downloaded resource
-- necessary for our collection proxy to load.
local function resource_store_response(self, hexdigest, status)
if status == true then
-- Successfully loaded resource
print("Resource data stored: " .. hexdigest)
-- One less resource to go...
self.resources_pending = self.resources_pending - 1
-- That was all of them, time to load the proxied collection.
if self.resources_pending == 0 then
msg.post("#proxy", "load") -- <8>
end
else
-- ERROR! Failed to store the data!
print("Failed to store resource data: " .. hexdigest)
end
end
function on_message(self, message_id, message, sender)
if message_id == hash("attempt_load_resources") then
local missing_resources = collectionproxy.missing_resources("#proxy") -- <2>
-- initiate a download request for each of the missing resources that has not yet been tried.
for _,resource_hash in ipairs(missing_resources) do
msg.post("#", "attempt_download", { resource_hash = resource_hash})
end
self.resources_pending = #missing_resources -- <3>
-- if we're running from editor all resources are there from the start.
if self.resources_pending == 0 then
msg.post("#proxy", "load")
end
elseif message_id == hash("attempt_download") then
local manifest = resource.get_current_manifest() -- <4>
local base_url = "https://my-game-bucket.s3.amazonaws.com/my-resources/" -- <5>
http.request(base_url .. message.resource_hash, "GET", function(self, id, response)
if response.status == 200 or response.status == 304 then -- <6>
-- We got the response ok.
print("storing " .. message.resource_hash)
resource.store_resource(manifest, response.response, message.resource_hash, resource_store_response) -- <7>
else
-- ERROR! Failed to download resource!
print("Failed to download resource: " .. message.resource_hash)
end
end)
elseif message_id == hash("proxy_loaded") then
msg.post(sender, "init")
msg.post(sender, "enable")
end
end
http.request()
."load"
do kolekcji proxy. Należy zauważyć, że jeśli pobieranie lub przechowywanie zawiedzie w którymś momencie, licznik nigdy nie osiągnie zera.Z kodem ładowania możemy przetestować aplikację. Jednak uruchamianie jej z edytora nie spowoduje pobierania niczego. Dzieje się tak, ponieważ funkcja Live update to funkcja paczki. W środowisku edytora nie wyklucza się żadnych zasobów. Aby upewnić się, że wszystko działa prawidłowo, trzeba utworzyć paczkę (bundle).
Pakowanie (bundle) z funkcją aktualizacji na żywo jest proste. Wybierz Project ▸ Bundle ▸ ..., a następnie platformę, dla której chcesz utworzyć pakiet aplikacji. Otwiera to okno dialogowe do pakowania:
Podczas pakowania wszelkie wykluczone zasoby zostaną pominięte w pakiecie aplikacji. Zaznaczając pole wyboru Publish Live update content (Opublikuj zawartość aktualizacji na żywo), informujesz Defolda, żeby albo przesyłał wykluczone zasoby na Amazon, albo tworzył archiwum Zip, w zależności od tego, jak skonfigurowałeś ustawienia aktualizacji na żywo (patrz wyżej). Plik manifestu dla paczki zostanie również uwzględniony w wykluczonych zasobach.
Kliknij Package i wybierz lokalizację pakietu aplikacji. Teraz możesz uruchomić aplikację i sprawdzić, czy wszystko działa zgodnie z oczekiwaniami.
Manifest to wewnętrzna struktura danych zawierająca listę wszystkich zasobów zawartych w buildzie oraz wartość skrótu każdego zasobu. Funkcjonalność Live update wykorzystuje manifest do śledzenia, co jest częścią zbudowanej gry, co można załadować z zewnętrznych źródeł i, jeśli tak się stanie, sprawdzenie, czy załadowane dane są nietknięte.
Z perspektywy użytkownika manifest to liczbowy uchwyt, ukrywający detale, jak jest zarządzany, w silniku.
Z funkcją aktualizacji na żywo nowy manifest można przechowywać lokalnie w trakcie działania programu. Manifest lokalny zostanie użyty podczas uruchamiania aplikacji zamiast tego, który jest dołączony w pakiecie aplikacji. Jest to przydatne do modyfikowania lub dodawania zasobów aktualizacji na żywo do opublikowanej gry, które nie były znane podczas budowy, bez konieczności publikowania pełnej wersji.
Podczas publikowania zasobów aktualizacji na żywo na Amazon Web Service lub do archiwum ZIP, manifest będzie uwzględniony w pakiecie obok zasobów. Nazwa pliku manifestu to liveupdate.game.dmanifest
.
Rozpoczęcie pracy z silnikiem Defold po raz pierwszy po przechowywaniu manifestu spowoduje utworzenie pliku identyfikatora paczki bundle.ver
obok manifestu. Służy to do wykrywania, czy paczka uległa zmianie od czasu przechowywania manifestu, na przykład po pełnej aktualizacji sklepu z aplikacjami. Jeśli tak się stanie, przechowany manifest zostanie usunięty z systemu plików, a nowszy manifest z paczki zastąpi go. Oznacza to, że pełna aktualizacja sklepu z aplikacjami usunie wcześniej przechowywany manifest. Wszystkie istniejące zasoby aktualizacji na żywo pozostaną jednak nietknięte.
Podczas przechowywania nowego manifestu jego dane zostaną zweryfikowane, zanim zostaną faktycznie zapisane na dysku. Weryfikacja składa się z kilku sprawdzeń:
Z perspektywy użytkownika proces weryfikacji jest zupełnie niewidoczny, ale ważne jest zrozumienie kroków, które są zaangażowane, aby uniknąć najczęstszych problemów.
Jeśli widzisz błąd "ERROR:RESOURCE: Byte mismatch in decrypted manifest signature. Different keys used for signing?"
w konsoli w trakcie budowania gry na HTML5, to prawdopodobnie oznacza, że Twój serwer WWW nie serwuje wykluczonych zasobów, ani zaktualizowanego pliku manifestu z właściwym typem MIME. Upewnij się, że typ MIME to application/octet-stream
. Możesz dodać plik .htaccess
z pojedynczą linią AddType application/octet-stream .
do folderu, z którego pobierane są zasoby aktualizacji na żywo.
Manifest zawsze będzie obsługiwać wersję Defolda używaną do jego generowania. Jeśli chcesz obsługiwać dodatkowe wersje silnika, dodaj je do listy w ustawieniach aktualizacji na żywo. Jest to przydatne, jeśli Twoja gra na żywo używa innej wersji Defolda niż ta, którą używasz do generowania manifestu.
Sygnatura manifestu służy do weryfikowania, że nikt ze złymi zamiarami nie będzie mógł grzebać w jego treści, i że załączony manifest i nowy manifest były podpisane tymi samymi kluczami. Podpisanie jest wykonywane w procesie budowania paczki (bundlowania).
Do kryptograficznego podpisywania manifestu używa się pary kluczy publicznych/prywatnych. Podpisanie jest realizowane przy użyciu kluczy RSA o długości 512/1024/2048 bitów w formacie .der
, które użytkownik musi dostarczyć. Możesz wygenerować je przykładowo za pomocą narzędzia openssl
:
$ openssl genrsa -out private_raw.key 1024
$ openssl pkcs8 -topk8 -inform pem -in private_raw.key -outform der -nocrypt -out private.der
$ openssl rsa -in private_raw.key -outform DER -RSAPublicKey_out -pubout -out public.der
To spowoduje wygenerowanie plików private_raw.key
(można go bezpiecznie usunąć), private.der
i public.der
. Aby użyć kluczy do podpisywania, otwórz widok ustawień aktualizacji na żywo (live update settings) i wskaz odpowiednie pola na wygenerowane klucze.
Dodając do powyższego przykładu skryptu, dodajmy poniższą funkcję zwrotną:
local function store_manifest_cb(self, status)
if status == resource.LIVEUPDATE_OK then
print("Successfully stored manifest!")
else
print("Failed to store manifest, status: ", status)
end
end
i następujący kod do funkcji on_message
, aby obsłużyć wiadomość attempt_download_manifest
:
...
elseif message_id == hash("attempt_download_manifest") then
local base_url = "https://my-game-bucket.s3.amazonaws.com/my-resources/" -- <1>
http.request(base_url .. MANIFEST_FILENAME, "GET", function(self, id, response)
if response.status == 200 or response.status == 304 then
-- We got the response ok.
print("verifying and storing manifest " .. MANIFEST_FILENAME)
resource.store_manifest(response.response, store_manifest_cb) -- <2>
else
-- ERROR! Failed to download manifest!
print("Failed to download manifest: " .. MANIFEST_FILENAME)
end
end)
end
http.request()
.resource.store_manifest
przyjmuje dane manifestu do pobrania i funkcję zwrotną jako argumenty. Funkcja zwrotna zweryfikuje manifest i zapisze go w pamięci lokalnej.Jeśli resource.store_manifest
zakończy się powodzeniem, nowy manifest będzie teraz w pamięci lokalnej. Następnym razem, gdy silnik zostanie uruchomiony, używany będzie ten nowy manifest zamiast tego, który był dołączony do gry.
Istnieją pewne rzeczy, o których warto wiedzieć, jeśli planujesz użyć tej funkcji do przechowywania nowego manifestu z aktualizacją na żywo.
Możliwe jest tylko dodawanie lub modyfikowanie zasobów używanych przez kolekcje proxy oznaczone jako Exclude
w nowym manifeście. Nie można dokonywać zmian w już dodanych zasobach lub zasobach, które nie znajdują się w wykluczonych pełnomocnikach kolekcji. Na przykład, wprowadzenie zmian w skrypcie używanym przez dołączoną kolekcję spowoduje, że system zasobów będzie szukał tego zasobu w archiwum danych paczki. Jednak ponieważ paczka gry nie zmieniła się (zmienił się tylko manifest), zmienionego skryptu nie można odnaleźć i w konsekwencji nie można go załadować.
Nawet jeśli funkcjonalność ta pozwala na bardzo szybkie wprowadzanie zmian lub łatanie błędów bez pełnego, nowego release aplikacji w sklepie, live update należy używać z zachowaniem szczególnej ostrożności. Dołączenie nowego manifestu powinno poprzedzać wszystko, co jest potrzebne przy faktycznym wydaniu nowej wersji gry (testowanie, QA, itd.).
Aby korzystać z funkcji Defold Live Update razem z usługami Amazon, potrzebujesz konta Amazon Web Services. Jeśli jeszcze nie masz konta, możesz je utworzyć tutaj.
W tej sekcji wyjaśnimy, jak utworzyć nowego użytkownika z ograniczonym dostępem w usługach Amazon Web Services, który może być wykorzystywany razem z edytorem Defold do automatycznego przesyłania zasobów aktualizacji na żywo podczas pakowania gry oraz jak skonfigurować Amazon S3, aby umożliwić klientom gier pobieranie zasobów. Dodatkowe informacje na temat konfigurowania Amazon S3 znajdziesz w dokumentacji Amazon S3.
Utwórz bucket (kubełek) na zasoby aktualizacji na żywo
Otwórz menu Services
i wybierz S3
, które znajduje się w kategorii Storage (Amazon S3 Console). Zobaczysz swoje istniejące kubełki wraz z opcją utworzenia nowego kubełka. Choć możliwe jest użycie istniejącego kubełka, zalecamy utworzenie nowego kubełka na zasoby aktualizacji na żywo, aby łatwo ograniczyć dostęp.
Dodaj politykę kubełka (bucket policy) do swojego kubełka
Wybierz kubełek, który chcesz użyć, otwórz panel Properties i rozwiń opcje Permissions w panelu. Otwórz politykę kubełka, klikając przycisk Add bucket policy. Polityka kubełka w tym przykładzie umożliwi anonimowemu użytkownikowi pobieranie plików z kubełka, co umożliwi graczowi pobieranie zasobów aktualizacji na żywo wymaganych przez grę. Dodatkowe informacje na temat polityk kubełka znajdziesz w dokumentacji Amazon o polityce.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AddPerm",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::defold-liveupdate-example/*"
}
]
}
Dodaj konfigurację CORS do swojego kubełka (opcjonalnie)
Udostępnianie zasobów z różnych domen (Cross-Origin Resource Sharing - CORS) to mechanizm, który umożliwia witrynie pobieranie zasobu z innej domeny za pomocą JavaScript. Jeśli planujesz opublikować swoją grę jako klienta HTML5, będziesz musiał dodać konfigurację CORS do swojego kubełka.
Wybierz kubełek, który chcesz użyć, otwórz panel Properties i rozwiń opcje Permissions. Otwórz konfigurację CORS klikając przycisk Add CORS Configuration. Konfiguracja w tym przykładzie umożliwi dostęp z dowolnej witryny, określając domenę wieloznaczną, choć możliwe jest bardziej restrykcyjne ograniczenie dostępu, jeśli wiesz, na jakich domenach zamierzasz udostępnić swoją grę. Dodatkowe informacje na temat konfiguracji CORS w Amazonie znajdziesz w dokumentacji Amazono CORS.
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
</CORSRule>
</CORSConfiguration>
Utwórz politykę IAM
Otwórz menu Services i wybierz IAM, które znajduje się w kategorii Security, Identity & Compliance category (Amazon IAM Console). Wybierz Policies w menu po lewej stronie i zobaczysz swoje istniejące polityki, wraz z opcją utworzenia nowej polityki.
Kliknij przycisk Create Policy i wybierz Create Your Own Policy. Polityka w tym przykładzie umożliwi użytkownikowi wyświetlenie wszystkich kubełków, co jest wymagane tylko podczas konfigurowania projektu Defold dla aktualizacji na żywo. Będzie również umożliwiać użytkownikowi uzyskanie listy kontroli dostępu (Access Control List - ACL) i przesyłanie zasobów do konkretnej nazwy kubełka używanej do zasobów aktualizacji na żywo. Dodatkowe informacje na temat Amazon Identity and Access Management (IAM) znajdziesz w dokumentacji Amazon.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets"
],
"Resource": "arn:aws:s3:::*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetBucketAcl"
],
"Resource": "arn:aws:s3:::defold-liveupdate-example"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3:::defold-liveupdate-example/*"
}
]
}
Utwórz użytkownika do dostępu programistycznego
Otwórz menu Services i wybierz IAM, które znajduje się w kategorii Security, Identity & Compliance category (Amazon IAM Console). Wybierz Users w menu po lewej stronie i zobaczysz swoich istniejących użytkowników wraz z opcją dodania nowego użytkownika. Choć możliwe jest użycie istniejącego użytkownika, zalecamy dodanie nowego użytkownika do zasobów aktualizacji na żywo, aby łatwo ograniczyć dostęp.
Kliknij przycisk Add User, podaj nazwę użytkownika i wybierz Programmatic access jako Access type, a następnie kliknij Next: Permissions. Wybierz Attach existing policies directly i wybierz politykę, którą utworzyłeś w kroku 4.
Po zakończeniu procesu zostaniesz dostarczony z Access key ID i Secret access key.
Bardzo ważne jest, aby zachować te klucze, ponieważ nie będziesz w stanie ich odzyskać z Amazon po opuszczeniu strony.
Utwórz plik profilu poświadczeń
W tym momencie powinieneś już mieć kubełek (bucket), skonfigurowaną politykę kubełka, dodaną konfigurację CORS, utworzoną politykę użytkownika i utworzonego nowego użytkownika. Jedyną rzeczą, która pozostała, jest utworzenie pliku profilu poświadczeń, aby Defold mógł uzyskać dostęp do kubełka w twoim imieniu.
Utwórz nowy katalog ~/.aws
w folderze domowym i utwórz w nim plik o nazwie credentials
.
```bash
$ mkdir ~/.aws
$ touch ~/.aws/credentials
```
Plik `~/.aws/credentials` zawiera twoje poświadczenia dostępu do Amazon Web Services poprzez dostęp programistyczny i jest standaryzowany sposób na zarządzanie poświadczeniami AWS. Otwórz plik w edytorze tekstowym i wprowadź swoje *Access key ID* i *Secret access key* w formacie pokazanym poniżej.
```ini
[defold-liveupdate-example]
aws_access_key_id = <Access key ID>
aws_secret_access_key = <Secret access key>
```
Identyfikator określony w nawiasach kwadratowych, w tym przykładzie `_defold-liveupdate-example_`, jest taki sam jak identyfikator, który powinieneś podać podczas konfigurowania ustawień aktualizacji na żywo projektu w edytorze Defold.
![Live update settings](/manuals/images/live-update/05-liveupdate-settings.png)
Teraz gra zaczyna się z oknem konsoli, które będzie wyświetlać wszystkie instrukcje print()
:
Defold tworzy folder o nazwie hasha stworzonej paczki na urządzeniu w folderze obsługi aplikacji. Jeśli usuniesz pliki z tego folderu, aplikacja unieważni zasoby z manifestu, dzięki czemu będziesz mógł je pobrać i ponownie przechować.
Lokalizacja folderu obsługi aplikacji zależy od systemu operacyjnego. Możesz ją znaleźć, używając polecenia print(sys.get_save_file("", ""))
.
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB