Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Share code between multiple projects #577

Open
git2013vb opened this issue Mar 13, 2020 · 36 comments
Open

Share code between multiple projects #577

git2013vb opened this issue Mar 13, 2020 · 36 comments

Comments

@git2013vb
Copy link

Describe the project you are working on:
Client server project
Describe the problem or limitation you are having in your project:
I have to duplicate some functionality between client and server ( log management, common classes for example)
Describe the feature / enhancement and how it helps to overcome the problem or limitation:
It will be nice if the project can use shared folder where user can put in common code (will be gdscript/c# or anything else)
Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
Add a configurable path option in project settings where user can decide where the shared code will be
Then the shared path will be displayed in dock together with current project folders

If this enhancement will not be used often, can it be worked around with a few lines of script?:
NA
Is there a reason why this should be core and not an add-on in the asset library?:
It will part of project structure.

@Xrayez
Copy link
Contributor

Xrayez commented Mar 13, 2020

See godotengine/godot#35432 (talking about global plugins). The implementation was not accepted but the feature is still desired, the rationale behind this as described in godotengine/godot#35432 (comment).

@git2013vb
Copy link
Author

git2013vb commented Mar 13, 2020

No, I'm against to do it by plugin.
It will be like using a cannon to kill a fly.
A simple settings in project properties against to build a plugin and import it in a project.

So far we have already a "shared" folder
.local/share/godot/app_userdata/

where inside we have all our projects
So will be enough to add a "common" folder we can use as "container" of any code/resource that can be shared/reused among all projects.

...More simple that that :)
edit: Also if is like that I suggest we will not need any settings in projects. Just to show this "common" folder in dock with a different color, eventually.
edit2: Even better: instead using app_userdata is will be better to create a "common" under .local/share/godot folder

It have not to be exactly "common" as name . important is to reach the functionality we need: share between projects.

edit2: Even better: instead using app_userdata is will be better to create a "common" under .local/share/godot folder

It have not to be exactly "common" as name . important is to reach the functionality we need: share between projects.

@Megalomaniak
Copy link

I think this is better served by an asset manager than a plugin interface, though here's an idea: Develop and bundle a asset/resource manager as a plugin and it can also potentially solve the need for global plugins as well.

@willnationsdev
Copy link
Contributor

Couldn't this be more easily solved by allowing users to arbitrarily add "include" folders for their Godot project in both ProjectSettings (on a per-project basis) and EditorSettings (on a multi-project basis)? You'd need the EditorFileSystem singleton to account for those locations and then make sure that they are all handled during project/pck export. But I think that's all that would be needed. Anything work that is done via the plugin system could be done as a separate layer on top of that (and plugin stuff like #142 won't be ready for a while whereas this could be done much sooner).

@git2013vb
Copy link
Author

Couldn't this be more easily solved by allowing users to arbitrarily add "include" folders for their Godot project in both ProjectSettings (on a per-project basis) and EditorSettings (on a multi-project basis)? You'd need the EditorFileSystem singleton to account for those locations and then make sure that they are all handled during project/pck export. But I think that's all that would be needed. Anything work that is done via the plugin system could be done as a separate layer on top of that (and plugin stuff like #142 won't be ready for a while whereas this could be done much sooner).

As long I can use this "include" folder like any other project folder I'm happy with your solution.
For project's point of view this folder have to be like any other project's folder.

@Flavien
Copy link

Flavien commented May 23, 2020

I agree with @willnationsdev, the first step, which will solve 95% of use cases is to simply let people include arbitrary paths into their res:// filesystem (e.g. set res://sprites/ to point to ~/sprites on my machine).

A "nice to have" after that is allowing to reference ZIP archives, so you can bundle resource packs and share them as a ZIP file.

@Jummit
Copy link

Jummit commented May 24, 2020

I actively share code between projects, I have a big library of plugins and utilities. I use symbolic links to synchronize them.

OP said:

No, I'm against to do it by plugin.
It will be like using a cannon to kill a fly.

I don't exactly understand the reasoning behind that argument. I have a lot of plugins that are ~30 lines of code. The benefits of plugins are that you can enable/disable them and that they have a lot of power over the Godot interface.

@git2013vb
Copy link
Author

git2013vb commented May 25, 2020

The reason was in the first place to avoid copy-paste. As far I know even if you use plugins you have to copy them between projects to have them.
My current "workaround" is to make a separate library project dll (C#)
Personally I prefer dll instead having a plugin with the risk that is not the same int all my projects (I don't count git to sync, I use git as pure versioning system)
But.. If we can have a personal local repo where we can put all our plugins together tha can be used I will have no qualm:
image

But how it work?
I did't find any documentations.

@Jummit
Copy link

Jummit commented May 25, 2020

Note that even if you'd get a custom server running, you'd still be copy-pasting. Use symbolic links if you really want to avoid duplicate code.

@git2013vb
Copy link
Author

git2013vb commented May 25, 2020

Note that even if you'd get a custom server running, you'd still be copy-pasting. Use symbolic links if you really want to avoid duplicate code.

Can you elaborate please?

ps.: I know copy-paste is a virus :)) the lesser the better

@willnationsdev
Copy link
Contributor

willnationsdev commented May 25, 2020

@git2013vb There are ways of creating "symbolic links" for files where you effectively tell the operating system to keep a reference to the same file in multiple places. ln on Linux/Mac and mklink on Windows can do it for you, given the right parameters. A "hard directory link", for example, could enable you to keep a plugin located in multiple projects' res://addons/ folder. Editing any files inside would also edit the same files in the other projects, because they all reference the same files.

Edit: A "soft link" is effectively the same thing as a shortcut where it simply points to the other file, but isn't a direct reference to it. With soft links, if you delete the original, then the shortcut/soft-link no longer works properly. Hard links will truly create another full reference to the file.

@git2013vb
Copy link
Author

@git2013vb There are ways of creating "symbolic links" for files where you effectively tell the operating system to keep a reference to the same file in multiple places. ln on Linux/Mac and mklink on Windows can do it for you, given the right parameters. A "hard directory link", for example, could enable you to keep a plugin located in multiple projects' res://addons/ folder. Editing any files inside would also edit the same files in the other projects, because they all reference the same files.

Edit: A "soft link" is effectively the same thing as a shortcut where it simply points to the other file, but isn't a direct reference to it. With soft links, if you delete the original, then the shortcut/soft-link no longer works properly. Hard links will truly create another full reference to the file.

Thank you but I know what are ln/sl (the main problem is you cannot "port" them across different OS, for someone like myself who use linux,win - and later mac - in different pc/machine/devices is hard to keep in synk all of them) btw I was asking about what he meant about his "you'd still be copy-pasting" sentence :)

What I suggest than any solution it is the best to be made in godot in order to be portable.

@Jummit
Copy link

Jummit commented May 25, 2020

what he meant about his "you'd still be copy-pasting"

Downloading things from the asset library just copies the files into your project, no links and no git repo.

@git2013vb
Copy link
Author

git2013vb commented May 25, 2020

That is fine if you use other plugins - in a certain extend - But when you are going to make your plugin/ common classes/common scenes - or anything that you don't wish to be duplicate the problem remain.
What kind of problem? difficult to keep all synced. That was the first reason why I had to make a dll. To be DRY :)

@tx350z
Copy link

tx350z commented May 29, 2020

I'm very much in favor of having a way to add a directory reference outside the project folder to the FileSystem doc. It seems to be the simplest, most direct direct way to support libraries of common/shared/library objects.

It might be good to have the option of making the folders read-only so editing of shared code can only be done within a common/shared/library project. Projects that "import" or "bind" or "reference" or "what-ever-term-you-like" to the external directories should still be able to view the code (e.g. for debugging) even when read-only.

@cybin
Copy link

cybin commented Jan 11, 2021

Is there any update on this? I really would appreciate to add external paths to res:// like proposed in earlier comments.

@Calinou
Copy link
Member

Calinou commented Jan 11, 2021

Is there any update on this? I really would appreciate to add external paths to res:// like proposed in earlier comments.

As far as I know, nobody started working on this feature. That said, proposals like #142 and #831 are more likely to be implemented as they're more concrete.

@tx350z
Copy link

tx350z commented Jan 11, 2021

It seems to me that implementing a read-only inclusion of another directory would be much easier than fiddling with add-ons, etc. Wouldn't the changes be just to the editor & exporter? But, I haven't looked at the editor code so I'm probably very wrong.

@Megalomaniak
Copy link

The positive of an add-on solution is that it can be updated and maintained separately outside the main engine release cycle. Other then that(and i just really want a good asset manager), @willnationsdev proposed include folders proposal is appealingly simple and fool proof.

@Shatur
Copy link

Shatur commented Mar 19, 2021

Currently, Godot ignores a folder if it contains project.godot. We could remove this check:

https://github.com/godotengine/godot/blob/ec3f220098f4bf5a10809e6682a9a24ff93d85cb/editor/editor_file_system.cpp#L1977

allow other projects to be included. What do you think?

@YuriSizov
Copy link
Contributor

@Shatur95 This is what #1205 is about.

@Shatur
Copy link

Shatur commented Mar 19, 2021

@pycbouh, missed it, thanks!

@tx350z
Copy link

tx350z commented Nov 30, 2021

I know there are many similar enhancement requests to this one and there have been many great ideas offered as solutions. I thought I'd offer a few findings from my efforts to implement a "shared code library" solution.

My project involves 7 separate game applications that interoperate to create a complex simulation for flight crew training. Each app shares some critical code such as network message protocols, etc. I found early on that manually keeping shared code across all 7 projects synchronized is nearly impossible.

I've tried hard symbolic links which fail to work properly in many cases (see "Problems" below).

So I cobbled together a solution that automatically keeps the shared code synchronized. It's a glorious Rube Goldberg solution involving editor plugins and a stand alone server that handles replication of shared code changes across the projects. It works ONLY because I fully understand all of the limitations.

Problems: Based on my experience creating and using the solution, sharing code across multiple projects is complicated and prone to disaster (specifically code loss) if not done correctly. Consider problems caused by file/folder renames/moves/deletions. What happens if one project moves a shared file out of the shared folder structure? There are also issues with shared code referencing paths outside of the shared folder structure. Add to that dependencies on project and editor settings that may not apply to all of the projects sharing the code. The list of issues is much larger than this.

Recommendation: I've come to the conclusion that the only sensible solution is to enhance the FileSystemDock to allow adding a reference to an external folder AND make that folder, along with all folders and files beneath it, read-only. This will also require the separate editors (scene, script, resource, etc.) to be enhanced to tolerate read-only folders and files. The external references should be restricted to the project root ("res://") which helps avoid problems with incompatible paths, etc. This approach does not solve the above mentioned problems with paths outside the shared code and editor/project settings, etc. Those become case-by-case problems for the programmer to avoid.

Comments and feedback are welcome.

@cloewen8
Copy link

So I cobbled together a solution that automatically keeps the shared code synchronized. It's a glorious Rube Goldberg solution involving editor plugins and a stand alone server that handles replication of shared code changes across the projects. It works ONLY because I fully understand all of the limitations.

Your solution is far more automated than mine. I have a git-like plugin with buttons to scan for changes, push changed files and pull in newer files. It runs a python cli from another external git repository.

It works, but only for me. The repository needs to be in a specific location.

Making the plugin read-only would defeat the point for me. In some projects I tend to cycle between making a change and testing. If I needed to use an external editor for resources, that doubles the time it would take (not worth it, would just use my own plugin).

@rickwight
Copy link

I think being able to import a remote folder into the project would be the ideal solution, but it would have to be read-write, so you can still edit the remote scripts within the current project.

@Jummit
Copy link

Jummit commented Feb 8, 2022

Because everyone is sharing their solution, I have made a package manager similar to pip, npm or cargo:
https://github.com/Jummit/godot-package-manager
It can be used to add addons found in Git repos. It even has a search feature.
I don't think this is how a built-in solution should work though. The best place to add package management would be the asset library IMO.

@tx350z
Copy link

tx350z commented Feb 8, 2022

I think being able to import a remote folder into the project would be the ideal solution, but it would have to be read-write, so you can still edit the remote scripts within the current project.

@rickwight I thought the same thing until I implemented my own solution. Editing shared file content within "subscriber" projects is simple enough. However, it presents numerous problems when shared files are renamed, moved, deleted, etc. It's even worse when shared folders/subfolders are renamed/moved/deleted. Since I commonly have multiple Godot editor instances open on different but related projects, it's no problem having the publisher projects open in case a change is needed.

The experience gained in my attempt to build a solution convinces me the simplest approach is for the file system dock to support adding a read-only reference to a folder outside the project folder structure.

@git2013vb
Copy link
Author

My current approach in C# is to have a separate project where I manage classes only ( so its a sub part of what I pointed out in this tread) .

Using VSCode I have a Solution explorer extension where I can reach the dll from my editor current project. I'm the only person who manage all project so I know when and where to modify my dll.

In case of a Team I think @tx350z solution (read only folder) can be a good solution.
Unless the team is instructed to do not change the folder without planning ahead for the whole team.

I'm not sure the impact using GDScript , or in case of shared Scenes or external Signals involved ( I can have a Singleton too in that folder ;) ) .

@rickwight
Copy link

It would be near pointless to have them read-only if you are using GDScript like I am. You want to use the editor to write GDScript, so having to switch to a different project just to edit the file would be a non-starter. If you could make them meta-read-only, but contents writable, maybe that's some kind of compromise? Like you can't rename or move any remote file, but you can edit the code in the editor.

@WarrenMarshall
Copy link

Another vote for external folders, please. We have common functionality we'd like to share between various games using gdscript and I just don't see a viable path to do that right now.

@tx350z
Copy link

tx350z commented Jun 8, 2022

Desperately needed this for a project involving 5 separate apps that share about 50% of the code base. I ended up building an external Godot/C# xcopy-style server and a Godot editor plug-in. The plug-in tells the server what libraries the project uses. The server handles all the file change monitoring and copying. The editor plug-in also sets the read_only flag on the script editor to prevent changing the library code anywhere except the "owning" library project. That greatly simplifies propagating changes across multiple projects. If I ever get time I'll clean it up and make it available to anyone interested.

@omggomb
Copy link

omggomb commented Jun 19, 2022

I never really worked on bigger projects so I'm genuinely curious: Why can't these requirements be solved by using a VCS, i.e. git and git submodules?

@WarrenMarshall
Copy link

Potentially. But those get messy and they require programmers to be aware of multiple repos and be aware of what code belongs to which repo, etc.

Or we could extend the file system inside Godot to be able to look outside of it's home directory for files, which would be much simpler.

@elinfame
Copy link

What is the state of the art re: solving this problem? In my case, I have a git monorepo with multiple projects and multiple languages. There are pieces of code that I would like to extract into a "GDScript library", like math functions and classes; I'm not interested in using 3P code or having to separate my code into a different repo just to download it again via git submodules.

@elinfame
Copy link

My 2c in favor of how this might work: no read/write restrictions on library code from the editor. The editor should be able to open an entire FS directory (like VSCode) and build any project within that directory tree. Obviously this is a significant lift and forces directories to align on previously project wide settings like Godot version, and requires changes in the editor to make other project settings (like input, display, etc) apply per project. This is like the "workspace" concept prevalent in Rust's Cargo, NPM, Xcode, Go, or Bazel.

@paul-mcnamee
Copy link

paul-mcnamee commented Oct 3, 2023

What is the state of the art re: solving this problem? In my case, I have a git monorepo with multiple projects and multiple languages. There are pieces of code that I would like to extract into a "GDScript library", like math functions and classes; I'm not interested in using 3P code or having to separate my code into a different repo just to download it again via git submodules.

If your project does not contain or require a project.godot file and you can omit it from git then you can just use submodules.

Currently if you use a submodule for the whole project and it contains a project.godot file then the folder will be ignored. Here is the current solution I have for adding folders from a project which contains a project.godot file in the root directory using git git sparse-checkout:

# in the base directory of the current godot project you are attempting to import folders into

mkdir imported_project_folder_name
cd .\imported_project_folder_name\
git init
git config core.sparsecheckout true
git sparse-checkout set --no-cone folder_to_import/*
# if you have multiple folders, add the patterns like the one above

git remote add -f origin <url_of_imported_project>
git pull origin main

# add folder_to_import to .gitignore in the project you imported it into

There are a lot of caveats with using the --no-cone flag for sparse-checkout see here for more info.

I would like to see alternatives though, I think this is messy and likely unnecessary but I am new to godot and haven't found other working solutions that are cleaner for sharing code between projects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests