[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Networking (was Re: [glob2-devel] Glob2 salvage proposal)
From: |
Andrew Sayers |
Subject: |
Networking (was Re: [glob2-devel] Glob2 salvage proposal) |
Date: |
Sun, 23 Oct 2005 04:30:45 +0100 |
User-agent: |
Mutt/1.5.11 |
I've had a look at Order.h (and a quick look around some other
networking-related files) today. Could you tell me how accurate the
following statements are:
Communication over the network consists *only* of orders being sent back
and forth between systems.
Orders are all defined in Order.h/Order.cpp, all descend from the
"Order" class, and are executed in Game.executeOrder() and
GameGUI.executeOrder() (or not executed at all);
Orders go through the following stages:
* They are created with a call to "new myOrderType", which can happen
anywhere in the program.
* They are serialised and transmitted to other computers
* <Some magic happens whereby transmission is confirmed, a whole tick's
worth of orders are grouped, etc.>
* A tick's worth of orders are reconstructed by code somewhere deep in
NetGame.cpp, and by the setData() function for each order.
* Later, GameGui.getOrder() is called, which in turn calls
Game.getOrder(). These two functions process the orders. No other
function has anything to do with executing orders.
If I'm understanding this right, I'd say the system has the following
pros and cons:
+ It's quite self-documenting. You can guess what's happening when you
see OrderCancelConstruction() in the program.
+ The system can be extended infinitely, albeit somewhat clunkily
- All the code has to be stored in files nothing to do with the job they
do. OrderCancelConstruction() should be in Building.h, not spread
across Order.h and Game.cpp
- Orders are stored after construction but before serialisation, and
after reconstruction but before handling. This increases the
complexity of the code without increasing functionality.
I've been trying to think of an implementation that gets around the
flaws without losing the benefits. The solution I'm thinking of at the
minute is:
Incoming orders are handled by handler functions, which I will explain
more about later. When the program starts, different modules register
handlers for the orders they want to handle, and get back handlerID
values:
const handlerID myHandlerID = registerOrder(myHandler);
A handlerID is a unique identifier for the handler function, which can
be safely transmitted over the network. To ensure handlerIDs are
registered in the same order every time, handlerIDs should be stored in
static members of classes (or failing that, global variables). The most
likely implementation for registerOrder() is:
std::vector<handler_type> orderHandlers;
typedef std::vectior<handler_type>::size_type handlerID;
const handlerID registerOrder(handler_type h)
{
orderHandlers.push_back(h);
return orderHandlers.size()-1;
};
Somewhere, there is an obstringstream (i.e. a Glob2 binary output
stream) holding the set of orders for the current tick:
obstringstream orderStream;
When a function in a class wants to send out an order, it simply writes
the handlerID and associated data to the stream. Authors are
recommended to make this obvious from the function name:
void myClass::orderSomethingToHappen()
{
// Do various things
orderStream
<< myHandlerID
<< title("foo") << foo
<< title("bar") << bar;
// Do some more things
};
(Note that titles are ignored in binary streams - they'd only be used if
we wanted to produce a text version of the stream during debugging)
This stream represents the serialised order, which can then be magically
transmitted, confirmed, etc. Later, a tick's worth of orders will need
to be processed:
void handleOrders(ibstringstream& handledOrderStream)
{
handlerID h;
while (handledOrderStream)
{
handledOrderStream >> h;
orderHandlers[h](handledOrderStream);
};
};
Finally, handlers can be defined like this:
void myHandler(ibstringstream& orderStream)
{
int foo, bar;
orderStream
>> title("foo") >> foo
>> title("bar") >> bar;
// handle order
};
Assuming all handlers read back the data they wrote out, we can be
certain that the handler will always leave the stream at either the
start of the next handler, or at EOF.
This is just a draft proposal, but what do you all think about it?
- Andrew
- [glob2-devel] Glob2 salvage proposal, Stephane Magnenat, 2005/10/21
- Re: [glob2-devel] Glob2 salvage proposal, Andrew Sayers, 2005/10/21
- Networking (was Re: [glob2-devel] Glob2 salvage proposal),
Andrew Sayers <=
- Re: Networking (was Re: [glob2-devel] Glob2 salvage proposal), Andrew Sayers, 2005/10/23
- Re: Networking (was Re: [glob2-devel] Glob2 salvage proposal), Stephane Magnenat, 2005/10/23
- Re: Networking (was Re: [glob2-devel] Glob2 salvage proposal), Martin Voelkle, 2005/10/23
- Re: Networking (was Re: [glob2-devel] Glob2 salvage proposal), Andrew Sayers, 2005/10/23
- Networking (was Re: [glob2-devel] Glob2 salvage proposal), Andrew Sayers, 2005/10/24
- Re: Networking (was Re: [glob2-devel] Glob2 salvage proposal), Martin Voelkle, 2005/10/24
- Re: Networking (was Re: [glob2-devel] Glob2 salvage proposal), Andrew Sayers, 2005/10/24
- Re: Networking (was Re: [glob2-devel] Glob2 salvage proposal), Martin Voelkle, 2005/10/24
- Re: Networking (was Re: [glob2-devel] Glob2 salvage proposal), Stephane Magnenat, 2005/10/24
- Re: Networking (was Re: [glob2-devel] Glob2 salvage proposal), Andrew Sayers, 2005/10/24