The new version of Defold 1.5.0 has expanded the liveupdate functionality.
I had some questions when adding mounts. Perhaps this example will help you avoid some mistakes.
Steps:
- Check if our archive is mounted. If the archive is mounted, then your data can already be used.
- Download archive. There may be problems when downloading a file if the speed is low or the connection is poor. For example, during tests, I sometimes received a response with status 0. (I don’t know why exactly 0). In order to fix this, you need to add several download attempts.
- Save archive to the IndexedDB. io.write() will help us with this.
When creating a file, you must specify the path. The path must have a string at the beginning of/data/
. For example/data/external_res.zip
. Otherwise there will be errors.
In the example I use the function sys.get_save_file(“my_key”, “external_res.zip”). This function will generate the correct name. It looks like:/data/.my_key/external_res.zip
- Add mount. In the uri parameter you need to specify your path described above and add
zip:
at the beginning. It looks like:zip:/data/.my_key/external_res.zip
. - Your data is ready. You can download a proxy.
When the files are deleted from the cache, the added mounts themselves will be deleted.
However, now you need to monitor the changed external files yourself. Once a mount is created, it will always take data from the cache. If you leave the same name for the archive and change the data, the mount will use the old data. You need to change the name and add a new mount. Or you can remove the old mount and reload the data. Now it’s up to you to choose.
Example:
local external_data = {
name = "external_res.zip", ---Name for zip archive
proxy = msg.url("example:/example#collectionproxy"), ---Excluded proxy
path = "./" ---Here we indicate the path to the file. I set root folder
}
---Check if the data already mounted
---@param archive_name string
---@return boolean
local function is_in_mount(archive_name)
local mounts = liveupdate.get_mounts()
for key, mount in pairs(mounts) do
if archive_name == mount.name then
return true
end
end
return false
end
---Start proxy loading
---@param proxy url
local function load_proxy(proxy)
msg.post(proxy, "async_load")
end
---Handle error
---@param data external_data
---@param error string
local function on_error(data, error)
pprint("Error", error)
---TODO: handle error
end
---Save file and mount data
---@param data external_data
---@param response string
---@param priority number
local function on_file_received(data, response, priority)
local new_path = sys.get_save_file("my_key", data.name)
---Create a file object to work with IndexedDB
local file, err = io.open(new_path, "w+")
if err then
on_error(data, err)
return
end
---Write our received data to IndexedDB
local f, err = file:write(response)
if err then
on_error(data, err)
return
end
---Close connection
file:close()
---Add new mount
liveupdate.add_mount(data.name, "zip:" .. new_path, priority, function(self, name, uri, priority)
---Our data loaded. Now we can load proxy.
load_proxy(data.proxy)
end)
end
local ATTEMPT_COUNT = 50
---We make requests for data until we receive it
---@param data external_data
---@param index number
---@param attempt number|nil
local function request_data(data, index, attempt)
attempt = attempt or 1
http.request(data.path .. data.name, "GET", function(self, id, response)
if (response.status == 200 or response.status == 304) and response.error == nil and response.response ~= nil then
on_file_received(data, response.response, index)
elseif attempt <= ATTEMPT_COUNT then
---If unsuccessful, I make several attempts to load the data.
attempt = attempt + 1
request_data(data, index, attempt)
else
on_error(data, response.error)
end
end)
end
---Start our loading
---@param self userdata
function init(self)
---I check that it is a web and check the created mounts
if not html5 or is_in_mount(external_data.name) then
---Data already loaded
load_proxy(external_data.proxy)
else
request_data(external_data, 1)
end
end
local PROXY_LOADED = hash("proxy_loaded")
---Handle proxy message
---@param self userdata
---@param message_id hash
---@param message any
---@param sender url
function on_message(self, message_id, message, sender)
if message_id == PROXY_LOADED then
if external_data.proxy == sender then
msg.post(sender, "init")
msg.post(sender, "enable")
pprint("Success! Proxy loaded!")
end
end
end