Replies: 1 comment 1 reply
-
Here's a bag of discussions (1, 2, 3) from Discord, and my related issue (#2865).
Did you mean a content addressed store? I think we can align multiple stakeholders on this feature, as it will also be nice for RBE interop with |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Here is a summary of a discussion we had on Discord. I wanted to share my thoughts as a junior game dev on how VCS systems like Jujutsu could better address the unique challenges of game creation and the game dev industry as a whole. I've worked in small to mid-sized studios and know people who work in mid to large-scale studios. This is my humble attempt at bringing forward the unique use cases for VCS that I've been aware of and discussing
What makes game dev unique
Game development borrows tools from software development because the end product is indeed software, but the projects have entirely different needs regarding source control and collaboration. This is because game projects involve a wide variety of domains like art, programming, design, animation, sound, etc, which means various file types, tools, workflows, people, expertise levels, and team dynamics.
Most game projects are monolithic repos, and the game creation process revolves around maintaining a single source of truth at all times: the game's build. Not even the repo's head. I often say, "a feature is not finished until it's in the build."
Why is that? Because of the variety of domains involved, game development often leads to integration hell. Additionally, the software used to create games (game engines) is very complex for a myriad of reasons, one of them being that engines handle dynamic data through UIs. This means that what you see in the engine is often quite different from the final built game, which is what gets shipped to players. For example, the process of packaging assets can malfunction, causing assets to disappear or not render as they do in the engine. In multiplayer games, features might behave differently when tested locally in P2P connections, versus in a build through a P2P connection, versus in a built version with a dedicated server. Development builds, which often include cheat commands, can also behave differently from the final shipping build. The key takeaway is: game dev is 25% making new stuff and 75% integration hell.
Most in-development projects rely on a single source of truth (the build) and it is be the only base used for the next iterations.
One source of truth, but many different people with widely different workflows, installed toolchains, computer specs, and technical knowledge. Each person works on a specific subset of binary or text files. For example, in Perforce, there are "filters" that allow each team to pull only the relevant part of the repo, so for example programmers and designers don't have to pull the raw 3D models.
At certain stages of production or in specific types of games, there might be multiple "sources of truth," but they are all closely related to the main repository. In live games, for example, if an update is about to be released while other teams are adding content for future updates, a branch might be created from the main repo to stabilize the update. This branch becomes the "source of truth" for what is about to be delivered, while other teams continue working on future updates. Essentially, each team may need its own "source of truth" for their current work, which is challenging when working within a monorepo. I've seen cases where multiple features were developed simultaneously, but one team's changes ended up breaking another team's features.
Prototyping and testing features that might not be integrated into the final project is another area which is essential in a game's production, but where current VCS fall short. In the early stages, many prototype ideas must be tested, and these tests often cannot be cleanly separated from the main game systems. Additionally, these are not just one-person tests: they often require collaboration among multiple people and must be built and tested before a decision is made on whether to integrate them.
Usability problems I've encountered with existing VCS
For live games, branching was extremely difficult with Perforce. Integrating changes from the main repo into a release branch was risky, and some changes involving binary files in the release branch could hardly be merged back into the main branch. This difficulty arises because game engines often make many modifications to files, even when the content hasn't changed meaningfully. This is largely due to each engine's file indexing schema. For example, Unreal Engine creates hidden "File Redirectors" if you move a file within the project, which can cause significant issues. Even renaming a file can be risky. I guess jujutsu's ability to easily make changes to parent commits could make this easier, for example by removing the change that created the file and adding a new one that creates the same file but with a different name.
This means that if you want to merge modifications, say to a buggy VFX from the release branch to the main one, you will almost certainly face conflicts. These can be resolved, but doing so may mess up the engine's file indexing, breaking references in subtle ways. I'm aware this is more of an engine-issue than VCS issue, but that's one use case game developers have to frequently face.
File locking, like Perforce's "Checkout" feature, is useful, but making local changes to test your work is poorly managed by Perforce. If you want to make local changes to a file that a coworker has checked out, you have to click "Set as writable," which essentially makes it unwatched by Perforce. Later when you want to get the latest repo version or discard your changes, you must manually press "Reconcile Files" so that all files not being watched by Perforce are added to your changelist. Then, you need to revert all temporary files you don't want to stage and finally either overwrite, revert or integrate your local change. Iirc, if you locally marked a file as "writeable" and you pulled the latest version of the repo, Perforce would silently not pull the new version of the file and keep yours, which could simply break your local project without any clues on what happened.
Ideas for Solutions
Paradoxically, adding more conflicts to VCS might improve the situation. We need to generalize and rethink VCS merging strategies and conflict resolution methods. Making "conflicts" not just about file types but also about environment or project-specific conditions could be a good idea. We may need to rethink "what is a change" and "what is a conflict".
In modern VCS, for binary conflicts, you typically have two options: "keep theirs" or "keep ours." It would be helpful to have a third option, where you can retrieve the latest file from the repo and have the VCS automatically keep your version under a different name for manual merging or to keep for prototyping purposes. You can essentially do that with jj by going to the parent commit, rename your file and retrying to merge the remote I think.
jj's support for first-class conflicts is great, but in a game dev project, for any given conflicting change, you will likely need to resolve the conflict for each team member whose local state conflicts with the remote one. This is because the remote state of the repo rarely matches what you will have on your local machine. To fully and rigorously resolve a conflict, you'd need to ask everyone to commit their changes, push them to the remote, pull that and resolve the conflict on one machine, then send the resolution and have everyone pull the change. An example: I renamed a texture in Unreal Engine, no conflicts, works-on-my-machine™, sent to the remote, worked on everyone else's machine, but then the texture disappeared in the build. This happened because, while pulling through the interactive interface, we manually handled things in ways that didn't cause immediate problems, but a remote headless build server didn't handle it the same way.
Redirector files often get messed up because they don't handle renaming well. In these cases, the VCS should allow you to make a manual change (e.g., renaming the file) before pulling the remote file and marking the conflict as resolved.
In video games, file references are everywhere, and are mostly not plain text and dynamic, defined by users through UIs. This means that in the event of a conflict with a binary file, even if you rename your local file and pull the remote one, references will break, leading to significant hassle. Implementing a system to "group" files together or mark files as "dependent" on other ones could be a solution. This way, when pulling or resolving conflicts, even if the files themselves haven't changed on the remote, the VCS could mark them as conflicted because a dependent file has a conflict. This could be game-changing, and I'm not sure if any VCS currently does this.
Most of the solutions I proposed above boil down to one key concept and feature that I believe no VCS has : being able to define "what is a conflict" and "how do we resolve them". Let's imagine we could define "what is a conflict", and propose "conflict resolution pipelines". These "conflict definitions" could mark certain files as conflicting under certain conditions, even if we haven't locally changed the file. For example, renaming a blueprint in Unreal should be marked as a conflict, because we know it's a change that cannot meaningfully be integrated into the environment as-is. For each "conflict types", repo owners could propose "resolution pipelines". These pipelines could be shown to the user when a conflict occurs on a file, with a particular matching condition met (file type, naming schema, specific rules, etc.). The pipeline would propose one or multiple actions to resolve the conflict, defined by the repo maintainer, on top of the regular options. Users could choose which pipeline to use to resolve the conflict or resolve it themselves.
Use Case: I'm pulling a change where a binary file, e.g., an Unreal Blueprint, has been renamed. I haven't changed the file, but it's considered a conflict due to project-defined "conflict rules." My options for resolving the conflict are "keep theirs," "keep mine," "keep both," or "Resolve Rename," which runs a script that updates my project's redirectors and avoids problems.
Conclusion
Hope this can give you an insight on what problems game dev teams face regarding source control and collaboration and to start interesting discussions. It's a bit long, so here are some key takeaways:
Random ideas
Beta Was this translation helpful? Give feedback.
All reactions