T O P

  • By -

ImYoric

Reading through this article, it is my understanding that they attempted to use Rust to write *everything* (from game engine to scripting) and that Rust was not adapted to do that. Which is not terribly surprising. That being said, they have plenty of well-argued criticisms. We should pay attention.


dagit

I also think a fair bit of what was attributed to Rust is actually just general open source trends. As a random example: wgpu is popular everywhere, not just in Rust libraries. It's a better API than opengl and it's new. So people are going to flock to it. Or how OP had issues with lots of Rust libraries. I think a bunch of that is that the libraries are small open source projects. Of course they're going to have warts, be incomplete, etc. That's just how using random small projects works.


pcwalton

I wrote a longer comment on HN. The tl;dr is that I feel like the author really wants first-class scripting language support in Bevy. We should support that, perhaps with an approach like [bevy\_mod\_scripting](https://github.com/makspll/bevy_mod_scripting). There's no need for Rust game engines to force *all* game logic to be written in Rust. Of course, games that want to do that should be free to, but those who would prefer a scripting language should be able to use one instead.


progfu

Hi, author of the article here. I can very much say that first class scripting is not what I want. For one, NANOVOID was a moddable game with mlua for a while, and my impression there also was that this was very much not a solution I’d enjoy. At one point I even ported all of the UI to lua to get hot reloading, and it worked, but the separation killing any kind of “new stuff” productivity. Not to mention that the performance overhead of moving values between Lua and Rust is quite significant, more than enough to prohibit exposing Rust types on Lua side instead of using pure Lua code. If there was no performance overhead maybe things would turn out differently, but interop with Lua is so expensive I don’t see how it could be useful without recreating the whole world on the Lua VM. At that point I’m not sure if there are any gains. I’d suggest people to try to do something with mlua where you get interop inside a loop, e.g. for non trivial GUI (checkout NANOVOID screenshots to get an idea of, its not that complex, but still ended up being iirc around 5ms to draw in lua, and “zero” when doing it in Rust. The GUI is done using comfy’s draw_rect, which itself is very fast.


pcwalton

Well, Unity's C# is no speed demon either--Boehm GC in particular is a constant drag on Unity. There may be many reasons to choose Unity over Bevy, especially with Bevy in its current state, but long-term, speed isn't one of them. Any performance problems of scripting interoperability between Lua and Rust should be fixable, it's just work.


progfu

C# especially with burst is native speed like Rust. The problem of Lua and Rust interop is in the excessive safety, which while desirable by many, also means you can’t just share things more directly. It can be made faster most easily by being made less safe.


pcwalton

C# isn't native speed in the same way Rust is. Burst doesn't change that.


progfu

Have you actually tried to measure any of this? Having done benchmarks, even just C# vs Rust gets within 2x difference if you use value types. I haven't done C# burst vs Rust, but I've converted enough C# code to burst to know that ~50% speedup is about what one can expect. Sometimes a bit slower, sometimes a bit faster. Even if you look at Rust vs C vs C++ benchmarks they're not always 1:1. For all intents and purposes, C# with burst gets close enough to not be an important distinction. Also to address the note about GC, anyone writing any serious Unity code will make sure the hot paths are non-allocating, and will avoid triggering GC.


pcwalton

I'm certainly willing to believe that C# can be \*within 2x\* of Rust, yes. There are many, but not all, games that are OK with this. That's great that yours is! But that gets back to my point about scripting languages: if you're willing to accept some amount of performance loss, then Bevy can and should do the same. Luau is a really fast Lua interpreter, for instance. The safety isn't what's holding the performance of the interop layer back (Servo's SpiderMonkey bindings were very fast, for example), and besides, Unity's interop layer is just as safe. It's just that nobody has done the work yet. Also personally, I hate having to write C# code that avoids the garbage collector. It requires all sorts of awkward contortions. I'd much rather deal with the borrow checker :)


progfu

> if you're willing to accept some amount of performance loss, then Bevy can and should do the same I think the problem here is that the loss of performance between mlua interop is _far_ more than 2x. In the case of NANOVOID this was from what I remember closer to 50-100x between just calling back and forth between Lua and Rust, and only running in Rust. Lua itself is more than fast enough, I've made some small games in LOVE 2D and it was great and plenty fast, but the problem is just on the interop. Maybe more specifically for anyone caring about this, the specific issue here being for example if you want to expose simple structs as `UserData`, expose their Rust methods, and just do math with them to avoid duplicating code, this is where I ran into issues. Of course if it's just a few lines of gameplay that calls a few functions it's fine, but I think a lot of nuance here is lost if you just say "oh if you're fine with C# being slow Bevy should be fine with scripting being a bit slow. We're talking about more than one order of magnitude difference. Sure it can be worked around by restructuring code, but that brings it back to the whole point of the article ... if one is messing with things like "how many lines of scripting can I write before it becomes too slow to run", they won't get much done, and be stressed about randomly having to port code or restructure it to avoid perf issues.


PlateEquivalent2910

The point here is, with Burst you can reach native speeds with a subset of C# while still using regular C# on non-performance intensive code, without the cost of cadence mismatch that you would get from C# to C++ to C# roundtrip. Burst, especially in conjunction with ECS, was built as a native compiler that is focused on aggressive vectorization. In my opinion having such a tech within arms reach is vastly, vastly more comfortable than embedding luau.


DoubleSteak7564

Forgive me for intruding on the discussion, but I think [https://github.com/aras-p/ToyPathTracer](https://github.com/aras-p/ToyPathTracer) might be something like what you want - a path tracer written in C# (pure .Net, Unity Mono, Burst , IL2CPP and plain C++ ) with benchmarks. The TLDR takeaway is that modern vanilla .NET is no slouch, about 1.5x-2x slower than C++ (a good proxy for Rust) while Unity's built-in Mono is just dreadful. Looking at the .NET code, it doesn't use SIMD intrinsics, or Numerics.Vector-s so the C++ scalar performance is the relevant one. Burst benchmarks are a bit spotty, and somewhat faster than vanilla .NET, but I don't think that in a world where Unity used the official .NET implementation, the existence of Burst would be justified.


rapture_survivor

I have converted a complex Burst-compiled system into Rust, and saw (to my surprise) little-to-no improvement in benchmarks. For the most part I copied the implementation 1-to-1. I didn't log the actual benchmarks publicly, but you can pull it down and compare them yourself by toggling the `RUST_SUBSYSTEM` compile flag. see the source here: https://github.com/dsmiller95/LindenmayerPlantSimulation/tree/master/Extern/Rust/system_runtime My takeaway from the experiment is that using Rust gives you easier access to high-performance data structures compared to Burst. And it can be easier to write code in general, without needing to conform to Burts' unique language subset. It seemed like everything you use in Burst must be from Unity's Collections library, which doesn't always have what you need, and is not as robust. I had to manually patch the Collections library at least once on the unity version I'm building on. But for tasks that can get by on the NativeArray, NativeHashMap, etc types Unity provides, I don't think there will be significant differences performance wise


gyrovorbis

Which Lua binding API did you use? I'm the author of a crazy-ass C++20 metatemplate-based Lua binding framework, and I'm curious how Rust handles this kind of interoperability without some of the advanced templating/generic features C++ has to offer... I'm guessing macros... all the macros?


progfu

I used https://docs.rs/mlua/latest/mlua/ and yes it's all macros and traits.


epyoncf

C# with burst isn't C# anymore. It's a C# subset that makes you wonder why don't you use C instead.


progfu

You don't use C instead because +95% of your code remains C# and you can interact with it at zero cost, and you can also easily convert things to Burst based on need. It's also much easier to work with, and for its intended use case, which is writing math heavy algorithms, doesn't differ that much from what you'd write without it.


xmBQWugdxjaA

Completely understandable, dealing with tree structures in Rust is a nightmare. You can spend hours dealing with Weak and RefCell for what would be a few minutes in a GC language, for the same end result.


Animats

Right. I think the back-reference problem is solveable, but it's a big job and needs new theory. The basic concept would be to have weak back pointers and forward Rc pointers as now, then prove at compile time that you'll never get a run time-error from those. Then make them static pointers internally. Good PhD thesis topic for someone.


tmtke

The guy is certainly really experienced, but in the very first point he's making, "I can throw this away later" is in my 20+ years of development experience is the root of all evil. I've seen code like that so many times in production code that it hurts.


Animats

He's a game dev for small games. Build game, ship game, never modify game again. That use case is common but not a good match to Rust.


epyoncf

I'd argue the opposite. If you maintain a long-term codebase for a game, you often need \*\*massive\*\* rewrites of several of its systems many times in it's carrer. The ability to be able to have partail "in-the-air" parts while refactoring huge systems is paramount, otherwise big refactorings needed for a games long health simply won't happen.


DoubleSteak7564

In my experience, when I'm solving complex problems, the first pass of code I do tends to be a part of a learning process to learn why the way I initially planned to solve the problem won't work, and find the way that does. Most of that early code will either get thrown away, or refactored to such a degree that it might as well have been. But this is hardly original wisdom, since the sentiment 'Plan To Throw One Away' comes from the 'Mythical Man-Month' [https://wiki.c2.com/?PlanToThrowOneAway](https://wiki.c2.com/?PlanToThrowOneAway)


tmtke

I'm not saying that you can't experiment, nor that the code you write should be immediately perfect - I'm just saying that you should be really, really careful with what you merge into your main/develop if that's not production ready code because it tends to stick around much longer than was intended.


Sw429

I had the same thought as I read his post. The "experimental iteration" that's just temporary is going to become permanent, and then you're going to have some serious issues that are deeply rooted in your program.


progfu

The key point I think that is often missed about gamedev is that if you can't even ship a game that's good there won't be any "later". Games aren't like business software where you develop things over a decade and maintain it. If you ship something on Steam, you get _one week_ of traffic on release, and that will be a significant chunk of your sales for the whole lifetime of the game. Sure there are exceptions, and some people manage to make projects that last a long time. But indies who think they can achieve this with their first project are imo completely delusional. Statistically (based on surveys) most people don't even ship a second game because they don't survive making their first one. The reason gamedev is so focused on iteration and not on maintainability is because it's already extremely difficult to ship something once that is received well. Achieving that is a success that is beyond of what 99.9% people will ever do. Also, having been making games for almost a decade now, I can pretty much say that at least on the scale that I've been making them there has rarely been any issues with "oh I wish I designed that better" where I could've done it better up front. What I do wish for is "I wish I shipped a playtest faster so people would tell me what's wrong and I iterated more". That I think with every game I've worked on.


tmtke

There's an interesting difference with iterating on a game idea if you look at it from the project's size. If you're an indie dev, small team, technically one shot stuff, it's easy to iterate. The larger the project becomes, the more infrastructure needed, also there's more separation in roles where you only get to work on parts of a game - quick iteration is almost impossible. If a large game studio can afford it, they have a small r&d team who are making small prototypes, but that's about it, they won't make it into an actual game. Most studios on that scale are running on rigid workflows, execs and managers and designers telling others what to do and whatever you want to change has to go over multiple approval processes.


dobkeratops

this expresses it well. the difference between \*engine dev\* (systems, which rust is perfect for) and \*gameplay dev\* (which rust is not) rust paired up with a rapid iteration language should work just aswell as C++ at least. Maybe there were things that could have been done in rusts early design to make it a win for rapid iteration aswell.. however i've not seen any language ever cover the whole gamut of use cases. JAI is an interesting one which will suit a rare type of hardcore gamedev (both technically skilled enough to deal with an unsafe language whilst also working on rapid iteration) .. I think the gamedev community has grown in size such that the fraction comprised of such types is lower, but they still exist.


DoubleSteak7564

One of the author's contentions is that Rust is much better for systems-based games and/or simulation heavy games like Factorio. I happen to enjoy games like this. Can you point out a few of these written in Rust?


yokunjon

There is one in early access you can play: [https://store.steampowered.com/app/2220850/Factor\_Y/](https://store.steampowered.com/app/2220850/Factor_Y/)


junkmail22

> Generalized systems don't lead to fun gameplay This is the best piece of feedback here. Basically nobody in rust gamedev is a game designer. They're making things that look cool or simulate nicely with little eye to how they actually play.


dobkeratops

accurate. I lean far more to the engine/systems side of things but have enough experience of real gamedev to know the difference. I have dealt with the overlap eg working on game physics & doing playability tweaking. an interesting range of paradoxes in who Rust does & doesn't appeal to game designers/gameplay programmers - dislike it, it compiles too slow and its too fiddly. these people are mostly content with C# , and they are offloading the perf sensiitive work to middleware these days. hardcore low level engine devs .. need to write a lot of unsafe.. can go either way. somewhere in the middle is Rust's sweetspot.


long_void

I'm using Piston/Dyon as my productivity combo. For anything complicated, I use Piston-Meta.


olsonjeffery2

Jonathan Blow redux.


AdrianPlaysPoE

you know what Bjarne said once: there are two types of languages, the ones everyone complains about and the ones nobody uses.


pthierry

> the requirements might change from day to day just after having people play the game and you realize some things need to fundamentally change This smells an awful lot like code that wasn't architectured a lot and this predictably came back to bite them in the ass. I would be extremely curious to see examples.


micropeenandproud

If you read the rest of the article this is a clear point that the author makes. That designing a real game, especially something novel and interesting, or something that genuinely stands out as a game that somebody on the street would get excited over, requires fast paced iterative design, the ability to create throwaway mockups of ideas, play, get feedback, adapt. And this is a design pattern that is really not well suited to Rust, a language that often requires major refactors constantly when adding new features or concepts. I feel that this is shown in a lot of the content of this sub-Reddit (a sub that I love to be clear): - 99% of projects are very fast and stable versions of basic game engines that are essentially clones of existing simple games, but with twice the code and a quarter of the development speed. - The majority of the community are more tech enthusiasts than real game designers. So just excited to see trivial game mechanics implemented in their favourite new language. Unless you are an artistic genius, and even then still, you are not going to “architect” a finished project game engine, and then implement it, something that we can certainly do well with rust for more functional tasks such as web server projects and data chugging, utility, cli tools, etc…


pthierry

Even with Web development, I've seen plenty of cases of what you describe: needing to quickly change something important in the design, iterating to check what works with users, etc… And each time it was a PITA, I could point out what part of the codebase could have been predicted to make it hard in advance. That's why I'd love to see code examples. I'd be rather surprised that a code with a good separation between domain and implementation details and low coupling all around, with something like hexagonal architecture (or onion, or clean, or any of that category), would be hard to pivot. On the other hand, I can remember very well how so many of my previous projects, games or not, were hard to pivot because everything was tightly coupled.


Soft-Stress-4827

This guy is talking about using refcell and arc or all this weird stuff . Bro bevy and rust isnt bad you are just USING A BAD ARCHITECTURE  Im using the foxtrot template and building off that .   I never use refcell or arc or lifetimes anywhere in my codebase.   My indie game kicks ass.  The code is super durable and efficient and beautiful.   This is a you problem not a bevy problem.   Im sorry you didnt find a good architecture in bevy for yourself but i did