The time has finally come to announce the opening of the floodgates - PBS will roll out to our temporary test server and you're all welcome to rip it to shreds during the following few weeks.

The server will open on Friday, 12:00 CEST, and you can already start preloading the test-client here. An important technical note I'd like to make: There's been a number of considerable changes in architecture, so it's important that you make this a separate installation! It is not recommended to install this over an existing Perpetuum installation or to try and skip ahead in preloading by using an existing datafile - this test client will only work with the test server! Other than that, it's the same old download-run-watch-progress-bar-login routine we all know so dreadfully well.

Now, this isn't the only thing to keep in mind. The test server, being somewhat different from the usual environment, needs a few things to be explained or taken note of:

  • If you have a valid, paid account when the test server opens up, your account will be valid for the test-server as well. On the other hand, we will not perform continuous syncing; if you're late for the party, you won't get in. (That doesn't mean we won't do syncing later, but you have to have your best puppy-eyes in store.)
  • The test server is subject to the same EULA/COC as the live one - be civil, even if something's broken (and oh yes, there will be blood).
  • PVP on the test server should be strictly consensual; we won't limit your options via technical restrictions, but assuming that you're on the server to test, breaking someone else's gameplay won't help any of us, and we might revoke your access if you keep continually disturbing other players.
  • For obvious reasons, some things will run in "cheat mode": The market will seed everything for low prices, you will get large amounts of EP and NIC, time-dependent processes will be sped up to minutes instead of hours, and robots will get automatically reimbursed after they've been shot. Of course this makes economic balancing difficult, but at the same time we don't want to wait two months for the first base to be built either.
  • The test server will cease operation as soon as we consider testing complete and deploy the patch to the final live server. No data will be migrated back.

There will be a separate forum for the testing server topics here, so please open topics or post opinions there instead of other forums so we don't have to fish all the ideas and death threats together from other forums.

That's all I suppose, happy preloading, testing, and Lord Have Mercy.

We received a large package addressed to "DEV GARGAJ" in the mail today. After the obvious security measures, we controlled our little EOD-robot towards the box, and as soon as the dust, debris and toxic fallout settled, we uncovered this:

I'm not exactly adept at expressing gratitude on a poetic level, but a gesture like this is not only appreciated for what it is, it also inspires on a more personal level to work harder/more on the upcoming patches. (Although that might be just the sugar rush.) Thank you very much on behalf of the remainder of the DEV team!

It also reminded me that we (somehow) forgot to mention our previous goodie-bag-by-mail, received last summer from Shea:

Again, thank you so much! <3

The time has arrived to wrap up the final phase of the anniversary events, and our final step is to perform some sort of prize ceremony, for the lack of a better method, here on this blog. (We'll see if we can work on this somewhere down the line and add fireworks, ribbons and glow for the next occasion; right now you have to make do with overwrought verbal gymnastics and crude image manipulations.)

It has been an extraordinary weekend for us, seeing both the Agents in the audience and in the arena completely tuned to the same frequency and enjoying it as much as we enjoyed donning the visibility vests while rounding up the teams, conducting the matches as the officials, and pushing out the Zamboni afterwards to clear the arena of leftover robot parts. The great atmosphere certainly underlined our trust in the community Perpetuum has built around itself, it has been a great inspiration for us, and we're certainly gonna do this once again.

The execution of the tournament by was no means flawless, and I'd like to observe some things that we need to think about later: First off, the upper rim of the arena was way too popular, because it consisted of one single ring without any interruptions. We duly noted this and while we don't want to discourage long-range fighting, the amount of constant merry-go-rounding eventually just became silly after a while, and we'll certainly take steps against this next time. Another thing that gave us a bit of a headache was the obviously hasty decision of allowing matches to be decided with a coin-flip. This turned out to be a bad idea and we'll make sure to granulate the rules more specifically next time, perhaps including things like damage dealt or shots fired. (Again, these are just conclusions, not plans. We'll see.)

That all said, let's start the ceremony with a few people who we need to thank.

The "Jackie Stewart"-award for the commentary booth

The tournament certainly wouldn't have been as enjoyable as it was for people outside the arena if it wasn't for the amazing (and I mean that to the fullest extent) insights to the people who did the commentary with Mancs and Calvin on the stream: a big thank you go out to Lemon, Gremrod and GLiMPSE who attended our little livestream as guests, performed interviews and generally made the video stream entertaining even for people who weren't as savvy about the game as most of us. Their reward for their time and unwavering enthusiasm shall be a custom label on the forums reminding everyone that these people mean business.

The "Baby's First PVP" award for the best newcomer group

We'd like to take time to provide some kudos to the only corporation in the tournament who, despite being a fairly new PVE formation, decided to not only give the whole thing a shot but also managed to advance to the second round of the tournament, so a big hand goes to Rue Tang Clan for proving that even low EP players with enough dedication, creativity, a good understanding of game mechanics can match up any other group. They will receive what they probably need the most after the tourney: a round of reimbursements for their robots lost during those two matches.

The combined "Dale Earnhardt Jr."-award for most left turn laps around the arena and the "Garden Rake"-award for least rules observed

To commemorate the special moment of seeing four completely masked Troiars running full speed around the top rim of the arena for 30 minutes in hopes to avoid any sort of firefight and getting through the round via the coin flip, but ultimately realizing that they forgot to fill out the point cap and will be eliminated regardless, we'd like to present Infinity with a special Perpetuum 500 lightweight frame to aid them in their future efforts of legging it from firefights. This is also in honor of what we perceived to be the biggest surprise in tournament, eliminating M2S in the first round.

The "COME AT ME BRO"-award for most spectacular tanking

This one goes to a moment in a match we all found incredibly entertaining: We'd like to hand out our only individual award to Tux from 62nd, who successfully held his ground as a single robot for about 20 minutes after his team was destroyed early by Remedy, eating ridiculous amount of damage and EW like a boss. His reward will be, appropriately, a unique The Wall-brand shield hardener, to help him become comfortably numb.

...and now without further ado, let's hear it for the winners:

  • On runner-up place: Remedy Inc.
  • On third place: Crimson Imperium Reborn
  • On second place: Immortal Legacy

And finally, the winner of the first anniversary Perpetuum Tournament is:

With a nail-biting finale, CHAOS has shown us amazing proficiency, tactics and discipline as they marched through the rounds with their impenetrable Tyrannos squad, and they're well deserving to the champion title, and by proxy the free entry to the next tournament as reigning champion. The top three teams are already in the process of receiving their rewards (see details here), and all other participating teams will also receive a complimentary goodie package, so hopefully we can wrap all this up within a few days.

Once again, a big big honest Thank You to all the groups who have stepped up to participate, the players spectating in the audience, all the players who in the meantime roamed the fields in search for treasure, and all those who watched the weekend unfold on the video stream. (If you missed it, check the video archive here.)

We had a great time - hope to see even more of you in the next event!

Over the course of the last few months, as I was reading forums and talking to people on IRC, I couldn't help but notice the staggering amount of suggestions and fairly simple requests that we've been offered. While this would be by default a fantastic thing, it triggers a returning problem that most players are blissfully unaware of: the complexity of our architecture, and our dedication to keep the architecture as robust as possible. What this essentially means is that sometimes the most trivial minuscule feature has to go through a rather arduous chain of procedures to be finally implemented on the client side. My attempt in this post today is to present you with a case study of how this happens in case of something most people would consider a single line of code and 20 seconds of work. But first, let's talk about concepts.

The principle of our system

The idea of the Perpetuum infrastructure has been engineered to be robust from pretty much Day 1, although admittedly we kept expanding on several things over time. The concept was the following: Since we're a very very small group of developers, we cannot afford turnaround time and taking time away from each other when it comes to fixing things, so the optimal solution is to allow anyone to fix anything they can. Of course, this doesn't mean that people with no interest in coding can happily add mov ax, 1 into random places into our source tree, but it's important to realize that in a project like Perpetuum (which is a rather strongly data-driven game), we have several times more the data than we have actual code. This means that as long as the artists and content folks can change the data, programmers can work independently of them, so essentially what it boils down to is exposing as much data as we can. (If you started giggling, do a few push-ups. It helps.)

The way we do it is manifold: For artists, who mostly work with standard format data (bitmaps, meshes, sound files), we have a file server where they can upload new versions of resources, and they get downloaded the next time someone starts the game. Of course this can result in some problems when we change some internal file formats, but as long as the client is able to do an update, this shouldn't be an issue. (We also have revision control, so reverting to an earlier version is easy.) On the other side, we have the content guys who work on managing the actual game logic data (i.e. item data, balancing, that sort of stuff) - this isn't as trivial because this data needs to run through both the server and the client: the server needs this data for calculating the game logic, the client needs this for displaying data and doing client-side prediction. This also needs to be both persistent and easily alterable, so for this, we need a strictly database-driven environment.

So here's how it works.

A simple example

The most trivial example I already noted when we were working on it was related to sparks: The spark GUI was pretty much finished codewise, when Zoom noted that the order of the sparks doesn't make much sense because the syndicate ones are on the bottom while the ones that are harder to access are on the top. The reason for that, obviously, was that Alf simply added them in the order he felt like at the time, assuming that we can just sort it on the GUI-level later. He was obviously right about that, except we didn't really think of a method.

The idea looks simple on the surface, but there are several solutions to fix it and all of them are either laborious or asinine:

  • We could leave them unsorted. That doesn't fly because it's annoying.
  • We could sort them on a GUI level, by hardcoding weight values. This is just a big no-no considering that any change would need to go through the client coder. (=me)
  • We could create a resource file in the resource repo that describes an order, and thus any non-programmer could edit it. Sounds good on paper, but sparks can be added or removed at any time, which means that if the resources are out of sync, the whole thing becomes a mess, and you're still working with two things at the same time. So no, this is just shooting ourselves in the foot. (Update - I might have forgotten to mention the most important part: non-programmers and markup languages rarely mix well.)
  • We could sort them on the server, by hardcoding etc etc see above yeah no.
  • We could extend the database records for sparks with a sort order value. Shiny clean solution, but with the most work to be done. Why? See below.


So here's the entire process of how a single integer value traverses through our infrastructure. As you may see these aren't particularly complicated steps by themselves, but the amount of steps and their versatility eventually amounts up into a surprising amount of time.

First, we take the database table for sparks, and add a field. This is done on the database server, usually by Crm.

SQL design phase

Second, we extend the administrative web-based back-end (what we lovingly christened "the MCP") with the field so that we can have data to work with. This can get tricky if the field isn't just a standard number (but e.g. a new item type or an extension ID), but in this case this is just a simple text field. This is done by me.

That isn't going to do you any good, Flynn.

Let's remind ourselves of something at this point: Because of our rather rigorous security-principles, no game-related data will be kept on client side, everything comes through the server. Now because sparks are very much a core gameplay element, everything related to them will also come through the server as well. So our next step is to add server code that loads the new value from the database, and hands it to the client. This is done by Crm again, and usually involves a server restart, much to the chagrin of whoever is working on the development server at the time.

Server phase

So now our value is en route to the client, all is left for me is to add fields to the client cache and use it to actually sort the sparks in the correct order, i.e. the aforementioned "single line of code". Of course, the actual sorting algorithm code is already there, I just have to build a new comparison function, test it, deploy it as the newest client update, and ultimately the feature is done easily.

Client phase

Simple enough, but if you look back, the ricochet performed by that one measly integer value is pretty staggering.

What you have to understand here is that this is the best solution, as strenuous as it seems:

  • It's robust (no hardcoding involved, extending doesn't involve breaking anything previous)
  • It's completely "user"-driven, anyone can use the web-interface to change the values without having to worry about breaking something in the code level (mostly); database-constraints and form-validation can take care of values we don't want in there.
  • Most of the code-changes needed are just passing around values without thinking of what it really is.
  • Once the code works, it'll always work as long as the data itself is solid.

But of course, as mentioned, the downside is that it needs four different levels of changes (database, back-end, server code, client code), which is only done by two people because of the involuntary competence we acquired over the years - in a "larger" project, this could possibly take a lot of cross-department management, while here it's usually just strong language and the occasional "Eh, I'll just do it myself". However, once we're done, we can wash our hands and never think of this pipeline again, because the content will go in on one end and the code will take care of it in the other. (On a tangential note, this applies to blogposts too: This post will probably be / was proofread and reviewed by several of us.)

Exercise for the reader

Now, to make sure that you understand the gravity of this stuff, here's a little thought-experiment for you: When you right-click an item and select "Information", there's a lot of parametric data that ends up on the screen, each with their specific measurement unit and number format. Now remind yourself that some of these values may look completely different internally: percentage values that show as 5% are obviously stored as 0.05, bonuses that show up as -25% may be stored as 0.75, some values need two decimal digits while others need five, and so on.

So here's the challenge: knowing the above principle (i.e. be data-driven), what kind of system do you build to make sure that each of those values end up being displayed correctly for the player? (No prize for the correct answer, although we do offer occasional trauma counselling.)

In a later post, I will go into a deeper insight about how an actual feature (case in point the whole spark-doohickey) goes from an idea to design to concept to task to implementation, down to the level of "BUG #4170 - please move that text one pixel to the left".

It's time to take a good old roflcopter for a ride and report you from a recent hilarious happening from our beloved Avatar Creations office of fun.

As you may expect from indie game developers, our daily nutrition-intake is largely homogeneous at best, and can be usually expressed with what our friends in Britain would characterize as "beans on toast". To this end, when the game launched, I decided to traverse to the local kitchen appliance store and surprise ourselves with a wonderful sandwich grill, to spice up our otherwise dull circulation of carbohydrates.

The grill has served us wonderfully for a few months, until it's untimely demise when encountering a larger piece of pastry, at which point the structural composition of the object underwent a major realignment:

It was a tragic casualty, but after much grieving, we carried on. Then today, tragedy struck again, as the trusty office toaster, which has served us for the entire duration of the Perpetuum development, has inexplicably caught fire and nearly proceeded to burn through the bottom of the cupboard, only to be carefully unplugged and shoved in the kitchen sink by yours truly in a haphazard but effective manner.

Forensics have later revealed that the culprit was quite possibly the ejection lever lodging in halfway, either due to hardware failure or the toast itself wedging between the rim and the metal framing, which has caused the heater mechanism to switch from "medium well" to "meteor shower", and eventually "thermal ammo AOE attack", cheerfully melting the plastic framing itself in the meantime and looking wistfully towards the wooden cupboard bottom.

So yeah, we're one toaster down, and I'm still hungry. However, on the plus side, rest assured this will not serve as a hindrance on our development schedule.