Becoming a developer
I am studying computer science but I also have a pilot license. I have been flying in BMS for many years and I love it.
I would like to start coding, even as a hobby, in something that I feel passionate about. I was wondering how can I start developing stuff for Falcon BMS?
@shadow_a_p Hi !
First question being… what would you like to do ? Code ? 3D ? DB ?
Something else ?
just a little de-motivation-al
@shadow_a_p What languages do you know / want to learn?
There’s a rich ecosystem of tools surrounding BMS… things like Alternative Launcher, which is open-source. Most of these things are C# targetting .Net Framework.
BMS itself is C/C++ code, from a style that dates back to late 1990s.
Learning to do C++ “right” (in a way that’s both safe and performant) is super hard. Jumping in to a 24-year-old codebase that didn’t do it right, from day one, is crazy super hard.
(I haven’t seen the code lately but I can tell from the mix of crash logs … null-pointer exceptions, double-free bugs, use-after-free bugs, race conditions, etc. It was never “good” C++ code. It has surely gotten better over past 15 years, but… still there be dragons.)
I know Python, Java and C++. I just did a DataStructures and Algorithms at uni. We used C++
I haven’t done any kind of graphics, I like coding though
my opinion is that every person should start with a hobby. Think of a tool to make your life easier for something.
This will give you the motivation you need. And if your tool is useful for others, others will see your value. And you will grow from there.
@airtex2019 you are absolutely right. And this is something we are trying to improve.
@Seifer so hypothetically speaking … if someone wanted to freshen their C++ skills, what flavor/vintage of C++ is BMS using these days?
I think I heard VS 2019 somewhere… is that C++ 20? Or is the codebase still built targetting an ealier standard. (what /std command line switch…)
What version/vendor of STL?
Using ATL or another smart-pointer library, for handling COM object ref-counting (for DirectX etc)?
Approach to exception-handling? (C++ style try/catch or Win32 SEH-style try/except/finally)?
Any other unusual build-time options (RTTI dynamic-cast, or new async/await and lambda expression stuff)?
@airtex2019 BMS (or Falcon) is a terrible place to learn C++. It is a mix of old and new C++. Smartpointers are introduced in some places, but in most cases we have raw pointers. Graphical API is a mix of D3D11 with old code which still lives and is very hard to get rid of. It uses its own library for things that STL does today (lists, iterators, hashes, trees etc). And all serialization/deserialization are manually done (needless to say, tons of bugs from that).
We are trying to move to C++20, but some internal issues are preventing us from doing this. Currently, we are at C++15 IIRC.
Exceptions: only one level, to catch and write the DMP, nothing else.
RTTI is enabled, which is kinda of sad. Because the code is full of:
if (i am child type A) FooAsA. else if (i am child type B) FooAsB else if (i am child type C) FooAsC ...
instead of a base interface at parent (ParentClass::Foo) and implementation at children classes.
As for sync async, BMS uses windows message passing at its core, using different mutexes everywhere to sync (which causes hard to catch deadlocks). I don’t recally having lambdas in code, although I could be wrong here.
@Seifer I can certainly imagine. As a MS alum from that era (late 90s - early 2000s) I’ve seen my share of horrible C/C++ code and have been through the hell of trying to update large codebases …
The devs who continue to improve and maintain BMS deserve the utmost of our respect and admiration!
Smart pointers >>
Definitely the most important thing you can do, to restore order to a large codebase. Doesn’t have to be ref-counted lifetime mgmt like COM pointers… just making ownership/lifetime explicit in the code, and to catch or protect against leaks / double-free / use-after-free etc bugs… is 90% of the battle.
Are expensive to throw (viz. they must capture a stack trace) so it’s probably a good practice for game codebases to adopt a coding convention of numeric error-codes (return values) rather than throwing exceptions.
That’s basically how we did things at MS. Often described as “part C part C++” or sometimes just “C plus”.
Yes, put a __try/__except block at the top of main() and every other thread’s entry point (and also WndProc, and any other callback entrypoints!) to catch and log things like OOM or page-faults etc.
I’m no fan of STL, it’s overly complex, verbose, and the data types (strings, collections, etc) can’t be passed across module boundaries… and it requires exception-handling, so for all those reasons it wasn’t commonly in use at MS.
When bootstrapping code for a new app or module, we’d have 1 or 2 devs spend a couple days making a simple String class and a couple collection templates, to suit our needs, and be done with it. (Usually such things would be copy/pasted from some other module the dev(s) worked on recently… of course.)
RTTI vs virtual-functions for polymorphism >>
I remember in the early days of COM, many oldschool game devs didn’t like the idea of virtual-function calls (for perf reasons). But that was more about crossing module boundaries, eg. invoking DX methods with high frequency.
For programming within bounds of a single codebase… that could certainly be avoided, but… I think RTTI (dynamic_cast<>) is probably even more expensive than virtual-fn call. I don’t know if my intuition on that is still valid, in the era of x64 and modern CPUs with larger cache lines, and also with more sophisticated branch-prediction…
But, similar to preferring numeric-error return codes vs exception handling, I could see a complex-world-simulator game like BMS wanting to define a numeric code for every type of “thing” (plane, ground unit, weapon, etc) and using that as a homegrown “type system”.
Yeah, it probably makes for some ugly if/else or switch/case blocks… especially as random bug-fixes and special-cases get injected over the years… and as the RL objects themselves diverge… thinking: AIM-120 -B vs -C vs -D etc.
Async / Await >>
Maybe a C++17 thing? I lost track. Not an advocate for it – just curious. I think the async/await paradigm has great promise, for new clean codebases, but not sure I would ever recommend it be retroactively applied to a large, existing codebase.
(And tbh I don’t fully understand how mechanisms like that even work, in a non-GC runtime env like C++.)
Definitely perf-critical code like BMS (game engines in general) should retain tighter, more explicit control over how threads interact, how data is passed (copy by-ref or by-value), who owns the lifetime of the objects passed, etc. Message-passing as you note, is the more useful paradigm, imho.
[Just wrote all the above to make sure my question wasn’t seen as code-shaming BMS for not being latest-greatest C++20.]
[And … on the one hand, to say BMS code is probably not much worse than a lot of Windows code … but otoh to make sure any aspiring C++ devs know the horrors that await them. :]