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

Add ability to export patch packs #97118

Merged
merged 1 commit into from
Sep 26, 2024
Merged

Conversation

mihe
Copy link
Contributor

@mihe mihe commented Sep 17, 2024

Closes godotengine/godot-proposals#146.
Supersedes #64712.

This is largely the same as #64712, but rebased to take into account the export extension API added in #90782, as well as some other minor additions, and as such @PoqXert deserves much of the credit here.

This PR adds the following to the public interface of Godot:

  1. A new tab to the Export dialog named "Patches", that lets you add previously exported PCK pack files to serve as the basis for exported patch packs.
  2. A new checkbox in the "Export PCK/ZIP" dialog titled "Export As Patch", which signals that the exported PCK/ZIP should only export files that have changed when taking into account the patches listed in the above mentioned "Patches" tab.
  3. A new --export-patch [preset] [path] command-line option, which lets you export patches from command-line, using the list of patches defined in the export preset.
  4. A new --patches [paths] command-line option, which overrides the patches defined in the export preset.
  5. EditorExportPreset now exposes the following methods: get_patches.
  6. EditorExportPlatform now exposes the following methods: export_pack_patch, export_zip_patch, save_pack_patch and save_zip_patch.
  7. EditorExportPlatformExtension now exposes the following virtual methods: _export_pack_patch and _export_zip_patch.

ExportDialog
ExportPckDialog

Copy link
Member

@AThousandShips AThousandShips left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good but haven't tested, might be able to later today, but looks good and makes sense

editor/export/project_export.cpp Outdated Show resolved Hide resolved
editor/export/project_export.cpp Outdated Show resolved Hide resolved
doc/classes/EditorExportPlatformExtension.xml Outdated Show resolved Hide resolved
doc/classes/EditorExportPlatformExtension.xml Outdated Show resolved Hide resolved
@akien-mga
Copy link
Member

I've tested this a bit using a modified version of https://github.com/gdquest-demos/godot-4-new-features/ which can be found here: https://github.com/akien-mga/godot-4-new-features/tree/test-patches-2d-3d

This demo is a good test case for patches/DLCs as it has a main UI launcher (base pck) used to start standalone demos which are all in their own folders.

So I tweaked the project to have a first export preset to export a base pck with common stuff, and then two more export presets to export the 2d_* and 3d_* demos, which then get loaded at runtime with ProjectSettings.load_resource_pack. (I didn't bother with other folders so in the export project with patches, only the demos titled "2D ..." and "3D ..." can be started.)

image

That seems to work fairly well! I didn't actually test stacking patches that depend on previous patches, which I believe is what the actual "Patches" tab in the export preset should be used for. If someone wants to try it out by further tweaking this demo, that should be doable I suppose?


Overall the feature seems functional, but the UX isn't great IMO. Having to create one export preset per patch makes sense, though it might not be very intuitive to users. But then having to know that to make a patch you can use "Export PCK" and enable "Export as Patch" there (with its state remembered across the session, but not specifically for that preset), is a bit weird.

It might be better to have a dedicated system to add "patch presets" of some form under a platform export preset, and only get patch-relevant options in a dedicated configuration dialog (e.g. no need to configure stuff that relates to the executable in a patch as we only care about the pck contents, the "export as patch" would be implicit or an option in the sectioned inspector as opposed to the file dialog, etc.).

Such presets could possibly even be reused for multiple platforms, because (as far as I can imagine at least) I would expect patches to be mostly about platform-agnostic content (scenes, resources), and at most what would change is the VRAM compressed texture type to export.

With such a structure, it would also become possible to implement a system to export the project + all its patches/DLCs in one go.

But all this is for future work, I think it makes sense to merge the actual feature for now, even with subpar UX, and rework it in the future. To be honest, the whole export dialog UX is bad IMO and needs a redesign. The patch/DLC workflow should be taken into account when doing that work.

One thing that could maybe still be done in this PR, if there's consensus, would be to move the "is this a patch" option to the export preset itself, and then have it appear in the UI as " (Patch)" like we currently have for the "(Runnable)" suffix. Mockup:
image


I haven't tested the command line yet, but one remark: semicolon separated strings seems a bit unconventional, and might conflict with some shells where a semicolon is actually used to separate commands. Users would need to remember to quote their list for the semicolon not to be handled by the shell.

I'd suggest using comma separated strings instead, like we already do for the --breakpoint command.

@KoBeWi
Copy link
Member

KoBeWi commented Sep 18, 2024

The feature works correctly. I made a simple test project:
DLCTest.zip
Export the game with Main preset, then export pack with DLC preset . If you run exported project with DLC.pck in the same folder, icon.svg will appear in the scene. The DLC package contains only content from DLC folder, as expected.


Some problems I found:

  • If exporting with invalid patch, the export will fail with only an error in the console. It should display error dialog.
  • The Patches tab could use some improvements:
    image
    • It's not immediately obvious how it should be used. "Add previous patches..." does not really suggest that you are supposed to use main game's PCK as base. Base game is not a patch.
    • Why patches can be disabled? You need to make separate list for each preset anyway. Disabling would make sense if the list was shared.
    • The usage of Tree is awkward. You add patches using browse button on fake item.
    • btw this should use FileBrowse icon I think, since you are technically picking a file.

My suggestions would be:

  • Remove "Add previous patches..." and instead make a label at the top, saying "Base Packages" or something similar.
  • Remove checkboxes and "disabled_patches".
  • Add "Add Package" button at the bottom, which would replace the fake item.
    image

EDIT:
I just noticed that the message says "Add initial export..." when there is no packs selected. My suggestions still apply though; "package" is more universal.

@mihe
Copy link
Contributor Author

mihe commented Sep 19, 2024

Having to create one export preset per patch makes sense, though it might not be very intuitive to users.

I must admit this was not exactly how I envisioned this to be used myself, but I've also been more focused on the patch aspect, rather than the DLC aspect. I figured most projects (or at least the simpler ones) would be fine with using their regular export presets and you would simply add any new patch pack to the list of packs in the "Patches" tab as you released them.

But I guess that would only really make sense for patches though, since for something like DLCs you would likely do exactly what you did with the 2D/3D demo separation, since they'd almost always be exporting different sets of scenes/resources. They would also likely not depend on eachother.

But yeah, managing multiple presets might perhaps end up being the more common way of interacting with patch/DLC exports, and I agree that it's not very intuitive/ergonomic with having all the regular executable-related options in there. It's not obvious which ones (if any) you might need to keep in sync in order for the exported patch pack to be correct.

One thing that could maybe still be done in this PR, if there's consensus, would be to move the "is this a patch" option to the export preset itself, and then have it appear in the UI as " (Patch)" like we currently have for the "(Runnable)" suffix.

I'd be fine with this so long as we also disable the "Export All..." and "Export Project..." buttons when selecting such presets, to drive home that it only makes sense for packs.

This would however mean that you can't utilize the flow I mentioned above of sharing the export preset between the base PCK and the patches, which seems mildly unfortunate.

I haven't tested the command line yet, but one remark: semicolon separated strings seems a bit unconventional, and might conflict with some shells where a semicolon is actually used to separate commands. Users would need to remember to quote their list for the semicolon not to be handled by the shell.

I'd suggest using comma separated strings instead, like we already do for the --breakpoint command.

Done.


If exporting with invalid patch, the export will fail with only an error in the console. It should display error dialog.

This strikes me as more of a general problem with exports. I can't spot any precedence for export errors showing a dialog. They all seems to go through the dedicated EditorExportPlatform::add_message method, like what the current error is doing.

Remove "Add previous patches..." and instead make a label at the top, saying "Base Packages" or something similar.

Done.

This is bordering on bikeshedding I guess, but the "Patches" tab itself sort of served as the title for the Tree control, whereas now we instead have this "Base Packages" label. So are they patches or are they base packages? Does it matter?

Also, I see PCK files being referred to as "packs" in some places in Godot and "packages" in some places. Which is the correct one?

Remove checkboxes and "disabled_patches".

Yeah, I think the enabled/disabled state was something just taken from the screenshots in the (now ancient) original proposal. I'm not entirely sure what the motivation was for this to be added in the first place, but it seems niche enough that I have no objections to removing, so I've done just that. It can always be added back if there's a great need for it I guess.

Add "Add Package" button at the bottom, which would replace the fake item.

Done.

btw this should use FileBrowse icon I think, since you are technically picking a file.

Done.


To sum up, these are the unresolved questions:

  1. Do we go with the patch toggle on the preset itself, or do we leave "Export As Patch" in there?
  2. Does the "Patches" tab title make sense with the "Base Packages" label in there?
  3. Is it "Packages" or "Packs"?

@KoBeWi
Copy link
Member

KoBeWi commented Sep 22, 2024

I figured most projects (or at least the simpler ones) would be fine with using their regular export presets and you would simply add any new patch pack to the list of packs in the "Patches" tab as you released them.

I'm not sure how useful is that workflow. Steam for example is able to automatically calculate the difference from last uploaded game package and make the user only download what's changed. Not sure about other stores though. Regardless, if you follow the incremental patch approach, you will eventually end up with a build that has e.g. 50+ patches, which kind of kills the purpose of PCK files, which are supposed to be singular for less fragmentation.

Do we go with the patch toggle on the preset itself, or do we leave "Export As Patch" in there?

Depends if you want to toggle it per export or not. For DLC, the DLC preset will always be a patch. For incremental patches, you might sometimes want to export everything.

Does the "Patches" tab title make sense with the "Base Packages" label in there?

IMO the label makes sense. Tab name describes content, while the label describes the specific element (though it's the only one).

Is it "Packages" or "Packs"?

"Packs", if you say it's already used in the engine. I used "packages" in contrast to "patches", as I find it more intuitive.

@SanteriLoitomaa
Copy link

I figured most projects (or at least the simpler ones) would be fine with using their regular export presets and you would simply add any new patch pack to the list of packs in the "Patches" tab as you released them.

I'm not sure how useful is that workflow. Steam for example is able to automatically calculate the difference from last uploaded game package and make the user only download what's changed. Not sure about other stores though. Regardless, if you follow the incremental patch approach, you will eventually end up with a build that has e.g. 50+ patches, which kind of kills the purpose of PCK files, which are supposed to be singular for less fragmentation.

I for one am waiting for this exact feature as in my project I cannot use an external store and have to code the patching system myself. You are correct though that making 50+ patches is not really intuitive. A manual cleanup might be required from time to time.

I'd use this to make one "base patch" with the main game assets and then a separate "fix patch" with only changed files which would be updated until it becomes too big. When that happens the "base patch" would be updated and the circle would continue or maybe just make the "fix patch" into a DLC kind of thing and start a new fix one. The main point being that the original binary would only need to be updated once the Godot version itself is changed.

reduz added a commit to reduz/godot that referenced this pull request Sep 23, 2024
* This was "kindof" existing in PCK but not properly done or supported. It seems this work was initiated over a decade ago and never completed.
* If a file has offset zero in a PCK, it will be considered removed and it will be removed if previously added.

This adds the possibility to add proper directory level diffing to godotengine#97118.
reduz added a commit to reduz/godot that referenced this pull request Sep 23, 2024
* This was "kindof" existing in PCK but not properly done or supported. It seems this work was initiated over a decade ago and never completed.
* If a file has offset zero in a PCK, it will be considered removed and it will be removed if previously added.

This adds the possibility to add proper directory level diffing to godotengine#97118.
@mihe mihe force-pushed the patch-exports branch 2 times, most recently from acab811 to 2fcd89f Compare September 24, 2024 12:23
@mihe
Copy link
Contributor Author

mihe commented Sep 24, 2024

Depends if you want to toggle it per export or not. For DLC, the DLC preset will always be a patch. For incremental patches, you might sometimes want to export everything.

I don't personally have any strong feelings one way or the other, so I'll leave it as-is for now.

IMO the label makes sense. Tab name describes content, while the label describes the specific element (though it's the only one).

Fair enough.

"Packs", if you say it's already used in the engine. I used "packages" in contrast to "patches", as I find it more intuitive.

I've gone ahead and changed the label to "Base Packs" and the button to "Add Pack".


Unless we consider the suggestion of the preset toggle to be a blocking issue it would seem to me that there are no unresolved issues remaining.

Let me know if there's anything I can do to help move this forward.

main/main.cpp Outdated Show resolved Hide resolved
main/main.cpp Outdated Show resolved Hide resolved
Comment on lines 107 to 110
Control *panel = custom_feature_display->get_parent_control();
if (panel) {
panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox("bg", "Tree"));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure to be honest. It looks unrelated to this PR, so I went ahead and removed it. Maybe @PoqXert can shed some light on why this was in there.

@KoBeWi
Copy link
Member

KoBeWi commented Sep 24, 2024

I think the feature is fine in the current state. It works, though I didn't test with various options like encryption etc.

I think "Export As Patch" should be enabled by default. Also the option could be hidden when there are no packs assigned, as it has no effect then.

@mihe
Copy link
Contributor Author

mihe commented Sep 25, 2024

I think "Export As Patch" should be enabled by default. Also the option could be hidden when there are no packs assigned, as it has no effect then.

I can see the reasoning behind this, but I personally feel like the UX of this would be even more confusing than what we have currently. I'd be curious to see some more input on this.

EDIT: Oh, and thank you for catching all the issues @KoBeWi, I was clearly in too much of a hurry with some of these later changes.

@KoBeWi
Copy link
Member

KoBeWi commented Sep 25, 2024

I can see the reasoning behind this, but I personally feel like the UX of this would be even more confusing than what we have currently. I'd be curious to see some more input on this.

And what about making it enabled by default? It's easy to imagine someone adding packs, but failing to notice the checkbox and get confused.

@SanteriLoitomaa
Copy link

I can see the reasoning behind this, but I personally feel like the UX of this would be even more confusing than what we have currently. I'd be curious to see some more input on this.

And what about making it enabled by default? It's easy to imagine someone adding packs, but failing to notice the checkbox and get confused.

I think it should be enabled by default as there is no harm for it being enabled for people who don't use the tab.

Co-authored-by: Poq Xert <poqxert@poqxert.ru>
@mihe
Copy link
Contributor Author

mihe commented Sep 25, 2024

I went ahead and made "Export As Patch" enabled by default.

Copy link
Member

@akien-mga akien-mga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't re-tested in depth but the changes done since my first review are good.

Let's merge and get some wider testing on both the functionality and the UX, so we can do further adjustments as needed before the 4.4 release.

@akien-mga akien-mga merged commit 2912cb9 into godotengine:master Sep 26, 2024
19 checks passed
@mihe mihe deleted the patch-exports branch September 26, 2024 10:47
@akien-mga
Copy link
Member

Thanks @mihe and @PoqXert for the great contribution! It's been a long time coming but it was worth the wait 🎉

@mihe
Copy link
Contributor Author

mihe commented Sep 26, 2024

Many thanks to @PoqXert for allowing me to supersede the original PR, despite having stuck with the original one for over two years now.

Hopefully we can get some more feedback now and dial in this feature further.

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

Successfully merging this pull request may close these issues.

Implement a patch system to generate PCK files with only the required data
6 participants