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.