Sunday, December 29, 2024

Fixing a Bug the Hard Way (NME5 Part 1)

The day was April 2, 2024. Team SCU had just unveiled a new mystery download link for any and all who dare peek inside. The few brave souls who clicked open the executable file were greeted by not one, not two, but ten-thousand blades of grass blowing in the wind...


That's right, my game engine was now on Version 5.0! Woohoo! And following that announcement was of course a playable demo for Team SCU's stealth video game.

So what did the new version mean exactly? It meant I finally decided to increase the number to 5.0!

Oh, and there was a pretty huge change, too. Our story begins eight months prior...

Lost in the Woods

It was an ordinary Wednesday afternoon in Camp Troidia when three hikers journeyed into the woods. "We'll head this way. Just keep walking," said the leader.

Not long had passed before the hikers wondered if they were headed the right direction. Suddenly they heard a sequence of snapping sounds, growing more fierce then stopping with a heavy thud. It was as if a tree had fallen in the forest, and everyone was around to hear it! Yet, within the resulting plume of dust, there was no toppled timber in sight. "Just keep walking," said the leader.

Hours passed, and the party grew concerned. Where were all the birds and ferns that should be here? The hikers turned a corner and stopped with a jolt. There was a vast angular ravine beneath them, and they'd nearly stepped over the edge! But with the blink of an eye, the ravine was gone. The ground was flat as far as they could see. "Just keep walking," said the leader.

As the sun descended into the horizon, the hikers knew they were lost. In the final moments of light, they pulled out their Book of Maps. "That's strange. The cover just says 'of Maps' now. I guess the other word must've rubbed off in my pack." They flipped through the pages trying to find something relevant, but all the important panels had become scrambled and indecipherable.

"Wait, where's my arm?!" By now it was too late. Within seconds the hikers were consumed... by darkness!

When the search party arrived the next day, they found only two bodies. The leader was was nowhere in sight.

"Oh I'm right here," a mysterious voice interjected, startling the two sleeping hikers awake. "We're totally fine. I'm just invisible right now. Once in a blue moon, Troid's engine doesn't load an image properly for some reason, so weird visual artifacts can happen."

Yep. That's annoying. But the occurrence is almost too infrequent to care. Well, almost...

Finding the Trail

Building a new feature into my engine is a huge commitment, often spanning several months to a year, so I must always choose my next steps wisely. But in Summer 2023, there were suddenly too many important paths forward, and no deadlines to point me toward any in particular. I was feeling as lost as those fictional hikers...

So I organized my thoughts into a full summary of my engine, highlighting the good, the bad, and the ugly. The hope was that this outline would make it obvious to me how to proceed. Spoiler: it worked! Let's walk through some of the shortcomings to discover the pattern I saw:

"Making games in NME means mostly just writing code, with minimal support for visual editors."
"It'd be nice to have model animations back, using standard formats instead of my custom system."

It takes a lot of code to make a game scene work, and as the one who writes the code, I become the de facto author of many core aspects of the game. In other words, I'm wearing too many hats! The more hats I can offload to others, the better.

However, I'm very picky about data formats I will support in NME. For one, I never want developers to feel they must pay money for 3rd-party software to get the most out of my engine. This rules out the most popular 2D skeletal animation tools out there like Spline and Spriter Pro.

A sequence of forces and procedural reactions allow these abstract shapes to glide around believably. I think it's some kind of bear's head maybe? Who knows.

If anyone knows of a robust free solution for playing with that kind of data, let me know! For now all these 2D figures will continue to be animated with my code and/or with more hand-drawn frames by the artists. In my head I was pondering the idea of projecting 3D formats into 2D space so that we could leverage programs like Blender to make game assets. Hey, that reminds me of another thing...

"I believe NME has a lot to offer as a 3D engine, but certain modules restrict it to 2D for now."

If I wish to start supporting 3D models in my engine, I might as well go all in! NME isn't too far off from going full 3D, but it would certainly take some time. The biggest barrier would be my own understanding of graphics APIs, as NME 4.4 uses only the most basic OpenGL features possible to achieve its results. (Note: a graphics API is how games display things to the screen, and OpenGL is the one I've always used). Which reminds me of another thing...

"The graphics capabilities are not reaching their full potential. NME runs well on older hardware, but someday I'd like to take better advantage of modern GPU architectures. I'm behind the times."

Over two decades behind to be more specific! Well, in a sense. I'm somewhat ashamed to admit that all my games had been using something called Immediate Mode for everything.

Sorry, I cut some corners on this one...

What is Immediate Mode? Pretend we're in a restaurant. I'm a chef and you're a waiter. The customer just ordered a bowl of rice from their phone, so I call you over to deliver it to them.

Now, I could just scoop the rice into a bowl and hand it to you, but that would be too sophisticated! Instead, I reach into the cooker and start handing over one grain at a time. I've gotten weirdly fast at this, but you'll still need some patience. I don't provide you with a bowl, and I don't even tell you in advance how much rice was ordered, so you first have to guess what size receptacle to use.

If you guess too small, the customer has to receive their order in multiple batches. But guess too large and that oversized bowl could've been used for something else, so go do some dishes! Anyway that's what Immediate Mode is like for your graphics driver. Many grains. Much improvisation.

In my defense, NME's games don't exactly have much data to send, so Immediate Mode can actually make a lot of sense as it's very flexible. The first room of Prime 2D renders 1640 triangles (from 3258 vertices), which might sound like a lot, but nowadays a single "low-detail character" in a typical console game might already have 10,000-40,000 triangles (source).

Unfortunately going beyond OpenGL's Immediate Mode is a daunting task for a hobbyist like me, even if the concepts are simple to use once understood. Poorly-named terms like Vertex Array Objects, Vertex Buffer Objects, and Element Buffer Objects (all different things) can easily scare someone away. Still, there was no excuse to put it off anymore. By procrastinating on this next layer, I was preventing NME from displaying detailed 3D models or tons of particles, not to mention that Immediate Mode isn't even available on mobile devices.

Hey, speaking of other platforms...

"NME is Windows-only. Native support for other platforms (Apple, Linux, web) would be nice."

I've tried to keep NME as cross-platform as possible, so there are only a few key locations in the engine that still require Windows. One of these locations relates to spinning up multiple OpenGL graphics threads, for tasks like loading several images at the same time. OpenGL was never designed for multi-threading, so this aspect required me to read through incomplete documentation of "WGL functions", discover best practices through old or obscure message boards, and do some plain old trial and error. Which reminds me of another thing...

"There are two phantom bugs that are incredibly rare but have been haunting me for years."

One of those bugs... is the one where images don't always load correctly! When tens of thousands of players tried one of NME's games, the bug was bound to show up a few times.

Did I look into it? Absolutely. The problem happens only with images, so I meticulously studied every image-related shared-state access. I experimented with extra command flushes and synchronization guards, but I wasn't able to narrow it down. It's possible I was hitting an obscure behavior of OpenGL context sharing, WGL functions, or maybe just certain drivers or hardware, but still, I couldn't shake the feeling that it was somehow my fault. I had no idea how to tiptoe around it, other than making load times longer by reducing image submissions to a single thread, just to stop this once-in-a-blue-moon phenomenon. I didn't want to do that, and my time was spread thin, so the bug continued to haunt me.

But... given all of the above shortcomings of my engine, and the path I just walked through... there was another way. Another way to make everything better.

I could switch to Vulkan.

Beneath the Crust

Vulkan (Vk for short) is a modern alternative to OpenGL. All the crumbs for this fell into place so neatly. Working backward:

Vulkan was designed with multi-threading in mind, so my phantom bug would surely go away. I would need fewer OS-specific calls to initiate that, so the codebase would be a step closer to being cross-platform (assuming MoltenVK stays strong). I'd be forced out of Immediate Mode and pulled closer to present-day GPU architecture, now with fancy techniques like Compute Shaders available at my fingertips. NME would take a big step toward eventual 3D capabilities, which would also add future potential to connect with many standard game asset formats.

Don't get me wrong: OpenGL is fine. Its latest flavors are still relevant and can handle the above. But my particular old-school use of it finally rang clear in my head as the #1 thing holding my engine back. I had two options: learn more advanced OpenGL features, or switch to a newer API.

It wasn't a decision to make lightly. I'd be dropping support for older hardware, and if Vulkan lost its traction in the coming years I'd have taken a big misstep. It's significantly more fine-grained than OpenGL, but that's exactly the kind of control I wanted. It seemed I was ready for such a challenge. It was time for NetMission to overcome its greatest weakness and join the world of cutting-edge graphics!

Luckily this switch would probably only take me a month or two, right? Everything would be up and running in no time. What could go wrong?

TO BE CONTINUED IN PART 2...

Tuesday, August 1, 2023

NetMission Engine in 2023

If you're familiar with NetMission already, maybe from playing some of the games it powers, or from engaging with Team SCU's community, then you're probably also familiar with how much of a mystery it is. One developer. Unclear intentions. And he disappears a lot. (Sorry about that.)

Let's fix that with a brand new...

Official Overview, 2023 Edition!

 

 

NetMission (NM or NME) is my private engine for making 2D video games. I started it in 2006 and have used it to produce games of my own as well as games with Team SCU. The most well-known of these was unfortunately discontinued, but it certainly influenced what I've built in the engine.

Today, NME has many features. Here's what you can expect to see in its games:

 

Pixel-Artwork Specializations:

  • Parallax can be difficult in low-resolution pixel-art games. NetMission combines the clarity of the pixel grid with the smoothness of subpixel blending for optimal results. Even without parallax, it lets me be fine-grained about exactly how each sprite should appear each frame.
  • Built-in support for SpinTroid, my 2019 pixel-art rotation algorithm with generally better results than the industry standard (RotSprite). SpinTroid can dynamically rotate entire scenes in real-time, as showcased in past games.

 

Special Effects:

Can be made using NME's GPU-accelerated graphics toolset which enables shaders, intermediate rendering, color operations, fully customizable particles, pre-multiplied texture alphas, sRGB gamma correction, and other such technical terms which I can cover someday. Players have appreciated that NME's games run smoothly on low-end hardware without sacrificing visual quality.


Fine-Tuned Controls:

Not discarding input data under stress: a surprisingly rare feature in the wild.

  • Player input is processed correctly even if the framerate were to drop or stutter, guaranteeing a reliably smooth feel.
  • [NEW!] NME now has controller support! Your feedback was heard!
  • [NEW!] Games can connect any device's signals to any player's actions via any possible data constraints, transformations, or grouped dependencies. Whew! In other words, I can now much more easily add spaghetti important configuration options to my games. Things like...
    • Button-mapping screens
    • Local multiplayer (even within one keyboard)
    • Customizable controls per character/nametag/controller/save slot
    • Arbitrary deadzone shapes
    • Accessibility options for motor control disabilities (e.g. tap-to-hold, rapid-fire)
    • And so on

This system took me forever, but I'm glad I finally did it! Of course, making a nice GUI for all of of this would be its own project, but at least the possibilities are now at my fingertips.

I think the jump signal is coming from the fork actually.


Optimized Asset Management: (aka the nerdy stuff)

  • Uses a thread pool to stream game assets in and out of memory as needed without interrupting gameplay.
  • Handles multi-stage loading and cyclic dependencies with ease, verified extensively with math and tests.
  • At game publish time, processes and packs game assets for fast load times and small file sizes.


3D Audio Soundscape: 

Powered by OpenAL-Soft, which features a wide range of real-time processing (reverb, EQ, positional surround-sound, distortion, etc.), enhanced by NME with seamless chaining of different formats (ogg, mp3, opus, etc.) through an easy-to-use code interface. In NME's games I've been able to implement nifty effects like synchronizing gameplay to music as well as placing large numbers of SFX in the environment for emergent sounds (like a swarm of 52 insects each with their own little pitch-shifting buzz).


Spline-Based Animation Systems:

Just kidding. This system and its custom editing tools were NME's greatest achievement 10 years ago, but I decided to cut all support 5 years ago. (What?!) That's a discussion for another post. For now I get by with other methods of animation, but at least the gifs still look kinda cool.


Saving Done Right:

  • [NEW!] The save system is totally revamped! NME now supports flexible game-specific storage formats with automatic versioning, backwards compatibility, and sanitization. Saving & loading is multi-threaded (so no gameplay interruptions) and can even handle system power failures mid-save (so no data corruption).
  • Relatedly, NME provides easy methods to prevent leaking gameplay events across boundaries, even if you were to like, start a cutscene, pause the game, and reset to title screen all in the same frame. If you watch speedruns, you've probably seen people do stuff like that in other games to exploit bizarre glitches!

 

Physics:

Powered by Chipmunk2D and enhanced by NME with automatic polygon decomposition, tunneling prevention, more powerful abstractions, the ability to change structural state within callbacks, and other confusing phrases that I'll have to explain in a more detailed post again. (Especially since Box2D seems to be back on the rise!)


Multilingual Text Support:

Unicode? No problem. NME unifies BMFont and FreeType as one and can wrap text in a column, align it, scale it, rotate it, type it, and otherwise treat it like any other image. Pretty standard stuff, but it's important for this system to be solid.

 

Instant Publish: 

[NEW!] I can now generate sharable game packages at the push of a button! Yes, everyone would expect this from even the most basic of engines out there, but it used to take me many hours to carefully organize all the right game files and gradually coax NME into forming a new demo. The dark ages...


There are many more features, but those are the current highlights in my view.




NetMission also falls short in many ways. Here are some things I hope to improve in the future:

  • The "Net" in "NetMission" was supposed to suggest online play, which is nonexistent so far. (Lol)
  • NME is Windows-only. Native support for other platforms (Apple, Linux, web) would be nice.
  • There's no lookup system for text. All text is typed directly in the game scripts. (Yikes!)
  • Making games in NME means mostly just writing code, with minimal support for visual editors.
  • The graphics capabilities are not reaching their full potential. NME runs well on older hardware, but someday I'd like to take better advantage of modern GPU architectures. I'm behind the times.
  • The GUI-making system is incomplete. I sometimes just roll a new GUI system on the fly. (Bad!)
  • We're missing rich-text features, like stylizing specific words or handling right-to-left scripts.
  • It'd be nice to have model animations back, using standard formats instead of my custom system.
  • There are two phantom bugs that are incredibly rare but have been haunting me for years.
  • I believe NME has a lot to offer as a 3D engine, but certain modules restrict it to 2D for now.

It'd be so awesome to resolve all the above, so I'll try to make it happen!




Lastly, I'd like to discuss the development process so you know what to expect going forward.

Side note: As mentioned, NME is private. If you're excited about making games and want to get started, you should definitely check out the well-established engines out there like Godot, Unity, Unreal, Game Maker, RPG Maker, and so on. NetMission isn't equipped for wider use right now.

Well, what to expect is that things can move pretty slowly. As a professional musician, I don't always have much time to work on NetMission, and that isn't anything new. If I can get in maybe ~3 hours of coding most weeks, then something that a full-time programmer could accomplish in two weeks might take me over half a year.

It might sound like I should recruit help from others to make it go faster, but that would defeat why I work on it. For a number of reasons I could go into, opening NetMission at this stage could quickly hurt my motivation, momentum, and design philosophy. That said, when the time is right, I do hope to make NME available for others to use. One of my dreams is to make fun educational games, and if NetMission itself can be someone else's fun educational experience, too, that would be amazing. It's just not ready for that yet.

For now, I'll scratch my itch of making fun educational content by posting to this blog, and you can get involved in NME by leaving comments and suggestions on what comes next. It will take patience, but I'm treating this site the same as the engine: write a bit when I get a chance, keep the process fun, go all out, and occasionally I'll have something cool to show. I hope you can be on board with that. :)

 



Thank you for reading this far. I'm sure you have questions. Every paragraph and bullet point in this overview could easily be the topic of its own post and beyond, so I certainly have my work cut out for me!

 ~ Troid92

Wednesday, June 7, 2023

Hello, World!

...

It's about time I write something here.

I've had this Blogger subdomain set up since February 2016. "The story of a videogame engine, in the hands of a busy musician." I always got a kick out of the fact that this subtitle was followed immediately by "No posts." Sounds about right.

But despite my busy music career, the lack of posts on this page has been very misleading. In fact, I even continued posting my development stories elsewhere, although the images there didn't survive long. I'd like to bring those essays here, as soon as I figure out how best to treat them in this new context.

 

"Hold on. What exactly is this 'NetMission' you're developing?"

NetMission is my game engine. Kind of like how Microsoft Word is software for making documents, a game engine is software for making videogames. Over the years I've used NetMission to make a handful of games with others, which I'll talk about in other posts.

If it sounds unusual for someone to make their own engine from scratch, you'd be right! Nowadays if you want to make a videogame, you have many delightful engines to choose from, each backed by huge teams of hard-working and talented professionals.

But when I wanted to make an online multiplayer game 17 years ago, those options weren't ready yet. At the time, it somehow made sense for aspiring indie developers to grab a beginner's programming book and go about it the hard way. I had no idea what I was getting myself into, but I've stuck with it ever since!

Anyway, I haven't posted a significant write-up on NetMission in nearly five years, even though I've still been coding up a storm. Part of that is intentional, as I've had several good reasons to keep it under wraps. But things have changed to a degree, I suppose. Lately I've been getting the sense from others and from myself that it's time for me to start writing again, so... let's get started!

 

"What exactly should I look forward to, Troid?"

Good question! I do have a few guidelines for myself:

  • No programming experience should be necessary to follow along with my articles. Even as I dive into advanced technical topics, I want to make them as approachable and entertaining as possible.
  • This site should become the definitive center for everything NetMission, since information about it is currently scattered and/or nonexistent.
  • I should feel free to branch out into loosely related topics as needed. Games can reach into so many aspects of life, and a game engine should understand and support that.
  • I must write at least 1 article per year. I'll try to do more than this, but you'll have to forgive me as I am a very slow writer.

Otherwise, I am not totally sure what direction I'll go in yet. If you're reading this I am definitely open to questions and topic suggestions.

I guess we'll see how it goes!

 ~ Troid92