Wednesday, November 23, 2011

Component Oriented Systems

Recently I have been doing some research on component oriented approached as an alternative to object oriented design. The problem with object oriented design is as things grow it gets harder to isolate and reuse individual parts of an object. The solution usually is to refactor your classes to make them more granular, this however takes time and is a constant struggle as you add in more features. As you gain more functionality you get a slew of classes and then when the time comes to debug it can be hard to track down at what place something went wrong. Of course all of this can be avoided by careful planning before hand but it's hardly the case where the requirements are static and there will be no changes to the game down the line.

Component oriented systems resolve this issue by separating out logic and data into different components. This makes adding new functionality and testing much easier. You can now write unit tests for a specific component to make sure they function correctly and since they work in isolation you don't have to worry about another feature coming along and breaking something. You also now have the power to add in new features to an entity (I describe an entity as a game object) without having to refactor existing code.

I've read a few articles on component oriented programming and they gave me a good idea on what one would look like but I didn't find many systems out there in the wild. I decided to create a component library which I call COP (Component Oriented Programming) to give others a framework or at least a basic implementation to mess with or give ideas for their own system. The full source for this library is available here . The library is written in C on linux and contains a makefile for building the library and a sample of how to use the library. This code should be easily portable to windows or mac, the only dependencies are libuuid and glib.

To help give you an idea of what the library is like I will run through the sample code. The sample contains two component systems, one that stores position data and another that does the physics (movement and basic collision detection). So here is our main code:


#include

#include <cop.h>
#include "positionData.h"
#include "physicsSystem.h"
#include "systemIds.h"

int main(int argv, char** argc)
{
int i = 0;
Point* p;
PhysicsInfo* pi;
COP_Entity* entities[5];


/* initialize COP */
COP_init();

/* initialize some custom systems */
positionData_init();
physicsSystem_init();

/* create 5 entities */
for(; i < 5; i++)
{
COP_Entity* ent = COP_entity_new();
entities[i] = ent;

/* add some position data */
p = (Point*)COP_system_addEntity(ent, POSITION_DATA);
p->x = i;
p->y = -i;

/* add it to our physics system */
pi = COP_system_addEntity(ent, PHYSICS_SYSTEM);
pi->radius = 1;
pi->movementVector->x = 1;
pi->movementVector->y = 1;
}

/* print out all the entities information */
for(i = 0; i < 5; i++)
{
COP_entity_print(entities[i]);
}

/* do a tick from the physics system */
physicsSystem_update();

/* print out all the entities information and see what has changed */
for(i = 0; i < 5; i++)
{
COP_entity_print(entities[i]);
}


/* shutdown COP */
COP_shutdown();

return 0;
}



First you initialize the COP library and all the component systems you create/use.


/* initialize COP */
COP_init();

/* initialize some custom systems */
positionData_init();
physicsSystem_init();


Next we add 5 entities and add a position and physics system component to them.


for(; i < i++)
{
COP_Entity* ent = COP_entity_new();
entities[i] = ent;

/* add some position data */
p = (Point*)COP_system_addEntity(ent, POSITION_DATA);
p->x = i;
p->y = -i;

/* add it to our physics system */
pi = COP_system_addEntity(ent, PHYSICS_SYSTEM);
pi->radius = 1;
pi->movementVector->x = 1;
pi->movementVector->y = 1;
}


COP_system_addEntity will add an entity to a system given the entity and the the id of the system and will return the data for that component. POSITION_DATA and PHYSICS_SYSTEM are just integers that are defined in an enum.


Next we print out all the entities. COP_entity_print will print out all the information for a given entity. Example output looks like this:

Entity: 32459875
POSITION_DATA:
Position: (0.0, 0.0)
PHYSICS_SYSTEM:
Radius: 1.0
MovementVector: (1.0, 1.0)



Next we update the "game" with a tick from the physics system with physicsSystem_update. Lastly we shutdown the COP library and exit.


This is very a simple example of how your components could look. The only thing we haven't really looked at is how a component system is implemented. Let's take a look at the PositionData system.



/* positionData.c */

#include <cop.h>
#include <stdio.h>
#include <malloc.h>
#include <glib.h>

#include "positionData.h"
#include "systemIds.h"

/*
from positionData.h for clarity
typedef struct
{
float x;
float y;
}Point;
*/

Point* point_new(float x, float y)
{
Point* p = (Point*)malloc(sizeof(Point));
p->x = x;
p->y = y;

return p;
}

void point_add(Point* a, Point* b)
{
a->x += b->x;
a->y += b->y;
}




void* positionData_addEntity(void* data, COP_Entity* entity)
{
Point* p = point_new(0, 0);
g_hash_table_insert(data, entity, p);

return p;
}


void* positionData_getEntityData(void* data, COP_Entity* entity)
{
return g_hash_table_lookup(data, (void*)entity);
}


void positionData_removeEntity(void* data, COP_Entity* entity)
{
Point* entData = (Point*)positionData_getEntityData(data, entity);
free(entData);

g_hash_table_remove(data, entity);
}


bool positionData_hasEntity(void* data, COP_Entity* entity)
{
return positionData_getEntityData(data, entity) != NULL;
}

void positionData_printEntity(void* data)
{
Point* p;
printf("\tPOSITION_DATA: ");

if(data != NULL)
{
p = (Point*)data;
printf("\n\t\tPosition: (%f, %f)", p->x, p->y);
}

printf("\n");
}



void positionData_init()
{
COP_System* system = COP_system_new(POSITION_DATA,
positionData_addEntity,
positionData_removeEntity,
positionData_hasEntity,
positionData_getEntityData,
positionData_printEntity);

system->data = g_hash_table_new((GHashFunc)COP_entity_hash, (GEqualFunc)COP_entity_equal);

COP_system_add(system);
}



This code is fairly simple and straight forward but there are a few points that are worth discussing. First let's start with positionData_init. When creating a new system it requires a few functions, a way to add an entity to the system, removing an entity, if the system has an entity, getting the data for that entity and lastly a way to print out the data for the system. A system also contains a pointer for all the data it will hold, in this case the positionData system is using a hash table between an Entity and a Point. You will notice that all the required functions use void* data as their first parameter such as in void positionData_addEntity(void* data, COP_Entity* entity), this contains the system data.

The physics system follows the same format as the position data system however it also has an update function. All the update function does is take the movementVector then test for collisions against other objects. In the real world you would want the movement vector to be generated from input or maybe a script, these two items could fit into different component systems. Anyways the basics for the component system are there, have fun with it.

Saturday, October 30, 2010

Gambit Scheme on Android

After a bit of work and research I've finally made gambit scheme (v4.6) work on android. I had to modify the source code a little bit to make it compile, my changes are as follows:


In lib/os_tty.c

add the following to the list of includes at the top of the file

#include <asm/termios.h>
#include <termios.h>
#include <signal.h>



on line ~790 comment out ctermid (term_name); /* get controlling terminal's name */

change line ~788 to char term_name[L_ctermid] = "/dev/tty";



In lib/os_io.c

add the following to the list of includes at the top of the file


#include <signal.h>
#include <asm/termios.h>
#include <termios.h>




on line ~6438 comment out <stropts.h>



comment out lines ~6503 to ~6509

The lines in question are:


if (!isastream (fd) || 
(ioctl (fd, I_PUSH, "ptem") >= 0 &&
ioctl (fd, I_PUSH, "ldterm") >= 0))
{
*slave_fd = fd;
return 0;
}




In lib/os.c

add #include <asm/signal.h> to the list of includes at the top of the file



In lib/os_time.c

add #include <asm/signal.h> to the list of includes at the top of the file





Now it's ready to compile. I used the crystax ndk to compile, I did have troubled with the official ndk but I'm unsure if another change I did fixed the issue or if it's a general ndk issue. I wrote a small build script to automate the task, the contents as follow:

export ANDROID_ROOT=/home/sean/dev/android-ndk-r4-crystax/build
export PATH=$PATH:$ANDROID_ROOT/prebuilt/linux-x86/arm-eabi-4.4.0/bin/
export LD=arm-eabi-ld
export AR=arm-eabi-ar
export STRIP=arm-eabi-strip
export RANLIB=arm-eabi-ranlib
export CC=arm-eabi-gcc
export CXX=arm-eabi-g++
export PREFIX=$ANDROID_ROOT/../gambc
./configure --enable-single-host --prefix=$PREFIX -host=arm-eabi CC=arm-eabi-gcc CPPFLAGS="-I$ANDROID_ROOT/platforms/android-5/arch-arm/usr/include/ -fno-short-enums" CFLAGS="-fno-short-enums -I$ANDROID_ROOT/platforms/android-5/arch-arm/usr/include/ -nostdlib" LDFLAGS="-fno-short-enums -Wl,-rpath-link=$ANDROID_ROOT/platforms/android-5/arch-arm/usr/lib/ -L$ANDROID_ROOT/platforms/android-5/arch-arm/usr/lib" LIBS="-lc -ldl"
make & make install



You will want to save this to the extracted gambit source directory, I called it build.sh . You will want to edit the paths in this to your liking, specifically PREFIX and ANDROID_ROOT. Now that gambit has been cross compile to android we can make a project.



I started with hello-jni sample project from the official ndk. There are three things that needed to be done; edit the Android.mk file, edit the jni c file and compile the scheme sources to c.



For compiling the scheme sources you just use "gsc -link file.scm" and it will spit out two files, file.c and file_.c. Here is my Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := test
LOCAL_SRC_FILES := test-jni.c fib.c fib_.c
LOCAL_CFLAGS := -I./depends -fno-short-enums
LOCAL_LDLIBS := -ldl -fno-short-enums -lc -L./depends -lgambc

include $(BUILD_SHARED_LIBRARY)



you will want to change the CFLAGS and LDFLAGS to where the gambc include and lib directories are. In the jni folder I made a directory named depends and put the gambit.h and libgambc.a in it.



Here is my code for test-jni.c:


#define ___VERSION 406000

#include "test_test_test.h"
#include
#include
#include
#include "gambit.h"

#define LINKER ____20_fib__

___BEGIN_C_LINKAGE
extern ___mod_or_lnk LINKER (___global_state_struct*);
___END_C_LINKAGE

___setup_params_struct setup_params;

int fib(int x);

jstring Java_test_test_test_stringFromJNI (JNIEnv *env, jobject obj)
{
// Taken from gambit, lib/main.c.
int debug_settings = ___DEBUG_SETTINGS_INITIAL;

// -:d- (force repl io to be stdin/stdout since terminal isn't
// -attached)
debug_settings =
(debug_settings
& ~___DEBUG_SETTINGS_REPL_MASK)
| (___DEBUG_SETTINGS_REPL_STDIO
<< ___DEBUG_SETTINGS_REPL_SHIFT);
// -:da
debug_settings =
(debug_settings
& ~___DEBUG_SETTINGS_UNCAUGHT_MASK)
| (___DEBUG_SETTINGS_UNCAUGHT_ALL
<< ___DEBUG_SETTINGS_UNCAUGHT_SHIFT);
// -:dr
debug_settings =
(debug_settings
& ~___DEBUG_SETTINGS_ERROR_MASK)
| (___DEBUG_SETTINGS_ERROR_REPL
<< ___DEBUG_SETTINGS_ERROR_SHIFT);

___setup_params_reset (&setup_params);
setup_params.version = ___VERSION;
setup_params.linker = LINKER;
setup_params.debug_settings = debug_settings;

___setup(&setup_params);

char buffer[100];
int n = sprintf(buffer, "fib of 10 is: %d", fib(10));

return (*env)->NewStringUTF(env, buffer);
}



You will notice there is quite a bit extra in there, which is required for calling scheme functions from c without having scheme as the main entry point. The one thing that will have to change if you have a different scheme file is LINKER ____20_fib__, you will need to replace fib with the name of the main file you are compiling to scheme.



Now we can just build ndk library with ndk-build and then build the java portion and run. All my example does is output the string "fib of 10 is: 55".



For clarity I've upload a sample project to github. It also includes the precompiled libgambc.a so you won't need to recompile it yourself.



I'm hoping that this will be a nice way to develop games in scheme on my desktop and then port them to android. Anyways, have fun.

Tuesday, June 9, 2009

Introducing Snagle

A little over a week ago I officially posted snagle , my new 2d/3d engine. Since then I've made quite a bit of progress.

So far the Engine features:

Common Math:
  • 2d Vector
  • 3d Vector
  • 4x4 Matrix
Graphics:
  • Vertex Buffers
  • Vertex Formats
  • Sprites
  • Textures
  • Colors
System:
  • Window setup
  • Keyboard and Mouse Input
  • Timers
I feel it is a good platform to expand upon and the basic foundation is done for the most part. Some things that I feel are needed to make the foundation done are:
  • State Management
  • Resource Management
  • Content System
Once those three features are done then it's only a mater of focusing on common features that most games will use. The biggest issue I have is that I don't know what people want, so I have been focusing on what I would like to see. The biggest reason for this blog post is to get feedback on what people think and shape the direction of it's future.

At this point I want to finish up some of things listed above before I spread the word about the engine too much however I encourage people to look at the wiki, browse through the source code and give feedback. The code is well document and is very presentable, if you don't agree let me know. Sending me feature requests, comments on my code, and general questions about the engine would be quite helpful. I hope to hear some feedback.

Sunday, May 31, 2009

Change of plans

Sometime when developing you come across an unexpected twist and new motivations. My latest "twist" is that for all intensive purpose the server part of my program is being put on hold. Trying to justify this with myself was hard because I feel that my only complete projects were ones I was forced to develop on the job. The new project I'm working on has several goals which I believe are more realistic then a "generic" mmo server.

Some of you may know about my 2d engine tutorial series on gpwiki.org . Since it has been released I've continued to get emails about it, more specifically how to compile/use the code rather than design. The whole purpose of those tutorials was to give people an idea of how to structure an engine rather than something to use. Some people have requested feature enchantments and others want to know when the next version is coming out. About a year ago I started on a new version of the engine. After awhile I was too busy at work and life in general and forgot about then abandoned it.

Since creating that project I've done a lot more engine design and coding and feel like it can be done better. Some of the bigger issues in my mind is that it uses immediate mode in OpenGL, which is slow and generally not that great to work with compared to VBOs and VAOs. The engine also isn't well documented nor structured in a consistent way and worst of all it carries some of my bad habits of using Get/Set in front of things where it isn't need and hungarian notation for private variables. I did delete the project but then the next day I decided that I will leave it up as a code sample and change the front page and license to reflect it's status.

So why the new engine? Besides the things listed in the last paragraph, I'm becoming more interested in modern graphics programming and 3D in general. I've done 3D and even a 3D engine for my current job however I haven't messed with modern features much such as VBOs, VAOs, shaders, FBOs which seem to be all the rage these days. Another big pushing factor for a new engine is to back-port what I do to my companies engine to make my life easier. Since my company is a startup I can really push the direct that the engine goes quite easily. The last point about the new engine is that it doesn't meaning that I have to give up the mmo idea, it just means I'm switching work from the server to the client. I still plan on making the server in scala as I feel it's suited well for that task but I also feel that C++ is better suited for the client (lack of game related libraries on java/scala).

Right now I've been working on the engine in my free time during the last week, I've put about ~15 hours into the project and feel it's coming along rather nicely. So far I've implemented input (keyboard, mouse), windowing, some math (vector2 & 3), vertex buffer formats, textures and vertex buffers. So far I feel that the VBO related stuff is the most interesting.

Right now the formats I support are:
  1. VertexNormalTexture
  2. VertexTexture
  3. VertexNormalColor
  4. VertexColor
They seem to be the common formats out there and if needed you can always plug-in your own formats if you want a custom one.

Here is the code for the vertex buffer:

/*
* File: vertexBuffer.hpp
* Author: Sean Chapel
*
* Created on May 30, 2009, 7:56 PM
* Copyright 2009 Seoushi Games. All rights reserved.
*/


#ifndef _VERTEXBUFFER_HPP
#define _VERTEXBUFFER_HPP


#include "vertexFormats.hpp"
#include "resource.hpp"
#include
#include "types.hpp"
#include "platform.hpp"


namespace k2e
{



/**
* A vertex buffer object that stores a fixed size of elements
*/

template <class T>
class VertexBuffer : public Resource
{

public:

/**
* A default constructor
*/

VertexBuffer()
{
}

/**
* A constructor with the number of elements and thier types
* @param numElements the number of elements to store
* @param type the type of vertex buffer
*/

VertexBuffer(unsigned int numElements)
{
SetSize(numElements);
}


/**
* Default destructor
*/

~VertexBuffer()
{
Dispose();
}

/**
* Sets the number of elements for the VBO
* @param numElements the number of elements to store
*/

void SetSize(unsigned int numElements)
{
buffer.clear();
buffer.reserve(numElements);
}

/**
* Adds an element
* @param v the element to add
*/

void AddElement(const T &element)
{
buffer.push_back(element);
}


/**
* Generates the buffer for use
*/

void Generate()
{
if(buffer.size() == 0)
{
return;
}

Dispose();

glGenBuffers( 1, &glId );
glBindBuffer( GL_ARRAY_BUFFER_ARB, glId );

glBufferData(GL_ARRAY_BUFFER_ARB,
buffer.size() * sizeof(buffer[0]),
&buffer[0], GL_STATIC_DRAW_ARB);

glUnmapBuffer( GL_ARRAY_BUFFER_ARB );
glBindBuffer( GL_ARRAY_BUFFER_ARB, 0 );

isResourceLoaded = true;
}


/**
* binds the buffer for use
*/

void Bind()
{
glBindBuffer(GL_ARRAY_BUFFER_ARB, glId);

T::SetupDraw();
}


/**
* Unbinds the buffer
*/

void Unbind()
{
T::TeardownDraw();
}


/**
* Implements the resource's dispose method
*/

virtual void Dispose()
{
if(isResourceLoaded)
{
glDeleteBuffers(1, &glId);
isResourceLoaded = false;
}
}

private:

u32 glId;
std::vector buffer;
};


} /* k2e */


#endif /* _VERTEXBUFFER_HPP */




If you noticed, every method is commented in doxygen format. It takes a lot long to code when adding all the comments up front but it also means that everything is documented as it progresses so people can actually use the code. All of my code so far has been commented like this and I feel it makes the code much nicer to work with and it makes me think of design before implementing something. When making my code I first design out all of the header file and make sure I'm not forgetting something then I'll comment the header then code. I find this method good pratice but it is more time consuming, fortunatly I don't have to hit crazy deadlines with this code.

Anyways about the code itself, you will notice it's templated which is something the kore2engine made little use of even though there are places that could definatly use it. It's also defined as a resource which means that I can easily have it managed by a resource manager (that's a topic for another blog post however).

Lets take a look at one of the texture formats that plug into the vertex buffer.


struct VertexTexture
{
/**
* A constructor that initializes all components
* @param position the verts position
* @param textureCoords the verts texture coordinatess
*/

VertexTexture(Vector3 position, Vector2 textureCoords)
{
this->position = position;
this->textureCoords = textureCoords;
}


/**
* Used for setuping up drawing with this format used by VertexBuffers
*/

static void SetupDraw()
{
int size = sizeof(Vector3) + sizeof(Vector2);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(3, GL_FLOAT, size, (char*)NULL + 0);
glTexCoordPointer(2, GL_FLOAT, size, (char*)NULL + sizeof(Vector3));
}


/**
* Used for tearing down drawing with this format used by VertexBuffers
*/

static void TeardownDraw()
{
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}


Vector3 position; /**<>
Vector2 textureCoords; /**<>
};


Nothing really too interesting, but it just goes to show how easy it is to make your own format.

So lets show some vertex buffers in use, in a simple application I'm using to test functionality and develop with I needed a hexagon grid. Here is the code to generate and draw a hexagon in a vbo.


HexGeometry::HexGeometry(float radius)
{
vbo.SetSize(8);

vbo.AddElement( k2e::VertexTexture(k2e::Vector3(0.0f, 0.0f, 0.0f),
k2e::Vector2(124.0f / 256.0f, 112.0f / 256.0f)));
vbo.AddElement( k2e::VertexTexture(k2e::Vector3(-radius/2.0f, radius, 0.0f),
k2e::Vector2(67.0f / 256.0f, 8.0f / 256.0f)));
vbo.AddElement( k2e::VertexTexture(k2e::Vector3(radius/2.0f, radius, 0.0f),
k2e::Vector2(189.0f / 256.0f, 8.0f / 256.0f)));
vbo.AddElement( k2e::VertexTexture(k2e::Vector3(radius, 0.0f, 0.0f),
k2e::Vector2(249.0f / 256.0f, 112.0f / 256.0f)));
vbo.AddElement( k2e::VertexTexture(k2e::Vector3(radius/2.0f, -radius, 0.0f),
k2e::Vector2(189.0f / 256.0f, 218.0f / 256.0f)));
vbo.AddElement( k2e::VertexTexture(k2e::Vector3(-radius/2.0f, -radius, 0.0f),
k2e::Vector2(67.0f / 256.0f, 218.0f / 256.0f)));
vbo.AddElement( k2e::VertexTexture(k2e::Vector3(-radius, 0.0f, 0.0f),
k2e::Vector2(7.0f / 256.0f, 112.0f / 256.0f)));
vbo.AddElement( k2e::VertexTexture(k2e::Vector3(-radius/2.0f, radius, 0.0f),
k2e::Vector2(67.0f / 256.0f, 8.0f / 256.0f)));

vbo.Generate();
}

HexGeometry::~HexGeometry()
{
}

void HexGeometry::Draw()
{
vbo.Bind();

glDrawArrays(GL_TRIANGLE_FAN, 0, 8);

vbo.Unbind();
}


The engine I wrote for my company would have been atleast three time as long because in that engine I decided to separate each component into their own buffer and force using an index array even if they were in order like above. Also at the moment that engine can only use GL_TRIANGLES, which made it easier to implement and use but less efficient along longer to setup. Overall I think this is pretty nice. Here is a screen shot from my test app with a grid of hexagons drawn with the above code.



Next time I'm unsure of what I will share and talk about, perhaps the resource manager would be a nice next step or possibly 2d graphics (My test app needs a gui).

Also I'm sorry about the code formating, since html ignores whitespace it makes it a pain to mess with. I've been using http://quickhighlighter.com/ and it looks great on their servers but this blog seems to mess it up for whatever reason, if someone has an idea on how to fix this let me know. Soon enough I'll publish all my code somewhere and I can just give links to a well formated html version.

Thursday, May 14, 2009

A Simple Server in Scala

Surprisingly enough there isn't much information regarding using sockets, scala and actors together. I figured that something like this would be quite wide spread however I found it straight forward to create. I took my knowledge of actors and then followed some sample code for Java sockets.

Right now all the server does is listen for connections and print out what clients send to it, nothing special. There are some downsides to the way I'm doing things. The actor class by default spawns it's own thread which can get ugly fast however it is easy enough to convert over to coroutine like behavior. The reason I haven't done this yet is because I'm not using select to see if there is data so waiting for one receive or in this case line would block the whole thread and that wouldn't be nice. Anyways here is my code.


  1. package stdServer
  2.  
  3. import java.io._
  4. import java.net.{InetAddress,ServerSocket,Socket,SocketException}
  5. import scala.actors.Actor
  6. import scala.actors.Actor._
  7.  
  8.  
  9. object Server
  10. {
  11.   def main(args : Array[String])
  12.   {
  13.     val port = 6669
  14.    
  15.     try
  16.     {
  17.         val listener = new ServerSocket(port)
  18.         var numClients = 1
  19.  
  20.         println("Listening on port " + port)
  21.        
  22.         while (true)
  23.         {
  24.             new ClientHandler(listener.accept(), numClients).start()
  25.             numClients += 1
  26.         }
  27.  
  28.         listener.close()
  29.     }
  30.     catch
  31.     {
  32.         case e: IOException =>
  33.             System.err.println("Could not listen on port: " + port + ".")
  34.             System.exit(-1)
  35.     }
  36.  
  37.   }
  38.  
  39. }
  40.  
  41.  
  42. class ClientHandler(socket : Socket, clientId : Int) extends Actor
  43. {
  44.   def act
  45.   {
  46.     try
  47.     {
  48.         val out = new PrintWriter(socket.getOutputStream(), true)
  49.         val in = new BufferedReader( new InputStreamReader(socket.getInputStream()))
  50.      
  51.         print("Client connected from " + socket.getInetAddress() + ":" + socket.getPort)
  52.         println(" assigning id " + clientId)
  53.      
  54.         var inputLine = in.readLine()
  55.         while (inputLine != null)
  56.         {  
  57.             println(clientId + ") " + inputLine)
  58.        
  59.             inputLine = in.readLine()
  60.         }
  61.  
  62.         socket.close()
  63.      
  64.         println("Client " + clientId + " quit")
  65.     }
  66.     catch
  67.     {
  68.         case e: SocketException =>
  69.             System.err.println(e)
  70.      
  71.         case e: IOException =>
  72.             System.err.println(e.printStackTrace())
  73.          
  74.         case e =>
  75.             System.err.println("Unknown error " + e)
  76.     }
  77.   }
  78. }
  79.  
  80.  


One of things I like about this code is that it shows off mixing Java code with Scala. If you haven't noticed it fits right in and you can't really tell that there is Java embedded.


I also wrote a version of this code with Scala's remote actors however it seems limiting. When I tried to connect to telnet and typed something my server instantly crashed with an out of memory error. I'm guessing that remote actors only can only talk to each other which means that I would have to learn the protocol that it is using and mimic it in my client thats not written in Scala and then hope no one tried to use telnet on it. I'd rather just use normal TCP/IP sockets and know that it will work with pretty much anything.

Well thats it for now, next time I hope to have an non-blocking version of this code with concurrent actors and perhaps some basic functionality.

Tuesday, May 12, 2009

Prototyping the MMO

So five days or so have gone by since I last posted on the MMO server development. Like (almost) all personal projects things are going slow but some progress has been made. I started making a server in python and using telnet for testing. I got as far as having multiple clients being able to connect, clients sending a user name/password (simple text strings) and the server telling the client if the authentication was correct by using a text file as my database. It worked well enough even though the sockets were blocking and synchronous, I didn't really care about scalability nor performance as it was just a prototype.

Being the language nazi I am, I found python not to my liking. First I will state some of the things I do like just to be fair.
  1. Indentation instead of brackets.
  2. No semicolons at the end of lines.
  3. Very feature rich set of common functions/tasks.
  4. No compile times.
  5. An interactive console (I miss this in most languages ever since I started playing with lisp/scheme).
  6. Good documentation and beginners guide.
So now for the things I didn't like.
  1. Classes are littered with self because they aren't real classes but rather namespaces.
  2. Global variables have nasty names __init__, __main__ for example.
  3. The state of flux between 2.5, 2.6 and 3.0. Most libraries are still only usable with 2.5 and then some of the bigger ones work with 2.6 but 3.0 is "virtually" unsupported which is shame.
  4. Lack of type annotations when wanted, for example I would love to be able to require that functions only accept and return certain types. This is just a drawback of dynamic languages for the most part however.
  5. Spaces and not tabs. Why people prefer spaces over tabs alludes me, tabs allow you to move around faster with the arrow keys and allow you to setup your preferred spacing. Mixing tabs and spaces is silly however as it will never look right between different computers. (let the religious wars begin)
Now most of these "cons" are just my opinion and I could probably live with them however #3 really annoys me. Once I got up my simple server I wanted a graphical interface for logging on my server and I decided to use wxWidgets except it only supports 2.5 and 2.6 (sort of). The reason I said sort of is because it actually doesn't work on 2.6 on windows because of some gui dll conflict, at least thats what google had to say. It ended up crashing anytime I moved my mouse over a very simple window. Hopefully this will be fixed in the future but it really makes me wonder about the state of python on windows in general. Windows seems to be a second class citizen in general when it comes to programming languages that are either open source or non-mainstream.

I decided to not take the risk and I started writing equivalent programs in other languages. I made a server in C# with async sockets and I really just didn't like the feel of it. I also made a version in C++ and boost.asio which I liked better than the C# version but I know that C++ will just lead to headaches later on and isn't a good prototyping language. Not being satisfied with either solutions I decided to re-look at some of the languages I skimmed over for one reason or another. In conclusion Scala is my next choice for prototyping a server with.

I looked over some of the beginning docs and I liked what I saw so I picked up "Programming in Scala". So far I'm only at chapter 7 however I really like the way the book is written and how material is presented. Most computer science or tech books bore the crap out of me but for whatever reason I like PinS. So what drove me to taking a look at Scala?
  1. The mix of function, imperative and object oriented paradigms.
  2. Having an actors library for concurrent processes in the same thread.
  3. Statically typed with type inference and the option to declare types if you want.
  4. Runs on the JVM and mixes well with Java (cross-platform goodness).
  5. Short concise programs, much like python is compared to C like languages
  6. The syntax is extensible and makes DSLs easy to create
  7. A familiar syntax without many odd operator symbols for everything.
In feel like Scala is mostly related to OCaml however with an object system that people actually use, mixed with Haskell except without forcing you to be purely functional and odd syntax choices. Of course it gets its influences from other languages as well.


Next time I hope to be able to post some code and my experiences with Scala.

Monday, May 4, 2009

New Project

So I haven't updated my blog in awhile, I'll talk a little bit about languages I've been messing with then I'll move into my new pet project.

Haskell was the last language I posted about and pretty much nothing has changed in my mind about it. It is a neat language and I hope to use it more some day however monads have really turned me off for the moment. Why have monads turned me away? Well it's actually quite simple, being a game programmer in C like languages I'm use to state and monads just makes it either more difficult, painful or ugly compared to the "C" way of doing it. There is always functional reactive programing which is suppose to be the new "cool thing" for programming in Haskell however I just don't feel like learning them as the concept is quite academic (like a lot of things in Haskell) and not really proven for game development yet. So to conclude I like Haskell as a language and it brings on some neat ideas however for game programming I'm having a hard time accepting it.

After I looked at Haskell I stumbled upon factor. Factor is a neat stack based language derived from Forth. I really liked how simple it was, push stuff on the stack then push a function that read the previous stack items and put the result on the stack. It seemed a lot like functional programming but a bit different. I really loved the idea of an image based programming language, basically what that means is that the programming language, libraries and programs are contained in an image file. What this means to the user is that it's very simple to import/include other modules as the programming language knows about everything in it's image. It also makes it painless to add new modules to the image, no need to worry about system paths and the such. As I worked with the language I just couldn't get my brain trained to think in the way factor wants you to (basically backwards or postfix). Because the language is stack based it depends what is already on the stack meaning you really don't pass arguments to a function it just reads from the stack. Also it reads the variables on the stack from back to front meaning it seems backwards in that way as well "push 3; push 4; +"(pseudo code). you would think that this translates to "3 + 4" if it was converted to infix but it's really "4 + 3". This seemed to cause me pain when coding, it made comprehending the code harder. I thought it would get better with time but I gave it a week of coding in my spare time and I felt no better than when I started. Curiously I looked around about factor and according to other blogs some guys had been programming in it for over a year and still are having the same problem I am. I decided that I will look at the language at another time.

Given all the languages I've looked at I got somewhat burnt out on looking for something to replace C, I decided I'd rather just make something. I decided up front that I wanted to make something that deals with networking as I haven't explored that area like I have graphics, sound and general game programming. Networking is becoming more and more important for game developers, it's getting harder to sell single player games and not having much experience with it I feel lacking.

So what did I decide on? I decided I want to design an mmo server. I'm unsure how far I will get with this but I do know I will take away some good knowledge from it. Right now I'm in the planning stages, designing protocols, server layouts and road maps/feature lists on how I will develop it. If your interested in this then I'm keeping all the information at my site here. Being a game programmer and having used C/C++ extensively, I naturally decided to use C++ for my language of choice without really considering my options. Upon doing research I came across Eve Online and surprisingly they use (stackless) python of all languages, this really surprised me because of how slow it is compared to C and how it had to handle tens of thousands of connections at a time (I believe peak is arround 50-60k players all on the same world). Also while I heard of python before I hadn't heard of stackless python. Apparently stackless is a modification to regular python for continuations, coroutines and talking between coroutines.

Now I saw why Eve could handle so many players at once. Still I wasn't exactly convinced python was the right choice so I started looking at other languages like erlang, boo, scala, clojure and even C#. I'm sure all those languages would work for an mmo server as well but besides from C# those are relatively obscure programming languages and if I ever wanted help (on the project, not in general) I probably shouldn't choose them. I then looked into the state of mono on the mac as that is my work machine and if it didn't work well at home and work then I didn't want to use it. I have to say mono has matured quite a bit since I last looked at it (over a year ago) however monodevelop still lacks a debugger and the coroutines that were recently hacked in were a hack that only mono has (.net doesn't support them) and the memory usage was almost double that of stackless python. So I've come to the conclusion that stackless python while it may not be the end result it will be good enough for prototyping and if I really need speed I can always extend with C.

I also must thank Richard Tew (for his posts on gamedev), the Eve Online developers (for their video presentations and developers blog) and lastly the other peoples that responded to my thread at Gamedev.net for helping me come to my conclusions on the subject so far.

In conclusion I've started work designing an MMO server/client and hope to have something to show for it in a couple of months. Lastly I've decided to start using twitter again for the sole purpose of letting people know about my latest developments on the MMO and this blog. You can follow me as Sean Chapel if your interested.