Bundle error: Unknown source (Access is denied)

Path handling can be extremely time consuming.
One (ancient) known pitfall is having spaces in paths.
What if you try renaming the “dialogue controller” to “dialogue_controller”?

Good suggestion, I should have known better for sure! :sweat_smile:

I fixed the whole path (even the project folder, just in case) but alas I still get the same error:

1 Like

Are you specifying an absolute path in game.project? Can you please try a relative path, starting from the project root?

Nope, wasn’t using an absolute path. It looks like this:

image

It’s just the error that brings out the full absolute path.

Currently loading the project up on my laptop to check if it’s some kind of permissions use on my dev machine.

Skip the first /

That certainly seems to have done something! It bundles successfully now.

Opening the resulting game closes it immediately, but I am guessing that is an unrelated issue. Builds in the engine work fine.

1 Like

The console should show you something I hope if you fail to load a custom resource.

Think I’ve found the error that’s preventing the game from launching. The console shut very quickly but I managed to snag a screenshot anyway.

I have a lua module that loads in a bunch of other .lua files (exports from Tiled), which looks something like this:

require "maps.map_codes.black_tower1"

The error I get when opening the game reads:

maps/map_dictionary.lua:7: module ‘maps.map_codes.black_tower1’ not found:
no file ‘maps.map_codes.black_tower1’

I had a look at the reference for require but that’s going over my head at the moment. With the files arranged like this in the editor, requiring the files works perfectly when building in engine:

image

I don’t have a reference to the map folder anywhere in the resource list (I tried adding it to “custom resources” just now but it didn’t seem to help).

image

I have refactored this map loader module since I last attempted a bundle, but in both versions I used require and in the previous bundle things worked without issue.

Before I embark on a scary debug journey, is there anything apparent I am doing wrong here?

Ah, I think I have a fix for that coming in the next release.

2 Likes

If you launch it from a console, the console shouldn’t automatically close, allowing you to copy the output .

1 Like

So you’re requiring files that you have in custom resources? The require() function will only look for files inside the application bundle and the bundling process will only include .lua files that are required by other files that are included in the main application bundle (based on the resource tree generated from the bootstrap collection).

If you want to load and run Lua code from custom resources you need to do something like this:

-- load the lua file as a string
local s = sys.load_resource("/foo/bar.lua")

-- compile the lua code in bar.lua and run it once, storing it's result in bar
local bar = loadstring(s)()

This is not really the same as require() since bar.lua will not be loaded into package.loaded. Maybe a better solution would be to add a new loader function?

local function custom_resources_loader(s)
	-- we may need to modify s here, replacing . with /
	local s = sys.load_resource(s)
	if not s then
		return nil
	end
	return loadstring(s)()
end

table.insert(package.loaders(), custom_resources_loader)

I’m a bit pressed for time here so I can’t investigate further right now…

2 Likes

Thanks for your help @Mathias_Westerdahl and @britzl. I’m not in a rush to bundle things so I will stand by to see what the next release does. I appreciate the time taken to write the example @britzl - will definitely come in handy if I need to change things up.

2 Likes

So I have just updated to 1.2.158 and tried bundling again.

Thanks to your tip, @Mathias_Westerdahl, it’s easier for me to capture the output by opening the game using the console. This is what I get:

E:\Fates of Ort builds\20190709 Win 64 v4\x86_64-win32\Fates of Ort>FatesofOrt.exe
INFO:DLIB: Log server started on port 58911
INFO:ENGINE: Engine service started on port 8001
INFO:ENGINE: Defold Engine 1.2.158 (3d63d05)
INFO:ENGINE: Loading data from: dmanif:./game.dmanifest
INFO:ENGINE: Initialised sound device 'default'

ERROR:SCRIPT: maps/map_dictionary.lua:11: module 'maps.map_codes.h_potion_hut' not found:
        no file 'maps.map_codes.h_potion_hut'
stack traceback:
        [C]: in function 'require'
        maps/map_dictionary.lua:11: in main chunk
        [C]: in function 'require'
        game controller/game_controller.script:9: in main chunk
WARNING:RESOURCE: Unable to create resource: /game controller/game_controller.scriptc
WARNING:RESOURCE: Unable to create resource: /game controller/game_controller.goc
ERROR:GAMEOBJECT: Could not instantiate game object from prototype /game controller/game_controller.goc.
WARNING:RESOURCE: Unable to create resource: /main/main.collectionc

I export .lua files from Tiled and put them in the resource tree:
image

Data about each map is stored in a table. Each line includes a require which I use to access the data in the .lua file:

M.map_info[hash("h_potion_hut")] = {script_require = require "maps.map_codes.h_potion_hut", [other vars trimmed for readability]}

Map data is then loaded like this in a map spawner file:

local map_dictionary = require "maps.map_dictionary"
map_info = map_dictionary.map_info[hash("h_potion_hut")].script_require

Given the above setup, are we saying that I have misunderstood how requiring files works? I am trying to understand what @britzl said in his last post but I am a bit confused. I think the gist of it is that the way I have set things up means that my .lua map files aren’t being included in the bundle and that I need to write some kind of custom function (like @britzl provided) to trigger the bundling in the way I am intending it.

I’ve read the resource manual and the require reference but I am still unsure about some things, e.g. the difference between “Custom Resources” and “Bundle Resources” and why my map data won’t load when it seems my other .lua modules work fine. I’m happy to mess around with the suggestions @britzl provided but would love to understand what I’m doing a bit better.

Thanks for the help!

The require function will try to load the file using one or more loader functions. Vanilla Lua loads from a number of different paths etc. The version of Lua we provide has a single loader function that loads from the game archive. Since your Lua files aren’t inside the game archive and instead included as custom resources you need to provide a loader function that can load from custom resources, like in my example.

Read the official Lua docs for require() and package.loaders() for more info.

2 Likes

I’ve now read the PiL require and package.loaders docs and think I understand it a bit better. Your second suggestion is to add a fifth custom loader to the four default loaders.

I tweaked your function and I am currently using it like this:

local function custom_resources_loader(s)

    print("running britzl custom resource loader", s)
	local s = sys.load_resource(string.gsub(s, "%.", "/"))
	if not s then
		return nil
	end
	return loadstring(s)()
end

table.insert(package.loaders, custom_resources_loader)
  1. I had to amend the last line to remove () because it read package.loaders() and I think it was attempting to call it as a function which gave an error.
  2. I was getting an error when using . instead of / like you suspected, so I am attempting to replace . with / (needing to escape using % because . seems to be a special character).

When bundling, I get the following error:

DEBUG:SCRIPT: running britzl custom resource loader     maps.map_codes.h_potion_hut
ERROR:RESOURCE: Resource path is not absolute (maps/map_codes/h_potion_hut)
ERROR:SCRIPT: maps/map_dictionary.lua:26: module 'maps.map_codes.h_potion_hut' not found:
        no file 'maps.map_codes.h_potion_hut'
stack traceback:
        [C]: in function 'require'
        maps/map_dictionary.lua:26: in main chunk
        [C]: in function 'require'
        game controller/game_controller.script:9: in main chunk
WARNING:RESOURCE: Unable to create resource: /game controller/game_controller.scriptc
WARNING:RESOURCE: Unable to create resource: /game controller/game_controller.goc
ERROR:GAMEOBJECT: Could not instantiate game object from prototype /game controller/game_controller.goc.
WARNING:RESOURCE: Unable to create resource: /main/main.collectionc

The good news is that the custom loader function appears to be called, but unfortunately the game still does not run when bundled. I have tried anything I could think of, like adding a “/” at the beginning, but no dice. If anyone has any ideas that would be appreciated!

(edit: Adding the leading “/” does remove the line about the resource path not being absolute, but the remainder of the error message is identical.)

Is your resource in the bundle? Have you verified? (Generate a build report and search for it)

1 Like

I think so, when I open report.html I can find it like this:

That’s when I place the directory in “Custom Resources” (it doesn’t appear when it’s in “Bundle Resources”, I tested both because I don’t yet understand the difference).
image

“custom” resources are stored like the other game assets, inside the internal archive (game.darc).
“bundle” resources are store “next to” the app executable, and cannot be loaded using sys.load_resource()

2 Likes

So basically I was having the exact problem discussed here. Using sys.load_resource() and loadstring() seems to be doing the trick (completely disregarding require). Like this:

map_info = sys.load_resource(map_path)
map_info = assert(loadstring(map_info))()

map_path looks something like this:

local map_path = "/" .. string.gsub(map_dictionary.map_info[hashed_level].script_require, "%.", "/") .. ".lua"

Map dictionary:

M.map_info[hash("h_potion_hut")] = {script_require = "maps.map_codes.h_potion_hut", [other stuff]}

This was just for testing purposes so if I go down this route then I may as well drop the string replacements etc and just have the path stored as “/maps/map_codes/h_potion_hut.lua” in the map dictionary.

So, uh… I guess this just entirely sidesteps the issue? Is using sys.load_resource() and loadstring() like this going to hit me with any unintended consequences? Maybe it would take a bit longer to load but I’m not noticing anything when testing. The docs for load_resource say the contents are just loaded as a string, so since I replace the map data whenever I load, I shouldn’t be accumulating a bunch of data in memory, right?

I created an example of a few ways to load Lua code here:

1 Like