Skip to content

Commit

Permalink
Work on persistence (using mongodb and java & scala drivers), and oth…
Browse files Browse the repository at this point in the history
…er architectural work.
  • Loading branch information
zzorn committed Jul 15, 2010
1 parent 7c62be2 commit bd31e3c
Show file tree
Hide file tree
Showing 44 changed files with 1,610 additions and 12 deletions.
9 changes: 8 additions & 1 deletion pom.xml
Expand Up @@ -5,7 +5,7 @@
<projname>cloudfun</projname>
<projver>0.1-SNAPSHOT</projver>
<projdesc>Middleware library that provides game centered storage and task execution for local, remote, or multi-node servers.</projdesc>
<scala.version>2.8.0.RC7</scala.version>
<scala.version>2.8.0</scala.version>
<scalatest.version>1.2-for-scala-2.8.0.RC6-SNAPSHOT</scalatest.version>
</properties>

Expand Down Expand Up @@ -62,6 +62,13 @@
<scope>test</scope>
</dependency>

<!-- MongoDB driver -->
<dependency>
<groupId>com.osinka</groupId>
<artifactId>mongo-scala-driver_2.8.0.RC7</artifactId>
<version>0.8.1</version>
</dependency>

</dependencies>

<build>
Expand Down
11 changes: 0 additions & 11 deletions src/main/scala/org/cloudfun/Client.scala

This file was deleted.

22 changes: 22 additions & 0 deletions src/main/scala/org/cloudfun/CloudFun.scala
@@ -0,0 +1,22 @@
package org.cloudfun

import entity.{FacetServiceImpl, FacetService}
import storage.memory.InMemoryStorage
import time.Clock
import time.real.RealClock
import scheduler.local.LocalScheduler
import scheduler.Scheduler
import storage.Storage

/**
* A singleton for accessing various services.
*
* Set up with local services by default.
*/
object CloudFun {
var storage: Storage = new InMemoryStorage()
var schedulerService: Scheduler = new LocalScheduler()
var timeService : Clock = RealClock
var facetService: FacetService = new FacetServiceImpl()
}

13 changes: 13 additions & 0 deletions src/main/scala/org/cloudfun/client/Client.scala
@@ -0,0 +1,13 @@
package org.cloudfun.client

import org.cloudfun.server.Account

/**
* CloudFun client-side interface.
*/
class Client {
private var sessions: List[Account] = Nil


}

46 changes: 46 additions & 0 deletions src/main/scala/org/cloudfun/client/ClientSession.scala
@@ -0,0 +1,46 @@
package org.cloudfun.client

import org.cloudfun.data.Data


/**
* Client side state for a session with a server / account / avatar (decide wich one makes sense - maybe avatar).
*/
trait ClientSession {

/**
The client provides facets(?) for various client side functionality:
* UI components
* Menus, quickbuttons, panels, lists, tables, specialized editors
* HUD indicators, gauges
* Documents that can be displayed by client side ui components
* Control mappings
* Server callbacks
* Client side value prediction / iteration etc
* Simple and sandboxed scripting?
* 3D scene objects
* Primitives
* Lights, skyboxes, terrains, etc
The client should not expose to the server in any scripts any client specific data (other than the login account etc as necessary)
The client core creates a system menu that is not editable by the connected game, that allows loading local games, connecting to a server, etc.
Basically the client has a similar entity system as the server, only the facets are UI components, 3D scene elements, etc?
And persistence is memory only
And it's also possible to update a part of the data -> mutable data structures with listeners...
The client doesn't maybe have to have a generic data directory, but instead a similar entity storage as the server
if data is needed for tables and such, they can be in some data facets that have own update functions.
*/

/**
* Updates some client side state.
*/
def setValue(path: List[Symbol], value: Data)



}

39 changes: 39 additions & 0 deletions src/main/scala/org/cloudfun/client/Skycastle.scala
@@ -0,0 +1,39 @@
package org.cloudfun.client


/**
* Main entry point for Skycastle client.
*/
/*
TODO: Give options to
- run a server locally
- continue playing with an existing world
- set up a new world
- connect to a remote server
- list the ones the player has an account on
- get list of all running servers (through server to server networking)
*/
object Skycastle {

def main(args: Array[String]) {
println( "Skycastle client starting." )

/*
// Setup screen
val screen = new Screen()
screen.run()
*/

// Get server based on user input (for now, just create a local one)

// Allow user to select an avatar/game on the account, or create a new one

// Enter main game loop

// draw scene
// get any updates
// listen to player inputs, map controls to actions, call server with action

}
}

56 changes: 56 additions & 0 deletions src/main/scala/org/cloudfun/data/Data.scala
@@ -0,0 +1,56 @@
package org.cloudfun.data

object EmptyData extends Data {
def get(name: Symbol) = None
def apply(name: Symbol) = throw new IllegalArgumentException("No such property exists: '"+name+"'")
def asMap = Map()
def keys = Nil
def contains(name: Symbol) = false
}

case class MapData(values: Map[Symbol, Object]) extends Data {
def apply(name: Symbol) = values(name)
def asMap = values
def keys = values.keys
def contains(name: Symbol) = values.contains(name)
}

/**
* Collection of key-value properties.
*/
trait Data {

/** Get property if found */
def get(name: Symbol): Option[Object]

/** True if a property with the specified name is present. */
def contains(name: Symbol): Boolean

/** The available properties. */
def properties: Iterable[Symbol]

/** The data as a map. */
def toMap: Map[Symbol, Object] = Map(properties map (x => x -> apply(x) ))

/** Get property, or throw error if not present */
def apply(name: Symbol): Object = if (contains(name)) get(name).get else throw new IllegalArgumentException("Unknown data field '"+name+"'")
def applyAs[T](name: Symbol): T = apply(name).asInstanceOf[T]

// Getter utilities
def get(name: Symbol, default: Object): Object = get(name).getOrElse(default)
def getAs[T](name: Symbol): Option[T] = if (contains(name) && apply(name).isInstanceOf[T]) Some(apply(name)) else None
def getAs[T](name: Symbol, default: T): T = getAs[T](name).getOrElse(default)

// Getter utilities for specific types
def getInt(name: Symbol, default: Int = 0) = getAs[Number](name).map(n => n.intValue).getOrElse(default)
def getLong(name: Symbol, default: Long = 0) = getAs[Number](name).map(n => n.longValue).getOrElse(default)
def getFloat(name: Symbol, default: Float = 0) = getAs[Number](name).map(n => n.floatValue).getOrElse(default)
def getDouble(name: Symbol, default: Double = 0) = getAs[Number](name).map(n => n.doubleValue).getOrElse(default)
def getBoolean(name: Symbol, default: Boolean) = getAs[Boolean](name).getOrElse(default)
def getString(name: Symbol, default: String) = getAs[String](name).getOrElse(default)
def getList(name: Symbol, default: List[Object] = Nil) = getAs[List[Object]](name).getOrElse(default)
def getData(name: Symbol, default: Data = EmptyData) = getAs[Data](name).getOrElse(default)

}


60 changes: 60 additions & 0 deletions src/main/scala/org/cloudfun/data/MutableData.scala
@@ -0,0 +1,60 @@
package org.cloudfun.data

import _root_.org.cloudfun.storage.Ref

/**
*
*/
trait MutableData extends Data {

def set(name: Symbol, value: Object)

def update(name: Symbol, value: Object) = set(name, value)


/*
implicit def self: MutableData = this
case class field[T](name: Symbol, value: T = null)(implicit mutableData: MutableData) {
if (value != null) this := value
type Listener = (T, T) => Unit
private var listeners: List[Listener] = Nil
def set(value: T){
val old = if (listeners != Nil) apply(null) else nul
mutableData.set(name, value)
listeners foreach( _(old, value))
}
def get = mutableData.applyAs[T](name)
def get(default: T) = mutableData.getAs[T](name, default)
def := (value: T) = set(value)
def apply() = get
def apply(default: T) = get(default)
def addListener(listener: Listener) = listeners = listener :: listeners
def removeListener(listener: Listener) = listeners = listeners.filterNot(_ == listener)
}
case class int(name: Symbol)(implicit m: MutableData) extends field[Int](name)(m)
case class long(name: Symbol)(implicit m: MutableData) extends field[Long](name)(m)
case class float(name: Symbol)(implicit m: MutableData) extends field[Float](name)(m)
case class double(name: Symbol)(implicit m: MutableData) extends field[Double](name)(m)
case class string(name: Symbol)(implicit m: MutableData) extends field[String](name)(m)
case class bool(name: Symbol)(implicit m: MutableData) extends field[Boolean](name)(m)
case class list[E](name: Symbol)(implicit m: MutableData) extends field[List[E]](name)(m) {
def += (element: E) = set(element :: get(Nil))
def -= (element: E) = set(get(Nil).filterNot(_ == element))
def contains(element: E) = get.contains(element)
}
case class data(name: Symbol)(implicit m: MutableData) extends field[Data](name)(m)
case class ref[R](name: Symbol)(implicit m: MutableData) extends field[Ref[R]](name)(m)
*/

}

16 changes: 16 additions & 0 deletions src/main/scala/org/cloudfun/data/MutableMapData.scala
@@ -0,0 +1,16 @@
package org.cloudfun.data

import _root_.java.util.HashMap

class MutableMapData extends MutableData {

private var values: HashMap[Symbol, Object] = new HashMap[Symbol, Object]()

def contains(name: Symbol) = values.containsKey(name)
def get(name: Symbol) = if (values.containsKey(name)) Some(values.get(name)) else None
def properties = values.keySet
def set(name: Symbol, value: Object) = values.put(name)
def remove(name: Symbol) = values.remove(name)

}

16 changes: 16 additions & 0 deletions src/main/scala/org/cloudfun/data/ObjectData.scala
@@ -0,0 +1,16 @@
package org.cloudfun.data

/**
* A scala object that implements MutableData.
*/
class ObjectData extends MutableData {

def set(name: Symbol, value: Object) = null

def properties = null

def contains(name: Symbol) = null

def get(name: Symbol) = null
}

0 comments on commit bd31e3c

Please sign in to comment.