I originally wanted to call this post Piiiiiiiggssss innnn Spaaaaace in homage to the Muppet Show, but I figured it would make it harder for people to actually find this content, so, we’re stuck with the boring title for now. In my previous blog post, I talked about enabling multiplayer and rigging up the essential infrastructure to support multiple players within an Akka-backed MMO universe.

So, we’ve got an iPad client (haven’t shown you this yet, mostly because it has no graphics) that connects to our Akka server. This iPad client sends a SignIn protobuf message and then, to keep the test going, sends itself a DirectMessage protobuf message. That’s all well and good if we’re building an MMO chat game, but this is a universe and, sooner or later, we’re going to have to put stuff in our universe.

So let’s take a look at some of the things that we think our stuff in this universe is going to need to do. Firstly, it’s going to need to exist at some point in space, e.g. a coordinate. All of the stuff that exists in space is only discovered by the player by virtue of appearing on their radar scan. I haven’t designed all this out yet, but I know that players who have invested more time and money in their ship’s navigational and scanning equipment will be able to see more stuff, see further out into space, and glean more information from what happens to be out there. Whether that stuff is visible may also have something to do with the thing itself. For example, I might have a cloaking device (though I’d probably have to call it something else, for fear of copyright infringement) which might make it so that cloaked stuff doesn’t appear on radar.

In other words, this is a very quantum style universe – you don’t actually know what’s in it until you inspect it, and the act of inspecting it can alter the results. I might, in the future, decide to code a sneaky NPC that waits to be radar scanned by nearby players and then automatically targets the source of that scan.

So what I’ve decided to do is create a sub-tree of my actor system hierarchy for physical things that exist in space, which includes planets, space ports, ships, star ports, and other stuff that might be harvestable for resources like asteroids and moons. For starters, these things can all be sent a RadarPing message which ultimately originates from a player. These things can then respond to that ping with a RadarPong. The iPad client can then collect radar pongs and use that to dynamically populate a star map of the “nearby universe”. Cool, huh?

So let’s start with the universe:

package com.kotancode.ulysses.space

import akka.actor._

class Universe extends Actor with ActorLogging {
	// create some child objects
	val testPlanet = context.actorOf(Props(new Planet()), name="Utopia1")

	def receive = {
		case p:RadarPing => context.children foreach (_.forward(p))
		case _ => log.debug("Received a universe message")
	}
}

So what we’re doing here is if I send the universeRadarPing message, that message then gets sent to all physical objects within that universe. If the object is out of range of the ping or is cloaked (or something else), then it won’t respond. Otherwise, it will comply and send back a RadarPong message. I know off the bat that I’m going to have many different types of actors that act as physical things in my universe, so this seems like the right time to bust out a trait that encapsulates this behavior:

package com.kotancode.ulysses.space

import com.kotancode.ulysses.space.Vector3D._
import akka.actor._

case class RadarPing(source: ActorRef, origin: Vector3D, scanDistance: Int)
case class RadarPong(source: ActorRef, origin: Vector3D, objectType: Int, name:String, description: String)

object RadarObjectTypes {
	val Planet = 1
	val Station = 2
	val Port = 3
	val Ship = 4

	val Unknown = 99
}

trait PhysicalObject extends Actor with ActorLogging {
	private var location = (6.5, 5.0, 7.2)
	var name = "Game Object"
	var description = "This is a game object"
	var objectType = RadarObjectTypes.Unknown

	def receiveSpatial: Receive = {
		case p:RadarPing => {
			log.debug(s"I received radar ping ${p}, it originated ${p.origin distanceFrom location} units from my location at ${location}.")
			if ( (p.origin distanceFrom location) < p.scanDistance) {
				p.source ! RadarPong(self, location, objectType, name, description)
			}
		}
	}
}

Since my game doesn’t currently have persistence, I’m making up hardcoded values for the planet but, in the future, the planet would ideally reach into some database, identify itself, and then pluck out a map of all of its data, such as its spatial coordinates. The Vector3D class I created back when I was writing a MUD in an earlier version of Akka, and it basically allows me to take a 3-tuple (e.g. (5.0, 1.5, 2.5)) and implicitly turn that into something that supports basic cartesian math. You can see this in the line of code that contains p.origin distanceFrom location, which utilizes the distanceFrom method that I added to my Vector3D class.

Now how about we create a planet that includes the PhysicalObject trait?

package com.kotancode.ulysses.space

import com.kotancode.ulysses.space.Vector3D._
import akka.actor._

class Planet extends Actor with PhysicalObject {

	objectType = RadarObjectTypes.Planet
	name = "Utopia 1"
	description = "This is a utopian planet, chock full of epic win."

	def receivePlanet: Receive = {
		case _ => log.debug("Received some message for a planet.")
	}

	def receive = {
		receiveSpatial orElse receivePlanet
	}
}

This is a pretty simple class and you can see that I’m doing some more hard-coding of values to serve as placeholders until I deal with the persistence deal (remember the YAGNI portion of the Agile Manifesto?). What I really like here is the receiveSpatial orElse receivePlanet partial function chaining. This lets me grab the receive function from the PhysicalObject trait and chain on the receive function from the Planet actor. I don’t have any planet-specific messages but you can imagine I might have messages like Land and TakeOff for when players bring their ships into orbit, etc.

Almost done. We’ve got a planet, which includes the physical object trait (and with it the associated message handling and state … I freaking love traits), and we’ve got a universe that contains the planet. Now we just need to send out radar pings. Rather than make the iPad client manually send radar ping packets, we can use an Akka scheduler on the server side to force the player’s proxy (GameClientProxy actor) to issue the RadarPing to the Universe object periodically.

Here’s the new code for my GameClientProxy class’ preStart() actor method:

lazy val universe = context.actorFor("../../Universe")

override def preStart() = {
	log.debug(s"GameClientProxy pre-start, socket uuid: ${socketHandle.uuid}")
	implicit val timeout = Timeout(1 second)
	import context.dispatcher
	SocketServer.system.scheduler.schedule(
		10 seconds,
		10 seconds,
		universe,
		RadarPing(self,  (5.0, 5.0, 5.0), 10)
	)
}

That’s pretty much it. We know from the code above that we’re going to be sending pongs directly back to the player proxy actor, so we need to respond to that. In the near future, this will involve creating a protobuf object and writing it back out to the client over the socket connection, but for now we’ll just log the fact that we got the pong back:

def receive = {
	case m:DirectMessage => {
		log.debug("I received a direct message.")
		writeRawMessage(m, MessageTypes.DirectMessage)
	}
	case pong:RadarPong => {
		log.debug(s"I received a radar pong ${pong}")
		// writeRawMessage(new raw pong protobuf ...)
	}
}

So that’s it… In just a few quick steps with a few small, lightweight actors, I’ve given my universe the ability to expose an infinitely expandable list of objects to players by virtue of modeling a message-based radar system. I’m nowhere near the point where I can add combat yet, but I’m adding building blocks slowly, which is always fun to do. I think next I’ll work on the “universe map” display for the iPad and possibly figure out a persistence method so I can load planets from my database.