I’m having too many issues setting up liveupdate. It seems simple in theory and even the extension appears like it’s plug and play. Unfortunately for me, it’s giving me a lot of issues.
First, mounting. Should mount on start be enabled or not? Does enabling it slow down loading?
Second, what’s the best way to debug? The manual mentions that a terminal will open when opening the application - but it doesn’t. Is there any way to trigger a terminal for the application to test a build? That would help a lot.
Finally, I’m only interseted in Poki integration right now. This means I wouldn’t need hosting, I think. I’m keeping it simple for now with one zip file that has levels 2-20. Level 1 loads with the build.
I’ve excluded the collection proxies. The problem I have right now is the level 2 doesn’t load. I can’t understand why because no prints are available in a build.
My init() looks like this
local zip_url = “http://localhost:8000/levels.zip”
local zip_name = “levels.zip”
local current_level = data.get_level()
local proxy_url = “/levels#level_” .. current_level
if current_level == 1 then
msg.post(proxy_url, "load")
return
end
local missing = collectionproxy.missing_resources(proxy_url)
if #missing > 0 then
http.request(zip_url, "GET", function(self, id, response)
if response.status == 200 then
local path = sys.get_save_file("game", zip_name)
local file = io.open(path, "wb")
if file then
file:write(response.response)
file:close()
end
liveupdate.add_mount("levels", "zip:" .. path, 10, function(uri, status)
if status == liveupdate.LIVEUPDATE_OK then
msg.post(proxy_url, "load")
end
end)
end
end)
else
msg.post(proxy_url, "load")
end
It does not slow down loading in a measurable way. When you mount an archive we store the path in a file. Next time you boot we read this file and remount the archives. Mounting an archive means reading the archive index, but not the entire file.
The main reason for not automatically mounting an archive is if you’ve made a mistake and for some reason the archive contains something game breaking and you want to avoid automatically mounting it.
This is a bit misinforming. There is no bespoke “live update debug console”. The manual refers to how a debug version of the engine outputs log (ie print and engine logs) to the console, like this: Debugging - game and system logs
We should fix this part of the live update manual tbh.
Correct, with Poki you can bundle your game and then zip up your html5 bundle and the live update .zip file when uploading. The live update archive can then be loaded over http to a file and then mounted. Something like this:
local url = "./levels.zip"
local headers = nil
local post_data = nil
local options = { path = "levels.zip" } -- the local file to store archive in
http.request(url, "GET", function(self, id, response)
if response.status == 200 or response.status == 304 then
print("stored ok")
liveupdate.add_mount("levels", "zip:/levels.zip", 10, function (result) end)
else
print("error")
end
end, headers, post_data, options)
Thank you. Right now I run test on a local server. This saves time from uploading new versions constantly to Poki. Is there a major difference between the inspector and local?
Almost got it working. The first build on a fresh session loads, but refreshing the page doesn’t load the level. I think the order of operations is wrong. I’m testing it again after changing the logic.
Here is the current code.
function init(self)
self.level = nil
local current_level = data.get_level()
local proxy_url = "/levels#level_" .. current_level
if current_level == 1 then
msg.post(proxy_url, "load")
return
end
local mounts = liveupdate.get_mounts()
local levels_loaded = false
for i = 1, #mounts do
if mounts[i].name == "levels" then
levels_loaded = true
pprint(mounts)
print("levels mounted")
msg.post(proxy_url, "load")
break
end
end
if not levels_loaded then
local url = "./levels.zip"
local headers = nil
local post_data = nil
local options = { path = "levels.zip" } -- the local file to store archive in
http.request(url, "GET", function(self, id, response)
if response.status == 200 or response.status == 304 then
print("stored ok")
liveupdate.add_mount("levels", "zip:/levels.zip", 10, function (result) end)
pprint(mounts)
msg.post(proxy_url, "load")
else
print("error")
end
end, headers, post_data, options)
end
msg.post("#", "acquire_input_focus")
-- if html5 then
-- poki_sdk.commercial_break(commercial_level_completed)
-- end
end
I restructured a lot and I think I have it working as intended. I ended up using my “main” proxy as the loader for the levels. Previously, I was using main and game/menu. This created unnecessary friction because the levels were being loaded in the game proxy.
This was a frustrating experience, but I’m glad to have made progress. I’m now testing my 20 levels to see if the faster load times will improve the player experience.
My final code for checking live updates now runs in main, the collection that loads during boot.
if data.get_level() == 1 then
load_level(self)
else
load_menu(self)
end
local mounts = liveupdate.get_mounts()
for i = 1, #mounts do
if mounts[i].name == "levels" then
pprint(mounts)
print("levels already mounted")
else
local url = "./levels.zip"
local headers = nil
local post_data = nil
local options = { path = "levels.zip" } -- the local file to store archive in
if html5 then
http.request(url, "GET", function(self, id, response)
if response.status == 200 or response.status == 304 then
liveupdate.add_mount("levels", "zip:/levels.zip", 10, function (result) end)
print("new levels successfully mounted")
else
print("error with mounts")
end
end, headers, post_data, options)
end
end
end
One thing I can’t explain is that the prints aren’t printing. I thought maybe it was because they were already loaded but they still don’t print after a cleared session. I’m building a HTML5 build in debug, but still not seeing any prints in the Chrome dev console.
Something else to consider next:
Loading each level as needed, but this may be overkill. The game is already under 5mb when first loading. The additional content is maybe 25mb. Maybe I could bundle the levels as load as needed — or — only preload the next level. The game plays one-way, so once a level is completed the player won’t go back to play it again.
I’m still getting errors from some players, especially returning. This error occured 91 times in a previous test, which means 20% of the players couldn’t continue. It’s a major issue. Not sure how to fix it.
Update: I think I found the issue. It’s trying to load the levels before they are fully downloaded. I had assumed they were small enough to have a quick download, but that’s not always the case. I changed the code so the menu won’t reveal itself until the content is downloaded.
New players who start at level 1 should have the content downloaded by level 2, but returning players wil have a delay. I will have to look at how to load everything better.
I think I fixed it. I must not have been checking or loading something in the right order. Recent tests are error free and I stopped seeing players having issues with loading.
Overall, Liveupdate is a very powerful feature! I want to understand it better. I’m still questioning how mounting works.
For example, this print still shows missing resources after loading the page.
local proxy_url = "/levels#level_" .. data.get_level() + 1
pprint("missing resources - current level + 1", collectionproxy.missing_resources(proxy_url))
But I don’t understand why, because here I’m mounting the levels when the game first loads.
local mounts = liveupdate.get_mounts()
local proxy_url = "/levels#level_" .. data.get_level() + 1
pprint("missing resources - current level + 1", collectionproxy.missing_resources(proxy_url))
for i = 1, #mounts do
if mounts[i].name == "levels" then
data.levels_loaded = true
break
end
end
if not data.levels_loaded then
if html5 then
local url = "./levels.zip"
local headers = nil
local post_data = nil
local options = { path = "levels.zip" } -- the local file to store archive in
http.request(url, "GET", function(self, id, response)
if response.status == 200 or response.status == 304 then
liveupdate.add_mount("levels", "zip:/levels.zip", 10, function (result) end)
data.levels_loaded = true
print("levels mount added")
else
print("error with mounts")
end
end, headers, post_data, options)
end
end
if data.get_level() == 1 then
load_level(self)
else
load_menu(self)
end
Does it always show missing even if the resources are loaded?
An even more efficient way of loading levels would be to preload the level after the current. So if player is on level 1, get level 2 ready, and so on. And to make that even better, the levels could unload / unmount after the player completes them.
Further testing, I’m still not seeing the levels mount in the mounts print … but the levels after 1 are loading. Maybe I’m misunderstanding how mounting works.
My latest code.
local mounts = liveupdate.get_mounts()
local proxy_url = "/levels#level_" .. data.get_level() + 1
pprint("missing resources - current level + 1", collectionproxy.missing_resources(proxy_url))
pprint("current mounts", mounts)
pprint("manifest", liveupdate.get_current_manifest())
pprint("is using liveupdate data?", liveupdate.is_using_liveupdate_data())
for i = 1, #mounts do
if mounts[i].name == "levels" then
data.levels_loaded = true
break
end
end
if not data.levels_loaded then
if html5 then
local url = "./levels.zip"
local headers = nil
local post_data = nil
local options = { path = "levels.zip" } -- the local file to store archive in
-- if html5 then
http.request(url, "GET", function(self, id, response)
if response.status == 200 or response.status == 304 then
liveupdate.add_mount("levels", "zip:/levels.zip", 10, function (result) end)
data.levels_loaded = true
mounts = liveupdate.get_mounts()
pprint("levels mount added", mounts)
pprint("missing resources check? current level + 1", collectionproxy.missing_resources(proxy_url))
else
print("error with mounts")
end
end, headers, post_data, options)
end
-- end
end
That’s what the "mount on start " is about. But we recommend not having it mount automatically on start, as then it may cause trouble for you if it’s an old data format, and you use a new engine.
We recommend that you each session download the zip archive (the http.request() will cache the result, so if it’s not changed on the server, you’ll get a quick response), then mount the .zip file.
Hmm, so this is only for if mounts are enabled on start?
But if not enabled and using an http request, the process of adding/removing is handled already?
If so, I think I can understand it better now. I also shouldn’t be using “liveupdate.get_mounts()” then during boot to check if the player hasn’t added the mount yet. There’s likely a better way.
data.levels_loaded = false -- flag to check if levels have been loaded, updates gui on success
if html5 then
local url = "./levels.zip"
local headers = nil
local post_data = nil
local options = { path = "levels.zip" } -- the local file to store archive in
-- if html5 then
http.request(url, "GET", function(self, id, response)
if response.status == 200 or response.status == 304 then
pprint("response", response)
liveupdate.add_mount("levels", "zip:/levels.zip", 10, function (result)
pprint("result: ", result)
data.levels_loaded = true
end)
else
print("error with mounts")
end
end, headers, post_data, options)
pprint(headers, post_data, options)
end
if data.get_level() == 1 then
load_level(self)
else
load_menu(self)
end
The flag in data is set during boot and checked in the gui. The player cannot continue to the later levels until they’re loaded.
Here it talks about how mounts are added and removed. It seems like a mount is added if the resources for it don’t exist, then removed after the resources are downloaded. Is that correct?
If so, I don’t understand when get_mounts() would be used. I don’t see the mounts at all when my game loads, but the resources (level collection data) is there. Those load okay.
Mounting is a manual operation (unless you have the automount enable, which we don’t recommend).
I don’t understand when get_mounts() would be used.
It is to inspect the current mounts. For a small game it’s easy to keep track of, but for a complex game with lots of mounts, it’s good to have it, in order to see the actual state.