Kotan Code 枯淡コード

In search of simple, elegant code

Menu Close

Tag: mud (page 1 of 2)

Speaking at ScalaDays 2012 in London

I am honored to have been invited to speak at ScalaDays 2012 in London this year. For a guy who for years was considered a “Microsoft guy” and then for a few years after that considered an “Apple guy”, this is great validation that I’m not a Microsoft guy or an Apple guy or even a Java guy – I am just a guy who spends most of his spare technical resources searching for things that exemplify Kotan – elegant simplicity, and that includes Scala.

The talk I will be giving is about my experience learning Scala and Akka 2.0 through my ScalaMUD project. Here is the description of my talk from the ScalaDays 2012 website:

When learning a new language, one of the first things I do is try and build a game in that language because games are a lot more fun than progressively complicated “hello world” samples. In this experience report, I discuss my learning process and experience, that of a developer who has spent the last 11 years in the Microsoft world. I am exploring Scala by building a simple network text adventure game that uses many language features and Akka 2.0 and encounters surprisingly real-world problems from many other industries, including finance. My focus in learning languages is on creating clean, simple, elegant code and, as always, justifying to others why this language is worth the learning curve.
The code I’ve been writing as part of this experiment is open-sourced and available on GitHub.

Looking forward to meeting a bunch of fellow Scala enthusiasts and being able to present on this compelling language.

ScalaMUD – More Multi-Threaded Command Parsing via Akka

In the last blog post on ScalaMUD, I showed how I was able to take advantage of a third party NLP library so that I could tag player input with the appropriate parts of speech like Verb, Noun, Adjective, etc. My goal here is to eventually use this information to match words in player input sentences with physical objects in the game so that when someone types ‘kill the blue dragon’, I will be able to find the ActorRef for the blue dragon, and find a verb handler for kill, and then initiate combat.

In this blog post, I’ve come one step closer to that goal by enabling the dispatching of commands. As players enter input, that input is sent off to a Commander actor which tags up the input with parts of speech. Once the Comander is finished with it, it wraps the tagged words in an EnrichedCommand message and sends that to the player, which now has the trait Commandable, allowing the player to respond to enriched commands. This has an added benefit of allowing NPCs to be scripted in the future by allowing them to pretend to ‘type’ things like “kill player”, etc.

Eventually rooms will add commands to players when they enter the room to allow them to type the name of the exit (e.g. north, south, up, window) as a verb. Mortals and Wizards alike each have a unique set of commands they need to be able to type and these commands are grouped into “command libraries” (my old alma mater MUD, Genesis, an LPMUD, called them command souls). For example, here’s the first version of the Mortal command lib:

package com.kotancode.scalamud.core.cmd

import com.kotancode.scalamud.core.ServerStats
import com.kotancode.scalamud.core.TextMessage
import com.kotancode.scalamud.Game
import com.kotancode.scalamud.core.Implicits._
import akka.actor._
import akka.routing._

abstract class CommandLibMessage
case class AttachCommandLib extends CommandLibMessage

class MortalCommandLib extends Actor {
	def receive = handleMortalCommands

	def handleMortalCommands: Receive = {
		case cmd:EnrichedCommand if cmd.firstVerb == "who" => {
			handleWho(cmd.issuer)
		}
		case AttachCommandLib => {
			attachToSender(sender)
		}
	}

	def handleWho(issuer: ActorRef) = {
		println("player "+ issuer.name + " typed who.")
		var stringOut = "Players logged in:\n"
		for (p: ActorRef <- Game.server.inventory) {
			stringOut += p.name + "\n"
		}
		issuer ! TextMessage(stringOut)
	}

	def attachToSender(sender:ActorRef) = {
		sender ! AddCommand(Set("who"), self)
	}

}

Those of you who program in iOS or Cocoa might recognize some of the “Delegate Pattern” here… when the command lib attaches itself to something capable of issuing commands (anything that carries the Commandable trait, like a player or NPC), it just passes the implicit sender ActorRef so that actor can now dispatch commands to that lib.

Here’s the code in the Commander object that sends enriched commands to the actor that “typed” (virtually or for real) the command:

package com.kotancode.scalamud.core.cmd

import akka.actor._
import akka.routing._

import com.kotancode.scalamud.core.lang.EnrichedWord
import java.util.ArrayList
import edu.stanford.nlp.ling.Sentence
import edu.stanford.nlp.ling.TaggedWord
import edu.stanford.nlp.ling.HasWord
import edu.stanford.nlp.tagger.maxent.MaxentTagger
import scala.collection.JavaConverters._
import scala.collection.mutable.ListBuffer
import com.kotancode.scalamud.core.cmd._

class Commander extends Actor {
	def receive = {
		case s:String => {
			val words = s.split(" ");
			val wordList = new java.util.ArrayList[String]();
			for (elem <- words) wordList.add(elem)
		    val sentence = Sentence.toWordList(wordList);
		    val taggedSentence = Commander.tagger.tagSentence(sentence).asScala.toList

			var enrichedWords = new ListBuffer[EnrichedWord]
		    for (tw : TaggedWord <- taggedSentence) {
				val ew = EnrichedWord(tw)
				println(ew)
				enrichedWords += ew
			}

			sender ! HandleCommand(EnrichedCommand(enrichedWords, sender))
	}
}
}

object Commander {
	val tagger = new MaxentTagger("models/english-bidirectional-distsim.tagger")
}

The important bit is that the player gets the HandleCommand message, which then goes through a dispatch process in the Commandable trait, and eventually registered verb handlers (like those registered via attached command libraries) get invoked via messages. Here’s the Commandable trait:

package com.kotancode.scalamud.core.cmd

import akka.actor._
import akka.routing._
import scala.collection.mutable.HashMap
import scala.collection.mutable.HashSet

sealed abstract class CommandMessage
case class AddCommand(verbs:Set[String], handlerTarget:ActorRef) extends CommandMessage
case class Removecommand(verb:String) extends CommandMessage
case class HandleCommand(command:EnrichedCommand) extends CommandMessage

trait Commandable {

	private val verbHandlers: HashMap[Set[String], ActorRef] = new HashMap[Set[String], ActorRef]

	def handleCommandMessages:akka.actor.Actor.Receive = {
		case AddCommand(verbs, handlerTarget) => {
			verbHandlers.put(verbs, handlerTarget)
		}

		case HandleCommand(cmd) => {
			dispatch(cmd)
		}
	}

	def dispatch(cmd:EnrichedCommand) = {
		println("handled a command "+ cmd +".")
		println("command's first verb: " + cmd.firstVerb)
		val targetHandlers = verbHandlers.filterKeys(key => key.contains(cmd.firstVerb))
		targetHandlers foreach {case (key, value) => value ! cmd}
	}
}

The dispatching actually happens in the targetHandlers foreach … line where the command is sent to every command handler that declared interest in that verb. In our case, we have a mortal command verb who that displays the list of connected users and the wizard command verb uptime that displays the length of time the server app has been running.

The following is sample session output from telnetting to the game:

Welcome to ScalaMUD 1.0

Login: Kevin
Welcome to ScalaMUD, Kevin
who
Kevin: who
Players logged in:
Bob
Kevin
Kevin
uptime
Kevin: uptime
Server has been up for 6 mins 39 secs.

Now that I can log in with multiple players, see who is online, and dispatch commands to handlers as well as differentiate between mortal and wizard abilities, this game is finally starting to feel like the beginnings of a real MUD.

ScalaMUD – Consuming Java from Scala and NLP Tagging

Last night I upgraded ScalaMUD’s POM file to point to the recently-available Akka 2.0-RC1. I was previously using M3 an was happy to note that all of my Akka 2.0 code continued working just fine without change from M3 to RC1. If the Akka RC is like most other RCs then there should be no further API changes, only fixes and tightening.

While I had the MUD code open I decided to start working on the problem of accepting player input. Sure, I have a socket reader that accepts text from players but what does one do with this text?

In the old days, I would’ve tokenized the string. By tokenized here I mean just splitting it blindly on spaces. Then I would have considered the first word in the array to be the verb and then dispatched the remaining parameters to some function in the MUD code that knows how to respond to that verb. For example, if I typed kill dragon then I would’ve tagged kill as the verb and dragon as the “rest”. This would have eventually found its way to some kill() method on a player that takes an array of strings as parameters.

Thankfully this isn’t the old days.

Instead what I did was declare a Maven dependency on the Stanford NLP (Natural Language Processing) project. To be specific, I wanted to use the Stanford non-linear Parts of Speech tagger. Why should I deal with parsing strings in a dumb way when someone else has spent years creating a powerful, well-trained NLP engine that can tag every sentence my player types with parts of speech?

This way, instead of relying on forcing players to type in pidgin dialects (e.g. kill dragon or cast spell or move north) I can let them type complete English sentences (if they want). I will then tag those sentences with the appropriate parts of speech and infer what they wanted to do from that.

I want this parsing to take place in the background. Once the player’s sentence has been enriched with parts of speech, I want to send the enriched sentence back to whatever typed it so that the command can be dispatched. To do this, I created a new Actor called Commander:

package com.kotancode.scalamud.core

import akka.actor._
import akka.routing._

import com.kotancode.scalamud.core.lang.EnrichedWord
import java.util.ArrayList
import edu.stanford.nlp.ling.Sentence
import edu.stanford.nlp.ling.TaggedWord
import edu.stanford.nlp.ling.HasWord
import edu.stanford.nlp.tagger.maxent.MaxentTagger
import scala.collection.JavaConverters._

class Commander extends Actor {
	def receive = {
		case s:String => {
			val words = s.split(" ");
			val wordList = new java.util.ArrayList[String]();
			for (elem <- words) wordList.add(elem)
		    val sentence = Sentence.toWordList(wordList);
		    val taggedSentence = Commander.tagger.tagSentence(sentence).asScala.toList

			var enrichedWords = new ArrayList[EnrichedWord]
		    for (tw : TaggedWord <- taggedSentence) {
		//		println(tw.value + "/" + tw.tag)
				val ew = EnrichedWord(tw)
				println(ew)
				enrichedWords.add(ew)
			}
	}
  }
}

object Commander {
	val tagger = new MaxentTagger("models/english-bidirectional-distsim.tagger")
}

At this point I’m just building the array of enriched words and I’m not actually sending the command back to the player (I’ll do that tonight or tomorrow, time permitting .. as always, you can check out the GitHub repo for the latest changes to the MUD). One of the interesting bits here is how I’m using a Java library from Scala. This is usually a pretty painless task but sometimes there are issues. In this case, the Stanford NLP library class Sentence has a bunch of overloads for the toWordList method. Java knows how to pick which overload but Scala doesn’t if I just use type inference and default Scala types. To get it to pick the right toWordList method I had to manually construct an ArrayList[String] because passing an Array[String] doesn’t let Scala know which overload to pick. It’s a little annoying but if I can keep the Scala->Java bridge points like this minimal then it’s not bad.

The flip side of this is that I’m getting back a regular Java array list in response to toWordList, which doesn’t support pretty Scala-native iteration because it doesn’t contain a foreach method, which is the underpinning that supports all the syntactic sugar around iteration. To deal with that, I imported the Java converters package implicits so that I could get the asScala function, which lets me call toList, which gives me a nice Scala list that I can use for easy iteration.

Here’s some sample output when I connect to the MUD and enter a sample sentence, which is then tokenized and tagged with parts of speech:

[EnrichedWord: word=attack, tag=VB, pos=Verb]
[EnrichedWord: word=the, tag=DT, pos=DontCare]
[EnrichedWord: word=green, tag=JJ, pos=Adjective]
[EnrichedWord: word=dragon, tag=NN, pos=Noun]
[EnrichedWord: word=with, tag=IN, pos=DontCare]
[EnrichedWord: word=the, tag=DT, pos=DontCare]
[EnrichedWord: word=yellow, tag=JJ, pos=Adjective]
[EnrichedWord: word=sword, tag=NN, pos=Noun]

The real goal here is that I will be taking the tagged nouns in the sentence and scanning through the player’s inventory and the environment in which the player stands for objects which have names that match the nouns and then using adjectives to disambiguate them if collisions occur. That way, when I type “kick blue bottle” I will be able to scan the surroundings for objects called “bottle” and if I find more than one, I’ll only gather up the ones that are blue.

In case you’re wondering what the EnrichedWord class looks like, which has some helper code that identifies only the parts of speech I care about, here it is:

package com.kotancode.scalamud.core.lang

import edu.stanford.nlp.ling.TaggedWord

case class PartOfSpeech
case object Noun extends PartOfSpeech
case object Verb extends PartOfSpeech
case object Adjective extends PartOfSpeech
case object DontCare extends PartOfSpeech

class EnrichedWord(value:String, tag:String, val pos:PartOfSpeech) extends TaggedWord(value, tag) {

	override def toString = "[EnrichedWord: word=" + value +", tag=" + tag + ", pos=" + pos + "]"
}

object EnrichedWord {
	def apply(hw: TaggedWord) = {
		val ew = new EnrichedWord(hw.value, hw.tag, rootTypeOf(hw.tag))
		ew
	}

	def rootTypeOf(s:String) = {
		s match {
			case "VB" | "VBD" | "VBG" | "VBN" | "VBP" | "VBZ" => Verb
			case  "NN" | "NNS" | "NNP" | "NNPS" => Noun
			case "JJ" | "JJR" | "JJS" => Adjective
			case _ => DontCare
		}
	}
}

Note that the EnrichedWord Scala class inherits from the Stanford TaggedWord Java class.

I really, really, love the syntax of the string pattern matcher I use to obtain the POS root (adjective, verb, noun, don’t care) from the Penn Treebank Tags that are used by the Stanford NLP POS tagger.

The takeaway I got from this exercise is further reinforcement of my rule to never re-invent the wheel because there are wheel experts out there who have dedicated their lives and careers to building wheels more awesome than I could ever hope to build. Hence I declare a Maven dependency on the NLP library and in a single night, I’ve got a MUD that can intelligently POS-tag player sentences which I can then use to identify potential targets of player commands. In addition, I don’t have to create a pidgin dialect for interacting with the MUD. English works and the MUD should be able to deal with “I kill the dragon with the blue sword because I am the shizzle” with the same ease as “kill dragon with sword”.

Adding State to Actors with the Pimp My Class Pattern

In my last blog post, I talked about how the new Akka 2.0 actor system hides an enforces the inaccessibility of the actual class of the underlying actor. For example, if you have a class called Zombie that is of type Actor, then when you use the actor system to start that actor, what you get back is an ActorRef, and (without cheating), there is no way to typecast or otherwise gain access to the Zombie type from an instance of ActorRef. While it felt limiting, once I embraced the design principle that necessitated that enforcement, I understood.

That said, I am building a MUD here and I’m going to need state. My rooms need names, descriptions, and exits. My NPCs are going to need combat stats and inventories, my players are going to need names, descriptions, races, genders, etc. This is all basic stuff but – if I can’t get to a game object reference from an ActorRef, how am I going to get at their internal state?

Easy! Don’t use internal state.

Remembering back to my first post where I upgraded my old Scala MUD to use Akka actors, I noted that every actor in a system has a unique path string that denotes its position within a hierarchy of supervisory actors much like the way supervisors and processes exist in an Erlang system. That gave me the idea to store the state for my actors in a big in-memory hash (which I could then upgrade to some kind of distributed or CouchDB-type store later).

With that problem solved, the only real problem now was that my ActorRef instances didn’t have concrete properties. One of my favorite features of Scala, which is also used in building DSLs, is the pimp my class or pimp my library pattern. This works very much like class extensions in C#. I can create a class that encapsulates or enriches an underlying class type by providing methods that operate on or with that class. In my case, I wanted strongly typed accessors like name and description that actually deferred the backing store to this singleton, in-memory hash.

Here’s my scala file that contains an Implicits object that enriches the ActorRef type with the wrapper class and the wrapper class provides a getter and setter for name.

package com.kotancode.scalamud.core

import akka.actor.ActorRef
import scala.collection.mutable.{Map,
    SynchronizedMap, HashMap}

object Implicits {
	implicit def enrichActorRef(value: ActorRef) = new WrappedActorRef(value)
}

/*
 * Singleton containing a hash map keyed on the Actor Ref path
 * which contains additional hash maps.
 * There is one hash map for every actorref that needs state
 */
object StateMap {

   // Creates a thread-safe hash map
   def makeMap: Map[String, HashMap[String,String]] = {
       new HashMap[String, HashMap[String,String]] with
           SynchronizedMap[String, HashMap[String,String]]
   }

   private var stateMap = makeMap

   def getState(key:String):HashMap[String,String] = {
   	 if (!stateMap.contains(key))
	     stateMap.put(key, new HashMap[String,String])
	 stateMap(key)
   }

   def setState(key:String, propertyName:String, value:String) = {
		var state: HashMap[String,String] = null
		val result = stateMap.get(key)
		result match {
			case Some(x) => state = x
			case None => state = new HashMap[String,String]
		}
		state.put(propertyName, value)
		stateMap.put(key, state)
   }
}

class WrappedActorRef(val actorRef: ActorRef) {

	def name:String = StateMap.getState(actorRef.path.toString)("name")
	def name_=(value:String) { StateMap.setState(actorRef.path.toString, "name", value) }
}

An obvious refactoring opportunity here would be to move the StateMap class out to its own separate Scala file but I’ve always been a huge fan of the agile process of getting something working first and refactoring afterward.

Now, to use my newly enhanced ActorRef (with state) class all I have to do is add the following import

import com.kotancode.scalamud.core.Implicits._

To the top of my Scala file and below anywhere the type ActorRef is known, I can read and write the name property, as shown here:

	private def handlePlayerLogin(player:ActorRef) = {
		println("Player logged in: " + player)
		allPlayers ::= player
		for (p: ActorRef <- allPlayers) {
			p ! TextMessage(player.name + " logged in.")
	    }

Because ActorRef has been pimped to use the external state provider, I can use player.name in my code and it works!

ScalaMUD – Updated to Akka 2.0-M3

Tonight I decided to dig back into my tiny little MUD sample (which doesn’t have much in common with a real MUD at this point… but that will change soon) and upgrade it to work with the current milestone of Akka, 2.0-M3 which came out just last week from what I can tell.

There is actually quite a bit of difference in complexity and power between Akka 1.3 and Akka 2.0. There’s a detailed blog post here that covers some details on the breaking changes between 1.2/1.3 and 2.0.

The biggest thing that concerns me is that Akka 2.0 has this concept of an actor system, which is really a tree-like hierarchy of actors. Some actors act in a supervisory capacity over other child actors and this tree is query able at runtime. If this sounds like Erlang’s supervisor process system to you that’s no accident… the philosophy guiding the development of Akka 2.0’s actor system is very Erlang-ish.

So when I create my top-level Game singleton object, I now need to create an instance of an Actor System and fire up a top level actor (I can have multiple top-level actors):

package com.kotancode.scalamud

import akka.actor._
import akka.routing._

/*
 * Root-level Game singleton
 * Creates the Akka Actor System for all subsequent game objects
 */
object Game extends App {
	val system = ActorSystem("ScalaMUD")
	val server = system.actorOf(Props(new GameServer()), "server")
	println("System Starting")
	server ! ServerStart()
}

Note here the use of system.actorOf. If I want to create a subordinate (child) actor within the context of the parent actor doing the creation, then I would use context.actorOf. I can give each of my actors a unique name so that they have descriptive path names when they appear in the actor system tree.

So far I was happy with the upgrade and I didn’t have too much trouble. Then I got to the point where I was creating anonymous actors in order to execute my while loops for accepting sockets and reading input from a socket in the background… Akka 2.0 has removed the spawn { } syntax and replaced it with some severe limitations, namely you can no longer create anonymous actors that do not implement a receive method. This means the old spawn { // do something } construct is impossible, replaced with this snippet from my GameServer class:

case s:ServerStart => {
	context.actorOf(Props(new Actor {
		def receive = {
			case ss:ServerStart => {
				startSocketListener
			}
		}
	})) ! s

If you’re thinking OMGWTFBBQ at this point, you’re not alone. Basically what I’m doing is creating an anonymous actor, defining a receive method that receives a specific message and does something in response to that message and then sending a message to my anonymous actor. This is actually the way the documentation tells you to spawn off asynchronous background tasks without using named actors.

Before you start the flame war here – it is worth taking a minute to think hard about the fact that everything that occurs asynchronously within Akka is supposed to be an asynchronous event-driven, message-passing construct. In short, if I was really anal about this, I would have spawned off an actor that reads from the input socket stream in its own private loop and I would have spawned off another actor that encapsulates the output writer. When the input reader has read a line, it should send a message indicating that a line has been read and when something needs to send text to a player, it should do so through its output writer actor.

At this point I’m not that anal and I don’t need that level of complexity, so I’m leaving it out. I only mention this alternative to ease the pain of the new way of doing anonymous actors.

In short, I did get the MUD running on Akka 2.0-M3 and, while a little put off by the anonymous actor syntax, I understand its need and I applaud the type safe people for forcing actors to receive messages.

If you want to follow the code for the MUD as I continue working on it, check out my GitHub repo.

Building a MUD in Scala – Revisited

In my previous blog posts where I tried learning the Scala language through an interesting project, that of building a text-based multiplayer game (a MUD), I made lot of mistakes. Thankfully, that is the real purpose behind that kind of experimentation. We learn from our mistakes and we never really grow until we take risks and deliberately step outside our comfort zone.

Some time has passed and I’ve learned a little bit more of Scala so this time I’m going to take another stab at building a MUD in Scala. This time, however, I’m going about it in a slightly different way. Here’s a list of some of my new goals:

  • All of the code for the MUD will be written in Scala 2.9.1
  • Instead of using regular Scala Actors, I will be using Akka 1.3 Actors
  • Rather than manually executing Scala every time at the command line, I will be using Maven to build AND execute my MUD.
  • I will not tolerate ANY ugliness. Everything I consider done must be clean, concise, easy to read, and as Scala-ish as possible.
First, let’s take a look at the POM file I’m using in order to allow Maven to build, test, and execute my MUD:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.kotancode</groupId>
    <artifactId>scalamud</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>ScalaMUD</name>
    <url>http://kotancode.com/tag/mud</url>
    <repositories>
        <repository>
            <id>scala-tools.org</id>
            <name>Scala-tools Maven2 Repository</name>
            <url>http://scala-tools.org/repo-releases</url>
        </repository>
		<repository>
		  <id>akka.repository</id>
		  <name>Akka Maven Repository</name>
		  <url>http://akka.io/repository</url>
		</repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>scala-tools.org</id>
            <name>Scala-tools Maven2 Repository</name>
            <url>http://scala-tools.org/repo-releases</url>
        </pluginRepository>
    </pluginRepositories>
    <dependencies>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>2.9.1</version>
        </dependency>
		<dependency>
		  <groupId>se.scalablesolutions.akka</groupId>
		  <artifactId>akka-actor</artifactId>
		  <version>1.3</version>
		</dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.scala-tools</groupId>
                <artifactId>maven-scala-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sourceDir>src/main/scala</sourceDir>
                    <jvmArgs>
                        <jvmArg>-Xms64m</jvmArg>
                        <jvmArg>-Xmx1024m</jvmArg>
                    </jvmArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
If I were to drop a simple Scala hello world object in src/main/scala then running mvn clean install would compile that Scala object and I could then execute my Scala application with mvn scala:run -DmainClass=Hello (assuming I created an unpackaged Scala class named hello).
To start with, I created a root/bootstrapper object called Game:
package com.kotancode.scalamud

import akka.actor.{Actor, PoisonPill}
import Actor._

object Game extends App {
	val server = actorOf(new GameServer).start()
	server ! ServerStart
}
At first I thought I would just create a singleton actor GameServer, but because of the way you have to use the actorOf method to get an ActorRef instance for Akka Actors, you can’t just create self-starting singleton actors (well you can, but it looks like a hack). Note that because I didn’t declare server as private, that member variable is now visible to the rest of my application, giving all of my game objects access to the game server Actor.
The first task of the game server, once it receives the ServerStart message, is to fire up a telnet server and spin off a background thread that accepts inbound connections.
package com.kotancode.scalamud

import akka.actor.{Actor, PoisonPill,ActorRef}
import Actor._

import java.net._
import java.io._

import com.kotancode.scalamud.core.Player
import com.kotancode.scalamud.core.NewSocket
import com.kotancode.scalamud.core.TextMessage

case object ServerStart
case class PlayerLoggedIn(player:Player)

class GameServer extends Actor {
	private var allPlayers = List[Player]()

	def receive = {
		case ServerStart => {
			startSocketListener
		}
		case PlayerLoggedIn(player) => {
			handlePlayerLogin(player)
		}
	}

	private def handlePlayerLogin(player:Player) = {
		println("Player logged in: " + player)
		allPlayers ::= player
		allPlayers.foreach( p=> {
			if (p.name != player.name) {
				p.self ! TextMessage(player.name + " logged in.")
			}
		})
	}

	private def startSocketListener = {
		spawn {
			val serverSocket = new ServerSocket(8888)

	  		while(true) {
	   				println("Awaiting connection...")
   					val clientSocket = serverSocket.accept()
	   				val player = actorOf(new Player()).start()
	   				player ! NewSocket(clientSocket)
	   				println("Spun off echo handler for player")
	  			}
		}
	 }
}

At this point, I’m now using Akka actors (whose receive method syntax I like much better than standard Scala actors) and a Maven build with automatic dependency management to build and launch my MUD. With just a few minor changes from my previous Scala MUD, I’m in a much better position to grow this into a real application.

Also note the use of the spawn class here. This executes whatever code is inside the code block as an asynchronous background thread, much like the standard Scala actor actor { } syntax. So, for Akka we use spawn { } and for standard Scala Actors we use actor { }.

Another thing worth noting is the use of the .self member before sending a message to an Akka actor. Unlike regular Scala actors, you can’t use !, ?, !!, etc to send messages directly to instances of objects that derive from akka.Actor. Instead, you need an ActorRef instance, which you get from the actor’s self member. In this way, there’s a much clearer distinction between the class’ message-handling behavior (accessed from it’s ActorRef) and it’s regular java-like behavior accessed from standard class members.

In my next blog post, I will get some more features implemented in the MUD. Eventually, if I like the way things turn out I’ll start pushing my code to a Git repo so that you can read/download it there instead of just copy/pasting it from this blog.

Building a MUD in Scala, Part 5: Refactoring and Idiomatic Scala

So far, so good. My quest to learn Scala by virtue of attempting to build a MUD in that language is going pretty well. At this point, I can telnet to the game server, I can log in (albeit without validation or persistence), and in my last post I added the ability for players to be granted commands like ‘who’, ‘cmdsoul’ (to see the command souls assigned to them), ‘broadcast’, etc.

When we learn new programming languages, we always look at the new language through the filter of our past experiences. This isn’t a sign of a bad programmer – this is merely human nature. It’s how we learn and how our brains filter everything we see, do, and hear. As a result, if we approach a new language like Scala from the point of view of someone who has been doing hard-core OOP for the past several years and only tinkering with functional programming – we tend to rely on certain crutches or conventions.

For example, I have an Actor (a Player, to be exact) and that Actor has multiple mix-in traits. One of these traits manages the list of commands currently available for the player. I am exposing the list of commands as a public field so that the Wizard Command Soul can tell wizards which command souls are attached (this ability is supremely helpful for debugging chained command parsing.. trust me..):

var commandSouls: Map[String, CommandSoul] = Map.empty[String, CommandSoul]

And in the Wizard Command Soul, I do a couple of really hideous things in order to display this list of command souls to the wizard:

val cmdIssuer = soulOwner.asInstanceOf[CommandIssuer]
...
cmdIssuer.commandSouls.foreach( ... )

The first problem with this code is that I’m doing a very classic OOP-style typecast. I’m coercing the soul’s owner (the Actor to which the command soul has been attached) to the trait type CommandIssuer. This means that my Wizard Command Soul now has to have explicit knowledge of how I built my application. In short, it needs to know that the CommandIssuer trait is the one that carries a public field named commandSouls.

Allowing other objects unfettered access to a ‘var’ (mutable) field in Scala just seems wrong. It’s certainly not thread-safe and it feels just wrong to me. This blog is about the pursuit of elegant simplicity and this seems neither elegant nor simple.

I could pull out another classic OOP principle: encapsulation, and wrap that var in a function that returns an immutable map:

	def getCommandSouls = {
		val cmdTemp = commandSouls.toMap
		cmdTemp
	}

When you call toMap and assign that value to a val , it automatically gives you an immutable map. This takes care of some of our thread-safety issues and also prevents other people from tampering with the internal list of commands. But, it’s still just a method wrapper and I still don’t like it because I still have to coerce the actor into the CommandIssuer trait/mixin type. If I decide to move the storage of command maps to a different trait during some future refactor, this code will break.

My next thought, then was to send a message to the soul owner (the player) and I would then expect a message back containing the information I need. This is far more Scala-looking than anything I’ve done so far:

	def handleCommandSoul(verb: String, extParams: List[String]) : Boolean = {
		//val cmdIssuer = soulOwner.asInstanceOf[CommandIssuer]
		var string = "\nCurrently Attached Command Souls:\n"
		soulOwner ! QueryCommandSouls
		self.receiveWithin(500) {
			case rep: CommandSoulReply => {
				rep.souls.foreach( mapitem => string += mapitem._1 + " - " + mapitem._2.describe()._2 + "\n")
				soulOwner ! TextMessage(string)
			}
			case TIMEOUT => {
				soulOwner ! TextMessage("Woah, your command issuer is roasted")
			}
			case somethingElse =>
			{
				println(somethingElse)
				soulOwner ! TextMessage("received a bizarro message!")
			}
		}
		true
	}

I’ve got a couple extra guards in there because I’ve never done this before and have no idea what to expect. What I assume is going to happen here is that the looping react pattern matcher I have in the player will eventually get to the partial function in CommandIssuer and handle the request to query the list of command souls. At that point, it will reply to the sender with the information I’m looking for, using this code:

	case QueryCommandSouls => {
		println(sender + " just asked me for the list of command souls!")
                val souls = commandSouls.toMap // Create an immutable copy!! encapsulation FTW
		sender ! CommandSoulReply(souls)
		}

When I compile and run the MUD this time and I type cmdsoul into my telnet client,  I get something entirely unexpected. The message that my receiveWithin(500) pattern match received was QueryCommandSouls! As it turns out, the wizard command soul is attached to the same player (Actor) that has the CommandIssuer trait. So, basically I’m sending myself the QueryCommandSouls message and immediately after that, I start a receive block. In short, I’m catching my own message before the rest of my reactors can see it.

Remember that Actors in Scala are really nothing more than objects backed by a queue (message box) and every message you send to an Actor is really just dumped into the queue and then pulled out of that queue synchronously or asynchronously using pattern matching syntax. So, when I called receive after sending myself the QueryCommandSouls message, I just received the message I sent a nanosecond ago. I need to refactor this some more to make this more asynchronous to allow the player’s reactors to handle things in the right order.

Here’s my new handleCommandSoul function:

def handleCommandSoul(verb: String, extParams: List[String]) : Boolean = {
		soulOwner ! QueryCommandSouls(this)
	}

Note that I had to change the query message into a case class instead of a case object. This is because if I send the message without any parameters, the sender object on the other end will be the player and not my command soul. To get the reply to come back exactly where I want it, I have to pass the object with the message (unless I actually want the player to handle the reply). This is looking much better – it looks much more idiomatic than my previous attempts.

Now I need to handle the reply in a react loop in my act method in the command soul:

def act() : Unit = {
	loop {
		react {
			case rep:CommandSoulReply => {
				var string = "\nCurrently Attached Command Souls:\n"
				rep.souls.foreach( mapitem => string += mapitem._1 + " - " + mapitem._2.describe()._2 + "\n")
				soulOwner ! TextMessage(string)
			}
		}
	}
}

At this point I can compile and run my MUD again and the cmdsoul command works just as it did before (at least from the player’s point of view) but the internal plumbing has been changed so that it now operates in a thread-safe, asynchronous fashion that looks far more like it belongs in Scala than it does in Java.

The whole point of this blog post is, first and foremost, strive for simplicity. My code looked convoluted, complex, and difficult to read. In addition, I knew it wasn’t thread-safe and violated encapsulation rules. I refactored a couple times and still wasn’t happy. With my final solution of asynchronous messaging between two traits attached to a single parent Actor, I am actually pleased with the result.

Building a MUD in Scala, Part 4: Command Processing

In many traditional MUDs, the list of things a player or an administrator can do is fixed at compile-time. In a standard Zork-style adventure you might be able to do the typical things like enter ‘north’, ‘south’, ‘get’, ‘attack’, ‘kill’, ‘drop’, ‘quit’, etc. In a MUD you get some additional commands that might be relevant in a multi-player environment like ‘who’ or ‘say’ or ‘tell’ and even some fancy muds let you emote with commands like ‘bow’, ‘praise’, ‘introduce’, ‘wave’, etc.

While I’m perfectly OK with that list of commands, I’ve never liked how the player is given those commands. In almost all MUDs that I’ve encountered, the game engine knows about the fixed list of available commands and the execution of said commands takes place somewhere at the low engine level. This totally violates my feelings toward the single responsibility principle (SRP), encapsulation, and domain-bleeding.

The following sample scenarios should make it clear why I hate the idea of the engine having built-in commands:

Scenario 1: A player is in a MUD and they enter a disco. While inside this disco, the player can type ‘disco’ to get their 70s funk on. The ‘disco’ command is only available to the player while they are in this one room out of the thousands of rooms that make up the MUD. Do we really want to go modify the command parser at the engine level in order to grant the player the ‘disco’ command in a single room? What happens if that room gets deleted … now we have orphaned, scar tissue code sitting in our engine that serves no purpose. This might not seem like a big deal for a game, but it illustrates a very good point about designing large applications with large domain models.

Scenario 2: A player in that same MUD stumbles across a sword. The sword has an inscription on it and when the player types the words from that inscription into the console, the sword bursts into flames and does an extra bajillion points of damage. In this case, the command is even more situational than the disco room. Only when the player is wielding this sword are they granted the ability to type the secret word ‘clambake’ into the console that will activate the sword’s secret powers.

So, what I’m envisioning here is I want to be able to send the Player actor a message whenever I grant them the ability to type a command and likewise, send them another message when they no longer have the ability to type that command. Consider the following functions that we might find in the Holy Clambake Sword:


def onWielded(player: Player) : Unit = {
    player ! AddCommand(List("clambake"), handleClambake)
}

def handleClambake(verb: String, extParams: List[String]): Boolean = {
    player ! TextMessage("You have activated the mighty abilities of the Holy Clambake Sword!")
    player ! Emote("has activated the mighty abilities of the Holy Clambake Sword!")
    isFlaming = true
    true
}

To be able to send Player’s the AddCommand message, I’m going to create a trait called CommandIssuer. This trait can be mixed into any Actor that is capable of issuing commands to the system. This includes NPCs and other interactive entities within the game. For now, since I haven’t coded NPCs, we can just start with players. Here’s the code for the CommandIssuer trait:

package com.kotancode.mud.engine

import scala.actors._
import scala.actors.Actor._

sealed abstract class CommandRequest
case class AddCommand(verbs: List[String], executor: Function2[String, List[String], Boolean],
	cmdSoul: CommandSoul = null) extends CommandRequest
case class RemoveCommand(verbs: List[String], cmdSoul: CommandSoul = null) extends CommandRequest
case class ExecuteCommand(verb: String, extParams: List[String]) extends CommandRequest

trait CommandIssuer extends Actor
{	                             // CMD verbs , Func to call
	private var commandMap: Map[List[String], Function2[String, List[String], Boolean]] =
		Map.empty[List[String], Function2[String, List[String], Boolean]]

	var commandSouls: Map[String, CommandSoul] = Map.empty[String, CommandSoul]

	protected val handleCommandMapping : PartialFunction[Any, Unit] = {
		case req: AddCommand => {
			commandMap += req.verbs -> req.executor
			if (req.cmdSoul != null) {
				commandSouls += req.cmdSoul.describe()._1 -> req.cmdSoul
			}
		}
		case req: RemoveCommand => {
			commandMap -= req.verbs
			if (req.cmdSoul != null)
				cmdSouls -= req.cmdSoul.describe()._1
		}
		case exec: ExecuteCommand => {
			val toExecute = commandMap.filter(m => m._1.contains(exec.verb))
			if (toExecute.size == 0) {
				self ! TextMessage("What?\n")
			}
			else {
				toExecute.foreach( m => m._2(exec.verb, exec.extParams))
			}
		}
	}
}

If we add the CommandIssuer trait to our Player class (or any other class we want to be able to issue commands, either from a terminal or at the behest of other Actors) then we can send Players the AddCommand, RemoveCommand, and ExecuteCommand messages. The code that reads in lines of text from the player’s attached socket can now invoke ExecuteCommand after splitting the input line into a head and tail (how LISPy is that??):

val tokens = line.split(' ').toList
this ! ExecuteCommand(tokens.head, tokens.tail)

Finally, I want to mention Command Souls. Command souls are logically bundled groups of command handlers that are also bundled with the code that attaches and removes the commands from targets. This provides a neat and tidy way of packaging logically related commands like the stock commands that belong to all mortals (who, quit, say, get, look, etc), stock commands that belong to wizards (broadcast, cmdsoul to inspect commands, destroy, teleport, etc). Command souls are part of what I consider a MUD’s library code, logically and physically separated from the MUD’s engine code. This concept neither original nor mine – I first encountered it when I was an Archwizard of Code on the LPmud Genesis.

Take a look at the code for the Wizard command soul, a classic example of what Scala should look like when done in clean, tidy, small modules:

/*
 * Wizard Command Soul
 * Commands granted to all wizards
 */
package com.kotancode.mud.lib.wizard

import com.kotancode.mud.engine._
import scala.actors._
import scala.actors.Actor._

class WizardCommandSoul extends CommandSoul
{
	private var soulOwner : Actor = null

	def attachTo(target:Actor) : Unit = {
		soulOwner = target
		target ! AddCommand( List("cmdsoul"), handleCommandSoul, this )
		target ! AddCommand( List("broadcast", "bcast"), handleBroadcast, this)
	}

	def detachFrom(target:Actor) : Unit = {
		soulOwner = null
		target ! RemoveCommand( List("cmdsoul"), this)
		target ! RemoveCommand( List("broadcast", "bcast"), this)
	}

	def describe() : (String, String) = {
		("Wizard", "Standard commands available to all Wizards")
	}

	def handleCommandSoul(verb: String, extParams: List[String]) : Boolean = {
		val cmdIssuer = soulOwner.asInstanceOf[CommandIssuer]
		var string = "\nCurrently Attached Command Souls:\n"
		cmdIssuer.commandSouls.foreach( mapitem => string += mapitem._1 + " - " + mapitem._2.describe()._2 + "\n")
		soulOwner ! TextMessage(string)
		true
	}

	def handleBroadcast(verb:String, extParams: List[String]) : Boolean = {
		var text = "[Broadcast from " + soulOwner.asInstanceOf[Player].name + "]: "
		text += extParams.reduceLeft(_ + " " + _)
		PlayerRegistry.allPlayers.foreach(p => p ! TextMessage(text))
		true
	}
}

And finally, to prove that I’m not just blowing hot air, here’s a screenshot of a session I had while logged into the MUD. My prototype MUD auto-grants every user both Mortal and Wizard command souls and doesn’t care what you type for a name. In the future, it will have to ask for a username and a password, look that person up from storage, and load their profile, yadda yadda … For now, this is what I’ve got:

Sample MUD Session, Illustrating Command Processing

Sample MUD Session, Illustrating Command Processing

Overall I’m still fairly pleased with Scala. A few times I’ve been slapped in the face by the strong-typing because I’m not used to that when everything else feels so functional and lightweight – side-effects of Scala’s Frankenstein/hybrid nature. Still, even with a few syntactic bits of ugliness, I continue to keep forging ahead with this to get a real feel for what it’s like to work with Scala to solve practical problems.

Building a MUD in Scala, Step 3: Refactoring and Pub/Sub

As I mentioned in the previous blog post, I left some ugliness lying around in the code last time. The biggest problem in the last version of the code was that every time a player logged in, the Player actor iterated through the connected player list, accessed a variable specific to networking (the socket writer), and then sent text directly to that player. Not only did that violate encapsulation, but it violated the laws of good taste. It wasn’t elegant, simple, or clean enough for me. I had to fix this and I had to fix it now!

First, before I did the coupling fix, I extracted my code into multiple files. I now have an engine directory which contains the Player.scala and GameServer.scala files. I put them both in the com.kotancode.mud.engine package. This made me feel a little better – at least I was getting some proper organization out of this and I was no longer cramming everything into a single file.

Next, to address the encapsulation problem. After thinking about the problem for a little while I realized that the issue was one of pub/sub (publish/subscribe). I wanted the Player actors to simply publish the fact that they have logged in and then any interested party could then respond to that. Great, I’ll make the PlayerRegistry subscribe to a player login event and then publish that same event. The reason why I can’t have players subscribing to that event on other player objects is that players don’t know about other players (at least until after they’ve logged in) – it’s a chicken and the egg problem that only the singleton PlayerRegistry object can fix.

To give my Actors the ability to publish and subscribe, I used a Trait as a mixin called ActorPublisher (which you can find at this great blog post here by Jim McBeath). So now my engine directory has the following class files:

  • Player.scala
  • ActorPublisher.scala
  • GameServer.scala

GameServer has now become ridiculously small and the only change I’ve made is that instead of calling the message sent to the Player actor echo, I now call it StartTextProcessing. I love the fact that the act of reading commands from the player over a socket in a multi-threaded fashion is just taken care of me by the very nature of actors in Scala.

Let’s take a look at Player.scala, which now contains a revised Player actor that publishes notification of logins and subscribes to notifications of other players logging in from the PlayerRegistry object, which is acting as a multiplexer for this type of notification.

/*
 * com.kotancode.mud.engine
 *
 * Player class and related goodies
 */
package com.kotancode.mud.engine

import java.net._
import java.io._

import scala.actors._
import scala.actors.Actor._

case class StartTextProcessing(socket: Socket)

class Player extends Actor with Subscriber[PlayerMessage] with ActorPublisher[PlayerMessage] {
 var name = "";
 var inReader: BufferedReader = null
 var outWriter: PrintWriter = null

 implicit def inputStreamWrapper(in: InputStream) =
  new BufferedReader(new InputStreamReader(in))

 implicit def outputStreamWrapper(out: OutputStream) =
  new PrintWriter(new OutputStreamWriter(out))

 def processText(in: BufferedReader, out: PrintWriter) {
   inReader = in
   outWriter = out
   PlayerRegistry ! Subscribe(this.asInstanceOf[Subscriber[PlayerMessage]])
   out.println("\nWho be ye?")
   out.flush()
   name = in.readLine();
   out.println("\nWelcome to the KotanMUD, " + name)
   publish(PlayerLoggedInMessage(this.asInstanceOf[Player]))
   out.println("Other people currently playing:")

   PlayerRegistry.allPlayers.foreach( p => out.println(p.name) )
   out.flush()
   while (true) {
       val line = in.readLine()
       out.println(name + ": " + line)
       out.flush()
  }
 }

private val handleOther : PartialFunction[Any,Unit] = {
	case StartTextProcessing(socket) => actor { processText(socket.getInputStream(), socket.getOutputStream()) }
	case PlayerLoggedInMessage(player) => {
		if (this != player) {
			outWriter.println(player.name + " logged in.")
			outWriter.flush()
		}
	}
}

def act() {
	loop {
		react (handleSubscribe orElse handleOther)
	}
}
}

sealed abstract class PlayerMessage
case class PlayerLoggedInMessage(source:Player) extends PlayerMessage

object PlayerRegistry extends Actor with Subscriber[PlayerMessage] with ActorPublisher[PlayerMessage]
{
	start
	var allPlayers = List[Player]()
	def getPlayer() : Player = {
		val newPlayer = new Player()
		allPlayers ::= newPlayer
		newPlayer ! Subscribe(this.asInstanceOf[Subscriber[PlayerMessage]])
		newPlayer
	}

	private val handleMessage : PartialFunction[Any, Unit] = {
		case m:PlayerLoggedInMessage => {
			println(m.source.name + " logged in.") // output to console
   			publish(PlayerLoggedInMessage(m.source)) // republish the message
			}
	}

	def act() {
		loop {
			react (handleSubscribe orElse handleMessage)
		}
	}
}

So now I will compile my new MUD with the following command (as I add files it adds a bit more complexity to my ability to rapidly run my MUD… at some point I’m going to have to upgrade to a build tool to automate this… but that’s a topic for another post):

scalac engine/ActorPublisher.scala engine/Player.scala engine/GameServer.scala

And then I run my MUD with:

scala com.kotancode.mud.engine.GameServer

I can now verify that I am able to handle incoming connections the same way I used to, the multi-threading and thread-local storage is all working properly and most importantly, I am now able to let other players know that a player has logged in using a more elegant publish/subscribe approach.

Building a MUD in Scala Part 2 – Shared State

In the previous post, I explained a little bit about my reasoning behind experimenting with a MUD as a way of learning a new language. As a result, I’ve been poking around a little with Scala. Whenever you’re learning a new language it helps to have a goal in mind rather than building a bunch of disparate “hello world” samples. My goal is a MUD.

Last time I build a telnet server that prompts the user for their name and then acts as an echo server thereafter. In this post, I’m going to experiment with how I can add some global state. I want to be able to keep track of who is currently logged into the MUD. In addition, I want to be able to send messages to all connected players and let them know that another player has connected.

To do this, I’m going to modify my original Scala script from the previous post to make it look like the following:

/*
 * Pathetically simple Scala echo server
 * Step 2 on the road to making a MUD - maintaining player list
 */
import java.net._
import java.io._

import scala.actors._
import scala.actors.Actor._

case class Echo(socket: Socket)

class Player extends Actor {
 var name = "";
 var inReader: BufferedReader = null
 var outWriter: PrintWriter = null

 implicit def inputStreamWrapper(in: InputStream) =
  new BufferedReader(new InputStreamReader(in))

 implicit def outputStreamWrapper(out: OutputStream) =
  new PrintWriter(new OutputStreamWriter(out))

 def echo(in: BufferedReader, out: PrintWriter) {
   inReader = in
   outWriter = out
   out.println("Who be ye?")
   out.flush()
   name = in.readLine();
   out.println("Welcome to the Echo Server, " + name)
   out.println("Other people currently playing:")
   PlayerRegistry.allPlayers.foreach( p=>
	{
		out.println(p.name)
		if (p.name != name)
			p.outWriter.println(name + " just logged in.")
		p.outWriter.flush()
	})
   out.flush()
   while (true) {
       val line = in.readLine()
       out.println(name + ": " + line)
       out.flush()
  }
 }

 def act() {
  loop {
   receive {
    case Echo(socket) =>
     actor {
      echo(socket.getInputStream(), socket.getOutputStream())
     }
   }
  }
 }

}

object PlayerRegistry
{
	var allPlayers = List[Player]()
	def getPlayer() : Player = {
		val newPlayer = new Player()
		allPlayers ::= newPlayer
		newPlayer
	}
}
// Singleton object for the echo server.
object EchoServer {
 val serverSocket = new ServerSocket(8888)

 def start() {
  while(true) {
   println("Awaiting connection...")
   val clientSocket = serverSocket.accept()
//   val player = new Player()
   val player = PlayerRegistry.getPlayer()
   player.start
   player ! Echo(clientSocket)
   println("Spun off echo handler for player")
  }
 }
}

EchoServer.start

The new code here is the PlayerRegistry object. Object’s in Scala are a first-class implementation of the singleton pattern. Simply by declaring something an ‘object’ rather than a ‘class’ Scala automatically takes care of the plumbing involved in setting that up as a singleton. The PlayerRegistry singleton contains a method called getPlayer, which is responsible for instantiating a new player as well as adding that new player object to a list. Note that as we change properties on the player object, that will be reflected in the global player list because we’re making changes to the same object (aren’t pointers awesome?).

The logic behind what I’ve done is pretty simple. The PlayerRegistry singleton object keeps track of all players currently in the game. When someone logs in, I iterate through the list of players. If the player object in the current iteration is not the player doing the logging in, I send the “(player) logged in.” message.

Veteran programmers and programmers with some measure of good taste will realize that I’m violating some patterns here. When a player logs in, I shouldn’t be looping through the player list and manually doing the notifications. What I should be doing is sending messages and letting the player object handle the message accordingly. I’ll take care of refactoring this in the next blog post. For now, take a look at this screenshot from a terminal session logged into my ‘game’ server:

Using My Scala MUD

Using My Scala MUD