Thursday, March 2, 2017

Long time no write

I began this blog to do pretty much two things. Learn to write better, and talk about World. So, rather than worry about structure or style or being useful, I'm going to just write a little bit now.

It's been, well, too busy for Toast in recent months. In August or so of 2015 I left my previous company to embark on a new endeavour with my old friend (and boss), Anthony Duca. I began working as a contractor full time while eeking side time for this new project, sort of working two jobs, but only in the split attentions sense, and not in the spending-too-much-time-working sense. We successfully kept it sane. I continued with Toast during this period of time, but it did slow down some.

In September 2016 we welcomed in our son Brandon to the world (lowercase). Halfway through 2016 or so it became apparent that between 2 works and pregnancy/parenting, Toast was going to slip off the list of things-that-be-doing.

In 2015 I built the AI system which I still intend to write about. In 2016 I worked on Caravan, the scenario that required it. I then rebuilt the AI to actually work. I then had to rebuild a lot of how the scenario worked. I built some tools to improve network performance, and began two other game system projects; A terrain flowing system for semi-solids (sand/gravel types) and liquids, and the Mission Builder, a potentially awesome project which needs to be discussed, but only after writing about AI.

There's still cool stuff to be done and I still desperately want to work on it, but realistically my time will be spent on Brandon, Irene, and then Cavrnus, my new company. I have lots to do there too, and every hour-of-focus I spend on it gets us closer to success. And if we triumphantly succeed... well, then there might be more time for Toast. But, well, while that's a nice thought, there's still lots of work to be done first.

In any case...

Writing is a skill, and one with which I need practice. I'm going to expand my topics here a little. Maybe a little more programming, maybe use it as a place to write about game design, or as a place to whine about game design in the games I'm playing :p

But maybe I should first write that AI post that's been sitting, started, in my edit list since last year, eh?


Thanks for reading.

Sunday, May 15, 2016

Caravan mission music recording

I did two new raw recordings, in theory for use in Caravan. I didn't really plan out these music selections; I just sort of played. The only constraint was the rough length (the non-combat part of Caravan is currently 6 or 7 minutes), and the combat part is expected to be from 6 or 7 to 15 minutes. I also didn't want it to be the same musical theme as from the tutorial, but a common element or two is still good.

It is raw and unprocessed but here they are:

Caravan Opening Theme: This ended up very slow and quite sad; I think there's hope in there but it takes some working up to. Not inappropriate for the mission, but it might be a little too slow. I was amused to realize a few minutes into recording it that I was playing in 6:4 time. It is not amusing in of itself, its more that I was amused that I didn't already know. :)

Caravan Combat Theme: This is supposed to be a pull from the same theme as above, but with a more pounding energy and constant tension. It bears some similarity to the tutorial's combat theme in the nature of the bass and the beat rhythm; that's alright I think.

I'll listen to them both for a while and decide if I'm gonna keep them.

Lots of Caravan and AI updates to talk about; but the current rule is that it waits for Caravan to have a successful full playthrough! Soon? SOON?! (hopefully)

EDIT: There's some funny resonances in the combat theme that are kind of painful and obviously not intended. I'll have to figure out how to fix those sometime, but I'm honestly not sure how.

Monday, February 15, 2016

Overdue update; AI and Terrain effects

Wow. September 5th for the previous post. Long time. Overdue for an update :)

AI was the task last mentioned. Guess what! It turns out AI is hard, just as I was saying in September. It is also interesting, but maybe even moreso frustrating. So what's the current state of it? Well, it works. It works and does some interesting things. We can specify AI parameters for actions we build in the spreadsheets, and it can use them; even those with complicated prerequisites. It can build sequences of steps needed for complex actions. It can forget all that and just decide on an immediate next step. It can be guided to some extent as well; the AI units can be given preferences for types of actions and considerations.

All fine and good you say, but what can it do?

It has a reasonable combat driver; it can control commanders reasonably in combat situations. It weighs objectives, current status and positioning, enemies' status and positioning, and allies'. It will retreat when hurt, rally when it can, charge from distance, advance to stay in proximity, hold when threatened.

It can reasonably find its way to a target location, even with blocked paths and terrain obstacles and complicated areas.

It can run a rudimentary protection objective, defending multiple points and sort of separating out the defense when there are multiple AIs.

It knows how to get unstuck in various ways; it will rally or use other available methods to gather its party and venture forth.

It works in a way that is asynchronous with the game, sort of, so the AI takes game time to execute rather than real time. It can be parameterized to think slow or think fast.

It doesn't sound like much, does it?

The immediate purpose of the AI is to control the caravan opponent in scenario #2. At this point it can control it reasonably well, but it still needs a few more lessons to acheive the goal. It needs to break down paths into pieces for piece-wise evaluation of threat. It needs a partially endurant memory that understands temporality. It needs to be able to be controlled to want to retreat/recover after certain actions (or it needs to decide to do so itself emergently). It needs to gracefully handle the player harassing it without a hard engagement. Still feels like a ways away.

Here's a 3 minute clip of the AI sort of succeeding a traversing the obstacle course. A couple bugs show up pretty obviously.

In any case, I decided to do something more frivolous before I return to Caravan again. I wrote in a system to have the terrain material types execute visual effects. I also changed how the terrain renders to use the materials system that got written somewhat recently. Every now and then you need an easy task with instant gratification.

I know it's not exactly amazing; but it adds a bit more life to the terrain. Here's a clip of some new layers thrown on top of the Caravan terrain as a test.

Next time should be sooner. :p

Saturday, September 5, 2015

Skirmish Update

Being sick and travel does a number on productivity for side projects. Alas this means that comparatively little has been completed in the last month.

The Caravan level's introduction, dialogue, and scripting are written and working (although it needs polish of course). The main content of the scenario is next, and that was a daunting prospect. This is the first scenario where we need a somewhat intelligent enemy. Intelligent in that it can use skills at the right times, find new paths when paths are blocked, and react to the player. The original concept was to build this within the scripting system for the scenario.

But we knew in the future that we were going to want to build procedural scenarios. Procedural scenarios can't have custom scripts to control enemies. Thus was born the need for a enemy control system; an AI one tier higher than our current AIs.

The current AIs in the system behave very primitively. It manages movement and pathing, deciding on an action to execute, handling getting to a relative range of their target, deciding on a target (through aggro/threat mechanics), etc. These operate at an individual level; each unit runs these control structures independently. One of those controls is the formation follower behavior, which keeps them trying to work together and in formation. There's plenty of complexity there that had to get handled, but it doesn't have any concept of future planning or any kind of analysis.

A while back (maybe 2 years ago) I worked on a system to control enemy formations, consisting of a set of directives which were selected through a cost function and periodically sampled. It really, really doesn't work. It kind of worked, but then it didn't. If you're wondering why the current scenarios don't have any enemy formations, this is why. Those of you who have played know there is one scenario with enemy commanders, and that they are barely barely barely functional.

So the need for an AI that runs on top of the behaviors is obvious. That's the current project. I'm building an AI Planner that looks at the current state, derives its options from available actions, derives its goals from the objectives (or script), and tries to come up with a sequence of actions to accomplish it. Then, searches over the space of sequences to find the best one.

The low level planner took a couple weeks to get working at a level I'm happy with. I'm now working on integrating the planner into the actual game. As of right now, the planner runs and the plan can be executed, but all it knows about is naive movement. It can move to its goal but basically it just knows how to dumbly right-click and hope for the best.

But it's a start. I built an AI obstacle course. When it can find its way through I'll make a vid.

.... AI is hard!

Monday, July 27, 2015

Earth and Air Elemental Rigs/Skins

Hey hey. I went back and built a new Air Elemental model, then realized I never posted the Earth ele!

Take a look :)

The last one's kinda... big :)

Keep in mind these are differently scaled versions of the elemental skin. Just like with the player's squad members, each unit has a variety of sizing attributes. The various types of elemental have the same parameterization. So yeah, that last one's kinda funny :)

Oh oh, and the Stone and Air bits animate; I didn't record a GIF for you though. Next time.

Saturday, July 18, 2015

Making parameterized ClickOnce installers work

Alright. I spent entirely too long working on this one purpose yesterday. Judging by the state of internet questions on the topic, others have also spent too long working on this one purpose. Since I did end the night with a functioning system, I thought today I would write how I did it.

Two days ago I live streamed development for a short while, and wanted to let people on the stream test the game with me, and give feedback. I've had click-once based installers for years, but I found myself missing a certain feature. I wanted to be able to authenticate users, and be able to selectively enable clients. I wanted to be also able to give out custom URLs to people to download the game from, in a way that modified their installation so that I know which URL the game was installed from. Each installation URL should still self-update normally, however, and I want to be able to get rid of a given URL and authentication easily at a later date.

So this is a story about how to parameterize a click-once installation.

Attempt 1: Use query parameters on the installation URL to provide unique data to each installation URL.

My first idea was to write a script on the build server that generated a unique URL for the installer using a unique identifier placed in the query-string. So instead of installing from World/World.exe, the link would be World/World.exe?id=yourcustomidentifier.

This attempt ultimately failed, but in finding that out I solved other related problems, so here were the steps and their problems and solutions:

  1. Building the unique links turns out to be easy: 
    1. PowerShell scripts can generate Guids by invoking the .NET class libraries as in $authGuid = [guid]::NewGuid().ToString().
    2. Likewise in MSBuild use the following in a PropertyGroup: $([System.Guid]::NewGuid())
  2. Getting the query parameter to be used by ClickOnce is less easy:
    1. Like many aspects of ClickOnce, it has become obvious that it was not meant to be used by build scripts. Passing the query parameters into the installer requires setting a flag in the application manifest; but there is no means to set this flag using the command-line Manifest Generator (mage). Since we don't want a person involved for every run, UI solutions will not work either. This leaves us with editing the manifest xml ourselves.
      1. Specifically, we need to add trustURLParameters="true" to the  xml tag in the root of the manifest.
      2. In PowerShell I did this hacky monstrosity:
        1. (gc <product>.application) -replace '<deployment ','<deployment trustURLParameters="true"' | Out-File -Encoding "UTF8" <product>.application; exit;
        2. Basically, a string replacement, but take care:
          1. Problem 1: My build script was not powershell, but rather a batch file! Running powershell from the batch requires careful escaping, and looks like powershell -Command "{above command with escaped quotes}"
          2. Problem 2: Why the 'exit'? Because powershell was stopping script execution and that seems to fix it.
          3. Problem 3: Don't forget the -Encoding! My manifest got corrupted and unusable without it. I think it had to do with BOM (Byte order marks).
          4. Problem 4: Be VERY careful to do this operation BEFORE you do any signing of the application file, obviously signing has to come last.
      3. Really it's just amazingly painful using mage.exe.
    2. And now the kicker; This doesn't work!. Why not? Because the links I provide are not to the application, but rather to a bootstrapper Setup.exe that ensure prerequisites are installed, such as the .NET Framework. The bootstrapper does not forward query parameters, which makes sense, it's an EXE, very separate from the URL itself.

Attempt 2: Find some other way to parameterize that is readable during the run of the installed application

  1. So query parameters are out. What else can be use? The next approach I tried was to encode the identifier into the filename itself. So now the download link would look like World/World-identifierhere.exe.
    1. This fails for similar reasons as above; This is the filename of the bootstrapper; not the application manifest. ClickOnce provides access to the launch URL in C#, but this does the application URL, not the bootstrapper EXE URL.
  2. Next attempt: The bootstrapper contains in it the URL of the application; maybe we can add a query-string there and the application will receive it?
    1. So now we have to make a custom Setup.exe for every user that embeds their identifier; this is surprisingly not that difficult! The Bootstrapper is built using MSBuild, and customizing the URL to include a new Guid is not hard
    2. But a new problem arises: When I attach a query to the URL, the bootstrapper no longer works automatically: It forwards the user to a webpage to download the application manifest, rather than just installing it! I don't know why! Google didn't help! 
    3. I thought here that I could just make a custom application manifest for every client, but then realized that to maintain automatic updates I would have to forever-after update EVERY single client's installation for every single patch. NO thank you.

Attempt 3 (Success!): Build the user's ID into the username of the URL of the application manifest, when constructing the Bootstrapper EXE

Every attempt at getting data into the application from the bootstrapper failed, EXCEPT adding a username to the URL, which was passed through and available in the C# ApplicationDeployment.CurrentDeployment.ApplicationURI

Caveat implementor: This URI is only available in the first run, from the bootstrapper! You need to save that identifier somewhere in your application or you'll lose it forever!

So to recap my hopefully final solution:
  1. Build the application manifest and installation the same as usual.
  2. Build a unique Bootstrapper EXE for every client authentication token you want to have.
    1. The bootstrapper's ApplicationUrl needs to include the authentication token inside the username section of the URL.
    2. Rename the bootstrapper's exe to include the authentication token, to provide a unique URL to give to the user to install.
    3. When building the bootstrapper, register your authentication with whatever database you have, to be able to track it later.
  3. In the client application, read from ApplicationDeployment.CurrentDeployment.ApplicationURI.UserInfo, and save the results somewhere permanent.
    1. Use the authentication token saved to authenticate and identify.
  4. Later, just delete the custom Setup.EXE when you want to cut off access, and remove the authentication token from your database.
It may not be the prettiest solution, but it works, for now.

Good luck.

Friday, July 17, 2015

Update + LiveStreaming

What's new?

  • I'm testing out live streaming at It's strangely entertaining, though I admit it isn't terribly good for actually getting work done. On the plus side the few guys that chatted with me last night did help me solve a few bugs that were as of yet undiscovered. I don't know how often I'll do this, but I may find some time tonight if not afterwards.
  • I've built a couple new visual effect types, based on the materials system and mesh duplication and offsets. Am using it for some slightly more subtle weapon glows.
  • Caravan, the second tutorial scenario, is in progress; the story bit and tutorial bits are written (but need polish), and the actual scenario part has begun, but only just.
  • I'm working on authenticated identification of installs, so existing installations will break at some point. I'll be able to supply custom links so that I can deprecate links and authentication codes later. 
  • I built some meshes in Blender! Specifically I built a skin for the main human mesh, the elemental default mesh, and specific multimaterial meshes for flame and stone elementals. Eirikr's weapons are getting UV coordinates as well, when I find time.
  • I did a pass over sound effects a few weeks ago; they are better but not thoroughly better.
  • I implemented a means for the server to instruct the client to do a spline-based camera flyby, useful for tutorial and cinematic sections.