<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Samuel Kahn</title>
    <description>The latest articles on DEV Community by Samuel Kahn (@kahncode).</description>
    <link>https://dev.to/kahncode</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F235424%2F927b93ee-15fe-40b8-8aa6-4d568bed6771.jpg</url>
      <title>DEV Community: Samuel Kahn</title>
      <link>https://dev.to/kahncode</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kahncode"/>
    <language>en</language>
    <item>
      <title>Best Source Control for game development: The Verdict</title>
      <dc:creator>Samuel Kahn</dc:creator>
      <pubDate>Fri, 08 May 2020 13:25:42 +0000</pubDate>
      <link>https://dev.to/kahncode/best-source-control-for-game-development-the-verdict-1504</link>
      <guid>https://dev.to/kahncode/best-source-control-for-game-development-the-verdict-1504</guid>
      <description>&lt;p&gt;&lt;em&gt;This is part of a &lt;a href="http://kahncode.com/category/source-control-comparison/"&gt;series of posts&lt;/a&gt; on source control for game development. Read more in the &lt;a href="http://kahncode.com/blog/"&gt;Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We have finally reached the end of this series trying to find the best source control for game development.&lt;/p&gt;

&lt;p&gt;If you have followed through all of the articles, the answer to your questions may still be unclear. Each solution has its pros and cons, many different pricing and hosting options. If you're a small team or an indie developer, you do not know what the future holds. Perhaps you'll sign a big publishing deal and need to scale rapidly with a larger budget, in which case your choices are changed once again.&lt;/p&gt;

&lt;p&gt;So, for the final article in this series, and perhaps the only one you should read, I'll try to provide an overview of our findings and provide simple guidelines to help you with your choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Available Options
&lt;/h2&gt;

&lt;p&gt;So far we've been studying in-depth 4 of the most popular source control options for game development.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="http://kahncode.com/2019/11/05/git-source-control-for-game-development/"&gt;Git&lt;/a&gt;, very popular outside of Games, but its regular downsides become showstoppers for game development at scale.&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://kahncode.com/2019/11/26/perforce-source-control-for-game-development/"&gt;Perforce&lt;/a&gt;, the game industry standard, very expensive but the best option for dealing with large and complex projects.&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://kahncode.com/2020/02/19/plastic-scm-source-control-for-game-development/"&gt;PlasticSCM&lt;/a&gt;, a very promising competitor to Perforce. Much better than SVN, but comes with a price tag.&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://kahncode.com/2020/04/29/svn-source-control-for-game-development/"&gt;Subversion (SVN)&lt;/a&gt;, a very solid option for small to medium projects, free and open-source.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why do I see those as being the most popular? Well, one indicator is that these are the 4 options included by default in Unreal Engine 4, for instance. Perforce seems to be the most commonly integrated source control among game engines, especially the proprietary ones that you're unlikely to get your hands on unless you're part of the company.&lt;/p&gt;

&lt;p&gt;That being said, there are other options we'll try to cover briefly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mercurial
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.mercurial-scm.org/"&gt;Mercurial&lt;/a&gt; is a Distributed Version Control System (DVCS for short) very similar to Git. It is written in Python and is an open-source project as well. Mercurial's data model, features, and functionalities are virtually identical to Git. This has caused sort of an internet feud over which system is superior, with each side trying to convince the other to no avail.&lt;/p&gt;

&lt;p&gt;Proponents of Mercurial argue that it is much better designed, and I generally tend to agree. In particular, Mercurial's command-line seems to be elegant and straightforward, using similar terms as subversion which makes learning Mercurial much easier than Git. There are other aspects that differentiate the two, most notably, while Git allows rewriting history through rebasing and several other commands, Mercurial's history is more immutable. For a full breakdown, these two articles from Atlassian summarize very well why &lt;a href="https://www.atlassian.com/blog/software-teams/mercurial-vs-git-why-mercurial"&gt;one&lt;/a&gt; would be better than the &lt;a href="https://www.atlassian.com/blog/git/git-vs-mercurial-why-git"&gt;other&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As with most DVCS, it requires a local copy of the history and therefore the same problems than we would have with Git would also apply. Mercurial seems to provide a solution for &lt;a href="https://www.mercurial-scm.org/wiki/LargefilesExtension"&gt;handling large binary files&lt;/a&gt;, and is considering a &lt;a href="https://www.mercurial-scm.org/wiki/LfsPlan"&gt;Git-LFS-compatible protocol&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mercurial is still very active and used today in &lt;a href="https://www.mercurial-scm.org/wiki/ProjectsUsingMercurial"&gt;open-source projects&lt;/a&gt; as well as large companies. The Wikipedia page lists &lt;a href="https://en.wikipedia.org/wiki/Mercurial"&gt;Facebook&lt;/a&gt; as one of the major users of Mercurial, and it is the common example thrown around when discussing Mercurial's adoption in the real world.&lt;/p&gt;

&lt;p&gt;However, it is undeniable that Git has won the popularity contest. With &lt;a href="https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket"&gt;Bitbucket shutting down support for Mercurial repositories&lt;/a&gt;, and now &lt;a href="http://kahncode.com/2020/04/15/github-is-free-for-teams/"&gt;GitHub private repositories being free&lt;/a&gt;, more and more projects are looking to migrate from Mercurial to Git, as indicated even by some projects still listed on Mercurial's page.&lt;/p&gt;

&lt;p&gt;For games, it seems that this is a poor option due to the lack of large file support, and the typical downsides of DVCS for non-mergeable files. I have, however, heard of some game projects using Mercurial, and would be very interested to hear some testimonies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unity Collaborate
&lt;/h3&gt;

&lt;p&gt;If you're using Unity for your game project, you may have heard of &lt;a href="https://unity.com/unity/features/collaborate"&gt;Unity Collaborate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unity Collaborate is an official Unity product and part of their &lt;a href="https://unity.com/products/unity-teams"&gt;Unity Teams&lt;/a&gt; offering. This seems to be a managed platform and service to host your project, run your continuous integration and automation. The &lt;a href="https://unity3d.com/get-teams"&gt;pricing&lt;/a&gt; is also very reasonable, especially considering there are 25GB of storage included.&lt;/p&gt;

&lt;p&gt;I haven't used Unity Teams myself, but it does seem quite similar to any of the &lt;a href="http://kahncode.com/2019/05/19/choosing-a-git-hosting-provider-for-game-projects/"&gt;cloud-hosting providers we already evaluated&lt;/a&gt; for Git. When compared to those, it also seems to lack in other features, such as project management tools, documentation tools, and so on.&lt;/p&gt;

&lt;p&gt;Unity Teams is also a black-box, and it seems that you can't access your repository in any other way than through the Unity Editor itself. As far as I know, Unity Collaborate actually runs on a Git-LFS backend, which makes it quite similar to &lt;a href="https://www.unrealengine.com/marketplace/en-US/product/git-central"&gt;GitCentral&lt;/a&gt;, but for Unity. However, I'd argue that having your entire project in a black-box system is not something you should feel comfortable with. There will be many opportunities where dealing with your source control from command-line or dedicated tools will be necessary, and as the project scales, I would be surprised if the Unity editor could handle the most extreme cases, especially since almost no dedicated source control GUI manages to do so. GitCentral, on the other hand, allows you to access the underlying Git-LFS repository directly, and deal with your project in any way you want.&lt;/p&gt;

&lt;p&gt;Unity Collaborate is still a good option for low-stakes projects, such as student projects and relatively simple projects. As soon as your project will scale or require specific features, you'll need more than the black-box can provide.&lt;/p&gt;

&lt;p&gt;I would still love to hear some testimonies about Unity Collaborate since I've never tried it myself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anything else?
&lt;/h3&gt;

&lt;p&gt;Well, this is where my knowledge ends. I haven't heard of any other viable solution, nor met game developers using any version control that was not on this list. As I mentioned in the &lt;a href="http://kahncode.com/2019/10/29/what-is-the-best-source-control-for-game-development/"&gt;introduction of this series&lt;/a&gt;, some people use systems that cannot be qualified as source control, such as Dropbox and other file repositories with some sort of versioning. But, since you should without any question be using source control, those options won't even be discussed here.&lt;/p&gt;

&lt;p&gt;If, however, you know of any other option you'd like me to look at, please reach out. I'll be very interested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison Matrix
&lt;/h2&gt;

&lt;p&gt;With all that said, let's put all of this research together and see if we can draw some conclusions.&lt;/p&gt;

&lt;p&gt;Please bear in mind that the assessments represent my subjective opinion after working with these tools in the context of game development. If we were talking about more traditional code projects, this table and the results would be very different. There are plenty of articles comparing source control for code projects if you need to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PZGPTvXf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aa1utg3qn8w5rdg172rc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PZGPTvXf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aa1utg3qn8w5rdg172rc.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;Unsurprisingly, the two most attractive options are Perforce and PlasticSCM. Both of these were designed for enterprise scenarios, very large projects, and a high number of collaborators. They were optimized to handle large binary files efficiently and provide great graphical tools and user experience. However, they are also the most expensive options.&lt;/p&gt;

&lt;p&gt;Git and SVN are both free and open-source. This makes them much more popular with the development community at large. While the basic package only contains the command-line tools, both Git and SVN are supported by a massive array of third-party tools, web applications, hosting providers, and integrations in almost anything you can think of.&lt;/p&gt;

&lt;p&gt;In my experience, your budget will be the main factor in the choice you make. This is why I've settled on the following ranking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Perforce:&lt;/strong&gt; If you can afford it, you cannot go wrong by choosing Perforce. It has been the industry standard for more than a decade, and for good reason. It does exactly what you need and you can easily work around its caveats.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;PlasticSCM:&lt;/strong&gt; A bold choice, but it can be worth it. PlasticSCM is constantly improving and I expect it to seriously challenge Perforce over the coming years. The price is affordable for most serious teams.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;SVN:&lt;/strong&gt; A classic for indie studios. SVN is free and allows you to spend a bit on your own hosting infrastructure rather than using the cloud providers. It will work well enough for small to medium-sized projects, and if your project grows larger, you should have money to spend to upgrade. &lt;strong&gt;For most readers, this is the right choice.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Git:&lt;/strong&gt; Certainly the most popular version control, its model simply doesn't fit the needs of game developers, where binary files and non-technical people concentrate the bulk of the action. I would not recommend Git unless you use &lt;a href="https://www.unrealengine.com/marketplace/en-US/product/git-central"&gt;GitCentral&lt;/a&gt;, or an equivalent. Note that if your project is using SVN, you can still use Git for your programming thanks to git-svn.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So there you have it. In my opinion, Perforce is still the best source control for game development. This is the one I've chosen for &lt;a href="http://darewise.com"&gt;Darewise&lt;/a&gt;, and we're very happy with it so far. I will continue to evaluate PlasticSCM periodically, as I feel it has a lot of potential.&lt;/p&gt;

&lt;p&gt;However, if your budget is tight, I'd strongly recommend to take a look at SVN. You can achieve similar results for a fraction of the price, and you'll be able to migrate to a better solution once your budget allows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;I put a lot of effort into this series. I researched the source control options I didn't use, learned about them and their ecosystem, browsed through mountains of documentation, and actually tried them out on a project to see how they behaved. It was a learning experience for me, and I hope it was interesting for you too.&lt;/p&gt;

&lt;p&gt;If you're reading this, thank you. I hope that it will help new game development teams to make the right choice on source control, which is arguably the most important technical choice to make after choosing a game engine.&lt;/p&gt;

&lt;p&gt;Feel free to contact me for comments, questions, new information, and ideas for improvements on this topic.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>productivity</category>
      <category>sourcecontrol</category>
      <category>git</category>
    </item>
    <item>
      <title>Subversion Source Control for Game Development</title>
      <dc:creator>Samuel Kahn</dc:creator>
      <pubDate>Thu, 30 Apr 2020 09:57:21 +0000</pubDate>
      <link>https://dev.to/kahncode/subversion-source-control-for-game-development-1dd2</link>
      <guid>https://dev.to/kahncode/subversion-source-control-for-game-development-1dd2</guid>
      <description>&lt;h1&gt;
  
  
  Subversion Source Control for game development 
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;This is part of a &lt;a href="http://kahncode.com/category/source-control-comparison/"&gt;series of posts&lt;/a&gt; on source control for game development. Read more in the &lt;a href="http://kahncode.com/blog/"&gt;Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We couldn't reach the end of this series without talking about a source control giant, I'm talking of course about &lt;a href="https://subversion.apache.org/"&gt;Subversion&lt;/a&gt; or SVN for short.&lt;/p&gt;

&lt;p&gt;Every programmer should have heard of Subversion. Its massive popularity from the 2000s until today has only been outshined by Git fairly recently. In the games industry, SVN remains a very popular choice due to being free and implementing the file-based source control model which maps so well to our needs, as outlined in the previous articles. While not a common choice in larger studios, smaller ones and indie teams have long been using SVN as their backbone and for good reason.&lt;/p&gt;

&lt;p&gt;Personally, I haven't used SVN since my early programming days, and never in my professional career. This article was a good opportunity to get familiar with it again and see how it competes against the other solutions we have studied so far.&lt;/p&gt;

&lt;p&gt;So, is SVN a good source control solution for game development? Let's dig in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Background and History
&lt;/h2&gt;

&lt;p&gt;Subversion was &lt;a href="http://svnbook.red-bean.com/en/1.7/svn-book.html#svn.intro.history"&gt;started in 2000&lt;/a&gt; as a replacement and improvement over &lt;a href="https://en.wikipedia.org/wiki/Concurrent_Versions_System"&gt;CVS&lt;/a&gt;, the most popular version control at the time. The main goal in designing Subversion wasn't to reinvent the wheel or a new source control model but to have a better CVS, without the bugs and the features deemed unnecessary or badly designed.&lt;/p&gt;

&lt;p&gt;Subversion has since then become a pillar of the software development world, overtaking CVS and becoming the standard for many years, both in the open-source communities and in the enterprise world. Subversion 1.5, in particular, was a major release that introduced highly needed features, most notably automated merge-tracking which is seen today as essential in a source control solution, as well as mirroring capabilities.&lt;/p&gt;

&lt;p&gt;In 2010, Subversion became part of the &lt;a href="https://www.apache.org/"&gt;Apache Software Foundation&lt;/a&gt;, one if not the most well-known organization maintaining large open-source projects. Apache now oversees the ongoing development and distribution of the rebranded Apache Subversion and is still looking for contributors to the project, in true open-source fashion. Recently, Subversion celebrated its &lt;a href="https://blogs.apache.org/foundation/entry/the-apache-software-foundation-announces58"&gt;20 years of existence&lt;/a&gt; and is arguably still the most widely used source control solution today.&lt;/p&gt;

&lt;p&gt;While it has certainly lost some of its popularity with more recent open-source projects in the age of GitHub, Subversion is used by many large open-source projects and in many organizations. Subversion doesn't benefit from a large platform such as GitHub, but it remains a robust and proven solution. Existing projects and organizations may not want to pay the cost of migrating, especially when the development community at large becomes more aware of the &lt;a href="http://kahncode.com/2019/11/05/git-source-control-for-game-development/"&gt;limitations of Git and DVCS&lt;/a&gt; they may have to contend with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;The official website lists the main &lt;a href="https://subversion.apache.org/features.html"&gt;features&lt;/a&gt; of SVN. Here we will go through what is relevant for us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Centralized source control
&lt;/h3&gt;

&lt;p&gt;SVN was designed as an improvement over CVS, which was centralized version control. Even though distributed version control existed at the time, a centralized model appears logical and simpler. Even in open-source projects, there is a central or "blessed" repository where the official releases emanate from. In enterprise projects, a centralized repository allows for better access control over the intellectual property stored in the version control system.&lt;/p&gt;

&lt;p&gt;The centralized is generally the way game development teams collaborate on game projects. This implies that, in order to share changes to others, you need to be connected to the central server. This should not be an issue in our day and age, but it does mean that you cannot easily work offline and keep a local version history. As we will see later, there are in fact workarounds to this issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  File-based model
&lt;/h3&gt;

&lt;p&gt;SVN uses a traditional file-based model to track changes. Each object has a revision number, and each change is tracked by a globally unique incrementing number. This is very similar to other version control systems such as Perforce, and is very easy to follow and understand, especially in comparison to Git's SHA hash-based revision identifiers.&lt;/p&gt;

&lt;p&gt;There are notable features of SVN's source control model that aren't commonly found in other. Directories are versioned as first-class objects, in the same way files are. &lt;a href="http://svnbook.red-bean.com/en/1.7/svn.advanced.props.html"&gt;Properties&lt;/a&gt; in the form of key-value pairs are versioned with each object (file or directory), which allows you to embed extra information, and potentially has creative uses.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://svnbook.red-bean.com/en/1.7/svn.branchmerge.using.html"&gt;Branching&lt;/a&gt; is done through the "copy" operation. This can sound strange at first, but a branch is, in fact, a copy of the entire repository in another directory. This is how most older source control systems operate with branches. Fortunately, there are series of commands that allow you to treat branches the same way you would in Git, and not have to actually maintain two directories with two versions of the project on your own machine. Internally, branches are managed using a &lt;a href="https://en.wikipedia.org/wiki/Copy-on-write"&gt;copy-on-write&lt;/a&gt; mechanism, so branches are not as costly as they may seem, and the cost of branching does not increase with the size of the data in the repository.&lt;/p&gt;

&lt;p&gt;Still, branching and merging is not as simple an operation as you may have gotten used to with Git. More importantly, branching is a server-side operation due to the centralized model of SVN. This means branches are visible to all users, and for that reason, managing branches is reserved for privileged users or administrators of larger repositories. Using feature branches for small development is usually not recommended, instead, you may use the &lt;a href="https://subversion.apache.org/docs/release-notes/1.10#shelving"&gt;shelving&lt;/a&gt; feature, which is similar to Git's stash.&lt;/p&gt;

&lt;p&gt;SVN has an interesting feature in the form of &lt;a href="http://svnbook.red-bean.com/en/1.7/svn.ref.properties.html"&gt;properties&lt;/a&gt;. Properties are key-value pairs that can be attached to any SVN object, such as a file, directory, or revision. SVN itself uses properties to implement some of its advanced behaviors and features, for instance, file-locking. You may also creatively leverage properties for anything required in your workflow, such as tagging certain files or using it for automation.&lt;/p&gt;

&lt;h3&gt;
  
  
  User experience
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Setup and administration
&lt;/h4&gt;

&lt;p&gt;Setting up SVN can be challenging for non-technical users. The &lt;a href="https://subversion.apache.org/"&gt;website&lt;/a&gt; and the documentation definitely have this old-school open-source look and feel, which could deter some people. The most complete documentation comes in the form of a &lt;a href="http://svnbook.red-bean.com/"&gt;free book&lt;/a&gt;, affectionately known as The Red Book, which is curated and kept up to date by the SVN community. You can consult the &lt;a href="http://svnbook.red-bean.com/en/1.7/index.html"&gt;HTML version&lt;/a&gt; directly on its website, and we will refer to it throughout this article.&lt;/p&gt;

&lt;p&gt;The first barrier of entry is that the Apache Foundation does not distribute binaries for subversion. You must &lt;a href="https://subversion.apache.org/download.cgi"&gt;download the sources&lt;/a&gt; and compile them yourself. They do, however, reference trusted &lt;a href="https://subversion.apache.org/packages.html"&gt;sources of binary packages&lt;/a&gt; for you to download the version that matches your OS. For most of us, this means Windows, and I'll recommend using &lt;a href="https://tortoisesvn.net/downloads.html"&gt;Tortoise SVN&lt;/a&gt; which also brings a very practical Windows Explorer contextual menu extension and a graphical user interface.&lt;/p&gt;

&lt;p&gt;While installing Tortoise SVN, don't forget to install the command-line tools. Without those, you won't really have SVN installed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--blrInBbY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_setup.png%3Fresize%3D495%252C387" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--blrInBbY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_setup.png%3Fresize%3D495%252C387" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you first create a SVN repository using Tortoise SVN, you will be asked if you want to use the default folder structure. This creates directories for &lt;em&gt;trunk, tags,&lt;/em&gt; and &lt;em&gt;branches&lt;/em&gt; which are pretty self-explanatory. You should use the standard folder structure to start with, as most of the tooling around SVN is configured to handle these by default. Of course, it is up to you to decide how you want to structure your repository, and where you want to store your branches. SVN offers you all the flexibility you need through the copy command, and those folders are merely a convention for the users to follow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wvD4LEF6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_repo.png%3Fresize%3D433%252C216" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wvD4LEF6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_repo.png%3Fresize%3D433%252C216" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Command-line
&lt;/h4&gt;

&lt;p&gt;SVN's command line uses terms and verbs that have come to be the standard vocabulary when talking about source control, and are understood by most. Most of the semantics we use for source control nowadays can be traced back to historical software, notably CVS, from which SVN takes most of its roots. This means SVN's command line is intuitive and easily understood, unlike Git's which introduces many new terms and confusing mechanics.&lt;/p&gt;

&lt;p&gt;All of the commands are well documented in the Red Book, and for the most part, I didn't have to consult the documentation much when operating on them. To get started quickly, you can learn the basics in a few minutes on the &lt;a href="https://subversion.apache.org/quick-start"&gt;official SVN website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All of the command-line output is designed both for human readability and for parsing by scripts and automation tools. On top of that, &lt;a href="http://svnbook.red-bean.com/en/1.7/svn.developer.usingapi.html"&gt;API bindings&lt;/a&gt; to several popular programming languages allow users to interoperate with SVN more efficiently and without having to start multiple processes and parse outputs.&lt;/p&gt;

&lt;p&gt;Overall, the command line takes some time to learn but it is relatively straightforward. The commands are single purpose and with a wealth of options, and the mental model of the source control repository is very simple to follow. Some commands have several logical (&lt;a href="http://svnbook.red-bean.com/en/1.8/svn.ref.svn.c.blame.html"&gt;or funny&lt;/a&gt;) aliases for convenience, so you should feel at home quickly no matter what other source control you may be used to.&lt;/p&gt;

&lt;h4&gt;
  
  
  Graphical User Interface
&lt;/h4&gt;

&lt;p&gt;The Apache Subversion project does not provide, maintain or endorse any Graphical User Interface. As is true with everything SVN, you will have to find your own tools to attach to the version control core. You can find a &lt;a href="https://en.wikipedia.org/wiki/Comparison_of_Subversion_clients"&gt;list of SVN clients&lt;/a&gt; on Wikipedia.&lt;/p&gt;

&lt;p&gt;In the context of writing this article, I have tried two popular SVN clients on Windows. They both provide graphical tools as well as a Windows Explorer contextual menu integration.&lt;/p&gt;

&lt;h5&gt;
  
  
  Tortoise SVN
&lt;/h5&gt;

&lt;p&gt;I've already talked about &lt;a href="https://tortoisesvn.net/downloads.html"&gt;Tortoise SVN&lt;/a&gt; before in the setup guide. Tortoise SVN has been popular for as long as I can remember and is fully free and open-source, released under GPL license.&lt;/p&gt;

&lt;p&gt;The main way to interact with Tortoise SVN is through the contextual menu integration. Right-click on any file or folder and the Tortoise SVN menu offers pretty much every possible action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W4_6vJca--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_menu.png%3Fresize%3D609%252C802" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W4_6vJca--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_menu.png%3Fresize%3D609%252C802" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, there is no Tortoise SVN integrated tool. Everything is done through the windows explorers and popup dialogs. Personally, I think this is a worse user experience, as I often want to see an overview of my repositories and rapidly get information over many things in my repository. On top of that, not all of the dialogs are created equal. They can differ in style and useability, and some are clearly more polished than others. For instance, the revision graph view could be made much more compact and user-friendly. Still, Tortoise SVN is very useable in its current form and will continue to be the workhorse of many developers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--59Ocreej--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_commit2.png%3Fresize%3D704%252C554" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--59Ocreej--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_commit2.png%3Fresize%3D704%252C554" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pdpnQ2iN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_log.png%3Fresize%3D737%252C612" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pdpnQ2iN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/04/tortoise_svn_log.png%3Fresize%3D737%252C612" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  SmartSVN
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://www.smartsvn.com/"&gt;SmartSVN&lt;/a&gt; is another Graphical User Interface that caught my eye. It seems to be from the same developers as &lt;a href="https://www.syntevo.com/smartgit/"&gt;SmartGit&lt;/a&gt;, a popular Git client.&lt;/p&gt;

&lt;p&gt;SmartSVN has a free version and &lt;a href="https://www.smartsvn.com/purchase/"&gt;a paid version&lt;/a&gt;. The free version contains only a &lt;a href="https://www.smartsvn.com/compare-editions/"&gt;subset of the features&lt;/a&gt;, and obviously the most advanced operations are left out.&lt;/p&gt;

&lt;p&gt;While SmartSVN also provides a contextual menu integration, it presents itself first and foremost as a standalone tool. Using SmartSVN feels very familiar coming from Perforce. The main view is a repository view where you can browse for all files and see their status. You can use the toolbar to perform all the main operations, such as Adding and Removing files, Updating, and Committing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1vdWZoeB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/04/smartsvn.png%3Fresize%3D1008%252C670" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1vdWZoeB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/04/smartsvn.png%3Fresize%3D1008%252C670" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can browse the &lt;a href="https://www.smartsvn.com/features/"&gt;full list of features&lt;/a&gt; on the SmartSVN website. There are important features only present in the paid version of SmartSVN:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Changesets, allowing one to separate modified files in several commits.&lt;/li&gt;
&lt;li&gt;  Merge and conflict resolution. Alternative and probably better tools are readily available for this.&lt;/li&gt;
&lt;li&gt;  Revision Graph, very useful to visualize changes of a file through branching and merging.&lt;/li&gt;
&lt;li&gt;  JIRA Integration, often useful in professional projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user experience of SmartSVN is, in my personal opinion, much better than that of Tortoise SVN, and the price could be well worth it. Alternatively, I'd consider using the free version alongside Tortoise SVN, command-line, as well as other tools. The paid version of SmartSVN seems to be the most advanced and well-integrated SVN client available at this time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Code review tool
&lt;/h4&gt;

&lt;p&gt;SVN does not come out of the box with a code review tool. There are several third-party &lt;a href="https://en.wikipedia.org/wiki/List_of_tools_for_code_review"&gt;options to choose from,&lt;/a&gt; some are free, and some others come at a premium.&lt;/p&gt;

&lt;p&gt;Out of all the tools listed, I would recommend looking at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.reviewboard.org/"&gt;Review Board&lt;/a&gt;, free and open-source. While lacking in features compared to paid competitors, it's done the job for many companies and I've used it myself professionally.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://smartbear.com/product/collaborator/overview/"&gt;Collaborator&lt;/a&gt;, probably my favorite code review tool, but the price is steep.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Diff and Merge tools
&lt;/h4&gt;

&lt;p&gt;SVN does not provide Diff or Merge tools out of the box either, outside of the command-line utilities.&lt;/p&gt;

&lt;p&gt;SVN can, fortunately, be configured to use an &lt;a href="http://svnbook.red-bean.com/en/1.7/svn.advanced.externaldifftools.html"&gt;external diff tool&lt;/a&gt;. You are free to choose yet again from a variety of options, free and paid. For those of you looking, here are some to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://meldmerge.org/"&gt;Meld&lt;/a&gt;, free and open-source, written in python. Well featured but sometimes slow.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.perforce.com/products/helix-core-apps/merge-diff-tool-p4merge"&gt;P4Merge&lt;/a&gt; is actually free, and this has been my workhorse for my entire career.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.semanticmerge.com/"&gt;SemanticMerge&lt;/a&gt; from the company behind PlasticSCM. A paid solution, but with unique features. I went in more detail about SemanticMerge in my &lt;a href="http://kahncode.com/2020/02/19/plastic-scm-source-control-for-game-development/"&gt;PlasticSCM breakdown.&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.scootersoftware.com/"&gt;Beyond Compare&lt;/a&gt;, a popular paid tool. I've also used this and enjoyed it, but I did not see enough benefit to warrant buying a license for myself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Useability for game development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Handling large projects
&lt;/h3&gt;

&lt;p&gt;SVN has proven time and time again to be dependable for game projects. Many independent studios have chosen SVN for their source control because of its price and file-based model. Therefore, we can safely say that by using SVN, you cannot go entirely wrong.&lt;/p&gt;

&lt;p&gt;However, it is also known that SVN has performance issues on larger repositories, and generally, this is the main argument its competitors, namely Perforce and PlasticSCM, use as the first real reason to consider switching. It's going to be very hard for me to evaluate SVN with a very large project that would recreate the enterprise conditions, so I can only take the testimonies at face value by saying: SVN is generally less performant than Perforce and PlasticSCM.&lt;/p&gt;

&lt;p&gt;Still, SVN handles binary files very well and its model should scale relatively well according to our use cases. Two lines on the &lt;a href="https://subversion.apache.org/features.html"&gt;features&lt;/a&gt; page stand out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Binary files handled efficiently.&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;Subversion is equally efficient on binary as on text files, because it uses a binary diffing algorithm to transmit and store successive revisions.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Costs are proportional to change size, not data size.&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;In general, the time required for a Subversion operation is proportional to the size of the changes resulting from that operation, not to the absolute size of the project in which the changes are taking place.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This should put you at ease when it comes to managing the binary files your game project will be filled with.&lt;/p&gt;

&lt;p&gt;SVN can be brought up to an enterprise level by leveraging several features and extensions, some built-in and some using third-party software and services. SVN has been successfully used in enterprise scenarios for many years, in fact, the &lt;a href="https://svnvsgit.com/"&gt;debate is still ongoing&lt;/a&gt; as to whether Git is really an improvement over SVN in many cases, and I tend to agree with some of the points made.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.visualsvn.com/server/"&gt;VisualSVN Server&lt;/a&gt; seems to be the most common server on offer, and it comes with multiple features useful for enterprises:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  ActiveDirectory / LDAP integration, which enables Access Control features&lt;/li&gt;
&lt;li&gt;  For globally distributed teams, offers the ability to replicate your repository on remote sites in write mode&lt;/li&gt;
&lt;li&gt;  Backup and restore policy&lt;/li&gt;
&lt;li&gt;  Logging and auditing features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;VisualSVN Server &lt;a href="https://www.visualsvn.com/server/licensing/"&gt;is unfortunately not free&lt;/a&gt;, though it seems to be the best enterprise SVN server available. Some of these features can be solved through other means, such as using &lt;a href="http://svnbook.red-bean.com/en/1.7/svn-book.html#svn.reposadmin.maint.replication"&gt;svnsync&lt;/a&gt; to create read-only copies of your repository, but then you'll have to manage them yourself.&lt;/p&gt;

&lt;p&gt;SVN also contains all the more advanced source control features you might need, for instance, you'll find an equivalent to Git's submodules in the &lt;a href="http://svnbook.red-bean.com/en/1.7/svn.advanced.externals.html"&gt;Externals&lt;/a&gt; feature of SVN. This really shines when you are managing multiple projects at once.&lt;/p&gt;

&lt;p&gt;There are also some more exotic tools that I found when doing my research. For example, &lt;a href="http://elixus.org/nightly/en/svk-book.html#svk.intro.whatis"&gt;SVK&lt;/a&gt; is an SVN client that adds more operations and allows for offline and decentralized workflow. I can't vouch for it as I haven't used it, but this goes to show that there is probably a solution out there for most of your SVN problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  File-locking
&lt;/h3&gt;

&lt;p&gt;File-locking is &lt;a href="http://svnbook.red-bean.com/en/1.7/svn.advanced.locking.html"&gt;fully supported by SVN&lt;/a&gt;. On top of the basic locking and unlocking features, SVN allows for a user to leave a message to explain why they locked a particular file, which is a surprisingly simple and useful addition that I haven't seen elsewhere.&lt;/p&gt;

&lt;p&gt;There are also ways to override locks when necessary. Of course, there are traditional administrator commands, but on top of that, SVN allows users to break and steal locks from other users. Of course, this is configurable and you may allow only privileged users to break locks instead of everyone. This can become useful when someone goes away for some reason while having the lock on a file, and you don't always have an administrator available to help.&lt;/p&gt;

&lt;p&gt;Finally, files can be tagged to require a lock, and SVN will automatically set the file mode to read-only when you don't have the lock. This works beautifully and avoids making mistakes and wasting time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ecosystem
&lt;/h2&gt;

&lt;p&gt;SVN has a long history and was very popular before the age of Git. Therefore, we should expect a great ecosystem that includes everything we need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrations
&lt;/h3&gt;

&lt;p&gt;SVN is well integrated with most typical development tools, such as IDEs and Continuous Integration tools. Here are some of the most useful for us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Visual Studio, the IDE you're most likely to use, has an up to date &lt;a href="https://marketplace.visualstudio.com/items?itemName=VisualSVNLimited.VisualSVN-VS2019"&gt;SVN integration&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://plugins.jenkins.io/subversion/"&gt;Jenkins&lt;/a&gt; and I'd expect most Continuous Integration tools.&lt;/li&gt;
&lt;li&gt;  Unreal Engine has &lt;a href="https://docs.unrealengine.com/en-US/Engine/Basics/SourceControl/SVN/index.html"&gt;first-class support&lt;/a&gt; for SVN, and the plugin is available out of the box when downloading the engine. Sadly, &lt;a href="https://docs.unity3d.com/Manual/ExternalVersionControlSystemSupport.html"&gt;Unity does not&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  Project management and bug tracking tools such as Jira also often support an &lt;a href="https://marketplace.atlassian.com/apps/291/subversion-integration-for-jira?hosting=server&amp;amp;tab=overview"&gt;SVN integration&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  Communication apps such as &lt;a href="https://www.google.com/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=2ahUKEwj8767C5PfoAhUMJhoKHaAEAMsQFjAAegQIBhAB&amp;amp;url=https%3A%2F%2Fslack.com%2Fapps%2FA0F827LTA-subversion&amp;amp;usg=AOvVaw0Q-SoU_nqntaDjIDSTdk0L"&gt;Slack&lt;/a&gt; or MS Teams.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SVN is almost as well supported if not better than Git. Of course, most modern software will aim to interoperate with Git before SVN these days, but there is more than enough to be happy with and to satisfy all of our workflow needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interoperability
&lt;/h3&gt;

&lt;p&gt;SVN used to be the ubiquitous source control, which makes it a prime target for competitors trying to convert users. Here are a few bridges between SVN and other source control software:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://git-scm.com/docs/git-svn"&gt;git-svn&lt;/a&gt;, an officially supported bidirectional integration between Git and SVN. You're most likely going to need this even if you use SVN as your primary repository since it's likely that you will need to collaborate with third-parties using GitHub.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.mercurial-scm.org/wiki/WorkingWithSubversion"&gt;HgSubversion&lt;/a&gt;, a bidirectional bridge with &lt;a href="https://www.mercurial-scm.org/"&gt;Mercurial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  Perforce provides a &lt;a href="https://www.perforce.com/resources/vcs/subversion-migration-toolkit"&gt;migration guide and toolkit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://blog.plasticscm.com/2015/09/moving-from-svn-to-plastic-scm-how-we.html"&gt;PlasticSCM&lt;/a&gt; recommends using git-svn and their own Git interoperability tools&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Hosting
&lt;/h3&gt;

&lt;p&gt;SVN has been around for a long time, and it is not surprising to see many providers of cloud hosting. Unfortunately, there isn't a hugely popular website setting the standard, so we'll have to dig ourselves to find the best options. Fortunately, Wikipedia contains a good &lt;a href="https://en.wikipedia.org/wiki/Comparison_of_source-code-hosting_facilities"&gt;overview of source control hosting&lt;/a&gt; we can start from.&lt;/p&gt;

&lt;p&gt;Here are some of the notable providers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://sourceforge.net/"&gt;SourceForge&lt;/a&gt;, one of the most well-known hosting providers for open-source projects. SourceForge offers both the project management backend and provides a landing and download page for the software for its users.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.assembla.com/pricing"&gt;Assembla&lt;/a&gt;, which is also the sole provider of cloud Perforce hosting, and can be considered a reliable hosting provider. The lower tier starts at $9.16/user/month for up to 5 users and 5GB of storage. Above this threshold, the price goes to $14.67/user/month with "500gb+" storage included.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.perforce.com/products/helix-teamhub/pricing"&gt;Helix TeamHub&lt;/a&gt; by Perforce. Free up to 5 users and up to 1Gb storage. The paid tier comes at a very low $19/user/&lt;strong&gt;year&lt;/strong&gt;, but still with a relatively limited storage capacity.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.cloudforge.com/pricing"&gt;Cloudforge&lt;/a&gt;, for $2/user/month, but the storage capacity is tied to the number of users. Higher tiers allow for more storage.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.phacility.com/pricing/"&gt;Phabricator&lt;/a&gt;, an open-source hosting provider platform. While it is $20/user/month for the cloud option, Phabricator is a very good choice to host internally to manage your projects and repositories.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://rhodecode.com/pricing"&gt;RhodeCode&lt;/a&gt; provides enterprise solutions starting at $8/user/month, with increasing costs depending on the hardware and storage capacity chosen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of these providers have been active for a long time, and it also shows on their website and their offers. On this front, SVN does not enjoy the modern luxury that Git hosting has become. The user experience and features of the above are most likely not up to par. More importantly, neither is the pricing model, especially in light of &lt;a href="http://kahncode.com/2020/04/15/github-is-free-for-teams/"&gt;GitHub's recent pricing updates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That being said, this is not such a big issue if you're considering SVN for your game development project. Any of these solutions will give you a server with high availability, and that is all you really need. You can use other tools for project management if your hosting provider's platform does not meet your needs. For smaller teams, you should be fine using those.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;SVN is free and open-source. However, source control for game development can never be completely free.&lt;/p&gt;

&lt;p&gt;You will have to host your project in a shared location, either on the cloud or on-premises. We touched on the cost of cloud hosting before. Of course, you may host SVN yourself on your own hardware, or using public cloud instances. The costs and maintenance involved can vary widely to be as expensive as you make it: hardware purchase and maintenance costs, backup and restore strategy, network infrastructure, and so on... It is up to you to find the best solution for your team size, configuration, and most importantly, your budget.&lt;/p&gt;

&lt;p&gt;In comparison to its competitors in our study, SVN is the second cheapest source control for game development. Its cloud hosting options are more expensive than Git, but there are no license costs of any kind. For the budget game developer, and considering the technical &lt;a href="http://kahncode.com/2019/11/05/git-source-control-for-game-development/"&gt;limitations of Git for game development&lt;/a&gt;, it appears to be the cheapest, and therefore the best choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Subversion is a robust and proven software. It was once the dominant source control solution and remains very competitive to this day. It is free and open-source, still being maintained, and has an active ecosystem, even in the age of Git. I would love for SVN to have a more visible roadmap, as the &lt;a href="https://subversion.apache.org/roadmap.html"&gt;current one&lt;/a&gt; doesn't provide much information. Some versions of SVN benefit from Long Term Support which is good news and a strong guarantee for you if you're starting today.&lt;/p&gt;

&lt;p&gt;While the bulk of the software industry has moved on to the next shiny thing, SVN remains a very relevant source control for game development. Why? Its file-based model is exactly what we need, and its handling of binary files is only surpassed by expensive proprietary software such as Perforce or Plastic SCM.&lt;/p&gt;

&lt;p&gt;SVN's flaws come mostly from its open-source legacy and its age. Much like Git, SVN is only the command-line core of the source control and does not provide the full package of tools and integrations a user will need on a day-to-day basis. Unlike Git, the tools and web services that are part of the SVN ecosystem aren't up to the latest standards of user experience and design. You will, therefore, have to research and choose for yourself which tools to use on top of SVN, and you may allow each of your team members to go with what fits them best.&lt;/p&gt;

&lt;p&gt;But this is mostly cosmetic, and while cosmetics matter very much to some, it should not be the most important aspect for you if you're in business for a source control solution for your game development project. Price and features are the primary axes of comparison, and on that front, SVN is by far a better solution than Git. If your budget allows, then probably PlasticSCM or Perforce would offer either more features or more performance. For independent developers, it is often not worth the cost, and it explains why SVN has found a niche there.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We're reaching the end of the in-depth studies in this series. In the final article, I will try to reach a conclusion from all the learnings, and a summary for those of you who are still (but rightfully) confused.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>productivity</category>
      <category>sourcecontrol</category>
      <category>svn</category>
    </item>
    <item>
      <title>Plastic SCM Source Control for Game Development</title>
      <dc:creator>Samuel Kahn</dc:creator>
      <pubDate>Mon, 24 Feb 2020 20:43:52 +0000</pubDate>
      <link>https://dev.to/kahncode/plastic-scm-source-control-for-game-development-30gg</link>
      <guid>https://dev.to/kahncode/plastic-scm-source-control-for-game-development-30gg</guid>
      <description>&lt;h1&gt;
  
  
  Plastic SCM Source Control for game development 
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;This is part of a &lt;a href="http://kahncode.com/category/source-control-comparison/"&gt;series of posts&lt;/a&gt; on source control for game development. Read more in the &lt;a href="http://kahncode.com/blog/"&gt;Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.plasticscm.com/"&gt;Plastic SCM&lt;/a&gt; is a lesser-known source control solution for game development. In fact, I expect that a lot of the readers will be hearing about it for the first time. I personally discovered it only a few years ago. So why is it worth an article in this series?&lt;/p&gt;

&lt;p&gt;Well, Plastic SCM promises a lot: Plastic SCM brands itself as &lt;a href="https://www.plasticscm.com/games"&gt;"the version control for games"&lt;/a&gt;, and promises to deliver all the &lt;a href="http://kahncode.com/2019/11/05/git-source-control-for-game-development/"&gt;benefits of Git&lt;/a&gt;, as well as all the &lt;a href="http://kahncode.com/2019/11/26/perforce-source-control-for-game-development/"&gt;speed and power of Perforce&lt;/a&gt;, enterprise-grade features and support, unparalleled user experience, and unique features on top of that!&lt;/p&gt;

&lt;p&gt;In fact, I was so excited by the product that I decided to evaluate it when I started &lt;a href="https://darewise.com/"&gt;Darewise&lt;/a&gt;, and back then I was very impressed. So let's jump right in and see how it looks like today!&lt;/p&gt;

&lt;h2&gt;
  
  
  Background and History
&lt;/h2&gt;

&lt;p&gt;According to &lt;a href="https://en.wikipedia.org/wiki/Plastic_SCM"&gt;wikipedia&lt;/a&gt;, Codice Software, the company behind Plastic SCM, started in 2005 to create a commercial version control system that would be better than SVN, a benchmark at the time. The first version of Plastic SCM was released in October 2006, and several major versions have been released since.&lt;/p&gt;

&lt;p&gt;One of the notable points to note from the history of Plastic SCM is that Plastic SCM 4.0 changed the source control model from a per-file model to a per-changeset model. This is interesting for us because, as we have noted previously, the per-file model is usually preferred for games, at least when it comes to not enforcing the entire workspace to be up to date before being allowed to commit.&lt;/p&gt;

&lt;p&gt;Plastic SCM 4.0 is also the version that allowed Plastic SCM to better interoperate with Git, as well as a notable focus of the product on game development.&lt;/p&gt;

&lt;p&gt;Another big focus of Plastic SCM and its side products is the focus on better diff and merge tools. One of the major axis of improvement is the ability to understand the code better and track methods as they are moved within a file or from a file to another. This should raise a few eyebrows for programmers as better diff and merge tools are always a great addition to our toolset.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;a href="https://www.plasticscm.com/download"&gt;current version&lt;/a&gt; of Plastic is version 8.0.x which receives several &lt;a href="https://www.plasticscm.com/download/releasenotes/"&gt;updates every month&lt;/a&gt;. Plastic SCM is clearly being actively maintained and improved, and that can only be a good sign.&lt;/p&gt;

&lt;p&gt;As you can see if you dig through the website and the release notes, Codice employs a cheeky tone in their communication which is refreshing, and this makes the product all the more appealing to me. It feels like a tool by devs, for devs, and a dream come true when looking at the &lt;a href="https://www.plasticscm.com/features"&gt;list of features&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;Before you dig deeper, or if you want the short story, here is a &lt;a href="https://www.plasticscm.com/comparisons"&gt;SCM comparison matrix&lt;/a&gt; from Plastic SCM showing its strengths, but also drawing a fairly good picture. Perhaps I'll make a matrix of my own at the end of this series.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed and centralized
&lt;/h3&gt;

&lt;p&gt;Plastic SCM is the only source control that is truly both &lt;a href="https://www.plasticscm.com/games/scenarios/distributed-teams"&gt;distributed&lt;/a&gt; and &lt;a href="https://www.plasticscm.com/games/scenarios/centralized-development"&gt;centralized&lt;/a&gt;. Plastic SCM is architectured around a client-server model, and each installation of the Plastic SCM client is paired with a local server. The beauty of this model is that there is virtually no difference in behavior or workflow when working against the local server or a remote server.&lt;/p&gt;

&lt;p&gt;Here are the typical use cases you may perform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Create repositories on your local server and work on them as easily as you would on any distributed SCM such as Git.&lt;/li&gt;
&lt;li&gt;  Work on a repository located on a remote server.&lt;/li&gt;
&lt;li&gt;  "Pull" from a remote repository, which transfers public branches of that repository to your local server, allowing you to work locally on your own copy of the repository.&lt;/li&gt;
&lt;li&gt;  Maintain private branches and history of your own changes on your local copy of the remote repository.&lt;/li&gt;
&lt;li&gt;  "Push" your changes or a branch from your local server to the remote server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KNR4IjKF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-multi-site.png%3Fresize%3D540%252C414" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KNR4IjKF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-multi-site.png%3Fresize%3D540%252C414" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As discussed in previous articles, game development is a centralized effort, and it is most important that your version control is optimized for a centralized workflow. In this instance, Plastic SCM's primary model is always client-server, and therefore the centralized workflow is seamless and very efficient. You are also not required to use your local server at all, and you may avoid storing any redundant information locally, avoiding the typical Git issues and saving hard-drive space and download time.&lt;/p&gt;

&lt;p&gt;You can easily combine distributed and centralized workflow in creative ways depending on your needs. Typically, programmers will enjoy the benefits of a distributed workflow to allow them to have private branches and history they do not wish to share. Less technical people will work directly against the central server, which is used as the single source of truth.&lt;/p&gt;

&lt;p&gt;In fact, all of the common &lt;a href="https://www.plasticscm.com/games/scenarios/game-engine-development"&gt;game development scenarios&lt;/a&gt; are covered: common repository for the engine but separate game projects, fully centralized or fully distributed, The combination of distributed and centralized setups elegantly solves most of the common collaboration issues, but everyone must be using Plastic SCM. If you're working with third-party companies, this is still unlikely.&lt;/p&gt;

&lt;p&gt;Ideally, you will need to automate the pushes and pulls from the replicas to the master to achieve seamless multi-site setups. Plastic SCM also provides &lt;a href="https://www.plasticscm.com/games/scenarios/optional-proxies?term=proxy"&gt;proxy servers&lt;/a&gt; for multi-site teams, but recommend using the distributed workflow instead, which doesn't suffer if the connection between the sites is interrupted. Where Perforce provides specific products to solve multi-site issues, Plastic SCM's distributed model appears like a more elegant solution and allows you to truly set up a multi-site infrastructure easily by using familiar elements of your regular workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Changeset model
&lt;/h3&gt;

&lt;p&gt;Plastic SCM changed its history model to a per-changeset model. This is closer to how Git presents the history. Each changeset is a collection of file changes, and changesets are presented in a tree-like hierarchy. Unlike Git, changesets are identified by an incremental number, and this makes it much more understandable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CoBPfG_L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic_branch_explorer.png%3Fresize%3D831%252C513" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CoBPfG_L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic_branch_explorer.png%3Fresize%3D831%252C513" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this is &lt;a href="http://blog.plasticscm.com/2018/02/why-checkin-asks-to-update-first.html"&gt;more modern than the older-generation per-file model&lt;/a&gt;, for us it could be an issue as we pointed out in our &lt;a href="http://kahncode.com/2019/11/05/git-source-control-for-game-development/"&gt;evaluation of Git&lt;/a&gt;. We do not want to have to download all the latest changes to submit a single file. Fortunately, Plastic SCM allows you to filter which files you are downloading using the cloaked files list. The other option is their Gluon tool, and we'll see how well it integrates into a typical game development workflow later in the article.&lt;/p&gt;

&lt;p&gt;One of the main advantages of this approach is extremely easy branching, but also faster merging. And talking about the merge engine, &lt;a href="https://www.plasticscm.com/mergemachine"&gt;Plastic SCM's is very good&lt;/a&gt;. While they claim it's better than Git at merging complex cases, the reality is that this is hard to test and you may find that it works better or worse depending on your merge cases. I certainly didn't have many issues and most complex merges seemed to resolve beautifully. This means time gained both in raw performance but also manual work for merges. In this aspect, Plastic SCM wins over Perforce in both speed and reliability of the merge engine.&lt;/p&gt;

&lt;h3&gt;
  
  
  User experience
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Setup and administration
&lt;/h4&gt;

&lt;p&gt;Plastic SCM's first-time user experience is very pleasant. Download and &lt;a href="https://www.plasticscm.com/documentation/administration/plastic-scm-version-control-administrator-guide#Chapter3:PlasticSCMinstallation"&gt;install like a regular program&lt;/a&gt;, and it just works! The &lt;a href="https://www.plasticscm.com/documentation"&gt;documentation&lt;/a&gt; is very complete and will guide even the most non-technical users through all the steps.&lt;/p&gt;

&lt;p&gt;Administrating the server is done through a mix of a &lt;a href="https://www.plasticscm.com/documentation/administration/plastic-scm-version-control-administrator-guide#Chapter6:webadmin-Serverconfigurationandadministration"&gt;web interface&lt;/a&gt;, &lt;a href="https://www.plasticscm.com/documentation/administration/plastic-scm-version-control-administrator-guide#Chapter16:Configurationfiles"&gt;configuration files&lt;/a&gt;, and executing commands from the GUI client or the command line. Again, it is surprisingly straightforward and doesn't involve a steep learning curve.&lt;/p&gt;

&lt;p&gt;Even advanced administration procedures that can be scary in other systems seem to be simpler here. For backup, simply stop the server and backup a specific set of files, copy them back for restore. Although the initial setup is as simple as it gets, there is a wealth of configuration available to fine-tune the behavior, performance, access, and automation that you would expect from an enterprise version control system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hgcaa9la--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-webadmin.png%3Fresize%3D971%252C661" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hgcaa9la--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-webadmin.png%3Fresize%3D971%252C661" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When evaluating Plastic SCM for the first time, I was blown away by the experience. After you register for evaluation, you are immediately offered a very thorough &lt;a href="https://www.plasticscm.com/evaluation-guide/"&gt;evaluation guide&lt;/a&gt; complete with test repositories to play with. On top of that, you are invited to a free webinar with one of the developers who will personally show you how to use the software and answer your questions. You even get a free t-shirt if you complete the guide, although I didn't apply for it in the end, so I can't confirm it actually works!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rlybBVj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-evaluation.png%3Fresize%3D569%252C370" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rlybBVj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-evaluation.png%3Fresize%3D569%252C370" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I can remember though, is the impressive amount of support I received during and after the evaluation, as a non-paying customer. All of my emails and questions were answered quickly by the development team, and when I challenged certain design decisions or explained the reasoning behind us choosing Perforce, they became very eager to understand and hear my thoughts. Several very productive exchanges ensued via e-mail, conference call and discussions at game conferences. All I can say is: the devs behind Plastic SCM are truly interested in our user stories and solving our real-life problems, and it shows throughout the entire product.&lt;/p&gt;

&lt;h4&gt;
  
  
  Command-line
&lt;/h4&gt;

&lt;p&gt;Version control always starts at the command-line, and Plastic SCM is no exception. The command-line tools are well-designed and well &lt;a href="https://www.plasticscm.com/documentation/cli/plastic-scm-version-control-cli-guide"&gt;documented&lt;/a&gt;. There are in total less than 30 commands that provide enough options, alongside a concise syntax. The result is a very intuitive and fairly powerful command-line utility. The &lt;a href="https://www.plasticscm.com/documentation/cmfind/plastic-scm-version-control-query-system-guide#%22cmfind%22"&gt;find command&lt;/a&gt; is a good example of an elegant and powerful command, which beats &lt;a href="https://git-scm.com/docs/git-log"&gt;Git log&lt;/a&gt; in every way.&lt;/p&gt;

&lt;p&gt;During my evaluation time, I didn't find any operation that would be difficult or impossible to perform using the command-line. Perhaps more surprisingly, I didn't find myself using the command-line as much as I expected, and that is thanks to all the graphical tools provided, where Plastic SCM really shines.&lt;/p&gt;

&lt;h4&gt;
  
  
  Graphical User Interface
&lt;/h4&gt;

&lt;p&gt;Plastic SCM clearly aims to be user-friendly. It provides not one, but two graphical applications in order to solve the learning curve problem of version control. The main tool Plastic GUI, is fully featured, while the other, Gluon, is specifically tailored for game development artists and their specific workflow. Both tools are supported on Windows, Mac and Linux for maximum compatibility.&lt;/p&gt;

&lt;p&gt;The main &lt;a href="https://www.plasticscm.com/documentation/gui/plastic-scm-version-control-gui-guide#Chapter1:IntroductiontotheGraphicalUserInterface"&gt;Plastic GUI&lt;/a&gt; is comparable to P4V and is similarly featured. You can perform all the operations from there without using the command-line. The main panels are a file browser, a view of the pending changes (&lt;a href="https://www.plasticscm.com/features/transparent-scm"&gt;detected automatically much like Git&lt;/a&gt;), and the ability to browse the history, labels, and shelves at the click of a button. You can also perform all of the administrative commands on your repositories from the client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VZVHidPf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-gui.png%3Fresize%3D1008%252C600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VZVHidPf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-gui.png%3Fresize%3D1008%252C600" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On top of this, Plastic provides a full suite of powerful tools you may have come to expect. There is a very graphical branch explorer to visualize the branching and merge history of the repository. This is extra powerful as you can use this view on a single file or directory, allowing you to filter and visualize the history in the most visual and intuitive way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--atJTi4Gx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-branchExplorer.png%3Fresize%3D1008%252C429" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--atJTi4Gx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-branchExplorer.png%3Fresize%3D1008%252C429" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The annotate view, which is similar to &lt;a href="https://git-scm.com/docs/git-blame"&gt;git blame&lt;/a&gt;, allows you to see who last changed a particular line. A time-lapse view would have been excellent, but this will do.&lt;/p&gt;

&lt;p&gt;Overall the Plastic GUI is great. There are still reports of some minor bugs and the occasional crash, but it hasn't been an issue for me.&lt;/p&gt;

&lt;p&gt;The most annoying thing, in my opinion, is its tab and window management. There are things that only open as windows that you would rather have as tabs and vice versa. It also creates a new tab for almost every view, rather than reusing them. Again this has both pros and cons, but the result is that working on a repository will quickly end up with way more tabs than you can manage. I'd love for them to improve on that front by adding, for instance, the ability to pin tabs, to force certain tools to always populate the same tab, and to detach and dock tabs and windows freely.&lt;/p&gt;

&lt;p&gt;Finally, as a power user, I'd love to have a log window much like P4V, where I can track all the commands issued by the GUI and the resulting console output. This helps you by keeping a history of your recent actions and comes very handy when debugging source control related issues.&lt;/p&gt;

&lt;h4&gt;
  
  
  Code review tool
&lt;/h4&gt;

&lt;p&gt;Plastic SCM comes bundled with a full &lt;a href="http://blog.plasticscm.com/2019/10/improving-new-plastic-code-review-part-ii.html"&gt;code review suite&lt;/a&gt;! Without having to install and configure an extra tool, you can review changes and even establish complex workflow rules out of the box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o8vSj9z8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic_code_review.jpg%3Fresize%3D753%252C463" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o8vSj9z8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic_code_review.jpg%3Fresize%3D753%252C463" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The review tool is fairly well featured, but you may find that you require more control and configuration as you scale. It allows you to review changesets that have been shared on the central server. In other words, reviews happen post-commit. This is fairly typical in distributed workflow with per-task branches, but an option to be able to review shelves would have been nice. Reviews can also easily be tied to automation, for instance, a completed review may be automatically merged into the common branch.&lt;/p&gt;

&lt;p&gt;While not perfect, it is very impressive to have it included at no extra cost.&lt;/p&gt;

&lt;h4&gt;
  
  
  Semantic Diff and Merge tools
&lt;/h4&gt;

&lt;p&gt;Naturally, Plastic SCM provides a &lt;a href="https://www.plasticscm.com/features/xmerge"&gt;diff tool and a three-way merge tool&lt;/a&gt;. However, there is more than meets the eye here.&lt;/p&gt;

&lt;p&gt;In parallel, Codice is working on a standalone product called &lt;a href="https://www.semanticmerge.com/"&gt;Semantic Merge&lt;/a&gt;, which doesn't simply analyze text differences. It performs additional static analysis which allows you to track changes not just as lines added and removed, but as functions moved, symbols renamed, and follow changes even across multiple files.&lt;/p&gt;

&lt;p&gt;In my eyes, this is a true breakthrough in programming tools. Using this, it is much easier to visualize what happened during a refactor, rather than deduce it from textual difference. The semantic engine is already very powerful, and hopefully will get better over time, as more and more diff tools take this direction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---hMUvWKQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-analyze-refactors.png%3Fresize%3D1008%252C863" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---hMUvWKQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-analyze-refactors.png%3Fresize%3D1008%252C863" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lately, Plastic SCM has been &lt;a href="https://www.plasticscm.com/features/semantic-version-control"&gt;bundled with&lt;/a&gt; the semantic diff and merge capabilities, so that every diff view within the main Plastic GUI benefits from this engine. You don't need to buy a license for Semantic Merge separately anymore. This is simply amazing!&lt;/p&gt;

&lt;p&gt;Semantic diff and merge are available for selected programming languages. There is &lt;a href="https://www.semanticmerge.com/features/"&gt;official support&lt;/a&gt; for C++, C, C#, Java, and PHP, with the ability to create &lt;a href="https://users.semanticmerge.com/documentation/external-parsers/external-parsers-guide.shtml#Usefullinks"&gt;custom parsers to support more languages&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Gluon
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.plasticscm.com/documentation/gluon/plastic-scm-version-control-gluon-guide"&gt;Gluon&lt;/a&gt; is a tool designed for users working on a single branch on binary files that can't be merged, using exclusive locking. It also allows you to choose and download only the files you require, as well as share your changes on one file at a time. Thanks to exclusive locking, you will never have to deal with merging or conflicts. This is exactly what's needed for the bulk of game development. It seems Gluon was developed in close collaboration with Telltale and the result is impressive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q3yKL2QK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/02/gluon-private-folder.png%3Fresize%3D986%252C597" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q3yKL2QK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2020/02/gluon-private-folder.png%3Fresize%3D986%252C597" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gluon has a very simplified user interface. After creating your workspace, you can perform the following operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Configure which files and folders you want to work on&lt;/li&gt;
&lt;li&gt;  Update to the latest changes&lt;/li&gt;
&lt;li&gt;  Checkout and exclusively lock one or multiple files&lt;/li&gt;
&lt;li&gt;  Checkin changes&lt;/li&gt;
&lt;li&gt;  View file history and diff between revisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it! Gluon is exactly what the artists and less technical people need. It has all the features you would find in a basic file explorer integration, yet it also adds the necessary features of day to day workflow, without adding complexity. It is very easy to learn as there are only a few buttons and options. The main selling point is that it lifts the restrictions on having to download all the changes to check in a single file. This is great when working on very large art repositories where you are only likely to work on a few files at a time.&lt;/p&gt;

&lt;p&gt;As a matter of fact, I'd love to see a Gluon equivalent for Perforce, and while &lt;a href="http://kahncode.com/gitcentral/"&gt;GitCentral&lt;/a&gt; is essentially the same for Git, it's only accessible from within Unreal Engine and not as a standalone application.&lt;/p&gt;

&lt;p&gt;There are some edge cases in which Gluon gets stuck. You generally have to discard your changes, or perform a manual operation with Plastic GUI to resolve the issue. It shouldn't happen often but it's worth noting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useability for game development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Handling large projects
&lt;/h3&gt;

&lt;p&gt;Plastic SCM was famously &lt;a href="https://www.gamasutra.com/view/news/286064/Sponsored_How_Telltale_Games_handles_version_control.php"&gt;used by Telltale Games&lt;/a&gt;, which should reassure you that shipping world-class game projects with Plastic SCM is possible. Codice Software has been using Telltale as its main showcase for game studios before Telltale tragically &lt;a href="https://en.wikipedia.org/wiki/Telltale_Games#Majority_studio_closure_and_aftermath_(2018%E2%80%932019)"&gt;closed doors&lt;/a&gt;. Besides that, there are only a few game studios using Plastic SCM that I know of. At the very least, even if there is not widespread adoption, Plastic SCM has proven to work for &lt;a href="https://www.plasticscm.com/games/success-stories"&gt;a number of studios&lt;/a&gt;, which warrants our interest and pushes us to dig deeper. Therefore, let's examine the features of Plastic SCM that support large-scale projects.&lt;/p&gt;

&lt;p&gt;Performance is clearly a focus of the development teams. There are numerous blog articles and &lt;a href="https://www.plasticscm.com/under-heavy-load"&gt;benchmarks&lt;/a&gt; available which focus on the optimization of a particular feature, sometimes with &lt;a href="https://www.plasticscm.com/games/performance/performance-results-of-plastic-scm"&gt;comparison to competing products&lt;/a&gt;. Some recent client optimization around multithreading and process management allowed them to push the performance even further, as they shared some numbers privately with me.&lt;/p&gt;

&lt;p&gt;Adding to that, the database backing Plastic SCM can be configured to fit your needs. Interestingly, the Jet storage is a &lt;a href="https://forum.plasticscm.com/topic/20600-jet-vs-different-database-backends/"&gt;special-purpose&lt;/a&gt; storage built for Plastic SCM, and now the default. It supposedly &lt;a href="https://www.plasticscm.com/documentation/administration/plastic-scm-version-control-administrator-guide#Chapter8:Repositorystorageconfiguration"&gt;performs 3 to 5 times better&lt;/a&gt; than any of the other SQL backends offered, but you may still confirm that by yourself. Jet also has a "high scalability" mode that further increases performance for large repositories, but this is only available in the Enterprise version.&lt;/p&gt;

&lt;p&gt;Finally, for enterprise networks and intercontinental data transfer, Plastic SCM supports a &lt;a href="https://www.plasticscm.com/games/performance/high-latency-network"&gt;specific network protocol&lt;/a&gt; based on UDP which performs much better than TCP. I've seen studios build custom data transfer tools for this reason, so this should be very interesting for large publishers.&lt;/p&gt;

&lt;p&gt;There are also some advanced features that really shine in larger organizations. Component-based development using &lt;a href="https://www.plasticscm.com/documentation/xlinks/plastic-scm-version-control-xlinks-guide"&gt;Xlinks&lt;/a&gt; is almost essential and very well integrated. There more configuration and automation of the workspace than you would expect. You may achieve remarkably &lt;a href="https://www.plasticscm.com/download/releasenotes/5.4.6.535"&gt;advanced tricks&lt;/a&gt; such as moving, renaming mounting directories locally while keeping the repository structure intact.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access control and Security
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.plasticscm.com/features/security"&gt;Access control&lt;/a&gt; and permissions are very easy to configure through the web interface and the Plastic GUI client. The permissions are granular enough to allow almost everything you could want. You can create group permissions to easily manage a large number of users. You can also integrate with LDAP or Active Directory as you'd expect from an enterprise product.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7ymwGXHo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-permissions.png%3Fresize%3D826%252C593" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7ymwGXHo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-permissions.png%3Fresize%3D826%252C593" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Security is enabled through SSL connections and file encryption. As a bonus, you can easily audit your server where errors and destructive actions leave a paper trail.&lt;/p&gt;

&lt;h3&gt;
  
  
  File-locking
&lt;/h3&gt;

&lt;p&gt;Plastic SCM provides file-locking out of the box. You can configure which files must be locked, as well as who can perform the operation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xnyouB59--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/gluon-john-workspace.png%3Fresize%3D1008%252C644" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xnyouB59--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/gluon-john-workspace.png%3Fresize%3D1008%252C644" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's simple and straightforward until you start working with branches. A file is locked globally on the repository, and not on a per-branch level. This makes it impractical to use in typical scenarios. For example, when you stabilize a build, you usually create a separate branch in which more fixes can be committed. However, if someone works on the same file in the development branch, you won't be able to lock the file in the stabilization branch. In this case, since you probably did not intend to merge back, you would have never had a conflict, and this workflow should be allowed. The only workaround available is to create a separate repository for stabilization, which is of course, not ideal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Full and partial workspaces
&lt;/h3&gt;

&lt;p&gt;Now, there is one caveat of Plastic SCM that I always have some trouble with. There are two GUIs, there are two sets of commands, and there are in fact two types of workspaces. A regular Plastic SCM workspace functions similarly to a Git workspace. It is synchronized with a specific changeset and may contain some local changes. A partial workspace is a Gluon workspace, in which you choose the files that are downloaded, and each file may be synchronized at a different changeset and may be committed individually.&lt;/p&gt;

&lt;p&gt;This might seem logical, but becomes a problem in practice. Artists and designers will almost exclusively use Gluon and will be fine. Programmers and technical users, however, will require Plastic GUI and its advanced features. This doesn't mean they necessarily want to forego the per-file workflow when dealing with large binary assets such as the content of a game project.&lt;/p&gt;

&lt;p&gt;It's not as bad as it sounds. Plastic GUI and Gluon will happily open a workspace and make the best of its current state. Gluon can mostly deal with Plastic workspaces, as they contain more information than the partial workspace would. In the worst case, you can resolve any blockers by discarding your changes. However, the Plastic GUI will require you to update your workspace to a changeset before being able to commit again. This may involve conflict resolution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fJZ8pMf0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-mixed-workspace.png%3Fresize%3D412%252C147" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fJZ8pMf0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2020/02/plastic-mixed-workspace.png%3Fresize%3D412%252C147" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This forces programmers to stick to the Plastic GUI (per-changeset) workflow and avoid using Gluon altogether. For other team members, such as technical artists, it may not be so simple, as their usage of Plastic SCM is usually occasional.&lt;/p&gt;

&lt;p&gt;It is an annoyance, but not a dealbreaker. Ideally, both workspace types would be fully compatible with one another. As a second choice, you could configure files and folders in a repository to be restricted to the per-file workflow. This, in fact, would solve the issue entirely. I tried several tricks using two repositories and mounting one workspace inside another to achieve this result, but I could not work around all the issues. It seems clear from the recent updates of Plastic SCM that "mixed-mode" workspace support is high on the priority list. Let's hope to hear some good news in the near future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ecosystem
&lt;/h2&gt;

&lt;p&gt;Naturally, we expect Plastic SCM to have a smaller ecosystem than the major solutions such as Git of Perforce. However, when taking a closer look, Plastic SCM seems to have everything you need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrations
&lt;/h3&gt;

&lt;p&gt;You can find a &lt;a href="https://www.plasticscm.com/company/technology-partners#plastic-scm-also-integrates-with-many-third-party-tools"&gt;list of official integrations&lt;/a&gt; on the website. The most notable integrations are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Project management tools, in particular, the popular tools of Atlassian as well as &lt;a href="https://www.mantisbt.org/"&gt;Mantis&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  Developer tools, especially Visual Studio which everyone is likely to be using for games.&lt;/li&gt;
&lt;li&gt;  Continuous Integrations tools, such as &lt;a href="https://github.com/PlasticSCM/jenkinsplug"&gt;Jenkins&lt;/a&gt; and TeamCity.&lt;/li&gt;
&lt;li&gt;  Communication tools are not mentioned on the page, but an example of Slack integration is &lt;a href="https://github.com/PlasticSCM/slackplug"&gt;shared on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of that, there are deep integrations in major commercial game engines. The &lt;a href="https://www.plasticscm.com/unity-plugin"&gt;Unity plugin&lt;/a&gt; is available with paid editions of Plastic SCM. The &lt;a href="https://www.plasticscm.com/unreal-engine-plugin"&gt;Unreal Plugin&lt;/a&gt; was developed by a &lt;a href="https://github.com/SRombauts/UE4PlasticPlugin"&gt;coworker&lt;/a&gt; and friend of mine, in collaboration with Epic and Codice. It is now bundled with Unreal Engine by default. During my time evaluating Plastic SCM I tried using the Unreal integration and for the most part, it was functional and well integrated. There are definitely some edge cases especially as a programmer who plays with both Gluon and Plastic GUI. The Unreal integration seems to work with Plastic workspaces in most simple scenarios, but it works best using Gluon workspaces, as Unreal's workflow is almost identical to Gluon's.&lt;/p&gt;

&lt;p&gt;For continuous integration, Plastic SCM features the &lt;a href="https://www.plasticscm.com/mergebot-devops"&gt;mergebots&lt;/a&gt; which enable deeper integration and automation with external systems. For instance, you can use mergebots to &lt;a href="http://blog.plasticscm.com/2018/09/add-mergebot-to-your-repo.html"&gt;automate merging a feature branch&lt;/a&gt; when the code review has been completed, or create merge queues to avoid the competing merge issues that can famously arise on graph-based source control. Think of mergebots as a powerful server-side trigger system to allow you to create and customize your workflow to your needs, and remove manual steps, especially manual merge actions which can be complex and time-consuming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interoperability
&lt;/h3&gt;

&lt;p&gt;Plastic SCM interoperates natively with Git, Perforce and TFS. However, there is a definite focus on the &lt;a href="https://www.plasticscm.com/features/plasticscm-for-git-users"&gt;Git interoperability&lt;/a&gt; through various key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.plasticscm.com/documentation/gitserver/plastic-scm-version-control-gitserver-guide"&gt;Git Server&lt;/a&gt;: Every Plastic SCM server is also a Git server to which git clients can connect. When enabled, Plastic SCM repositories can be accessed as if they were Git repositories using a Git client.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.plasticscm.com/documentation/gitsync/plastic-scm-version-control-gitsync-guide"&gt;Git Sync&lt;/a&gt;: A protocol allowing to perform distributed workflow operations (push/pull) against a Git repository not hosted on the Plastic server. For instance, you could use Git Sync to work seamlessly on a Git repository hosted on GitHub. This is great if you find Git's user experience complex, as Plastic is much more artist-friendly.&lt;/li&gt;
&lt;li&gt;  Plastic SCM now supports the &lt;a href="https://git-scm.com/docs/git-fast-import"&gt;Git fast-import&lt;/a&gt; format which is the de-facto standard for source control import and export. This allows for easy migration from another version control system to Plastic SCM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This remarkable Git interoperability is not without its caveats. Plastic SCM does not have an equivalent to the &lt;a href="https://git-scm.com/book/en/v2/Git-Branching-Rebasing"&gt;Git rebase&lt;/a&gt; which allows you to rewrite your history in a more coherent form before sharing it. Rebase and fast-forward merges are therefore prohibited. It also relies on specific naming conventions and other little gimmicks which should be fine as long as you use it mostly as a read-only replica of the central Plastic SCM server.&lt;/p&gt;

&lt;p&gt;The bigger issue remains, Git's properties still make it unwieldy for game projects filled with large binary files. To my knowledge, GitSync does not implement Git-LFS. The GitSync replicated repositories will need to contain the entire history of the binary files, which pretty much prevents using it on a large project. The same goes for cloaked files in Plastic SCM, which do not have equivalent in Git. If you use Plastic SCM primarily, you will probably fare better by avoiding the Git interoperability features unless they are required. That being said, it can have one very practical application: you can use Plastic SCM as your central repository even when contributing to external GitHub projects, which are commonplace nowadays even when collaborating with proprietary software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting
&lt;/h3&gt;

&lt;p&gt;Codice provides an option for cloud hosting of Plastic SCM repositories with all of the different versions of the software. There is a specific &lt;a href="https://www.plasticscm.com/plasticscm-cloud-edition"&gt;cloud edition&lt;/a&gt; priced at $6.95/user/month which includes 5 GB storage space but is limited to teams of 15 members.&lt;/p&gt;

&lt;p&gt;Here is the &lt;a href="https://www.plasticscm.com/plasticscm-cloud-edition/pricing"&gt;full pricing breakdown&lt;/a&gt; when increasing storage space. A 100 GB server will cost you $19.95/user/month on top of the basic license fee if you are using the Team or Enterprise edition. As you scale, it may be worth considering moving to your own hosting solutions.&lt;/p&gt;

&lt;p&gt;Plastic SCM is, of course, made to be self-hosted on beefy hardware for enterprise needs. In this case, you will have to factor in the cost of purchasing and maintaining the hardware over time, which can be significant. Another option is to use &lt;a href="https://stackoverflow.com/questions/22646859/hosting-plastic-scm-on-amazon"&gt;public cloud instances&lt;/a&gt; to host your Plastic SCM server. This gives you more control over the hardware and the storage space, but also requires technical knowledge to set up, administer, and has an operational cost that may not be easy to forecast for novices.&lt;/p&gt;

&lt;p&gt;While Plastic SCM doesn't have as many cloud hosting providers as Git does, the cloud edition is fairly priced and serves as a good starting point. It is assumed that, as your needs and budgets grow, you will move into more enterprise-like hosting solutions, and Plastic SCM comes with all the necessary features to support it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;Plastic SCM is commercial software and therefore must be licensed. There is a &lt;a href="https://www.plasticscm.com/pricing"&gt;tiered pricing model&lt;/a&gt; that targets different types of teams with different offerings. We already discussed the cost of data storage on cloud-hosted servers, so let's focus here on the licensing costs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Plastic SCM is free for open-source software and non-profit. It is also free for individuals and hobbyists. Those versions come with a limited feature set focusing on the core source control. In particular, you may not use the Gluon GUI or the Unity plugin.&lt;/li&gt;
&lt;li&gt;  For small teams that don't fit in the above category, there is a cutoff at 15 users. You can choose between the cloud-hosted version ($6.95/user/month + storage costs) or the self-hosted version ($9.95/user/month).&lt;/li&gt;
&lt;li&gt;  Finally, the enterprise version allows you to scale above 15 users and adds the enterprise features such as LDAP/Active Directory integration and the high-performance storage and network features you are likely to need on very large projects. The full version is priced at $23.25/user/month, which makes it quite affordable overall, and certainly more affordable than its main enterprise competitor: Perforce.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to this tiered pricing, Plastic SCM can be affordable for many types of teams. When comparing the feature set with its competitors and taking the price into account, it is a very compelling offer. In particular, smaller teams with lower budgets may find that Plastic SCM has all of the features they need for a fraction of the budget and favor Plastic SCM over Perforce. Price was, in fact, the main reason why I evaluated Plastic SCM against Perforce when starting Darewise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Plastic SCM is an amazing suite of tools, backed by an impressive and dedicated team at Codice Software. I would like to personally congratulate them for a great product.&lt;/p&gt;

&lt;p&gt;There is a lot to love here: a huge and complete list of features, great UX and performance, one of the best Git interoperability, enterprise features ... but perhaps the thing that stands out the most is the amazing team behind Plastic SCM and the support that they are eager to provide. I would like to thank them again for their availability and openness during all of my interactions with them.&lt;/p&gt;

&lt;p&gt;I've evaluated Plastic SCM twice now: once when starting Darewise, once again today. I was expecting to write the same notes as previously, but instead, it's amazing how much more there is to say, two years later. Most of my original points have been addressed, or are on the right track. There is a long list of new features and improvements at every level. Plastic SCM seems more viable than ever, supporting both Programmer and Artist workflow elegantly and providing solutions to all the typical situations you will find yourself in as a game developer, no matter your profile. It tries to combine the best features of Git and Perforce in one coherent solution, and it's not far from hitting the mark!&lt;/p&gt;

&lt;p&gt;For enterprise users, Plastic SCM is more affordable than its main competitor, Perforce, but the choice is still not clear-cut and it will be up to every team to decide. I encourage every game studio to evaluate Plastic SCM hands-on, as they may be pleasantly surprised. While it is expensive to migrate ongoing projects, it could be a very reasonable option for upcoming ones. Old habits die hard and it may be a long road before game developers widely adopt a new tool, especially of such importance as version control. I've heard of a few studios trying Plastic SCM only to switch back to Perforce recently, and it's hard to know what were their reasons. Others, who came from Git and SVN are &lt;a href="https://www.youtube.com/watch?v=SGPleVfrPyo&amp;amp;feature=youtu.be&amp;amp;t=1674"&gt;adopting Plastic SCM&lt;/a&gt; to overcome their hurdles. As for me, I am impressed but there are a few remaining obstacles. I would like to see resolved before seriously considering it for my professional projects.&lt;/p&gt;

&lt;p&gt;For smaller and newer teams, it's a very different story. Plastic definitely beats Git and other free solutions for game development and should be within their financial reach. The time gain alone will be well worth the price, as non-technical team members will be operational in minutes and rarely get stuck.&lt;/p&gt;

&lt;p&gt;I'd love to hear more testimonials of developers with Plastic SCM, whether good or bad, as I expect this article will need revision in the coming years.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the next article, we will take a look back at an open-source source control that used to be the gold standard and still stands the test of time, I'm talking of course about SVN.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>productivity</category>
      <category>sourcecontrol</category>
      <category>plasticscm</category>
    </item>
    <item>
      <title>Perforce Source Control for game development</title>
      <dc:creator>Samuel Kahn</dc:creator>
      <pubDate>Mon, 24 Feb 2020 20:40:58 +0000</pubDate>
      <link>https://dev.to/kahncode/perforce-source-control-for-game-development-if0</link>
      <guid>https://dev.to/kahncode/perforce-source-control-for-game-development-if0</guid>
      <description>&lt;h1&gt;
  
  
  Perforce Source Control for game development 
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;This is part of a &lt;a href="http://kahncode.com/category/source-control-comparison/"&gt;series of posts&lt;/a&gt; on source control for game development. Read more in the &lt;a href="http://kahncode.com/blog/"&gt;Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Perforce is the most widely used source control solution for game development studios.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://darewise.com/"&gt;Darewise&lt;/a&gt;, we evaluated many options and finally opted for &lt;a href="https://www.perforce.com/"&gt;Perforce&lt;/a&gt;, much like the rest of the game industry, or at least those who can afford it. Pretty much all major AAA studios, and medium to large teams are using Perforce as their main source control, so there must be some valid reasons behind this choice. I have personally used Perforce in every single one of my professional projects. I have worked primarily with workflow issues and source control, so this is a product I know very well and I might be slightly biased towards it.&lt;/p&gt;

&lt;p&gt;In the previous article, I explained why &lt;a href="http://kahncode.com/2019/11/05/git-source-control-for-game-development/"&gt;Git is not the most optimal&lt;/a&gt; source control solution for game development. This time, let's examine why is Perforce so popular.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background and History
&lt;/h2&gt;

&lt;p&gt;According to &lt;a href="https://en.wikipedia.org/wiki/Perforce"&gt;wikipedia&lt;/a&gt;, Perforce (the company) was started in 1995 with its first product being the eponymous Perforce (the source control solution). The goal was to provide a system allowing companies to keep track of changes in large projects containing both source code and binary files. This already sounds interesting to us.&lt;/p&gt;

&lt;p&gt;Perforce went through a few branding (mis)adventures as the years went by. I still remember its slogan being "the fast source control". Later, the company was bought and more products were added over the years to compliment the source control. These days the official branding for the source control product is "Helix Core", but in my heart and for this article, we will still refer to it as Perforce.&lt;/p&gt;

&lt;p&gt;As stated on the &lt;a href="https://www.perforce.com/solutions/version-control"&gt;official website&lt;/a&gt;, Perforce focuses on security, managing binary artifacts, performance at scale and teams distributed globally. They also claim that 19 out of 20 game development studios are using Perforce. While this claim is hard to verify, in my experience this is true when it comes to medium to large teams. In fact, I do not know of any sizeable studio not using Perforce.&lt;/p&gt;

&lt;p&gt;On their officially disclosed &lt;a href="https://www.perforce.com/customers"&gt;list of customers&lt;/a&gt;, you can find Perforce is used by major game studios. EA, &lt;a href="https://www.perforce.com/case-studies/vcs/ubisoft"&gt;Ubisoft&lt;/a&gt;, Epic, Capcom, Crytek, &lt;a href="https://www.perforce.com/case-studies/vcs/cd-projekt-red"&gt;CD Projekt Red&lt;/a&gt; just to name a few.&lt;/p&gt;

&lt;p&gt;Microsoft famously maintains (or maintained?) a fork of Perforce called &lt;a href="https://devblogs.microsoft.com/oldnewthing/20180122-00/?p=97855"&gt;Source Depot&lt;/a&gt;. This was used notably for the Windows repository, which has now been &lt;a href="https://twitter.com/GabeAul/status/846189637945110528"&gt;migrated to Git&lt;/a&gt;, but they could only achieve this incredible feat after creating &lt;a href="https://github.com/microsoft/VFSForGit"&gt;VFS for Git&lt;/a&gt; (previously called GVFS). This shows how much effort was necessary to adapt Git to handle as much as Perforce could.&lt;/p&gt;

&lt;p&gt;Perforce has a history of being successfully used on large projects and by reputable companies. Some are migrating away after massive engineering efforts, others like the game industry are sticking with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;Perforce is packed full of features and I'm still discovering some of them. Let's go over the main points.&lt;/p&gt;

&lt;h3&gt;
  
  
  Centralized source control
&lt;/h3&gt;

&lt;p&gt;Game development is at its core a centralized effort. Everyone needs to collaborate on the same project and be allowed to change it and receive updates as fast as possible.&lt;/p&gt;

&lt;p&gt;Where open source leverages the distributed model to make up for a lack of trust, game development projects are most likely comprised of people trusting each other to work in a central repository. The only really interesting part of the distributed workflow is evident for programmers: the ability to create commits and branches which are only on your local machine and are not shared with everyone. This is great for programmers working on several features at the same time, amongst other things.&lt;/p&gt;

&lt;p&gt;Perforce is often criticized for a lack of decentralized workflow, even though it provides several tools for it. The most basic tool is &lt;a href="https://www.perforce.com/manuals/p4v/Content/P4V/files.shelve.html"&gt;shelving&lt;/a&gt; which is the equivalent of Git stashes. I will agree that it is mostly a workaround, and feels lackluster after using Git for a while. However, Perforce does, in fact, have a decentralized option called &lt;a href="https://www.perforce.com/manuals/dvcs/Content/DVCS/Home-dvcs.html"&gt;DVCS&lt;/a&gt;. This works in command-line in a similar way to Git and has recently been added to the P4V client. Unfortunately, not many people know or use DVCS, so let's hope this article gets the word out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Changelists and per-file versioning model
&lt;/h3&gt;

&lt;p&gt;Each change in Perforce is grouped together into a &lt;a href="https://www.perforce.com/perforce/doc.051/manuals/p4guide/07_changelists.html"&gt;Changelist&lt;/a&gt;. A changelist is a list of files, their revision numbers and the operations performed on each file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_changelist.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--654gBD7B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_changelist.png%3Fresize%3D697%252C625" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each changelist is given a unique incremental number. This makes it very easy to understand which change precedes or follows another. The number is unique on the entire Perforce server, even if you have multiple projects. In fact, one changelist can theoretically contain files from multiple projects, although I would not encourage you to do this often.&lt;/p&gt;

&lt;p&gt;The change model is also per-file. While each changelist is a collection of changes, each file has a history with incremental revision numbers. Again, this is clear and easy to follow, as opposed to git's object model and commit hashes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_history2.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Kfo17J9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_history2.png%3Fresize%3D1008%252C229" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's more, your workspace does not need to be up to date with every single file when submitting a changelist. You only need to be up to date with the files you are planning to change. This means you can iterate much faster than Git, especially when dealing with many large files in a game project. However, this also means your workspace may not be in a fully working state, as some of your files are up to date while others may not be. In practice, this is not as big of an issue as it sounds, you can easily synchronize your workspace to a specific changelist, or more frequently the latest change, when a problem arises with your workspace. As you don't have to sync so often, your iteration time is increased.&lt;/p&gt;

&lt;p&gt;The branching model of Perforce is not as simple as Git's. Since each file is versioned independently, branches are performed at a file-level and are harder to visualize when looking at the big picture.&lt;/p&gt;

&lt;p&gt;In the past, working on several branches was cumbersome and required the creation of a new folder on your hard drive. Since the introduction of &lt;a href="https://www.perforce.com/video-tutorials/vcs/what-perforce-streams"&gt;streams&lt;/a&gt;, you can easily switch branches within the same folder, as you do with Git. On top of that, streams formalize the branching workflow by enforcing which files belong to which branch and controlling how you can integrate or copy from one branch to another, at a granular level. This is great because your guidelines are present in the tool rather than simply by convention, which helps avoid human error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i0.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_streams.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--di1AboMn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_streams.png%3Fresize%3D727%252C598" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Large project support
&lt;/h3&gt;

&lt;p&gt;Perforce puts the accent on performance when handling large files. This is evident in all of their communication and can be verified in practice. Storing and retrieving files is fast, especially if you are hosting your server on-premises.&lt;/p&gt;

&lt;p&gt;On top of that, Perforce provides &lt;a href="https://www.perforce.com/manuals/p4dist/Content/P4Dist/chapter.concepts.html"&gt;multiple solutions&lt;/a&gt; to allow geographically distributed teams to work together more efficiently. You can use basic caching proxies and read-only replicas, all the way to a network of "edge" servers that act as your local server and ensure eventual consistency with the master. This, combined with enterprise-grade networks and bandwidth, allows large organizations to work around the world on a centralized repository. Of course, setting up such an infrastructure involves massive costs as well as constant maintenance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i0.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_edge.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cxfiPh_M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_edge.png%3Fresize%3D621%252C309" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another key enterprise feature is the integration with LDAP or Active Directory for user management, as well as the myriad of &lt;a href="https://www.perforce.com/manuals/p4sag/Content/P4SAG/protections.set.html"&gt;access control&lt;/a&gt; options to restrict access in all kinds of way. Large organizations can, therefore, use a single Perforce infrastructure for all of their projects while maintaining the security and confidentiality of their data. Additionally, Perforce can be configured to use the SSL protocol for greater security.&lt;/p&gt;

&lt;h3&gt;
  
  
  User experience
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Command-line
&lt;/h4&gt;

&lt;p&gt;For programmers and advanced users out there, Perforce provides a command-line interface. Having used it for years, I can say for certain that it is very well designed, consistent, easily understood, very powerful and &lt;a href="https://www.perforce.com/manuals/cmdref/Content/CmdRef/Home-cmdref.html"&gt;very well documented&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When compared to Git and the criticism I emitted in the previous article, it's night and day. Perforce's command line is almost intuitive in its design and has remained very stable over the years. This has made my job easier when integrating Perforce in our automation systems or in various game engines in my career, where updates to the Perforce client or server rarely if ever require code changes. There are a few subtle issues that experienced users will eventually run into, but they are very minor inconveniences in practice, and Perforce's command line is a joy to use.&lt;/p&gt;

&lt;h4&gt;
  
  
  Graphical User Interface
&lt;/h4&gt;

&lt;p&gt;This is where things get interesting. Perforce ships with &lt;a href="https://www.perforce.com/products/helix-core-apps/helix-visual-client-p4v"&gt;P4V&lt;/a&gt;, the official a graphical client for Perforce and the only one worth mentioning. This is one of the biggest differentiating factors, as Perforce has always put emphasis on user experience especially for less technical users. One of the major arguments for the adoption of Perforce against other solutions is P4V.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4v.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rTlxQC2g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4v.png%3Fresize%3D1008%252C618" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's be honest, this is source control and it can never really be trivial to use, so there is a bit of a learning curve, but it is my personal opinion that P4V is the best source control GUI bar none.&lt;/p&gt;

&lt;p&gt;For beginner users, it intuitively presents the file tree of the local workspace and the remote repository, provides basic functionality such as showing the history of a file or a directory, organizing your changelists and of course submitting your changes. This means non-technical users will never have to see or use the command-line. The same can't be said for most competitors.&lt;/p&gt;

&lt;p&gt;For power users, it is a fully-featured Perforce client that can perform almost all the tasks you will ever need in practice. In fact, as a very experienced Perforce user and administrator, I rarely have to use the command line. I can perform complex queries over the files and the history and visualize all of the results in very well designed tools. With the administrator GUI, I can perform the most regular administrator tasks such as creating and managing my users and groups. The only time where I really need the command line is to perform complex and unfrequent server configuration or maintenance.&lt;/p&gt;

&lt;p&gt;Here are some of the most advanced tools which don't have equivalents elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revision Graph:&lt;/strong&gt; Easily visualize and follow the changes and integrations of a file. This is similar to visualizations of a Git branching tree, except it only shows you the evolution of a file which is often more useful in practice and lacking in Git interfaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i1.wp.com/kahncode.com/wp-content/uploads/2019/11/p4v_revision_graph.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--daO_tzJD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2019/11/p4v_revision_graph.png%3Fresize%3D1008%252C618" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time-Lapse View:&lt;/strong&gt; The most useful of them all. This is git blame on steroids. It allows you to browse a file and see for each line who was the last person to edit it, just like git blame. However, you can also scroll through time! Using this tool, you can follow a line and see the surrounding context evolve with revisions. You can quickly and easily understand how some code came to be, and when appropriate, blame the right person for their mistakes. The attempts to &lt;a href="https://github.com/JonathanAquino/git-time-lapse-view"&gt;replicate this tool for Git&lt;/a&gt; still have a long way to go before they reach the same efficiency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4v_time_lapse_view.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xPp8Gb59--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4v_time_lapse_view.png%3Fresize%3D1008%252C592" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;P4V is certainly not perfect, and Perforce development teams are releasing improvements and updates on a regular basis. What I would like to address here is the common belief that Perforce's user interface is difficult to handle. Those complaints often come from non-technical people who don't have a lot of experience with source control and find the core concepts confusing. However, I have not encountered a better graphical tool to handle source control than P4V so far. The concepts are daunting at first, but once understood, P4V allows you to efficiently manipulate them. I would be interested, of course, in knowing your opinion on this, but ultimately this is a tool that has been proven to work in real-life situations. Even the less technical minded artists and designers end up learning and understanding enough to work with it and they do get over the initial pain. In fact, the reputation of having a bad UX probably comes from not having been presented with the alternatives. That's not to say that UX of source control software cannot be improved further, but this is almost as good as it gets in 2019.&lt;/p&gt;

&lt;h4&gt;
  
  
  Merge tool
&lt;/h4&gt;

&lt;p&gt;If all of this wasn't enough, Perforce also maintains and distributes a &lt;a href="https://www.perforce.com/products/helix-core-apps/merge-diff-tool-p4merge"&gt;free diff and merge tool: P4Merge&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_merge.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_9DAt5kT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2019/11/p4_merge.png%3Fresize%3D1008%252C667" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is, of course, included and well-integrated with P4V, but it is available for anyone to use. It is one of the better diff and merge tools out there, and includes most of the features you'd expect. It is easy to use and consistent with the other tools from Perforce. As an architect and today a CTO, you can trust me on the fact that I have performed a lot of very complex integrations using many different source control solutions and setups. For all of those, I have been using P4Merge and still do to this day.&lt;/p&gt;

&lt;p&gt;I have seen some people prefer &lt;a href="https://www.scootersoftware.com/"&gt;Beyond Compare&lt;/a&gt; or &lt;a href="https://www.araxis.com/merge/index.en"&gt;Araxis Merge&lt;/a&gt; over it, but those aren't free and I never really understood what makes them so much better. I'd love to hear some compelling arguments. There is, in fact, a very promising and much more interesting merge tool I'm looking at these days, but we'll get to this in another article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useability for game development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Handling large projects
&lt;/h3&gt;

&lt;p&gt;Perforce can handle source control for game development projects of any real-life scale. It performs reasonably well even with huge projects containing terabytes of data, hundreds of thousands of files and hundreds of users.&lt;/p&gt;

&lt;p&gt;I have some personal experience with Ubisoft's Perforce infrastructure which is probably one of the most complex in the industry, and it undeniably does the job. Teams are building on top of Perforce to improve and optimize where needs be: transferring large amounts of data across the globe can be slow, but this becomes a rich man's problem when reaching such scales. For reasonably large teams, using Perforce out of the box should cover all of your collaborative needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup and administration
&lt;/h3&gt;

&lt;p&gt;Perforce is complex software to deal with as an administrator. Where you can start using Git simply by typing "git init", for Perforce you'll have to take your time and learn.&lt;/p&gt;

&lt;p&gt;The initial investment is significant: you will need hardware to host your server and learn to set it all up. Perforce can be hosted on Windows or Linux but for many reasons Linux is preferable, and this is once again not beginner-friendly. You also need to figure out a backup and restore strategy, to plan for the worst. You do not want to lose your data, as this is your most valuable asset.&lt;/p&gt;

&lt;p&gt;Perforce requires configuration to fine-tune to your needs. You should configure the &lt;a href="https://www.perforce.com/manuals/p4sag/Content/P4SAG/auth.users.html"&gt;authentication&lt;/a&gt;, &lt;a href="https://www.perforce.com/manuals/p4sag/Content/P4SAG/DB5-48112.html?Highlight=typemap"&gt;typemap&lt;/a&gt;, depots and streams before you start working. Sounds like a lot, but the upside is that you can get exactly what you want out of it. For more customization, you can create &lt;a href="https://www.perforce.com/manuals/p4sag/Content/P4SAG/chapter.scripting.html"&gt;triggers&lt;/a&gt;, the equivalent of Git hooks, and &lt;a href="https://www.perforce.com/manuals/extensions/Content/Extensions/Home-extensions.html"&gt;server-side&lt;/a&gt; extensions in Lua. On the client-side, you can create plug-ins for P4v, or use the client APIs with &lt;a href="https://www.perforce.com/manuals/p4api/Content/P4API/Home-p4api.html"&gt;C++&lt;/a&gt;, &lt;a href="https://www.perforce.com/manuals/v17.1/p4script/index.html"&gt;Perl, PHP, Python, Ruby&lt;/a&gt;, &lt;a href="https://www.perforce.com/manuals/p4java/Content/P4Java/Home-p4java.html"&gt;Java&lt;/a&gt;, &lt;a href="https://github.com/jenkinsci/p4-plugin/blob/master/docs/P4GROOVY.md"&gt;Groovy&lt;/a&gt; and perhaps more.&lt;/p&gt;

&lt;p&gt;While the learning curve is steep, Perforce allows you to truly implement your desired workflow down to the specifics. This can be extremely valuable over time and especially in larger organizations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tricky operations
&lt;/h3&gt;

&lt;p&gt;Branching and merging operations are harder than on Git. This is generally reserved for power users, even with experienced teams. Branching can be slow and error-prone, and the merge engine is not as efficient as Git's. Some specific cases are very delicate to handle: those of you who have integrated moved and modified files will know what I'm talking about.&lt;/p&gt;

&lt;p&gt;You will also encounter limitations of P4V one day or another. It performs extremely well on regular operations, but when dealing with several thousand files, you are better off using the command-line. Again, those operations should be unfrequent in most game projects and generally reserved for power users.&lt;/p&gt;

&lt;p&gt;Perforce will be a great tool to leverage, provided you have technical people to support it. For small teams with artists and designers only, this could be daunting. For most serious game development projects, one of the programmers will be capable of taking this responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ecosystem
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Integrations
&lt;/h3&gt;

&lt;p&gt;Perforce (the company) provides an &lt;a href="https://www.perforce.com/products"&gt;array of products&lt;/a&gt; on top of the source control. Each one of them has its own licensing model. While some are free, some others require a separate paid license.&lt;/p&gt;

&lt;p&gt;One of the most relevant for us is &lt;a href="https://www.perforce.com/products/helix-swarm"&gt;Helix Swarm&lt;/a&gt;, which is a free code review tool for Perforce. This is a great addition to the toolbox, and an indispensible one if you are serious about programming. Swarm is well integrated with Perforce and provides enough features to do the job. Just be aware that it is not the best tool on the market. Here is a &lt;a href="https://en.wikipedia.org/wiki/List_of_tools_for_code_review"&gt;list of alternatives&lt;/a&gt;. I hear that Perforce is planning for an update of Swarm, and I can't wait to try it out.&lt;/p&gt;

&lt;p&gt;Because it is used everywhere in the game industry, Perforce is also well integrated with game engines. Unreal, Unity, Cryengine, and every proprietary engine I've worked on had a Perforce integration of some sort.&lt;/p&gt;

&lt;p&gt;Perforce is also integrated with IDEs, most notably Visual Studio with its official plugin &lt;a href="https://www.perforce.com/downloads/helix-plugin-visual-studio-p4vs"&gt;P4VS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Of course, Perforce also has integrations with all of the major Continuous Integration solutions. For instance, they maintain and distribute the official &lt;a href="https://www.perforce.com/integrations/jenkins-and-perforce-integrations"&gt;Jenkins integration&lt;/a&gt;. This is what we use here at Darewise.&lt;/p&gt;

&lt;p&gt;There is a &lt;a href="https://www.perforce.com/products/helix-alm/slack-integration"&gt;Slack integration&lt;/a&gt;, sadly it is part of a separate Perforce product. A little research will tell you if your favorite tool has an Integration, but don't count on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interoperability
&lt;/h3&gt;

&lt;p&gt;In recent years, Perforce has fully embraced Git as an attempt to increase interoperability with Perforce source control as well as their other products. They provide several tools to that effect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.perforce.com/perforce/r15.3/manuals/git-fusion/"&gt;git-fusion&lt;/a&gt;: a legacy python script that allows two-way copies between a Git repository and Perforce server. While it is no longer listed on the website, it is still in use and I don't think there is a replacement for this particular use case. git-fusion is, for instance, how &lt;a href="https://www.unrealengine.com/en-US/ue4-on-github"&gt;Epic Games&lt;/a&gt; and &lt;a href="https://github.com/CRYTEK/CRYENGINE"&gt;Cryengine&lt;/a&gt; provide a public Git endpoint, even though they work on Perforce internally.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.perforce.com/products/helix4git"&gt;Helix4Git&lt;/a&gt;: a Git server available on-premises or in the cloud. The unique selling point being, of course, its performance as it is backed by a Perforce server, presumably at least the same database engine (oracle). This allows for hosting both Perforce and Git repositories on the same server.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.perforce.com/products/helix-teamhub"&gt;Helix TeamHub&lt;/a&gt;: a full project management solution including hosting the repositories, access control, kanban boards. It even supports SVN and Mercurial. Basically this is the equivalent of GitLab by Perforce, although it lacks the DevOps/Continuous Integration which makes GitLab so popular.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Hosting
&lt;/h3&gt;

&lt;p&gt;Simple hosting solutions for Perforce are rare. Most teams choose to host on-premises using their &lt;a href="https://www.perforce.com/perforce-and-cloud"&gt;own hardware or public cloud options&lt;/a&gt;. For managed solutions, it seems that &lt;a href="https://www.assembla.com/perforce"&gt;Assembla&lt;/a&gt; is the exclusive provider of cloud hosting.&lt;/p&gt;

&lt;p&gt;Overall, the ecosystem of Perforce is smaller than that of Git, as expected. That being said, all of the major points are covered: everything necessary for you to perform your daily tasks is available and pretty high quality. If that's not enough, there are several P4 to Git options to choose from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;Perforce sells itself as an "enterprise" software and comes with an "enterprise" level price. In other words, Perforce is expensive.&lt;/p&gt;

&lt;p&gt;You can use &lt;a href="https://www.perforce.com/products/helix-core/free-version-control"&gt;Perforce for free&lt;/a&gt; if you host it yourself. It is however limited to 5 users and 20 workspaces. In practice, most people will exceed this limitation. Each user needs to create several workspaces, at least one per workstation. It is recommended to create "system" users such as an administrator user, and probably one for your swarm and for your CI system. Of course, you can ignore these recommendations but the free tier remains very limiting.&lt;/p&gt;

&lt;p&gt;If you require more, you must negotiate a licensing agreement with Perforce, with an undisclosed price and licensing model. While I am using Perforce myself, I am not sure I am at liberty to disclose our agreement. We'll just stick to public information to be safe.&lt;/p&gt;

&lt;p&gt;For cloud-hosted servers with Assembla, the &lt;a href="https://www.assembla.com/pricing#perforce"&gt;pricing comes in two tiers.&lt;/a&gt; The basic price starts at $44.50/user/month with a 12-month commitment. Moreover, extra features, as well as single-tenant hosting, can be negotiated with a custom pricing agreement.&lt;/p&gt;

&lt;p&gt;We can safely assume all the undisclosed pricing is at least the same if not more expensive, which makes Perforce at least $534/user/year. This is before you factor in hardware and maintenance costs if you choose to self-host, which many studios do for greater control and data security. This is a large investment for most teams, and it is the most expensive source control solutions of all we are going to be looking at in this series.&lt;/p&gt;

&lt;p&gt;I would love for Perforce to reconsider their licensing model to allow for more teams to access the software. This is the backbone of the game industry and it would surely benefit from a larger ecosystem. I'm sure many small teams would be inclined to switch to Perforce if they were offered a reasonable monthly model per user. The free tier limitations could also be relaxed to allow for small teams to use it properly, but it would require some development on Perforce's side due to how the license system is implemented. Let's keep out hopes up and see what the future holds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Perforce is a great source control option for game development if you have the means to afford it, both financially and technically. For newer or smaller teams, it can be scary to get into, not to mention expensive.&lt;/p&gt;

&lt;p&gt;It is still the undisputed champion of the game industry and the workhorse of all the major studios. It was adopted for good reason, as its ability to handle large projects was unrivaled, and this is the biggest issue facing game development projects, far before user experience or interconnectivity with the open-source ecosystem. However, the game industry has also accumulated enough legacy on top of Perforce that even if there was a better solution available today, the adoption would be slow due to the ever-increasing costs of migration.&lt;/p&gt;

&lt;p&gt;Perforce is constantly improving in the meantime. There are several yearly releases of the server and the client, as well as the satellite products. A lot of these updates are going in the right direction, improving the user experience, adding features to support our workflows and interoperability with more systems. The company is clearly investing and consolidating its ecosystem to cover all grounds of software development, from source control to application lifecycle and project planning with more recent acquisitions. I believe it has a great opportunity to increase adoption by proposing new business models to attract new customers, and I will certainly keep an eye out for major updates.&lt;/p&gt;

&lt;p&gt;In the meantime, newer teams should aim to start with the best tools available presently and within their budget. Which is the best fit is certainly not obvious, this is why I'm writing this after all. As an industry, we should never stop looking for better solutions, challenge our assumptions and established processes in order to improve our workflow. Making games is one of the most challenging tasks in software and art development of our time, and every improvement to our quality of life is worth it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the next article, we will look at a challenger that could rival Perforce on its own territory: Plastic SCM.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sourcecontrol</category>
      <category>perforce</category>
      <category>gamedev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Git Source Control for Game Development</title>
      <dc:creator>Samuel Kahn</dc:creator>
      <pubDate>Wed, 06 Nov 2019 13:58:56 +0000</pubDate>
      <link>https://dev.to/kahncode/git-source-control-for-game-development-3mf5</link>
      <guid>https://dev.to/kahncode/git-source-control-for-game-development-3mf5</guid>
      <description>&lt;p&gt;&lt;em&gt;This is part of a &lt;a href="http://kahncode.com/category/source-control-comparison/"&gt;series of posts&lt;/a&gt; on source control for game development. Read more in the &lt;a href="http://kahncode.com/blog/"&gt;Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/"&gt;Git&lt;/a&gt; is probably the first result people stumble onto when researching source control for their game development project.&lt;/p&gt;

&lt;p&gt;As evidenced by &lt;a href="http://kahncode.com/tag/git/"&gt;my activity&lt;/a&gt; on this very website, I am very interested in Git. I have used it extensively both professionally as well as for personal projects including game projects. I have come to love its beautiful design, and hate its limitations. Because of those, I created &lt;a href="http://kahncode.com/gitcentral/"&gt;GitCentral&lt;/a&gt; to overcome Git's shortcomings and create a better-suited source control workflow for game development.&lt;/p&gt;

&lt;p&gt;This article is a good opportunity to examine the motivations behind creating GitCentral, and shed some light on why Git is both great, and difficult to use for game development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background and History
&lt;/h2&gt;

&lt;p&gt;Git no longer needs to be introduced. Its &lt;a href="https://trends.google.com/trends/explore?date=all&amp;amp;q=git,svn"&gt;steady rise to popularity&lt;/a&gt; alongside &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; makes it nearly impossible to avoid.&lt;/p&gt;

&lt;p&gt;If you're a programmer or aspire to become one, you need to learn Git now! Whether you want to participate in open-source projects, fork someone else's cool program, or just for your local hobby projects, Git is the tool you need. Git will be useful for you even in enterprise scenarios where you may use a different solution for the primary repository, and work on closed-source code. Many companies have started to use GitHub as a practical means to collaborate on proprietary code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;A complete list of features of Git can be found in the &lt;a href="https://git-scm.com/about"&gt;official documentation&lt;/a&gt;. Here we will focus on the major features that separate git from other source control solutions. We assume that all of them provide the most common source control features of versioning, collaboration, and data integrity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed source control
&lt;/h3&gt;

&lt;p&gt;Git was born out of the needs of the open-source community. These design intentions can be seen and felt in all the features and implementation of Git.&lt;/p&gt;

&lt;p&gt;It uses a &lt;a href="https://git-scm.com/about/distributed"&gt;distributed model&lt;/a&gt;, which means there is no central server holding the source of truth. Instead, each developer holds an entire copy of the code and all the history. At their discretion, they may redistribute the code or its artifacts, or contribute their modifications to someone who does. Teams of maintainers curate popular repositories, and sometimes, a difference of needs or opinions leads to a fork which takes a life of its own.&lt;/p&gt;

&lt;p&gt;In the most common form, the open-source distributed workflow can look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZTsTzGC6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2019/10/workflow-b%402x.png%3Fresize%3D814%252C328" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZTsTzGC6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2019/10/workflow-b%402x.png%3Fresize%3D814%252C328" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Graph model
&lt;/h3&gt;

&lt;p&gt;Git uses a &lt;a href="https://medium.com/girl-writes-code/git-is-a-directed-acyclic-graph-and-what-the-heck-does-that-mean-b6c8dec65059"&gt;graph model&lt;/a&gt; to represent the history. Each change is stored as an object and a link to its parent. The beauty of this representation means that every change is potentially a branch. Git also provides a very powerful merge engine.&lt;/p&gt;

&lt;p&gt;Those features encourage a liberal usage of branching and merging. This workflow is very practical for programmers and is a big driver behind Git's popularity. By comparison, branches and merges in older version control systems such as SVN were time-consuming and error-prone. They tended to be avoided or reserved for elite programmers. Not only the ability to branch and merge liberates programmers and allows them to experiment freely, it also encourages merging more often, which leads to smaller patches that are easier to review and maintain. The result is increased overall productivity, stability and maintainability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/about/small-and-fast"&gt;Git is very fast&lt;/a&gt; at performing all the regular source control operations with a local repository. It's when working with a remote repository that its limits start to show. The implementation of the graph model requires the repository to be fully consistent with the revision from which the current changes are being built upon, in order to allow committing. In practice, this means before every commit, one must get all the updates from the remote repository. By contrast, other version control systems only require you to download the updates to the files you have changed. With Git you must download everything. Git is not particularly fast at file transfer either, but more on this later.&lt;/p&gt;

&lt;h3&gt;
  
  
  User experience
&lt;/h3&gt;

&lt;p&gt;Git is primarily a command-line tool. This makes it harder to use for beginners and less technical users. Its model can be confusing and it can be hard to understand what is going on when something went wrong.&lt;/p&gt;

&lt;p&gt;The steep learning curve has become somewhat of a meme, spawning many websites and &lt;a href="https://ohshitgit.com/"&gt;tongue-in-cheek&lt;/a&gt; literature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XYb6My5i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/imgs.xkcd.com/comics/git.png%3Fresize%3D330%252C478%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XYb6My5i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/imgs.xkcd.com/comics/git.png%3Fresize%3D330%252C478%26ssl%3D1" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git is a very powerful tool, but we should also recognize its flaws. I share the opinion of many that the commands and the user experience could be improved. Some commands such as checkout or reset perform far too many different actions which would have been better separated into unique verbs. &lt;a href="https://gitless.com/"&gt;Gitless&lt;/a&gt; is a notable attempt to provide a better user experience on top of Git, and this might be just enough for beginners to get into it.&lt;/p&gt;

&lt;p&gt;Still, even with a lot of experience using Git and diving into the &lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain"&gt;plumbing&lt;/a&gt; while working on &lt;a href="http://kahncode.com/gitcentral/"&gt;GitCentral&lt;/a&gt;, I find myself often looking at the documentation, begin confused by the inconsistent semantics used, or facing undocumented behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Graphical User Interface
&lt;/h3&gt;

&lt;p&gt;Git does not provide any Graphical User Interface. It is only a command-line tool. Here is an &lt;a href="https://git-scm.com/downloads/guis/"&gt;official list&lt;/a&gt; of third-party GUIs from the official website. However, they all seem to be lacking something when put to the test.&lt;/p&gt;

&lt;p&gt;Personally, I have tried a couple of the major GUI tools and currently settled for &lt;a href="https://www.sourcetreeapp.com/"&gt;SourceTree&lt;/a&gt;. Even then, I perform most of the actions using the command-line, which means the graphical tool has not provided me with a better alternative. You also have to add your own diff and merge tool. As I am used to Perforce in my professional life, I really miss some of the most advanced features which make me more efficient such as Time-Lapse View, though there is, in fact, a &lt;a href="https://github.com/JonathanAquino/git-time-lapse-view"&gt;similar tool&lt;/a&gt; for Git. I'm sure some people are faster using only the command-line, but I am certainly less efficient and I would bet that the majority of developers are in the same category, especially the less experienced ones.&lt;/p&gt;

&lt;p&gt;Having a graphical tool at your disposal to perform basic actions doesn't solve the learning curve entirely though. Git's underlying model and semantics are complex and hard to grasp for non-technical users. The best way to work with Git is through simple integrations, such as &lt;a href="https://tortoisegit.org/"&gt;TortoiseGit&lt;/a&gt; which adds actions in the contextual menu of Windows Explorer. &lt;a href="http://kahncode.com/gitcentral/"&gt;GitCentral&lt;/a&gt; does essentially the same from within Unreal Engine.&lt;/p&gt;

&lt;p&gt;Overall, Git attracts for its features and its great model for programmers, but it is hindered by its complexity and user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useability for game development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Downsides of the distributed graph model
&lt;/h3&gt;

&lt;p&gt;Game projects are rarely distributed efforts. More often than not, you want to collaborate with your entire team on a central repository. This goes against Git's model and creates very specific issues.&lt;/p&gt;

&lt;h4&gt;
  
  
  No single file versioning operations
&lt;/h4&gt;

&lt;p&gt;As we already mentioned, in order to share any change, you must first download all the latest updates from the central server. This is very sensible for code, as it forces you to test your changes with the latest version before committing. On game projects where large binary files may have been changed, this could mean waiting a very long time for the updates to download. If anyone pushed their work in the meantime, you have to do it all over again until you're fast enough to commit your changes. When the number of collaborators increases, it can become almost impossible to commit a change manually. This sort of "traffic jam" situation can be solved using a lot of extra tooling and automation, but it is an extra hassle that many other source control solutions don't have. Interestingly, open-source workflow generally does not suffer from this because relatively few maintainers work on the central repositories.&lt;/p&gt;

&lt;p&gt;On top of this, you may not want to get all the latest changes yourself. The very latest may be unstable, which is a reality of most game projects. More importantly, it may require you to stop your work and start a long process of compiling and "&lt;a href="https://cgcookie.com/articles/big-idea-baking"&gt;baking&lt;/a&gt;" the new code and assets. With some game engines and enough changes to download, this could take hours, only to find yourself with a potentially unstable version of the game. The ability to push or pull one file at a time is therefore very important in game development scenarios. Of course, Git's approach is safer. Pushing only a few files without testing with the latest changes could create unexpected issues. However, depending on your iteration time, the tradeoff may be well worth it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Binary files need a centralized workflow
&lt;/h4&gt;

&lt;p&gt;A more subtle issue is that the default function of git is to work against your local version of the repository. You will not see the changes made to a specific file on the central repository until you fetch the information and run specific commands. Since binary files cannot be merged, it is more important to know the status of a file when compared with its latest version on the remote repository, rather than the local one. When using Git traditionally, you will only see the conflict when you try to merge your changes with the remote changes, and it may already be too late at this point. File locking, as explained below, helps avoiding conflicts, but not entirely.&lt;/p&gt;

&lt;p&gt;In essence, the workflow of Git does not match the collaboration model of the majority of game development teams. Game projects will find that they often have a better iteration time when using a &lt;a href="http://kahncode.com/gitcentral/features/#centralized_source_control"&gt;centralized, file-based model&lt;/a&gt;. This is how many other version control solutions are implemented. Unfortunately achieving this workflow with Git is very complex and requires using many plumbing commands, as I did with GitCentral. You may be able to adapt to Git's distributed graph model, but the issues will start appearing when adding more people to the project, and the iteration time will be dramatically impacted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling large projects
&lt;/h3&gt;

&lt;p&gt;Git's distributed model means that every developer has a copy of the entire repository and all of the history on their hard drive. As the project gets larger, this causes the repository to grow in size to the point where it is too large for the hard drives and too slow to download. Git was created to handle text files primarily, but in game projects, binary files will quickly grow a Git repository beyond reasonable limits.&lt;/p&gt;

&lt;p&gt;To allow Git to handle binary files more gracefully, &lt;a href="https://anarc.at/blog/2018-12-21-large-files-with-git/"&gt;several extensions&lt;/a&gt; have been created. &lt;a href="https://git-lfs.github.com/"&gt;Git-LFS&lt;/a&gt;, backed by GitHub has emerged as the dominant solution for a couple of years now. Git-LFS is transparent and stores binary files remotely to avoid bloating the main Git repository and its history. This solves the size issue and doesn't create an additional layer of complexity for the user. However, Git-LFS is very slow when compared to other source control solutions. I could not find a good benchmark online, but it is very noticeable. It seems clear that the current design of Git-LFS and how it integrates with Git could be optimized for performance.&lt;/p&gt;

&lt;p&gt;Git's scaling issues are &lt;a href="https://docs.microsoft.com/en-us/azure/devops/learn/git/technical-scale-challenges"&gt;well known&lt;/a&gt; and there are still many &lt;a href="https://devblogs.microsoft.com/bharry/the-largest-git-repo-on-the-planet/"&gt;attempts to improve&lt;/a&gt; on it. In the future, those problems may be completely resolved, but as of this day, Git scales poorly with game projects especially when compared to some other solutions. Meanwhile, there are &lt;a href="https://www.atlassian.com/git/tutorials/big-repositories"&gt;some workarounds&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  File locking
&lt;/h3&gt;

&lt;p&gt;File locking is the action of "locking" a specific file, which means no other user can modify it until the lock is released. This avoids conflicts, and is critical for game development where binary files cannot be merged.&lt;/p&gt;

&lt;p&gt;Git-LFS provides a &lt;a href="https://github.com/git-lfs/git-lfs/wiki/File-Locking"&gt;basic file locking&lt;/a&gt; implementation since the release of Git-LFS 2.0.0. Most of the hosting providers support Git-LFS and locking by now.&lt;/p&gt;

&lt;p&gt;There are a few caveats to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Only the files tracked by Git-LFS can be locked.&lt;/li&gt;
&lt;li&gt;  Locking a file locks it for all the branches of the repository. This can prevent two people from working on the same file on different branches.&lt;/li&gt;
&lt;li&gt;  The implementation of locking depends on your Git-LFS server, so your mileage may vary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is very important to note that two people may not work on separate branches at the same time. When working on a stabilization branch, say for a demo or a release, you may have to coordinate with others working on the next features in the master branch, and avoid using the lock at the same time. This can work with small teams, but the more people you add, the more this will slow you down and create issues. You may not anticipate it yet, but your source control workflow will get more complex over time, adding more branches for features, demos, releases and patches, and all those small problems at first will become worse.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access control
&lt;/h3&gt;

&lt;p&gt;In a game project, you often want to control who can access your files. You may even want some files to be read or written only by privileged users, for security or confidentiality reasons.&lt;/p&gt;

&lt;p&gt;Because of its distributed nature, Git does not provide any access control out of the box. You must add it to your repository server. Luckily, virtually all the cloud hosting providers and self-hosted solutions offer private repositories and user management. However, I haven't found more fine-grained control such as per-directory or per-file permissions. You can often enforce additional rules, such as locking a branch, requiring a successful code review and automated tests before the change can be committed to the central repository. Generally, git offers less access control options than its competitors, but this is likely to improve in the future.&lt;/p&gt;

&lt;p&gt;Of course, you can implement your dream workflow using &lt;a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks"&gt;git hooks&lt;/a&gt;, but this comes at a cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ecosystem
&lt;/h2&gt;

&lt;p&gt;Git has access to the most comprehensive ecosystem of tools and integrations available. I did not attempt to make an exhaustive list as it would be too long and quickly outdated. Virtually every tool or technology you are likely to require integration with your source control will provide some level of support. Git is available for all desktop platforms used in game development (Windows, Mac, Linux)&lt;/p&gt;

&lt;p&gt;The most notable integrations include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Game engines: Unreal has a Git integration by default, but &lt;a href="http://kahncode.com/gitcentral/"&gt;GitCentral&lt;/a&gt; allows for a better workflow adapted to gamedev. If you decide to use Git and Unreal, then this will greatly improve your quality of life.&lt;/li&gt;
&lt;li&gt;  Developer tools from IDEs like Visual Studio to DCC tools.&lt;/li&gt;
&lt;li&gt;  Continuous integration tools such as &lt;a href="https://jenkins.io/"&gt;Jenkins&lt;/a&gt; or the aptly named &lt;a href="https://about.gitlab.com/"&gt;GitLab&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Productivity tools like Jira or Trello&lt;/li&gt;
&lt;li&gt;  Communication apps (Slack, MS Teams...)&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://kahncode.com/2019/05/19/choosing-a-git-hosting-provider-for-game-projects/"&gt;Cloud hosting providers&lt;/a&gt;, these often provide extra tools on top of hosting the repository, including many of the above&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that some of these integrations only work with GitHub, which can limit you if you're not hosting your project there.&lt;/p&gt;

&lt;p&gt;There are also scripts to allow migrating to and from most version control solutions to Git. This can be useful to migrate, and if you ever need to replicate your history in another version control for some reason. &lt;a href="https://git-scm.com/docs/git-svn"&gt;Git-SVN&lt;/a&gt; is available out of the box. Perforce has various tools as well, but I'll get deeper into those when talking about Perforce in a future post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;Git is open-source and &lt;a href="https://git-scm.com/download/"&gt;entirely free&lt;/a&gt;. However, there are costs to running a game development project with Git, as you still need to host your repository and its data in a shared location.&lt;/p&gt;

&lt;p&gt;In a previous blog article, &lt;a href="http://kahncode.com/2019/05/19/choosing-a-git-hosting-provider-for-game-projects/"&gt;I compared the major Git hosting providers&lt;/a&gt; and their features. This should give you a good overview of the features and costs involved, and pointers to choose the best solution. Of course, you may host on your own hardware, which comes with its own time and financial costs.&lt;/p&gt;

&lt;p&gt;Nonetheless, there are no license fees, which makes Git one of the cheapest and by far the most accessible source control solution for game development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Git is here to stay and you will have to learn to work with it, whether you want it or not.&lt;/p&gt;

&lt;p&gt;Thanks to its popularity, you have access to the biggest ecosystem of integrations and interoperability. You also have plenty of great cloud hosting options for your repository and your productivity tools.&lt;/p&gt;

&lt;p&gt;Despite these great features, Git is not very well suited for game development. Its distributed model does not match the typical centralized workflow and does not scale very well: the larger your project gets or the more collaborators you add, the more you will run into issues. On top of this, it is one of the hardest source control solutions to learn. If your project has less technical people such as artists or designers, you will likely spend a lot of time helping them understand Git, and fix many mistakes made along the way. Git can be good enough for small-sized teams comprised of fairly technical people, and where the pace of change is slow enough to not create too many conflicts with binary files. As your project scales, you will be looking for a better solution.&lt;/p&gt;

&lt;p&gt;On my personal game projects, I quickly encountered issues with Git's model and user experience. I decided to create &lt;a href="http://kahncode.com/gitcentral/"&gt;GitCentral&lt;/a&gt; to solve them. It has since allowed me to collaborate in a convenient way with Git and Unreal Engine. Even so, GitCentral is best used on smaller projects, since the Git-LFS backend does not scale so well when your game project gets inevitably larger. In retrospect, I should have extracted the logic of GitCentral into a library from which to create several tools, such as a Windows Explorer integration, or allowing to integrate it in Unity and other common game development tools. Perhaps this will be a future project if there is demand.&lt;/p&gt;

&lt;p&gt;In my professional life, when starting &lt;a href="https://darewise.com/"&gt;Darewise&lt;/a&gt;, we evaluated many options and finally opted for &lt;a href="https://www.perforce.com/"&gt;Perforce&lt;/a&gt;, which is the game industry standard, and what I have used in all of my previous positions. In the next article, I will show you what motivated this decision.&lt;/p&gt;

</description>
      <category>git</category>
      <category>sourcecontrol</category>
      <category>gamedev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What is the best Source Control for game development ?</title>
      <dc:creator>Samuel Kahn</dc:creator>
      <pubDate>Wed, 06 Nov 2019 13:54:57 +0000</pubDate>
      <link>https://dev.to/kahncode/what-is-the-best-source-control-for-game-development-5g0p</link>
      <guid>https://dev.to/kahncode/what-is-the-best-source-control-for-game-development-5g0p</guid>
      <description>&lt;p&gt;Choosing the best Source Control for a game development project is a hot topic in the indie community. Many teams struggle with making the right choice, and the advice available online is often misleading. The answer is surprisingly not obvious, and there is no one size fits all solution.&lt;/p&gt;

&lt;p&gt;Earlier this year I &lt;a href="http://kahncode.com/2019/05/24/nordic-game-2019-is-over/"&gt;talked at the Nordic Game Conference&lt;/a&gt; about Source Control, and how to structure your team's workflow, automation and continuous integration and deployment pipeline around it. You can &lt;a href="http://kahncode.com/wp-content/uploads/2019/05/Always-Playable-NG19-Kahncode.pdf"&gt;download the slides&lt;/a&gt; here. As this is one of my areas of expertise, I wanted to go deeper into the subject and break down the options available in order for game development teams to make an educated choice about source control.&lt;/p&gt;

&lt;p&gt;In this &lt;a href="http://kahncode.com/category/source-control-comparison/"&gt;series&lt;/a&gt;, we will study the major options available to you, their various pros and cons, and highlight the reasons why you should choose one over another depending on your team size, budget, and makeup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should I use Source Control?
&lt;/h2&gt;

&lt;p&gt;Let's get one thing out of the way first, &lt;strong&gt;Yes you should always use source control.&lt;/strong&gt; Yes, even if you're a solo developer working on a hobby project. Yes, even more so if you are a beginner.&lt;/p&gt;

&lt;p&gt;Don't be afraid of source control, this is your most useful tool in the toolbox as a programmer, and the earlier you learn it, the more you will appreciate its many features and benefits.&lt;/p&gt;

&lt;p&gt;There are many &lt;a href="https://medium.com/better-programming/9-reasons-even-solo-developers-should-use-source-control-c4f5939e2a36"&gt;articles&lt;/a&gt; and &lt;a href="https://stackoverflow.com/questions/3868436/why-should-i-use-version-control-if-im-working-alone-and-already-back-up-regula"&gt;threads&lt;/a&gt; outlining why you should use source control, but let me list a few points that I feel are relevant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Source control (with a remote repository) acts as a backup for your code. If your hard drive or computer burns, you are safe. Even if you do not value your code much, having a backup can't hurt.&lt;/li&gt;
&lt;li&gt;  History and branching allow you to quickly explore several solutions and go back in time&lt;/li&gt;
&lt;li&gt;  Comments allow you to understand what you previously did and why. You may not believe me, but you will forget your own code sooner than you think. Here are some tips on &lt;a href="https://dev.to/jacobherrington/how-to-write-useful-commit-messages-my-commit-message-template-20n9"&gt;how to write good commit messages&lt;/a&gt; for your future self and others.&lt;/li&gt;
&lt;li&gt;  You may have several computers on which you want to work on the project. Source control will make this easy.&lt;/li&gt;
&lt;li&gt;  One day your small project may grow. Perhaps more team members, perhaps you will sign a publishing deal and go big! You'll be very happy to have source control then.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note that Dropbox or any cloud drive equivalent is not a source control tool. Yes, it provides remote backup and some history, but it lacks all the tools and specific functionality that make source control software so useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source control for game development
&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href="https://git-scm.com/"&gt;Git&lt;/a&gt; and &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt;, source control has now become ubiquitous and collaboration has never been easier.&lt;/p&gt;

&lt;p&gt;So, why is source control for game development so problematic? What makes game projects special?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Source control was mostly designed for code, which generally translates to text files. Game projects consist of code as well as game data, usually in the form of large binary files. Binary files generally cannot be diffed, nor merged. This hinders the possibility of using branches in the same fashion as you would with text files. It also requires exclusive locking mechanisms or conflict resolution.&lt;/li&gt;
&lt;li&gt;  Project size. Even the largest code-only projects remain manageable. Game projects can very quickly take more than a hundred of gigabytes, especially in the age of asset marketplaces. Some source control solutions struggle to handle large projects as they were not designed for this use case.&lt;/li&gt;
&lt;li&gt;  Non-technical team members. Code projects mostly involve programmers who can find their way around complex command-line tools such as Git. Game projects have many Artists and Designers who require a good user experience to properly use Source Control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The available source control solutions for game development all have major drawbacks, whether it is price, complexity, user experience, or inability to handle large game projects. This makes the choice of source control very difficult.&lt;/p&gt;

&lt;p&gt;This is why I created &lt;a href="http://kahncode.com/gitcentral/"&gt;GitCentral&lt;/a&gt;. GitCentral allows using Git as a source control backend but solves the user experience, workflow, and technical issues by providing full &lt;a href="https://www.unrealengine.com/marketplace/en-US/slug/git-central"&gt;integration in Unreal Engine&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Candidate choices and comparison axes
&lt;/h2&gt;

&lt;p&gt;In this &lt;a href="http://kahncode.com/category/source-control-comparison/"&gt;series&lt;/a&gt;, we will compare the major source control options, provide the information, and draw conclusions in order for you to make the best choice for your team.&lt;/p&gt;

&lt;p&gt;In order to compare them properly, we will evaluate each option using the following criteria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Features and source control model&lt;/li&gt;
&lt;li&gt;  Ability to support game projects, handling large projects and binary files&lt;/li&gt;
&lt;li&gt;  Iteration time&lt;/li&gt;
&lt;li&gt;  User Experience out of the box&lt;/li&gt;
&lt;li&gt;  Ecosystem of tools and integrations, notably with continuous integration&lt;/li&gt;
&lt;li&gt;  Cloud hosting providers&lt;/li&gt;
&lt;li&gt;  Price&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are the source control solutions that we will evaluate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="http://kahncode.com/2019/11/05/git-source-control-for-game-development/"&gt;Git&lt;/a&gt;, the ubiquitous source control software popularized by the open-source community and GitHub.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://subversion.apache.org/"&gt;Subversion&lt;/a&gt; (SVN), another open-source staple. SVN is losing popularity to Git but is still one of the major source control systems out there.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.perforce.com/solutions/version-control"&gt;Perforce&lt;/a&gt;, the AAA game industry standard choice.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.plasticscm.com/"&gt;Plastic SCM&lt;/a&gt;, a source control specifically designed for game development and large projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are other players to note in the source control field, such as &lt;a href="https://www.mercurial-scm.org/"&gt;Mercurial&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Azure_DevOps_Server"&gt;Team Foundation&lt;/a&gt;, &lt;a href="https://www.alienbrain.com/"&gt;Alienbrain&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Concurrent_Versions_System"&gt;CVS&lt;/a&gt;. We will touch briefly on them whenever relevant, but their reported low rates of adoption, lack of specific functionality relevant for game projects, and them being arguably inferior products to the ones mentioned above, makes them secondary choices. We will also explore engine-specific solutions for commercial engines. Of course, if there is an interesting solution I do not know about or you want me to dig deeper into, please contact me.&lt;/p&gt;

&lt;p&gt;Stay tuned for the first article where we will break down Git's pros and cons for game development projects.&lt;/p&gt;

</description>
      <category>git</category>
      <category>gamedev</category>
      <category>sourcecontrol</category>
      <category>productivity</category>
    </item>
    <item>
      <title>C++ Tricks: Fast RTTI and Dynamic Cast </title>
      <dc:creator>Samuel Kahn</dc:creator>
      <pubDate>Tue, 08 Oct 2019 07:50:22 +0000</pubDate>
      <link>https://dev.to/kahncode/c-tricks-fast-rtti-and-dynamic-cast-3k2f</link>
      <guid>https://dev.to/kahncode/c-tricks-fast-rtti-and-dynamic-cast-3k2f</guid>
      <description>&lt;p&gt;&lt;em&gt;C++ Tricks is a &lt;a href="http://kahncode.com/category/kcl/"&gt;series of posts&lt;/a&gt; on core libraries for game engines and language experiments shared as the &lt;a href="https://github.com/Kahncode/kcl"&gt;Kahncode Core Libraries&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As introduced in the &lt;a href="http://kahncode.com/2019/09/10/c-tricks-efficient-core-libraries-for-game-engines/"&gt;first post of these series&lt;/a&gt;, I will share the first piece of KCL: an implementation of RTTI and Dynamic Cast. The code can be found on &lt;a href="https://github.com/Kahncode/kcl/blob/master/Source/KCL/KCL_RTTI.h"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you don't know what dynamic casting is, then I suggest you read &lt;a href="https://www.learncpp.com/cpp-tutorial/12-9-dynamic-casting/"&gt;some online resources&lt;/a&gt; before diving into this article.&lt;/p&gt;

&lt;p&gt;I will avoid debating whether or not you need RTTI. Some say that it correlates with bad architectural choices and violates the &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;SOLID principles.&lt;/a&gt; However in practice most game engines have an extensive RTTI and introspection system and make wild use of it. Unreal Engine solves this issue using &lt;a href="https://docs.unrealengine.com/en-US/Programming/BuildTools/UnrealHeaderTool/index.html"&gt;code generation&lt;/a&gt; in their &lt;a href="https://docs.unrealengine.com/en-US/Programming/UnrealArchitecture/Objects/index.html"&gt;object system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Following the philosophy of &lt;a href="https://github.com/Kahncode/kcl"&gt;KCL&lt;/a&gt;, our RTTI system will fulfill the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Must support at least: dynamic cast, multiple inheritance, and retrieving the type name as a string.&lt;/li&gt;
&lt;li&gt;  As elegant syntax as possible. Only two macros are necessary. A one macro version is possible as well.&lt;/li&gt;
&lt;li&gt;  No code generation, use only the preprocessor and compiler.&lt;/li&gt;
&lt;li&gt;  Minimalist: there are less than 350 lines of code including all comments.&lt;/li&gt;
&lt;li&gt;  Efficient: one of the main complaints about STL RTTI and dynamic_cast is that is it slow. We must outperform the STL at least in runtime performance.&lt;/li&gt;
&lt;li&gt;  Avoid polluting the global namespace except for our version of dynamic_cast and the necessary macros.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, let's explain how we are going to solve this problem.&lt;/p&gt;

&lt;p&gt;To better understand the following part, I will clarify some terminology. We will build the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;TypeID&lt;/strong&gt;: a unique identifier for a single type.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TypeData&lt;/strong&gt;: the necessary information to perform a dynamic cast&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TypeInfo&lt;/strong&gt;: a structure which contains the TypeID, the type name and the TypeData&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plan of action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We must add at least one virtual method to a polymorphic type, in order to retrieve the type information at runtime. This is unavoidable.&lt;/li&gt;
&lt;li&gt;  The type info itself should contain enough information to identify the type, its name, and all the necessary information to perform dynamic cast. The entirety of the information must be contiguous in memory for best performance, we will therefore avoid linked lists and pointers of any kind.&lt;/li&gt;
&lt;li&gt;  The cost of a dynamic_cast will therefore be that of calling a virtual method, loading the type info, and iterating over a contiguous region of memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  TypeInfo breakdown
&lt;/h3&gt;

&lt;p&gt;First let's create the TypeId by assigning one unique integer identifier for each type. For most programs 16 bits should be enough, so the typedef allows you to adjust the memory footprint of the RTTI system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="nf"&gt;GenerateId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;theTypeIdCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;theTypeIdCounter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We could build the TypeInfo as a simple array of all the Type IDs of the type and its base types. However there is one more information necessary to perform dynamic casts.&lt;/p&gt;

&lt;p&gt;In a multiple inheritance scenario, the dynamic cast of a pointer may actually change the value of the pointer due to pointer adjustment. In order to understand this mechanic, let's take an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;pC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// No offset adjustment, pA == pB &lt;/span&gt;
&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;pC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Offset adjustment, pB != pA&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The pointer difference can be explained when examining the memory layouts of these objects. In order to return a valid pointer to an instance of B, the compiler must return the adress of B in the memory layout of C.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i1.wp.com/kahncode.com/wp-content/uploads/2019/09/kcl_pointer_offset.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vnHhsPCL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2019/09/kcl_pointer_offset.png%3Fresize%3D397%252C441" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The compiler may also introduce padding between the types, so the offset of B* is not necessarily &lt;code&gt;A* + sizeof(A)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will use the compiler itself to determine the offset accurately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Derived&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt; &lt;span class="nf"&gt;ComputePointerOffset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;derivedPtr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;basePtr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;derivedPtr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;intptr_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;basePtr&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;intptr_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;derivedPtr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here is the final TypeInfo info design we come up with, containing all the necessary information. The data array is later implemented as &lt;code&gt;TypeData&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pZ_Im0df--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2019/09/kcl_typedata_layout.png%3Fresize%3D1001%252C66" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pZ_Im0df--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2019/09/kcl_typedata_layout.png%3Fresize%3D1001%252C66" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The data starts as a TypeID string with a size and an array of TypeIDs. The first type is the current type's TypeID. In the cases of multiple inheritance, it follows with more TypeID strings as well as their pointer offset adjustment information.&lt;/p&gt;

&lt;p&gt;We can observe that the first list does not have an offset. This is because all first bases can be casted without pointer offset adjustment. We can therefore perform a slight optimization by omitting this offset value.&lt;/p&gt;

&lt;p&gt;As none of the following lists should have 0 as pointer adjustment value, this allows us to treat a null offset value as the end marker to the chain.&lt;/p&gt;

&lt;p&gt;The recursive nature of the TypeInfo will allow algorithms to walk through the data structure and extract the necessary information during dynamic cast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the type info
&lt;/h2&gt;

&lt;p&gt;The TypeInfo struct must not be templated, and contains all the necessary API to access the RTTI. A pointer to the static instance of this TypeInfo will be returned by the virtual function on the object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;TypeInfo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;myName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; 
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;GetTypeData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; 
    &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;GetTypeId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; 
    &lt;span class="kt"&gt;intptr_t&lt;/span&gt; &lt;span class="n"&gt;CastTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;intptr_t&lt;/span&gt; &lt;span class="n"&gt;aPtr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;aTypeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetTypeData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;byteIndex&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;aTypeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;aPtr&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;byteIndex&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The TypeInfo contains the name, and assumes that is it followed in memory by the Type Data as described above. The type data starts with the current type's TypeID, which is returned by GetTypeId. The CastTo method iterates through the type data and tries to find the TypeID we are trying to dynamic cast to. If it is found, it performs the offset adjusment and returns the new pointer value.&lt;/p&gt;

&lt;p&gt;The most complex part is still ahead of us: we must use the compiler to compute this Type Data. Variadic templates will allow us to fill the Type Data recursively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;TypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;TypeDataImpl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BaseTypes&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Simple Type
&lt;/h3&gt;

&lt;p&gt;Let's start with the most simple type, which does not inherit from anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;TypeDataImpl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TypeDataImpl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;myTypeId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GenerateId&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;myEndMarker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;GetData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; 
    &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;myTypeId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt; &lt;span class="n"&gt;myEndMarker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We simply generate a new TypeID for this type and set the size to 1 and the end marker.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single Inheritance
&lt;/h3&gt;

&lt;p&gt;Let's examine now the case of a type with single inheritance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;TypeDataImpl&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TypeDataImpl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;myTypeId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GenerateId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;myBaseTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FillBaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="cm"&gt;/* No offset with first base */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Size is the base's size + 1 to account for current type id&lt;/span&gt;
        &lt;span class="n"&gt;myEndMarker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;GetData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; 

    &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;myTypeId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;BaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;myBaseTypeData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt; &lt;span class="n"&gt;myEndMarker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Again we build the type data starting with a size and a fresh TypeID. However we will follow it by the type data of the base type. Therefore the size of the first TypeID list in the array is one more than the base type as we include the new type's Type ID.&lt;/p&gt;

&lt;p&gt;In order to generate BaseTypeData we retrive the TypeDataImpl of the base type and iterate through it. Don't worry, this is the most complex part of the whole thing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;BaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;FillBaseTypeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt; &lt;span class="n"&gt;aOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;outHeadSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Retrieves the TypeData&amp;lt;Base&amp;gt; instance, explained below in the article&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;*&lt;/span&gt; &lt;span class="n"&gt;baseTypeId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;GetTypeInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetTypeData&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;// return size of head list&lt;/span&gt;
        &lt;span class="n"&gt;outHeadSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;baseTypeId&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;baseTypeId&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;byteSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;baseTypeId&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mySize&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// copy type list&lt;/span&gt;
        &lt;span class="n"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byteSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;byteSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// fill next offset and add pointer offset&lt;/span&gt;
            &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;aOffset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;byteIndex&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// fill next size&lt;/span&gt;
            &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;byteSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;byteIndex&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// copy types&lt;/span&gt;
            &lt;span class="n"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byteSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;byteIndex&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;byteSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;byteIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// We only need the previous type data array, but not its size or end marker as we will insert them ourselves&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code iterates through the base type's data and fills the derived type's data. It finally stops when the offset found is 0, which denotes the end.&lt;/p&gt;

&lt;p&gt;Interesting things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It doesn't simply copy the data but it will add an extra potential offset to the base's data to account for pointer offset adjustment. This is why in the single inheritance example, we passed an offset of 0.&lt;/li&gt;
&lt;li&gt;  The size of the buffer constructed is based on the base types TypeData structure, of which we only need the internal array. We have added our own size and end markers in the TypeDataImpl above.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Multiple Inheritance
&lt;/h3&gt;

&lt;p&gt;In a multiple inheritance scenario, we use variadic templates to build the BaseTypeData recursively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nc"&gt;BaseTypes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;TypeDataImpl&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TypeDataImpl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;myTypeId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GenerateId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;myBaseTypeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FillBaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="cm"&gt;/* No offset with first base */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Size is the base's size + 1 to account for current type id&lt;/span&gt;
        &lt;span class="n"&gt;myEndMarker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;GetData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; 

    &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;myTypeId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;BaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BaseTypes&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;myBaseTypeData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt; &lt;span class="n"&gt;myEndMarker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The base type data is built taking into account pointer offset. We can calculate it as the base types are unpacked in the variadic expansion, and the final derived type is passed as a template parameter to FillBaseTypeData. This is why we needed to use a static method and not a constructor. The sizes of the following lists are not incremented as no Type ID is added.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;FirstBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;SecondBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nc"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;BaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FirstBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SecondBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Derived&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;FillBaseTypeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt; &lt;span class="n"&gt;aOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;typeId_t&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;outHeadSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;myFirst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FillBaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ComputePointerOffset&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FirstBase&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;outHeadSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;myOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ComputePointerOffset&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SecondBase&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;myNext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FillBaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;BaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FirstBase&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;myFirst&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt; &lt;span class="n"&gt;myOffset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;mySize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;BaseTypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SecondBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;myNext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One word of warning: this technique may be compromised by the compilers. Padding may be added which will not keep the type data contiguous in memory and the algorithms will fail. We can however prevent that using &lt;code&gt;#pragma pack&lt;/code&gt; which is supported by most compilers, or other compiler-specific packing options.&lt;/p&gt;

&lt;p&gt;Here is the mechanic visualized:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i2.wp.com/kahncode.com/wp-content/uploads/2019/09/kcl_build_typedata.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4Y0QxaT_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/kahncode.com/wp-content/uploads/2019/09/kcl_build_typedata.png%3Fresize%3D801%252C377" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Registering a type
&lt;/h2&gt;

&lt;p&gt;With the TypeDataImpl and TypeInfo taken care of, it is now time to implement the mechanic to instanciate these and retrieve them.&lt;/p&gt;

&lt;p&gt;We need to assemble a TypeInfo with the name of the type followed by its TypeData&amp;lt;T&amp;gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;TypeInfoImpl&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TypeInfo&lt;/span&gt; &lt;span class="n"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TypeData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can now use this in a type registration macro. The macro is needed to trigger template specialization and therefore trigger the instanciation of this TypeInfoImpl. Conveniently, we also use the macro to retrieve the type name.&lt;/p&gt;

&lt;p&gt;First we declare tye TypeData&amp;lt;T&amp;gt; type, using &lt;a href="https://github.com/Kahncode/kcl/blob/master/Source/KCL/KCL_Utils_Preprocessor.h"&gt;macro expansion tricks&lt;/a&gt; to extract the first argument and inherit from TypeDataImpl&amp;lt;Type, BaseTypes...&amp;gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define KCL_RTTI_REGISTER(...)                                                     \
template&amp;lt;&amp;gt;                                                                         \
struct TypeData&amp;lt;KCL_FIRST_ARG(__VA_ARGS__)&amp;gt; : public TypeDataImpl&amp;lt;__VA_ARGS__&amp;gt; ; \
// continued...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally the static instance of the TypeInfo (contained in the TypeInfoImpl) is accessed through a static method on the specialization of the GetTypeInfo stuct.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// continuation... TYPE is the type being registered&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;                                                                     \
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;GetTypeInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TYPE&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                                                       \
&lt;span class="p"&gt;{&lt;/span&gt;                                                                              \
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TypeInfo&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                                               \
    &lt;span class="p"&gt;{&lt;/span&gt;                                                                          \
        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;TypeInfoImpl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TYPE&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ourInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;   \
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ourInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                                            \
    &lt;span class="p"&gt;}&lt;/span&gt;                                                                          \
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can now retrieve the TypeInfo at compile time, but we also need it at runtime. For this we must use a virtual method.&lt;/p&gt;

&lt;p&gt;This is declared in a second macro that must be used within the derived type declaration scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define KCL_RTTI_IMPL()                                               \
                                                                      \
    virtual const TypeInfo* KCL_RTTI_GetTypeInfo() const              \
    {                                                                 \
        typedef std::remove_pointer&amp;lt;decltype(this)&amp;gt;::type ObjectType; \
        return GetTypeInfo&amp;lt;ObjectType&amp;gt;::Get();                        \
    }                                                                 \
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Dynamic Cast
&lt;/h3&gt;

&lt;p&gt;The goal is finally within our reach. We have built all the type information necessary to perform a dynamic cast and we can access it at runtime on an instance of a registered type.&lt;/p&gt;

&lt;p&gt;However, there are still a few subtleties in the dynamic cast implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We must not forget to handle the case of a null pointer. Interestingly, the pointer offset is not performed when the parameter of static_cast or dynamic_cast is called.&lt;/li&gt;
&lt;li&gt;  We can avoid the expensive dynamic_cast logic if we can safely call static_cast instead. We will use if constexpr here but SFINAE can be used as polyfill.&lt;/li&gt;
&lt;li&gt;  The offset present in the TypeData&amp;lt;T&amp;gt; is relative to the canonical pointer of the object, that is the pointer to an instance of its most derived type. If we hold a pointer to this object at an offset, we must perform the dynamic cast from the canonical this pointer. Fortunately the &lt;a href="https://en.cppreference.com/w/cpp/language/virtual"&gt;final overrider&lt;/a&gt; rule in the standard allows us to do this using a virtual method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the final implementation of dynamic_cast:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//continuation of KCL_RTTI_IMPL, this method is declared in the object and allows to always begin from the canonical "this" pointer&lt;/span&gt;
    &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;intptr_t&lt;/span&gt; &lt;span class="n"&gt;KCL_RTTI_DynamicCast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId_t&lt;/span&gt; &lt;span class="n"&gt;aOtherTypeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;                \
    &lt;span class="p"&gt;{&lt;/span&gt;                                                                                 \
        &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;remove_pointer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;decltype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ObjectType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                 \
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;GetTypeInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ObjectType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;CastTo&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;intptr_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aOtherTypeId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  \
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//Implementation of dynamic_cast in the global namespace&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Derived&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;Derived&lt;/span&gt; &lt;span class="nf"&gt;kcl_dynamic_cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;aBasePtr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_pointer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Return type must be a pointer"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;remove_pointer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;DerivedObjectType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_base_of&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DerivedObjectType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aBasePtr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aBasePtr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aBasePtr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;KCL_RTTI_DynamicCast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetTypeId&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DerivedObjectType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And there we have it. The &lt;a href="https://github.com/Kahncode/kcl/blob/master/Source/KCL/KCL_RTTI.h"&gt;real implementation&lt;/a&gt; is slightly more complex to ensure more type safety and avoid polluting the global scope, but the principle is essentially the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark
&lt;/h2&gt;

&lt;p&gt;We have done our best to design a RTTI system by packing all the information in a contiguous region of memory accessible at the cost of one virtual method call.&lt;/p&gt;

&lt;p&gt;Let's see how it performs against the standard implementation and confirm that ours is indeed faster.&lt;/p&gt;

&lt;p&gt;Each benchmark runs 3000000 dynamic_casts, and the measure is taken 10 times. Tests have shown that increasing those numbers significantly yields similar results so we will consider this enough to take conclusions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single Inheritance
&lt;/h3&gt;

&lt;p&gt;Here we tested downcasting to the most derived type of a single inheritance chain of varying levels.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i1.wp.com/kahncode.com/wp-content/uploads/2019/09/Downcast-single-inheritance.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fsDjVPdp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/kahncode.com/wp-content/uploads/2019/09/Downcast-single-inheritance.png%3Fresize%3D985%252C609" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see the cost of dynamic_casting increasing with the number of base types. KCL performs better on all compilers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple Inheritance
&lt;/h3&gt;

&lt;p&gt;Similar results can be obtained when examining multiple inheritance. The nested multiple inheritance case is interesting as some of its second bases themselves have second bases. This validates the pointer offset adjustment logic and is assumed to be one of the most complex cases for linked-list implementations to follow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i0.wp.com/kahncode.com/wp-content/uploads/2019/09/Downcast-multiple-inheritance.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8BWZaSIo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2019/09/Downcast-multiple-inheritance.png%3Fresize%3D985%252C609" alt=""&gt;&lt;/a&gt;Once again KCL is dramatically faster in all scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrong casts
&lt;/h3&gt;

&lt;p&gt;Here let's examine the cost of dynamic_cast to a type that is not part of the type's hierarchy. This is the very worst case as the algorithm has to iterate through the entire type information before failing to cast.&lt;/p&gt;

&lt;p&gt;We will also test casts with a nullptr input value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i0.wp.com/kahncode.com/wp-content/uploads/2019/09/Wrong-casts.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aMRA3FV_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/kahncode.com/wp-content/uploads/2019/09/Wrong-casts.png%3Fresize%3D985%252C609" alt=""&gt;&lt;/a&gt;The results are similar again, KCL performs better and the speed gain is higher the more complex hierarchies are traversed. Nullptr cast is virtually the same except for MSVC where it is up to 5 times slower at 10ms!&lt;/p&gt;

&lt;h3&gt;
  
  
  Findings
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Averaged over all the results, KCL performs more than &lt;strong&gt;3.5 times faster with MSVC&lt;/strong&gt;, more than &lt;strong&gt;4.5 times faster with GCC&lt;/strong&gt;, and more than &lt;strong&gt;6 times faster with clang&lt;/strong&gt;!&lt;/li&gt;
&lt;li&gt;  The cost of the standard implementations dramatically increases with the size of the hierarchy. For KCL it only increases linearly.&lt;/li&gt;
&lt;li&gt;  The initial cost of a dynamic_cast is always lower with KCL. We can assume retrieving the TypeInfo is more complex in the standard implementation.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;clang performs consistently better&lt;/strong&gt; than GCC and MSVC.&lt;/li&gt;
&lt;li&gt;  Interestingly, the compilers with the fastest implementation of dynamic cast also seem to perform better optimizations of KCL which results in an even bigger spead increase over their own implementation.&lt;/li&gt;
&lt;li&gt;  I did not report the metrics of upcasts that can be optimized with static_cast. This is because all compilers perform this successfully as well as KCL, compiling down to the exact same code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations and possible improvements
&lt;/h2&gt;

&lt;p&gt;Our approach has some caveats and limitations as opposed to the standard library's dynamic cast. Let's try to list them all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The TypeInfo is created on first access in the static method call. This means the startup performance should be less than the standard, which can compute embed all type info in the executable.&lt;/li&gt;
&lt;li&gt;  This is not thread safe. There could be race conditions in which the TypeID of a type is generated twice at the same time. This can be alleviated in various ways.&lt;/li&gt;
&lt;li&gt;  The static mechanic used to build the TypeID make this not safe to pass across module boundaries. This could be improved by generating a TypeID using a hash of the symbol name.&lt;/li&gt;
&lt;li&gt;  The TypeData architecture duplicates some information by design, and therefore uses more executable space than is stricly necessary. Using linked lists we could theoretically use less space but the runtime performance would be impacted significantly.&lt;/li&gt;
&lt;li&gt;  The design relies on compiler tricks and assumptions that may not hold true, especially with regards to padding. More static asserts, unit testing and instrumentation could be added to validate the integrity of the memory layout.&lt;/li&gt;
&lt;li&gt;  Behaviors related to &lt;a href="https://en.cppreference.com/w/cpp/language/dynamic_cast"&gt;std::bad_cast&lt;/a&gt; exception is not supported as opposed to the standard. If you really need it, it can be added.&lt;/li&gt;
&lt;li&gt;  In addition, we do not support dynamic casting references. This is because references should never be null, therefore a failed cast could break otherwise correct assumptions. The standard dynamic cast uses exceptions which we cannot use. This is however not a big issue as pointer logic can always be substituted.&lt;/li&gt;
&lt;li&gt;  You may have noticed I am using the std type traits. This is to allow you to easily port the code. If you do not want to depend on std at all you can reimplement this easily and better manage your compilation times.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As far as I'm concerned, these tradeoffs are worth the performance boost, and most of the issues can be alleviated by building upon this base.&lt;/p&gt;

&lt;p&gt;If you find more issues with my code, please reach out to me, or better send a pull request!&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this breakdown of a possible RTTI implementation as much as I enjoyed making it. More is coming for KCL, so stay tuned for the next article.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>architecture</category>
      <category>optimization</category>
    </item>
  </channel>
</rss>
