Comfy, the 2D rust game engine, is now archived
github.com
github.com
That's insane. For comparison SDL does breaking API changes every ~10 years (and they implement the previous version's API as a wrapper around the current version's API to support legacy software). Maybe the egui/winit/wgpu devs just expect that every end-user will just pin their package versions for the duration of a project, but it seems like a real burden for devs of libraries like Comfy that depend on them.
Basing any serious project on 0.x libraries is always subject to this issue.
For most use-cases, it's fine to stay on out of date libraries for years, and that's what the Linux distros do all the time (mostly patching crippling bugs and security vulnerabilities).
So I guess I'll hold off on having random numbers in Rust then [1].
I think this speaks to rust's strengths in that if you know your spec, you can write a rock-solid version of it - and its weakness, where if you don't know your spec you'll be making breaking changes a lot.
And I, as his only user, have to constantly update my local Rust installation to newest dev to be able to compile his newest code base.
I understand it's more about him being on edge than the language itself alone -- but it still feels insane for me. In most of other languages, you can't make your code so backwards incompatible even if you actively try.
This is not the majority sentiment, for better or for worse. The project stopped releasing "what version of Rust do you use most" in the survey results in 2020 (which is a shame, imho) the vast, vast majority of folks use the latest stable, and very few use a previous version of stable. I have no real reason to believe this overall trend has changed since then.
This is especially true for an application, which this project seems to be. Libraries may have more of a reason to explicitly lag behind the latest, but there's not really a good reason to bother if nobody else is going to depend on your code.
And God forbid you fall behind on React Native major releases in a project. I think the Expo project's solution to this is for all of the native configuration be done via plugins and cross-platform config[0]. Otherwise you'll be dealing with large diffs of native Android/iOS code that would have even native mobile devs tread carefully.
[0] https://docs.expo.dev/workflow/prebuild/#sensible-upgrades
Why? As I see, requiring a higher minor version of your dependency including the compiler is not a breaking change (and does not warrant a major version bump wrt semver), as there should be no problem in bumping the minor version of any dependency, even if it's used for different packages.
Someone should tell that to Rust library devs, because from what I understand, their packaging ecosystem pretty much always assumes that all libraries are running on the latest version of Rust.
There's no "commonly used versions" or LTS builds for Rust, so it seems that every packaging maintainer just supports the latest and everyone is up shitcreek if a new version changes and hard breaks code for older Rust. With how micropackage oriented Rust is, you practically can only jump to the newest version if you want your builds to keep working since I doubt you'll be using stdlib-only Rust.
Compare and contrast every (anecdotal) Rust users favorite bugbear, Python, where if you're building a library, it's pretty commonly assumed that you can follow one of the two major deprecation points for Python versions (end of bugfixes or end of security updates), which means most major libraries usually follow one of the two for the internal features (and therefore lowest version) they use.
The bytecode would only ever work with the VM that it's been compiled against I think, which sounds to me like the real issue here...?
I don't think you'd have this issue if you'd fetch your rust dependencies via git and then build them locally.
And pre building for every version is expensive, which is likely why the rust ecosystem doesn't really do it right now.
And I doubt it's gonna change unless a MAMA (Microsoft, Apple, Meta, Alphabet) company "embraces" it... The EEE style
Rust does not have a VM, and doesn't use bytecode.
That being said, it could in theory serve them as binary code, which yes, would then mean that it would need to be stored per version and per architecture both, which would be quite a lot more than the source that's stored now.
At the very least I can say, that experiences I've had that are common in rust, where I have dependency X needing to be upgraded in lockstep (the same version) across multiple external dependencies with different maintainers. Are things that I've basically never experienced with C based languages.
At least I don't think it is just that things need time to stabilize, but also just the packaging system causes network effects which you don't get the joy of experiencing if you don't have one.
Also, previously I had weird quirks occuring randomly, but after having switched to vendored deps, everything works stable, reliable, and as expected.
I don't agree with the fast pace of how often certain crates produce breaking changes, but I found that with Bazel at least stuff works all the time regardless. Also, builds are noticably faster because downloading and building sub dependencies can take considerably time in large projects.
I am leaning towards starting future Rust personal projects on buck or bazel or gn, instead of Cargo. And checked-in vendored dependencies.
It's not a popular position, but I have seen the crates explosion in larger projects go so wrong... And 10 years at Google taught me that vendored third party deps is an entirely reasonable approach for that.
That said I am intrigued by using buck more as well, though I haven't been actually doing it yet.
If upstream (which you’ve vendored) releases a security fix, how does your system capture and act on that event?
If vendoring just means we periodically pull a copy of upstream into our repo then you can have unbounded time when you don’t know there’s a vuln and therefore haven’t considered whether you need to act.
This is obv different from the situation where we all just cargo install (without —locked) and different from c style dep mgmt where we get sec fixes for many libs via our OS patching.
You still retain the Cargo.toml and Cargo.lock, so the exact same way as if you didn't vendor: `cargo-audit` would inform you, you'd update the version, and re-vendor.
Are some developer(s) on the team responsible for subscribing to the relevant vuln lists and scanning them each day? Do you buy in some tooling?
But, also, this is pretty far afield from my original question: I understand why keeping copies of your dependencies can introduce various things you should handle, but my original question was "what is vendoring your dependencies if not 'keeping a copy of the source code of your dependencies in the repository'"? That's my understanding of the definition of "vendoring," so I was curious what my original parents' definition was.
In C they also only happen when you update the dependencies you have.
Granted, Rust makes it easier to pull on dependecies, but it also makes it easier to keep them up to date.
great in theory but ``cargo install`` will straight up ignore lockfiles by default[0], meaning trying to install a binary package is a roulette of "did this tiny package update before everyone in the dependency tree noticed"
That mindset leads to the start of this thread:
> It might not be obvious how much effort it takes to manage bugfixes in dependencies where every few weeks there's a new breaking API change in egui/winit/wgpu, and while these probably seem extremely minor to those who spend all their time building an engine on top of said libraries, sinking a day or two in figuring things out and fixing stuff on every release is a gigantic waste of time in my view.
This same sentiment is also echoed by Steve Klabnik here [0], it seems.
As I said, the mindset.
It's just that developers in the slow languages don't do that often.
With the guarantee to be able to build older projects (version specified in the Cargo.toml file) and only one real mainstream compiler (the "can compile code but lacks any of the language checks" GCC version doesn't really count), there are few downsides to always having the latest compiler, something other languages sometimes struggle with.
Coming from Rust, I made the foolish mistake of installing the latest Clang and GCC, only to find out that tons of software suddenly stopped compiling because apparently the code requires old compiler bugs/features to work (that are not emulated in newer versions). I've had similar issues with Java, where JRE 17 or 21 could not compile Java 8 projects without modifications to the project because of the new modules feature.
In an environment where updating your compiler toolkit is basically worry-free, it's a lot easier to use recent or even unstable functions. This invites developers to make use of recently added APIs, whereas developers from other ecosystems will wait months or years before even considering new APIs that have been stabilised.
It went something like this: you start with a nice little tidy spec for basic arithmetic; how "a + b" must be the same as "b + a", etc. Then the designer comes back to you and asks for the ability to make numbers blue. You're like wtf but ok, when you add a blue "a" to a non-blue "b", the result becomes blue; you must remove half of your tests (because they no longer even apply) and rewrite the other half to match the spec, and a week of work later the result somehow still makes some mathematical sense. Then the designer comes back to you with the request to make even numbers shoot sparks on death, and to remove all fives...
And it's just how it goes. Games need to be iterated on quickly and efficiently, with a tight feedback loop on what ends up being fun during playtesting, and what doesn't. Rust might be great for writing low-level code / engines, but it will constantly get in your way where you need to respond quickly.
It might be that rust ecosystem this dev was dealing with was itself draining with continually shifting APIs, but that's not the same as the language itself.
The problem is C is far too low level. And everything you can do in C, you can do in C++. You just also get things like namespaces and RAII.
From a game making perspective, there's no rules anywhere saying you have to write good, readable, C++. You can, and often people do, make amalgamations and monstrosities. You can do this very quickly, and if there's little bugs here and there it's no biggie, because you're just making a game. A segmentation fault is really not the end of the world.
Rust isn't actually nicer to program in than C++. It takes longer to produce the same amount of code. The tradeoff is correctness. So now the value of using Rust depends on the value of correctness. In most domains, correctness is very valuable. Game development is one in a million, where correctness really doesn't matter that much. What matters more is velocity and tooling.
Even if Rust catches up with C++ in tooling and is stable, I don't believe it will replace C++ in gaming specifically. Because C++ naturally orients itself more towards that super fast development, throw-shit-at-the-wall approach to software. For gaming, that works best.
... and without the messiness of OOP inheritance in C++ messing with your convoluted game rules... (that was the main thing kyren was focusing on in that keynote) - obviously you don't have to use OOP, but your C++ frameworks probably do, and it's the natural way to do C++ and to augment your data structures with useful behaviours... if you're not doing that, you're kinda back to C-like, and at that point I feel Rust does win again...
C++ is one of the most flexible languages, ever. OOP is a very tiny part of C++. You can 100% do data-oriented designs. And most and engines, do!
> if you're not doing that, you're kinda back to C-like
I don't understand how you can believe this. Maybe you don't have the C++ experience.
You have higher order functions, you have templates, you have compile-time programming. Hell, C++ has higher-kinded types - even Rust's type system can't do that!
C++ is very convenient to program in and very powerful. That's why it's used for games and will continue to be used for games. Rust is not more powerful, in any ways, in that regard. It can do the same shit, but with more headache. Usually that's worth it, but not for video games.
AND don't bundle bugfixes with API breaks if it can be avoided.
Otherwise, just don't bother!
This is hype-driven development at its worst.
For Slint (Another GUI toolkit in Rust), we try to keep our API as stable as possible for as long as possible. We use other crates behind the scene such as winit and co., but we don't expose them in our public API, and we take care of the burden to update them.
My background is as a generalist full stack developer using Node, Python and similar things. I have used C but only deployed one very small thing in production. I have managed devs using C++ but I took the view that I wasn't up to coding C++ for production (more or less Pit of Failure vs Pit of Success thinking).
I started a commercial project some time ago which required one application (think data ingestion) to be high performance. I decided to try Rust and these are my observations:
1. I was able to learn Rust while writing a daemon/service application which performs well and is robustly handling millions of "objects" per day for the last 6 months. I don't think I would have managed this with C++ without blowing my own foot off several times.
2. Library support for everything I needed was excellent. I have yet to experience a breaking change since starting the work more than a year ago.
3. Library devs have been very responsive and chatty about problems etc...
4. Really enjoyed working a strongly typed and compiled language. Bugs are bugs, but I realize that I've had a habit of just spotting problems in production after the fact and fixing them for things that just shouldn't happen. It's like DB integrity once you get used to it, it makes you feel a lot better.
5. Syntax is ugly as all hell.
6. Async / Tokio stuff makes you feel like you have no idea what's going on.
I think somewhere between the "Rebuild it in Rust" and "Rust is a horrible Deadend" there is a real opportunity to have a solid language which can allow devs of my level build decent software.
Update: when I wrote slow, I meant development pace, not runtime performance
Edit: I just noticed that this article is also writen in the archival reason. I'll leave it here anyway for those that miss it.
Development time is absurdly faster, though, since you don't spend much time debugging annoying language-design bugs, and can focus entirely in your code's logic.
That is if your code satisfies the borrow checker out of the gate, fine. I have seen Rust book authors get derailed for years by apparently simple seeming projects that do not.
rust can be very frustrating because it forces you to think up front at a level of safety you may not be used to. That's the issue.
I do fairly simple things with rust (i.e. just some threads, no complex data structure (but complex program nonetheless)) and rust safety helps me a lot in reducing the number of bugs.
There are types in the standard library that, if you use them, do runtime checks. If you run afoul of those checks, then yes, you’ll get a runtime failure. (The primary example being RefCell<T> linked in the article linked there, yes.)
These types are not super common in Rust code generally, but they do exist and are useful at times.
Think of them like Python's metaclasses.
What are you referring to here?
Sure, once you get your code to compile things may go faster. But getting there is not always easy.
I don't mean to be dismissive, but if this was really true we'd all be writing TLA+ specifications/Coq proofs before finalizing our Ada SPARK implementations. In reality, static analysis only improves development time if time_lost_to_debugging > time_lost_to_arm_wrestling_compiler, and in my experience that's not always as common as one would like to believe.
Utter BS. I mainly developing in C++ at the moment (not limited to this single language though) and I do not find myself debugging "language-design bugs". I do not design libraries hence my code and set of used language features is of course simpler. I tend to avoid esoteric code and do not have habit to shove everything into new templates.
Outside very specific use cases, we already have Ada like safety on programing languages with automatic memory management.
Many people here say that languages like Ruby or frameworks like Rails are dying, or some such, but in reality these languages just carve out their space, settle into it, and become the go-to choice because there's nothing surprising about them any more. If Rust can be considered stable or boring in this way then it will have succeeded where a lot of new and novel languages tend to fade into obscurity.
It turns out that when you need to get the details right and be safe in a systems level language, development can be slow. This is a good thing. Studies with Ada projects compared to C have shown that time and money is saved in the long run due to fewer bugs and less maintenance. You just have to embrace that particular suck because it pays off in the end.
Such unfinished code can be obviously buggy and unsafe, but in game dev it matters more to have short feedback loop to try how things feel, than to have a perfectly correct code all the time.
Rust doesn't do quick and dirty, and will complain about code quality even when game devs don't even plan to keep the code.
This is a substantially different situation from other domains like application and services development, where it's easier to plan what you're going to implement, correctness is more important, and you don't need to try out 20 different JSON parsers to see which one has the most satisfying feel.
I've worked with Bevy, and there's it's incredibly easy to write "quick and dirty" to test stuff. I guess the major "downside" you need to account for is that the type system will try to prote you from crashes. Which can be a bit of a chore since youknow it won't crash with the values you've given it. But if you're comfortable with .unwrap and the occasional unsafe while prototyping, it's honestly fine (at least within Bevy).
Alternatively, they could try "scripting" behaviour first before implementing it in Rust, although from what I understand bevy's scripting support (I don't think it's explicitly supported, but bevy is very extensible) is still very early in development
If you add a scripting language and blueprints, you're shortening the feedback cycles by using Rust less.
I like Bevy, but it seems like Rust currently is much better suited for making game engines than the games themselves. Some "RustScript" is needed.
Can you elaborate? Or did you mean dynamically dispatched?
2. Bevy's entity references are generational IDs, without static lifetime guarantees (and restrictions) of Rust's references.
They do, they're `Entity`, always.
> where you can add and remove properties at will
I don't think this is true for either `Component` or `Entity` in Bevy. You set what fields a `Component` has when writing the code, then it remains so during the runtime. There is no dynamically adding/removing fields at runtime, at least yet.
What you do tend to do in Bevy is adding/removing `Component`s to `Entity`s at runtime, is that maybe where the confusion comes in?
Yes, technically, but in how they're used - no. They're a dynamic type.
> What you do tend to do in Bevy is adding/removing `Component`s to `Entity`s at runtime
Yes, this is dynamic typing. Or, at least, one way to look at it - and what allows games to be iterated on quick.
No, they're really not. Are you talking about Archetypes or something else? Because an Entity is just a ID + a generation, that's it. Nothing more and nothing less. You don't define them as more/less, nor do you use them are more/less either.
> Yes, this is dynamic typing. Or, at least, one way to look at it - and what allows games to be iterated on quick.
I guess a `Vec<u8>` is also then dynamic typing in your mind as you can add/remove elements to the vector? Doesn't really compute for me personally, but whatever floats your boat.
That approach gives you the best of both worlds: high-performance core with high-velocity iterations for gameplay. Don't use Rust or C++ for scripting... madness lies that way.
Also supports is kind of relative,
"CHR is very new and experimental feature of the engine, it is based on wildly unsafe functionality which could result in memory corruption, subtle bugs, etc."
I also think that doc page is a little old. The feature is over 2 years old now and hot reloading is inherently "unsafe" in any compiled language. It's just letting you know that Rust's safety guarantees might go out the window if there are bugs in the code that handles hot-reloading.
Also that was only one example, there are other similar ones.
You can do very easily do quick and dirty in C++. (And shoot your foot off also..but that's a different thing)
Such code is of course crappy, but the OP wants to test if things are fun before committing to implementing them properly. Rust wants things done properly on the first try (which usually is a good thing, except throw-away prototypes).
The problem might just be an aversion to using quick and dirty solutions. Rust does a good job of making it feel wrong to write code that's not production ready, but there's nothing stopping you from using unsafe wherever you want.
> Comfy is now archived until further notice... After abandoning Rust for gamedev [1] ... I just don't have the energy to constantly play catchup to the Rust ecosystem
[1] (April 2024) https://loglog.games/blog/leaving-rust-gamedev/
I don't get why somebody would start a new project based on OpenGL these days.
Depreciated by 'who'?
It's a standard, not a feature from some company that is ending support. There is a governing body.
"The Khronos Group, Inc. is an open, non-profit, member-driven consortium of 170 organizations developing, publishing and maintaining royalty-free interoperability standards for 3D graphics, virtual reality, augmented reality, parallel computation, vision acceleration and machine learning.[1][2] "
By the very Khronos Group you mentioned. They are developing Vulkan now, which they consider the successor to OpenGL. There will be no new OpenGL versions, again it is deprecated technology. Deprecated by its creators just like Python 2.
And just like Python 2, you can still use it, but again it would be a questionable choice for a new project in both cases, and for the same reason.
It isn't like because Python 2 was depreciated, you have to switch to C#. It isn't gone. You can use the new version. Or older version until ready to migrate. Maybe it seems like it because of a name change, and you don't want to call Vulkan, OpenGL
So why give up on OpenGL altogether, when there is continuing development.
Going from Python 2 to 3 wasn't a cake walk. Hence so many years to migrate.
But I get what you are saying. Some upgrade paths are easier/harder than others.
Yes, even despite of many similarities and shared stuff, which can't really be said about OpenGL and Vulkan.
I think the term "deprecate" implies some level of actively discouraging use that is simply not happening with OpenGL (and that was/is for sure happening with Python 2). Specific platform vendors may deprecate OpenGL on their platform (as notably Apple has done), but that does not mean OpenGL is deprecated by Khronos Group.
OpenGL will continue to be supported for the foreseeable future but it will not gain any major new features, and it will likely lose direct support (requiring emulation or shims to actually work) on many platforms that still do support it now within a decade. For many games, this actually isn't a big issue, as they're not pushing the envelope anyway. But for those that do (or potentially will), OpenGL is the wrong choice.
If you don't need the features of the newer APIs it makes perfect sense to keep using it.
Let me say this loud and clear for anyone who dares to hear a fool: don't even think about performance until it becomes a problem and even then you could still probably stand to ignore it. Ergonomics are infinitely more important for an engine. If you can't develop and iterate quickly you can't prove your ideas and make something fun. These are two things Rust is very bad at.
Rust is good at many things, but game development is really not one of them. C++ is still okay. If you want to try something new, Odin[1] is shaping up nicely.
> At this point I've fully switched to developing games in C++, and I'm very happy with this choice.
Hm.
Well, I hope that works out for them, but if iterating speed and quick prototypes with hot reloading that doesn't crash is what people are looking for, I don't think anyone who hasn't spent 20 years programming in C++ is going to find it there (or possibly, anyone at all...).
I feel like as a small-moderate sized team, you really REALLY need a compelling reason not to pick UE / Unity / Godot.
The choice of language probably is less significant than the decision to use an existing engine rather than rolling your own.
For all the talk about prototyping and iteration speeds, and given they have:
> released a game on Steam in Unity, Unreal Engine 4, and Godot
I'm astonished that they haven't prioritized 'stick with one technology and ship more often' over 'try new things'.
This is all valuable feedback.
But
Rust is new, so libraries are still in flux. That happens with being 'new'.
This seems more like single dev running out of time. Not a huge condemnation of Rust.
There have always been people who have been skeptical of, or dislike, Rust. Just like every technology.
> even something organized and funded to push anti-Rust sentiment?
Nah, anyone who believes this is engaging in conspiracy theory.
That in mind, the main reason why people tend to get frustrated with Rust to the point of condemning it is because Rust programmers tend to be rather zealous of how much they want to spread it's use, even in domains where it's more a disadvantage than a strength (game dev is the most obvious example, but Rust is a quagmire of constant rewrites if you have any form of rapid iteration or unstable specs). When those disadvantages subsequently pop up and become an issue, the response from Rust programmers often amounts to "you're holding it wrong", which just makes people curious about the language more annoyed since it comes across like their problems aren't being taken seriously.
It's perhaps no surprise that Rust communities oft find overlap with Wayland and Nix zealots because of this, where the shortcomings of their tools aren't an impediment to getting as many people as possible to use their tools.
I don't think it's any concerted movement, it's just that people tend to get annoyed when they're preached to even when what's being preached doesn't work for them, so they push back against it.
It was a personal project then. It wasn't until 2009 that it was shared more publicly, and the first stable release was in 2015.
That's still almost ten years ago, so your overall conclusion about it not being new is not incorrect, but it's not as old as you suggest here.
That said, if you actually look at the things the critics are saying, most of them are from a place of misunderstandings. Every time there is some Rust drama, tech influencers like primagen are doing back bends to be “fair”, even if it means given reasonable doubt to an unreasonable position, lest they turn off audience members who are too emotionally invested in seeing Rust be bad because it validates their choices.
What a weird thing to say. There is no 'standard language', never has been and never will be (otherwise we'd all be programming in Java or Javascript, which during their heydays were 'obviously' becoming the 'future standard programming language').
Ask innocent question about why there seems to be a lot of drama, negative feedback about Rust.
Get downvoted.
Isn't this part of the problem? Can't ask about it without inviting backlash?
Was only asking in this way, because a lot of the negative feedback in the entire thread, seemed counter to how things actually are in Rust. Kind of like FUD.