godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Allow to import and load external assets at run-time (in exported projects, without extra PCK files) #1632

Open Xrayez opened 4 years ago

Xrayez commented 4 years ago

Describe the project you are working on:

A game with user-generated content (and less of a modding support). Mostly related to godotengine/godot#17848. Also Goost - Godot Engine extension, where some stuff gets exposed in non-editor builds.

Describe the problem or limitation you are having in your project:

See very useful discussion which illustrates the problem at godotengine/godot#17748.

Godot requires that most files must be first imported into a project (converted from various file formats to Resources, such as *.png to Texture) before they can be used in a game, and this works well for games which don't require dynamic loading of assets.

The export process involves packing all of the previously imported assets into a special *.pck file which is then unpacked upon running a particular game.

The problem comes when you want to give a player an ability to load external assets which are not part of the original game, without creating additional tools to make *.pck files to be used by a player, because players are not developers, and there has to be an intuitive way to load external assets within a game itself. See also limitations at #1212.

Loading imported resources requires you to use load() or ResourceLoader.load(). Loading non-imported, external resources require you to replicate the import process at run-time first (which is already done in the editor), and then store a reference to the loaded resource somewhere for it to be accessed later, so it's not possible to use load() for those resources, because they were not actually imported, but created at run-time instead.

This in turn leads to various confusions and misuse like with Image.load() and ResourceLoader.load().

See also related issues and other proposals:

Marginally related:

Describe the feature / enhancement and how it helps to overcome the problem or limitation:

I suggest to add a way to seamlessly load() external resources by first importing them if they are outside of the res:// path, like user:// or any other system path.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:

The crude logic is the following:

Alternatively, perhaps ResourceImporter and corresponding import() GDScript method could be added (or exposed), to allow users to import external resources at run-time first, if this proves to be easier to implement and/or maintain.

I understand that a lot of importers are tied to the editor, so this likely needs a rewrite/refactor, or adding a build option to allow those importers to be available in release builds, at the very least.

If this enhancement will not be used often, can it be worked around with a few lines of script?:

Currently, you have to use File and various load(), load_from_file(), load_from_buffer() exposed methods scattered in various classes like Image, AudioStreamSample to replicate the import process to some degree (difficult to account for various peculiarities inherent to parsing files), so none of those existing methods provide a way to import those resources exactly like in the editor.

Is there a reason why this should be core and not an add-on in the asset library?:

I believe one has to rewrite/adapt the ResourceLoader and the import mechanism for this to work, which is pretty core.

I believe implementing this proposal could solve a lot of reported issues, and even some specific loading functions could be unexposed that way.

amoriqbal commented 4 years ago

Is anyone working on this already?

Calinou commented 4 years ago

@amoriqbal As far as I know, nobody is currently working on implementing this.

Keep in mind exposing import functionality in export templates will likely increase their size noticeably, which can be problematic for mobile/web platforms.

drwhut commented 4 years ago

For those interested, since it seems that this FP has been declined for good, I've made a C++ module that allows for importing resources at runtime via GDScript for my game, which can be found here. Feel free to use the code in tabletop_importer.cpp as inspiration.

It's worth noting that the C++ module alone won't work in a build with tools=no, since the importing code is in the editor. This is where I also made a custom fork of Godot which essentially just has the above module, as well as macros to make sure that the engine compiles with tools=no with the importing code, without any of the other editor code (so the final executable isn't massive).

Xrayez commented 4 years ago

@drwhut I've looked up the module you linked and even tested it out, also added to a list of community Godot modules in goostengine/godot-modules#4 which can be compiled for testing purposes (build artifacts for editor are also uploaded), thanks. ๐Ÿ™‚

Looking at the source, this demonstrates the issue with having to add dedicated importers and expose corresponding methods for each recognized resource type.

That said, the way I see it, a GDScript import() method would be good to add, but I still think that it should be possible to use the ResourceLoader to do this under the hood with load(), we don't really want to pollute the global scope: #1590, and this could just be narrowed down to implementation details which could be disabled at compile-time without even exposing any other additional APIs for this.

It's worth noting that the C++ module alone won't work in a build with tools=no, since the importing code is in the editor. This is where I also made a custom fork of Godot which essentially just has the above module, as well as macros to make sure that the engine compiles with tools=no with the importing code, without any of the other editor code (so the final executable isn't massive).

Yes, so I guess the most feasible way to implement this proposal is through adding build options, like scons use_importers=yes. As Calinou said, I'm afraid Godot won't allow to bloat its binary size for mobile and web. But I think that usually, those platforms don't even need run-time import capabilities anyways.

Considering the fact that this is not what every game will need, nonetheless it's impossible to make this work with GDScript nor GDNative, since we need low-level access to resource importer API which is only accessible via modules, and also requires some core modifications.

it seems that this FP has been declined for good

That doesn't seem to be optimistic! With enough of support, I hope anything is possible. ๐Ÿ˜…

I mean, see the number of feature requests and issues I linked in the proposal.

Otherwise, yeah perhaps Godot is not the right tool for this, but it seems like a low-hanging fruit to implement, it's just a matter of finding a way to expose existing functionality in the engine to make this work in a general-purpose way.

Perhaps I'd work on this myself given approval of core developers, else maybe this can be implemented in a fork/extension. ๐Ÿ˜›

drwhut commented 4 years ago

Looking at the source, this demonstrates the issue with having to add dedicated importers and expose corresponding methods for each recognized resource type.

This is one of the challenges with implementing this feature - you need to instance the importer singletons if they haven't been instanced already (e.g. in a release build). In some cases, I've noticed there are also different importers for the same resource. For example, the .obj resource has one importer which creates an array mesh, and another that creates a mesh instance similar to other scene importers.

It's worth noting that the C++ module alone won't work in a build with tools=no, since the importing code is in the editor. This is where I also made a custom fork of Godot which essentially just has the above module, as well as macros to make sure that the engine compiles with tools=no with the importing code, without any of the other editor code (so the final executable isn't massive).

Yes, so I guess the most feasible way to implement this proposal is through adding build options, like scons use_importers=yes. As Calinou said, I'm afraid Godot won't allow to bloat its binary size for mobile and web. But I think that usually, those platforms don't even need run-time import capabilities anyways.

That's probably the best way to go about it, and based on what I had to do to get it working for release builds, this shouldn't be too difficult to do if you know your way around SCons.

it seems that this FP has been declined for good

That doesn't seem to be optimistic! With enough of support, I hope anything is possible. sweat_smile

I mean, see the number of feature requests and issues I linked in the proposal.

Otherwise, yeah perhaps Godot is not the right tool for this, but it seems like a low-hanging fruit to implement, it's just a matter of finding a way to expose existing functionality in the engine to make this work in a general-purpose way.

Haha, while I do agree that this would be a very handy feature to have (as you said, the functionality is already there, it's just exposing it to GDScript), I'm hesitant to say that this would be useful to a majority of developers. For most developers, this functionality is already implemented statically with .pck files. That's just my opinion though. It's really up to the developers to see whether this is worth implementing.

Xrayez commented 4 years ago

This is one of the challenges with implementing this feature - you need to instance the importer singletons if they haven't been instanced already (e.g. in a release build).

Possibly have to refactor this logic into a dedicated register_import_types(), currently all importers initialization is hardcoded in EditorNode constructor, looking at the source.

For instance, the existing ResourceImporterWAV would be useful for #732.

I've noticed there are also different importers for the same resource.

Yeah, when we talk about importing images for example, then there are numerous ways to import as Image, Texture, BitMap if you go into the Import tab. I think it would be just a matter of providing an additional parameter, like import(Dictionary options) or something along those lines.

Haha, while I do agree that this would be a very handy feature to have (as you said, the functionality is already there, it's just exposing it to GDScript), I'm hesitant to say that this would be useful to a majority of developers. For most developers, this functionality is already implemented statically with .pck files.

I dunno, I think this is where the engine could really shine and has a good potential, it's just that none of the existing core developers really dig into the UGC/modding capabilities with Godot currently, that's all. It's a matter of creating enough demand and awareness.

Xrayez commented 4 years ago

Also, regarding increased binary sizes, I think it's not that much code which needs to be exposed out of the box currently, I speculate that it would only add up like 3MB to export templates. In any case, depending on my motivation, I'll see whether that's actually the case, but it should be quite possible for Godot to provide such customization level at build-time, at least, so the actual custom non-editor resource importing feature can be implemented outside of Godot more easily without having to patch the source for that.

akien-mga commented 4 years ago

I support this proposal, though we need to get @reduz onboard with this as he designed the import system (and thereby its limitations).

For a concrete example of use case, have a look at https://github.com/Gianclgar/GDScriptAudioImport This is a GDScript script that can load WAV and OGG files at runtime, and thus needs to replicate the logic that the importer would do in the editor.

For OGG it's "simple enough", like the hacks that users currently have to do to load PNGs at runtime: https://github.com/Gianclgar/GDScriptAudioImport/blob/master/GDScriptAudioImport.gd#L114-L118

But for WAV it requires a full reimplementation of the header parsing already done in the engine: https://github.com/Gianclgar/GDScriptAudioImport/blob/56c8d70f8aa4da3ee0d498497c61e583208a515b/GDScriptAudioImport.gd#L42-L111

Here's a quick Music Player that I made to help https://store.steampowered.com/app/1369320/Virtual_Cottage/ developers to include runtime loading of user-provided music tracks: Music Player.zip

I only handled OGG as it's easy enough from parsing the file as raw data, but for WAV I'd have to do the same as https://github.com/Gianclgar/GDScriptAudioImport

IMO that's a use case that we need to support out of the box, so importers should be available at runtime - at least for the most common data formats like PNG, JPG, OGG, WAV, and possibly MP3 if #85 is implemented. This may not be possible/relevant for formats like glTF or Collada, which are full scene formats.

Xrayez commented 4 years ago

This would also be useful for #1362, as import functionality doesn't have to be tied to editor instance:

So better idea is to add new flag e.g. --import-only which would import files and after that just close Godot. It would be great if the editor wasn't even running.

akien-mga commented 4 years ago

For the reference, we discussed this a few days ago with @reduz and @Calinou, see logs here: https://freenode.logbot.info/godotengine-devel/20201020#c5530593-c5531175

A key distinction made during this chat is between import (which should stay an editor-specific process) and loading resources (which should be made as easy as possible at runtime). So we wouldn't add ways to import resources and use the imported versions with ResourceLoader at runtime, but there should be APIs for any relevant resource type to load them at runtime (as is already possible - by jumping through a few hoops - for images and sounds).

For more complex resources, @reduz suggests adding a feature to be able to export an imported resource (i.e. while in the editor) to a single file (bundling all dependencies) that could be loaded at runtime. This needs its own proposal for further discussion though.

Xrayez commented 4 years ago

Yeah, as I said, @reduz likely doesn't dig into UGC with Godot ๐Ÿ˜•.

Quoting you, @akien-mga:

Akien: reduz: that only helps for the use case where you (the dev) have the resource beforehand. The main use case that motivates the above proposal is loading user-provided content, like letting users load their own music or pictures


For more complex resources, @reduz suggests adding a feature to be able to export an imported resource (i.e. while in the editor) to a single file (bundling all dependencies) that could be loaded at runtime. This needs its own proposal for further discussion though.

Yeah, not useful for this proposal at all, and certainly not useful for me. ๐Ÿ˜„

The idea is that you should just be able to import a new resource with import(path). This will store the imported resource at user:// directory (such resources won't be packed), which then can be loaded normally with load(path). This would solve the collision mentioned by @reduz, so really this could be implemented as a parallel system to ResourceLoader.

The module provided by @drwhut in https://github.com/drwhut/open_tabletop_godot_module does something similar, but it's not general-purpose enough, because importers have to be instantiated manually for this, and of course required some core modifications to build scripts.

That said, for now this is modules territory, it seems. But I'm not sure what minimal core functionality is required to facilitate implementing this proposal via modules yet. For now, I'm limited to Image.load().

Xrayez commented 4 years ago

At the very least, my recommendation/suggestion to developers is that common resources like images and audio should have loaders implemented in classes, and the import process can just reuse those loading methods just like with the current Image.load().

The reason why Image.load() exists in the first place is because there are different kinds of loaders for each image format registered in the engine, and that's handled by ImageLoader internally, so I think we've just got lucky enough such a thing exists and exposed to scripting currently. ๐Ÿ˜ƒ

fire commented 4 years ago

According to my reading of the logs, Reduz has rejected runtime import and export code.

Since this is the case, and I want to use my glTF module to runtime load glb files. I'm not sure what to do.

I'm presuming that gltf2 export and import at runtime will be rejected.

Since this is my requirement. Here are some workarounds:

  1. Use an external Godot Engine module.
  2. Create a custom out of core module that wraps all the loaders for Godot Engine and exposes it as a runtime loader.
  3. Create a custom out of core module that wraps my import and export it as a runtime saver.
  4. Not wanting to argue over this. So ResourceRuntimeLoader and ResourceRuntimeSaver will be designed to Godot Engine core requirements and posted at godot-extended-libraries.

API:

    Ref<EditorSceneImporterFBX> import_fbx;
    import_fbx.instance();
    ResourceRuntimeImporterScene::get_singleton()->add_runtime_importer(import_fbx);

    image_loader_svg = memnew(ImageLoaderSVG);
    ImageRuntimeLoader::add_image_runtime_format_loader(image_loader_svg);

    resource_format_saver_crypto.instance();
    ResourceRuntimeSaver::add_resource_runtime_format_saver(resource_format_saver_crypto);

    ResourceRuntimeSaver::save(path, resource, flags)
    ResourceRuntimeLoader::load(path, original_path, type_hint, no_cache, error);

May be converted to use any system that can compile c++ code to intermediary binary code to executed at runtime on any architecture.

Edited:

A loader for TSCN, TRES, STEX is not an acceptable route.

Shadowblitz16 commented 4 years ago

So what I want to see is the ability to mark resources to be exported as certain file types... textures - png, bmp, gif, tiff, jpeg models - gltf, obj other things - json, ini, cfg

Then when the editor versions of the resources are created in code they automatedly populate themselves and are ready to be used.

An ideal use for this would have a game json which contains all your object's json files which contains paths to images, models, scripts and other nested json files

willnationsdev commented 3 years ago

Looking at this, it seems like it would be a good use case for #2063 since the whole idea is to make it possible outside the editor, but also conditionally remove it from mobile/web games that might not want the bloat.

BastiaanOlij commented 3 years ago

Just to add another use case to this proposal.

When dealing with systems like OpenVR and OpenXR we often obtain assets from these systems for things like controller meshes, headsets and various trackers. As the assets in question are dependent on the hardware in use by the player and this hardware may not even have existed when the game was created having the VR system provide these assets is of utmost importance to immersion of the player.

If importing new assets is only possible during development and not during runtime we have a gap in functionality. OpenXR for instance will provide fully articulated assets for controllers as a GLTF resource (GLB). Important here as well is that these assets are provided in binary form in memory and not in file form. See: https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XR_MSFT_controller_model

The ideal setup I see is that the import logic itself becomes part of the normal runtime and only has saving the converted resources in .import and the subsequent exporting logic be part of the editor code. This would simply be an extra check to see if a converted resource already exists when loading, and saving the converted resource after the import is run when used in editor while the core import process is shared between runtime and editor versions.

When loading asset source files in runtime this will incur a performance penalty as all the conversions need to be performed but when assets are imported during development optimized formats can be used. Best of both worlds solution while removing the need to duplicate code.

CsloudX commented 3 years ago

For me, I really wish can import audio file at runtime, other game engines like UE and Unity all can do this. If I can load mp3 at runtime, I can create my MusicApp, I like. BTW, Now almost image formats can load at runtime, PERFECT!

DanielJoyce commented 3 years ago

I'd love to use godot to make desktop apps, it's pretty killer already, but the really inflexible import system kinda breaks that.

Couldn't the importer code be compiled 'twice', once for use in the editor, linked in, and then also broken out as modules, which could be used by games/apps if they so choose? They could be scoped differently in GD script as well.

chottokite commented 3 years ago

I think the core of the problem that the author of this proposal exposes here is already solvable by current Godot. I am working on a similar project that wants to make possible for users/players to make their own user-generated-content for my game. and I have an idea on how to tackle it, though I haven't reached that point yet. There is ProjectSettings.load_resource_pack that allows loading additional and arbitrary resources. Users/Players can use the standard editor and a project template provided by the developer to create their own resource packs that may be loaded at runtime by the game. There are, however, some issues with this path:

  1. Godot won't expose the contents of the user-generated-content pack in the res:// virtual filesystem. The functionality isn't there. [0] While it can access any resource in it, it won't be listed by the Directory class. There seems to be a solution for that, however: [1].
  2. Discoverability is difficult because of 1.. A possible solution is to have a resource list file in the root of the pack to help the game discover the game content. However, this is tricky to do because of the next point.
  3. Every single file/resource is put into the same namespace. This means, user-generated-content not only may conflict with the game data, it also means that every additional resource path must be unique. Thus the user must choose a folder name to hold their resources in and ensure it won't conflict with user-generated-content made by other people. This makes discoverability of user content tricky for the game. A possible solution is to have the user pack content be inside a folder named the same as the pack filename. For example, there is UserPack1.pck and UserPack2.pck in the game folder. Each of these packs must have their resources inside UserPack1/ and UserPack2/ folders.
  4. Use of game core scripts by user resources is tricky. To avoid having users attach scripts to resources and nodes, I have added custom modules with new types for users to build their packs with. By the way, how do C# scripts work in additional resource packs? This is still an unknown to me.
  5. Use of game core resources (like materials, shaders, control templates, etc.) is tricky. To fix this for materials at least, I have made proxy classes that store the path to the real resource and load it at runtime.

Is it desirable to solve some of these issues in core Godot? It'd be nice to have discoverable res:// content at runtime in the exported game. Or, instead, optionally have loaded resource packs have their own namespace.

By the way, I don't think editor functionality should be exposed to Godot projects. Not only it's likely it won't be a perfect match for every or most games, it may also shackle the engine to provide the current API and behavior indefinitely and leave much less room to innovate. Interested parties should make an external module that exposes similar editor features for games.

[0] https://github.com/godotengine/godot/issues/7845 [1] https://godotengine.org/asset-library/asset/96

fire commented 3 years ago

@lyuma was able to port my gltf module to gdnative in 3.x. He can comment on that design.

Xrayez commented 3 years ago

Users/Players can use the standard editor and a project template provided by the developer to create their own resource packs that may be loaded at runtime by the game.

The core idea behind this proposal is that users don't need to be programmers/modders to learn and use developer-provided tools, so this is not an option for me personally. In fact, users might not even be interested to create the content themselves: it may be just an arbitrary image they have from which level geometry could be created, or a song from which a gameplay may be procedurally generated backed up by the mood of the song, etc.

2. Discoverability is difficult because of 1.. A possible solution is to have a resource list file in the root of the pack to help the game discover the game content. However, this is tricky to do because of the next point.

Yep, it's a separate problem which I hope could be solved in a straightforward way, see another proposal of mine: #1212.

3. Every single file/resource is put into the same namespace. This means, user-generated-content not only may conflict with the game data, it also means that every additional resource path must be unique.

4. Use of game core scripts by user resources is tricky. To avoid having users attach scripts to resources and nodes, I have added custom modules with new types for users to build their packs with. By the way, how do C# scripts work in additional resource packs? This is still an unknown to me.

This could probably be handled by #2689 proposal. ๐Ÿ™‚


Of course, every above point can be solved by third-parties given enough time and resources. But the question is whether Godot could provide those tools without having to fight with the engine internals, and be maintained at first-party level. So far, the lead developer does not seem to approve any of these ideas, or provide alternatives that don't really help the limitations presented here, and I respect the decision, but as I said, it's really something which could probably make Godot even better tool in this regard.

So, yeah, you'll likely be a happier person coming up with in-house solutions to solve those problems at the moment.

chottokite commented 3 years ago

Users/Players can use the standard editor and a project template provided by the developer to create their own resource packs that may be loaded at runtime by the game.

The core idea behind this proposal is that users don't need to be programmers/modders to learn and use developer-provided tools, so this is not an option for me personally. In fact, users might not even be interested to create the content themselves: it may be just an arbitrary image they have from which level geometry could be created, or a song from which a gameplay may be procedurally generated backed up by the mood of the song, etc.

I know and I failed to address this point. Or points, I would argue. In the approach my project has, users don't have to program anything. The only skill they have to train is to import and build scene trees. That and building a package file. So I think it programming isn't a necessary skill in general. Even if there is something to learn or train about, without coding, users that love a game manage to do things that they would have otherwise never have considered doing before for modding sake. The other point this proposal makes is loading some specific types of resources at runtime, like images and audio and 3D geometry. I entirely support that, I definitely have uses for that too in my project. This though, might be doable with GDNative addons. In fewer words, I think the scope of this proposal is too broad and it could be more agreeable with more focused problems and solutions.

Besides, I think the use of the word "import" should be changed to "load". By "import" I understand the process of converting a resource to a space-efficient and fast-loading format for use of a well-defined game project. Stand-alone user content, i.e., single files outside of a game package, isn't imported, it's loaded. And thus, you might desire to skip Godot's special package formats, like images that can be compressed and stored in an upload efficient format. It might be better to load a GLTF scene straight from disk to a scene tree and graphics memory without importing to an intermediate format.

That is the point I missed to say. To import is to store in an intermediate area for quick loading. At runtime, the benefits of importing are likely gone. So the exposure of Godot's importers to games is likely to be of little use in some cases, if not most.

Yep, it's a separate problem which I hope could be solved in a straightforward way, see another proposal of mine: #1212. This could probably be handled by #2689 proposal. slightly_smiling_face

These are nice proposals and they have my thumbs up but, I don't count on them having some kind of resolution any time soon :sweat_smile:

Of course, every above point can be solved by third-parties given enough time and resources. But the question is whether Godot could provide those tools without having to fight with the engine internals, and be maintained at first-party level. So far, the lead developer does not seem to approve any of these ideas, or provide alternatives that don't really help the limitations presented here, and I respect the decision, but as I said, it's really something which could probably make Godot even better tool in this regard.

So, yeah, you'll likely be a happier person coming up with in-house solutions to solve those problems at the moment.

golddotasksquestions commented 3 years ago

@Xrayez

I'm afraid Godot won't allow to bloat its binary size for mobile and web. But I think that usually, those platforms don't even need run-time import capabilities anyways.

I'd like to say I most definitely use and need run-time import capabilities on mobile. In my game I need to be able to load photos I have in storage. But music could be a obvious use case for mobile too. There are so many situations in games and apps where this would be great to have an easy way to use external resources, but currently it's a gigantic pain, especially on mobile.

I think I wasted a month trying to find a method that works on both Android and Windows (however only in GLES2). I got so frustrated I could not even bring myself to write an issue after I finally found the one method that worked, because I just wanted to be done with it. We really need something simple that works cross platform to load external resources. Not just desktop.

fire commented 3 years ago

News update.

The core team has allow for importing glTF2 files at run-time (in exported projects, without extra PCK files).

https://github.com/godotengine/godot-proposals/issues/3273

SoapSpangledGames commented 2 years ago

I'll throw my vote into the "dynamically loading assets at run-time is a crucial feature" hat. My new games are all client/server multiplayer, and need the ability for the server to dynamically upload assets to the client, and for the client to be able to load them into the scene upon receipt of the assets.

To be clear, I don't need the data transfer as part of the engine. I can handle that myself (and already have that capability in my server). What I need is for Godot to be able to dynamically load resources from anywhere within the user:// path (where my server uploads get written to), whether those resources were built into the game or not. That includes models, images, sounds, etc. All resources Godot recognizes need to be dynamically loadable from the core engine.

SylvanSign commented 2 years ago

I've been spending the last couple of days trying to make sense of imports and resources and pck files, and I think this thread sums up most of my desires.

I would love if PCKPacker could be used at runtime to build (and write to disk) pck files that contain imported versions of their assets. This way, on future runs of the game, loading that pck would mean being able to access the most efficient representation of these assets.

My use case is something like:

  1. Have game
  2. Want to load assets (images, audio, etc) from outside of game to make available in game. This could be user created content already on disk, or assets to be downloaded from the internet.
  3. Want those assets to be available in future game runs, so use PckPacker to write the pck to the user:// directory (ie. persisted on disk)
  4. Want to accomplish #3 while maximizing for runtime efficiency of reading that data (my understanding is that imported assets would take care of this)
  5. Want to accomplish #4 at runtime (ie. programmatically trigger the import pipeline through GDScript)
fire commented 2 years ago

One problem is the desire from the other maintainers to not compile the code for the importers in game templates. That has an easy solution, use the editor as the game template.

Hope that gives you an approach.

SylvanSign commented 2 years ago

Thanks @fire , that makes sense. For my specific case, I'm worried less about the export size of the engine/editor and more about abstracting this import process (and having to even open the editor UI) from the player of the game.

Maybe I'll have to follow this other proposal for running imports through the CLI? https://github.com/godotengine/godot-proposals/issues/1362

Beider commented 1 year ago

I am currently in the process of making a game that will allow modding, so far I can work around the quirks by loading images with Image.Load and not using .wav files (I don't want to parse the header). However I have yet to find a way to load true type fonts directly from an external file system.

It's sad to see that this was not fixed for godot 4.0. This really limits godot for making games with mod support or tools. I do hope this gets picked up in one of the future godot 4.x releases.

Calinou commented 1 year ago

However I have yet to find a way to load true type fonts directly from an external file system.

You can use system fonts in Godot 4. Since this involves loading fonts at runtime, it's likely that this can be extracted into a standalone way to load arbitrary fonts (even if they aren't in the system folders).

Beider commented 1 year ago

You can use system fonts in Godot 4. Since this involves loading fonts at runtime, it's likely that this can be extracted into a standalone way to load arbitrary fonts (even if they aren't in the system folders).

That is certainly an improvement, but for my usecase where I want to use steam workshop to provide mods it does not work (without extracting the functionality as you said). I can work around it since I use C#. I can load the font with a C# library, convert it to an image, then load the image in godot and make a bitmap font from it.

But it really is a hassle that you have to figure out per asset type (and also per file type in some cases, .wav files for example) how to import them into the engine. I dropped .wav support now because of the effort of parsing the header myself.

I am quite experienced with godot and programming in general and I find it very time consuming to figure out how to import this stuff. I can only imagine how difficult this would be for someone less experienced. I think making either a ResourceLoader.LoadExternal or just hiding it inside ResourceLoader.Load would be nice. If binary size is a problem then providing a setting to choose if this functionality is included or not could be a solution. I think the main motivator for such a change would be to make it easier for people to allow modding of their games.

Gerark commented 1 year ago

You can use system fonts in Godot 4. Since this involves loading fonts at runtime, it's likely that this can be extracted into a standalone way to load arbitrary fonts (even if they aren't in the system folders).

That is certainly an improvement, but for my usecase where I want to use steam workshop to provide mods it does not work (without extracting the functionality as you said). I can work around it since I use C#. I can load the font with a C# library, convert it to an image, then load the image in godot and make a bitmap font from it.

But it really is a hassle that you have to figure out per asset type (and also per file type in some cases, .wav files for example) how to import them into the engine. I dropped .wav support now because of the effort of parsing the header myself.

I am quite experienced with godot and programming in general and I find it very time consuming to figure out how to import this stuff. I can only imagine how difficult this would be for someone less experienced. I think making either a ResourceLoader.LoadExternal or just hiding it inside ResourceLoader.Load would be nice. If binary size is a problem then providing a setting to choose if this functionality is included or not could be a solution. I think the main motivator for such a change would be to make it easier for people to allow modding of their games.

I wonder how RPG in a box achieved this. In the FAQ it claims everything is built on top of Godot so I guess somehow this is doable? I'm asking cause I'm on the same boat. At this stage I'm considering to checkout the engine/editor source code and start stripping and changing whatever I don't need and transform it to a very specialized editor for my own game.

thephox1982 commented 1 year ago

With the recent Unity fiasco.. I REALLY would love to see another engine able to load models from either a file at runtime or a URL directly. A local file would be acceptable as I could use C# to natively download to file and then load it from disk. This would allow for dynamic games, virtual worlds and game mods.

lyuma commented 1 year ago

First of all, I'd like to point out that Godot .scn or .res files can be used at runtime as a native runtime format alternative to .pck. Godot is very capable of loading these native Resource formats, and by their nature, they will cover all file types Godot supports. .res is the format I am currently using in the V-Sekai project, though we of course will keep our eyes on the gltf ecosystem as the set of supported gltf extensions is continuously growing such as the recently added physics support.

(Side note: If there is concern about UGC security, I have GDScript code which can pretty efficiently validate a resource file for embedded scripts which is one of the bigger dangers: https://gist.github.com/lyuma/8de4620a402d565b86e1287150c8fb31 Some Resources such as PackedScene, Animation, AnimationNodeStateMachineTransition and so on will need additional validation after being loaded to ensure they don't reference unwanted properties / classes, since those properties/classes are technically binary/strings within the PackedScene resource.)

Regarding WAV file import, they contain raw PCM data and should be pretty simple to load at runtime from script if needed. - this is an example from python, but given that it uses only struct it there are GDScript equivalents for everything that sample code does.

Font loading at runtime is already supported by instantiating a FontFile instance and assigning the raw contents of the .ttf file into its data property. I think there's certainly a documentation shortcoming because it's not obvious that this is possible, but creating a FontFile instance is basically all the editor-time font importer does. - the preload step can also be done if you want, but my understanding is preloading is optional. Godot has a FontServer whose responsibility is to dynamically fetch glyphs from the font.

I do think it would be cool to see some equivalent of the import system for runtime, but doing so would be a major overhaul to how the entire import system works. I'm trying to point out that there are already ways to load most of asset formats described in this thread at runtime, just not through a single unified API.

@thephox1982 Re: "I REALLY would love to see another engine able to load models from either a file at runtime or a URL directly" - my understanding is the way Godot works in this regard is actually fairly similar to how other engines (such as Unity) work. The heavy lifting is intended to be done by the editor-time import process, and the runtime engine is slimmed down to only support specific formats. Thus, I'd suspect similar issues to exist in other engines, beyond the basic set of runtime supported formats.

Finally, I want to summarize what I think is one of the points of confusion in this thread.

The title of the proposal reads "Allow to import and load external assets at run-time ... without extra PCK files" I think it is worth breaking this down into both sub-pieces, since there are really two separate issues here.

load external assets at run-time. I'd say this is already possible today in 4.0+ for most formats: though the code needed is format-by-format. If there are specific asset formats you are having trouble with, feel free to ask about those specific formats.

import external assets at run-time. This is a valid proposal to make. Godot's Import system has a lot of features to it including a settings GUI, post processing, compression/baking, and some of those post-processing features are not trivial to do at run-time. Imported assets can reference other assets by file-path, so designing this system to work at runtime would require a file system structure similar to a Godot project, with a .godot temporary directory, some way to store imported file references (.import files) and so on. This is a major feature which would need to be designed, planned and implemented, since the entire import system at present is very dependent on this very editor-specific project filesystem infrastructure.

I suspect most of the usecases you are asking for can be covered by the load external assets at run-time case, which should be doable today on Godot 4.x versions. A runtime import system would certainly be easier to use, but does not exist at present.

Sorry for the long-winded comment: it's just my way of writing. I'm also always available by DM or on the #asset-pipeline channel on Godot Contributors Rocket Chat if you want to discuss these types of issues with me directly or with others working on the asset pipeline.

thephox1982 commented 1 year ago

@lyuma As for me personally, if I could load a fbx or gltf/glb from disk directly, this is frankly all I would need and of course either JPG/PNG file for the material, etc. The use case is a dynamic virtual world with user contributed content, which I have working in Unity but I'm looking to move away from Unity. If there are ways of doing this with Godot, I have yet to find a concise answer, example, or documentation that explains how it can be achieved.

Honestly, the locked down methods game engines still employ in 2023 seems baffling and archaic and a move toward allowing dynamic worlds both as static games and virtual world based games is the natural next step in gaming evolution, but we keep getting held back and instead we need to write our own engines from scratch to achieve these use cases.

As for the having to re-write importing system and such to allow for this, I'd personally would just make a separate importing system for runtime and have it as a module users of Godot could enable/install if they need it. This is sort of how it is in Unity, Unity doesn't natively support loading raw assets from disk or web server, but by purchasing an asset someone else made, I was able to get the ability to do just that.

I mainly just want to escape confines of greedy corporations where they can just change their ToS and begin charging new fees on a whim and other such things, so I'm looking for a new engine that can at LEAST be able to load from files I download via C# to file or better yet directly from a web server without having to first use C# to download the file and then load it.

Alternatively, if I could make a script that accepts a file via editor code that then packages up a Godot file that can then be sent to game clients and loaded, that would also work!

Calinou commented 1 year ago

As for me personally, if I could load a fbx or gltf/glb from disk directly, this is frankly all I would need and of course either JPG/PNG file for the material, etc.

Godot 4.0 and later can load glTF scenes at run-time, including from exported projects. Documentation is currently missing, but it is technically feasible.

Edit: Documentation was added by https://github.com/godotengine/godot-docs/pull/8363 and https://github.com/godotengine/godot-demo-projects/pull/993.

drwhut commented 1 year ago

As for the having to re-write importing system and such to allow for this, I'd personally would just make a separate importing system for runtime and have it as a module users of Godot could enable/install if they need it.

This is pretty much the solution I came up with for my game - this is my custom module that includes a function to import specific file formats at runtime almost exactly how the editor would (the function being TabletopImporter::import). It does however require you to compile the engine yourself, and if you want the functionality in release builds of your game, some tweaks are needed across the engine to make it work. There are more details in the module's README if you're interested!

PereViader commented 1 year ago

Godot 4.2 adds functionality to load OGG files by path. It would be ideal to do the same for all other audio formats and then have a unified interface to load them as AudioStream.

AudioStream.LoadFromFile(path) -> AudioStream
AudioStreamMP3.LoadFromFile(path) -> AudioStreamMP3
AudioStreamOggVorbis.LoadFromFile(path) -> AudioStreamOggVorbis
AudioStreamWav.LoadFromFile(path) -> AudioStreamWav

Edit: Honestly it would even be better if godot could just load non imported files and just manage the complexity for us and have it work transparently.

GD.Load<AudioStream>(path) -> AudioStream
Wad67 commented 1 year ago

To get around this obscene limitation, and to avoid rewriting my entire project I have simply resorted to shipping the editor and the entirety of my project, instead of a binary and packed files.

I have no idea why I would have to go and rewrite what the editor does, just so that the output binary can loose load files. The editor functionality and the runtime functionality should be 1:1.

Had I of known of this limitation in advance, I would have likely not used godot at all. But now I'm at the finish line, staring at a brick wall, because my game doesn't function outside the editor. Bravo!

Calinou commented 1 year ago

I have no idea why I would have to go and rewrite what the editor does, just so that the output binary can loose load files. The editor functionality and the runtime functionality should be 1:1.

In addition to PCK files, Godot supports many ways of saving/loading various standard file types at run-time: https://docs.godotengine.org/en/latest/tutorials/io/runtime_file_loading_and_saving.html

The above page was written for Godot 4.2, but Godot 4.1 supports all features listed there except run-time SVG and Oggย Vorbis loading โ€“ย if you need those right now, use 4.2.beta4.

drwhut commented 1 year ago

In addition to PCK files, Godot supports many ways of saving/loading various standard file types at run-time: https://docs.godotengine.org/en/latest/tutorials/io/runtime_file_loading_and_saving.html

Oh wow, you can do so much more with vanilla GDScript in 4.2 than you can with 3.5 :open_mouth: I just want to confirm, do all of these functions mentioned in the documentation still work in release builds of the engine?

Also, I've noticed that there are not any functions for .obj and .dae 3D model formats - are these formats planned to be added in the future at all? If not, that's totally OK, I'm more than happy to write custom importers for them if it means I no longer need to maintain a custom fork of the engine!

Calinou commented 1 year ago

I just want to confirm, do all of these functions mentioned in the documentation still work in release builds of the engine?

Yes, I've tested the demo project with a release export template. The examples/ folder in the demo has a .gdignore, so none of the files inside are imported in the project.

Also, I've noticed that there are not any functions for .obj and .dae 3D model formats - are these formats planned to be added in the future at all? If not, that's totally OK, I'm more than happy to write custom importers for them if it means I no longer need to maintain a custom fork of the engine!

This should be tracked in its own proposal (like for audio). Personally, I think being able to load OBJ at runtime makes some sense (since it provides individual meshes as opposed to scenes), but Collada is a dead-end format nowadays (nearly everyone has moved to glTF).

That said, even OBJ remains a less optimal format than glTF for meshes, because glTF can be a binary format which compresses better and loads faster (for complex meshes). This would be another reason to encourage users to use glTF, also because you can save glTF at runtime with Godot (while runtime OBJ support would likely be read-only).

Wad67 commented 1 year ago

I have no idea why I would have to go and rewrite what the editor does, just so that the output binary can loose load files. The editor functionality and the runtime functionality should be 1:1.

In addition to PCK files, Godot supports many ways of saving/loading various standard file types at run-time: https://docs.godotengine.org/en/latest/tutorials/io/runtime_file_loading_and_saving.html

The above page was written for Godot 4.2, but Godot 4.1 supports all features listed there except run-time SVG and Ogg Vorbis loading โ€“ if you need those right now, use 4.2.beta4.

The issue remains that I would have to rewrite everything instead of just having load and preload work as expected. As I understand this is due to a reliance on the import files, which can not be generated by the exported binaries?

Instead I am just shipping the editor, and setting the path argument to the project directory. Now load and preload work as expected, except the audience is stuck with debug, which if I understand correctly is slower.

Calinou commented 1 year ago

The issue remains that I would have to rewrite everything instead of just having load and preload work as expected. As I understand this is due to a reliance on the import files, which can not be generated by the exported binaries?

I think this will remain the case for the foreseeable future. load() and preload() aren't designed to work with arbitrary files on the filesystem โ€“ย they handle many Godot-specific things, such as its resource file types, resource translation remaps, reading import settings from the .import file. In contrast, none of this is relevant when loading standard file types, which is why different methods are used for this.

To clarify, runtime resource loading should not be used to load files that are part of the project. You should keep using load() and preload() for those.

PereViader commented 1 year ago

Because Load and Preload accept paths as input parameters, it is not clear that they are not meant to be used in runtime to load assets outside the project.

If I recall properly, they even returned null instead of failing / logging an error on the console mentioning that they don't support files outside the project.

It was even more confusing after that because the exported binary was able to load files outside the project that were copy pasted outside the project thus still having the .import files besides them. (while loading audio files at runtime).

--

On a totally different note, it was weird to not be able to not be able to stream audio file from disc while playing. AudioStreamOggVorbis.LoadFromFile(path) -> AudioStreamOggVorbis read the whole contents of the file before being able to play it. My usecase required reading a 24h sound file which took a bit to load ๐Ÿคฃ

Yukitty commented 11 months ago

Runtime loading of Ogg Vorbis used to work in Godot 3, it seems like it just got "optimized away" at some point. I need it for loading from external ZIP files and user-generated content.

... So I have cludged it together as a messy little GDExtension and submitted it to the Asset Library.

https://github.com/Yukitty/godot-runtime-ogg-vorbis https://godotengine.org/asset-library/asset/9877

Calinou commented 11 months ago

Runtime loading of Ogg Vorbis used to work in Godot 3, it seems like it just got "optimized away" at some point. I need it for loading from external ZIP files and user-generated content.

This is already available out of the box in 4.2 and later: https://docs.godotengine.org/en/latest/tutorials/io/runtime_file_loading_and_saving.html#audio-video-files

Yukitty commented 11 months ago

... ah. ๐Ÿคฆ๐Ÿผโ€โ™€๏ธ I appear to have checked the asset library, checked proposals, checked (open) pull requests, aaand somehow forgot to check the current development version. It's already implemented exactly where and how I was wanting it. ๐Ÿ˜…

gibloor commented 3 months ago

Five years later, it's impossible to export a game that has .ogv video without dancing around =)

Calinou commented 3 months ago

@gibloor Please don't bump issues without contributing significant new information. Use the :+1: reaction button on the first post instead.

The issue you're mentioning is also unrelated: you need to add *.ogv to your non-resource export filter. You should be able to load such files at runtime in an exported project as well, even if they're stored in user://: https://docs.godotengine.org/en/latest/tutorials/io/runtime_file_loading_and_saving.html#audio-video-files