C#, IOCP, MOGRE for a game? Buh? Looking for some insight.

Mephs

24-07-2008 20:00:10

I already hear the groaning at the use of the word "MMO" somewhere in this post, I'll make this as brief as possible.

I've been in a planning/design stage for the last 2 years, mostly with free time and as a hobby, and reading as many articles about the industry as I can. I have a pretty decent understanding that I'm lighting the fuse to my own human cannon pointed directly at a brick wall. I do have about intermediate experience with a few OO languages, such as Java and C#, with a bit of delving into C++ and vague scratching-of-the-surface when it comes to memory management.

The plan is an MMOSRPG, which I think simplifies some aspects of the development process. Namely, an online tactical RPG that plays much like some old classic tacticals, i.e. Final Fantasy Tactics, Ogre Battle, etc. Just for reference sake, since typically an MMO is free-range in 360 degrees, real-time, etc.

Anyway moving on to the questions:

Graphics: I've messed around with a few engines and I think I'm going with (M)OGRE [MOGRE is the C#/.NET wrapper for OGRE, of course] as my graphics engine. Given a 2d (sprites) / 3d landscapes graphical structure, do you think this would be adequate, and using C# no less? Would it be overkill, or just fine given OGRE's beautiful integration and capabilities?

Language: C# mainly for the client, I'm thinking, anyone really have a solid conclusion that C# in today's 2039582035GB computing world is acceptable for such a project?

Networking: Here is where the cannon fires and I plunge headfirst into the wall. I really do not have any real experience programming server-client relationships, though I do have a basic understanding of networking in general (packets, TCP, UDP). How difficult will it be to break into writing just a simple server-client, and eventually graduating to a level that I can implement for the purpose of a larger scale game?

Networking 2: Given the nature of the game (turn-based combat), would this greatly simplify the workload of the server, and on writing the server's code? Or would it still be about as intense a project as I'm lead on to believe? :)

(Also note that for things like writing server/client and all that I am very patient and willing to learn from the ground up if necessary)

Networking 3: I hate to ask this but, is it absolutely necessary I do the server code in C++? Some people swear by it and already have the garlic and crosses out when I mention C#, I bet, or is it acceptably capable of doing what I need done? Also, what kind of libraries for networking type stuff would you suggest for the final product? For learning? I keep hearing about IOCP but I'm not finding many resources relating it to C# or .NET in particular.

Database: I am pretty fluent with SQL and managing databases, I was just curious if there is any caveat to using say, MySQL vs. MSSQL Server vs. Oracle, etc. If anyone knows of course.

That's about all I can think of that I'm not 100% on just yet. Again, this is a 2 year in-design project that I'm really just now starting to actually work on writing the code for, starting with the client side and an offline workable graphics demo =). Any and all help/suggestions is greatly appreciated. I'm not going to tout things I can't show for yet, so I'm not about to go into any more detail about the project, or try to hype it until I have something that's actually functional :P

Lastly, and this is optional and more of a Marketting question: If you ever did play games like FFT, Disgaea, OB and all those, would you play an online based game in the same style?

Makaze

24-07-2008 20:39:28

Graphics - Ogre can do what you're asking no doubt but at the same time there are engines made specifically for isometric 2.5D that might make things a little bit easier.

Networking - Being turn based makes things a whole lot easier on both the server and the client.

Server - A lot of MMO servers run on a *nix platform due to its much smaller footprint and greater overall stability. I personally don't trust Mono enough to use it but also haven't checked up on it lately. But considering the scale of your project there's likely nothing wrong with running the server on windows and therefor C#.

Database - Generally the SQL flavor you use isn't all that important. MySQL is free, and works on *nix while MSSQL has better features. I've only used Oracle a couple of times so can't really speak to it.

MMO - Good luck, never happen, etc. Make a single player version first, seriously.

Your marketing question - I liked FFT, loved Disgaea (hell nearly anything from Nippon Ichi), and didn't care for the OBs all that much. But I would not play an MMO version of any of them since I don't feel like waiting for other people to take their turns, and without co-op battles it's not much of an MMO. Make a good single player SRPG, at most make it able to do P2P co-op. Online with random people and turnbased simply do not mix well.

Mephs

24-07-2008 21:01:53


Networking - Being turn based makes things a whole lot easier on both the server and the client.


Whew! Good for a "newb" network programmer then I guess =)


MMO - Good luck, never happen, etc. Make a single player version first, seriously.


Fully aware of the difficulty, and as you say right now, my priority is mastering the single player engine and maybe moving up to Peer-2-Peer functionality first before going any furthur.


Your marketing question - I liked FFT, loved Disgaea (hell nearly anything from Nippon Ichi), and didn't care for the OBs all that much. But I would not play an MMO version of any of them since I don't feel like waiting for other people to take their turns, and without co-op battles it's not much of an MMO. Make a good single player SRPG, at most make it able to do P2P co-op. Online with random people and turnbased simply do not mix well.


I had a battleplan for the "waiting" part, that is maybe even making it more semi-RTS style, but that is up in the air for now. I will start with pebbles before taking on boulders, thanks for the helpful input!

Kerion

24-07-2008 21:20:26

IOCP stands for I/O Completion Ports. They are the Windows analog of aio/epoll from Linux and KQueue from FreeBSD. Basically, the idea is that you can be asynchronously notified when network activity happens. It's a bit more complicated than that (especially in the case of IOCP's), but that's the basics.

The idea is, of course, to not use non-blocking sockets (which are really quite inefficient), but to instead use threading to listen for I/O events. When properly used, asynchronous I/O allows you to greatly enhance throughput and scalability.

In the .NET framework, IOCP's are used to back the network base asynchronous I/O exposed by the Begin/End methods of Socket. For instance, Socket.BeginRead uses IOCP's internally to know when to trigger your Read callback.

You could write your own IOCP engine, but they can be quite complex.

Mephs

24-07-2008 21:24:30


You could write your own IOCP engine, but they can be quite complex.


This is kind of what I was hoping there was already established somewhere out there, but is that all I need to start off on writing some simple net code and getting a feel for it or is it more than just IOCP? Been doing random googling about but can't seem to find anything helpful.

Kerion

24-07-2008 21:55:32

Look at the documentation for System.Net.Sockets. As I said, the Socket.Begin/End asynchronous methods are all backed by IOCP's internally in the framework. Read up on how to do asynchronous network I/O using System.Net.Sockets and that will put you on the right track.

The documentation for IOCP's is very sparse. We wrote a from-scratch IOCP engine at my last jab, and frankly it was a lot of trial and error. There is some documentation out there, but it's incomplete much of the time, and doesn't explain WHY you need to do some things. I would honestly AVOID IOCP's right now, except in using them transparently through System.Net.Sockets.

e: Here is the MSDN docs for System.Net.Sockets.Socket:

http://msdn.microsoft.com/en-us/library ... ocket.aspx

Star there, it talks briefly about the async I/O functions.

Mephs

24-07-2008 22:04:44

Look at the documentation for System.Net.Sockets. As I said, the Socket.Begin/End asynchronous methods are all backed by IOCP's internally in the framework. Read up on how to do asynchronous network I/O using System.Net.Sockets and that will put you on the right track.

The documentation for IOCP's is very sparse. We wrote a from-scratch IOCP engine at my last jab, and frankly it was a lot of trial and error. There is some documentation out there, but it's incomplete much of the time, and doesn't explain WHY you need to do some things. I would honestly AVOID IOCP's right now, except in using them transparently through System.Net.Sockets.

e: Here is the MSDN docs for System.Net.Sockets.Socket:

http://msdn.microsoft.com/en-us/library ... ocket.aspx

Star there, it talks briefly about the async I/O functions.


Thanks, this definitely gives me a head start!

From the sound of things after a bit more poking around it sounds like TCP is all I really need (turn-based system), and from a couple other suggestions on another forum it sounds like the actual processing load on the server would be rather lightweight compared to most as a result of being turn based.

Simply:

ClientA tells Server "Hey, I'm moving Unit #25 to (32, 57)"
Server goes "Okay!" and updates the location in memory
Server tells ClientB "Your opponent moved Unit #25 to (32, 57)"
ClientB updates Unit #25's location on screen
ClientA tells Server "Unit #25 is attacking #28"
Server goes "Okay", calculates the result of the attack and updates Unit #28's HP in mem.
Server relays back to ClientA with the calculation and gives the OK to play the attack animation and display the dmg (*)
Server tells ClientB "Hey, #25 hit #28, here's how much it hit for"
ClientB plays an animation of #25 swinging at #28, displaying the damage, and updating the status of the units.

* = This would be to prevent client side editting of the damage done, among other server side checks on legal moves like attacking a unit from beyond the range of the ability or command, or moving beyond the unit's limit, etc. Unit capabilities would be server side on a database to double check these things and make sure the client isn't "cheating", yes?

Something like that is the depth of the cause and effect I need. While it probably is quite a bit more to code it in reality, that's basically all I need between the server and client communication, I think. Client telling Server whats up, Server relaying the message to other Client(s) participating in the same "battle".

Makaze

24-07-2008 22:52:46

Write your whole engine to be message based. Even in single player when a player clicks to attack something don't just have it do it. Instead send a message to a message handler that does it. That way for a P2P or server based multiplayer you just send messages back and forth, the only difference is whether they originate inside the application or come over the wire. Your engine reacts to them the same way. This makes going from single to multi player much easier in addition to helping with threading among other things.

Mephs

24-07-2008 23:06:47

Write your whole engine to be message based. Even in single player when a player clicks to attack something don't just have it do it. Instead send a message to a message handler that does it. That way for a P2P or server based multiplayer you just send messages back and forth, the only difference is whether they originate inside the application or come over the wire. Your engine reacts to them the same way. This makes going from single to multi player much easier in addition to helping with threading among other things.

So would it just be possible then to base all actions off this MessageHandler like you say? I.E.

Player clicks Unit #1, Input is disabled.

MessageHandler.add("LOCAL SELECT [UNIT, 1]")

(MessageHandler sees a Unit was selected, and the command is client only, so it calls an EventHandler to do the next part)

Unit #1 is highlighted on the player's screen, Input restored.

Player clicks area to move the unit (30,30)

MessageHandler.add("SERVER SELECT [UNIT, 1] MOVE [30,30]")

This sends the message to the server, which processes the message the same way.

=ServerSide
(MessageHandler on the server sees Unit 1 is being moved to 30,30 runs a class that handles integrity checking to prevent cheating, updates info server side)

=ServerSide
MessageHandler.add("RESPOND [Socket of playerA, socket of playerB] SELECT [UNIT, 1] MOVE [30,30]")

Both players receive this command meaning the message was approved by the server, the message is translated as "LOCAL SELECT [UNIT,1] MOVE [30,30]" and sent to the Client event handlers to animate the action on screen.

^-- like that?

I guess I could have a main Message class and extend class types such as Message:Local, Message:Server, Message:Respond or something of that nature?

Sorry if I'm being overly conceptual. Trying to get a solid image in my head before I end up "hacking" my way through a project =)

Also, would it be better to design a bare client/server that just send messages to each other and then build everything else AROUND that, using MOGRE to just display the result of the messages with actions, animations and whatnot?

I'm thinking now maybe I should just do that, make a completely text based messaging server-client (almost like a chatroom or MUD) and then build from there, using the messaging system as what drives all the on-screen actions. Y/N?

Really appreciate all the suggestions from everyone.

Kerion

24-07-2008 23:53:08

That's the basic idea, but generally you want to "pack" your messages. Make the commands numerics, instead of long strings. Pack as much data in to as small a space as you can.

Makaze

25-07-2008 00:36:40

Don't use strings to construct the messages. The type of message should just be an enumeration. That way you can pass an int representing the message type. Extend that into subtypes if you need to. Same thing for message origin.

Personally I subclass my messages from a message interface and then into messages that have similar functions. The main message handler then receives messages and based on type sends them on to a message handler specifically for that message type, it might even send it to another one that does something specific.

No need to disable input at all especially if you're using buffered input. Any decision to ignore an input should take place in the logic based that particular input and game state.

So using your examples...

Player clicks unit 1 and the input handler generates a message to select that unit. It would be caught and handled locally.

The player then clicks to move that unit. The input handler would generate a message asking this unit to move. A handler, in this case a move hander for multiplayer mode, would handle the message and generate a new one that is sent to the server. No further action is taken client side. Once the server receives the message it would handle it just like normal to determine the legality, what needs to happen to move the unit, etc. A message would then be sent back to the client to move the unit, this is handled by the client's single player move handler which would generate other messages to be handled locally like a sound effect, animations, or updating mesh locations. All other clients that could see that unit would receive the same messages.

Now that basically means the server is completely authoritative, if it ignores a request for movement, movement never happens. But so long as you're using a reliable network protocol like TCP things will happen eventually. It also means it has the potential to be under a lot of load. Off loading some calculations like A*s to the client and then spot checking the results can help with that.

You can absolutely set up all that using only text for display. But I personally like to go ahead and add in some programmer art graphics, I find it helps keep motivation up and you uncover a lot of issues that will later come up.

Mephs

25-07-2008 00:43:53

That's the basic idea, but generally you want to "pack" your messages. Make the commands numerics, instead of long strings. Pack as much data in to as small a space as you can.

I kinda see what you're getting at, maybe more like codes or something?

Like example the MessageHandler could take a STRING command and convert it to the following:

LOCAL SELECT [UNIT,1] MOVE [30,30]

could be represented as

00010101051E1E

1st: Location
2nd: Source command
3rd: Source target (1st param)
4th: Source target (2nd param)
5th: Action command
6th: Action target (1st param)
7th: Action target (2nd param)

1st: 00 = LOCAL
2nd: 01 = SELECT
3rd: 01 = UNIT (1 being the type ID)
4th: 01 = base 10 value converted to base 16 for the ID
5th: 05 = MOVE (5 being the command ID)
6th: 1E = 30 (base10) converted to base16 (1E), X tile on Map object
7th: 1E = 30 (base10) converted to base16 (1E), Y tile on Map object

Something along those lines then?

Actually enumeration sounds even better.

I can potentially see the server going under load with 1000s of these transactions taking place, what would cause a huge load sending these simple messages back and forth however maybe only once every 15+ seconds (give or take, allowing time to think out moves, probably more).

By off-site calculation do you mean sending the algorithm back to the client to do the calculation?

Basically the server just going "okay the values check out, here's the math, you do it" <-?

Kerion

25-07-2008 01:12:33

Well, you need to design a protocol. I wouldn't chain commands together like that, I would send them in distinct messages.

Don't worry about the server having to process a lot of these, it's very quick.

So, for instance, a message might look like:


struct PackedMessage {
short cmd;
int dataLen;
byte[] data;
}


Then you might have a enum of commands, as such:

enum Commands : short {
None = 0,
Select = 1,
Move = 2
...
}


Now, you might abstract out your higher order game logic not to interact directly with these PackedMessages. Part of your network engine would be to translate a more object oriented pattern to the packed message format just before sending. So you would interact directly with classes like this:

class SelectMessage {
public string Location { get; set; }
public string Type { get; set; }
public int Id { get; set; }

PackedMessage ToPackedMessage() { // convert to a PackedMessage }
void FromPackedMessage(PackedMessage msg) { // load from PackedMessage }
}

// other message classes
...


Sort of see what I am getting at?

In your ToPackedMessage/FromPackedMessage functions, you could very easily use a BinaryWriter/BinaryReader to read to and from the data byte[] portion of the packed message (by wrapping a MemoryStream around it). This gives you a nice object oriented framework to use for your network coding, but allows you to send very tightly packed messages that only contain what they need to contain.

Mephs

25-07-2008 02:01:03

Crystal clear! =D

Kerion

26-07-2008 02:17:03

Something else you could do is create a MessageHandlerAttribute class that inherits from Attribute. Make it take a Commands enum value as it's constructor parameter. Then at runtime, you can use a quick reflection routine to load all the classes in your assembly that have the MessageHandlerAttribute, and use it to map message classes to command types in your network engine. This way you don't have to maintain a big if laden method to figure out which message class to pass a PackedMessage to.

So you could do:


[MessageHandler(Commands.Select)]
class SelectMessageHandler {
....
};


Then in your main network engine when you get a packet, you could simply reference a dictionary of commands, hashed by the Commands enum, and create a message handler that way, rather than maintaining a huge if block. It also makes adding new message handlers very easy.