Friday 15 January 2010

We have a world!

I haven't blogged in a few days because of the sickness, but I have made some more progress on the Globe system, so here goes ...

At the end of my last post I had the Simulator server in a state where it could be connected to, it would return information about the skybox, and an IP and port of its primary asset server. The asset server was in a state where it could serve textures across TCP.

No socket code was implemented in the client at that point to support any of this.

Present day ...

The client can now login, display a loading screen whilst it connects to the Simulator, gets the initialization data, checks which assets it already has in its cache, and downloads any missing textures etc. from the asset server. When its happy it has everything it needs to start, the loading screen disappears and it renders the skybox that has just come from the servers and some basic GUI.

But what a journey it was to get there, I have hit some really nasty problems along the way. Read on ...

My first hurdle was threading. My implementation of the sockets code was not asynchronous, so the animation on the loading screen would stop whilst everything loaded. Not good. As a C# developer I would think, no problem, the Thread class can sort that out. But in C++ things are not quite so straight forward.

As I read through forum post upon forum post, it became more obvious that threading is not supported in C++. It is only possible through functionality in old C libraries. ... Gulp.

I eventually came across this great article by Arun N Kumar, which solved the problem.
The class he has developed there wraps the C functionality into an inheritable C++ class. Using his code as guidance I successfully created a C++ thread class for use in the Globe client.

Perfect, so now we have threaded sockets in the client application, I could pass a login token into the thread and it would go off and connect to its servers asynchronously allowing the loading animations to carry on doing their thing.

Next I need to get data returned from the servers out of the threads in its object form, which could be a few different class types, but I am already using the thread argument as a pointer to the login token and accessing class members from inside the thread produces access violations.

This was a hard one. After about 12 hours I found a solution.
  • I created a 4k (void*) buffer in memory before the thread was called.
  • The login token is serialized into that buffer, with a 4 byte DWORD value indicating the size of the class it contains, and then the thread is started.
  • The pointer to the buffer is passed into the thread as the argument.
  • The thread carries out its tasks, and loads data into the buffer, along with its class size.
  • The main thread checks the buffer to see what type of data it has based on its size.
  • When the size matching the correct class is found it knows the data is ready and retrieves it.
The next problem I came across was that the textures the asset server was sending were becoming corrupt when they arrived in the client cache. I checked everything I could think of, the files were being written as binary, the data was coming across correctly.

I eventually opened the downloaded JPG in a hex editor, and compared the original. I realized the downloaded one had no zeros in it, they had been stripped at some point in the process. On closer inspection of the code, the client was loading the file into a irr::core::stringc object before it was saved, this was the cause. I loaded it into a standard buffer and it started working fine.

Great free hex editor.

These were the main problems I hit, there has been times I have had to walk away from the screen because I find myself getting nowhere. Its always good to take a break when you think you have hit a problem you will never solve. Everything is solvable. Sometimes you can save hours of pain with a 30 minute break.

After getting over the nightmare communicating asynchronously with the servers, I quickly implemented a skybox based on the data we have received and started to render it.

The next thing was to create some way of the user controlling the camera. In Second Life, there is a nice camera control, a small widget that sits usually at the top of the screen allowing you to rotate and move the camera around (known as caming in-world). It's a UI element, that takes a small amount of getting used to, but people become familiar with it, so I decided to create something similar.

I created a nice menu system, similar to the standard Windows one, but of course much better looking. :) The main headers at present are File, Edit, Window. File contains Upload and Exit, Edit contains Preferences and Window contains Camera Control. The system is very scalable to allow new menus and items to easily be added. I plan to add a server authenticated Admin menu in the near future.

You can now move the camera around with the Camera Control, but the positioning algorithm is not yet perfect, I am now working on that.

So .... essentially, Globe's first sim exists, so we have a virtual world!

No comments:

Post a Comment