Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: I wrote my own RTS game engine in C (github.com/eduard-permyakov)
1102 points by epermyakov 41 days ago | hide | past | favorite | 262 comments



Very nice code quality.

C gets a hard time and this code base highlights some of the modern features C is missing by its use of perfectly clear workarounds. E.g. The prefix “namespacing” done here works just fine, easy to understand. The go-style visibility approach is growing on me lately and it works well here.

C does deserve some of the criticism right enough, e.g. the same macros re-defined in a few places - it’d be nice if c had a better way than its version of macros although its not actually a problem here because the macros aren’t really big enough to have subtle sharp edges.

Ahh a beautifully written project, just shows that maybe C is entirely workable in the right hands.


I see a lot of salt in the comments below on the C language. Like, "how do you scan a string", "it is unteachable to junior devs", "not because you are used to it, it does not mean it is any good", etc.

Well, the same old critiscisms again and again. You can do shit in any language if you don't understand what you do. For instance, Duck typing in Python or Javascript can lead to huge mistakes at runtime, code injection and unchecked values in java can lead to severe runtime crashes, etc.

So yeah basically you want good code quality (knowing what you do) and good unit testing in any language.

C has proved totally workable on many occasions. I guess a lot of the comments on this thread where written from a Linux Kernel :)


Or a Windows Kernel which is also (mostly) C.


The nice thing about C is that it's so small that you can hold every corner, nook and cranny of the language in your head. There must be less than a dozen people in the world that can say that about C++.


Quick, I need to parse a simple string; should I use scanf, fscanf, sscanf, scanf_s, fscanf_s, or sscanf_s?


You write your own parser.

Seriously, I don't use scanf that much in C. Most of the times, it doesn't do exactly what I want, or there is a more specialized alternative (ex: strtol). Also, generally, %s is bad, even the "safe" variant. For sscanf, it makes a copy, which is inefficient (if you are writing C, you want efficient code, right?) and you have to know the size in advance, and usually, you don't.

Most of my string manipulation in C involves loops, pointers and a lot of in-place manipulation. It is tedious compared to other languages but it is very efficient, the reason I picked C in the first place.


So in the context of the larger debate, this answer falls in to the "C is simple, until you try to use it, at which point you start writing your own programming language in C to write your application in," category. In this perspective C is simple mainly because it's missing the already-written code that you have to benefit you in other languages.


I don't think any of this is close to fair. "C is simple" and "it takes some work to do stuff in C sometimes" aren't mutually exclusive, in fact the former necessarily implies the latter. C is simple, which means it doesn't have a pre-written obscure built-in or convoluted syntax to handle every possible thing you might want to do in the language. You're going to have to write some of the code in your project yourself. That doesn't mean C isn't simple. I don't think I have to get into why writing a string-parsing function isn't quite the same thing as writing your own programming language.

And C has libraries too, to be fair. So if you prefer the "choose between 25 competing libraries that all provide the desired functionality but half of them are deprecated or don't work" workflow a lot of people are used to from C++ or whatever you can do that. Lots of people use libraries in C. In fact, as you might be aware, your OS's package manager doubles as the C language's third-party package manager. There has been plenty of "already-written C code," because it's a language that has been ubiquitous in computing for fifty years.

I'm not sure where these same tired critiques bubble up from but I see them constantly and they don't make sense. There are a number of entirely valid and damning critiques to be made of the C ecosystem but "there aren't any libraries written in C" and "oh, so you say C is simple, huh? Have you tried using it?!" aren't among them.

You're not going to be a 20 year veteran C developer and then suddenly just today learn about some obscure built-in, and that's what is meant by "simple" here, and that's a good thing.


>You're not going to be a 20 year veteran C developer and then suddenly just today learn about some obscure built-in, and that's what is meant by "simple" here, and that's a good thing.

But you could suddenly learn about a new library feature that performs the same function as another language's builtin, which is for all practical purposes an equivalent experience. In both cases you see an unfamiliar string of characters in someone else's code, and then look up what it does.


someone else on the internet writing a function does not make the c programming language more complicated. c's (lack of) library namespacing, which is responsible for this confusion, is, frankly, one of those valid critiques, but this is gibberish.


I don't understand C programmers are their seemingly utter inability to understand that C is actually not perfect and has tons of flaws, including a lot of complexity. Just because you're used to something doesn't make that thing not complex. Try teaching C to first year undergrads.


I don't understand non-C programmers and their seeming utter inability to understand that C programmers are very aware of C imperfections and how to effectively deal with it, while being equally blind to the flaws and complexity in their own environments.

I learned C as a first year undergrad.


I'm a final year undergrad and all my courses have used C except for the funcprog and OOP courses which used haskell and Java respectively.

I've even been a teaching assistant for the very first programming course students take, so I have taught C to first year undergrads!


I feel like undergrads learn C in their first year? Or at least I did (well I already knew it, but had a class that was in C).


I don't think C is the standard anymore. I'm graduating class of 2022 and my college taught Java to freshmen. My friends at different colleges mostly had the same experience, with a few using Python or C++


This definitely varies by university. I had haskell and C on my first year, only had Java on the second.


On my university we learned C++, already with proper strings, vectors, in-house collection library.

About 30 years ago.


C the language is really neat and exciting. C the ecosystem, including standard libraries, is a lot less compelling.


I do (well to apprentices who are the same age and same level) I teach about 2 hours a week on c++ and they are fine. They pass the cpp institute exams (which are super hard!)

So unless you actually DO teach then don't assume :)


Have taught first year undergrads. Highly recommended experience: 5 stars.

C definitely has many flaws, but I wouldn't say complexity is one of them. I wulld rather say it's too simple and one has to add the complexity all by themselves :D


Learned C in a class as a first year undergrad, it was great!


C was my first language as a first year undergrad, in mechanical engineering to boot. I think I came out of the experience just fine.


How often do you need to parse a string in an RTS game?

If you need to do lots of string processing, C is simply not the right language.

Thankfully one isn't forced to only learn a single programming language in life ;)


>How often do you need to parse a string in an RTS game?

Asset files, config files, shaders, obj files, CSV, XML, JSON, etc... it's not uncommon. Read the asset loading code in the posted game.

For a language that doesn't even know what a "string" is, C applications tend to involve a lot of string parsing.


I type "man scanf" and check which one I need, I wish other languages had such accessible documentation.


Is this supposed to be a trick question? All do virtually the same thing at their core, differing in where they take their input from and whether they are the C11 bounds checking variants. You can add all the v prefix variants too, doesn't really make things more difficult.

You could have thrown in a bunch of functions from string(3), but even then... C string handling isn't great by any means, but it isn't vast or complicated either.


You can learn the C stdlib+system headers, but at that point you're doing something more or less equivalent to learning a high level language's features, and you're past the simplicity of K&R.


I'm not sure what you mean. C is a high level language. And yes it and standard library has obviously grown more complex than it was 50 years ago.

It's small and easy to grasp the entire thing though, unlike most other more modern high level languages.

That said, it's not entirely clear that matters too much. Almost any non-toy C project is going to be bringing in libraries outside libc, so you still need to go off and learn those if you want to work on a project. Doesn't really matter whether they're in the base language or not.


I think the argument is converging on, "by the time you do anything useful with it, C is as complex as any other language, except for C++ which almost nothing is as complex as." That's more or less what everyone seems to agree on.


Ready for a random question out of the 200+ UB cases on the ISO C, or about a random feature from any C compiler?


I'm not sure if you replied to the wrong comment or not because it doesn't address what I wrote.


I surely replied to the right comment,

> It's small and easy to grasp the entire thing though, unlike most other more modern high level languages.

So ready for the question?


> I surely replied to the right comment,

Oh, well it didn't address what I wrote.

> So ready for the question?

Doesn't address what I wrote.


> It's small and easy to grasp the entire thing though,

Whatever


If you asked some dumb question and I answered it, it wouldn't change your mind would it? If it did, then your position is so flimsy it's laughable. Just make a point in plain language rather than rhetorical questions that vaguely relate to the comment but are lazy incomplete thoughts that don't actually address what was written.

You would have a point about knowing exactly every single corner case of the language. I don't think that's easy even for C. Fortunately I didn't claim it was either.

> grasp


> You would have a point about knowing exactly every single corner case of the language. I don't think that's easy even for C. Fortunately I didn't claim it was either.

You said "It's small and easy to grasp the entire thing though, unlike most other more modern high level languages."

The entire thing doesn't include corners? And you entered the conversation in support of someone that literally said "every corner, nook and cranny"! If you were making a much weaker claim, it's on you to make that clear. Instead of this petty "doesn't address what I wrote" garbage.

On top of that, being able to suss out what is undefined behavior is in fact quite important for proper use of C. I wish it was a super rare corner case but it's not.


More half cocked rhetorical questions.

> The entire thing doesn't include corners?

It does.

> And you entered the conversation in support of someone that literally said "every corner, nook and cranny"!

So reply to that.

> If you were making a much weaker claim, it's on you to make that clear.

I did. You just didn't read what I wrote.

> Instead of this petty "doesn't address what I wrote" garbage.

Garbage. Ironic.

> On top of that, being able to suss out what is undefined behavior is in fact quite important for proper use of C. I wish it was a super rare corner case but it's not.

Sure. Doesn't change the fact your question was stupid and didn't address what I wrote.


In general though c++ has some level of feature orthogonality, that is features you don't use will not hurt you. But for large projects, C++ is the saner choice with its builtin library of data structures, templating, namespaces etc..

All these could perhaps be done in c, but why spent a lot of time making this infrastructure if one could spent more time on ones application domain solutions.


You gloss over the complexity cost of having too many overlapping tools in the bag though, a complexity cost that has drowned projects in the past. Arguably C++ as a language could be improved if someone was able to depreciate and remove the "legacy" parts.

In practice though that's simply not possible. E.g. trivial example but you couldn't ever depreciate #include even though we have #import now.

Instead of "fixing" the language, there's written (not enforced by the compiler) documentation https://github.com/isocpp/CppCoreGuidelines - actually the first line is the perfect summary:

"Within C++ is a smaller, simpler, safer language struggling to get out." -- Bjarne Stroustrup

This is great documentation (and many parts are relevant to other languages) but many of its proscriptions cannot be enforced by the compiler so it will always be opt in, mis interpreted or ignored.


I count Stroustrup, Walter Bright... and 10 posers


Stroustrup once ranked himself a 6 on a scale of 1 to 10 as to how well he knows C++.


I've been known to rank myself as a 6 out of 10 "where 10 is Stroustrup".


I haven’t written C professionally or hobbily in 5+ years and I can fairly quickly get accommodated in open source projects. I know that it has many valid criticisms but C is such a pleasure.


If a project requires an open API like OpenGL, SDL, Vulkan which is documented and defined using ANSI C or C99 language constructs, then some amount of C is required regardless of the merits of the language. With high level language with large community maybe someone writes and maintains wrapper, library, or FFI binding for you but this relies on economy of scale and out-sourcing work. If a programmer doesn't understand a C API then writing a binding to a function they don't understand in order to test it is a point of friction which encourages returning to plain C. Ideally more of the "Better C" languages would retain ability to parse and compile vanilla C header files without manual binding. Zig attempts this but reduces the cognitive simplicity of the language by using structs as namespaces for holding local function definitions rather than as "plain old data".


> Ideally more of the "Better C" languages would retain ability to parse and compile vanilla C header files without manual binding.

I've been doing a lot of zero-copy FFI work in Haskell. It became quite mechanical to create 100% literal bindings to C libs (Pointers and all), and it's nice to use it directly in Haskell as-is. I'm hoping I can write a simple tool to do exactly what you describe.


Indeed. For a language that strives to be as different as Haskell does, the FFI experience is absolutely stellar. The only other language I've seen come close in terms of C interoperability is perhaps Rust.


You should take a look at Zig.


For programmers which need to consume C APIs ideally the tool is the standard compiler. Eeverything gets handled at compile time without the need for community-maintained cache of bindings. New language designers start with a C compiler which handles header files, then extend compiler to also parse NewLang files. The in-memory representation is loaded from both source types, without throwing away the C functionality. In NewLang there is some standard namespace and calling convention.

    @importc "stdio.h"
    num : I32 : 123456789
    fd : c:int : c:open(c:"file.txt", c:O_RDONLY)
    :: c:print("file:%d  number:%d\n", fd, num)
But nothing more, everything else is handled by compiler.


For a "Better C" language, that would be wonderful.

For my Haskell ideas, generating Haskell from headers automatically feels like the best route. Especially if it's configurable to some degree. It's common that you can better type a C API with Haskell than C ever could. Usually with techniques like IO, phantom types, GADTs, and the new linear types.


The chicken-and-egg problem is where programmers don't know how the C API works well enough to provide function-specific type annotation or library-specific configuration settings, but want to try calling the API anyway because they are following a tutorial written in C or C++. In this situation if there is no "dumb" binding mode builtin to the language the programmer is likely to abandon the language and go back to writing C or C++ until they get the IO working and something displayed on screen.


The last paragraph sounds so no weird to people who have worked years of their life in firmware development.

Of course it's workable. It does have a lot of gotchas and seems to foment a propensity to reinvent the wheel (Although that also relates to the limited contexts in which it is used).

I'd generally avoid it unless it really is the right tool, in which case, just approach it in a methodical way, like every other project.


What I think is the greatest problem of C is the confusing syntax for types. Other than that, I think C is good (and in many ways, does many things better than a lot of modern programming languages do), although there are things I would improve (some of which are already implemented in GCC), including a few additional macro functionalities (including adding to existing macros like {append} does in Free Hero Mesh, and a kind of macros which are scoped as variables similar to vardef in METAFONT, and the ability to count the number of arguments to a macro (without expanding any of the arguments), etc)


> Ahh a beautifully written project, just shows that maybe C is entirely workable in the right hands.

And because it is in C, you can talk to it from Nim, Python, Rust, etc.

And scripting is a very big part of RTS games.


> And because it is in C

I'm curious, what difference does it make if it was written in, say, Rust, or C++. Wouldn't you still be able to talk to it in a similar way? What's so special about C in this context?


The thing that's always special about C, it's basically the default goto programming language for calling from higher level code, most languages that support FFI do so by being able to communicate with C apis and having tools written around C. C also lacks more complex things like classes, it's much easier to build up a complex piece of software from C building blocks bound to your language. Think of like a struct that has a set of functions that operate on it. You can map that basically directly to a class definition in most higher level languages and then wrap up the c implementation details like memory management behind the scenes so you can produce a nice clean api in your chosen language to use.

This practice is fairly common in python when you're dealing with AI (I'm sure there's other examples, but this is the one that sticks out to me.) SDKs like TensorFlow are written in a lower level language (C++ I think for TF) and then FFI called from python, so you can end up with a function like initTensorFlow() and calling it is enough to bring TF online and ready to start processing other data.

And you may be thinking "Well, I can do all that in rust or go or <insert prefered language here>" and of course you can, ultimately it's all just a linker and compiler deciding where to put code and data in an executable, but C is the defacto standard and more tools from more languages are going to work well with it than say, rust or go. Which, now that I think about it, is probably why Rust supports defining a c api for your code, so it's easier to call from other platforms. Rust specifically tries to play nice with being embedded in existing projects because it makes it easier to adopt rust incrementally.

Just my $0.02


"The thing that's always special about the C ABI..." Fixed. The C ABI is not in anyway restricted to the C language.


An important distinction. Thank you.


Nowadays, 40 years ago it was hardly the case unless one worked at a place rich enough to afford UNIX workstations.


You can expose a C ABI from Rust, and some folks do, but it takes some work. Some people don’t find that acceptable.


To me, If it solves the problem it’s acceptable.


C constructs normally map 1:1 in most languages. It's rare for a modern language to not be able to do all the things that C does. And, even if it's a little weird, it's not too hard to give out an escape hatch because the features aren't that advanced.

C++ constructs--not so much.

Does your language allow overloaded functions? If not, okay, you have to map that somehow (probably name mangling).

Oh, your language has a different notion of inheritance than C++, well, now you need to map vtables somehow.

And what does your system do about exceptions? Constructors/Destructors? Does it agree with the standard library about what a String is? What about memory allocation? etc.

Even if the C++ ABI was perfectly described and standardized, mapping to it is always going to be error prone and clunky relative to the C ABI (which is just a lot simpler).

If you want a good example, look at what it takes to use Vulkan via the C API/ABI--which is an exemplary implementation of an API, in my opinion. Look at the hoops you go through with loaders, structs that have type fields in them, extension fields so that you can add functionality without breaking compatibility, etc. All of that extra "gunk" is the kind of thing that C++ hides normally that gets terribly exposed when you have to cross an ABI boundary.


> It's rare for a modern language to not be able to do all the things that C does.

I agree with the general gist of this, but:

• Java has no unions

• Java has no rectangular multidimensional arrays, although of course C arrays decay to pointers when passed anyway

• Java has no unsigned integer types, I imagine this is generally easily handled though

• Java has no const modifier, you'd need to keep track of that manually

• Java has no preprocessor, although of course this happens at the API level not the ABI level

• Java lacks bitfields but they're generally avoided in C APIs anyway, for good reason

• Probably worst of all, Java references are importantly different from C pointers

You're absolutely right though that the C ABI is a pretty good lingua franca ABI largely due to C being a pretty minimal language. No overloading, templates, garbage collector, or object model to worry about.


I think, as a generalization, most communication between languages goes through C. For example Rust or Switft to C++ would go Rust -> C -> C++. Or Switft -> C -> Rust as examples. I think Swift is trying to make C++ bindings, but in general most languages can talk to/from C.

Of course there are other mechanisms, but for direct bindings I think C bindings are by far the most common.


Actually for Swift <-> C++ you tend to go via Objective C++, which as easy as renaming your .cpp file to .mm, and calling in to Swift via a bridging header


The important part is "C API", the actual implementation language under the API isn't all that important, but C is usually a good fit as implementation language for a C API ;)


Can you elaborate on the “go-style” approach, or link an article or two?


If you look at the source code, "public" functions are capitalized, and "private" ones aren't, by convention.


What’s the reason for serializing the full engine state for the save/load functionality? Seems like a lot of complexity.


I guess because RTS games are soft-realtime systems and need precise control of everything. RTS multiplayer logic is some of the most complex I've ever seen, these games are basically distributed computing frameworks.


Sometimes I feel like i'm an untalented, unproductive waste of oxygen.

Then I see a post like this and know for sure that I am.


Eh, yeah, it can feel like that, but the probably reality is that you just have different priorities in life. Especially as you get older and it starts to sink in how finite your time is, you can't let yourself be fooled into thinking you have to accomplish certain things to be worthy.

I program, rock climb, ride bikes, and write. For any given one of those I can easily find 10,000 people who are more accomplished than I am and often at a younger age. I accept that I will never be that good at any of them, not because I can't be, but because I don't want to invest that much of myself into one of them. There's nothing wrong with that.


Don't discount the creativity, intelligence, and dedication it takes to create something like this. Chances are you actually can't, even if you did make it a priority.


Nonsense. Sure, they wouldn’t make this exact game, but neither would the entire rest of the population who is capable of making a project like this. Most people are roughly the same in terms of physical and mental capability, and if you need to convince yourself of that, think about how fast a computer can do an arbitrary thing versus how fast a human can, or how different a mouse’s musical intellect is from a human’s.


> Most people are roughly the same in terms of physical and mental capability

This is a story we stop telling kids around the end of high school. We tell this story because, as a child, being told you’re dumb can stunt intellectual growth, or being told you’re not physically capable can stop kids from forming a habit of exercising.


I don’t mean it in the way it’s sometimes expressed as, “you can train anyone to do anything,” I mean it in the sense that the 50%ile capable person is really all things considered, not that different from the 95%ile capable person. The range is just not that high. A person can only accomplish so much in the day and with the animal body we are given. Compare that to a computer, which for many tasks, can accomplish things at a rate 10,000,000 times faster than a human.


Let's not pretend someone in the 50th percentile can write a game engine in C.

If you're on this website and your day job is programming, your expected IQ is already way north of 100.


They very much can. Have you ever walked into a classroom and seen the ancient runes left on the board from a more advanced class, wondering how any person can possibly understand all that and wonder whether it was possibly even scribbled as a joke? And then two years later, you realize that you have learned and mastered that very content you saw on the board that seemed so unachievable. Many things seem unlearnable, but given the right conditions (teacher, home situation, motivation) most people are surprised by the scope of what can be learned by an average person.


So, we're engineers---very much not the average person.

Speaking from the point of view of someone who spent 8 years in school learning computer science, then the next 15+ practicing it:

I cannot create an RTS game engine in C. Not in a million years.

It's all good and well to be encouraging, but this is literally our field. If we can't identify our own short comings accurately (after for some people is decades of experience), then we are probably less capable than we think instead of more.


I don't understand why you wouldn't be able to, especially given "a million years" to learn whatever you need to learn. Why does it feel inaccessible to you?


I'm not good at implementing algorithms that directly relate to mathematical equations. I learned this from 1 year banging away at computational photography while in university and 2 years banging away at automated trading systems at one of my first jobs.

Given enough time I can copy other peoples implementations, but its extremely mechanistic to the point where you can't say that I actually 'wrote' it or learned anything. And it would be questionable if all the functionality would fit together as a succinctly as the posters.

I hope you don't think that is goal post moving, but if I do something mathematical in order to get it correct I have to sacrifice everything else: speed of production, efficiency of the end-product, readability of the code, etc. Compared to my output in logic problems or HCI, you'd think two entirely different people were involved and one was significantly smarter.

It's a failing (of the sort where asked "What is your biggest weakness?" at an interview, I can always answer immediately this), but it's what allows me to be impressed with work like an entire RTS game engine in C in just 3 years as a passion project.


You say this as, in all likelihood, someone with significantly above average abilities.


Yes, as I’m sure the commenters above me are as well. The context of this being on HN is important, and I’d be a lot less likely to say an arbitrary person could do this project on some other forum.


The shared delusion of HNer's that they are intellectually superior the rest of humanity because they write computer software continues to astound and infuriate me.


Superiority is a pretty loaded word.

I wouldn't call athletes "physically superior" either. That kind of supremacist talk is looked askance upon, for good reason.

But they're definitely faster/more coordinated/stronger than average, pretty much by definition. They can be proud of that.

Computer programmers are also smarter than average. If they weren't, they wouldn't stick around. It's not physics or higher maths; I figure anyone above the 80th percentile can do a good job of it, and some people in 60-80th can get the hang if it, but will probably never be great.

That's just the way it is. Phrasing it as being intellectually superior to the rest of humanity, that's just your hangup.


While that’s definitely frustrating sometimes on HN, that’s nowhere near what has been expressed in this thread (at least not in the comment you replied to).


It is amusing that your comment is about IQ and your name is IQunder130... I feel like you might be too focused on a poor measure of human intellect.


Is there a better one? Bonus points for a scientific publication and not a tabloid article.


Isn't it a fact that IQ is bad at measuring people's intelligence?


I'd say it isn't. IQ is the best thing we've found for measuring people's intelligence so far. That doesn't mean that it explains all the variance in people's results but I'm pretty sure it explains the majority of it, through the g factor. So it's not perfect, or maybe even very good, but I'd say it's still very far from "bad".


> I mean it in the sense that the 50%ile capable person is really all things considered, not that different from the 95%ile capable person.

You must be living on a different planet from me. I can kind of see how someone might be tempted to just say “you know what, you’re right” and let you keep on thinking that, though.


Both my parents are MENSAns. I agree with the parent poster, there isn't specifically anything special about being a 95%ile, and most of the members of the 95%ile that have joined MENSA aren't massively successful, any more than anyone on the middle of the bell curve.

It's not, what you have. It's what you do with it. I struggle with some things my parents find easy, vice versa, most of the 95%ile that I know have various mental health problems or other hidden disabilities that make daily life difficult -- especially achieving something like this.

And Feynman went far with being just an ordinary person supposedly slightly lower on the bell curve.

The only thing that actually tangibly matters is dedication and sweat, and how much time and effort you're willing to put in to something.

Of course, that's not to outright say that an IQ test or however you want to measure cognitive "capital"* isn't valuable in some aspect -- it does measure something, after all. Less fighter pilots died in training once they started selecting using early IQ tests (Source is a psych book from the 80s I skimmed a few years back :P). But that's an extreme case. For projects like this, for most of the things you will ever, ever want to do, it outright does not matter and the emphasis on it in programming and "intellectual circles" (on the internet, I don't think anyone in real life actually gives a shit outside of college admissions) is massively overblown.

* - I'm phrasing this in capitalist terms explicitly because "cognitive capital" is an explicitly western construct that to be honest seems to be more detrimental than it has been positive. Also, outright racist in the historical use and implementation.


Feynman wasn't ordinary - https://www.psychologytoday.com/intl/blog/finding-the-next-e...

"Feynman was universally regarded as one of the fastest-thinking and most creative theorists in his generation. Yet, it has been reported-including by Feynman himself-that he only obtained a score of 125 on a school IQ test.

I suspect that this test emphasized verbal, as opposed to mathematical, ability. Feynman received the highest score in the country by a large margin on the notoriously difficult Putnam mathematics competition exam, although he joined the MIT team on short notice and did not prepare for the test. He also reportedly had the highest scores on record on the math/physics graduate admission exams at Princeton.

It seems quite possible to me that Feynman's cognitive abilities might have been a bit lopsided — his vocabulary and verbal ability were well above average, but perhaps not as great as his mathematical abilities."


Yeah, the Feynman story doesn't prove what people who bring it up think it does, or indeed, what Feynman presented it as.

Anyone can botch a test. You can't fake winning the Putnam.

He was a very smart man. Also very sociable, a man of the people. I think Feynman demurring about his 125 IQ test was a way of presenting himself as relatable. He could have easily done the opposite by slamming home the point that he aced the Putnam and intimating that he was one of the most intelligent men alive, but he was smart not to.


> most of the members of the 95%ile that have joined MENSA aren't massively successful, any more than anyone on the middle of the bell curve.

This may be a selection effect. Perhaps the members of the 95%ile who are successful don't have the bandwidth left to join MENSA and see no value in doing so.

As a personal anecdote from ~15 years ago, which was the last time I affiliated with anybody who talked openly about being in MENSA, their activities there frankly sounded a bit like a self-therapy group which turned me off from even attempting to join.


> This may be a selection effect. Perhaps the members of the 95%ile who are successful don't have the bandwidth left to join MENSA and see no value in doing so.

That doesn't matter for the purposes of this discussion: It still shows that there's room for a lot of non-over-achievement in those top five IQ percentiles.


Maybe it’s born out of all these times I’ve seen “10x engineers” hired, or “very senior” managers who will “change everything.” There’s just not that much that one human can do that is fundamentally different from what the median human can, so these hires are almost always overblown.


But how is the hiring of those engineers or managers relevant to the current thread, which is about a project explicitly described: "I am a one-man development team doing everything"?


Claim: Some people have a higher plane of capability than others, so high that it’s such a difference in scale that it’s a fundamental difference in kind as well.

Situation: “We have a broken company. Let’s hire one of these superhumans to fix everything.” Reality: the person hired is the same as everyone else, so they can’t apply their superhuman strength to fix the situation. Lesson: People are more similar than they seem.

Situation: Complex project seems to be so involved and difficult that it must have been done by someone possessing powers on a different plane than the rest of us. Reality: The creator spent a very long time learning about the concepts and technologies, then spent a shorter, but still long, time building the project. Lesson: Even those who accomplished great things did not do so effortlessly, and not overnight either. Unlike a god, they did not download the “desire to build great things” program and simply execute it.

Judgment of the claim: this appearance of higher kindedness is (mostly) an illusion. Most people are largely the same.


My point was, the two situations are very different. It is wrong to make similar conclusions.

In your first example, the superhuman cannot fix everything because he has to work with other average humans, who drag him down.

In the second case, since he is not forced to work in a team, his superior skills are shown in the result.


The argument is a relative one. It isn't that these mid-level person and high-level intelligence people aren't quite different in many ways ... it is that relative to non-human standards of intelligence, they are likely relatively close (say within an order of magnitude of capability).

Here is a much better summary of the argument:

https://aiimpacts.org/is-the-range-of-human-intelligence-sma...


Why does it matter how it compares to some x10M performance difference that exists somewhere? The individual output of two people can still hugely differ, which is what this discussion was about, no?


The claim was that someone would be not just very slow but completely incapable of completing a task even given an arbitrary amount of time. That would mean there’s some kind of fundamental difference between the two people, which is just a ridiculous claim. What one person can accomplish in three years can almost certainly be accomplished by another in ten provided they are in the same profession and competent.


> and competent

Seems like begging the question.


Again, let’s assume 50%ile, not “competent enough to complete the task.” Though realistically, I would bet Hacker News commenters skew higher than 50%.


Looking at relative differences without any perspective on the absolute difference is pretty silly.


You're probably just thinking about differences between people in relative terms. Yes, the best marathon runner does it in less than half the time of the average marathon finisher, and finishing a marathon is already considered a significant accomplishment that a very small portion of people ever do. But compared to a car, there's no point in even looking at the absolute difference in speed between different marathon runners. Why beat yourself up about the relative difference between the human runners?


>Most people are roughly the same in terms of physical and mental capability

I don't think this is true. People vary wildly in how long it takes them to learn and understand concepts. Some people are better at this and so they achieve more with the same amount of time devoted to a particular endeavour. We can be honest about this without feeling worthless. I could devote my entire life to mathematics and I wouldn't become Euler.

Thankfully people vary just as wildly in their affinity for things and that's why we see impressive projects like this. But I aqree with your general premise that seeing other people's endeavours and achievements shouldn't make you feel depressed about how you spend your life.


> Most people are roughly the same in terms of physical and mental capability

Most of the people on the street? Yes. Most of the people in a history book or at the top of their fields? Not remotely. The author of this is in the second category.


> Most of the people in a history book or at the top of their fields? Not remotely.

They mostly got there through the trick of being a good leader and then getting assigned all the credit for their group's work in the history book.

> "There's a tendency among the press to attribute the creation of a game to a single person," says Warren Spector, creator of Thief and Deus Ex.


Your history book assertion seems similar to an assertion regarding "Magic". That being it is simply "hidden work".

Stage magicians can spend years conceiving, preparing and rehearsing a "trick". But on stage, when the audience experiences the illusion ... it is magic.

Similar to some workplaces stuff. There can be many man hours of time spent propping up repositories, testing, debugging, logging etc etc capabilities in general.

And when the shit hits the fan and the capability solves the problem ... magic.

Then the audience says "Thanks for solving the problem 10x Dev."


> "There's a tendency among the press to attribute the creation of a game to a single person," says Warren Spector, creator of Thief and Deus Ex.

I see what you did there.


I mean it's not breaking any new ground. It's a great accomplishment for a person because of the amount of time committed, but there isn't any single fundamentally hard piece that's out of reach from an average developer.


I think you overestimate what it takes. I've done hard things that took dedication before, for instance I'm a national champion slot car racer, and I've lost over 150lbs. The most important step in accomplishing those things was putting in the time and effort to do them. You also overestimate how smart you need to be to program a game, which I've also done before. What people usually call "talent" is not some innate ability but rather the result of thousands of hours of learning and practicing. Which isn't to say that innate advantages don't exist, but without hard work and dedication they will always be surpassed by someone who put the effort in.


> Chances are you actually can't, even if you did make it a priority.

In this sentence, the first 'you' is a different person/reality than the second 'you'. Our priorities are integral to our identity.


I prefer this to remain my fear, not to succumb to it being my belief.


> not because I can't be

So what difference does it make if you can't be? Realistically speaking, the very best pour both their soul and their genes into an endeavor, and most people literally can't match them even if they tried.


Who's talking about 'the very best'? No disrespect to the author of this game engine, but I'd hardly rank them with the likes of John Carmack. You don't have to be John Carmack to write a game engine, but you do have to devote time and effort to it. Parent is comparing themselves to someone who successfully did a thing, while apparently having not put any effort in to this particular thing, and feeling bad. That doesn't make any sense.


You're correct.


It's easy to feel discouraged, but keep in mind:

1. The author didn't write this overnight. The oldest commits go back to Oct. 2017, three and a half years ago. Imagine what you could accomplish if you worked on something for three and a half years.

2. There are many things we can do with our time, and ultimately we do them all to be happy. Don't measure your own worth by how much product you leave behind. Measure it instead by how happy you are today. Most likely the OP wrote this code because working on it made them happy, and that's great. For many of us, though, the activities that make us happy don't have biproducts. But that doesn't detract from how happy those activities make us. Value the things that you do because they make you happy, not because they appear impressive when held against some external grading scheme.

Edit: list formatting


I wish more people like the author of the OP would feel free to admit things like they were compelled to finish the project because they couldn't see anything else they felt like doing with their time, so that's simply where all the time went. That would make perfect sense in my mind, and restore a notion of calm.

One problem is making assumptions that the author is trying to prove something by a clear display of superiority. The code itself is of a high quality, from what other people are saying. But it's probably only because so much effort was put in for three years on it.

Also, I have to wonder how many other doors the author left closed because he spent so much time on this project. Was there anything else of a similar impact that he contributed to for all those years? And what of the other things he may have passed up?

Some projects will consume you. They will be the tantalizing activity pulling you away from Friday night dinner parties with people you don't understand and other miscellaneous outings that are comparatively less interesting. You constantly think you're leaving something unsaid or undone away from a keyboard. In some cases you feel obligated to continue for no reason other than having already come so close to accomplishing the thing, sunk costs and all.

With some projects, hypothetically, if someone is to see me in a cafe with nothing better to do, I'm almost certainly going to wrap up my current conversation after a point and take out my laptop to continue working. That is how my life is structured with those projects. That is how they affect my actions day after day. It isn't necessarily a life of glory.

Working on projects and having the finished product in my hands is not what brings me happiness; it merely staves off misery. It fills a void in my life that was agonizing up to that point. My theory is that if your goal is to avoid misery and despair at any cost, and have the means to do so, you can be driven out of desperation to accomplish substantial things. Other people could see what I did and make their own guesses as to what it took. But really I was only trying to prevent myself from becoming undone. It was simply too irritating of a problem for me to leave alone. I'll probably never be able to fully explain why. It certainly wasn't because I was trying to prove something to other people.

But I'm only speaking from my personal experience. It's not like I actually understand why the author did what he did. People just don't seem to know at the moment, and maybe that's where the air of sadness over suddenly seeing this accomplishment come out of nowhere originates. There's nothing to counterbalance the impact of learning of its existence within a split second with what actually went on behind the scenes for many orders of magnitude longer.


Why is the only world where OP created this project one of great sacrifice? You mention the code quality; is it not possible OP is simply highly talented from years on the job and this product actually didn't require polish and refinement constantly, OP simply is a better programmer than most?

Your post has a sad undertone, one that it feels like you are trying to apply to OP in order to justify not achieving the heights others have. Some people are insanely good at things. Most people are barely good at anything. Don't think of OP as a bastion of despair, reframe the project as an achievement and I believe you will feel better.


I don't think what I've done for the last three and a half years has made me happier than working on a big project would have, and I have much less to show for it.

I'm not feeling less discouraged.


Well, now you have a data point. Will you use this reflection to shape the next three and a half years?


I honestly don't know what you're suggesting. A data point isn't motivation, and there is no real way to convert it. This isn't something that can be resolved by making a decision.

It's not that I worked on the wrong project, it's that most months I worked on no project.

I feel like that's pretty normal but it's still bad. I could be just as happy and make more nice things.


What I'm saying, or more appropriately asking, is whether your impression with the OP's project is inspiring you to change your actions in the future towards being impressed with yourself in similar ways.

> It's not that I worked on the wrong project, it's that most months I worked on no project.

Will you start working on projects in future months?


> What I'm saying, or more appropriately asking, is whether your impression with the OP's project is inspiring you to change your actions in the future towards being impressed with yourself in similar ways.

It doesn't seem to be.

So if I take your advice and imagine what I could accomplish... that just makes the feelings of discouragement worse.

You listed two things to keep in mind. For me the first one actively makes the negative feelings worse and the second one doesn't really apply.


> So if I take your advice and imagine what I could accomplish... that just makes the feelings of discouragement worse.

That's a good point, and I didn't take a healthy perspective on it. Imagining what we can accomplish in a long span of time can be distressing. The road ahead always appears longer than the road behind; that's why it's so easy to look at the accomplishments of others with awe and then look towards our own intentions and feel anxiety.

A better approach is to not imagine what we could accomplish in three and a half years, and instead just dedicate the next three and a half years to doing the things that make us happy and pleased with what we're building. Projecting our intentions can be daunting, but taking one day to do a bit of code or design is not a big step. And doing it again the next day is no bigger a step. Taking it each day at a time, and taking care to enjoy each of those days at a time, is key to keeping our motivations high. And then some day we look back and realize just how long we've been crafting our craft, and how far it's come. But it all starts with one day's work.


You can still be a consumer/buyer, like me. Together we make the world go round and around.


How about we setup a plan to develop something similar and stick to it for a few months and see what happens?

I mean this is definitely a piece of gem, but nothing is exactly high tech or hugely difficult. And if you don't think you can make it, you can lower the target and create a, say, a 2d rpg engine that emulates Ultima IV or Pool of Radiance, those pioneers of modern RPG. For art assets you can use free resources or purchase inexpensive ones.

I really think that's achievable for pretty much every programmer. After all in some universities they give you a similar task as a project for advanced game programming classes.

And then you go from there, polish the game and make it fun to play.


To clarify, I'm not saying that the RTS of OP is similar to a university project. I'm speaking about the watered down 2D RPG engine.


It is extremely impressive but judging from commit history it took over 4 years to build this.

My takeaway is that the most difficult part of building something like this isn't the code, it's the life skill of sticking with it. I think that's both a more valuable and difficult skill to acquire.


1. Fight try to measure yourself up against the most talented person you can think of. Can you code? Well, then, there are plenty of FOSS projects in the languages you know which could use your help. Can't code? Not a problem, do QA work then, that's important and very useful and not enough people do it seriously.

2. Seek self-fulfillment and purpose in other aspects of your life. I am 100% sure the people around you - family, community, neighborhood, etc. - could use someone who devotes some time for doing good. Sure, it might not be what you had assumed you would gain fame and glory doing, but so what?

I'd be more specific but obviously I don't know anything about you or where you live or what you do.


The power is within you to change that, you know?


Came here to say this. Kudos to the author.


I blame Netflix instead


Blaming is easy.

Start doing things is easy, too.

Finishing stuff, is hard.

The trick is to gradually work your way up from small, completed projects. If you start big, you probably fail big.


Yep. All big projects started as small projects.

The hard part is justifying the time spent on a project. You often start a project and feel like it's not the best use of your time. That you may be the only one to use the project or find value in the project and that's enough to kill motivation. Why start a business if the vast majority of businesses fail? Why start a business when there is already so much competition? Why write a novel when there is no hope of selling it? Then there are the "I'm too old for..." thoughts.

These thoughts eat away at people.

If someone pointed me to my purpose project and told me if I were to keep at it that I would find guaranteed success, then I would have an infinite well of energy at my disposal. But of course, no one is there to tell you that.


I think the pbjective of a project is to...be a time filler, like I can definitely watch Netflix and then Netflix does not satisfy my creative mind so programming something would be a better exercise.


Parent poster might have been committing a wee joke there


A joke yes, but probably one with too much bitter truth in it.


Who does the artwork? It’s definitely pro quality. Please tell me it’s not also the developer because I may want to kill myself at this point.


According to the Steam page: "I am a one-man development team doing everything from writing the engine from scratch in C99 to modeling all the 3D assets in Blender."


Goodbye, cruel world.


Goodbye, goodbye... goodbye.


You aren’t allowed to participate in my pathetic little joke because being one of the greatest minds on Hacker News deprives you of that luxury ;) [0]

I on the other hand can die happy knowing you answered one of my comments!

[0] https://news.ycombinator.com/item?id=26271117


Well, you’ve done some good work yourself, based on your profile:

> Investor, husband, father, ex-Microsoft. Creator of vuepressbook.com.

Being a good husband and a father while common, still involves effort, and is an accomplishment in itself. Also, being an investor is way to have a big positive impact on the world! So is writing that little book on Vuepress! And you can still more creative stuff (even if you’re close to retirement) in your life—especially if you have saved up a FIRE level of money.


You are super kind, and man do you speak the truth. I have both a home and a farm that are paid off, so I know my handicapped kids will have a place to live after I die. House and farm both within 2 miles of Microsoft!


Is that a reference to the Monkees' Porpoise Song?



A motherfucking polymath at this point

From wikipedia: A polymath (Greek: πολυμαθής, polymathēs, "having learned much"; Latin: homo universalis, "universal man") is an individual whose knowledge spans a substantial number of subjects, known to draw on complex bodies of knowledge to solve specific problems.


2D art or 3D art? If the former, it looks like some of that is from existing art (e.g., "Bear Rider" is clearly from https://en.wikipedia.org/wiki/Bogatyr#/media/File:Viktor_Vas...).

The latter is made by the developer, but I wouldn't call those assets "pro quality". This isn't to diminish the astonishing amount of effort that went into the project though!


Yeah, the 2d comes from somewhere else. I'm also an indie dev, and that looks like the kind of 3d art I'd create...mostly just enough that it works, but not great.


Hahaha, my thoughts are similar.


Looking through the assets on github, it seems he has done some work himself and gotten some off OpenGameArt.org


Which is fine, even good 3d designers advice not spending much time designing bushes, better to spend time on your main character


of course! was just answering the question. Awesome job on the engine and game.


Just came to congratulate the human effort! One can only imagine the hours of frustation to bypass to produce this (oneman) production. Enjoy the first page of HN !


That's awesome! It's always exciting to see not only low level game development, but also RTS development - my favourite childhood genre. I think C has much underutilised potential as a game dev language, especially as data oriented design (eg ECS) is coming into prominence.

I'm also building an open source game in my spare time, although it's nowhere near as far along as this (and I'm also a massive noob at game dev) - it's a civ-type game in three.js designed to showcase bottom up organising behaviour; think age of empires 2, if the villagers determined their own behaviour. I shared it on HN years ago but shelved it until recently when I was looking for a fun project to pick back up - https://github.com/ajeffrey/civarium.


Amazing work, you mad lad. And not that many lines of code in my opinion—you’re good. Do you feel you are missing any error handling or other infrastructure? How do you feel about C as a vehicle for that size project? Looks quite manageable to me.


Over the long development cycle of the project, I've accumulated a nice little library of data structures, allocators, and utilities (mostly in src/lib). Between those and the low-level engine systems such as the task scheduler and event system which have a generic API for any other system to make use of, I believe I have good foundations in place to develop new engine systems relatively easily. Of course, this required the initial investment of laying these foundations.

Most error handling just consists of checking the return value of a call and propagating it up to the caller if necessary. Sometimes I also set an errno-like variable with an error message to check it in the top-level code. It's a bit wordy but obvious and sufficiently good for all my use cases.

I don't think C limits the size of the project. It's all about good organization and coming up with the right higher-level protocols/conventions. This, IMHO, is what allows or prevents the code size from scaling gracefully.


My experience in C as well. Have been questioning my own sanity over the years when I read about the language because I get such a different impressions of it from people on this very site, so it’s a relief to get your perspective.


Coming from C++, the main thing I am missing in C is generic data structures. Having to resort to macros to implement generic vectors (https://github.com/eduard-permyakov/permafrost-engine/blob/m...) I find cumbersome to say the least. It is also hard to beat the performance of the STL data structures when implementing something seemingly straightforward like a vector type.


> It is also hard to beat the performance of the STL

If you want to re-create the STL, maybe. But you can make custom data structures tailored to your task at hand instead.

For example, instead of a std::map or std::unordered_map that allocates and initializes each node separately, you could preallocate some of them in a big chunk of memory, hand them out via a bump allocator scheme, and later free them all at once. Instead of a std::sort algorithm, you could use a bucket sort if it's possible in your situation, to improve your asymptotics from O(n log n) to O(n). Etc, etc.


There's plenty of papers you can find online where people beat the STL: http://www.cs.cmu.edu/~dga/papers/cuckoo-eurosys14.pdf It's usually because there's some use case or underlying assumption they can make that the STL can't, because the STL is designed to be the best possible one-size-fits-all-approach, which is even further constrained by things like ABI history. So it's always a discouraging sign to hear a software engineer talking about such things as though they're holy, since that'd be like hiring a tailor who uses spandex.


Are there any features you would like in C that would make things easier? I'm writing a c compiler and adding low hanging stuff such as removing forward declarations and supporting multiple returns. One thing I'm flip flopping on is function overloading for example. I'd appreciate your opinion.


I guess the "shtick" of C is that it has a small and obvious feature set. The readability and style of programming follows from that. As you start adding more and more language features and constructs, you start getting all the other languages that were derived from C and you no longer have C.

During the development of the project, I had a thought that it would be nice to have a RAII/defer mechanism to get rid of repetitive code for freeing resources at the end of a function. But I'm not sure if that's really necessary since you can just put the 'free' calls at the end of the function and insert some labels between them in a kind of 'stack'. This perhaps is more in the spirit of the language - a bit more wordy, but having less voodoo done by the compiler.


Some people like to make a defer macro like this:

     #define itervar(i) i##__LINE__
     #define FOR_DEFER(pre, post) for (int itervar(i) = ((pre), 0);
                               !itervar(i)++; (post))

     Foo *foos;
     FOR_DEFER(foos = alloc(Foo, 1024), free(foos))
     {
         // This "loop" only runs once.
     }
Those can be easily stacked

     FOR_DEFER(foos = alloc(Foo, 1024), free(foos))
     FOR_DEFER(bars = alloc(Bar, 1024), free(bars))
     {
          ///
     }
Here is a memory arena macro.

     #define FOR_MEMORY_ARENA(name) for DEFER(Arena name = make_arena(), free_arena(&arena))

     FOR_MEMORY_ARENA(arena)
     {
         Foo *foos = arena_alloc(&arena, Foo, 1024);
         Bar *bars = arena_alloc(&arena, Bar, 1024);
         // all allocations automatically freed at the end
     }


gcc and llvm have a cleanup attribute you can use for this. Systemd uses it.

https://fdiv.net/2015/10/08/emulating-defer-c-clang-or-gccbl...


I guess you have to be careful not to return inside of these :)


Interesting, I think defer as a statement might not be too much magic but it would be too complicated for my mostly single-pass approach.

Thank you for your response.


Before substantially modifying the language, make sure your parser can still load vanilla C header files with no new features.

This way if you accidentally create a new language, programmers will still be able to load existing C header files without having to manually write and maintain FFI bindings.


Adding multiple return values creates a new language


The more relevant issue is whether or not it preserves backwards compatibility. It is possible for their compiler to continue to consume existing ANSI C and C99 header files and source code, without requiring the programmer to manually write FFI bindings and wrappers to call regular C functions as is the case in many other high-level languages, and also without adding as many features as C++.


Not OP but based on his comment about checking return values of stuff.. would be nice to have lightweight exceptions. could improve readability and debuggability, less if statements, generally easier to propagate errors up the call stack. my 2cents.


One question I have (and please don't take this as criticism or judgement, it's purely curiosity): why Python 2 and not Python 3? Was it because of when you started working on this, or were there some architectural/design issues that prevented use of Python 3?


Eh, I don't have a great justification why Python 2 should be used over Python 3. I made this choice like 3 years ago when I didn't know too much about Python. That's it. Since I wrote some code against the C API of the interpreter and made a whole bunch of scripts already, it's a massive chore to migrate. Classic story, I know. If I were to start a similar project today, I would attempt to use Python 3 first.

That being said, I did come across some discussions (ex: https://stackoverflow.com/questions/34724057/embed-python3-w...) where it is not possible to strip the standard library from Python 3. I think the use case of embedding strictly the interpreter without any "batteries" is not popular and thus has not been that well-maintained. I've not tested this in practice, however.


Cool. Thanks for the response. It's definitely an interesting project. As a long-time RTS fan, I'll be following this project closely. I hope to have some time soon to come back and give it a more thorough read.


Shifting attention to keep every lib updated is a distraction from getting things done.


I was curious about this too and looked around a bit. I see he has to do some inspection of python interpreter -- so maybe that, coupled with demos already within in python2 are enough inertia to stay back on version 2.


The devlog videos are great : https://github.com/eduard-permyakov/permafrost-engine#devlog

Thank you so much for making this in the open and documenting everything !


What an extremely talented individual you are. Thanks for sharing your work and your process in the YouTube videos.

As someone who comes from a web dev background and who's completely unfamiliar with developing large projects in C, I'm curious about your setup. What does it look like? In terms of what kind of IDE, OS, interesting tooling, etc. you use on a regular basis to work on this.

Also, I've seen the first commit goes back to Oct 2017. Did you work on this full time during the whole time / how many full-time months you would say you devoted to this project? Also, if I may ask – what do you do for a living?

Thanks again and congrats on the project!


Wow, this is incredibly impressive!

As a web dev, I feel a moment of satisfaction when I manage to make a heading look right on both desktop and mobile. Lol, what you've done is several orders of magnitude more difficult... I could spend a lifetime coding and not even know how to start drawing the first pixel. Kudos!!


Well. I usually work on system programming but recently started to code a web app (Account manager at c1.fi - Golang, JS, HTML, CSS) and I can say that creating even most simplistic & light weight web app can be rather demanding job. Especially when you need it to render and behave well on both desktop and mobile! =)


I don't know that it's "demanding" as much as "tedious"... I feel like our entire field is built as a mountain of hacks upon hacks. How the heck did Javascript become the dominant programming language of worldwide communications?! The ecosystem is so fragile and unstable (https://hackernoon.com/how-it-feels-to-learn-javascript-in-2...) that it seems like most of web dev is keeping up with fashion changes rather than doing anything truly good for the user.

Windows Forms supported responsive layouts decades ago, and Visual Studio was a beautiful system to work in... now we have forty dialects of Javascript and twenty thousand CSS mutations served by like four browsers that share mostly the same renderer but still aren't compatible, overseen by standards groups that compete with each other to actually be the standards... sigh... it's like our main output is job security, producing new features to fix the new features from last week, like a ouroboros forever trapped in the matrix.

</rant>

I just really appreciate people who can code a clean, elegant app, because I can't remember the last time I saw one in the web world!


Did you implement netcode? A deterministic approach or not?

I have to admit that would be quite the single feature I would be curious to learn about.

All I know about RTS netcode is that if there are N players, each players "commits" an order, in a turn by turn manner, and all the game code, physics and behavior etc is entirely deterministic, which guarantees that all clients are always synchronized and don't need to share state (well there is some hashing system to detect if there is a bad sync, and I don't know if it's possible to rewind and cancel things).

A RTS netcode doesn't seem difficult to implement, but making a deterministic RTS doesn't seem so easy, I think, especially if you have boids and other pathfinding cool things.


Another thing that blew my mind recently was that Rollercoaster Tycoon, a fairly complex game, was hand written in x86 assembly...

Although, this is less crazy when you think about how heavily you can use macros, and sort of roll your own high-level language yourself.


> use macros, and sort of roll your own high-level language yourself.

See also Engelbart & Co. Amazing how productive this approach can be.


Truly beautiful code. It is so clearly structured and written I feel like I could dive in an work on it easily if needed, that is quite rare.


I love that aspect of it. Maintainable code just makes me feel good


> Permafrost Engine is licensed under the GPLv3, with a special linking exception.

This is most awesome thing, I wish more projects would use linking exception!

Just in case someone will reuse code on server side; why not to use AGPL instead of GPL ?


What's strange is the README says this, but I don't see a linking exception in the actual license.


It's per source code file, and it is not explicitly defined what is and what is not an engine API calls.


This is very cool, In my head, writing a game engine seems like one of the real 'final frontier' projects -- an os, a compiler/language, a game engine all feel like similar levels of project insane complexity with limitless scope.

Every time I've attempted even the basics of graphics programming I very much get scared off when it doesnt click quickly (if anyone has tips on how to get into it, it would surely be appreciated :))


This is huge. I have a pet RTS project too, and the stuff is really complex. The information on large-scale pathfinding for example (ClearPath etc.) is scarce. And I do it on Unity3D/C#, doing this on homemade engine is pure insanity.


Awesome looking project.

I couldn't find any tests in the project. How do you test things and maintain it?


This looks like some high-quality code so I was also looking forward to learn how good unit tests look in C. Was surprised to not find any, at least for the engine part of the code.


This is really cool, wonderful project! I love seeing people put so much effort into projects like this.

I'm a bit curious about the choice of OpenGL 3.3. When OpenGL 4.0 came out in 2010 it was a game changer for me and I remember it made everything (apart from quick debug drawing) so much nicer. OpenGL 3.3 was released simultaneously and was essentially as much of 4.0 as could be backported for those unable to move over right away.

Is this choice a hint at how long you've been writing this, is it comfort and familiarity? I'm not criticising the choice, it obviously works for you. I'm just interested in the reasons.


The reason I kept the minimum OpenGL 3.3 requirement is because it is supported on the biggest range of platforms. OpenGL 4.xx features require some features from newer generation cards. Of course, with time this is becoming less and less relevant.

In some parts of the code, I did make use of OpenGL 4.xx features like glMultiDrawIndirect, but this is put behind a check to see if it's supported by the driver and added a slower fallback for OpenGL 3.3.


Why didn't you directly use SDL for rendering instead of OpenGL? Was it for performance reasons? OpenGL is deprecated on mac, and SDL use Vulkan on Window and Linux which I guess is better, performance wise than OpenGL.


SDL gives you an API for 2D rendering, mostly limited to drawing boxes, lines, and bitmaps. OpenGL lets you program the graphics card for any use case, most commonly 3D graphics with room to add complex effects and post-processing. The SDL API is just nowhere near flexible enough for what I want to achieve.

Plus, Vulkan is not really "faster" than OpenGL. It just gives you a different API for programming the same graphics hardware, which in the hands of the right person can be used for writing code which is "faster".


That's a very reasonable approach and what I would typically do at work.

I guess my surprise was mainly because it's the kind of extra bother I personally like to get away from in my personal projects. Then again, I typically don't write things meant for adoption by a wide audience. Kudos for making the necessary effort.


As someone who has made a custom engine - and intended at first for it to be an RTS engine - kudos. Huge accomplishment :)


This looks really awesome. The screenshots from the demo game take me back to Warcraft 3 days. The code is clear and well organized. Everything about this project is well done and extremely professional looking.


I got to poking around and found this reddit posting in which the author describes the features of the engine which includes an embedded python interpreter and saving restoring python state. https://www.reddit.com/r/C_Programming/comments/gwg5u5/openg...


Here's a trailer for a game the developer built using the engine https://www.youtube.com/watch?v=xleJeiOHHh4 and a devlog describing how he persists python interpreter state. https://www.youtube.com/watch?v=ch-zjn05gxQ


Interesting license choice - GPLv3 with a linking exception so that the final binary and other independent libraries are not GPLed. Is this common for game engines?


Looking at: https://www.youtube.com/watch?v=xleJeiOHHh4 the FPS seems very bad, is it an issue on the capture side? Nice and clean C otherwise!


yeah what is it like 15 fps? The repo says " It is made in the image of old classics, but incorporating some modern ideas."

But does that mean low FPS too?


I don't think it's the FPS I think the animations are just kind of rough.


Super cool. What assumptions about RTS design does the engine make? What is particularly easy in the engine, and what's something that's harder than it maybe could be in another RTS engine that made some different decisions?


I love the wooden AT-AT.


I think that's Babba Yaga's house with chicken legs.


It got two legs, so it's more like AT-ST


There is an AT-AT right next to them.


Amazing job! If you could tell, how much time did you spend on it daily or weekly? And how much experience in the gamedev industry and/or with C did you already have when you started?


It's cool and all, but looking at the videos the FPS is taking a huge hit. Doesn't matter how the comments are about beautiful code if no consumer can play it.


Why the engine internals exposed using Python 2.7 rather than Python 3?

Regardless of how you feel about Python 2 vs Python 3...one is officially EOL and the other isn't...


After seeing this…

Newbie: “I need to start programming!”

Veteran: “I should stop programming.”


The Engine Summary is really impressive for a solo project.


I like how chicken + resources = wooden chicken tank.


Impressive! And excellent coding style. I attempted to write an RTS at least 5 times in the past 30 years and could never stay focused, so I'm seriously impressed by this. In C no less!

How did you stay focused? And how did you segment the work? It requires progressive refinement to coordinate all of the systems. Wondering what order you took.


Can I ask how old are you and how long you've been programming for? This is an amazing achievement.


For those who want to see it in action: https://www.youtube.com/channel/UCNklkpsPnNpRhC9oVkpIpLA/vid...


Do you develop this game on Twitch at all? I'd love to watch the work being done.


I hope this inspires someone to make a new kick ass RTS. I really miss the OG WC3 days.


Check out Back2Warcraft and W3Champions if you haven't yet


I checked the websites and I don't know what I'm looking at. What games are being played?


W3Champions is an unofficial amazing work to bring back to warcraft 3 what reforged has taken away (mostly ladder and tournaments, for competitive games). But there's more, since they could provide intercontinental servers that offer low ping for players from different continents. We have for the first time in history pro players from china battling with the ones in europe, european vs NA, etc.

Back2Warcraft are the guys that stream and cast most of the competitive games. I suggest you watch them live on twitch when there's some tournament, and/or on youtube for past games.

It's a great time for warcraft 3, thanks to the great effort put in by fans. If only the game hadn't been killed by Blizzard :( But there's still plenty of people playing, with classic graphics and W3Champions servers (you still need reforged), and plenty of pros to watch.

Enjoy your warcraft 3!


Age of Empires 2 has experienced a resurgence recently.


Some people from Blizzard formed a company named Frost Giant and are apparently working on a new RTS.


This is super impressive considering it's written in C. Well done and keep it up.


Quick question: all the goto fail's where

  fail:
    return false;

This is just to perhaps change return false to something else in the future, correct? Else why not just return false everywhere instead of goto fail


Not sure if this is the author's reason but I find it helpful to have a single return point from functions. Much easier to follow code paths.

You'll see this in some places in Linux's source too.


I think it’s to cleanly show when he is using his pseudo-exception handling system. So goto fail would be “throw”


Not op, but that's obviously in case you need to do something more complicated than returning false later. It's good practice


As someone who's working on his own game engine in C, I applaud you for releasing an engine, a game and with such great code quality!

Thank you for open sourcing it as well. I've already learnt a thing or two by skimming the code.


Nice project! I too am working on my own game engine in C. The language gets a reputation for being inaccessible to mere mortals, but I find it refreshingly simple.


This is incredible. Great work!

I recently looked at making a really simple RTS using something like Unity and I was surprised how little love that genre gets from a lot of engines.


Well done! Very nice to see that this is still possible :)


Oh wow, that's pretty darn cool.

I like the Babba Yaga as a unit, lol!


Great great job! This project reminds me why I could never become an independent developer. Luckily I give up on becoming one 2 months ago.


bootleg warcraft 4, lets go


Let's go! I waited for 20 years.


Says ‘build - for Linux, for Windows’ - I’d just like to ask if the Linux build works for MacOS, natively; as well?


I'm not a software engineer. Can someone contextualize the magnitude of this achievement for me?


Impressive work and a lot of effort for one person, but not earth shattering or ground breaking. There's a whole community of people who do this type of thing - handroll relatively large and complex projects in C with a data-oriented mindset.

https://handmade.network/


The pathfinding video is awesome! Could you do a video on the rendering mechanism?


Are the unit behaviors coded in C, or some scripting/config language?


All the fundamental behaviours (movement, combat, resource harvesting) are implemented in C.

The engine uses Python as a scripting/config language. You can use it to hook into a lot of events pushed from the engine core (unit got selected, unit started movement, unit started harvesting, etc.) and customize or change the unit behaviours.


Why Python though (and not lua or something)? It is rather annoying to use as embedded language.


My initial idea was that I wanted a more "sexy" language for scripting. Python is a lot more popular and (arguably) more enjoyable to use than Lua. There's a lot of cool stuff like list comprehensions. Plus I had a selfish reason of just wanting to learn more Python and fool around with the CPython code.

Over the duration of the project, I really did learn to appreciate why Lua is embedded into games and Python isn't. Lua is really small and you have full control over everything. And you're eventually going to need that control when you implement features like reflection, pausing the game, etc. CPython is this big shared library that does its' own thing and you have a lot less control over. The parts where it just doesn't expose enough through its' API do do what you want is a real huge pain. I ended up writing a bunch of code to serialize all the internal data structures and this was a massive chore. Also you have a lot less control over CPython's performance and memory allocations.

I didn't really appreciate these things when I started the project so hence I went with Python. But since I ended up doing it, I guess you can still enjoy the benefits of it.


Interesting; thx for the answer!


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: