New server

For the last few years I had been using DigitalOcean to host this website & a few others, file sync and my git repos. Fairly low traffic stuff on a single VPS instance. It was nice and cheap. But still… the recent 20% price increase got me thinking…

Can I build my own server?

Turns out I could! And it was a lot of fun.

I used a 10th generation Intel NUC with a 6-core i7 CPU, 32GB RAM and a 1TB NVMe SSD. Yes, overkill. But the key parameter is power usage. The whole system draws ~7W at idle. What a wonderful little machine!

For the OS I decided to install Ubuntu (22.04 LTS). I’m familiar with it and it was useful having the same OS on both systems. Then, some housekeeping on the old server:

  • removed old disconnected websites
  • put websites under separate user accounts
  • moved from Gogs to Gitea
  • organized my git repositories
  • setup a more thorough backup procedure

When I had everything set up to begin the migration, I brought the NUC to the new Prague data center and turned it on. Then I started moving websites and services one by one. Soon the old VPS instance will be empty and I’ll be able to shut it down.

CPU RAM Storage
DigitalOcean 1x vCPU 2GB 50GB + $extra
Intel NUC 6x CPU / 12 threads 32GB 1000GB

There’s plenty of headroom for no extra money and I feel like I’m more self-reliant.

To elaborate a little bit on the backup procedure:

  1. daily rsync (soon → rsnapshot)
  2. daily mysql dumps
  3. /etc and apt package list versioned in git
  4. secondary NUC ready for deployment
  5. backup VPS account ready for deployment  (prepaid credit)
  6. up-to-date checklist for configuring the whole software stack

D2 log 070 – Attack tokens

It looks ridiculous when all enemies attack the player at once. And it’s frustrating. We need to globally throttle the attack rate.

Inspired by this fascinating Doom talk, I implemented a token system. Before each attack, enemies must acquire a token for it. After the attack and some cooldown period, the token goes back into the “free” pool.

Changing the number of available tokens for each attack type and tweaking the cooldown periods are an easy way to adjust overall difficulty.

The state of the token queue can be used to determine pressure on the player. This will be a useful input for the dynamic sountrack…

D2 log 069 – Editor streamlining

While making a test level to try out some gameplay-related code I realized the editor had become a bit cumbersome to use. It was time for another round of editor improvements.

Some commands got moved into a global top menu bar, which helped a lot. Not all controls need to be always visible.

Second, I added a panel with the sorely needed list of all entities in a level. It automatically pans the camera to the selected entity and the next tab shows all its properties.

The navigation mesh was a separate layer of points and links with its own custom editing mode. I converted the navpoints into regular game entities. Same for the navmesh object which pulls them together and handles path search queries. Now the only custom code is the test mode (move origin/destination points around, editor draws the resulting path).

Finally, I upgraded all the editor icons. They were a total mess and adding new ones was a pain. Now they are all in a single Pixelmator document, ready to be exported with 1 click. The icons will not be seen by players but it helps me see quickly what’s what.

D2 log 068 – Water shader

Spent some time tinkering with shaders. It was fun but also hard to come up with something actually usable in the game.

Ended up with a subtle effect which is blended on top of the pre-rendered water surface. It doesn’t tile properly but the seam is hard to notice so I’m fine with it.

I also tried distortion for the bottom layer but UV wrapping is a problem because the tiles are in a texture atlas. Putting tiles in an array texture instead of an atlas would give me more options. Maybe next time…

D2 log 067 – Tiles, pt.3

Good progress on the tileset. I made basic outlines and shapes in Blender, then exported into Pixelmator for touchups and additional dirt layers.

First time I used Geometry Nodes in Blender. Fun!

The rest though, not so much… it’s a lot of work to make everything seamless, color matched and correctly exported. Listening to podcasts & GDC talks while working on the tileset helps a lot because it stops me from overthinking it. I really need to push through this one.

Still not the final version here; there’s an off-by-one error in my Geometry Nodes setup for the curb and one of the dirt layers is disabled.

D2 log 064 – Audio improvements

Before recording new sound effects and adding music, I want to improve the audio engine a little bit.

In this first part, I implemented some fundamentals.

  1. Envelopes. Automated adjustments of gain, pitch or pan etc. Already replaced old code for fading music in and out.
  2. Audio bus hierarchy. Apply parameters to all related sounds in one place.
  3. Lowpass/highpass filter. This has been on my wishlist since Superforce and I finally got around to it. I used this article as inspiration but the code is 100% rewritten for clarity & performance.
  4. Limiter. Safety guard to avoid clipping.

The big payoff for these features will be ducking. To make important sounds stand out, I want to suppress the less important ones. This can be done with gain but also applying the lowpass filter could make it sound even better.

D2 log 063 – Ammo box

Recently I ran into a design problem. Some enemies in the game will be immune to bullets and you’ll have to use grenades. Of which you can only carry a few. What if you miss and run out? You’d have to restart the level.

For a moment I considered loot drops. For something you’d be required to get they seemed too random and potentially frustrating. Instead I shamelessly copied Half-Life and added a grenade dispenser!

It’s a box full of… grenades. Just walk up to it and get a refill. The lid opens automatically to indicate you’re not supposed (or able) to break it like the regular ammo crates.

D2 log 062 – Menu navigation

I’d love to see the game running on Steam Deck one day. Until then, I’m using an Xbox controller for testing.

Some menus were impossible to navigate with the gamepad or keyboard. I’m not building any sort of generalized UI framework but this needed to be fixed.

Each menu item contains links to its neighbors and pressing ←↑↓→ changes focus accordingly. In most simple cases, such as the main menu, the autogenerated links were enough but in more complex layouts some were omitted. So added a way to create the missing links manually.

Now I can get right into the game using just the controller, which is cool.