|
multiplayer game development blog
#72117
04/25/06 07:52
04/25/06 07:52
|
Joined: Aug 2005
Posts: 1,012 germany, dresden
ulf
OP
Serious User
|
OP
Serious User
Joined: Aug 2005
Posts: 1,012
germany, dresden
|
hey there yesterday i started developing the core of our game. in short its a 10 player rpg/rts fast paced action game. i thought because here is almost no live in the multiplayerforum i write a blog about creating the multiplayer core of our game. this might be interesting for some of you to read - at least i hope so. it helps me also keeping track of the project. be aware, iam not the best coder i just want to cover developing a multiplayer project with a6. maybe this helps the community a bit when i show how i solve some problems. i hope its okay for the mods, to leave the topic here and that i post each day iam working on. others are invited to give me hints or discuss problems. if its not okay please tell me so, ill then post the blog at my own site but that would be difficult for others to join the discussion. okay here we go: yesterday the 24.04. i used locoweeds tutorial to get a start all worked well and seemed logic. then i ran into a strange behaviour. the server code works well but the client never gets the server_says_yes variable wich is triggerd by the on_server function. i did everything like in locoweeds tutorial until the part where the player entities are created and the players_connected are count. i was shure i understood all the code. after some testing i realised that i have to put a sleep(1) bevore the level load, so that the on_server command is properly triggered when the client joins the game. iam wondering why nobody else or locoweed had this problem yet? after i made this little change in the code, everything works well. Code:
sleep(1); // solves the bug where event_join is skipped when a player joins level_load(str_map); // load level, must be loaded after connection is set sleep(1); // make shure level is loaded
today the 25.04. i have planned writing the chat part of the core and add some more debug information. lets see how far i come... edit: i have successfully implented a chat and some debug information. you can see how far iam here: however, i found a little thing in the tutorial to fix. when a client joins he doesnt see the right number of people already in the game. so i added this: Code:
send_var_to(you, number_of_players); // send the number of players ingame to joined client this was not part of locoweeds tut
at the server_called function wich is the on_server function under the ifdef server; to fix it. next things iam gonna work on are camera and unit selection...
Last edited by ulf; 04/25/06 12:52.
|
|
|
Re: multiplayer game development blog
[Re: ulf]
#72120
04/27/06 03:13
04/27/06 03:13
|
Joined: Aug 2001
Posts: 2,320 Alberta, Canada
William
Expert
|
Expert
Joined: Aug 2001
Posts: 2,320
Alberta, Canada
|
Quote:
after some testing i realised that i have to put a sleep(1) bevore the level load, so that the on_server command is properly triggered when the client joins the game. iam wondering why nobody else or locoweed had this problem yet?
I ran across this problem a while back, though I thought it was just me(since I didn't re-create locoweeds level/tut, just used it for reference). I ended up putting the sleep in the on_server function, but I think i'll change that to putting the sleep before the level loading. Thanks for sharing that.
Some Tips:
- Proc_client/proc_local functions do not keep the "you" pointer when creating.
- Make sure your proc_local function isn't running code thats meant only for instances with your clients main entity. Use my.native for this.
- My.client flag and connection variable are your friends, i've used them alot.
- If you want a different interpolation solution for lan games, it's a good idea to create a global variable and differentiate between lan and internet play in your interpolation code. Lan cant have the ent_sendrate set at 0 so might as well reap the benifit and have options for it.
- If your creating a hybrid server you'll have to always keep in mind the server/client combination. Remember, this does not mean the server runs functions from proc_client or proc_local even though it's a hyrbrid. If your doing an rts or any game that requires a group of players before the game starts(not a server running and players come and go as please) then I think you'll need a hybrid server solution. I'm going for both hybrid server and a dedicated server solution in one.
- Checks and balances. Keeping track on whats realisitic when recieving and sending var/skills/arrays; hampers hacking.
- Watch your pointers! I cannot stress this enough, a large degree of my headaches come from pointer problems. Part of this is due to transfering a single-player code base to multiplayer, other part is due to stupidity. You can send pointers via handles to the other entities, but, if a new entity joins the game then it will not have the skills of the other entities. So... you have to resend the pointers.
- Are you sure you want to create a multiplayer game first? Why not create single player than take that wad of code and change it for mulitplayer? Currently i've been converting my single player base to mulitplayer for a little over a month now. I think if I went mulitplayer from day one, at my experience level(in day one), it would have took much much longer to get where I am right now due to time consuming multiplayer testing. Single player testing is not time consuming as you don't have to create multiple instances of your game over and over. If you do go single player first, create very modularized code(for example, for mine I can shut down each weapon, all weapons, chop up movement and still have functional code). This makes the task a bit easier bringing over to multiplayer as you create a base(creation of ents), and go thru your code from there 3-4 functions at a time. Keep in mind i'm speaking from my own experience, I havn't done any MMORPG work so mabye it's best to go multiplayer right from the get-go there.
- For single player I have 8 kart pointers, kart1 for the main player, kart2-kart8 for the A.I. For multiplayer, every kart creates as kart1 to keep all the single player code functional, and on top of that, I have new pointers from mkart1-mkart8 for each multiplayer kart to differentiate them. This allows me to easily transer ammo/health/ect. thru the different kart pointers, and also, keep the single player functions running well while keeping A.I seperate.
- Headeaches, i've still got a couple more weeks of them as I transer the rest of my weapons over to multiplayer, lol... I honestly cant say multiplayer has been any fun past the first week or so.
|
|
|
Re: multiplayer game development blog
[Re: ulf]
#72122
04/27/06 19:23
04/27/06 19:23
|
Joined: Aug 2005
Posts: 1,012 germany, dresden
ulf
OP
Serious User
|
OP
Serious User
Joined: Aug 2005
Posts: 1,012
germany, dresden
|
27.06. today i was able to implent a functionality like in most mmorpgs or rts games where you can use /w name text or /a text. so in short you can whisper to other players only, talk to your team only or talk to all players on the server. what i do is check the string with: if(str_cmpni(str_sendchat,"/a ")) // we got a broadcast incoming -> display it and send to clients then its like locoweed code works. its all based on some string manipulation. so far it works for /a perfectly. tomorrow ill add /w for whisper and maybe /t for the teamsay. i planned that i send the messages to all clients like "/w namefrom nameto text" and only display the text if nameto is equal player_name. so again locoweeds chat skeleton is used here. i realised that some string functions like str_getnextword and so on would be useful. but right now iam to lazy to write them for the little string manipulation i do
|
|
|
Re: multiplayer game development blog
[Re: ulf]
#72123
04/28/06 11:27
04/28/06 11:27
|
Joined: Aug 2005
Posts: 1,012 germany, dresden
ulf
OP
Serious User
|
OP
Serious User
Joined: Aug 2005
Posts: 1,012
germany, dresden
|
28.06 after some worries with the if and else clauses i finally got the whisper command working. switch/case would have been a real helper here!! now you can "/w name text" and its displayed only for the player with the right player_name. iam really happy because teamsay shouldnt be a problem now because it works similar. what i did was to send the chat over the network in the form "/a playerto playerfrom messagetext". then only display it in the on_server or on_client functions at the "EVENT_STRING" if the playerfrom text was equal to player_name. heres a little example code of how my probably ugly string manipulation works just to get the idea: (note: its not complete, and uses locoweeds chat example as base) Code:
// send chat to a special player with "/w playerto text" if(str_cmpni(str_chatentry,"/w ")) {
txtchatentry.visible = off; // change text so that it is "you whisper to nameto: messagetext" str_cpy(str_temp,"you whisper to "); // put players name before entry str_clip(str_chatentry,3); // clip /a at start str_cpy(str_whisperto, str_chatentry); // copy first 20 chars to name temp = str_stri(str_whisperto," "); // find first space after name str_trunc(str_whisperto, (str_len(str_whisperto)-temp)+1); // trunctate the rest of the name string str_cat(str_temp,str_whisperto); // copy name to temp str_cat(str_temp,":"); // copy : to temp str_clip(str_chatentry,str_len(str_whisperto)); // clip the name from the chatentry str_cat(str_temp,str_chatentry); // paste chatentry after name str_cpy(str_sendchat, str_temp); // place the result in sendchat // if host display already and send to others if(connection == 3) { // move old chat entries one up and display str_sendchat at bottom update_chat(); // add "/w " and send "/w nameto namefrom messagetext" to clients str_cpy(str_temp, "/w "); // add /w str_cat(str_temp, str_whisperto); // add name to whisper to str_cat(str_temp, " "); // spacer str_cat(str_temp, player_name); // add sender name str_cat(str_temp, " "); // spacer str_cat(str_temp, str_chatentry); // message text left over from top str_cpy(str_sendchat, str_temp); send_string(str_sendchat); } else // if client send entry to server for processing/manipulation { // move old chat entries one up and display str_sendchat at bottom update_chat(); // add "/w " and send "/w nameto namefrom messagetext" to clients str_cpy(str_temp, "/w "); // add /w str_cat(str_temp, str_whisperto); // add name to whisper to str_cat(str_temp, " "); // spacer str_cat(str_temp, player_name); // add sender name str_cat(str_temp, " "); // spacer str_cat(str_temp, str_chatentry); // message text left over from top str_cpy(str_sendchat, str_temp); send_string(str_sendchat); } }
and here is a screenshot of it working (notice the chat at the bottom)
Last edited by ulf; 04/28/06 11:28.
|
|
|
Re: multiplayer game development blog
[Re: ulf]
#72124
04/28/06 11:48
04/28/06 11:48
|
Joined: Aug 2001
Posts: 2,320 Alberta, Canada
William
Expert
|
Expert
Joined: Aug 2001
Posts: 2,320
Alberta, Canada
|
Once you understand exactly where functions run on the client and server by default, and how to manipulate them to run anywhere, multiplayer thinking makes sense. Here is a quick run-down: - Entities created will create an "instance" of themselves on each computer. Each entity will have the same pointer. A handle that calls up an entity on one computer will call up the same entity on the other computer. There is no problems retrieving "you" pointers from other computers, just place them in a skill, send that skill, and ptr_for_handle them. In a single player game you wouldn't have to worry about this; in a multiplayer environment entities don't know what their instances "you" pointers are ect. You have to send them. - Entities created will run their action on the server. In that action you can call proc_client many times, it will start a function for that entity on the client that created the entity. This is needed for individual input. - Proc_local starts a function for the entity on all computers for its instance. Do not put specialized input in here unless you validate if "my.native == on". Because it's being run on each computer for the same entity. Only call this function once and branch from there. When a new client joins the game only the last proc_local for each entity called will be called again for the new client. - Even though a hybrid server is both a server and client it will not run proc_local or proc_client functions. Which is rightfully so since the server already started a function for each entity when they were created. Just do the work from those those functions or branches from them. Just nail down exactly how to manipulate functions to run between the clients and server and you'll have a foothold on mulitplayer. After that is the tougher part, how to go about it? Depending on the size of your project, this can be very tedious. Some questions you'll come across: Collisions? Scans? and the very big one - Syncronization. Create a small movement demo before you go into your real projects. It'll help introduce some issues, but don't become over zealous and lose sight once succesfull in that, I learned that lesson... theres many more problems awaiting and it depends on the genre really. Quote:
btw whats your game all about?
It's a kart racing game somewhat similar to Mario Kart. Take Mario Kart and innovate many key aspects of it, some more than others, from weapons, level selections, mulitplayer, modes, gameplay, and graphics. While i'm not going to say to much now, i'll have a website up sometime this year. Afterwards i'll release some details here on the forum alongside a couple screenshots, I think most will be surprised.
|
|
|
Re: multiplayer game development blog
[Re: ulf]
#72125
04/28/06 13:56
04/28/06 13:56
|
Joined: Apr 2006
Posts: 1,551 Netherlands
D3D
Serious User
|
Serious User
Joined: Apr 2006
Posts: 1,551
Netherlands
|
Ulf: Thank you for sharing your project and the chat code. I was trying something like that for fun a while back, but it didn't worked (because i'm not advanced) also without some good samples to look at, it's going to become very hard to create multiplayer games for me with GameStudio. Keep it up All the best, Dusty
|
|
|
|