These last weeks and the following ones are going to be really busy: several conferences, certification training and exam, closing a project at work,... So I'm going to be a little missing till the start of June. But I have plans in June to set things back to motion again. So stay tuned until them, I'm really looking forward the summer to get a lot of Jade 2.0 work done (as happened last one).
(this post is also written on the Jade forums, in this thread)
This post is not going to be a very positive post for most people probably, but I don't think things are going to change much in the near future, so let's go.
Currently we have 2 branches in Jade: Jade 1.X (based on Haddd) and Jade 2. When I released Jade 1.0 a team of people assembled around the engine to help on it (I won't post names here because I'm sure I would forgot someone who has helped and I don't want to). Our objective at that time was to finish Jade 1.X missing parts and polish it. The work was directed towards 3 things: animation, importing and a game editor. We never finished any of those 3 things (although there was quite a lot of work done on all of them). There were several factors involved on this (MDX dying, it was hard to interact in an editor with Jade,...), but in the end we decided to stop working on the Jade 1.X branch and make a new engine from the ground: Jade 2.
Jade 2 started very nicely, with a lot of development done, specially in the engine core and the plugins library (Pluto). But after some time the developer team started to have less time to work on the engine. I have to blame myself for this as I slacked a lot during the start of Jade 2 (no excuses here). It's true there are some things in the works: gonzo is preparing a Jade 1.2 release, several students are doing their projects to extend Jade and I'm writing some Ai namespaces. But nothing is related to the the graphic core of Jade 2 (and that's the most important thing for people following or who plan to use the engine).
So, this is what I was planning to do given the current situation. To keep advancing Jade 2 we would need to find some graphic programmers with a good level on the subject of engine design. We would walk them on the engine internals, tasks that need to be done, how things work and why,... I have played with the idea of doing that myself, but I have no strength to learn 3D graphics programming at the level that is needed. Also, as I don't have much free time lately and I don't spend much of it on Jade, I don't want to search contributors until I know that I will have a decent activity again. My idea is to continue working on the new Ai libraries, writing code and small demos and when I feel that I have advanced that part enough (and I'm more free), try to find some people interested on helping with the 3D code.
And that's how things are right now. Do not think the project is dead (far from it), but for some time it is going to advance at a very slow rate. Opinions are really welcomed on this subject :)
Here are the materials of my last conference about XNA 2.0.
The demo was a remake of a webgame called Globulos. It's a very fun game, try it if you didn't know it. The slides are in spanish and the code is in english mostly. I did the network code and some cleaning while Jorge did the game itself. I used the Creators Club examples for my part and a small chat demo I found on Ziggyware.
To run the demo you need to computers in the same subnet (the demo uses SystemLink to connect both players). On the login screen, press F1 to create or join a game (if you don't have a local LIVE profile you will be prompted to create one, but don't worry, as local profiles you only need to give a profile name, and that's it, no need to really register to LIVE), then press any key except the spacebar and move your players. To end your turn use the spacebar, and that's it.
Hope you enjoy it! :)
I continue using most of my free time working on the XNA 2.0 lecture I'll be giving this friday with Jorge (Kartones won't be able to attend in the end :( ). It's shaping very well but there are lots of rough edges to polish, and several ppt slides to write (the lecture will last one hour and a half! We'll need a really good ppt to win us some time at the stage :p).
I have done very little work on Jade.Ai, mostly fixing some minor errors on the Graphs namespace and adding Dijkstra algorithm as a stand-alone class. I didn't add it at the start because I was thinking: "well, A* with a 0 cost heuristic behaves as Dijkstra algorithm, so no need to add it". But I forgot a very small difference: A* needs a target node (to estimate the cost) while Dijkstra doesn't! So I fixed it and added Dijkstra to the library.
I've been playing also a little with my behavior trees ideas and implementation and I think it's going to end as a really sweet namespace :) I'm learning quite a lot on the AiGameDev forums (they are full with people that know a hell lot about Ai) so I expect this will turn out as a very interesting part of the new Jade.Ai DLL.
After this friday I will take some days off to play a little and on easter I'm not sure if I'll be here or if I'll go to the beach, but if I stay I'll dedicate a good part of my time to Jade.Ai.BehaviorTrees.
These last weeks I've been working on a very basic namespace for Jade.Ai: Jade.Ai.Graphs. This namespace contains the classes needed to execute graph-based algorithms. Currently it only supports Breadth-First-Search, Depth-First-Search and A*. In Jade 1.1 we had also Dijkstra algorithm but you can get the same result using A* with an heuristic that always returns 0.
I could have just ported the 1.1 code to 2.0, but I decided to rewrite it. I don't remember exactly how, but some time ago I found the Boost Graph Library (BGL) and I must admit I liked a lot how it was organized. After that I also found that there was a C# port of the BGL called QuickGraph (pretty amazing stuff). So I decided to port also the BGL to C# for Jade 2.0. Rest assured I didn't port the whole BGL to C# (it is pretty big), I only coded the classes I felt necessary for our needs (that's why I didn't simply use QuickGraph, it has too much stuff and there are some inner things I don't like much).
So, let's get a little overview of what you can find in Jade.Ai.Graphs (better read this looking at the Jade.Ai.Graphs code or you won't understand a thing :p):
- Root/Base folder: the interfaces ISomethingGraph represent several types of graphs. The hierarchy starts in IGraph, that gives nearly no information, and ends in IVertexAndEdgeListGraph, where you have several methods and properties to get the vertices, edges, out edges,... The interfaces IMutableSomethingGraph represent the same information as the ISomethingGraph interfaces, but also give you Add/Remove operations so you can modify the graph. The idea is that you use a Mutable graph to build the graph from your data and then the algorithm uses the non-mutable graph to perform the algorithm (as the algorithm shouldn't modify the graph data at all).
- Algorithms: here you can find the BFS, DFS and A* implementations. The algorithms are implemented so you can perform the full algorithm in one call (Compute() method) or you can execute step by step (Step() method). The Step() method is pretty useful for debugging and also for time-sliced searches (quite useful in games). Also, every Step the algorithms raise several events when interesting things happen: a vertex is discovered, an edge is examined,... The idea is that external classes will add handlers to those events to gather interesting data about the algorithm execution. I must admit that I'm not very happy with the BaseAlgorithm class, that's something I'll improve in the future for sure.
- Implementations: if the root folder was full of interfaces, here you'll find implementations of those interfaces. Currently there's only an AdjacencyList class, which performs as a directed mutable graph that can have parallel edges if needed. This class implements the IMutableVertexAndEdgeListGraph so it covers all the interfaces in the base namespace. I will probably add in the future an UndirectedAdjacencyList and an AdjacencyMatrix class, but for now on the AdjacencyList is more than enough.
- Observers: some useful classes that observe several events that the algorithms raise. PredecessorRecorderObserver tracks the predecessor of every vertex (useful to know the path to get from one vertex to another) and TargetObserver tracks if a given vertex has been reached. They are more an example than anything else, but they should work as inspiration for other custom observers when you are using the library.
And that's it :) But when I started the new AI library for Jade I did the promise of not writing a lot of code without tests and examples, so I have also added several examples in the AITestApplication project. To try them do the following:
- Run the project.
- Choose a source and a target vertex (target is not mandatory). For example if you want to try BFS and DFS choose source 0 and no target. If you want to try Dijkstra choose source A and target F.
- Click the button of the algorithm you want to execute. You'll get a file dialog where you have to choose a graph file. I have included 2 examples in AITestApplication/Graph/Examples. The file format is pretty easy if you want to create your own graphs to test the code.
- Once you choose the graph file the algorithm will execute and put the result in the big text box. You'll get the list of vertices in the order the algorithm examined them and if you set a target, the path from the source vertex to the target vertex.
Let's look a little at the code to give you an idea of what's happening (warning: code is very ugly right now, I'll clean it later on). The following code snippets are from GraphDemoPanel.cs, method buttonBFS_Click.
1: // Create the grpah
2: AdjacencyList<Vertex, Edge> graph = LoadGraph();
3: if (graph == null)
4: return;
5:
6: // Create the algorithm
7: BreadthFirstSearch<Vertex, Edge> algorithm = new BreadthFirstSearch<Vertex, Edge>(graph);
First we use LoadGraph() to create an AdjacencyList. It has two generic parametters: the vertex type and the edge type. Second we create the BreadthFirstSearch algorithm passing him the graph (and with the same generic parametters as the AdjacencyList).
One of the things we want to track in the example is the order in witch the algorithm examines the vertices, so we write a simple method:
1: private void ExamineVertex(object sender, VertexEventArgs<Vertex> e)
2: {
3: _examinedVertices.Add(e.Vertex);
4: }
_examinedVertices is a List<Vertex> where we add the vertices the algorithm discovers.
Now we should connect this method with our algorithm.
1: _examinedVertices.Clear();
2: algorithm.ExamineVertex += ExamineVertex;
Just add the method to the algorithm event and we are set :)
Let's add some other observers to the algorithm. First we declare them:
1: TargetObserver<Vertex> targetObserver = new TargetObserver<Vertex>();
2: PredecessorRecorderObserver<Vertex, Edge> predecessorRecorder = new PredecessorRecorderObserver<Vertex, Edge>();
We declare a TargetObserver to keep track of the target (if one is set) and a PredecessorRecorderObserver to keep track of the path to reach each vertex. Now time to connect them to the graph:
1: // Track the predecessors
2: predecessorRecorder.Attach(algorithm);
3:
4: // If there is a target, set it and attach the observer to the algorithm
5: if (textBoxTarget.Text.CompareTo(string.Empty) != 0)
6: {
7: foreach (Vertex v in graph.Vertices)
8: if (v.Label.CompareTo(textBoxTarget.Text) == 0)
9: {
10: targetObserver.Target = v;
11: targetObserver.Attach(algorithm);
12: break;
13: }
14: }
We just use the Attach method to connect the observer methods with the algorithm events. Easy :)
Time to initialize the algorithm:
1: // Initialize the algorithm
2: foreach (Vertex v in graph.Vertices)
3: if (v.Label.CompareTo(textBoxSource.Text) == 0)
4: {
5: algorithm.Initialize(v);
6: break;
7: }
You have to call to Initialize before executing the algorithm or it won't work!
And now let's execute the algorithm itself:
1: // Iterate through the algorithm
2: while (algorithm.State == AlgorithmState.Running && targetObserver.TargetFound == false)
3: algorithm.Step();
If we weren't tracking the target we could just call algorithm.Compute() and execute the full algorithm in one go, but we want to stop when we find the target so we have to execute it this way.
The rest of the code is just printing the data to the textbox, nothing special there.
And that's all about Jade.Ai.Graphs. I know it lacks an A* example; I'll do it, but I wanted something more spectacular as output instead of a simple textbox, so it will take me some time to put it up. Once the A* example is done I'll write some small tutorials for people who want to learn how to use the graphs and some explanations about the inner workings, but the code will be probably similar to the one I have just explained.
Now my next objective for Jade.Ai is to add Behavior Trees, Hierachical Task Networks and Planners. Most games nowadays use state machines and scripting for their Ai, but there has been a special interest lately in HTN and planners, specially after the game F.E.A.R. I have been following for quite time the excellent AI blog of Alex J. Champandard and I have decided that this kind of techniques would be really useful for Jade.Ai users. It's going to be a hard work as I know very little about the subject but I think it will be a worthwhile effort.
Next week don't expect something spectacular here: I have to make a big XNA demo with Kartones and Jorge so I'm going to be pretty busy :S
Great way of starting the year, I already missed 2 weeks posts :( I'm pretty short on time this week also so instead of talking about the pathfinding and navigation demo (as I promised) I'm going to link 2 things:
- An article about genetic algorithms and evolutionary computing using Haddd.AI.EvolutionaryComputing (pre-Jade, but the code is the same as in Jade 1.1). I wrote this article for the first number of MSCoder Magazine and as it's now out of print they have given me permission to publish it here :) The article aims to explain how GAs work. It also comes with an example (with code) about how to solve the N-Puzzle (3x3) using GAs. You can find the article here and the code here (spanish article with english source code).
- A link to an overview of Jade 2.0 rendering system written by Steve and compiled from one of our IRC meetings. You can find it here (english).
I hope next week I'll have a little more free time and I can do the navigation article, I think it will be pretty interesting :)
Last thursday I gave another AI lecture in the Madrid .NET Users Group about pathfinding and steering behaviors. You can find the slides (in spanish) and a navigation demo here. The lecture was first a little of graph theory and explanations and comparisons between depth-first search and breath-first search. Then I jumped into Dijkstra and A*, talking specially about A+, heuristic functions and when you should use Dijkstra and when you should use A*.
The second part of the lecture was about steering behaviors. I took most of my ideas and examples from Craig Reynolds website and the Opensteer project. I showed some examples from Jade tutorials and the Opensteer demo application.
And then lastly I talked a little about how to organize and coordinate AI, putting some examples with the jade cat navigation demo. I talked a little about state machines, goals based behaviors and messaging.
I think most people enjoyed the talk and most of them told me later that they enjoyed a lot the steering behaviors part (Opensteer demo application is a great demo project indeed, very visual and quite fun to see :) I would have loved to spend more time speaking about goal-based behaviors but I didn't have time to do proper research before the lecture.
And that's it, short post today as I have had a very busy week assembling and installing my new PC, but it's now nearly finished :) I only lack some more installations (mostly VS2005 SP for Vista), some data migration from my old laptop and it's ready to go. Next week I'll go in more detail with the navigation demo, explaining the code, how it uses most Jade 1.1 AI namespaces and how I plan to work on them for Jade 2.0
Well, first of all, happy new year to all readers :) As some of you may know my current computer is an old Dell Inspiron 8600c laptop. It works great but it's starting to fail quite often (the battery hangs the PC, the hard drive died one month ago,...) and even after upgrading it from 512MB to 2GB RAM the graphic card (and ATI 9600) and the CPU (Centrino 1.7MHz) are starting to feel too old.
So I decided to get a new computer for myself. I bought the Inspiron four years ago because I was studying and I needed mobility but this time I wanted a computer that I would use only when I was at home, so I went for a normal PC. I wanted to save some money buying all the parts and then assembling the PC myself (with help) but as I was quite newbie in hardware subjects I had to spend nearly one month reading Tomshardware and asking questions in hardware forums to decide what to buy. I had also to check availability in Spain and the suppliers I was going to use. The uses for the PC would be mostly to work on Jade and to play so I went for a high-end machine (well, as high-end as I could afford).
This is what I got in the end:
- Case: Coolermaster Stacker STC-T01. Not the prettiest case in the world but I don't care much about that and it's very big and affordable.
- Powersupply: Seasonic 700HM Active PFC. I was told this would be more than enough to handle all the
computer power needs and that it was a good powersupply.
- Motherboard: Asus P5N32-E. I wanted to go dual 8800 cards so I had to choose a 680i motherboard. The Asus Striker Extreme doesn't have many more bells and whistles than this one so I settled for the P5N32-E.
- CPU: Intel Q6600. One of my main interests with the new PC will be to test threaded applications and libraries, so I decided to go for this quad-core CPU. Also it has quite good overcloking potential (G0 stepping). The CPU will have also a Thermalright Ultra-120 eXtreme with a Scythe 120mm fan.
- RAM: 2x 2GB G.Skill 6400 4-4-4-12 modules. I was pretty lost in what RAM to use and I got these ones recommended. They seemed a solid choice, so I got them.
- Hard Drives: 2x WD2500YS in RAID 0 for SO and applications and 1x WD5000AAKS for data. Western Digital has a good reputation in hard drives and I didn't see such a big performance increase using a Raptor hard disk as main (and I couldn't afford two Raptors in RAID 0).
- Graphic Cards: 2x Asus 8800GT 512MB. I had to wait for ages for these cards, they are sold out in most of Spain :( Each one will get also a Thermalright HR-03 GT and a 90mm fan from Akasa.
- Sound Card: SoundBlaster X-Fi XtremeGamer Fatal1ty Pro. Probably I should have got the cheaper XtremeGamer (not Fatal1ty) but well...
- Speakers: Creative Inspire T6100. I wanted to get a 7.1 system from Creative or Logitech but I decided to get the 5.1 system because I doubted I could place 7 speakers on my small room (I doubt I will be able to place 5, but I have to try :p).
- Keyboard: Logitech G15. Very nice gaming keyboard. I'm thinking if buying a cheaper keyboard to code, but I think I'll try the G15 first.
- Mouse: Logitech G9. A gaming mouse, very sweet thing (I have used it a little and it works great).
- Screen: BenQ FP241WZ. In my Dell I have a 1920x1200 resolution so I wanted a TFT that supported at least the same resolution so I got this 24" BenQ that has quite good reviews.
- Extra things: a DVD writer unit, a normal DVD and a floppy + card reader unit.
That's all :) The rig is not assembled yet (I'll do it next week with the help of some workmates) but I'm pretty happy with it. I have tried the mouse and the screen and they are working flawlessly. The BenQ impressed me specially because I'm used to the 15" screen of my laptop and it's a very big change :)
I must admit I had (and continue to have) some doubts about the choices, but nothing I can do about it now. I thought a lot about going ATI instead of NVidia: choosing two 3870 cards, a X38 motherboard and DDR3 RAM but in the end I went with the 8800GT. I hope I did right although probably at 1920x1200 I won't notice many differences.
And that's it, I hope I'll have it working perfectly next week so I can shelve once for all my laptop (I'll keep using it for lectures, but not at home anymore :)
Well, not many interesting things in today , i just wanted to write a last time before we start year 2008. These last months I have been pretty busy giving some XNA and AI lectures around Spain (mostly in Madrid, where I live). Here are 2 pics from the last one I did in Mallorca 2 weeks ago. It was about graphs, path-finding and steering behaviors. Not many people could attend (lots of other things to do on these dates) but it was a nice session. Here goes a pic from the people who went to the lecture.
And here it goes another pic:

From right to left:
- Jose: coordinator of Baleares .NET user group Baleares on .NET. Thanks for giving me the opportunity of going there, it's a very nice city :)
- Javier (Jader): one of the main developers of Haddd and Jad Engine. It was pretty nice to see you in person again man ;)
- Myself: not much to say here :p
I decided to give the lecture on those topics because I have started work on the Jade.Ai namespace and those are the ones I understand better and are easier to use on a game/demo. I have checked in some work with the steering behaviors and core AI classes (changesets 29272 and 29319) but a lot of work remains to be done. I have also done several "new year promises" related to how I have been developing in Jade so far.
For Jade 1.1 I wrote/translated quite a lot of Ai code, but I tested very little of it and I tested it very informally. The new company where I'm working promotes agile development methods and my project is using TDD as methodology (Test Driven Development). While I do not fully agree to write soooo many tests for everything we have to code (the ratio code:tests is 1:MORE_THAN_I_THINK_NECESSARY ;) ), my old way of coding was not testing at all and that's not serious to be honest.
So for Jade.Ai 2.0 I'll be writting a small application to test the code that I check (so instead of lots of code and then some tutorials, it should go as code, example, code, example, code,...). It will double also as tutorial/demo to show what things Jade.Ai will be capable of.
And just to see next year if I have keep my "new year promises", I'll post the most relevants here:
- Jade.Ai 2.0 as complete as Jade.Ai 1.1 with examples in all the main areas. I would like to advance more on planning Ai (goals) but let's keep the target "easy".
- Write at least 1 post per week. I have repeated this one a lot to myself :p Probably I'll post some not Jade related things more often.
- Pass certifications exams 70-526 and 70-536. My company is a Microsoft Gold Partner so I have to get certifications and they are a good way to learn some things and review others.
- Design a web game. In my company we have the idea of doing a web based game (yes!) and I have been writing a design proposal but I have slacked a lot on it the last few months (and I have lost a lot of work in my last hard drive crash :( ). Developing it would be great but it depends on lots of external factors.
And that closes 2007 for me. Tomorrow I start my holidays and I won't get back till the 6th of January so to all of you have a great 2007 ending and a better 2008 start. And let's hope 2008 turns as a great year for Jade (I really hope so :)
These days I was
supposed to be working on the input but gonzo has taken over it and he is doing
quite good progress so I decided to review some general things we had around and that should be solved to
easy development in Jade2. Jader for example has
two main complaints currently:
- When an
exception is thrown inside an Invoke call the stack trace is broken so it's
very hard to debug what happened. This is related to Jade2 multithreading and
after talking with Reed about the subject I haven't come to a solution (yet
;)). I will investigate more this in the near future because it's a pretty
important issue to solve.
- While testing
in Jade we add constantly scenes, textures,... and it's a pain to synch all
those files in the different developers computers. It's also a pain for people
that want to use Jade as they have to download those files separately from the
engine and update them when we change them (and we update them quite often in
development). For Jade1.1 I did a very simple FTP sync tool that worked so-so.
So I have
decided to tackle the second point in a general way: coding a Pluto plugin
(Pluto.Synchronization) that will allow two different file repositories to sync
their files. Currently sync is one way only (server to client) and it will
continue to be like that as I think it's the common scenario in games and most apps (unless someone gives me a really good reason to code
2-way sync). The plugin works pretty
similar to the VFS plugin I wrote (more about this later). A
SynchronizationServiceClass registers several classes in Pluto to be used by
other apps:
- ISynchronizationService: a service that syncs 2 different file repositories.
- IClientUpdateService: a service that updates the file system of a client
according to a set of changes.
- IServerGetDataService: a service that gets files from a server.
- IClientUpdateServiceBuilder: service to configure a IClientUpdateService.
- IServerGetDataServiceBuilder: a service to configure a IServerGetDataService.
(if Sync was 2-way then
IClientUpdateService and IServerGetDataService would merge on a single
interface)
Currently I have
provided implementations for:
- Client: HardDisk.
- Server: HardDisk, FTP.
This means that you can
sync 2 hard disk folders or a hard disk folder and a FTP. Nice enough for a
start. But let's look the service, client and server interfaces more closely.
First the
ISynchronizationService interface:
namespace Pluto.Synchronization
{
public interface ISynchronizationService
{
#region Properties
IClientUpdateService UpdateService { get; set; }
IServerGetDataService GetDataService { get; set; }
#endregion
#region Methods
void Synchronize();
#endregion
}
}
Pretty generic, it just
holds a IClientUpdateService object, a IServerGetDataService object and a
method (Synchronize) that surprisingly syncs both of them :p Nothing here ties you to any strange requisite you
wouldn't want.
Now the
IClientUpdateService:
namespace Pluto.Synchronization
{
public interface IClientUpdateService
{
#region Properties
string HashAlgorithm { get; set; }
#endregion
#region Methods
void Start();
void End();
Catalog GetCatalog();
Stream CreateFile(string universalFileName);
void DeleteFile(string universalFileName);
Stream UpdateFile(string universalFileName);
#endregion
}
}
A little less generic
this time. First we have GetCatalog that gets the client file Catalog: a
catalog is just a collection of all the files inside the client. Each catalog
item represents a file and has a string name that uniquevocally identifies it,
the hash of the file contents and the length of the file. The important thing
here is that the name that identifies the file can be resolved equally by the
client and the server to the same file! The VFS has a similar requeriment but
we haven't done a class to enforce this, maybe it's something we should look at
in the future... Then we have a Start and
End methods: this methods are called before sync starts and after sync ends and
they client can use them to any initilization and cleanup it needs. And last we have the 3
"real" methods: CreateFile, DeleteFile and UpdateFile. DeleteFile is
pretty straightforward, but CreateFile and UpdateFile have a
"curious" return: a stream. This streams represents the file and the
Server service is supposed to be writting here to create/overwrite the client data.
And now the
IServerGetDataService:
namespace Pluto.Synchronization
{
public interface IServerGetDataService
{
#region Methods
void Start();
void End();
Catalog GetCatalog();
void TransferFile(string universalFileName, Stream targetStream);
#endregion
}
}
As with the client, we
have a GetCatalog method to get the server catalog and Start and End methods.
The interesting method is TransferFile that takes a file name and a stream where the server writes its data. Currently the HardDisk
and FTP implementations just run over the normal system IO or directly against
a socket, but the only requisite for us is that the client exposes streams and
that the server is able to write on streams.
This means Pluto.Sync could be used perfectly with Pluto.VFS :) Pluto.VFS only wraps
differents file origins to make a system independent from them and Pluto.Sync
just wants a simple way to get files and write onto them, something that
Pluto.VFS.FilesSource Pluto.VFS.WritableFilesSource provide easily. To be truth life is not so easy as Synchronizing can create folders in the file system (something not supported by the VFS right now), but it will be in the near future :)
The code is now uploaded in the last check-in of Pluto and you can play with it using the TestApp we have there. Maybe you'll have to change the configuration.xml file, but it's pretty easy, this is how the sync configuration part looks:
<Synchronization>
<ClientUpdate Type="HardDisk" Path="C:\TestUpdate" HashAlgorithm="MD5" />
<ServerGetData Type ="HardDisk" Path="C:\TestGetData" />
</Synchronization>
It just sets the type of service used in the Client and Server, their paths and the HashAlgorithm to use in the client (I haven't put that in the server but maybe I should, not sure about this one). So after a little polishing in the code (documentation, some tests and a small GUI) I'll start looking at the exceptions problem. Let's hope it gets solved quickly :)
All projects have ups
and downs and in the last few weeks Jade members have been hit by work, examns
and all sort of boring "Real Life" (TM) things. To be honest, our
development pace on summer was totally crazy, with Reed and Jader writting code
faster than any of us would have dreamt. Jade 2 advanced a lot during those
months and now it seems we are going to move at a more normal development
speed.
And what am I doing now? After
"finishing" the VFS (it lacks things here and there) I have moved to
complete input adding mouse movement. Half of it is finished now and the other
half will be when I start using it in the InputTransform class to handle transformations using mouse input. gonzo is also working on
that area for a little app he is doing so I suppose this will be finished
pretty soon (I'm aiming for 1 week).
After that I will
probably start reviewing Jade 2 internals to try to understand the engine architecture
and why things are done like they are. While I have worked mostly in AI and
Utility code until now with Jader and Reed designing Core and
Graphics, finally I'll have to study the inner workings of the engine. I
would have loved to continue working in non-graphics code but it seems you can
avoid your destiny only for so long :)
And to finish something
totally unrelated to Jade or coding: some pictures of my trip to Japan, an amazing place to visit
(100% recommended).
Akihabara in Tokyo, the "Electric Town", full of gadgets and other things geeks love.
Mount Fuji from the Fuji Go Ko (Fuji Five Lakes). The small mountain below Fuji is a parasite volcano (do not remember the exact name).
A garden in Nikko (japanese gardens are truly breath-taking sights).

A Pagoda in Kyoto, the second highest in Japan if I remember right. A pitty we couldn't see the inside.

This is probably a "classic" pic if you go to Nara: one of their "lovely" deers (you should see what happens if you have deer-food and you don't give it to them).
A wooden statue in Nara also. The picture doesn't make them justice at all, they are amazing!

I hope you enjoyed the pics!
I'm going to Japan tomorrow for nearly 2 weeks, so a little update before I go (I doubt you would notice given my post rate, but who knows ;)).
- Statik and his team are building a very interesting demo using Jade 1.1 codenamed "DM", you can watch some screenshots here:
http://www.jadengine.com/index.php?title=Projects:DM
- I have rewritten the VFS again but this time it seems that everything is in the right place. I have been struggling with the VFS design for a long time and it has given me lots of headaches, but I have been able to put it up with several things that were bugging me:
- Multi-threading support: now sources understand about threads and are safe to be used in multi-threaded environments.
- Culture: the sources are also now aware to culture settings. Jade 1.1 for example had some problems in turkish Windows XP (strange problem but well, life is full of those :p). Now the VFS should understand culture and work well in other culture settings different to english, spanish and dutch (our main languages).
- Code reuse: I was repeating lot of code in the different sources implementations. I have separated a lot functionality so now sources only translate global filenames to source-specific filenames and create/destroy the streams. The rest of the code comes from an abstract implemmentation and it's commont to all sources. Implementing hard disk sources and memory sources was a blast with the new architecture in place :)
The bad part is that I have a mistake somewhere when files are closed (locks aren't released so the engine deadlocks). I haven't found it yet so it'll have to wait till I return from my trip (no programming in Japan ;)).
- I have started brainstorming about the AI library for Jade. I'm going to start with pathfinding and movement and more specifically with graphs. I have been reading the Boost Graph Library implementation and Quickgraph (a .NET port of the BGL) and I have got some nice ideas (although I think they are an overkill for Jade). When I get back I'll be finishing the VFS and implementing the graphs and some algorithms on them (DFS, BFS, A*). Comments on what you would expect as users from Jade graph library would be nice (or if you would live happier without knowing about graphs and how movement works on low level ;)).
Well, as most of you probably know, the MDX samples and
documentation have been deprecated from the August DirectX SDK and all forthcomingreleases. I'm not sure if the redistributable is continuing to ship
with it or if it's been taken out too (I
haven't looked at it to be honest).
This means that the main renderer so far for Jade is now
officially dead from Microsoft's point of view.
I posted a lot about this subject earlier this year when we started to shape Jade 2 features and
objectives and that we had to plan for MDX dying in the future.
Now that the future has come and MDX has died, what can we
do?
1 - continue with MDX. The redistributable for MDX 1.1 will most likely continue to exist (although MS did trick us with MDX 2), so we can keep using it. However, the lack of documentation in the SDK represents MS's lack of support for improvements (features, fixes, etc) to this technology.
2- move to XNA. I personally like XNA and what it can become
for the game industry. While I also think it's quite young, yet the new features in XNA 2.0 (announced some
days ago) are a very big step in the right direction. But for us XNA is just a
another flavor of MDX and no matter how
hard we try we won't be able to run on a 360 because our code is way out of the
scope of the Compact Framework. Without being able to port Jade to 360 (and not planning to do that in the near future), XNA offers very little to us.
3- use a DX wrapper. There's a very good project started at
Gamedev called SlimDX that wraps around DX9 and DX10. We did some tests with it
but we didn't get very far; although it shows a
lot of promise given the talented people working on it. But for us, as we use
very little functionality of DX it was overkill.
4- wrap the needed functionality of DX ourselves. We could write a new renderer in C++/CLI
that calls directly the DX dlls.
The 4th point is the path we have taken in Jade and
currently the C++/CLI renderer is up and doing everything we were doing with
MDX. Well, actually, there's a difference: it's
running much faster than the old renderer :) MS numbers were that MDX was around
10% slower than raw DX but our numbers are showing a bigger difference there
(although our tests are quite simple so maybe this could change as we add more
features to the engine).
This jump from MDX to C++/CLI has also shown us that it will
be easy enough to have several renderers in the new architecture (in fact we
have 3 renderers now: the deprecated MDX renderer, the new C++/CLI renderer and
a very simple fixed pipeline renderer).
So it seems we are going in the right direction as lots
of new and important features are working in the engine so far. These include multiple renderers, multi-threading, support
for multiple scenes,... And much more is yet to come :)
Well, nearly 2 months since last post... Summer is not a very productive time for me :) But I have lots of things to talk about so updates should come more often during the next weeks.
Today I wanted to talk about Project Simply Complex, probably the most ambitious project done with Jade 1.1 (that we know about). As you can see in our wiki page here, it's the work of a group of people from Milwaukee School of Engineering about Rube Goldberg machines. I must thank Alikar and the rest of the project team for sharing their code with the the Jade community and people involved in 3D game programming in general. You can download it our page on Codeplex.
Take into account that the code is in early alpha state not pretty or finished by any way ;) But there you'll find very nice examples of picking, physics integration, drag and drop and an UI for Jade (the UI is probably one of the most requested features of the engine). Also, they got quite a good understanding about Jade 1.1 and their suggestions and comments have been pretty important for several Jade 2 decisions.
Yesterday I finished porting Jade Virtual File System to Pluto. It involved mostly getting rid of all the "J" in the class names (JFilesSource to FilesSource and so on), some namespace clashes (System.IO.Directory with Pluto.VFS.Storage.Directory for example), and some new extra features to transform the VFS into a fully working Pluto plugin.
First, let's talk about Pluto: it stands for PLUgin TOolkit, and as it's name tells is a toolkit to give plugins support to any application. Pluto is not tied to the engine, although it was born from the work Reed and Quimbo did in Jaded. Our idea in our next Jade release is to use Pluto extensively to give us extensibility and flexibility. Pluto also comes with several base classes and tools to help you develop new plugins.
Pluto works publishing a set of services to the outside world, so other apps can use these services when needed. That means that the VFS must become a service in Pluto so other applications can query it. Let's see how to create and publish it in Pluto:
#region Using Directies
using Pluto.Core;
using Pluto.Configuration;
#endregion
namespace Pluto.VFS
{
/// <summary>
/// Exposes an <see cref="IVFSService"/> service.
/// </summary>
[CompletionStatus(100)]
[ExposedService(typeof(IVFSService))]
[ExposedService(typeof(IFilesSourceBuilderService))]
[ServiceDependency(typeof(IConfigurationService))]
public class VFSServicePlugin : ServicePluginBase
{
#region Methods
/// <summary>
/// Registers the <see cref="IVFSService"/>.
/// </summary>
protected override bool RegisterServices(IPlutoServiceContainer serviceContainer)
{
serviceContainer.AddService<IVFSService>(new VFSService(serviceContainer));
serviceContainer.AddService<IFilesSourceBuilderService>(new HardDiskSourceBuilder(), "HardDisk");
serviceContainer.AddService<IFilesSourceBuilderService>(new StorageSourceBuilder(), "Storage");
return true;
}
#endregion
}
}
Let's review the important (and probably a little strange right now) part of this code:
- VFSPluginService : PluginBase: all plugins in pluto must inherit from this class. When Pluto loads an assembly it queries for these classes to load their declared services.
- [ExposedService(typeof(IVFSService))] and [ExposedService(typeof(IFilesSourceBuilderService))] : these are the services that this plugin declares to the outside world. As you can see in the method RegisterServices I add them to Pluto ServiceContainer so other classes will be able to use them later. The services are declared as interfaces, so people can do and use different implementations of the same service and aren't tied to the default one we give in Pluto.
- [ServiceDependency(typeof(IConfigurationService))]: I also tell Pluto that our plugin will need the IConfigurationService to work. When a plugin depends on other plugins you should use this attribute so Pluto knows the right order to load plugins.
- [CompletionStatus(100)]: this attribute is a development attribute that tells us that this class is 100% done now. Pluto comes with an assembly browser that uses this attribute to see what classes, methods,.. are done, documented, tested and so on. It's pretty useful to know what's the status of things when a project gets big.
That's the plugin part. You can see it's pretty easy to create a plugin in Pluto. There are some other small changes in the VFS main code (in the constructor mainly, so I'll only post that code).
namespace Pluto.VFS
{
/// <summary>
/// Represents a virtual file system.
/// </summary>
/// <remarks>
/// The priority in the searches within this object is related to the order in which the
/// <see cref="IFilesSource"/> items are aggregated. The first item gets higher priority
/// and so on.
/// </remarks>
[CompletionStatus(100)]
public class VFSService : IVFSService
{
#region Constructors
/// <summary>
/// Default constructor.
/// </summary>
/// <remarks>
/// Uses the <see cref="IConfigurationService"/> to load itself
/// from the configuration.xml file.
/// </remarks>
internal VFSService(IPlutoServiceContainer serviceContainer)
{
_serviceContainer = serviceContainer;
IConfigurationService configuration = _serviceContainer.GetService<IConfigurationService>();
// Read the VFS main values
_name = configuration.ReadValue<string>("VFS", "Name", string.Empty);
_path = configuration.ReadValue<string>("VFS", "Path", string.Empty);
// Get all sources and load them
string[] keys = configuration.GetPaths("VFS/FilesSource", "Name");
foreach (string key in keys)
{
string type = configuration.ReadValue<string>(key, "Type", string.Empty);
string name = configuration.ReadValue<string>(key, "Name", string.Empty);
string path = configuration.ReadValue<string>(key, "Path", string.Empty);
IFilesSource source = _serviceContainer.GetService<IFilesSourceBuilderService>(type).Create(this, name, path);
// Get the defined paths of the source
if (source != null)
{
string[] paths = configuration.GetPaths(key + "/DefinedPath", "Name");
foreach (string definedPath in paths)
{
name = configuration.ReadValue<string>(definedPath, "Alias", string.Empty);
path = configuration.ReadValue<string>(definedPath, "Path", string.Empty);
source.AddDefinedPath(name, path);
}
_sources.Add(source);
}
}
}
#endregion
}
}
Now the VFS constructor uses the IConfigurationService to read the configuration values (from a xml file) file and the IFilesSourceBuilderService to create files sources (based on the type).
As you can see Pluto give us the ability to decouple components (services as interfaces, quering services to the ServiceContainer instead of having lots of statics properties and methods in the code) while doing things in a more .NET way (heavy usage of attributes). In the next post I'll probably talk about other nice things that are inside Pluto and how they relate to the engine.
More Posts
Next page »