Multiplayer using directplay
Blitz3D Forums/Blitz3D Programming/Multiplayer using directplay
| ||
I have already coded a pretty cool game that is a single player fps. I have recently wanted to make my game multiplayer from more than one computer...no mmofps, just a small game that can accept 2 or three people. I have found code from user 'b32' but the code is set for a 2d simple game. I'm trying to get the game to 3d. I understand the whole messaging and client thing, but I'm not sure how to code it. Here's b32's code for directplay... [bbcode] ;----------------------------------------------------------------------------------- ; DirectPlay example ;----------------------------------------------------------------------------------- ;run this example twice, once as a server and once as a client. Graphics 800, 600, 0, 3 SetBuffer BackBuffer() ;start network game Select StartNetGame() Case 0 End Case 1 Print "Joined!" Case 2 Print "Server!" End Select ;create player player = CreateNetPlayer("Bram") x = Rand(400) + 200 y = Rand(300) + 150 ;main loop While Not KeyHit(1) Cls ;cursor keys to move around If KeyDown(203) Then x = x - 10 If KeyDown(205) Then x = x + 10 If KeyDown(200) Then y = y - 10 If KeyDown(208) Then y = y + 10 ;send message io = MilliSecs() / 50 If io > ioi Then SendNetMsg 1, y + x * 800, player, 0, 1 ioi = io End If ;incoming messages If RecvNetMsg() Then msgType = NetMsgType() msgFrom = NetMsgFrom() msgData = NetMsgData$() a# = msgData / 800 b# = msgData Mod 800 End If ;draw player Color 255, 255, 0 Oval x, y, 20, 20, True ;draw player Color 255, 0, 0 Oval a, b, 20, 20, True Flip Wend End [/bbcode] and that I have tested and works fine on 2 computers.... here is my code...for my fps... [bbcode] ;sandbox city ;------------------ Graphics3D 1280,960 SetBuffer BackBuffer() ;types type_player=1 type_city=2 type_boundary=3 ;camera camera=CreateCamera() Cam_range=100000 EntityType camera,type_player ;light light=CreateLight() ;city city=LoadMesh("metro 1.3ds") tex=LoadTexture("metro01.jpg","metro02.jpg") EntityTexture city,tex PositionEntity city,0,-30,+100 ScaleEntity city,10,10,10 EntityType city,type_city ;soldier soldier=LoadMesh("soldier.3ds") tex3=LoadTexture("swattex.jpg") RotateEntity soldier,0,180,0 ScaleEntity soldier,.08,.08,.08 EntityTexture soldier,tex3 PositionEntity soldier,EntityX(camera),EntityY(camera)-5,EntityZ(camera)+.5 EntityParent soldier,camera ;boundary boundary=CreateCube() PositionEntity boundary,0,0,0 ScaleEntity boundary,2200,2200,2200 FlipMesh boundary EntityAlpha boundary,.1 EntityType boundary,type_boundary ;sky sky=CreateSphere() tex2=LoadTexture("sky9.jpg") EntityTexture sky,tex2 ScaleEntity sky,100000,100000,100000 FlipMesh sky ;plane ground=CreatePlane() PositionEntity ground,0,-30,0 EntityColor ground,0,0,0 ;collisions Collisions type_player,type_city,2,2 Collisions type_player,type_boundary,2,1 EntityRadius camera,5 HidePointer ;pro run velocity#=0 While Not KeyDown(1) ;velocity If CountCollisions (camera) time=0 velocity#=0 End If If KeyHit(57) Then time=time+1 velocity#=7-.01*time TranslateEntity camera,0,velocity#,0 End If yaw#=yaw#-.01 roll#=roll#-.01 RotateEntity sky,0,yaw#,roll# time=time+1 velocity#=velocity#-.01*time TranslateEntity camera,0,velocity#,0 If KeyDown(17)=True Then MoveEntity camera,0,0,5 If KeyDown(17)=True Then cam_range=cam_range+1 CameraRange camera,1,cam_range If KeyDown(30)=True Then MoveEntity camera,-5,0,0 If KeyDown(31)=True Then MoveEntity camera,0,0,-5 If KeyDown(32)=True Then MoveEntity camera,5,0,0 UpdateWorld RenderWorld mxs#=mxs#+MouseXSpeed()/4 mys#=mys#+MouseYSpeed()/4 If mxs#<0 Then mxs#=360 If mxs#>360 Then mxs#=0 If mys#>80 Then mys#=80 If mys#<-80 Then mys#=-80 RotateEntity camera,mys#,-mxs#,0 MoveMouse 400,300 Flip Wend End [/bbcode] I understand that I will first need to create a dialog box asking to join a server....but I am asking how to make the soldier's movements and positions become transfered so another soldier can recieve a message of the location (client / server)...Please help. |
| ||
Basically you decide how often to send them, in tiny tanks I am sending them (if memory is correct, ive changed it a few times) about 5 times per second, and while that sounds like a lot. Games like counterstrike send about 10 or more movement/position packets per second. The real trick is to get your interpolation working well on the client side so that even though the packet data has "missing positions" your client will interpolate or "morph" positions and rotations between these missing positions so it is still a smooth movement. Compress the data as much as possible before sending, and uncompress it where you can. My game is Client-->Server--->ALL Clients. This allows me to bundle messages from multiple clients before retransmitting and reducing the number of packets received(per client, not server) a great deal. The server being the middle man also allows more data checking, for example even if you fire a rocket locally, the server does the check to see if it detonated close to a rival, and tells everyone about the impact. even the player that fired the rocket. Another example is for firing and reloading, this is all checked server side as well, you press the fire button and the server will reply with a success shot or a restriction where needed (ie.. still reloading ect) TIP 2: Its important to have fixed rate logic or things will get wacky, in blitz3d I couldnt send position packets for every projectile so I send firing postion, and rotation, and time fired. Then fixed rate logic on each client keeps things the same from there. The projectiles are tracked and when impacted a new packet of impact is sent so even if they are a few (game feet) difference on a machine the exact impact coordinates are resent to re sync that impact. For my game I use rendertweening, and in my projectile management code I also have delta timing in there.. In all of my tests projectiles on each client (even with simulated packet loss of 35%) stay in the same positions. Last edited 2012 Last edited 2012 |
| ||
Thank you for your extensive help and I will try what you suggested as soon as possible. I downloaded your Tiny Tanks online game, it looks really cool but nobody is on it, I'll try to get my friends to download this and play it.. |
| ||
sweet, let me know if you get a game going.. Would join in myself if possible. |
| ||
Has anyone any experience of how programs using DirectPlay work (or not) with DX11 ? Since all lthe DirectPlay code is deprecated, is it still supported by COM libraries? |
| ||
Holy moly, I missed the topic entirely. Yoshark, I used UDP for my game not direct play. There are many libraries available for UPD games in Blitz3D , rottnett is a good one, and blitzplay is good too. I used TCP WEBGET for my file updating and such. |
| ||
Wow RifRaf, that was a stunning description of comms, and what's involved and what you have achieved in TinyTanks. I truly felt like applauding. |
| ||
Well if ever asked I could go on and on really. I learned soo much making Tiny Tanks Online. A lot more than I bargained for, troubleshooting online action games can take a lot out of you. Especially when your support group is less than three people. If it werent for KingNothings help playing and bug hunting (used to be his name here) I would not have had a stable game at all. Im always looking for someone who is making online games with a blitz product to share with or learn from. Edit : Tip3.. dont use molebox, that thing caused me so much trouble with false virus flags I almost pulled my hair out. In the end I ditched Molebox and reworked my own compression and CRC system. Last edited 2013 |
| ||
Packets per second is outright wrong unless you are using an analogue controller (and even then...) In most cases when doing multiplayer I keep track of system time in a variable for each individual network component, in this case, a player. time = millisecs() sendNextPacketAt = time + 30000 if time > sendNextPacketAt then SendAPacket() Yes, 30 seconds... But here is the thing, when a player changes their control state, or is struck for damage etc. I change the sendNextPacketAt to 0. The reason is simple, if I send a data packet 5 times I second I am sending every 200ms. If I press a control key just after a packet it could be 199ms before it is sent, add in some network latency over the internet (or even local network is not 0ms) and suddenly it takes quarter of a second for the other machine to respond. This is insanity, but it is the standard approach. However, but sending the packet timing interval to "RIGHT NOW" by making it 0, you send that information straight away so the only lag is literally the ping time and the speed of your own program code to display that result. -*- My own method of sending is only to send the data required to recreate what has happened, ie: position in 3D space (often Y isnt needed but that depends upon map design), bearing of the player, and the momentum of the player. And probably some animation information (I would be happy with current sequence ID rather than current frame in most cases). The goal is not to recreate your full physics system for each player, if an AI you dont need the AI logic running on both machines. You just need to recreate the movement. So in effect the remote machine is effectively serving a replay, rather than "a gameplay" if that makes sense. |
| ||
Packets per second is outright wrong not sure what you would say that? state changes are easy to send off as needed but I was talking about an action game, and position data not state data. Jumping, Firing, typing, and many more things can be considered state.. im my several years working with this the only practical dependable way to translate fast motion across a network is with continual streaming position data.. I would like to see your game in action and a snippet of your position code, this could perhaps show me something I have not seen before.. although in my research and testing my own game I have seen a lot, I even looked over and counterstrike and a few other popular multiplayer games code where it was available to view time = millisecs() sendNextPacketAt = time + 30000 if time > sendNextPacketAt then SendAPacket() This is not uncommon type of usage. However you may want to replace millisecs with a Millisecs2() command (or similar timer scaling.) if you plan on running a server for a long time. Global Game_StartTime#=millisecs() Function Millisecs2#() return ( MilliSecs()-game_starttime# ) End Function here is my code from Tiny Tanks Online for movement/position packets If NetSendFreq_Cnt% = NETSendFreq_MAX And pSTATE=0 Then ;WAS A CHECK FOR FINISHNEXTMAP=0 AS WELL maxtime#=millisecs2()-sendtime# sendtime#=millisecs2() ;;if our chat state changes , show it over the tank If home\chatstate<>home\chatstateold home\chatstateold=home\chatstate If home\chatstate And 2 Then EntityTexture home\chatplate,chatstate_Texture(1) ShowEntity home\chatplate ElseIf home\chatstate And 4 Then EntityTexture home\chatplate,chatstate_Texture(2) ShowEntity home\chatplate Else HideEntity home\chatplate EndIf EndIf ;;create and send off packet, including any state changes/values packet$=createpositionpacket(LocalTank) Message(HOST_ID,home\NETID,msgDestinationSuper%,packet$,False) EndIf Last edited 2013 |
| ||
RifRaf>>I don't understand something. In my current project, i have organized the routines like this : UserInput() CollidersUpdate() UserLogic1() NpcsLogic1() WeaponsLogic1() ProjectilesLogic1() ParticlesLogic1() Updateworld() UserLogic2() NpcsLogic2() WeaponsLogic2() ProjectilesLogic2() ParticlesLogic2() ;optional it depends if the particle uses a collider and requires collision calculation+update HideShowEntities() AnimationsUpdate() Renderworld() HUDUpdate() or GUIUpdate() Flip() SoundsUpdate() As you can see i update the logic of the moving entities before the collisions calculation+update and after the collisions calculation+update. This is because it is only possible to retrieve the informations about the collisions that have happened only after UpdateWorld() Does this mean that i will have to send some datas on the server twice per loop ? Or only the state/orientation/movement before the collisions calculation+update and calculate the collisions on the server and update the states on the server and send back the states to the clients ? Can you give more details about this please ? |
| ||
No I would not think you would need to send position data twice, just once after the movement of the player is completed. If you do it continually X times per second as I do then it will self correct from small variances of the recipients end via interpolation. I cant tell whats happening exactly there, but you shouldnt use collisions on remote clients, let each local client handle its own physics and just transmit its coordinates. Performing local physics for remote players, can give you the "jitter" or "bounce back" effect on remote player movement. Hope that makes sense, or better yet I hope I understood you question. EDIT: You could put your comms for position at the beginning of your loop if you wanted to, that would in fact be send directly after the previous loop and all its movement. Last edited 2013 |
| ||
So if i understand correctly i only have to update the orientation/movement of the user and of the weapons/projectiles used/thrown by the user, then i send these datas (state, orientation, position) to the server, then the server receives the datas of all users, calculates the collisions, decides what is the state of each entity and send back these results to the users ? If yes, can you explain how to code a "server" that manages this ? Or maybe you have links or code examples ? And where do you put this "server", i guess it is a program that runs on its own and communicates with the client programs. Yes ? No ? |
| ||
RemiD, Basically yes, You could do real poly collisions server side if your server was 3D and had dummy models for everyone and level geometry and such, but my example is with a 2d server as a redistribution center of messages. With a 2D server, you can have xyz positions, speed and any other data you need and run some basic math to do checks based on distance, line intersects and other neat things to tell if things have collided between each new position update. Tip4. In Tiny Tanks Online my projectiles geometry collisions are tracked by their shooter (player to player impacts are server checked) to see if they touch something, or for any other reason need to explode/expire. They then send the hit data to the server with xyz positions of the impact. The server checks the impact and does a check to make sure this impact falls within reason from the recorded original firing position of the projectile vs time allowed to travel, if it does fall within reason the impact is recorded, and sent to all players.. each client will then display the proper explosion, the server will send out any health changes or damage done this is never calculated client side, as mentioned the server has the real time positions, health, and states of all clients so if sees an explosion it can tell who was hit by it, adjust health and send the new health information to the clients Last edited 2013 |
| ||
Reading from the first post and quickly flicking through (bit hard to read on a ipod) i wouldnt use directplay i would use tcp/ip or udp networking quite simply because directplay was 'removed' from dx 9 so you games wont work properly on any of todays os's. There are apps that compensate for it like hamatchi but its not ideal. |
| ||
Thanks, EdZup - that pretty much answers my earlier question :) |