Skip to content

Extend template instantiation tool #1214

Closed
1 of 1 issue completed
Closed

Description

@wjt

A request from our learning team, building on #909:

User Story

  • When I copy a template folder (intro, outro, minigames),
  • I want to automatically duplicate all included files, subfolders, and referenced resources (e.g., .tres dialogue files, sprite frames, tile sets), with scenes relinked to these new copies,
  • So I can safely edit my own StoryQuest without breaking templates or the base game.

Requirements

Full duplication:

  • Copy the entire folder structure (intro, outro, 3 minigames)
  • As more mini-games are added, create the option to duplicate mini-games as a standalone process.
  • Include all nested subfolders and files.

Resource duplication:

  • Duplicate all resources referenced by those scenes: .tres files, sprite frames, tile sets, etc.

Resource relinking:

  • Ensure the new scenes point to their duplicated resources, not originals.
  • No references in the learner’s copy should remain tied to the template folder or base game files.

Naming & organization:

  • Place copies under a new learner-specific folder.
  • (Optional) support renaming all instances of “template” with a chosen StoryQuest name (not just removing the word “template” from the duplicated files).

Robustness

  • Learners should never need to manually rename or relink files.
  • The copied folder should be ready to open and edit immediately.

Activity

  1. added theissue type on Sep 18, 2025
  2. wjt commented on Sep 26, 2025

    @wjt
    MemberAuthor

    Resource duplication:

    • Duplicate all resources referenced by those scenes: .tres files, sprite frames, tile sets, etc.

    I think this would be easier to do if the resources were not saved as .tres files but saved as sub-resources of the scene ("make unique").

    The dialogue plugin doesn't support this for dialogue files, but I opened an upstream ticket about it nathanhoad/godot_dialogue_manager#979 and had an interesting discussion on the Godot Discord to try to understand how hard it would be.

  3. moved this from Untriaged to Todo in Threadbare Developmenton Oct 1, 2025
  4. self-assigned this
    on Oct 1, 2025
  5. moved this from Todo to In Progress in Threadbare Developmenton Oct 3, 2025
  6. moved this from In Progress to No status in Threadbare Developmenton Oct 3, 2025
  7. wjt commented on Oct 3, 2025

    @wjt
    MemberAuthor

    I'm trying to figure out if we can do something a little less ad-hoc than the current implementation.

    If you have a Resource (which can be a PackedScene) you can get a list of its external dependencies with ResourceLoader.get_dependencies(), which conceptually gives a list of tuples of (uid, "", path) (though the tuple is actually a string, "uid::::path", for reasons unknown).

    If you have a PackedScene you can look at its SceneState to find which of its child nodes are instances of other scenes with SceneState.get_node_instance().

    You can also traverse all the properties and check their values; which we could use to find other referenced resources such as SpriteFrames.

    Of course Godot doesn't know that cinematic.gd and collectible_item.tscn's next_scene properties are actually UIDs of other scenes so we'll have to special case them. Ditto Quest's first_scene.

    So here's my idea:

    • Start with the quest.tres file;
    • Recursively walk the graph of referenced resources, ignoring any that are not under res://scenes/quests/story_quests/NO_EDIT/
    • Flatten this out to a depth-first list in an order where each element only depends on elements earlier in the list
    • Make a dictionary duplicated mapping original UID to new UID
    • For each element in the list:
      • Duplicate it (which may mean copying the underlying file for .png files or .dialogue files, or using Resource.duplicate() for everything else
      • For resources, rewrite all references to other resources with the remapped UID from duplicated
      • Save this element
      • Update duplicated to map the old UID to the copy's UID
  8. moved this to In Progress in Threadbare Developmenton Oct 3, 2025
  9. wjt commented on Oct 14, 2025

    @wjt
    MemberAuthor

    The approach above does actually work!

    We made the decision that player.tscn's default sprite_frames should be the template. This actually makes the plugin harder to implement because when copying a scene, you have to recurse into the scenes it instantiates, even those that don't live in the template, to see if they reference something in the template.

    I wonder if we should revisit this; but not today.

  10. wjt commented on Oct 14, 2025

    @wjt
    MemberAuthor

    Actually after working out a few bugs, it's easy enough to support both cases. But I noticed that we are inconsistent: the throwing enemy scene's default sprite is the template, but the bucket default sprite is the one from the main game. We should probably be consistent one way or another. I'll file a followup.

  11. moved this from Done to In Progress in Threadbare Developmenton Oct 15, 2025
  12. reopened this on Oct 15, 2025
  13. linked a pull request that will close this issuePrefix quest files (not dirs) with quest name #1357on Oct 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions