Custom Authorization Schemes in .Net Core 3

Recently while working on a .Net Core API project I had to add some authorization features to further protect endpoints based on user-level security. This security scheme was conceptually pretty simple, but a little complicated to implement. In the end I had to implement some custom authorization middleware myself, so I would have just the right level of granularity and control.

The Problem

The project I was working on has some fairly granular and customizable security controls originally implemented in the legacy codebase. This API needed to reimplement the same security controls for parity with the legacy codebase, so that from a user’s standpoint nothing changes at all.

To do this, I wanted to put a top-level auth check on a resource, or endpoint, so the API could reject unauthorized requests right off the bat without even thinking of going any further. A simple want, but the details were a little hairier.

In this system, each user is assigned a security group. These security groups determine the accessibility of roughly 800 controls, actions, data points, and more. This translates to roughly 800 VMAD-style permission combinations. Further, security groups were customizable per-installation. So an ADMIN at one site might be a SYSADMIN at anotheror, even if the names are the same, the permissions for the ADMIN groups at each site might be just slightly different.

This immediately ruled out any baked-in authorization feature. I couldn’t use role-based and policy-based authorization, because these rely on roles or policies to be named in a standard fashion, and for that I had zero guarantee.

Claims-based authorization was likely out. Stuffing the required data into claims data itself didn’t appeal to me. Neither did having to write out the requirements for every possible VMAD permission needed.

Fortunately, there was one constant across all this: because of the way the permission data was stored, the index of the permission would never change. So the ability to “view(44)” meant the same no matter what configurations you made.

So I decided my end goal would be simple: slap a custom authorize attribute on the endpoints that need one, and then move on. It would look like this1:

[CanView(44)]

The Solution

In the end I needed to implement my own IAuthorizationProvider, along with custom attributes and an in-memory cache storing configured security information.

I’ll show some examples for a theoretical “CanView” requirement, assuming we’re implementing a classic VMAD permission scheme with the structure I outlined above.2

Defining an Authorize Attribute

We’ll need to start with the authorization attribute first. This includes the IAuthorizationRequirement as well as a new attribute implementation.

public class CanViewRequirement : IAuthorizationRequirement
{
  public int Index { get; }

  public CanViewRequirement(int index)
  {
    Index = index;
  }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
internal class CanViewAttribute : AuthorizeAttribute
{
  const string POLICY_PREFIX = "CanView";
  
  public int Index
  {
    get
    {
      if (int.TryParse(Policy.Substring(POLICY_PREFIX.Length), out var index))
      {
        return index;
      }
      return default;
    }
    set
    {
      Policy = $"{POLICY_PREFIX}{value}";
    }
  }

  public CanViewAttribute(int index)
  {
    Index = index;
  }
}

internal class CanViewAuthorizationHandler : AuthorizationHandler<CanViewRequirement>
{
  private readonly IServiceProvider Services;

  public CanViewAuthorizationHandler(IServiceProvider services)
  {
    Services = services;
  }

  protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, CanViewRequirement requirement)
  {
    if (!context.User.Identity.IsAuthenticated)
    {
      return;
    }

    SecurityGroup security;
    using (var scope = Services.CreateScope())
    {
      var securityService = scope.ServiceProvider.GetRequiredService<MySecurityGroupService>();
      security = await securityService.GetSecurityGroupInfoAsync(context.User).ConfigureAwait(false);
    }

    if (security.CanView(requirement.Index))
    {
      context.Succeed(requirement);
    }
    else
    {
      // reject and log the request accordingly
    }

    return;
  }
}

Okay, there’s a bit going on here. First, we create a class that implements the IAuthorizationRequirement interface. The CanViewRequirement simply holds the index of the permission in our data, and implements that interface so we can use it for our AuthorizationHandler down below in HandleRequirementsAsync.

In HandleRequirementsAsync, we check an in-memory cache holding the security groups to see if the calling user’s security group does indeed have the requested permission. If so, context.Succeed(requirement) allows the request throughotherwise, we log the failed request and it’s rejected by default.

The CanViewAttribute class simply lets me set all this up as defined above, by using an attribute on a method or endpoint like this: [CanView({index})]

A note about attributes

In C# attributes can be used for metadata and code extensions. They go above your method declaration and provide helpful documentation, often extending behavior in a standardized way. It’s helpful to think of attributes as wrappers around methods, especially in this case. If you look at a method like this:

[CanView(44)]
public async Task<IActionResult> GetFooAsync()
{
  // do things
  return Ok();
}

And then unbox it, it might look something like this (pseudocode):

public async Task<IActionResult> CanGetFooAsync(int index, GetFooAsync getMethod)
{
  if (authService.IsAllowed(CanView, index))
  {
    return await getMethod;
  }
  return Unauthorized();
}

public async Task<IActionResult> GetFooAsync() 
{ 
  // do things 
  return Ok(); 
}

The Authorization Provider

All the above is well and good, but none of it does anything on its own. We have to set up a policy provider for the right code to get called when the attribute is reached. For this, we need to implement IAuthorizationPolicyProvider:

internal class VmadPolicyProvider : IAuthorizationPolicyProvider
{
  const string POLICY_PREFIX_VIEW = "CanView";
  public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }

  public VmadPolicyProvider(IOptions<AuthorizationOptions> options)
  {
    FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
  }

  public Task<AuthorizationPolicy> GetDefaultPolicyAsync() =>
    FallbackPolicyProvider.GetDefaultPolicyAsync();

  public Task<AuthorizationPolicy> GetFallbackPolicyAsync() => 
    FallbackPolicyProvider.GetFallbackPolicyAsync();

  public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
  {
    if (policyName.StartsWith(POLICY_PREFIX_VIEW, StringComparison.OrdinalIgnoreCase) &&
        int.TryParse(policyName.Substring(POLICY_PREFIX_VIEW.Length), out var index))
    {
      var policy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme);
      policy.AddRequirements(new CanViewRequirement(index));
      return Task.FromResult(policy.Build());
    }

    return FallbackPolicyProvider.GetPolicyAsync(policyName);
  }
}

All this is a semi-fancy way to generate the policies we need on an as-needed basis. Instead of hardcoding every CanViewRequirement possibility from 1 to 800, these are built for us by the attributes and requirements as we go. The interface also specifies that we add a default and fallback policy provider, from which I simply grabbed the defaults from the default, created in the class’s constructor.3

This is the ultimate goal of the code: do the work once, and use it everywhere. If we wanted to extend or refine details behind our CanView security, that is only done in one place.

Plugging it All In

Since this is .Net Core 3, we’re relying on dependency injection to keep things afloat. So we need to add services for everything we’re using here:

services.AddSingleton<IAuthorizationHandler, CanViewAuthorizationHandler>();
services.AddSingleton<IAuthorizationPolicyProvider, VmadPolicyProvider>();
services.AddAuthorization();

This tells the software that we’re using some custom authorization handlers and policy providers and points it to their definitions.

After this, using custom authorization attributes for our endpoints is a breeze. With just one line, we can narrow access to a single flag in the database out of thousands. Extending this would likewise be a breeze. Definitely easier than defining every single one manually, or crossing our fingers and hoping a security group name doesn’t change!

Wrapping Up

This may or may not be the best way to solve this particular problem. But we analyzed the trade-offs and made a calculated decision. If you were to go through and comment the code above with the intentions behind it all, I personally believe it would be easier for a new developer to hop on and get going than the alternatives. While complexity has to go somewhere, it’s better for these types of abstractions to have a gentle curve. Let someone care about the details only if they need to.

From WordPress to Pelican and Back to WordPress

This blog started out built on WordPress. For some reasons that made sense to me at the time, last year I moved everything over to a platform called Pelican.

Pelican is a static site generator that takes plain text input and converts it to web pages.  This is great for a variety of reasons, especially if you like writing in Markdown or want to keep your blog in some kind of source control.

Both of those sounded pretty neat to me and I got tired of WordPress, so I made the jump. I downloaded my WordPress installation, ran a script to convert its posts to Markdown, then tinkered with a few themes and plugins until I had something that looked fairly close to the original.

For a time, things were good. I enjoyed writing in Markdown. It took me back to the “old days” of plain text, scratching out the words without care for how they might appear. There was a kind of magic to the process. Writing, then waiting, then finally seeing the article published. All it took was Notepad++ and a command line and baby, I had a blog going.

Then I took a break. Life got in the way. I finally returned to add new posts, but when it came time to publish I actually forgot for a moment what the damn tool was even called. Then I forgot the command line options. Then I forgot where the output went. Most recently, I tried linking one article to another and this caused the generator to throw new errors. I googled around for about ten minutes before thinking, “I don’t have time for this.”

So instead of fixing that problem I spent an evening restoring WordPress. If you’re curious, here’s how to do it like I did:

  • Create a brand new WordPress installation
  • Google “export pelican to wordpress”, then wonder if you have your old backup still
  • Find the backup *.tar.gz file and poke around its contents
  • Upload everything over FTP
  • Play Master of Orion while you wait for 3,500+ files to upload
  • Update wp-config to point to the new database
  • Drop all the tables and recreate them with the old WordPress DB table contents
  • Find the functions.php file for your theme and add a few lines of code to programmatically update all mentions of the old URL to the new URL
  • Refresh the login page about 5 times
  • Log in and update WordPress
  • Update hyperlinks in posts
  • Copy-paste the Pelican posts into WordPress posts

And voila! It’s like I never left WordPress! Except for all the times I linked to the old old blog, then destroyed them by moving to Pelican, and then destroyed those links by moving again over here. One day I’ll write a redirect so folks following those old links will come here, instead. Another day.

Mang 1.0 is Released

As part of my ongoing work with SCOREDIT, I’ve been working on porting some old code to a new utility for use in my newer project as well as a few other things I’ve got going on. To that end, I released Mang (Markov Name Generator), a tool for generating names and words.

Sigh… A procrastinator’s work is never done…

Mang uses Markov chains to generate output that is similar to, but not the same as, a given set of inputs. This means if you feed it a dictionary of English words, it will output words that look like English but are just a little bit off. This is great for building up conlangs, creating NPC names for your tabletop games, etc.

The library comes “batteries included,” meaning it already has a small collection of names you can use for name generation. The readme has more details on this. You can also browse the source to see what all is available.

I’ve had the old Mang lying around for a long time gathering dust. Built with WPF, it was serviceable and the output was okay. But I wanted to extract the Markov and name generation code and make it into something more portable. I was also frequently unhappy with the output, hitting the refresh button forever until I found something inspiring.

The new Mang has a few improvements to word generation to ensure no gibberish is put out. The library itself is tiny – just a few files. And its interface is small and foolproof.

To prove all these things to myself I plugged it into SCOREDIT today and got to generating:

Mang used with SCOREDIT to generate words

As you can see, it’s not all perfect, but there’s a few good ones in there to serve as starting points. In the future I plan to extend the generation capabilities to come up with more “realistic” output, but that’s another blog post.

Head on over to the repo to check it out!

SCRL: Week 06

After motivation petered off, it was easy to rationalize not doing anything on this project. The excuses rolled in: what’s the point, it will never make money; no one will play it; making games fun is hard. Etc.

Times like these, I remind myself when motivation wanes, it’s usually because of a good reason. I’d hit a wall, and it had nothing to do with the excuses I was making. After some thought and false starts, I finally found out what was happening: working on SCRL was no longer fun.

Above all else this project is supposed to be fun for me. It’s a side project for a game that likely no one will ever play but me. So why not make it fun just for me? And why not work on the things that are fun and interesting to me? With that in mind, I thought about what I dreaded doing the most for the project, then thought of a way to make it fun for myself to do it.

Enter… SCOREDIT! (I am not good at naming things.)

SCOREDIT is a GUI application to add and edit game data, from NPCs to game regions (dungeons and towns) to treasure drops. A few semi-difficult decisions were made in the process of setting this up:

  • The GUI will be written in WPF.
  • The CSV files are getting replaced with a SQLite database.

I went with WPF because I know it and can move relatively quickly with it. SQLite (along with Dapper) will make it so I worry less about how I’m serializing/deserializing data and more about the data itself. Plus, most of the data does require some kind of relational integrity, such as monsters referencing aspects, treasure classes, and other monsters. Using a proper mini-database will make it harder for me to shoot myself in the foot.

a screenshot of SCOREDIT

Nothing pretty, but that’s not the goal here. So far it’s purely UI. I’m using this as a kind of mockup phase, where as I think of attributes or pieces of data to add, I add the boxes for them. Then, once I’m done, I’ll write up the database to back it. After that, I’ll rewire SCORLIB to talk to the database instead of the CSV files.

So far, for the screen above what I like the most is the auto-generation of stats. Of course, this could be done at runtime, but I like to tweak things beforehand and I don’t want to rely too much on in-game random generation for things like this. The plan is to choose a monster type — is it a tank? magic user? a speed demon? — and adjust its stat distribution accordingly. When I was still staring at the CSV files, manually choosing and writing out stats was one of the things I dreaded most.

This UI is bound to change quite a bit before it’s finished.

SCRL: Week 05

2020-03-28

Wow. Already been a month since I started working on this project. Kind of crazy how quickly that time just… disappeared.

Anyway, today I started working on some random generation utilities. Not a lot of this was new work — I’ve already done 90% of that job in SCORLIB. My factories are serving me well, so far. But, in order to actually test and make sure the random generation is producing sensible results — for some definition of sensible, I guess — I needed a way to hammer generation without loading up game levels.

Enter SCORLIB CMD:

cmd line output

(Naming things is hard.)

Essentially, I wanted a command line utility I could use to generate the things I tell it to generate. I want to be able to inspect the output of this generation in a game-agnostic way just to see how things work and make sense, because this is how I think about things. This is not a way to test game balance (though in the future it might get some features like that), nor to test anything specifically game related at all.

Say I want to see what treasure a gordix1 drops:

command line output

Or I want to see a full list of possible drops:

command line output

This is a very simply use case; the screenshots are just illustrative. Because this game is going to be fairly loot-driven, I need to iron out how “good” the loot drops themselves feel. I think this is the first step to making sure it’s all right. Once I have a decent amount of Things for monsters to drop, I can throw them into the game and then run around and test there. …after I implement the inventory system…

2020-03-29

Cleaned up SCORLIB a little and had it load some item properties that weren’t being read from data files. Then I started work on a proper Inventory screen. Not much to show yet – still rough work, and I think I need to step away from the code and use a pen and paper to sketch possible layouts before I do any more work.

2020-03-30

I spent 2 hours modding Fallout 4 today. So, in other words, I was not productive at all.

2020-04-01

Brain is feeling fried this evening. Tinkered with the Inventory screen some more. Decided to probably start off from something like the ADOM inventory screen, more or less, and go from there. Figured they got something good going. I got just a little bit done as far as drawing everything up properly – not enough to show or feel productive about.

SCRL: Weeks 03 & 04

2020-03-15

Spent some time writing up another blog post on how I want Aspects and similarities to work. That post will probably go up later this week. After writing, I went and sketched up some code to calculate the “similarity index” between two monsters, and made a little command line application that I could use to test SCORLIB components and run through the code without having to run the game and test there. This made it very easy to compare a few different approaches to calculating this index, which I go over in that blog post.

2020-03-19

It’s been a busy week and I haven’t had any time to work on this project, except for some thinking here and there. The last time I started working on this I started to implement loading game data from SCORLIB. This involved parsing flat files into game objects and setting up factories that I would use to retrieve new objects / mobs / items / etc. as needed. This all works really well – I even have loot generation going, very similar to Diablo’s mostly because I straight up stole the Diablo II file format and style of loot / mob generation.

However, I came across a snag: I want SCORLIB to be as “pure” as possible. Meaning, I don’t want to sully the library with implementation details for whatever game “front-end” is using it. So, even though this game is a roguelike and uses ASCII graphics, I still might want to use SCORLIB with another project later. The problem here is I still need somewhere to store graphics-related metadata so my factories can function without huge gobs of code gluing them together and slapping graphics on things. I think what I’ll end up doing is adding a second set of metadata files to SCORLIB in their own folder / namespace and joining the graphics data (colors, the character glyphs representing entities, etc.) with game data. This way these graphics settings are still separate, but also still loaded from disk instead of hard coded.

2020-03-24

Decided to combine two weeks of dev journaling because… well, I didn’t do much last week.

Today I got a good portion of the work done for my monster factory to a) load in all the game data from SCORLIB from disk and b) load in all Monogame-specific data, also from disk. So at “design time” in my tab-delimited text file I can set all required display settings for my in-game objects, divorced from the logic behind it all (stats and other rules). If my parser somehow fails to conver the string to a proper color / glyph representation (like if I fat-finger while typing) then it gracefully falls back to hot-pink foreground, blue background, and ‘?’ as a glyph.

Because all these objects are relatively small in the grand scheme of things, I just hoover everything up into memory when the game starts, so when I need a new instance of something I request it from the factory. Like so many decisions before this, if it does become a problem, I will revisit it — but I want to move forward adding things to the game without spending too much time right now on what may be premature optimization.

The factory stuff isn’t done, but the loading from disk is 90% done. Probably tomorrow I’ll finish the monster factory and start generating monsters randomly for real!

2020-03-25

It is done!

Monsters, both their stats and display info, are drawn from disk into little factories where they can get pumped out onto maps at will. Because of the number of properties and objects that live inside the Monster class, instead of trying to get clever with reflection or MemberwiseClone or any number of things, I just sucked it up and wrote out all the assignments needed for cloning operations. It took two excruciatingly long minutes to do, but in the end it was far easier to write, test, and look at than any other code would have been — and it runs faster, too. Imagine that.

Next it’s time to extend the MapFactory to randomly assign the next map type, then assign that map a Deity type. I think I want the map factory methods to populate the maps with their creatures, as well. I’m not sure what’s next, but there’s a few options:

  • Spawning boss monsters
  • Spawning monsters in groups based on their monstats metadata
  • Implementing treasure classes for loot

Week(s) In Review

Can’t always have productive weeks. When your day job is also programming, sometimes it’s hard to motivate yourself to do more of the same during your free time. In any case, I got a few key things done these past couple weeks, and now things are starting to get “hard”. Designing and implementing systems is easy, but making them playable and fun? That’s the challenge.

SCRL: Aspects and Deities

One of the core focuses of this game lies on the concepts of Aspects and Deities. These are two separate-but-related concepts that will affect nearly every other aspect of the game: level generation, monster aggression, loot generation, and probably more. This post covers at a high level how each of these might work, and then will dive into some implementation details on how monster aggression is calculated using a “Similarity Index.”

The Goal

Every living thing in the game worships or is somehow bound to a Deity. Every Deity has three Aspects – something the Deity is, has, or does; something it embodies or personifies; a quality, statement, or goal. In short, an Aspect can sort of be anything you might use to describe that Diety. The followers of these Deities will most often carry one or more shared Aspects, but it is not required for every follower to share every Aspect. In addition, an entity can potentially embody many Aspects, instead of the limited number that each Deity personifies.

When the player moves through the Chapel, each “floor” generated will be themed around one (and sometimes more) Deities. Map generation will be tied to the Aspects embodied by this Deity, and typically there will be an altar of some sort where the player can perform certain actions: pray, offer, desecrate, etc. Performing these may dramatically alter that player’s standing with the given Deity.

The creatures that appear on any given floor will either be followers of that floor’s Deity, or share enough Aspects to be allowed nearby. How many Aspects are shared, and how close the shared Aspects are to each other in some given quality (Healing and Peace, for example, are friendly, but not Healing and War) come together to determine the aggressiveness of an entity toward another entity. Most of the time, this is just the monsters toward the player. Sometimes, the player will stumble upon a floor with two altars, and the monsters spawned may be hostile toward each other.

A stretch goal of mine is to also include Aspects and Deities in item generation. More than affecting which items spawn, certain items may only be usable if you share an Aspect; some rare items may only be worn or used if you worship the Deity that spawned the item. This is low on the list, and I’m not sure exactly how fun it would even be if it did work this way. Something to consider and test later.

How it Works, Probably

Below is still mostly in flux, save for how the game data is stored and modified on disk – I’m pretty set on that.

Game Data

Game data is stored in tab-delimited flat files. A header row denotes the value below. This makes it easy to open the files in Excel or some other spreadshett, add a bunch of stuff, and get going. Since the game is text-based, this is really all I need. Game data is pretty simple here, anyway:

As you can probably guess, the Deity “table” three columns that act as foreign keys to the Aspect “table”. Factories in SCORLIB are written to grab entities by ID, among other properties, making it pretty simple to just grab anything without worrying about whatever its name or other properties might be. For the example above, I used an old program of mine I called “MANG” to generate some random names.

I decided to limit myself to 64 Aspects at most, the labels of which are for now subject to change. I haven’t decided how many Deities I’m going to add. Probably no more than 16, or maybe 32.

These numbers weren’t picked just because they’re fun programmer numbers. I have a reason for the things I do, sometimes!

In the Game

The end goal for all of this is to calculate some sort of “similarity index” between two given monsters, and set their levels of aggression accordingly. This similarity index is calculated based on the Aspects each monster has in common, with 0.00 being completely hostile, and 1.00 being completely friendly.

The reason the upper limit of the Aspect count is 64 is because I’ll be using an enum, generated at runtime from the game data, whose values are calculated with bitwise operators – 1, bit shifted to the left by the ID value of the Aspect. So, 1 << 1, then 1 << 2, etc.

Each monster will contain a bitmask (which is each Aspect enum value compared with a bitwise OR) representing its Aspect flags, and when it sees a new monster, will calculate the similar index with that monster and adjust aggression accordingly.

Why use bitmasks? Well, if a monster can have at least three, but possibly more Aspects, without bitmasks I would have to implement each manually, or manage something like a List<> or array of Aspect flags. Instead I’m storing a single item with possibly multiple values inside it, so I could have a crazy circumstance like a monster with 50 Aspects but that list would still take no more space than a long.

In the end the Similarity Index calculation will really be very simple. Monster A has four Aspects and Monster B has two. They share exactly one Aspect. So A->B is .25, and B->A is .5, making Monster B neutral and Monster A aggressive. When struck, Monster B will fight back, but it will not seek out a fight, unlike Monster A. Once struck by another entity, this similarity index immediately drops to 0 (possibly only for a short time).

The lower this similarity index, the more hostile an entity is toward another. If A->B is .25, and A->Player is .33, then Monster A will target Monster B before the Player. But if Player attacks Monster A while those two are fighting, then Monster A changes its course.

Also, a monster’s Wisdom will affect how it prioritizes in scenarios where multiple other entities are attacking it at the same time. A low Wisdom means the monster will continue to target its most recent attacker, no matter what. But a high Wisdom will make the monster target the weakest enemy in its list of targets and strategize to eliminate that one first.

Implementation

The Code

/// <summary>
/// Calculates the Similarity Index to determine how aggressive Actor1 should be toward Actor2.
/// </summary>
/// <param name="actor1">The source IActor</param>
/// <param name="actor2">The target IActor</param>
/// <returns>A percentage value representing how similar actor2 is to actor1.</returns>
public static double SimilarityIndex(IActor actor1, IActor actor2)
{
  var firstAspect = (Aspect.aspect1 | Aspect.aspect2 | Aspect.aspect3);
  var secondAspect = (Aspect.aspect1 | Aspect.aspect4 | Aspect.aspect5 | Aspect.aspect6);

  var aspectList = GetSetFlags((long)firstAspect);
  var aspectCount = GetFlagCount((long)firstAspect);

  var matchCount = 0;
  foreach (var aspect in aspectList)
  {
    if (secondAspect.HasFlag((Aspect)aspect))
    {
      matchCount++;
    }
  }

  return (double)matchCount / aspectCount;
}

/// <summary>
/// Counts how many flags are set for the given bitmasked value passed in.
/// </summary>
/// <param name="flags"></param>
/// <returns>A count of enabled flags in the bitmask</returns>
private static int GetFlagCount(long flags)
{
  int count = 0;
  while (flags != 0)
  {
    flags &= (flags - 1);
    count++;
  }
  return count;
}

/// <summary>
/// Gets a list of bitmask flags that have been set for the value passed int.
/// </summary>
/// <param name="flags"></param>
/// <returns>An IEnumberable<long> of the enabled flags</long></returns>
private static IEnumerable<long> GetSetFlags(long flags)
{
  while (flags != 0)
  {
    flags &= (flags - 1);
    yield return flags;
  }
}

Here we have three methods: the “main” method, used to calculate the Similarity Index between two IActor implementations. For this test I ignored those and just made my own sets of Aspects to test against.

I get a list of enabled flags and the flag count, and I check the enabled flags against the flags for the other IActor, and divide the flags in common against the flag count. Very simple. I could have used only one method for getting flags, and done the adding in the calling method to get the flag count, but I like having two methods with distinct purposes, even though they’re very similar, in case later I need to do only one or the other from elsewhere.

Initially I used LINQ to get the set flags, then in my testing watched my memory usage skyrocket when the list grew large. Partially because the LINQ had to sort through the entire Aspects enum to get the ones that matched, and partially because I think LINQ itself has some non-negligible overhead. The same thing happened before I added the GetFlagCount method – the divisor was initially aspectList.Count(), and that also caused a non-trivial bump in memory usage.

The above approach, in my testing, ended up having near-zero memory overhead, according to my completely unscientific and non-rigorous calculations. By that, I mean I just watched the memory usage bar in Visual Studio as I ran the method. The application went from using 7MB to… 7MB. No change. That’s as much detail as I feel like going into this for now.

This approach also lets me keep my foreign key relationship between Deity data and Aspect data — the underlying value for the Aspect is 1 << {AspectId}, so I get my type safety and some amount of relational integrity.

Now, all this covers why I’m using a bitmask for Aspect flags (at least I hope that’s clear). If you’re curious on how exactly these bitwise operators work, here is a good page describing them in detail.

The Rest

I haven’t made it to the point where any of this affects monster aggression yet. I’ll most likely come back and update this post, or add a new one with the details at that time. For now, it’s enough that I have these details ironed out and I can move onto the actual hard work: creating game data to use in the game. These Aspects aren’t gonna describe themselves.

SCRL: Week 02

2020-03-09

Spent a little time changing the dungeon palette to make it more distinct from UI elements. I’m using Solarized colors for this because I like Solarized and it’s easy on the eyes. Also made it so the starting “Big Room” isn’t pre-lit and always lit, so I can actually test FOV / lighting properly.

Since it’s lunch time, I moved fast and not very carefully… and added pathfinding not-so-successfully:

All the goblins move in the direction they last saw the player, indefinitely, and will attack each other if they get too close. While this is kind of hilarious to watch, it isn’t really what I wanted to do, so I’ll have to just mark this down as a fun detour and return to make sure they a) actually follow the player and b) don’t attack other monsters if those monsters are “friendly”. (For now, all monsters will be friendly with each other.)

(Later…) I removed all but one monster from the map and set a breakpoint to inspect the values of the Path enumerable, as well as the “ToDirection” function that converted an x,y pair to a compass direction. After a little bit of fiddling, I realized the problem was me (again). I was passing in the next step coordinates of the path, where this function expected the delta of current position plus new position. Afterward, with pathing working, I made it so the monster only follows the player’s current position until the player is out of sight. The monster now follows to the player’s last known position, and waits there until the monster sees the player again.

screenshot of game

To cap the night I decided to finish changing the game’s color palette.

screenshot of game

I think now that I have the bare bones down, it’s time to change direction again. This game is supposed to work with a combination of prefabs and procedural map generation. To start with, I’ll work on plain old static maps loaded from external data.

2020-03-10

It was suspiciously easy to implement prebuilt maps.

I downloaded REXPaint, drew some boxes, and saved the *.xp file. SadConsole has a pretty handy built-in REXPaint reader that parses the native REXPaint format, and even lets you iterate through map layers in the .xp file for reasons. Mine was a simple file, no layers, no special coloring, just floors and walls.

After drawing the file I built a StaticMapLoader class. This has a static “LoadMap” method that loads a map file based on filename, parses its contents, and returns a valid game map from the contents. Right now the parsing is dead simple: map a REXPaint tile to its tile blueprint cousin in the map generation code, and bam, we’ve got a walkable map. Player is placed based on the map’s WalkabilityView, monsters are similarly placed, and things just work!

screenshot of game

It isn’t quite perfect. Monsters, after disappearing from my FOV, no longer reappear — though, they’re still “on” the map and will still follow, attack, and die. Also, I forgot to remove monsters from the Scheduling System when they die, so that throws a null reference exception. So got a few bugs to fix.

And now the above bugs are fixed… Next I think I’ll work on the tile blueprint stuff so it can read more tile types from REXPaint.

So I:

  • drew a full starting map in REXPaint
  • added mapped char values to Tile Blueprints
  • added Tile Blueprints to represent map objects as drawn, with my own colors

Which resulted in:

screenshot of game

Things are looking all right. Not sure I’m a huge fan of the way I’m doing these tile blueprints – but they work for now. It’s a fairly standard factory pattern that, when you call it with a “tile name”, returns a new instance of that type of tile object. I can’t say exactly what it is I dislike about doing it this way, except that I have to type out every type of tile I ever want to use (just the once, though, which is fine I guess) before I get to use it.

2020-03-12

Started working on a “message history” window to view some messages that are older and no longer displayed on the current message window, then I decided it wasn’t worth spending time on yet and moved on. I am, however, storing all messages in a list (for now) with the plan that, on death, you can go through and view it all, if you wanted.

Next I started on a MapFactory that I plan on using to transition between maps. This will have a handful of basic “GetMap” style methods, where you give a maptype and some settings and get a map in return. I also need to extend the basic map class with a few properties for starting position and entrance/exit. Then map generation itself will need to be updated to account for ways in and out.

If I plan on letting players go back and forth between maps (probably not, or at least not more than once in any direction), then there needs to be a way not only to clear entities from the map when transitioning, but to restore them when going back. Gonna think on that one, but my gut says to not do it. Progress should be forward-only, with “backward” being a return to “town”.

Anyway, I don’t think I’ll get too much done tonight. Work has been a little more draining than usual, and my sleep has not been very good lately, so I’m moving slowly tonight.

2020-03-13

I decided to not pass in strings for the map factory. Instead, there’s now a MapType enum, with the first two slots reserved for STATIC and PREFAB. I like the idea of having a sort of strongly typed set of map possibilities. Plus, it’s easier this way to randomly select a map generation type by picking a random integer within the range of enum types.

In putting together the map factory and the other pieces to allow for smooth map transitions, I’ve realized how scattered some of the map update / drawing code has become – to center the viewport on the player, for instance, can fail thanks to bad order of operations. Or, creating the ScrollingConsole that acts as a renderer for the map itself can fail if I try to instantiate it before the map itself is created. These are small things and very easily fixed, but it’s still a distraction and again I find myself looking at this late at night after a long day and don’t have the energy to do it. Oh, well. That’s what weekends are for, right?

What else am I going to do with that coronavirus out there? 🙂

2020-03-14

Mostly have map transitions working well. A few hitches here and there and there is definitely some more cleaning to do. I’m in phase 1 of this, which is “get it working.” Soon, I’ll be on to phase 2: “make it right.” For now, I just want to be able to hop from map to map without too much hassle.

I redid the main map a little bit to add some hard-coded stairs down and also some light sources. Then I wrote the code for light source entities, made them cast their light, etc., but there’s currently a bug where the player can sometimes not see inside the light source radius of these entities if his own FOV so wills it. Going to file that one under “fix me later”. For now, I kind of like how it is, and will spend my time further refining the flow of map-to-map travel.

Here’s the starting map with its torches:

screenshot of game

(Later) I added some TileFlags (which is an enum of bitshifted ints) to allow for StairsUp and StairsDown — later, maybe I will split these flags based on the flag’s purpose, but for now there aren’t many and it’s Good Enough — so when the factory creates stairs I don’t need to do anything else for the map to know where they are. When descending, the player will start on the stairs that lead back up, and when ascending, the player will just pop back to “town”. For now the stairs and placed randomly on a walkable position. When you stand on stairs and ask to go down, you’re prompted so the game is sure you didn’t hit that key by accident. If you say yes, you descend.

For funsies, I made it so I can tap M to jump to the next map automatically. Here’s a gif of me holding down the M key.

screenshot of game

I only have three “random” map generators right now: the Big Room Generator, which just makes a big room; the Cellular Automata Generator; and the Random Walk Generator. I think I’ll work on a Binary Space Partition generator next, or maybe just a regular old random room / hall placer.

Week in Review

Feels like I got an okay amount done this week. Pathfinding, dead simple AI, map transitions, static map loading… Not too shabby!

In the coming week I plan to work more on game library stuff. Right now my single monster is a hardcoded entity. I want to take advantage of my SCORLIB library and external data, and generate monsters using a Monster Factory. At first it will just be a small range of monsters, but the eventual plan is to generate specific types of monsters on specific types of “dungeon floors,” where each floor will be devoted to a deity, and the monsters there that deity’s followers. So, with the aggression system, you may end up on a floor of totally peaceful creatures.

All the “hard work” of serialization and deserialization has already been done, so right now it’s a matter of a) actually creating the data and b) plugging that data into the game itself to plop monsters down in the world. Next week.

SCRL: Week 01

2020-03-02

Spent too long rewriting FOV code because monsters were being drawn even outside the player’s FOV, only to realize my calls to get/set “isvisible” were setting the wrong property. Rewrote everything for nothing. Instead, called Animation.IsVisible, and they turned invisible as expected.

So I reverted back to old FOV code and set the appropriate flags there. Tomorrow: – Rearrange UI consoles – add “DialogueWindow” to handle dialogue and message pop ups – add “InventoryWindow” to show inventory

2020-03-03

No need to implement special Dialogue windows. SadConsole already implements Message and Prompt windows. Message windows allow you to show a simple message window with text and an OK button, while Prompts are yes/no dialogues with Action as a result callback.

Instead I’m going to focus on the UI a little bit. I want to make the MessageLog a little more readable and add a hotbar / belt style window which the user can click for useful actions like drinking a potion.

I shrunk the Adventure window and centered it, along with the MessageLog. On the left side of the screen is the Belt, and the right has Stats. For now, this layout will be good enough. I’m not going to work on an Inventory window right now, since there are no real items to speak of. This UI will suffice. It’s time to start working on:

  • spawning monsters
  • log messages when a monster is seen, how aggressive it looks, etc. – partially done (need aggressive check)
  • add monster to Stat window with neutrality ([n] for neutral, [a] for aggressive, etc.) and health
  • make monsters aggressive toward player attack player
  • make monsters aggressive toward each other attack each other
  • make neutral monsters do nothing

Procrastinated by setting up blog. Procrastinated a bit more by setting up a git repo for the project. For now it’s private.

Progress so far:

screenshot of game

2020-03-04

Decided to bring in a fork of SCORLIB from the old project. A lot of work was done there for the little details that I will eventually be using, mostly in the ActorInterfaces namespace. I’ll probably drop the ‘xxClasses’ folders in favor of implementing the interfaces in the game itself, rather than the library. I just didn’t want to rewrite all this stuff.

Got caught tinkering with MessageLogWindow because I didn’t like how some code could cause null reference exceptions if a monster spawn in the wrong spot at the wrong time — order of operations on generating map & FOV then logging monster appearances. While tinkering, noticed SCLR uses ~165MB memory almost right off the bat. Just for fun I looked at the old scrl and saw it used around ~70mb. A memory snapshot shows ~30k SadConsole.Cell objects and ~30k EventHandlers — an event handler for every cell? Is this a SadConsole 8 thing, a GoRogue thing, or did I do this by accident?

Looking further into the dump it’s partially GoRogue, partially me. In this fork of the GoRogue.SadConsole helpers library, the “Tile” class instantiates an event handler on every single tile. With a 100×100 map, this adds up. There’s a few other issues in here too, but I’ve just decided to leave it. Focus on the game first and come back to the memory later to clean things up.

Couldn’t leave the message log how it was, so I move the queue away from the UI so it’s a static queue with a set size within the library. the ui just draws the messages and that’s it. Dropped 10mb of memory by dumping the scrollbar? Interesting.

Moved FOV calculation out of base LivingCharacter into the Actors descending from it. So Player does Player’s FOV, Monster does Monter’s FOV, and no more checks for “if ControlledGameObject” or anything like that.

Monsters will log when they first spot the player, but that’s it right now. I won’t be doing the aggression-check stuff until later. I can spend time doing basic “move in player direction and bump him” attacks, or I can spend time on a command / scheduling system. I think I’ll do the latter, but dunno if I want to do that today or later.

2020-03-05

Debating the merits of using GoRogue’s Actions vs. building out / rebuilding my own command and scheduling system. GoRogue’s feels a little overengineered for my needs and I feel that if I try to conform my own work around it, I’ll end up fighting it rather than being productive.

On second thought, I think I will try the GoRogue way of things. It has many moving parts, but allows for more flexibility for each entity to manage its own actions, rather than a central processor processing actions for everyone. We’ll see how that goes.

(later) Turns out that was easier than I thought. Monsters just sit around and wait to die, but combat technically “works”. Player can hit, miss, etc., based on his and the monster’s stats. Very basic, but it gets the job done for now. When the monster dies, it’s removed from the map, and the player can move into that spot.

Next:

  • Make the monster drop some gold or something
  • Make the player pick up that gold when he walks over it
  • Make monsters who have sighted the player move toward him to attack

Later:

  • Add / update a scheduling system so monsters and players move at their own speeds, and so that no one moves if there’s no player action taken

Right now:

  • Add a small display to show in the UI the monsters on-screen with a health bar

screenshot of game

2020-03-06

In true Me Fashion, dropped the last thing I was doing – not going to display monster health on the sidebar for now. Just went ahead with dropping items when monsters die. This involved:

  • Adding ItemBase and ConsumableBase
  • Adding an Inventory with a limited size and stackable consumables
  • Adding a Gold class – for now inherits from ItemBase, as it’s “outside” the Inventory, but I might change later and make gold a Consumable inside the inventory so it, too, takes up space. This feels… draconian.

Now, monsters drop gold on their deaths (that’s it right now). When a player tries to walk into gold, he picks it up, but doesn’t move there.

I think how this will work in the future is a player can move onto the gold tile and auto pickup, but items must be picked up manually. I want multiple items to drop on one tile, and when the player tries to pick up, a dialog pops up showing item details and the inventory, and the player picks which ones to get.

As a side note, I need to be more disciplined on my commits, and commit when something is done and working instead of letting it all build up over the day…

screenshot of git changelog

2020-03-07

The ActionProcessor stuff from GoRogue wasn’t working out for me. When it came time to implement an actual scheduling system on top of it, I struggled with conforming my own ideas to the action stack concept — instead, I went with a Scheduling System / Command System similar to my old project, where the Schedule is a sorted dictionary of times and ISchedulable entities. The game loops through the schedule and executes actions for each entity at a given point in the schedule, waiting for input when it’s the player’s turn.

This way, a monster or NPC can have a faster/slower speed than the player and thus act more often or less often, depending. Not going to be usable or useful for a while, but it’s there for me.

I also made it so you now auto-pickup gold when walking over it.

I got tired of crawling through caves to get to monsters to test this so I just made a “map generator” that generates a single room. This room is always “lit”, but the player sight is still small, to test monsters appearing and those types of messages.

screenshot of game

Next, I implement pathfinding. What I want is for monsters to move toward the player while they see him, and if he leaves their sight, they continue moving to his last known location or until they see him again.

Week in Review

It doesn’t feel like a great deal of progress was made this week. I spent most of my time shoring down systems in place, making sure they worked well enough, and moving on. So there haven’t been any gameplay additions. I’m okay with this for now. My first (non-blogged) days were spent on map generation and endless tweaking of stupid nonsense that doesn’t even exist anymore, so in comparison I was very productive while I blogged!

Writing out what I have worked on, and then what I intend to work on next, has been very helpful in keeping myself on track and away from falling into the pit of nonsense work. I have a good feeling about moving forward and the progress I’ll make next week. I think, at least for the near future, things are going to speed up some, and I’ll have something moderately playable and fun.

SCRL: Introduction

Project SCRL, or “SadConsole Roguelike”, will be a Diablo-style roguelike game written in C#, using Monogame / SadConsole / GoRogue libraries for display and various rogue-specific utilities.

This project originally began in 2018 when I decided to try to make a game “for real”. I read a bunch of tutorials, set my sights high, and got to coding. I had a functional, but basic, game, which I though was well-engineered and extensible, but in the process of actually extending it I ran into a lot of roadblocks. Most were of my own doing with my ambitions, and some were with the tools I used. I let the project languish.

A few days ago I picked it up, dusted it off, and saw something that could be fun in there. In true Developer Fashion, I am not using the old project, but starting from scratch. I’ll reference old code and old design documents here and there, but I want to try and do things a new way this time. To start with, I’ve decided to document the process every day I work on the project.

At first, it will mostly be raw notes for each day of work. These will include to-do lists, accomplishments, or trains of thought that lead absolutely nowhere. Hopefully, if the project continues long enough, there will be enough material to write detailed and informative blog posts.

For now, here’s the original “game design document”:

=====

Are you a bad enough dude to come out alive?

The Chapel of Stilled Voices

Deep in the jungle lies the mansion of an ancient and wealthy madman. In his elder years he grew to fear death, and built shrines to every god imaginable so he could pray and offer his material wealth to them to stave off death. This didn’t work, naturally, and he died, leaving behind no family.

The mansion is a small castle, with countless wings and rooms filled with both unimaginable wealth and unimaginable horrors — for some of these gods were not benevolent.

Word traveled, legend grew, and adventurers came from far and wide to try to get to the fabled treasure. Some, wiser than the others, decided to simply set up shop on the road leading to the mansion, to sell to and buy from those about to give their lives to one of the countless gods in what would be called the Chapel of Stilled Voices.

You, the player, are one of these foolhardy adventurers, set on finding the treasure within and becoming rich beyond your wildest dreams.

Game Loop

The game play will consist of two main loops.

Dungeon Crawl

In this portion of the game, you are trawling through the dungeon, killing monsters, picking up loot, and killing more monsters.

The Dungeon Crawl will be high-paced action, with a high number of mobs on-screen at once to deal with. This makes the next portion of the game a welcome reprieve and more likely to be cherished rather than dreaded.

Every level of the Chapel (dungeon) is randomly generated the first time the PC explores it. Subsequently, each play-through re-randomizes the Chapel, so Level 1 will be different for PC1 and PC2.

The random generation should use a combination of prefabs (prefabricated sections of dungeon, hand-designed and combined like puzzle pieces), as well as pure “random” generation like Binary Space Partitioning.

Towntime

In this portion, you are interacting with merchants in-town, accepting and turning in quests, or enhancing your items or yourself.

In the beginning of the game this is just a camp where you can rest and store items. You’ll have a bed and a chest. If your run lasts long enough, or if you accumulate enough wealth (via gold or item worth), new merchants will be drawn to your camp area. As the game progresses, more and different merchants will appear, each offering different services or themselves in possession of more wealth.

This progression may or may not last between runs. If the player reaches yet another threshold, then the game considers this place “noteworthy” enough for certain merchants to stick behind after the player dies, so the next player character who arrives won’t start completely from scratch.

Religion

Religion will play a big role in SCRL, mechanically speaking. Because the Chapel is a mish-mash of altars to various gods and spirits, the character’s religious affiliation will have an impact on every playthrough.

This page will attempt to list the major religions of the game setting, along with appropriate metadata.

Alignments

As with many RPG systems, SCRL will use a type of alignment system, though (as with other systems in SCRL) it will be simplified. Rather than a 3×3 grid of alignment types a la D&D, it will be this:

  • Lawful
  • Good
  • Neutral
  • Evil
  • Chaotic

These alignments will not affect gameplay choices. They will affect how certain spawned monsters in-game respond to the PC’s presence. If the PC happens upon a shrine room to their chosen god, the monsters within may not respond to the player, or perhaps will even interact with and act as special in-dungeon NPCs (one-time shops, like in Fate).

Aspects

An Aspect is a quality, statement, or goal a character may strive toward, and which a Deity personifies. A Deity may personify multiple aspects, and many Deities with different Alignments may share Aspects among each other. The more Aspects a PC has in common with a given Deity, the more friendly that Deity’s followers may act.

Aspects will be defined in a metadata file, but here is a basic list of some.

  • “It is a good day to die!”
  • Intrepid
  • Wisdom
  • Desire
  • Pleasure
  • War
  • “No stranger to pain”

Aesthetics

“Aesthetics” refers to visual aspects of a Deity. A Deity may be dark and broody, or bright and bubbly. This data is mostly meant to be used in room / shrine generation, and will also be contained in a metadata file. Some examples of Aesthetic types are:

  • Alien
  • Dark
  • Colorful
  • Strange

Deities and Demigods

The world of SCRL is filled with countless deities, demigods, major and minor spirits, primordial beings, ascendants, etc. From now on they will simply be referred to as Deities.

Each Deity follows one Alignment, embodies up to three Aspects, and holds up to two Aesthetics. Full Deity data will, of course, be held in a metadata file.