Jump to content

  • Log In with Google      Sign In   
  • Create Account

Awesome job so far everyone! Please give us your feedback on how our article efforts are going. We still need more finished articles for our May contest theme: Remake the Classics

noizex

Member Since 04 Jul 2011
Offline Last Active Yesterday, 05:21 PM
-----

Topics I've Started

Network message solution for client/server architecture

16 January 2013 - 04:27 PM

Hello,

 

What are most common approaches for solving network messaging issue for client/server architecture (more towards online RPG game than first person shooter, so amount of messages is much bigger because there is a lot more going on in the world)? By message I mean communication between client and server (back and forth).

 

First method - Message classes

 

So far I explored Ryzom and Planeshift MMOs sources and they seem to solve this by having a shared code between client and server that has a Message class that is then inherited by every message (ClientLoginMsg, CharacterSelectMsg, GetInventoryMsg). Obviously each message will be used in two ways - the sender will serialize message into bitstream thats sent over the network, and receiver will deserialize it into something usable (class members, data structures etc.). So it looks a bit like this in pseudo-code:

 

class Message
{
}

class LoginAuthorizeMessgae: Message
{
    string user;
    string pass;
    BitStream out;

    // Assume that BitStream has already MESSAGE_ID read from it, so all thats left is message content
    // Because we read MESSAGE_ID, dispatcher knows which message to instantiate and it can be sent to
    // proper handlers
    LoginAuthorizeMessage(BitStream* in)
    {
       in.read(&user);
       in.read(&pass);
    }

    LoginAuthorizeMessage(string username, string password): user(username), pass(password);
    {
       out.write(MSG_AUTHORIZE_ID);  // write message id
       out.write(user);
       out.write(pass);
    }
}

// Then, client side:

void SendAuthRequest(login, pass)
{
    LoginAuthorizeMessage msg(login, pass);
    dispatcher->Send(msg);
}

// Server side:

void ReceiveAuthRequestHandler(Message* msg)
{
    LoginAuthorizeMessage* msg = (LoginAuthorizeMessage*)msg;
    if (db->auth(msg->user, msg->pass)
    {
       // ...
    }
}

 


Problem with this approach seems to be insane number of classes that need to be maintained. Just creating a simple response message with one text field requires declaring class with 2 constructors, then its .cpp file etc. Pros of this method is that same messages can be used by both, receiver and sender, so the code can be shared between client and server. All the serialize/deserialize logic is in one place, so its easier to maintain and harder to make some mistake because you see code for both, serialization and deserialization.

 

I came to even more advanced solution than the one above - I have a factory class that can create an instance of a correct class based on MESSAGE_ID, then I have an event dispatcher that is able to send that exact instance to receivers. A bit of a code snippet to demonstrate:

 
// =================
// NetworkManager
// =================

NetworkManager()
{
   m_MsgFactory->Register<SampleMessage>(NetMessageType::MSG_SAMPLE);
}

NetworkManager::HandlePacket(Packet* packet)
{
   msgID = GetPacketMsgId(packet);
 
   // Create a class thats registered for a given msgID
   // - for example for MSG_SAMPLE it will instantiate SampleMessage class and pass
   //   bitstream from packet.data into its constructor

   NetMessage* msg = m_MsgFactory->Create(msgID, packet.data);

   // This call sends that message to methods that are registered to handle it
   // I register methods instead of msgID, so the method is called with exact
   // class that it needs (so SampleMessage, instead of Message). It doesn't 
   // require explicit casting in handler method)

   m_MsgDispatcher->DispatchEvent(msg);
}

// =================
// SampleMessage
// =================

class SampleMessage: public NetMessage
{
public:
   int a;
   float b; 
 
  SampleMessage(RakNet::BitStream& msg): SampleMessage()
   {
      msg.Read(a);
      msg.Read(b);
   }

   SampleMessage(): NetMessage(NetMessageType::MSG_SAMPLE)
   {
      // This sets MSG_SAMPLE id for this message, so we 
      // dont have to care about it later
   }
};

// ====================
// SampleMessageHandler
// ====================
bool Init(NetMessageDispatcher& dispatcher)
{
    dispatcher.Subscribe(this, &SampleMessageHandler::HandleSampleMsg);
    return true;
}

void HandleSampleMsg(const SampleMessage* msg)
{
    std::cout << "Received sample message: " << msg.a << "\n";
} 

This works really nicely, but its probably a bit slower than some direct method (that clever event dispatcher that sends exact instance instead of passing Message* which allows me to register methods that receive directly what they want is probably doing some casting that could be avoided, although these are static_casts). Also it doesn't help with a problem of enormous amount of very small classes that may be hard to keep in order. 

 

Second method - sendXX methods to serialize some data to bitstream, and directly reading from message in receiver

 

This is method I've seen in some SWG emulator, but it was emulator and I only saw server code, so don't know how well it would work with client and if it was shared in any way or it was separate. In that code, there was a huge MsgLib.h file that defined a lot of methods like:

 


void sendPlayerPosition(Player*, Client*)
void sendServerTime(double time, Client*)
void sendInventory(Inventory*, Client*)
void sendChatMessage(message, channel, Client*)

and so on. Each of this methods serialized required data into a network message (msg.addUint32, msg.addString, msg.addFloat etc.) and sent it directly using provided Client.

 

void HandlePlayerPosition(Message* msg)
{
   msg.getFloat(&player.x);
   msg.getFloat(&player.y);
   msg.getFloat(&player.z);
}

 

This means that writing and reading happens in totally different places (server or client) so code is not really shared, all thats shared is opcodes or message ids because both sides need to be aware of them. 

 

 

The question

So, the question is, are there other methods? Are methods I described good enough and what can be done better? Am I doing something really wrong here? I find it hard to gather any knowledge on this topic, there seem to be no books on this, and only help were source codes of these three MMOs I mentioned at the beginning.

 

Thanks for any input! It would be very interesting to see how others solve this.

 


Game lobby as a separate application

27 December 2012 - 05:10 PM

Hello,

A lot of online games seem to use separate application for a game lobby where you log into your game account, pick a server and then launch the game. This is also where downloading patches takes place.

 

I'd like to know, what are arguments for using lobby as a separate app, rather than build it into the game? I mean, it could do the same things, but as a game. This often has a side effect in some games, that forces player to quit the game if he looses connection, because reconnecting is only available through lobby.

 

Are there some serious things to consider if I'd like to integrate game and lobby so its one process, that can restart itself if executable has to be patched?

 

Thanks,

 


Angelscript with Objective-C

02 December 2012 - 03:38 PM

Hello,

I recently tried to code something on iOS using Xcode and Objective-C. I thought it would be nice if I could hook scripting with AS into my game, but I encounter a lot of problems, most of them come from mixing Obj-C and C++ (Angelscript). I managed to compile AS and even create script engine, but thats as far as I can go with my limited knowledge.

For example how this should be handled in Obj-C class that's some kind of ScriptManager (creating engine, handling pool and message callback):
[source lang="cpp"] r = engine->SetMessageCallback(asMETHOD(CScriptMgr, MessageCallback), this, asCALL_THISCALL); assert( r >= 0 );[/source]
I have no idea how to pass Obj-C method to asMETHOD() macro. Can I even do this? If not, how should I "bridge" such things with AS C++ API?

Its even worse when it comes to registering Obj-C classes (NSString, GLKVector etc.) - I have no idea where to start.

Did anyone make a successful implementation of AS on iOS and has any example that would let me start with this? Because I couldn't find a clue regarding working with AS and Objective-C.

Thanks,

noizex

Storing non-uniform size building blocks on the grid

25 October 2012 - 02:45 PM

Hi,
I'm in the process of coding something that will let me build on a grid, and I've run into problem. Let me show a quickly sketched picture that will help describe what I mean:

Posted Image
At first I thought I'm gonna build with uniform sized blocks - these blocks would be the green block on my picture. Then I decided that I need blocks that will be half as thick and appear in two width variants: 1x1 and 1x2. Mind that each size mean a block that can't be divided - a separate 3D model that will connect to other (allowed) block seamlessly.

Problem is with storing information about these blocks. If I create a grid consisting of smallest elements, biggest block on the example which is 2x2 will occupy 4 cells. How should I handle storing this information so I can query the grid for the smallest cell and still get information about the big one if part of it occupies the queried cell. Following the picture:

grid[0][0] = GREEN_BLOCK_1*;
grid[0][1] = GREEN_BLOCK_1*;
grid[1][0] = GREEN_BLOCK_1*;
grid[1][1] = GREEN_BLOCK_1*;

* GREEN_BLOCK is just representation of some data structure describing that particular block, depending on building block it may store different information

How should I keep information that this GREEN_BLOCK is actually one and the same object? Should I keep some register on top of grid, and grid should keep index into this register? Like:

grid[0][0] = 0;
grid[0][1] = 0;
grid[1][0] = 0;
grid[1][1] = 0;

grid[2][0] = 1;

register[0] = GREEN_BLOCK_1*;
register[1] = RED_BLOCK_1*;

This problem is probably quite common because there were many games that had non-uniform building blocks on some isometric maps, I just can't figure how to store that information in a way that will allow querying by smallest neighbouring blocks, but also supporting blocks that span over more than 1 cell.

I was even considering quadtrees (octrees actually, because whole thing is 3D but I describe 2D to simplify the case) that I don't really like because they don't allow as fast neighbour querying as simple grid and are generally cumbersome. But then, the problem will be blocks that are not 1x1, 2x2, 3x3 like the one thats 2x1 - quadtree can't subdivide in such way, so the 2x1 block would have to consist of 2 smaller blocks and we're back to problem we have on grid, but this time we're also using quadtrees:


Posted Image

If anyone can point me in the right direction here, I'd be very grateful. There is probably some nice and clean solution, I just can't figure it out. Thanks!

Voxel-based polygonal mesh collision detection

05 October 2012 - 04:26 AM

Hello,

I'm trying to figure out how to do terrain collision using my terrain mesh that is extracted from voxel density volume (method similar to Marching Cubes and such). In the past, on non-networked project, I used voxel data for player<->terrain collision, because it seemt to be most logical way. I could just sample the voxel volume at certain points (head, legs etc.) and interpolate values to get the data required for processing collision with the terrain.

But now, I ran into a problem, because I want my game to be networked and I don't plan on sending voxel data to players (for gameplay reasons, but also performance). I want to be able to do at least some simple client-side prediction, so I don't end up with players walking into walls before the server verifies its wrong.

So what I have on client side is triangle mesh of the terrain, which can have overhangs, caves etc. and I need to perform collision prediction using only this data (while server has both, mesh and underlying voxel volume info). How can I perform such collision, so not only player don't fall into the terrain, but also can't walk into narrow spaces or caves, and don't clip with overhangs? Is it possible to achieve with usual physics engines by supplying terrain mesh, and is it efficient? How does it work? Is the mesh simplified in some way, and then what sort of computation is needed to see if players collides with his head, legs, and how to adjust his position?


Regards,
noizex

PARTNERS